@orkestrel/terminal 0.0.9 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@orkestrel/terminal",
3
- "version": "0.0.9",
3
+ "version": "0.0.10",
4
4
  "description": "An interactive terminal-prompt toolkit — a headless prompt state-machine broker, an SSE client bridge, and a raw-mode terminal driver. Part of the @orkestrel line.",
5
5
  "keywords": [
6
6
  "cli",
@@ -78,18 +78,18 @@
78
78
  "prepublishOnly": "npm run format:check && npm run lint:check && npm run check && npm run build && npm test"
79
79
  },
80
80
  "dependencies": {
81
- "@orkestrel/console": "^0.0.7",
82
- "@orkestrel/contract": "^0.0.11",
83
- "@orkestrel/database": "^0.0.9",
84
- "@orkestrel/emitter": "^0.0.6",
85
- "@orkestrel/form": "^0.0.1",
81
+ "@orkestrel/console": "^0.0.8",
82
+ "@orkestrel/contract": "^0.0.12",
83
+ "@orkestrel/database": "^0.0.10",
84
+ "@orkestrel/emitter": "^0.0.7",
85
+ "@orkestrel/form": "^0.0.2",
86
86
  "@orkestrel/sse": "^0.0.5"
87
87
  },
88
88
  "devDependencies": {
89
89
  "@microsoft/api-extractor": "^7.58.12",
90
90
  "@orkestrel/guide": "^0.0.11",
91
- "@orkestrel/scaffold": "^0.0.33",
92
- "@orkestrel/test": "^0.0.3",
91
+ "@orkestrel/scaffold": "^0.0.38",
92
+ "@orkestrel/test": "^0.0.6",
93
93
  "@types/node": "^26.1.2",
94
94
  "@vitest/browser-playwright": "^4.1.10",
95
95
  "oxfmt": "^0.61.0",
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","names":["#timeout","#timer","#cap","#parked","#emitter","#destroyed","#expire","#answer","#submit","#errors","#field","#terminal","#token","#reconnect","#delay","#fetch","#timer","#emitter","#seen","#queue","#connected","#destroyed","#connecting","#stream","#markDisconnected","#wait","#controller","#backoff","#wake","#interrupt","#warnedInsecureToken","#headers","#handle","#drain","#expire","#draining","#render","#active","#createRenderingForm","#post","#createSettler","#terminals","#config","#listeners","#edges","#store","#timeout","#timer","#cap","#emitter","#destroyed","#createPendingListener","#createAnswerListener","#createExpireListener","#findCycle","#createEdgeClear","#removeOne","#clearEdges","#snapshots","#table"],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/Prompt.ts","../../../src/core/PromptClient.ts","../../../src/core/TerminalManager.ts","../../../src/core/MemoryTerminalStore.ts","../../../src/core/DatabaseTerminalStore.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { PromptRole, PromptTheme } from './types.js'\nimport { freezeStyle, STATUS_ICONS } from '@orkestrel/console'\n\n// The constant DATA the pure terminal core reads: key decoding, rendering, and transport defaults.\n// UPPER_SNAKE, `Object.freeze`d, every member exported. Control bytes are built with\n// `String.fromCharCode` so no raw control character appears in source.\n\n// === Control bytes (named, no raw control characters in source)\n\n/** Carriage return (`\\r`, U+000D) — Enter on most terminals. */\nexport const RETURN = String.fromCharCode(13)\n/** Line feed (`\\n`, U+000A) — Enter on some terminals / pasted input. */\nexport const NEWLINE = String.fromCharCode(10)\n/** Tab (`\\t`, U+0009). */\nexport const TAB = String.fromCharCode(9)\n/** Escape (ESC, U+001B) — the lone byte, and the lead byte of every CSI / SS3 sequence. */\nexport const ESCAPE = String.fromCharCode(27)\n/** Backspace (BS, U+0008) — Ctrl+H / some terminals' Backspace. */\nexport const BACKSPACE = String.fromCharCode(8)\n/** Delete (DEL, U+007F) — the usual Backspace byte on a Unix TTY. */\nexport const DELETE = String.fromCharCode(127)\n/** Space (U+0020). */\nexport const SPACE = ' '\n/** Ctrl+C (ETX, U+0003) — interrupt / cancel. */\nexport const CTRL_C = String.fromCharCode(3)\n/** Ctrl+D (EOT, U+0004) — end-of-transmission / finish (the editor's commit key). */\nexport const CTRL_D = String.fromCharCode(4)\n/** Ctrl+U (NAK, U+0015) — clear the current line. */\nexport const CTRL_U = String.fromCharCode(21)\n/** Ctrl+A (SOH, U+0001) — move to start of line. */\nexport const CTRL_A = String.fromCharCode(1)\n/** Ctrl+E (ENQ, U+0005) — move to end of line. */\nexport const CTRL_E = String.fromCharCode(5)\n\n/**\n * The Control Sequence Introducer lead (`ESC[`) for the navigation keys — the prefix of the\n * arrow / home / end / delete sequences {@link SEQUENCE_NAMES} is keyed by. Named `KEY_CSI`\n * (not `CSI`) so it never collides with the console module's SGR `CSI` (both barrel through\n * `@src/core`).\n */\nexport const KEY_CSI = `${ESCAPE}[`\n/** The Single Shift Three lead (`ESCO`) — the alternate arrow-key prefix some terminals emit (`ESC O A`). */\nexport const KEY_SS3 = `${ESCAPE}O`\n\n/**\n * The exact escape SEQUENCE → canonical key NAME table {@link import('./helpers.js').parseKey}\n * consults for the navigation / editing keys. Covers BOTH the CSI form (`ESC[A`…) and the SS3\n * form (`ESCOA`…) of the four arrows, plus the `home` / `end` / `delete` CSI sequences (with\n * their numeric-tilde variants). The source of truth for the multi-byte key decode; frozen.\n *\n * @remarks\n * Terminals disagree on these: a cursor key is `ESC[A` (normal) or `ESCOA` (application mode),\n * and Home / End / Delete each have a letter form (`ESC[H` / `ESC[F`) and a numeric form\n * (`ESC[1~` / `ESC[4~` / `ESC[3~`). Every accepted spelling maps to one name so a reducer never\n * sees the wire encoding.\n */\nexport const SEQUENCE_NAMES: Readonly<Record<string, string>> = Object.freeze({\n\t[`${KEY_CSI}A`]: 'up',\n\t[`${KEY_CSI}B`]: 'down',\n\t[`${KEY_CSI}C`]: 'right',\n\t[`${KEY_CSI}D`]: 'left',\n\t[`${KEY_SS3}A`]: 'up',\n\t[`${KEY_SS3}B`]: 'down',\n\t[`${KEY_SS3}C`]: 'right',\n\t[`${KEY_SS3}D`]: 'left',\n\t[`${KEY_CSI}H`]: 'home',\n\t[`${KEY_CSI}F`]: 'end',\n\t[`${KEY_CSI}1~`]: 'home',\n\t[`${KEY_CSI}4~`]: 'end',\n\t[`${KEY_CSI}3~`]: 'delete',\n\t[`${KEY_CSI}7~`]: 'home',\n\t[`${KEY_CSI}8~`]: 'end',\n})\n\n/**\n * The single control BYTE → key descriptor table {@link import('./helpers.js').parseKey}\n * consults for the one-byte keys. Each entry carries the canonical `name` and whether it is a\n * `ctrl` combination. The source of truth for the single-byte key decode; frozen.\n *\n * @remarks\n * `return` / `newline` map to `return` (one canonical Enter name); `delete` / `backspace` both\n * map to `backspace` (the two Backspace bytes); the Ctrl combos (`c` / `d` / `u` / `a` / `e`)\n * carry `ctrl: true` so a reducer can match `key.ctrl && key.name === 'c'`. `escape` / `tab` /\n * `space` are plain named keys.\n */\nexport const CONTROL_NAMES: Readonly<\n\tRecord<string, { readonly name: string; readonly ctrl: boolean }>\n> = Object.freeze({\n\t[RETURN]: Object.freeze({ name: 'return', ctrl: false }),\n\t[NEWLINE]: Object.freeze({ name: 'return', ctrl: false }),\n\t[TAB]: Object.freeze({ name: 'tab', ctrl: false }),\n\t[ESCAPE]: Object.freeze({ name: 'escape', ctrl: false }),\n\t[BACKSPACE]: Object.freeze({ name: 'backspace', ctrl: false }),\n\t[DELETE]: Object.freeze({ name: 'backspace', ctrl: false }),\n\t[SPACE]: Object.freeze({ name: 'space', ctrl: false }),\n\t[CTRL_C]: Object.freeze({ name: 'c', ctrl: true }),\n\t[CTRL_D]: Object.freeze({ name: 'd', ctrl: true }),\n\t[CTRL_U]: Object.freeze({ name: 'u', ctrl: true }),\n\t[CTRL_A]: Object.freeze({ name: 'a', ctrl: true }),\n\t[CTRL_E]: Object.freeze({ name: 'e', ctrl: true }),\n})\n\n// === Prompt defaults\n\n/** The default mask glyph {@link import('./helpers.js').createPasswordState} uses — `*`. */\nexport const DEFAULT_MASK = '*'\n\n// === Prompt-view icons\n\n/**\n * The six default glyphs {@link DEFAULT_PROMPT_THEME} assembles its `icons` from. Read only when\n * the default theme is assembled; a view reads its resolved theme and never this constant. Frozen.\n *\n * @remarks\n * - `question` — the leading mark on a prompt's message line.\n * - `pointer` — the cursor before the input / the focused choice row.\n * - `dot` / `selected` — an unfocused / focused row marker in a select list.\n * - `checked` / `unchecked` — a checked / unchecked box in a checkbox list.\n */\nexport const PROMPT_ICONS = Object.freeze({\n\tquestion: '?',\n\tpointer: '›',\n\tdot: '○',\n\tselected: '●',\n\tchecked: '☑',\n\tunchecked: '☐',\n})\n\n// === The default prompt theme\n\n/**\n * Every {@link import('./types.js').PromptRole}, in one frozen list — the role axis's source of\n * truth. {@link import('./helpers.js').createPromptTheme} walks it to merge a partial theme, and\n * a consumer building a complete role map reads it rather than retyping every name.\n */\nexport const PROMPT_ROLES: readonly PromptRole[] = Object.freeze([\n\t'question',\n\t'pointer',\n\t'message',\n\t'content',\n\t'success',\n\t'error',\n\t'selected',\n\t'focus',\n\t'hint',\n\t'muted',\n\t'description',\n])\n\n/**\n * The {@link import('./types.js').PromptTheme} every prompt renders with unless its options supply\n * another — the glyph set assembled from {@link PROMPT_ICONS} plus the console\n * {@link import('@orkestrel/console').STATUS_ICONS} `success` / `error` marks, and the console\n * {@link import('@orkestrel/console').Style} each role is painted with. Deeply frozen through the\n * console module's own {@link import('@orkestrel/console').freezeStyle}; the baseline\n * {@link import('./helpers.js').createPromptTheme} merges a partial theme over.\n *\n * @remarks\n * The default roles reproduce the views' historical coloring exactly: `question` / `pointer` cyan,\n * `message` / `focus` bold, `success` / `selected` green, `error` red, `hint` / `muted` /\n * `description` dim, and `content` the EMPTY style — an empty style renders bare text, so primary\n * content keeps the bytes it had before it became themeable.\n * Two roles sharing a style today are still two roles — re-mapping one leaves the other alone.\n */\nexport const DEFAULT_PROMPT_THEME: PromptTheme = Object.freeze({\n\ticons: Object.freeze({\n\t\tquestion: PROMPT_ICONS.question,\n\t\tpointer: PROMPT_ICONS.pointer,\n\t\tdot: PROMPT_ICONS.dot,\n\t\tselected: PROMPT_ICONS.selected,\n\t\tchecked: PROMPT_ICONS.checked,\n\t\tunchecked: PROMPT_ICONS.unchecked,\n\t\tsuccess: STATUS_ICONS.success,\n\t\terror: STATUS_ICONS.error,\n\t}),\n\troles: Object.freeze({\n\t\tquestion: freezeStyle({ foreground: 'cyan', attributes: [] }),\n\t\tpointer: freezeStyle({ foreground: 'cyan', attributes: [] }),\n\t\tmessage: freezeStyle({ attributes: ['bold'] }),\n\t\tcontent: freezeStyle({ attributes: [] }),\n\t\tsuccess: freezeStyle({ foreground: 'green', attributes: [] }),\n\t\terror: freezeStyle({ foreground: 'red', attributes: [] }),\n\t\tselected: freezeStyle({ foreground: 'green', attributes: [] }),\n\t\tfocus: freezeStyle({ attributes: ['bold'] }),\n\t\thint: freezeStyle({ attributes: ['dim'] }),\n\t\tmuted: freezeStyle({ attributes: ['dim'] }),\n\t\tdescription: freezeStyle({ attributes: ['dim'] }),\n\t}),\n})\n\n// === Broker + SSE-bridge defaults (T-b)\n\n/** How long (ms) the {@link import('./types.js').PromptInterface} broker parks an unanswered prompt before it expires — 5 minutes. */\nexport const DEFAULT_PROMPT_TIMEOUT_MS = 300_000\n\n/** How long (ms) the {@link import('./types.js').PromptClientInterface} waits before each reconnect attempt — 2 seconds. */\nexport const DEFAULT_RECONNECT_DELAY_MS = 2_000\n\n/**\n * The SSE `event:` names the broker emits and the {@link import('./types.js').PromptClientInterface}\n * dispatches on. Frozen; the source of truth for the wire event vocabulary.\n *\n * @remarks\n * - `pending` — a serialized {@link import('./types.js').PendingForm} to dispatch and answer.\n * - `expire` — an `{ id }` payload: the broker expired a parked prompt (the client drops it).\n * - `shutdown` — the broker is going away; the client disconnects (no auto-reconnect) but stays reusable.\n */\nexport const SSE_EVENTS = Object.freeze({\n\tpending: 'pending',\n\texpire: 'expire',\n\tshutdown: 'shutdown',\n})\n\n/** The auth-token request header the {@link import('./types.js').PromptClientInterface} sends. */\nexport const HEADER_TOKEN = 'x-orkestrel-token'\n\n/** The `Accept` header value that opens the broker's SSE stream. */\nexport const ACCEPT_EVENT_STREAM = 'text/event-stream'\n\n/**\n * The maximum number of characters the {@link import('./types.js').PromptClientInterface} lets its\n * SSE parser buffer before treating the stream as hostile — 1 MiB, comfortably above any\n * legitimate prompt payload. Passed as the `limit` to `createSSEParser` so an unterminated\n * or oversized `data:` field cannot grow the buffer without bound (a memory-exhaustion guard).\n */\nexport const SSE_BUFFER_LIMIT = 1_048_576\n","import type { TerminalErrorCode } from './types.js'\n\n// AGENTS §12: a real error type, not a sentinel. Callers branch on the machine-readable\n// `error.code` rather than parsing the message, and the guard narrows with `instanceof`,\n// mirroring the agents-module errors.\n\n/**\n * The error the terminal surfaces for its own refusals: parking on a destroyed or full broker, an\n * unusable driver stream, a manager routing fault, or a ctrl-c cancellation. A parked form's own\n * lifecycle failures reject through the form's `answer` with the form package's error, never with\n * this one.\n *\n * @remarks\n * Carries a {@link TerminalErrorCode} and an optional `context` bag naming the offending values:\n * `{ cap }` on `LIMIT`, `{ to, known }` on `TARGET`, and `{ from, to, path }` on `DEADLOCK`. Narrow\n * a caught value with {@link isTerminalError} and branch on `error.code`.\n */\nexport class TerminalError extends Error {\n\t/** The machine-readable condition — see {@link TerminalErrorCode}. */\n\treadonly code: TerminalErrorCode\n\t/** An optional context bag naming the offending values — see the class {@link TerminalError remarks}. */\n\treadonly context?: Readonly<Record<string, unknown>>\n\n\tconstructor(\n\t\tcode: TerminalErrorCode,\n\t\tmessage: string,\n\t\tcontext?: Readonly<Record<string, unknown>>,\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'TerminalError'\n\t\tthis.code = code\n\t\tif (context !== undefined) this.context = context\n\t}\n}\n\n/**\n * Narrow an unknown caught value to a {@link TerminalError}.\n *\n * @param value - The value to test (typically a `catch` binding or a rejected prompt call)\n * @returns `true` when `value` is a {@link TerminalError}\n *\n * @example\n * ```ts\n * try {\n * \tawait terminal.ask(form)\n * } catch (error) {\n * \tif (isTerminalError(error) && error.code === 'CANCEL') {\n * \t\t// the person aborted\n * \t}\n * }\n * ```\n */\nexport function isTerminalError(value: unknown): value is TerminalError {\n\treturn value instanceof TerminalError\n}\n","import type { PendingForm, PendingFormStatus, TerminalSnapshot, WireEvent } from './types.js'\nimport type { Guard } from '@orkestrel/contract'\nimport {\n\tisNonEmptyString,\n\tisNumber,\n\tisRecord,\n\tisString,\n\tliteralOf,\n\trecordOf,\n} from '@orkestrel/contract'\n\n/** Narrow an unknown value to a {@link PendingFormStatus}. */\nexport const isPendingFormStatus: Guard<PendingFormStatus> = literalOf(\n\t'pending',\n\t'answered',\n\t'expired',\n)\n\n/**\n * Narrow an unknown wire value to a {@link PendingForm} envelope.\n *\n * @remarks\n * This guard checks the transport record and proves only that `schema` is a record. The Form\n * package's `parseForm` owns the schema payload and its semantic audit.\n *\n * @param value - The decoded wire value to inspect\n * @returns Whether the value is a complete pending-form envelope\n */\nexport function isPendingForm(value: unknown): value is PendingForm {\n\treturn recordOf(\n\t\t{\n\t\t\tid: isNonEmptyString,\n\t\t\tschema: isRecord,\n\t\t\tstatus: isPendingFormStatus,\n\t\t\ttime: isNumber,\n\t\t\tfrom: isString,\n\t\t\tto: isString,\n\t\t},\n\t\t['from', 'to'],\n\t)(value)\n}\n\n/**\n * Narrow an unknown value to a transport-neutral {@link WireEvent}.\n *\n * @param value - The candidate wire event\n * @returns Whether the value carries an event name, serialized data, and an optional id\n */\nexport const isWireEvent: Guard<WireEvent> = recordOf(\n\t{ event: isString, data: isString, id: isString },\n\t['id'],\n)\n\n/** Narrow an unknown value to a {@link TerminalSnapshot}. */\nexport const isTerminalSnapshot: Guard<TerminalSnapshot> = recordOf(\n\t{ id: isNonEmptyString, timeout: isNumber },\n\t['timeout'],\n)\n","import type {\n\tFetchInit,\n\tKeyEvent,\n\tPendingForm,\n\tPromptIcon,\n\tPromptRole,\n\tPromptStep,\n\tPromptTheme,\n\tPromptThemeOptions,\n\tTimerCancel,\n\tWireEvent,\n} from './types.js'\nimport type { Style, StylerInterface } from '@orkestrel/console'\nimport type {\n\tCheckboxField,\n\tConfirmField,\n\tEditorField,\n\tFormField,\n\tFormSchema,\n\tPasswordField,\n\tSelectField,\n\tTextField,\n} from '@orkestrel/form'\nimport {\n\tCONTROL_NAMES,\n\tDEFAULT_MASK,\n\tDEFAULT_PROMPT_THEME,\n\tPROMPT_ROLES,\n\tSEQUENCE_NAMES,\n} from './constants.js'\nimport { isString } from '@orkestrel/contract'\nimport { createStyler, freezeStyle, strip, stripControls } from '@orkestrel/console'\n\n// The PURE prompt core implementation — all EXPORTED, all pure, all unit-tested (AGENTS §5):\n// the key decoder, schema sanitization, per-field view renderers, and the six `create*State`\n// factories + `*Reduce` reducers. No `node:*`, no I/O, no events. Form owns validation and\n// settlement; these reducers only turn keys into candidate field values.\n\n// === Key decoding\n\n/**\n * Decode one keypress's bytes into a {@link KeyEvent} — total, never throws. A `Uint8Array` is\n * read as UTF-8; the resulting string is matched against the known control bytes\n * ({@link CONTROL_NAMES}) and escape sequences ({@link SEQUENCE_NAMES}), falling back to a\n * single printable character. An unrecognized sequence yields `name: ''` with the raw `sequence`\n * preserved.\n *\n * @remarks\n * - **Single control byte.** A one-character control input (`return` / `backspace` / `tab` /\n * `escape` / `space`, or a Ctrl combo `c` / `d` / `u` / `a` / `e`) is looked up in\n * {@link CONTROL_NAMES}, carrying its `ctrl` flag.\n * - **Escape sequence.** A multi-byte ESC sequence (`up` / `down` / `left` / `right` in BOTH the\n * `ESC[A` and `ESCOA` forms, plus `home` / `end` / `delete`) is looked up in\n * {@link SEQUENCE_NAMES} and flagged `meta`.\n * - **Printable character.** A single printable character becomes `name` = that character, with\n * `shift` set when it is an uppercase letter. A multi-code-point printable (an emoji, a pasted\n * run) keeps its first code point as the name and the whole input as `sequence`.\n * - **Unknown.** Anything else (an unrecognized escape, an empty input) yields `name: ''` —\n * total, so the driver never crashes on a stray byte.\n *\n * @param input - The raw keypress bytes, as a string or `Uint8Array`\n * @returns The decoded {@link KeyEvent}\n *\n * @example\n * ```ts\n * parseKey('\\r') // { name: 'return', sequence: '\\r', ctrl: false, meta: false, shift: false }\n * parseKey('\\x1b[A') // { name: 'up', sequence: '\\x1b[A', ctrl: false, meta: true, shift: false }\n * parseKey('A') // { name: 'A', sequence: 'A', ctrl: false, meta: false, shift: true }\n * parseKey('\\x03') // { name: 'c', sequence: '\\x03', ctrl: true, meta: false, shift: false }\n * ```\n */\nexport function parseKey(input: string | Uint8Array): KeyEvent {\n\tconst sequence = isString(input) ? input : new TextDecoder().decode(input)\n\n\t// A known multi-byte escape sequence (arrows / home / end / delete) — flagged `meta`.\n\tconst sequenceName = SEQUENCE_NAMES[sequence]\n\tif (sequenceName !== undefined) {\n\t\treturn { name: sequenceName, sequence, ctrl: false, meta: true, shift: false }\n\t}\n\n\t// A known single control byte (return / backspace / tab / escape / space / a ctrl combo).\n\tconst control = CONTROL_NAMES[sequence]\n\tif (control !== undefined) {\n\t\treturn { name: control.name, sequence, ctrl: control.ctrl, meta: false, shift: false }\n\t}\n\n\t// A printable character — one or more code points, the first naming the key.\n\tconst points = [...sequence]\n\tconst first = points[0]\n\tif (first !== undefined && isPrintable(first)) {\n\t\treturn { name: first, sequence, ctrl: false, meta: false, shift: first !== first.toLowerCase() }\n\t}\n\n\t// Anything else (an unrecognized escape, an empty input) — total, never a throw.\n\treturn { name: '', sequence, ctrl: false, meta: false, shift: false }\n}\n\n/** Whether a single character is a printable (non-control) character — used by {@link parseKey}'s char fallback. */\nexport function isPrintable(character: string): boolean {\n\tif (character.length === 0) return false\n\tconst code = character.codePointAt(0)\n\tif (code === undefined) return false\n\t// Exclude the C0 controls (0–31) and DEL (127); everything at or above space is printable.\n\treturn code >= 32 && code !== 127\n}\n\n// === Prompt theme\n\n/**\n * Build a complete {@link PromptTheme} by merging a partial one over\n * {@link DEFAULT_PROMPT_THEME}, leaf by leaf — each supplied icon replaces that glyph, each\n * supplied role replaces that {@link Style}, and everything else keeps its default. Each supplied\n * style is snapshotted through the console module's own\n * {@link import('@orkestrel/console').freezeStyle}, so the result is deeply frozen and a caller\n * mutating its own attribute list afterwards cannot reach into a built theme.\n *\n * @param options - The partial theme to merge, or `undefined` for the defaults\n * @returns The resolved, deeply frozen theme every prompt state carries\n *\n * @example\n * ```ts\n * createPromptTheme() // the defaults\n * createPromptTheme({\n * \ticons: { pointer: '=>' },\n * \troles: { message: { foreground: 'magenta', attributes: ['bold'] } },\n * })\n * ```\n */\nexport function createPromptTheme(options?: PromptThemeOptions): PromptTheme {\n\tconst icons: Record<PromptIcon, string> = { ...DEFAULT_PROMPT_THEME.icons, ...options?.icons }\n\tconst roles: Record<PromptRole, Style> = { ...DEFAULT_PROMPT_THEME.roles }\n\tfor (const role of PROMPT_ROLES) {\n\t\tconst style = options?.roles?.[role]\n\t\tif (style !== undefined) roles[role] = freezeStyle(style)\n\t}\n\treturn Object.freeze({ icons: Object.freeze(icons), roles: Object.freeze(roles) })\n}\n\n/**\n * Sanitize text for one single-line display slot. Composes console's ANSI {@link strip} and C0\n * {@link stripControls} passes with removal of tab, line feed, and carriage return.\n *\n * @param text - The text to sanitize for a glyph or hint slot\n * @returns The text with ANSI sequences, every C0 control character, and DEL removed\n *\n * @example\n * ```ts\n * sanitizeDisplayText('Q\\rOVERWRITE\\nNEXT\\tX') // 'QOVERWRITENEXTX'\n * ```\n */\nexport function sanitizeDisplayText(text: string): string {\n\treturn stripControls(strip(text)).replaceAll('\\t', '').replaceAll('\\n', '').replaceAll('\\r', '')\n}\n\n/**\n * Sanitize every terminal-readable string in a parsed form schema.\n *\n * @remarks\n * Display strings pass through {@link sanitizeDisplayText}: labels, help, placeholders, masks,\n * choice labels and help, file accept entries, and pattern sources. Identity and answer strings\n * stay verbatim: schema, group, and field names, group references, choice values, and defaults.\n * Rewriting those would sever the rendering copy from the authoritative form. Field metadata is\n * removed because terminal neither renders nor interprets it. Pattern sources are sanitized as\n * text only and are never compiled or executed here.\n *\n * @param schema - A schema already accepted by the Form package's `parseForm`\n * @returns A new schema with terminal-readable strings sanitized and field metadata omitted\n *\n * @example\n * ```ts\n * sanitizeSchema({ fields: [{ control: 'text', name: 'na\\u001bme', label: 'N\\u0000ame' }] })\n * // { fields: [{ control: 'text', name: 'na\\u001bme', label: 'Name' }] }\n * ```\n */\nexport function sanitizeSchema(schema: FormSchema): FormSchema {\n\tconst groups = schema.groups?.map((group) => ({\n\t\tname: group.name,\n\t\tlabel: sanitizeDisplayText(group.label),\n\t\t...(group.help !== undefined ? { help: sanitizeDisplayText(group.help) } : {}),\n\t}))\n\tconst fields: FormField[] = []\n\tfor (const source of schema.fields) {\n\t\tconst { meta: _meta, ...field } = source\n\t\tconst rule =\n\t\t\tfield.rule === undefined\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\t...field.rule,\n\t\t\t\t\t\t...(field.rule.pattern !== undefined\n\t\t\t\t\t\t\t? { pattern: sanitizeDisplayText(field.rule.pattern) }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t}\n\t\tconst shared = {\n\t\t\tname: field.name,\n\t\t\t...(field.label !== undefined ? { label: sanitizeDisplayText(field.label) } : {}),\n\t\t\t...(field.help !== undefined ? { help: sanitizeDisplayText(field.help) } : {}),\n\t\t\t...(field.group !== undefined ? { group: field.group } : {}),\n\t\t\t...(rule !== undefined ? { rule } : {}),\n\t\t}\n\n\t\tswitch (field.control) {\n\t\t\tcase 'text':\n\t\t\tcase 'editor': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\t...(field.placeholder !== undefined\n\t\t\t\t\t\t? { placeholder: sanitizeDisplayText(field.placeholder) }\n\t\t\t\t\t\t: {}),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'password': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\t...(field.mask !== undefined ? { mask: sanitizeDisplayText(field.mask) } : {}),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'number': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\t...(field.placeholder !== undefined\n\t\t\t\t\t\t? { placeholder: sanitizeDisplayText(field.placeholder) }\n\t\t\t\t\t\t: {}),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'date':\n\t\t\tcase 'time':\n\t\t\tcase 'datetime':\n\t\t\tcase 'color': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'confirm': {\n\t\t\t\tfields.push({ ...field, ...shared })\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'select': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\tchoices: field.choices.map((choice) => ({\n\t\t\t\t\t\t...choice,\n\t\t\t\t\t\tvalue: choice.value,\n\t\t\t\t\t\tlabel: sanitizeDisplayText(choice.label),\n\t\t\t\t\t\t...(choice.help !== undefined ? { help: sanitizeDisplayText(choice.help) } : {}),\n\t\t\t\t\t})),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'checkbox': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\tchoices: field.choices.map((choice) => ({\n\t\t\t\t\t\t...choice,\n\t\t\t\t\t\tvalue: choice.value,\n\t\t\t\t\t\tlabel: sanitizeDisplayText(choice.label),\n\t\t\t\t\t\t...(choice.help !== undefined ? { help: sanitizeDisplayText(choice.help) } : {}),\n\t\t\t\t\t})),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'file': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\t...(field.accept !== undefined ? { accept: field.accept.map(sanitizeDisplayText) } : {}),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\t...(schema.name !== undefined ? { name: schema.name } : {}),\n\t\t...(schema.label !== undefined ? { label: sanitizeDisplayText(schema.label) } : {}),\n\t\t...(schema.help !== undefined ? { help: sanitizeDisplayText(schema.help) } : {}),\n\t\t...(groups !== undefined ? { groups } : {}),\n\t\tfields,\n\t}\n}\n\n/**\n * Sanitize every glyph a wire-supplied {@link PromptThemeOptions} carries for a single-line display\n * slot. Only the icons need it: a role is guard-narrowed to a console {@link Style}, whose colors\n * and attributes are fixed name sets, so no role can carry a byte a terminal would act on.\n *\n * @param theme - The narrowed theme options a remote prompt supplied\n * @returns The same theme with every supplied glyph sanitized for a single-line display slot\n */\nexport function sanitizeThemeIcons(theme: PromptThemeOptions): PromptThemeOptions {\n\tconst icons = theme.icons\n\tif (icons === undefined) return theme\n\tconst sanitized: Record<string, string> = {}\n\tfor (const [icon, glyph] of Object.entries(icons)) sanitized[icon] = sanitizeDisplayText(glyph)\n\treturn { ...theme, icons: sanitized }\n}\n\n// === Shared view helpers\n\n/** The styled prompt-message header (`? message`) — the leading line every active prompt view shares, themed by the `question` + `message` roles. */\nexport function promptHeader(styler: StylerInterface, theme: PromptTheme, message: string): string {\n\treturn `${styler.render(theme.roles.question, theme.icons.question)} ${styler.render(theme.roles.message, message)}`\n}\n\n/**\n * Render a prompt header followed by a key hint painted with the `hint` role, or the header alone\n * when no hint is supplied.\n *\n * @param styler - The console styler that renders each role\n * @param theme - The resolved prompt theme\n * @param message - The prompt's question text\n * @param hint - The optional key hint to append\n * @returns The rendered header with the optional hint\n */\nexport function hintedHeader(\n\tstyler: StylerInterface,\n\ttheme: PromptTheme,\n\tmessage: string,\n\thint?: string,\n): string {\n\tconst head = promptHeader(styler, theme, message)\n\treturn hint === undefined ? head : `${head} ${styler.render(theme.roles.hint, hint)}`\n}\n\n/** The styled submit line (`✔ message`) — the committed header an interactive prompt shows once resolved, themed by the `success` + `message` roles. */\nexport function submitHeader(styler: StylerInterface, theme: PromptTheme, message: string): string {\n\treturn `${styler.render(theme.roles.success, theme.icons.success)} ${styler.render(theme.roles.message, message)}`\n}\n\n/** The styled error line (`✖ message`) a form driver appends for a field failure. */\nexport function errorLine(styler: StylerInterface, theme: PromptTheme, message: string): string {\n\treturn `${styler.render(theme.roles.error, theme.icons.error)} ${styler.render(theme.roles.error, message)}`\n}\n\n// === Input prompt\n\n/**\n * Build the initial text-field key state.\n *\n * @param field - The text field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createInputState(\n\tfield: TextField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tdefault: field.default ?? '',\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t\tvalue: '',\n\t}\n}\n\n/** Render a text-field key state as a styled view. */\nexport function inputView(state: ReturnType<typeof createInputState>): string {\n\tconst content = state.value.length > 0 ? state.value : state.default\n\tconst role = state.value.length > 0 ? state.theme.roles.content : state.theme.roles.hint\n\tconst shown = state.styler.render(role, sanitizeDisplayText(content))\n\treturn `${promptHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)} ${shown}`\n}\n\n/**\n * Advance an input prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`\n * reducer. Printable characters extend the value; backspace shrinks it; ctrl-u clears it; ctrl-c\n * cancels; return produces the candidate value, with an empty line falling back to the default.\n */\nexport function inputReduce(\n\tstate: ReturnType<typeof createInputState>,\n\tkey: KeyEvent,\n): PromptStep<string, ReturnType<typeof createInputState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: inputView(state), status: 'cancel' }\n\n\tif (key.name === 'return') {\n\t\tconst answer = state.value.length > 0 ? state.value : state.default\n\t\tconst next = { ...state, value: answer }\n\t\treturn {\n\t\t\tstate: next,\n\t\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, sanitizeDisplayText(answer))}`,\n\t\t\tstatus: 'submit',\n\t\t\tvalue: answer,\n\t\t}\n\t}\n\n\tconst value = editLine(state.value, key)\n\tif (value === undefined) return { state, view: inputView(state), status: 'active' }\n\tconst next = { ...state, value }\n\treturn { state: next, view: inputView(next), status: 'active' }\n}\n\n// === Password prompt\n\n/**\n * Build the initial password-field key state.\n *\n * @param field - The password field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createPasswordState(\n\tfield: PasswordField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tmask: sanitizeDisplayText(field.mask ?? DEFAULT_MASK),\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t\tvalue: '',\n\t}\n}\n\n/** Render a password-field key state as a styled view. */\nexport function passwordView(state: ReturnType<typeof createPasswordState>): string {\n\tconst masked = state.styler.render(\n\t\tstate.theme.roles.content,\n\t\tstate.mask.repeat(state.value.length),\n\t)\n\treturn `${promptHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)} ${masked}`\n}\n\n/**\n * Advance a password prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`\n * reducer. Identical line-editing to {@link inputReduce} (printable extends, backspace shrinks,\n * ctrl-u clears, ctrl-c cancels) but the view masks the value. Return produces the candidate value.\n */\nexport function passwordReduce(\n\tstate: ReturnType<typeof createPasswordState>,\n\tkey: KeyEvent,\n): PromptStep<string, ReturnType<typeof createPasswordState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: passwordView(state), status: 'cancel' }\n\n\tif (key.name === 'return') {\n\t\treturn {\n\t\t\tstate,\n\t\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, state.mask.repeat(state.value.length))}`,\n\t\t\tstatus: 'submit',\n\t\t\tvalue: state.value,\n\t\t}\n\t}\n\n\tconst value = editLine(state.value, key)\n\tif (value === undefined) return { state, view: passwordView(state), status: 'active' }\n\tconst next = { ...state, value }\n\treturn { state: next, view: passwordView(next), status: 'active' }\n}\n\n// === Confirm prompt\n\n/**\n * Build the initial confirm-field key state.\n *\n * @param field - The confirm field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createConfirmState(\n\tfield: ConfirmField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tdefault: field.default ?? false,\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t}\n}\n\n/**\n * Render a confirm-field key state as a styled view. The selected role paints the default letter.\n */\nexport function confirmView(state: ReturnType<typeof createConfirmState>): string {\n\tconst head = promptHeader(state.styler, state.theme, state.message)\n\tconst answer = state.default\n\t\t? `${state.styler.render(state.theme.roles.selected, 'Y')}${state.styler.render(state.theme.roles.hint, '/n')}`\n\t\t: `${state.styler.render(state.theme.roles.hint, 'y/')}${state.styler.render(state.theme.roles.selected, 'N')}`\n\treturn `${head} ${state.styler.render(state.theme.roles.hint, '(')}${answer}${state.styler.render(state.theme.roles.hint, ')')}`\n}\n\n/**\n * Advance a confirm prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<boolean>`\n * reducer. `y` / `Y` submits `true`, `n` / `N` submits `false`, return on an empty line submits\n * the `default`, ctrl-c cancels; any other key is ignored (stays active).\n */\nexport function confirmReduce(\n\tstate: ReturnType<typeof createConfirmState>,\n\tkey: KeyEvent,\n): PromptStep<boolean, ReturnType<typeof createConfirmState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: confirmView(state), status: 'cancel' }\n\n\tlet answer: boolean | undefined\n\tconst choice = key.name.toLowerCase()\n\tif (key.name === 'return') answer = state.default\n\telse if (choice === 'y') answer = true\n\telse if (choice === 'n') answer = false\n\n\tif (answer === undefined) return { state, view: confirmView(state), status: 'active' }\n\treturn {\n\t\tstate,\n\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, answer ? 'yes' : 'no')}`,\n\t\tstatus: 'submit',\n\t\tvalue: answer,\n\t}\n}\n\n// === Select prompt\n\n/**\n * Build the initial select-field key state.\n *\n * @param field - The select field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createSelectState(\n\tfield: SelectField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\tconst choices = [...field.choices]\n\tconst index = choices.findIndex((choice) => choice.value === field.default)\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tchoices,\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t\tfocused: index >= 0 ? index : 0,\n\t}\n}\n\n/** Render a select-field key state as a multi-line styled view. */\nexport function selectView(state: ReturnType<typeof createSelectState>): string {\n\tconst lines = state.choices.map((choice, index) => {\n\t\tconst active = index === state.focused\n\t\tconst pointer = active\n\t\t\t? state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)\n\t\t\t: ' '\n\t\tconst marker = active\n\t\t\t? state.styler.render(state.theme.roles.selected, state.theme.icons.selected)\n\t\t\t: state.styler.render(state.theme.roles.muted, state.theme.icons.dot)\n\t\tconst label = active\n\t\t\t? state.styler.render(state.theme.roles.focus, choice.label)\n\t\t\t: state.styler.render(state.theme.roles.content, choice.label)\n\t\tconst description =\n\t\t\tchoice.help === undefined\n\t\t\t\t? ''\n\t\t\t\t: ` ${state.styler.render(state.theme.roles.description, choice.help)}`\n\t\treturn `${pointer} ${marker} ${label}${description}`\n\t})\n\treturn [promptHeader(state.styler, state.theme, state.message), ...lines].join('\\n')\n}\n\n/**\n * Advance a select prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`\n * reducer. `up` / `down` (and `k` / `j`) move the focus, WRAPPING at the ends; return submits the\n * focused choice's `value`; ctrl-c cancels. An empty choice list can never submit (a higher layer\n * guards against it); any other key is ignored.\n */\nexport function selectReduce(\n\tstate: ReturnType<typeof createSelectState>,\n\tkey: KeyEvent,\n): PromptStep<string, ReturnType<typeof createSelectState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: selectView(state), status: 'cancel' }\n\n\tconst count = state.choices.length\n\tif (count === 0) return { state, view: selectView(state), status: 'active' }\n\n\tif (key.name === 'up' || key.name === 'k') {\n\t\tconst next = { ...state, focused: (state.focused - 1 + count) % count }\n\t\treturn { state: next, view: selectView(next), status: 'active' }\n\t}\n\tif (key.name === 'down' || key.name === 'j') {\n\t\tconst next = { ...state, focused: (state.focused + 1) % count }\n\t\treturn { state: next, view: selectView(next), status: 'active' }\n\t}\n\tif (key.name === 'return') {\n\t\tconst choice = state.choices[state.focused]\n\t\tconst value = choice?.value ?? ''\n\t\treturn {\n\t\t\tstate,\n\t\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, choice?.label ?? '')}`,\n\t\t\tstatus: 'submit',\n\t\t\tvalue,\n\t\t}\n\t}\n\treturn { state, view: selectView(state), status: 'active' }\n}\n\n// === Checkbox prompt\n\n/**\n * Build the initial checkbox-field key state.\n *\n * @param field - The checkbox field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createCheckboxState(\n\tfield: CheckboxField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\tconst choices = [...field.choices]\n\tconst checked: readonly number[] = choices.reduce<number[]>((indices, choice, index) => {\n\t\tif (field.default?.includes(choice.value) === true) indices.push(index)\n\t\treturn indices\n\t}, [])\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tchoices,\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t\tfocused: 0,\n\t\tchecked,\n\t}\n}\n\n/** Render a checkbox-field key state as a multi-line styled view. */\nexport function checkboxView(state: ReturnType<typeof createCheckboxState>): string {\n\tconst lines = state.choices.map((choice, index) => {\n\t\tconst active = index === state.focused\n\t\tconst ticked = state.checked.includes(index)\n\t\tconst pointer = active\n\t\t\t? state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)\n\t\t\t: ' '\n\t\tconst box = ticked\n\t\t\t? state.styler.render(state.theme.roles.selected, state.theme.icons.checked)\n\t\t\t: state.styler.render(state.theme.roles.muted, state.theme.icons.unchecked)\n\t\tconst label = active\n\t\t\t? state.styler.render(state.theme.roles.focus, choice.label)\n\t\t\t: state.styler.render(state.theme.roles.content, choice.label)\n\t\tconst description =\n\t\t\tchoice.help === undefined\n\t\t\t\t? ''\n\t\t\t\t: ` ${state.styler.render(state.theme.roles.description, choice.help)}`\n\t\treturn `${pointer} ${box} ${label}${description}`\n\t})\n\tconst summary = state.styler.render(state.theme.roles.hint, `${state.checked.length} selected`)\n\tconst body = [promptHeader(state.styler, state.theme, state.message), ...lines, summary].join(\n\t\t'\\n',\n\t)\n\treturn body\n}\n\n/**\n * Advance a checkbox prompt by one {@link KeyEvent} — the pure\n * `(state, key) → PromptStep<readonly string[]>` reducer. `up` / `down` (and `k` / `j`) move the\n * focus (wrapping); `space` toggles the focused index in the checked set; return submits the\n * checked values in choice order; ctrl-c cancels. The form applies selection-count rules.\n */\nexport function checkboxReduce(\n\tstate: ReturnType<typeof createCheckboxState>,\n\tkey: KeyEvent,\n): PromptStep<readonly string[], ReturnType<typeof createCheckboxState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: checkboxView(state), status: 'cancel' }\n\n\tconst count = state.choices.length\n\n\tif ((key.name === 'up' || key.name === 'k') && count > 0) {\n\t\tconst next = {\n\t\t\t...state,\n\t\t\tfocused: (state.focused - 1 + count) % count,\n\t\t}\n\t\treturn { state: next, view: checkboxView(next), status: 'active' }\n\t}\n\tif ((key.name === 'down' || key.name === 'j') && count > 0) {\n\t\tconst next = { ...state, focused: (state.focused + 1) % count }\n\t\treturn { state: next, view: checkboxView(next), status: 'active' }\n\t}\n\tif (key.name === 'space' && count > 0) {\n\t\tconst checked = toggleIndex(state.checked, state.focused)\n\t\tconst next = { ...state, checked }\n\t\treturn { state: next, view: checkboxView(next), status: 'active' }\n\t}\n\tif (key.name === 'return') {\n\t\tconst ordered = [...state.checked].sort((a, b) => a - b)\n\t\tconst values = ordered\n\t\t\t.map((index) => state.choices[index]?.value)\n\t\t\t.filter((value): value is string => value !== undefined)\n\t\tconst summary = ordered\n\t\t\t.map((index) => state.choices[index]?.label)\n\t\t\t.filter((name): name is string => name !== undefined)\n\t\t\t.join(', ')\n\t\treturn {\n\t\t\tstate,\n\t\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, summary)}`,\n\t\t\tstatus: 'submit',\n\t\t\tvalue: values,\n\t\t}\n\t}\n\treturn { state, view: checkboxView(state), status: 'active' }\n}\n\n/** Toggle `index` in a readonly index list — copy-on-write, returning the new sorted-by-insertion list. */\nexport function toggleIndex(indices: readonly number[], index: number): readonly number[] {\n\treturn indices.includes(index) ? indices.filter((i) => i !== index) : [...indices, index]\n}\n\n// === Editor prompt\n\n/**\n * Build the initial editor-field key state.\n *\n * @param field - The editor field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createEditorState(\n\tfield: EditorField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\tconst lines: readonly string[] = []\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tdefault: field.default ?? '',\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t\tlines,\n\t\tcurrent: '',\n\t}\n}\n\n/**\n * Render an editor-field key state as a multi-line styled view with its finish hint.\n */\nexport function editorView(state: ReturnType<typeof createEditorState>): string {\n\tconst head = hintedHeader(state.styler, state.theme, state.message, '(Ctrl+D to finish)')\n\tconst pointer = state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)\n\tconst committed = state.lines.map((line) => state.styler.render(state.theme.roles.content, line))\n\tconst body = [\n\t\t...committed,\n\t\t`${pointer} ${state.styler.render(state.theme.roles.content, state.current)}`,\n\t]\n\treturn [head, ...body].join('\\n')\n}\n\n/**\n * Advance an editor prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`\n * reducer. Printable characters extend the current line; backspace shrinks it; return commits the\n * current line and starts a fresh one; ctrl-d FINISHES (joining all lines, falling back to the\n * default when empty); ctrl-c cancels. The form validates the candidate after the driver fills it.\n */\nexport function editorReduce(\n\tstate: ReturnType<typeof createEditorState>,\n\tkey: KeyEvent,\n): PromptStep<string, ReturnType<typeof createEditorState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: editorView(state), status: 'cancel' }\n\n\tif (key.ctrl && key.name === 'd') {\n\t\tconst lines = state.current.length > 0 ? [...state.lines, state.current] : state.lines\n\t\tconst joined = lines.join('\\n')\n\t\tconst answer = joined.length > 0 ? joined : state.default\n\t\treturn {\n\t\t\tstate,\n\t\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, `${String(lines.length)} line${lines.length === 1 ? '' : 's'}`)}`,\n\t\t\tstatus: 'submit',\n\t\t\tvalue: answer,\n\t\t}\n\t}\n\n\tif (key.name === 'return') {\n\t\tconst next = {\n\t\t\t...state,\n\t\t\tlines: [...state.lines, state.current],\n\t\t\tcurrent: '',\n\t\t}\n\t\treturn { state: next, view: editorView(next), status: 'active' }\n\t}\n\n\tconst current = editLine(state.current, key)\n\tif (current === undefined) return { state, view: editorView(state), status: 'active' }\n\tconst next = { ...state, current }\n\treturn { state: next, view: editorView(next), status: 'active' }\n}\n\n// === Shared reducer helpers\n\n/**\n * Apply a single line-editing {@link KeyEvent} to a text buffer — the editing shared by input /\n * password / editor. A printable key appends its character; `backspace` drops the last character;\n * `space` appends a space; ctrl-u clears the line. Returns the new buffer, or `undefined` when the\n * key does not edit the line (so the caller can leave the state untouched).\n */\nexport function editLine(value: string, key: KeyEvent): string | undefined {\n\tif (key.ctrl && key.name === 'u') return ''\n\tif (key.name === 'backspace') return value.slice(0, -1)\n\tif (key.name === 'space') return `${value} `\n\t// A printable key that is not a control / navigation key — `name` is the literal character. Count\n\t// CODE POINTS (not UTF-16 units) so an astral printable (an emoji, a surrogate pair — `name.length`\n\t// 2 but ONE code point) appends instead of being dropped, while a multi-char control name (`up`,\n\t// `return`) is still rejected.\n\tif (!key.ctrl && !key.meta && [...key.name].length === 1 && isPrintable(key.name)) {\n\t\treturn `${value}${key.sequence}`\n\t}\n\treturn undefined\n}\n\n// === Broker + bridge wiring helpers (T-b)\n\n/**\n * The default {@link import('./types.js').TimerHandler} — a thin host `setTimeout` / `clearTimeout`\n * wrapper that arms `callback` after `ms` and returns a {@link TimerCancel}. The deadline seam\n * behind both the {@link import('./Prompt.js').Prompt} broker (its expiry) and the\n * {@link import('./PromptClient.js').PromptClient} (its reconnect backoff); a test injects a\n * deterministic timer instead, so neither entity touches real time.\n */\nexport function defaultTimer(callback: () => void, ms: number): TimerCancel {\n\tconst handle = setTimeout(callback, ms)\n\treturn () => clearTimeout(handle)\n}\n\n/** The default {@link import('./types.js').FetchHandler} — the global `fetch`, adapted to the minimal injected shape the {@link import('./PromptClient.js').PromptClient} uses. */\nexport function globalFetch(input: string, init?: FetchInit): Promise<Response> {\n\treturn fetch(input, init)\n}\n\n/**\n * Whether a caught value is an `AbortError` — the {@link import('./PromptClient.js').PromptClient}\n * distinguishes a deliberate `disconnect` / teardown (an aborted `fetch`) from a real fault, so it\n * exits its connect loop quietly instead of emitting `error` / reconnecting.\n */\nexport function isAbortError(error: unknown): boolean {\n\treturn (error instanceof DOMException || error instanceof Error) && error.name === 'AbortError'\n}\n\n/**\n * Whether `url` is an INSECURE remote endpoint — a plain `http://` URL whose host is NOT a\n * loopback address. Pure string parsing (no `URL` global), so it stays total on malformed input.\n *\n * @remarks\n * A loopback host (`localhost`, `127.0.0.1`, `[::1]`) over `http://` is exempt (local\n * development has no network hop to eavesdrop on); every other `http://` host is insecure.\n * An `https://` URL (or any non-`http://` scheme) is never flagged.\n *\n * @param url - The candidate endpoint URL\n * @returns `true` when `url` is a non-loopback `http://` endpoint\n *\n * @example\n * ```ts\n * isInsecureRemote('http://example.com') // true\n * isInsecureRemote('http://localhost:3000') // false\n * isInsecureRemote('https://example.com') // false\n * ```\n */\nexport function isInsecureRemote(url: string): boolean {\n\tconst prefix = 'http://'\n\tif (!url.startsWith(prefix)) return false\n\tconst rest = url.slice(prefix.length)\n\tconst hostEnd = rest.search(/[/?#]/)\n\tconst authority = hostEnd === -1 ? rest : rest.slice(0, hostEnd)\n\tconst host = authority.includes('@') ? authority.slice(authority.indexOf('@') + 1) : authority\n\tconst hostname = host.startsWith('[')\n\t\t? host.slice(0, host.indexOf(']') + 1)\n\t\t: (host.split(':')[0] ?? '')\n\treturn hostname !== 'localhost' && hostname !== '127.0.0.1' && hostname !== '[::1]'\n}\n\n// === Terminal manager wire seams (transport-neutral, no http dependency)\n\n/** Serialize a parked {@link PendingForm} into a {@link WireEvent}. */\nexport function serializePending(form: PendingForm): WireEvent {\n\treturn { event: 'pending', data: JSON.stringify(form), id: form.id }\n}\n\n/** Serialize a parked prompt's expiry into a {@link WireEvent} — event `'expire'`, `data` the JSON-stringified `{ id }` payload. */\nexport function serializeExpire(id: string): WireEvent {\n\treturn { event: 'expire', data: JSON.stringify({ id }) }\n}\n\n/** The {@link WireEvent} a broker/manager sends when it is going away — event `'shutdown'`, no payload. */\nexport function serializeShutdown(): WireEvent {\n\treturn { event: 'shutdown', data: '' }\n}\n","import type {\n\tAnswerError,\n\tParked,\n\tParkRequest,\n\tPendingForm,\n\tPromptEventMap,\n\tPromptInterface,\n\tPromptOptions,\n\tTimerHandler,\n} from './types.js'\nimport type { Result } from '@orkestrel/contract'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport type { FieldError, FormInterface, FormResult, FormValues } from '@orkestrel/form'\nimport { DEFAULT_PROMPT_TIMEOUT_MS } from './constants.js'\nimport { TerminalError } from './errors.js'\nimport { defaultTimer } from './helpers.js'\nimport { attempt } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { isFieldError, isFormError, serializeForm } from '@orkestrel/form'\n\n/**\n * The headless form broker. It parks live forms, exposes their serialized schemas, and applies\n * remote answers to the authoritative form.\n *\n * @remarks\n * A parked record carries one call to `serializeForm`. A failed fill or submit leaves the record\n * parked for another answer. A successful submit settles the form once, emits `answer`, and removes\n * the record. Timeout and teardown abandon every unsettled form through its own `destroy` method.\n *\n * @example\n * ```ts\n * const form = createForm({ fields: [{ control: 'text', name: 'name' }] })\n * const prompt = createPrompt()\n * const id = prompt.park(form)\n * prompt.answer(id, { name: 'Ada' })\n * await form.answer // { name: 'Ada' }\n * ```\n */\nexport class Prompt implements PromptInterface {\n\treadonly #timeout: number\n\treadonly #timer: TimerHandler\n\treadonly #cap: number | undefined\n\treadonly #parked = new Map<string, Parked>()\n\treadonly #emitter: Emitter<PromptEventMap>\n\t#destroyed = false\n\n\tconstructor(options?: PromptOptions) {\n\t\tthis.#timeout = options?.timeout ?? DEFAULT_PROMPT_TIMEOUT_MS\n\t\tthis.#timer = options?.timer ?? defaultTimer\n\t\tthis.#cap = options?.cap\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options?.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options?.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t}\n\n\tget emitter(): EmitterInterface<PromptEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget count(): number {\n\t\treturn this.#parked.size\n\t}\n\n\tpending(): readonly PendingForm[]\n\tpending(id: string): PendingForm | undefined\n\tpending(id?: string): readonly PendingForm[] | PendingForm | undefined {\n\t\tif (id !== undefined) return this.#parked.get(id)?.pending\n\t\tconst forms: PendingForm[] = []\n\t\tfor (const parked of this.#parked.values()) forms.push(parked.pending)\n\t\treturn forms\n\t}\n\n\tpark(form: FormInterface, request?: ParkRequest): string {\n\t\tif (this.#destroyed) {\n\t\t\tform.destroy()\n\t\t\tthrow new TerminalError('EXPIRE', 'The broker has been destroyed')\n\t\t}\n\t\tif (this.#cap !== undefined && this.#parked.size >= this.#cap) {\n\t\t\tform.destroy()\n\t\t\tthrow new TerminalError('LIMIT', `The parked-form cap (${String(this.#cap)}) was reached`, {\n\t\t\t\tcap: this.#cap,\n\t\t\t})\n\t\t}\n\n\t\tconst id = crypto.randomUUID()\n\t\tconst pending: PendingForm = {\n\t\t\tid,\n\t\t\tschema: serializeForm(form.schema),\n\t\t\tstatus: 'pending',\n\t\t\ttime: Date.now(),\n\t\t\t...(request?.from !== undefined ? { from: request.from } : {}),\n\t\t\t...(request?.to !== undefined ? { to: request.to } : {}),\n\t\t}\n\t\tconst cancel = this.#timer(() => this.#expire(id), this.#timeout)\n\t\tthis.#parked.set(id, { form, pending, cancel })\n\t\tthis.#emitter.emit('pending', pending)\n\t\treturn id\n\t}\n\n\tanswer(id: string, values: FormValues): Result<FormValues, AnswerError> {\n\t\tconst outcome = attempt(() => this.#answer(id, values))\n\t\tif (outcome.success) return outcome.value\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\treason: 'rejected',\n\t\t\t\terrors: [{ field: 'form', message: 'The form rejected the answer' }],\n\t\t\t},\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tfor (const id of [...this.#parked.keys()]) this.#expire(id)\n\t\tthis.#emitter.destroy()\n\t}\n\n\t#answer(id: string, values: FormValues): Result<FormValues, AnswerError> {\n\t\tconst parked = this.#parked.get(id)\n\t\tif (parked === undefined || parked.pending.status !== 'pending') {\n\t\t\treturn { success: false, error: { reason: 'unknown' } }\n\t\t}\n\n\t\tconst outcome = attempt(() => this.#submit(parked.form, values))\n\t\tif (!outcome.success) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { reason: 'rejected', errors: this.#errors(outcome.error, parked.form) },\n\t\t\t}\n\t\t}\n\t\tif (!outcome.value.success) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { reason: 'rejected', errors: outcome.value.error },\n\t\t\t}\n\t\t}\n\n\t\tparked.cancel()\n\t\tconst answered: Parked = {\n\t\t\t...parked,\n\t\t\tpending: { ...parked.pending, status: 'answered' },\n\t\t}\n\t\tthis.#parked.set(id, answered)\n\t\tthis.#emitter.emit('answer', id, outcome.value.value)\n\t\tthis.#parked.delete(id)\n\t\treturn outcome.value\n\t}\n\n\t#submit(form: FormInterface, values: FormValues): FormResult {\n\t\tfor (const [field, value] of Object.entries(values)) {\n\t\t\tconst outcome = attempt(() => form.fill(field, value))\n\t\t\tif (!outcome.success) {\n\t\t\t\treturn { success: false, error: this.#errors(outcome.error, form, field) }\n\t\t\t}\n\t\t}\n\t\treturn form.submit()\n\t}\n\n\t#errors(error: unknown, form: FormInterface, field?: string): readonly FieldError[] {\n\t\tif (isFormError(error)) {\n\t\t\tif (isFieldError(error.context)) return [error.context]\n\t\t\tconst named = error.context?.field\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tfield: typeof named === 'string' ? named : this.#field(form, field),\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t},\n\t\t\t]\n\t\t}\n\t\treturn [\n\t\t\t{\n\t\t\t\tfield: this.#field(form, field),\n\t\t\t\tmessage: 'The form rejected the answer',\n\t\t\t},\n\t\t]\n\t}\n\n\t#field(form: FormInterface, field?: string): string {\n\t\treturn field ?? form.schema.fields[0]?.name ?? form.schema.name ?? 'form'\n\t}\n\n\t#expire(id: string): void {\n\t\tconst parked = this.#parked.get(id)\n\t\tif (parked === undefined || parked.pending.status !== 'pending') return\n\t\tparked.cancel()\n\t\tconst expired: Parked = {\n\t\t\t...parked,\n\t\t\tpending: { ...parked.pending, status: 'expired' },\n\t\t}\n\t\tthis.#parked.set(id, expired)\n\t\tparked.form.destroy()\n\t\tthis.#emitter.emit('expire', id)\n\t\tthis.#parked.delete(id)\n\t}\n}\n","import type {\n\tFetchHandler,\n\tPromptClientEventMap,\n\tPromptClientInterface,\n\tPromptClientOptions,\n\tTimerCancel,\n\tTimerHandler,\n} from './types.js'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport type { FieldError, FormInterface, FormSchema, FormValues } from '@orkestrel/form'\nimport type { SSEEvent } from '@orkestrel/sse'\nimport {\n\tACCEPT_EVENT_STREAM,\n\tDEFAULT_RECONNECT_DELAY_MS,\n\tHEADER_TOKEN,\n\tSSE_BUFFER_LIMIT,\n\tSSE_EVENTS,\n} from './constants.js'\nimport {\n\tdefaultTimer,\n\tglobalFetch,\n\tisAbortError,\n\tisInsecureRemote,\n\tsanitizeDisplayText,\n\tsanitizeSchema,\n} from './helpers.js'\nimport { isPendingForm } from './validators.js'\nimport { arrayOf, isBoolean, isRecord, isString, parseJSON } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { createForm, isFieldError, parseForm } from '@orkestrel/form'\nimport { createSSEParser } from '@orkestrel/sse'\n\n/**\n * The SSE form bridge. It ingests serialized forms from a remote broker, renders them through a\n * local terminal, and posts answers back without blocking the event stream.\n *\n * @remarks\n * - **Connect + reconnect.** {@link connect} opens the SSE stream and reconnects after a transport\n * drop with the injected backoff unless reconnect is disabled, the client was destroyed, or\n * {@link disconnect} deliberately stopped it.\n * - **Ingest + render.** Each `pending` envelope passes through `isPendingForm`, Form's `parseForm`,\n * and terminal's `sanitizeSchema`, then enters a serial render queue. The SSE reader never awaits\n * that queue, so `expire` and `shutdown` remain live while a person is answering.\n * - **Safe local form.** The rendering copy omits every wire `pattern`, because Form compiles a\n * pattern during local evaluation. The broker's parked form retains it and remains authoritative.\n * - **Refusal retry.** A structured `rejected` response seeds a new rendering form with the values\n * just submitted, applies every {@link FieldError} through `invalidate`, and asks again. No retry\n * counter truncates the loop; acceptance, expiry, and shutdown are its bounds.\n * - **Replay safety.** A replayed id is skipped while it is queued, rendering, or posting. Once an\n * attempt ends, a later delivery of that id may be rendered again.\n *\n * @example\n * ```ts\n * const client = createPromptClient({\n * \turl: 'http://localhost:3001/prompts',\n * \tterminal: createTerminal(),\n * })\n * await client.connect()\n * ```\n */\nexport class PromptClient implements PromptClientInterface {\n\treadonly url: string\n\treadonly #terminal: PromptClientOptions['terminal']\n\treadonly #token: string | undefined\n\treadonly #reconnect: boolean\n\treadonly #delay: number\n\treadonly #fetch: FetchHandler\n\treadonly #timer: TimerHandler\n\treadonly #emitter: Emitter<PromptClientEventMap>\n\t#controller: AbortController | undefined\n\t#backoff: TimerCancel | undefined\n\t#wake: (() => void) | undefined\n\t#connecting = false\n\t#connected = false\n\t#destroyed = false\n\t#draining = false\n\t#warnedInsecureToken = false\n\treadonly #seen = new Set<string>()\n\treadonly #queue = new Map<string, FormSchema>()\n\t#active:\n\t\t| { readonly id: string; readonly form: FormInterface; readonly stopped: boolean }\n\t\t| undefined\n\n\tconstructor(options: PromptClientOptions) {\n\t\tthis.url = options.url\n\t\tthis.#terminal = options.terminal\n\t\tthis.#token = options.token\n\t\tthis.#reconnect = options.reconnect ?? true\n\t\tthis.#delay = options.delay ?? DEFAULT_RECONNECT_DELAY_MS\n\t\tthis.#fetch = options.fetch ?? globalFetch\n\t\tthis.#timer = options.timer ?? defaultTimer\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t}\n\n\tget emitter(): EmitterInterface<PromptClientEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget connected(): boolean {\n\t\treturn this.#connected\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.#destroyed || this.#connecting) return\n\t\tthis.#connecting = true\n\t\twhile (this.#connecting && !this.#destroyed) {\n\t\t\ttry {\n\t\t\t\tawait this.#stream()\n\t\t\t} catch (error) {\n\t\t\t\tthis.#markDisconnected()\n\t\t\t\tif (this.#destroyed || isAbortError(error)) return\n\t\t\t\tthis.#emitter.emit('error', error)\n\t\t\t}\n\t\t\tif (!this.#reconnect || !this.#connecting || this.#destroyed) return\n\t\t\tawait this.#wait(this.#delay)\n\t\t}\n\t}\n\n\tdisconnect(): void {\n\t\tthis.#connecting = false\n\t\tthis.#controller?.abort()\n\t\tthis.#controller = undefined\n\t\tthis.#backoff?.()\n\t\tthis.#backoff = undefined\n\t\tconst wake = this.#wake\n\t\tthis.#wake = undefined\n\t\twake?.()\n\t\tthis.#markDisconnected()\n\t}\n\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tthis.disconnect()\n\t\tthis.#interrupt()\n\t\tthis.#emitter.destroy()\n\t}\n\n\tasync #stream(): Promise<void> {\n\t\tif (this.#token !== undefined && isInsecureRemote(this.url) && !this.#warnedInsecureToken) {\n\t\t\tthis.#warnedInsecureToken = true\n\t\t\tthis.#emitter.emit(\n\t\t\t\t'error',\n\t\t\t\tnew Error('auth token sent as cleartext over insecure http; use https'),\n\t\t\t)\n\t\t}\n\t\tconst controller = new AbortController()\n\t\tthis.#controller = controller\n\t\tconst response = await this.#fetch(this.url, {\n\t\t\theaders: this.#headers({ Accept: ACCEPT_EVENT_STREAM }),\n\t\t\tsignal: controller.signal,\n\t\t})\n\t\tif (!response.ok) throw new Error(`broker returned ${String(response.status)}`)\n\t\tconst body = response.body\n\t\tif (body === null) throw new Error('broker sent no stream')\n\n\t\tthis.#connected = true\n\t\tthis.#emitter.emit('connect')\n\n\t\tconst reader = body.getReader()\n\t\tconst decoder = new TextDecoder()\n\t\tconst parser = createSSEParser({ limit: SSE_BUFFER_LIMIT })\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\tif (done) break\n\t\t\t\tfor (const event of parser.parse(decoder.decode(value, { stream: true }))) {\n\t\t\t\t\tthis.#handle(event)\n\t\t\t\t\tif (!this.#connecting) break\n\t\t\t\t}\n\t\t\t\tif (!this.#connecting) break\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t\tthis.#markDisconnected()\n\t}\n\n\t#handle(event: SSEEvent): void {\n\t\tif (event.event === SSE_EVENTS.pending) {\n\t\t\tconst parsed = parseJSON(event.data)\n\t\t\tif (!isPendingForm(parsed) || this.#seen.has(parsed.id)) return\n\t\t\tconst schema = parseForm(parsed.schema)\n\t\t\tif (schema === undefined) {\n\t\t\t\tthis.#emitter.emit(\n\t\t\t\t\t'error',\n\t\t\t\t\tnew Error(`broker sent an invalid form schema for ${parsed.id}`),\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.#seen.add(parsed.id)\n\t\t\tthis.#queue.set(parsed.id, sanitizeSchema(schema))\n\t\t\tvoid this.#drain()\n\t\t\treturn\n\t\t}\n\t\tif (event.event === SSE_EVENTS.expire) {\n\t\t\tconst parsed = parseJSON(event.data)\n\t\t\tif (isRecord(parsed) && isString(parsed.id)) this.#expire(parsed.id)\n\t\t\treturn\n\t\t}\n\t\tif (event.event === SSE_EVENTS.shutdown) {\n\t\t\tthis.disconnect()\n\t\t\tthis.#interrupt()\n\t\t}\n\t}\n\n\tasync #drain(): Promise<void> {\n\t\tif (this.#draining) return\n\t\tthis.#draining = true\n\t\ttry {\n\t\t\twhile (!this.#destroyed) {\n\t\t\t\tlet queued: readonly [string, FormSchema] | undefined\n\t\t\t\tfor (const entry of this.#queue) {\n\t\t\t\t\tqueued = entry\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif (queued === undefined) return\n\t\t\t\tconst [id, schema] = queued\n\t\t\t\tthis.#queue.delete(id)\n\t\t\t\ttry {\n\t\t\t\t\tawait this.#render(id, schema)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst active = this.#active\n\t\t\t\t\tif (active?.id !== id || !active.stopped) this.#emitter.emit('error', error)\n\t\t\t\t} finally {\n\t\t\t\t\tconst active = this.#active\n\t\t\t\t\tif (active?.id === id) {\n\t\t\t\t\t\tactive.form.destroy()\n\t\t\t\t\t\tthis.#active = undefined\n\t\t\t\t\t}\n\t\t\t\t\tif (!this.#queue.has(id)) this.#seen.delete(id)\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.#draining = false\n\t\t}\n\t}\n\n\tasync #render(id: string, schema: FormSchema): Promise<void> {\n\t\tlet values: FormValues | undefined\n\t\tlet errors: readonly FieldError[] = []\n\t\twhile (this.#seen.has(id) && !this.#destroyed) {\n\t\t\tconst form = this.#createRenderingForm(schema, values)\n\t\t\tthis.#active = { id, form, stopped: false }\n\t\t\tfor (const error of errors) form.invalidate(error.field, sanitizeDisplayText(error.message))\n\t\t\tconst submitted = await this.#terminal.ask(form)\n\t\t\tconst active = this.#active\n\t\t\tif (active?.id !== id || active.stopped) return\n\t\t\tconst rejected = await this.#post(id, submitted)\n\t\t\tconst posted = this.#active\n\t\t\tif (posted?.id !== id || posted.stopped || rejected === undefined) return\n\t\t\tvalues = submitted\n\t\t\terrors = rejected\n\t\t\tform.destroy()\n\t\t\tthis.#active = undefined\n\t\t}\n\t}\n\n\t#createRenderingForm(schema: FormSchema, values?: FormValues): FormInterface {\n\t\tconst fields = schema.fields.map((field) => {\n\t\t\tif (field.rule?.pattern === undefined) return field\n\t\t\tconst { pattern: _pattern, ...rule } = field.rule\n\t\t\treturn { ...field, rule }\n\t\t})\n\t\tconst form = createForm({ ...schema, fields }, values === undefined ? undefined : { values })\n\t\tvoid form.answer.catch(() => undefined)\n\t\treturn form\n\t}\n\n\tasync #post(id: string, values: FormValues): Promise<readonly FieldError[] | undefined> {\n\t\tconst response = await this.#fetch(this.url, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: this.#headers({ 'Content-Type': 'application/json' }),\n\t\t\tbody: JSON.stringify({ id, values }),\n\t\t})\n\t\tif (!response.ok) this.#emitter.emit('error', new Error(`broker rejected answer ${id}`))\n\t\tconst parsed = parseJSON(await response.text())\n\t\tif (!isRecord(parsed) || !isBoolean(parsed.success)) {\n\t\t\tthis.#emitter.emit('error', new Error(`broker returned an invalid answer result for ${id}`))\n\t\t\treturn undefined\n\t\t}\n\t\tif (parsed.success) return undefined\n\t\tconst error = parsed.error\n\t\tif (!isRecord(error) || !isString(error.reason)) {\n\t\t\tthis.#emitter.emit('error', new Error(`broker returned an invalid answer error for ${id}`))\n\t\t\treturn undefined\n\t\t}\n\t\tif (error.reason === 'unknown') return undefined\n\t\tif (error.reason === 'rejected' && arrayOf(isFieldError)(error.errors)) return error.errors\n\t\tthis.#emitter.emit('error', new Error(`broker returned an invalid answer refusal for ${id}`))\n\t\treturn undefined\n\t}\n\n\t#expire(id: string): void {\n\t\tconst active = this.#active\n\t\tif (active?.id === id) {\n\t\t\tthis.#active = { ...active, stopped: true }\n\t\t\tthis.#seen.delete(id)\n\t\t\tactive.form.destroy()\n\t\t} else if (this.#queue.delete(id)) this.#seen.delete(id)\n\t\tthis.#emitter.emit('expire', id)\n\t}\n\n\t#interrupt(): void {\n\t\tthis.#queue.clear()\n\t\tthis.#seen.clear()\n\t\tconst active = this.#active\n\t\tif (active === undefined) return\n\t\tthis.#active = { ...active, stopped: true }\n\t\tactive.form.destroy()\n\t}\n\n\t#markDisconnected(): void {\n\t\tif (!this.#connected) return\n\t\tthis.#connected = false\n\t\tthis.#emitter.emit('disconnect')\n\t}\n\n\t#headers(base: Record<string, string>): Record<string, string> {\n\t\tif (this.#token !== undefined) return { ...base, [HEADER_TOKEN]: this.#token }\n\t\treturn { ...base }\n\t}\n\n\t#wait(ms: number): Promise<void> {\n\t\treturn new Promise((resolve) => {\n\t\t\tconst settle = this.#createSettler(resolve)\n\t\t\tthis.#wake = settle\n\t\t\tthis.#backoff = this.#timer(settle, ms)\n\t\t})\n\t}\n\n\t#createSettler(resolve: () => void): () => void {\n\t\treturn () => {\n\t\t\tthis.#backoff = undefined\n\t\t\tthis.#wake = undefined\n\t\t\tresolve()\n\t\t}\n\t}\n}\n","import type {\n\tPendingForm,\n\tPromptInterface,\n\tPromptOptions,\n\tTerminalAnswerError,\n\tTerminalManagerEventMap,\n\tTerminalManagerInterface,\n\tTerminalManagerOptions,\n\tTerminalSnapshot,\n\tTerminalStoreInterface,\n\tTimerHandler,\n} from './types.js'\nimport type { Result } from '@orkestrel/contract'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport type { FormInterface, FormValues } from '@orkestrel/form'\nimport { TerminalError } from './errors.js'\nimport { createPrompt } from './factories.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { isArray } from '@orkestrel/contract'\n\n/**\n * The multi-endpoint terminal MANAGER — a registry of named {@link PromptInterface} brokers (one\n * per endpoint), so several parties can `ask` forms of each other by NAME with a `from` → `to`\n * attribution edge on every parked form, and a transitive DEADLOCK check across all in-flight\n * asks.\n *\n * @remarks\n * - **Registry.** `add(name, options?)` mints (or, if `name` is already mounted, returns the\n * EXISTING broker UNCHANGED — idempotent, never clobbers a live/parked endpoint). Every mounted\n * broker's `pending` / `answer` / `expire` events are re-emitted on the manager, attributed by\n * `name`.\n * - **`ask`.** The target must already be mounted via {@link add} — `ask` never auto-adds it;\n * rejects `TARGET` for an unknown `to` (listing the known names). Rejects `DEADLOCK` when parking\n * `from → to` would close a cycle over the CURRENT in-flight edge set (walked transitively);\n * otherwise parks the caller's live form through the target's broker and returns that form's own\n * `answer` promise. Edge cleanup never alters the value or rejection the caller observes.\n * - **Durable open / save.** `open(name)` restores an EMPTY broker from the `store` (parked\n * Promises are process-bound and never resurrected); `save(name)` persists the endpoint's\n * configured `timeout`.\n * - **Removal.** `remove` drops one endpoint, a batch (§9.2, array overload FIRST), or every\n * endpoint when called without an argument. It destroys each broker, which expires every form\n * still parked on it. `destroy` is idempotent.\n *\n * @example\n * ```ts\n * const form = createForm({ fields: [{ control: 'text', name: 'name' }] })\n * const manager = new TerminalManager()\n * manager.add('agent')\n * const answer = manager.ask('user', 'agent', form)\n * manager.answer('agent', manager.pending('agent')[0].id, { name: 'Ada' })\n * await answer // { name: 'Ada' }\n * ```\n */\nexport class TerminalManager implements TerminalManagerInterface {\n\treadonly #terminals = new Map<string, PromptInterface>()\n\treadonly #config = new Map<string, PromptOptions>()\n\t// The handlers subscribed on a mounted broker's emitter — kept so `remove` can `off` them\n\t// explicitly (on top of the broker's own `destroy`, which already renders its emitter inert).\n\treadonly #listeners = new Map<\n\t\tstring,\n\t\t{\n\t\t\treadonly pending: (form: PendingForm) => void\n\t\t\treadonly answer: (id: string, values: FormValues) => void\n\t\t\treadonly expire: (id: string) => void\n\t\t}\n\t>()\n\t// In-flight `ask` edges, keyed by the parked form's id — the deadlock graph. `from` asked\n\t// `to`; cleanup on settle (answer / expire / destroy / remove) removes EXACTLY the edge that\n\t// call created.\n\treadonly #edges = new Map<string, { readonly from: string; readonly to: string }>()\n\treadonly #store: TerminalStoreInterface | undefined\n\treadonly #timeout: number | undefined\n\treadonly #timer: TimerHandler | undefined\n\treadonly #cap: number | undefined\n\treadonly #emitter: Emitter<TerminalManagerEventMap>\n\t#destroyed = false\n\n\tconstructor(options?: TerminalManagerOptions) {\n\t\tthis.#store = options?.store\n\t\tthis.#timeout = options?.timeout\n\t\tthis.#timer = options?.timer\n\t\tthis.#cap = options?.cap\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options?.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options?.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t}\n\n\tget emitter(): EmitterInterface<TerminalManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget count(): number {\n\t\treturn this.#terminals.size\n\t}\n\n\t// === Accessors (§9.1)\n\n\tterminal(name: string): PromptInterface | undefined {\n\t\treturn this.#terminals.get(name)\n\t}\n\n\tterminals(): readonly string[] {\n\t\treturn [...this.#terminals.keys()]\n\t}\n\n\t// === Registry\n\n\tadd(name: string, options?: PromptOptions): PromptInterface {\n\t\tif (this.#destroyed) throw new TerminalError('DESTROYED', 'manager destroyed')\n\t\tconst existing = this.#terminals.get(name)\n\t\tif (existing !== undefined) return existing\n\t\tconst timeout = options?.timeout ?? this.#timeout\n\t\tconst timer = options?.timer ?? this.#timer\n\t\tconst cap = options?.cap ?? this.#cap\n\t\tconst promptOptions: PromptOptions = {\n\t\t\t...(options?.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options?.error !== undefined ? { error: options.error } : {}),\n\t\t\t...(timeout !== undefined ? { timeout } : {}),\n\t\t\t...(timer !== undefined ? { timer } : {}),\n\t\t\t...(cap !== undefined ? { cap } : {}),\n\t\t}\n\t\tconst broker = createPrompt(promptOptions)\n\t\tconst listeners = {\n\t\t\tpending: this.#createPendingListener(),\n\t\t\tanswer: this.#createAnswerListener(name),\n\t\t\texpire: this.#createExpireListener(name),\n\t\t}\n\t\tbroker.emitter.on('pending', listeners.pending)\n\t\tbroker.emitter.on('answer', listeners.answer)\n\t\tbroker.emitter.on('expire', listeners.expire)\n\t\tthis.#terminals.set(name, broker)\n\t\tthis.#config.set(name, { ...options })\n\t\tthis.#listeners.set(name, listeners)\n\t\treturn broker\n\t}\n\n\t// === Ask\n\n\task(from: string, to: string, form: FormInterface): Promise<FormValues> {\n\t\tconst broker = this.#terminals.get(to)\n\t\tif (broker === undefined) {\n\t\t\tconst known = this.terminals()\n\t\t\treturn Promise.reject(\n\t\t\t\tnew TerminalError(\n\t\t\t\t\t'TARGET',\n\t\t\t\t\t`unknown terminal '${to}' (known: ${known.length > 0 ? known.join(', ') : 'none'})`,\n\t\t\t\t\t{ to, known },\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t\tconst cycle = this.#findCycle(from, to)\n\t\tif (cycle !== undefined) {\n\t\t\treturn Promise.reject(\n\t\t\t\tnew TerminalError(\n\t\t\t\t\t'DEADLOCK',\n\t\t\t\t\t`ask ${from} -> ${to} would deadlock: ${cycle.join(' -> ')}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tfrom,\n\t\t\t\t\t\tto,\n\t\t\t\t\t\tpath: cycle,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t\tconst id = broker.park(form, { from, to })\n\t\tif (broker.pending(id) !== undefined) {\n\t\t\tthis.#edges.set(id, { from, to })\n\t\t\tform.answer.then(this.#createEdgeClear(id), this.#createEdgeClear(id))\n\t\t}\n\t\treturn form.answer\n\t}\n\n\t// === Pending accessors (§9.1)\n\n\tpending(): readonly PendingForm[]\n\tpending(to: string): readonly PendingForm[]\n\tpending(to?: string): readonly PendingForm[] {\n\t\tif (to !== undefined) {\n\t\t\tconst broker = this.#terminals.get(to)\n\t\t\treturn broker === undefined ? [] : broker.pending()\n\t\t}\n\t\tconst result: PendingForm[] = []\n\t\tfor (const broker of this.#terminals.values()) result.push(...broker.pending())\n\t\treturn result\n\t}\n\n\t// === Answer\n\n\tanswer(to: string, id: string, values: FormValues): Result<FormValues, TerminalAnswerError> {\n\t\tconst broker = this.#terminals.get(to)\n\t\tif (broker === undefined) return { success: false, error: { reason: 'terminal' } }\n\t\tconst result = broker.answer(id, values)\n\t\tif (result.success) this.#edges.delete(id)\n\t\treturn result\n\t}\n\n\t// === Durable open / save\n\n\tasync open(name: string): Promise<PromptInterface | undefined> {\n\t\tif (this.#destroyed) throw new TerminalError('DESTROYED', 'manager destroyed')\n\t\tconst existing = this.#terminals.get(name)\n\t\tif (existing !== undefined) return existing\n\t\tif (this.#store === undefined) return undefined\n\t\tconst snapshot = await this.#store.get(name)\n\t\tif (this.#destroyed) throw new TerminalError('DESTROYED', 'manager destroyed')\n\t\tif (snapshot === undefined) return undefined\n\t\treturn this.add(name, snapshot.timeout !== undefined ? { timeout: snapshot.timeout } : {})\n\t}\n\n\tasync save(name: string): Promise<boolean> {\n\t\tconst broker = this.#terminals.get(name)\n\t\tif (this.#store === undefined || broker === undefined) return false\n\t\tconst config = this.#config.get(name)\n\t\tconst snapshot: TerminalSnapshot = {\n\t\t\tid: name,\n\t\t\t...(config?.timeout !== undefined ? { timeout: config.timeout } : {}),\n\t\t}\n\t\tawait this.#store.set(snapshot)\n\t\treturn true\n\t}\n\n\t// === Removal (§9.2: the array overload FIRST)\n\n\tremove(names: readonly string[]): boolean\n\tremove(name: string): boolean\n\tremove(): void\n\tremove(names?: string | readonly string[]): boolean | void {\n\t\tif (names === undefined) {\n\t\t\tfor (const name of [...this.#terminals.keys()]) this.#removeOne(name)\n\t\t\treturn\n\t\t}\n\t\tif (isArray(names)) {\n\t\t\tlet removed = false\n\t\t\tfor (const name of names) {\n\t\t\t\tif (this.#removeOne(name)) removed = true\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#removeOne(names)\n\t}\n\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tthis.remove()\n\t\tthis.#edges.clear()\n\t\tthis.#emitter.destroy()\n\t}\n\n\t// === Private helpers\n\n\t#createPendingListener(): (form: PendingForm) => void {\n\t\treturn (form) => this.#emitter.emit('pending', form)\n\t}\n\n\t#createAnswerListener(name: string): (id: string, values: FormValues) => void {\n\t\treturn (id, values) => {\n\t\t\tthis.#edges.delete(id)\n\t\t\tthis.#emitter.emit('answer', name, id, values)\n\t\t}\n\t}\n\n\t#createExpireListener(name: string): (id: string) => void {\n\t\treturn (id) => {\n\t\t\tthis.#edges.delete(id)\n\t\t\tthis.#emitter.emit('expire', name, id)\n\t\t}\n\t}\n\n\t#createEdgeClear(id: string): () => void {\n\t\treturn () => {\n\t\t\tthis.#edges.delete(id)\n\t\t}\n\t}\n\n\t// Drop one endpoint: destroy its broker FIRST (its expire loop re-emits `expire` for every\n\t// still-parked form through the manager's listeners — still attached at this point, so\n\t// each settles on the manager emitter too), THEN unsubscribe the manager's listeners and\n\t// remove it from every registry map. `false` when `name` was not mounted.\n\t#removeOne(name: string): boolean {\n\t\tconst broker = this.#terminals.get(name)\n\t\tif (broker === undefined) return false\n\t\tbroker.destroy()\n\t\tconst listeners = this.#listeners.get(name)\n\t\tif (listeners !== undefined) {\n\t\t\tbroker.emitter.off('pending', listeners.pending)\n\t\t\tbroker.emitter.off('answer', listeners.answer)\n\t\t\tbroker.emitter.off('expire', listeners.expire)\n\t\t}\n\t\tthis.#terminals.delete(name)\n\t\tthis.#config.delete(name)\n\t\tthis.#listeners.delete(name)\n\t\tthis.#clearEdges(name)\n\t\treturn true\n\t}\n\n\t#clearEdges(to: string): void {\n\t\tfor (const [id, edge] of this.#edges) {\n\t\t\tif (edge.to === to) this.#edges.delete(id)\n\t\t}\n\t}\n\n\t// Walk the in-flight edge graph forward from `to`, looking for `from` — a hit means parking\n\t// `from -> to` would close a cycle. Returns the closing cycle path (`from` first and last),\n\t// or `undefined` when no cycle would form.\n\t#findCycle(from: string, to: string): readonly string[] | undefined {\n\t\tif (from === to) return [from, to]\n\t\tconst visited = new Set<string>([to])\n\t\tconst queue: Array<readonly string[]> = [[to]]\n\t\twhile (queue.length > 0) {\n\t\t\tconst path = queue.shift()\n\t\t\tif (path === undefined) break\n\t\t\tconst last = path[path.length - 1]\n\t\t\tif (last === undefined) continue\n\t\t\tfor (const edge of this.#edges.values()) {\n\t\t\t\tif (edge.from !== last) continue\n\t\t\t\tif (edge.to === from) return [from, ...path, from]\n\t\t\t\tif (visited.has(edge.to)) continue\n\t\t\t\tvisited.add(edge.to)\n\t\t\t\tqueue.push([...path, edge.to])\n\t\t\t}\n\t\t}\n\t\treturn undefined\n\t}\n}\n","import type { TerminalSnapshot, TerminalStoreInterface } from './types.js'\n\n/**\n * The in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of\n * {@link TerminalSnapshot}s keyed by endpoint id, the DEFAULT store\n * {@link import('./factories.js').createMemoryTerminalStore} builds. The EXACT twin of\n * {@link import('./DatabaseTerminalStore.js').DatabaseTerminalStore}.\n *\n * @remarks\n * A plain `Map<string, TerminalSnapshot>` (AGENTS §21 — the snapshot is already pure, self-contained\n * CONFIG-only JSON, so no encoding is needed for the memory tier). There is NO idle-TTL and NO\n * eviction: a persisted config lives until an explicit `delete`. A durable backend (JSON / SQLite /\n * IndexedDB) swaps in through the SAME interface without touching the manager — its\n * driver-pluggable twin is {@link import('./DatabaseTerminalStore.js').DatabaseTerminalStore} (the\n * snapshot as one opaque JSON column).\n *\n * - **`get` resolves the persisted snapshot for an id**, or `undefined` if none is stored.\n * - **`set` inserts / replaces under the snapshot's OWN `id`** (no separate id param).\n * - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).\n *\n * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method\n * bijection with {@link TerminalStoreInterface}). Hydration is a caller concern: `open` always\n * restores an EMPTY broker — parked Promises are process-bound and never resurrected.\n *\n * @example\n * ```ts\n * import { createMemoryTerminalStore } from '@src/core'\n *\n * const store = createMemoryTerminalStore()\n * await store.set({ id: 'shell', timeout: 5000 }) // persist a config\n * const snapshot = await store.get('shell')\n * await store.delete('shell') // drop it\n * ```\n */\nexport class MemoryTerminalStore implements TerminalStoreInterface {\n\treadonly #snapshots = new Map<string, TerminalSnapshot>()\n\n\tget(id: string): Promise<TerminalSnapshot | undefined> {\n\t\treturn Promise.resolve(this.#snapshots.get(id))\n\t}\n\n\tset(snapshot: TerminalSnapshot): Promise<void> {\n\t\t// Insert / replace under the snapshot's OWN id (no separate id param).\n\t\tthis.#snapshots.set(snapshot.id, snapshot)\n\t\treturn Promise.resolve()\n\t}\n\n\tdelete(id: string): Promise<void> {\n\t\t// Drop by id; `Map.delete` of an absent id is already a no-op (no throw).\n\t\tthis.#snapshots.delete(id)\n\t\treturn Promise.resolve()\n\t}\n}\n","import type { TerminalSnapshot, TerminalSnapshotRow, TerminalStoreInterface } from './types.js'\nimport type { TableInterface } from '@orkestrel/database'\nimport { isTerminalSnapshot } from './validators.js'\n\n/**\n * A {@link TerminalStoreInterface} backed by one table of the `databases` layer — an endpoint's\n * durable CONFIG state IS a row, so persistence reduces to keyed point-access (`get` / `set` /\n * `delete`) over a {@link TableInterface}, the driver-pluggable twin of the plain-`Map`\n * {@link import('./MemoryTerminalStore.js').MemoryTerminalStore}.\n *\n * @remarks\n * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,\n * JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /\n * IndexedDB backend swaps in WITHOUT touching the manager — the same seam as\n * {@link import('./MemoryTerminalStore.js').MemoryTerminalStore}. The driver defaults to memory\n * ({@link import('./factories.js').createDatabaseTerminalStore} passes `createMemoryDriver()`), so\n * it ALSO works in memory out of the box; you opt into the durable plumbing by passing a JSON /\n * SQLite / IndexedDB driver.\n *\n * The {@link TerminalSnapshot} is stored as ONE OPAQUE JSON COLUMN — the table is a row of\n * `{ id; snapshot }` ({@link TerminalSnapshotRow}). The snapshot is already a COMPLETE,\n * self-contained, pure-JSON CONFIG payload (no live broker state), so storing it whole is lossless\n * AND keeps the row type flat (`snapshot` reads back as `unknown`).\n *\n * - **`set(snapshot)` upserts under the snapshot's OWN `id`** (no separate id param) — it writes\n * the row `{ id: snapshot.id, snapshot }`.\n * - **`get(id)` resolves the stored snapshot for an id**, narrowing the opaque JSON column back to\n * a {@link TerminalSnapshot} ({@link import('./validators.js').isTerminalSnapshot} — the AGENTS §14\n * boundary narrow for an untrusted storage read), or `undefined` if none is stored.\n * - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).\n *\n * There is NO idle-TTL / eviction — a persisted config lives until an explicit `delete`. The public\n * surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method bijection with\n * {@link TerminalStoreInterface}). Hydration stays a caller concern: `open` always restores an EMPTY\n * broker — parked Promises are process-bound and never resurrected.\n *\n * @example\n * ```ts\n * import { createDatabaseTerminalStore, createMemoryDriver } from '@src/core'\n *\n * const store = createDatabaseTerminalStore(createMemoryDriver()) // a durable driver swaps in here\n * await store.set({ id: 'shell', timeout: 5000 }) // persist the config (one JSON column)\n * const snapshot = await store.get('shell')\n * await store.delete('shell') // drop it\n * ```\n */\nexport class DatabaseTerminalStore implements TerminalStoreInterface {\n\treadonly #table: TableInterface<TerminalSnapshotRow>\n\n\t/**\n\t * Wrap a table as a terminal store.\n\t *\n\t * @param table - The {@link TableInterface} holding the snapshots — its row is the\n\t * {@link TerminalSnapshotRow} `{ id; snapshot }` shape (the snapshot one opaque JSON column)\n\t */\n\tconstructor(table: TableInterface<TerminalSnapshotRow>) {\n\t\tthis.#table = table\n\t}\n\n\t/** Resolve the persisted snapshot for `id`, narrowing the opaque JSON column back to a `TerminalSnapshot`. */\n\tasync get(id: string): Promise<TerminalSnapshot | undefined> {\n\t\tconst row = await this.#table.get(id)\n\t\tif (row === undefined) return undefined\n\t\t// The snapshot crosses back as an untrusted storage read (a structured clone / a JSON row),\n\t\t// so narrow the opaque JSON column with the boundary guard rather than a cast (AGENTS §14);\n\t\t// a malformed blob resolves `undefined`, never a broken config.\n\t\treturn isTerminalSnapshot(row.snapshot) ? row.snapshot : undefined\n\t}\n\n\t/** Insert or replace under the snapshot's OWN `id` (no separate id param) — the row is `{ id, snapshot }`. */\n\tasync set(snapshot: TerminalSnapshot): Promise<void> {\n\t\tawait this.#table.set({ id: snapshot.id, snapshot })\n\t}\n\n\t/** Drop a snapshot by id; an absent id is a no-op (no throw). */\n\tasync delete(id: string): Promise<void> {\n\t\tawait this.#table.remove(id)\n\t}\n}\n","import type {\n\tPromptClientInterface,\n\tPromptClientOptions,\n\tPromptInterface,\n\tPromptOptions,\n\tTerminalManagerInterface,\n\tTerminalManagerOptions,\n\tTerminalSnapshotRow,\n\tTerminalStoreInterface,\n} from './types.js'\nimport type { DriverInterface, TableInterface } from '@orkestrel/database'\nimport { Prompt } from './Prompt.js'\nimport { PromptClient } from './PromptClient.js'\nimport { TerminalManager } from './TerminalManager.js'\nimport { MemoryTerminalStore } from './MemoryTerminalStore.js'\nimport { DatabaseTerminalStore } from './DatabaseTerminalStore.js'\nimport { createDatabase, createMemoryDriver } from '@orkestrel/database'\nimport { rawShape, stringShape } from '@orkestrel/contract'\n\n/**\n * Create the headless {@link PromptInterface} broker. It parks live forms and applies remote\n * answers to the authoritative instances.\n *\n * @param options - See {@link PromptOptions}\n * @returns A {@link PromptInterface}\n *\n * @remarks\n * The caller awaits the parked form's own `answer`. Timeout or teardown destroys the form, so that\n * promise rejects with the Form package's `ABANDONED` error. Inject `options.timer` to drive\n * expiry without real time.\n *\n * @example\n * ```ts\n * import { createPrompt } from '@src/core'\n * import { createForm } from '@orkestrel/form'\n *\n * const prompt = createPrompt()\n * const form = createForm({ fields: [{ control: 'text', name: 'name' }] })\n * const id = prompt.park(form)\n * prompt.answer(id, { name: 'Ada' })\n * ```\n */\nexport function createPrompt(options?: PromptOptions): PromptInterface {\n\treturn new Prompt(options)\n}\n\n/**\n * Create the SSE prompt {@link PromptClientInterface} BRIDGE — it connects to a remote broker's SSE\n * endpoint, dispatches each received form to a local {@link import('./types.js').TerminalInterface},\n * and POSTs the answer back. Universal — `fetch` / SSE are web-standard.\n *\n * @param options - See {@link PromptClientOptions} (`url` + `terminal` required)\n * @returns A {@link PromptClientInterface}\n *\n * @remarks\n * - **Connect + reconnect.** `await client.connect()` streams remote prompts until the stream\n * ends; it reconnects with the `delay` backoff unless `reconnect` is `false` / the client was\n * `destroy`ed. Inject `options.fetch` (a scripted `fetch`) and `options.timer` to drive it\n * deterministically in tests — no real network.\n * - **§14 wire narrowing.** Every decoded prompt is guard-narrowed before dispatch (never an `as`).\n *\n * @example\n * ```ts\n * import { createPromptClient } from '@src/core'\n *\n * const client = createPromptClient({ url: 'http://host/prompts', terminal })\n * await client.connect()\n * ```\n */\nexport function createPromptClient(options: PromptClientOptions): PromptClientInterface {\n\treturn new PromptClient(options)\n}\n\n/**\n * Create the multi-endpoint {@link TerminalManager} — a named registry of\n * {@link PromptInterface} brokers so several parties can `ask` prompts of each other by name,\n * with a transitive DEADLOCK check across every in-flight ask.\n *\n * @param options - See {@link TerminalManagerOptions}\n * @returns A {@link TerminalManager}\n *\n * @example\n * ```ts\n * import { createTerminalManager } from '@src/core'\n *\n * const manager = createTerminalManager()\n * manager.add('agent')\n * ```\n */\nexport function createTerminalManager(options?: TerminalManagerOptions): TerminalManagerInterface {\n\treturn new TerminalManager(options)\n}\n\n/**\n * Create the in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of endpoint\n * config snapshots, the default store backing a {@link TerminalManagerInterface}'s `open` / `save`.\n *\n * @returns A {@link TerminalStoreInterface}\n *\n * @example\n * ```ts\n * import { createMemoryTerminalStore } from '@src/core'\n *\n * const store = createMemoryTerminalStore()\n * ```\n */\nexport function createMemoryTerminalStore(): TerminalStoreInterface {\n\treturn new MemoryTerminalStore()\n}\n\n/**\n * Create a {@link TerminalStoreInterface} backed by one table of the `databases` layer — the\n * driver-pluggable twin of {@link createMemoryTerminalStore}, storing each endpoint's config\n * snapshot as one opaque JSON column.\n *\n * @param driver - The {@link DriverInterface} backing the table (default an in-memory driver)\n * @returns A {@link TerminalStoreInterface}\n *\n * @example\n * ```ts\n * import { createDatabaseTerminalStore } from '@src/core'\n *\n * const store = createDatabaseTerminalStore() // in-memory by default\n * ```\n */\nexport function createDatabaseTerminalStore(\n\tdriver: DriverInterface = createMemoryDriver(),\n): TerminalStoreInterface {\n\t// The snapshot is stored as ONE OPAQUE JSON column (`rawShape`), so the row infers FLAT —\n\t// `{ id: string; snapshot: unknown }` = TerminalSnapshotRow.\n\tconst columns = { id: stringShape(), snapshot: rawShape({}) }\n\tconst database = createDatabase({ driver, tables: { terminals: columns } })\n\tconst table: TableInterface<TerminalSnapshotRow> = database.table('terminals')\n\treturn new DatabaseTerminalStore(table)\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["#timeout","#timer","#cap","#parked","#emitter","#destroyed","#expire","#answer","#submit","#errors","#field","#terminal","#token","#reconnect","#delay","#fetch","#timer","#emitter","#seen","#queue","#connected","#destroyed","#connecting","#stream","#markDisconnected","#wait","#controller","#backoff","#wake","#interrupt","#warnedInsecureToken","#headers","#handle","#drain","#expire","#draining","#render","#active","#createRenderingForm","#post","#createSettler","#terminals","#config","#listeners","#edges","#store","#timeout","#timer","#cap","#emitter","#destroyed","#createPendingListener","#createAnswerListener","#createExpireListener","#findCycle","#createEdgeClear","#removeOne","#clearEdges","#snapshots","#table"],"sources":["../../../src/core/constants.ts","../../../src/core/errors.ts","../../../src/core/validators.ts","../../../src/core/helpers.ts","../../../src/core/Prompt.ts","../../../src/core/PromptClient.ts","../../../src/core/TerminalManager.ts","../../../src/core/MemoryTerminalStore.ts","../../../src/core/DatabaseTerminalStore.ts","../../../src/core/factories.ts"],"sourcesContent":["import type { PromptRole, PromptTheme } from './types.js'\nimport { freezeStyle, STATUS_ICONS } from '@orkestrel/console'\n\n// The constant DATA the pure terminal core reads: key decoding, rendering, and transport defaults.\n// UPPER_SNAKE, `Object.freeze`d, every member exported. Control bytes are built with\n// `String.fromCharCode` so no raw control character appears in source.\n\n// === Control bytes (named, no raw control characters in source)\n\n/** Carriage return (`\\r`, U+000D) — Enter on most terminals. */\nexport const RETURN = String.fromCharCode(13)\n/** Line feed (`\\n`, U+000A) — Enter on some terminals / pasted input. */\nexport const NEWLINE = String.fromCharCode(10)\n/** Tab (`\\t`, U+0009). */\nexport const TAB = String.fromCharCode(9)\n/** Escape (ESC, U+001B) — the lone byte, and the lead byte of every CSI / SS3 sequence. */\nexport const ESCAPE = String.fromCharCode(27)\n/** Backspace (BS, U+0008) — Ctrl+H / some terminals' Backspace. */\nexport const BACKSPACE = String.fromCharCode(8)\n/** Delete (DEL, U+007F) — the usual Backspace byte on a Unix TTY. */\nexport const DELETE = String.fromCharCode(127)\n/** Space (U+0020). */\nexport const SPACE = ' '\n/** Ctrl+C (ETX, U+0003) — interrupt / cancel. */\nexport const CTRL_C = String.fromCharCode(3)\n/** Ctrl+D (EOT, U+0004) — end-of-transmission / finish (the editor's commit key). */\nexport const CTRL_D = String.fromCharCode(4)\n/** Ctrl+U (NAK, U+0015) — clear the current line. */\nexport const CTRL_U = String.fromCharCode(21)\n/** Ctrl+A (SOH, U+0001) — move to start of line. */\nexport const CTRL_A = String.fromCharCode(1)\n/** Ctrl+E (ENQ, U+0005) — move to end of line. */\nexport const CTRL_E = String.fromCharCode(5)\n\n/**\n * The Control Sequence Introducer lead (`ESC[`) for the navigation keys — the prefix of the\n * arrow / home / end / delete sequences {@link SEQUENCE_NAMES} is keyed by. Named `KEY_CSI`\n * (not `CSI`) so it never collides with the console module's SGR `CSI` (both barrel through\n * `@src/core`).\n */\nexport const KEY_CSI = `${ESCAPE}[`\n/** The Single Shift Three lead (`ESCO`) — the alternate arrow-key prefix some terminals emit (`ESC O A`). */\nexport const KEY_SS3 = `${ESCAPE}O`\n\n/**\n * The exact escape SEQUENCE → canonical key NAME table {@link import('./helpers.js').parseKey}\n * consults for the navigation / editing keys. Covers BOTH the CSI form (`ESC[A`…) and the SS3\n * form (`ESCOA`…) of the four arrows, plus the `home` / `end` / `delete` CSI sequences (with\n * their numeric-tilde variants). The source of truth for the multi-byte key decode; frozen.\n *\n * @remarks\n * Terminals disagree on these: a cursor key is `ESC[A` (normal) or `ESCOA` (application mode),\n * and Home / End / Delete each have a letter form (`ESC[H` / `ESC[F`) and a numeric form\n * (`ESC[1~` / `ESC[4~` / `ESC[3~`). Every accepted spelling maps to one name so a reducer never\n * sees the wire encoding.\n */\nexport const SEQUENCE_NAMES: Readonly<Record<string, string>> = Object.freeze({\n\t[`${KEY_CSI}A`]: 'up',\n\t[`${KEY_CSI}B`]: 'down',\n\t[`${KEY_CSI}C`]: 'right',\n\t[`${KEY_CSI}D`]: 'left',\n\t[`${KEY_SS3}A`]: 'up',\n\t[`${KEY_SS3}B`]: 'down',\n\t[`${KEY_SS3}C`]: 'right',\n\t[`${KEY_SS3}D`]: 'left',\n\t[`${KEY_CSI}H`]: 'home',\n\t[`${KEY_CSI}F`]: 'end',\n\t[`${KEY_CSI}1~`]: 'home',\n\t[`${KEY_CSI}4~`]: 'end',\n\t[`${KEY_CSI}3~`]: 'delete',\n\t[`${KEY_CSI}7~`]: 'home',\n\t[`${KEY_CSI}8~`]: 'end',\n})\n\n/**\n * The single control BYTE → key descriptor table {@link import('./helpers.js').parseKey}\n * consults for the one-byte keys. Each entry carries the canonical `name` and whether it is a\n * `ctrl` combination. The source of truth for the single-byte key decode; frozen.\n *\n * @remarks\n * `return` / `newline` map to `return` (one canonical Enter name); `delete` / `backspace` both\n * map to `backspace` (the two Backspace bytes); the Ctrl combos (`c` / `d` / `u` / `a` / `e`)\n * carry `ctrl: true` so a reducer can match `key.ctrl && key.name === 'c'`. `escape` / `tab` /\n * `space` are plain named keys.\n */\nexport const CONTROL_NAMES: Readonly<\n\tRecord<string, { readonly name: string; readonly ctrl: boolean }>\n> = Object.freeze({\n\t[RETURN]: Object.freeze({ name: 'return', ctrl: false }),\n\t[NEWLINE]: Object.freeze({ name: 'return', ctrl: false }),\n\t[TAB]: Object.freeze({ name: 'tab', ctrl: false }),\n\t[ESCAPE]: Object.freeze({ name: 'escape', ctrl: false }),\n\t[BACKSPACE]: Object.freeze({ name: 'backspace', ctrl: false }),\n\t[DELETE]: Object.freeze({ name: 'backspace', ctrl: false }),\n\t[SPACE]: Object.freeze({ name: 'space', ctrl: false }),\n\t[CTRL_C]: Object.freeze({ name: 'c', ctrl: true }),\n\t[CTRL_D]: Object.freeze({ name: 'd', ctrl: true }),\n\t[CTRL_U]: Object.freeze({ name: 'u', ctrl: true }),\n\t[CTRL_A]: Object.freeze({ name: 'a', ctrl: true }),\n\t[CTRL_E]: Object.freeze({ name: 'e', ctrl: true }),\n})\n\n// === Prompt defaults\n\n/** The default mask glyph {@link import('./helpers.js').createPasswordState} uses — `*`. */\nexport const DEFAULT_MASK = '*'\n\n// === Prompt-view icons\n\n/**\n * The six default glyphs {@link DEFAULT_PROMPT_THEME} assembles its `icons` from. Read only when\n * the default theme is assembled; a view reads its resolved theme and never this constant. Frozen.\n *\n * @remarks\n * - `question` — the leading mark on a prompt's message line.\n * - `pointer` — the cursor before the input / the focused choice row.\n * - `dot` / `selected` — an unfocused / focused row marker in a select list.\n * - `checked` / `unchecked` — a checked / unchecked box in a checkbox list.\n */\nexport const PROMPT_ICONS = Object.freeze({\n\tquestion: '?',\n\tpointer: '›',\n\tdot: '○',\n\tselected: '●',\n\tchecked: '☑',\n\tunchecked: '☐',\n})\n\n// === The default prompt theme\n\n/**\n * Every {@link import('./types.js').PromptRole}, in one frozen list — the role axis's source of\n * truth. {@link import('./helpers.js').createPromptTheme} walks it to merge a partial theme, and\n * a consumer building a complete role map reads it rather than retyping every name.\n */\nexport const PROMPT_ROLES: readonly PromptRole[] = Object.freeze([\n\t'question',\n\t'pointer',\n\t'message',\n\t'content',\n\t'success',\n\t'error',\n\t'selected',\n\t'focus',\n\t'hint',\n\t'muted',\n\t'description',\n])\n\n/**\n * The {@link import('./types.js').PromptTheme} every prompt renders with unless its options supply\n * another — the glyph set assembled from {@link PROMPT_ICONS} plus the console\n * {@link import('@orkestrel/console').STATUS_ICONS} `success` / `error` marks, and the console\n * {@link import('@orkestrel/console').Style} each role is painted with. Deeply frozen through the\n * console module's own {@link import('@orkestrel/console').freezeStyle}; the baseline\n * {@link import('./helpers.js').createPromptTheme} merges a partial theme over.\n *\n * @remarks\n * The default roles reproduce the views' historical coloring exactly: `question` / `pointer` cyan,\n * `message` / `focus` bold, `success` / `selected` green, `error` red, `hint` / `muted` /\n * `description` dim, and `content` the EMPTY style — an empty style renders bare text, so primary\n * content keeps the bytes it had before it became themeable.\n * Two roles sharing a style today are still two roles — re-mapping one leaves the other alone.\n */\nexport const DEFAULT_PROMPT_THEME: PromptTheme = Object.freeze({\n\ticons: Object.freeze({\n\t\tquestion: PROMPT_ICONS.question,\n\t\tpointer: PROMPT_ICONS.pointer,\n\t\tdot: PROMPT_ICONS.dot,\n\t\tselected: PROMPT_ICONS.selected,\n\t\tchecked: PROMPT_ICONS.checked,\n\t\tunchecked: PROMPT_ICONS.unchecked,\n\t\tsuccess: STATUS_ICONS.success,\n\t\terror: STATUS_ICONS.error,\n\t}),\n\troles: Object.freeze({\n\t\tquestion: freezeStyle({ foreground: 'cyan', attributes: [] }),\n\t\tpointer: freezeStyle({ foreground: 'cyan', attributes: [] }),\n\t\tmessage: freezeStyle({ attributes: ['bold'] }),\n\t\tcontent: freezeStyle({ attributes: [] }),\n\t\tsuccess: freezeStyle({ foreground: 'green', attributes: [] }),\n\t\terror: freezeStyle({ foreground: 'red', attributes: [] }),\n\t\tselected: freezeStyle({ foreground: 'green', attributes: [] }),\n\t\tfocus: freezeStyle({ attributes: ['bold'] }),\n\t\thint: freezeStyle({ attributes: ['dim'] }),\n\t\tmuted: freezeStyle({ attributes: ['dim'] }),\n\t\tdescription: freezeStyle({ attributes: ['dim'] }),\n\t}),\n})\n\n// === Broker + SSE-bridge defaults (T-b)\n\n/** How long (ms) the {@link import('./types.js').PromptInterface} broker parks an unanswered prompt before it expires — 5 minutes. */\nexport const DEFAULT_PROMPT_TIMEOUT_MS = 300_000\n\n/** How long (ms) the {@link import('./types.js').PromptClientInterface} waits before each reconnect attempt — 2 seconds. */\nexport const DEFAULT_RECONNECT_DELAY_MS = 2_000\n\n/**\n * The SSE `event:` names the broker emits and the {@link import('./types.js').PromptClientInterface}\n * dispatches on. Frozen; the source of truth for the wire event vocabulary.\n *\n * @remarks\n * - `pending` — a serialized {@link import('./types.js').PendingForm} to dispatch and answer.\n * - `expire` — an `{ id }` payload: the broker expired a parked prompt (the client drops it).\n * - `shutdown` — the broker is going away; the client disconnects (no auto-reconnect) but stays reusable.\n */\nexport const SSE_EVENTS = Object.freeze({\n\tpending: 'pending',\n\texpire: 'expire',\n\tshutdown: 'shutdown',\n})\n\n/** The auth-token request header the {@link import('./types.js').PromptClientInterface} sends. */\nexport const HEADER_TOKEN = 'x-orkestrel-token'\n\n/** The `Accept` header value that opens the broker's SSE stream. */\nexport const ACCEPT_EVENT_STREAM = 'text/event-stream'\n\n/**\n * The maximum number of characters the {@link import('./types.js').PromptClientInterface} lets its\n * SSE parser buffer before treating the stream as hostile — 1 MiB, comfortably above any\n * legitimate prompt payload. Passed as the `limit` to `createSSEParser` so an unterminated\n * or oversized `data:` field cannot grow the buffer without bound (a memory-exhaustion guard).\n */\nexport const SSE_BUFFER_LIMIT = 1_048_576\n","import type { TerminalErrorCode } from './types.js'\n\n// AGENTS §12: a real error type, not a sentinel. Callers branch on the machine-readable\n// `error.code` rather than parsing the message, and the guard narrows with `instanceof`,\n// mirroring the agents-module errors.\n\n/**\n * The error the terminal surfaces for its own refusals: parking on a destroyed or full broker, an\n * unusable driver stream, a manager routing fault, or a ctrl-c cancellation. A parked form's own\n * lifecycle failures reject through the form's `answer` with the form package's error, never with\n * this one.\n *\n * @remarks\n * Carries a {@link TerminalErrorCode} and an optional `context` bag naming the offending values:\n * `{ cap }` on `LIMIT`, `{ to, known }` on `TARGET`, and `{ from, to, path }` on `DEADLOCK`. Narrow\n * a caught value with {@link isTerminalError} and branch on `error.code`.\n */\nexport class TerminalError extends Error {\n\t/** The machine-readable condition — see {@link TerminalErrorCode}. */\n\treadonly code: TerminalErrorCode\n\t/** An optional context bag naming the offending values — see the class {@link TerminalError remarks}. */\n\treadonly context?: Readonly<Record<string, unknown>>\n\n\tconstructor(\n\t\tcode: TerminalErrorCode,\n\t\tmessage: string,\n\t\tcontext?: Readonly<Record<string, unknown>>,\n\t) {\n\t\tsuper(message)\n\t\tthis.name = 'TerminalError'\n\t\tthis.code = code\n\t\tif (context !== undefined) this.context = context\n\t}\n}\n\n/**\n * Narrow an unknown caught value to a {@link TerminalError}.\n *\n * @param value - The value to test (typically a `catch` binding or a rejected prompt call)\n * @returns `true` when `value` is a {@link TerminalError}\n *\n * @example\n * ```ts\n * try {\n * \tawait terminal.ask(form)\n * } catch (error) {\n * \tif (isTerminalError(error) && error.code === 'CANCEL') {\n * \t\t// the person aborted\n * \t}\n * }\n * ```\n */\nexport function isTerminalError(value: unknown): value is TerminalError {\n\treturn value instanceof TerminalError\n}\n","import type { PendingForm, PendingFormStatus, TerminalSnapshot, WireEvent } from './types.js'\nimport type { Guard } from '@orkestrel/contract'\nimport {\n\tisNonEmptyString,\n\tisNumber,\n\tisRecord,\n\tisString,\n\tliteralOf,\n\trecordOf,\n} from '@orkestrel/contract'\n\n/** Narrow an unknown value to a {@link PendingFormStatus}. */\nexport const isPendingFormStatus: Guard<PendingFormStatus> = literalOf(\n\t'pending',\n\t'answered',\n\t'expired',\n)\n\n/**\n * Narrow an unknown wire value to a {@link PendingForm} envelope.\n *\n * @remarks\n * This guard checks the transport record and proves only that `schema` is a record. The Form\n * package's `parseForm` owns the schema payload and its semantic audit.\n *\n * @param value - The decoded wire value to inspect\n * @returns Whether the value is a complete pending-form envelope\n */\nexport function isPendingForm(value: unknown): value is PendingForm {\n\treturn recordOf(\n\t\t{\n\t\t\tid: isNonEmptyString,\n\t\t\tschema: isRecord,\n\t\t\tstatus: isPendingFormStatus,\n\t\t\ttime: isNumber,\n\t\t\tfrom: isString,\n\t\t\tto: isString,\n\t\t},\n\t\t['from', 'to'],\n\t)(value)\n}\n\n/**\n * Narrow an unknown value to a transport-neutral {@link WireEvent}.\n *\n * @param value - The candidate wire event\n * @returns Whether the value carries an event name, serialized data, and an optional id\n */\nexport const isWireEvent: Guard<WireEvent> = recordOf(\n\t{ event: isString, data: isString, id: isString },\n\t['id'],\n)\n\n/** Narrow an unknown value to a {@link TerminalSnapshot}. */\nexport const isTerminalSnapshot: Guard<TerminalSnapshot> = recordOf(\n\t{ id: isNonEmptyString, timeout: isNumber },\n\t['timeout'],\n)\n","import type {\n\tFetchInit,\n\tKeyEvent,\n\tPendingForm,\n\tPromptIcon,\n\tPromptRole,\n\tPromptStep,\n\tPromptTheme,\n\tPromptThemeOptions,\n\tTimerCancel,\n\tWireEvent,\n} from './types.js'\nimport type { Style, StylerInterface } from '@orkestrel/console'\nimport type {\n\tCheckboxField,\n\tConfirmField,\n\tEditorField,\n\tFormField,\n\tFormSchema,\n\tPasswordField,\n\tSelectField,\n\tTextField,\n} from '@orkestrel/form'\nimport {\n\tCONTROL_NAMES,\n\tDEFAULT_MASK,\n\tDEFAULT_PROMPT_THEME,\n\tPROMPT_ROLES,\n\tSEQUENCE_NAMES,\n} from './constants.js'\nimport { isString } from '@orkestrel/contract'\nimport { createStyler, freezeStyle, strip, stripControls } from '@orkestrel/console'\n\n// The PURE prompt core implementation — all EXPORTED, all pure, all unit-tested (AGENTS §5):\n// the key decoder, schema sanitization, per-field view renderers, and the six `create*State`\n// factories + `*Reduce` reducers. No `node:*`, no I/O, no events. Form owns validation and\n// settlement; these reducers only turn keys into candidate field values.\n\n// === Key decoding\n\n/**\n * Decode one keypress's bytes into a {@link KeyEvent} — total, never throws. A `Uint8Array` is\n * read as UTF-8; the resulting string is matched against the known control bytes\n * ({@link CONTROL_NAMES}) and escape sequences ({@link SEQUENCE_NAMES}), falling back to a\n * single printable character. An unrecognized sequence yields `name: ''` with the raw `sequence`\n * preserved.\n *\n * @remarks\n * - **Single control byte.** A one-character control input (`return` / `backspace` / `tab` /\n * `escape` / `space`, or a Ctrl combo `c` / `d` / `u` / `a` / `e`) is looked up in\n * {@link CONTROL_NAMES}, carrying its `ctrl` flag.\n * - **Escape sequence.** A multi-byte ESC sequence (`up` / `down` / `left` / `right` in BOTH the\n * `ESC[A` and `ESCOA` forms, plus `home` / `end` / `delete`) is looked up in\n * {@link SEQUENCE_NAMES} and flagged `meta`.\n * - **Printable character.** A single printable character becomes `name` = that character, with\n * `shift` set when it is an uppercase letter. A multi-code-point printable (an emoji, a pasted\n * run) keeps its first code point as the name and the whole input as `sequence`.\n * - **Unknown.** Anything else (an unrecognized escape, an empty input) yields `name: ''` —\n * total, so the driver never crashes on a stray byte.\n *\n * @param input - The raw keypress bytes, as a string or `Uint8Array`\n * @returns The decoded {@link KeyEvent}\n *\n * @example\n * ```ts\n * parseKey('\\r') // { name: 'return', sequence: '\\r', ctrl: false, meta: false, shift: false }\n * parseKey('\\x1b[A') // { name: 'up', sequence: '\\x1b[A', ctrl: false, meta: true, shift: false }\n * parseKey('A') // { name: 'A', sequence: 'A', ctrl: false, meta: false, shift: true }\n * parseKey('\\x03') // { name: 'c', sequence: '\\x03', ctrl: true, meta: false, shift: false }\n * ```\n */\nexport function parseKey(input: string | Uint8Array): KeyEvent {\n\tconst sequence = isString(input) ? input : new TextDecoder().decode(input)\n\n\t// A known multi-byte escape sequence (arrows / home / end / delete) — flagged `meta`.\n\tconst sequenceName = SEQUENCE_NAMES[sequence]\n\tif (sequenceName !== undefined) {\n\t\treturn { name: sequenceName, sequence, ctrl: false, meta: true, shift: false }\n\t}\n\n\t// A known single control byte (return / backspace / tab / escape / space / a ctrl combo).\n\tconst control = CONTROL_NAMES[sequence]\n\tif (control !== undefined) {\n\t\treturn { name: control.name, sequence, ctrl: control.ctrl, meta: false, shift: false }\n\t}\n\n\t// A printable character — one or more code points, the first naming the key.\n\tconst points = [...sequence]\n\tconst first = points[0]\n\tif (first !== undefined && isPrintable(first)) {\n\t\treturn { name: first, sequence, ctrl: false, meta: false, shift: first !== first.toLowerCase() }\n\t}\n\n\t// Anything else (an unrecognized escape, an empty input) — total, never a throw.\n\treturn { name: '', sequence, ctrl: false, meta: false, shift: false }\n}\n\n/** Whether a single character is a printable (non-control) character — used by {@link parseKey}'s char fallback. */\nexport function isPrintable(character: string): boolean {\n\tif (character.length === 0) return false\n\tconst code = character.codePointAt(0)\n\tif (code === undefined) return false\n\t// Exclude the C0 controls (0–31) and DEL (127); everything at or above space is printable.\n\treturn code >= 32 && code !== 127\n}\n\n// === Prompt theme\n\n/**\n * Build a complete {@link PromptTheme} by merging a partial one over\n * {@link DEFAULT_PROMPT_THEME}, leaf by leaf — each supplied icon replaces that glyph, each\n * supplied role replaces that {@link Style}, and everything else keeps its default. Each supplied\n * style is snapshotted through the console module's own\n * {@link import('@orkestrel/console').freezeStyle}, so the result is deeply frozen and a caller\n * mutating its own attribute list afterwards cannot reach into a built theme.\n *\n * @param options - The partial theme to merge, or `undefined` for the defaults\n * @returns The resolved, deeply frozen theme every prompt state carries\n *\n * @example\n * ```ts\n * createPromptTheme() // the defaults\n * createPromptTheme({\n * \ticons: { pointer: '=>' },\n * \troles: { message: { foreground: 'magenta', attributes: ['bold'] } },\n * })\n * ```\n */\nexport function createPromptTheme(options?: PromptThemeOptions): PromptTheme {\n\tconst icons: Record<PromptIcon, string> = { ...DEFAULT_PROMPT_THEME.icons, ...options?.icons }\n\tconst roles: Record<PromptRole, Style> = { ...DEFAULT_PROMPT_THEME.roles }\n\tfor (const role of PROMPT_ROLES) {\n\t\tconst style = options?.roles?.[role]\n\t\tif (style !== undefined) roles[role] = freezeStyle(style)\n\t}\n\treturn Object.freeze({ icons: Object.freeze(icons), roles: Object.freeze(roles) })\n}\n\n/**\n * Sanitize text for one single-line display slot. Composes console's ANSI {@link strip} and C0\n * {@link stripControls} passes with removal of tab, line feed, and carriage return.\n *\n * @param text - The text to sanitize for a glyph or hint slot\n * @returns The text with ANSI sequences, every C0 control character, and DEL removed\n *\n * @example\n * ```ts\n * sanitizeDisplayText('Q\\rOVERWRITE\\nNEXT\\tX') // 'QOVERWRITENEXTX'\n * ```\n */\nexport function sanitizeDisplayText(text: string): string {\n\treturn stripControls(strip(text)).replaceAll('\\t', '').replaceAll('\\n', '').replaceAll('\\r', '')\n}\n\n/**\n * Sanitize every terminal-readable string in a parsed form schema.\n *\n * @remarks\n * Display strings pass through {@link sanitizeDisplayText}: labels, help, placeholders, masks,\n * choice labels and help, file accept entries, and pattern sources. Identity and answer strings\n * stay verbatim: schema, group, and field names, group references, choice values, and defaults.\n * Rewriting those would sever the rendering copy from the authoritative form. Field metadata is\n * removed because terminal neither renders nor interprets it. Pattern sources are sanitized as\n * text only and are never compiled or executed here.\n *\n * @param schema - A schema already accepted by the Form package's `parseForm`\n * @returns A new schema with terminal-readable strings sanitized and field metadata omitted\n *\n * @example\n * ```ts\n * sanitizeSchema({ fields: [{ control: 'text', name: 'na\\u001bme', label: 'N\\u0000ame' }] })\n * // { fields: [{ control: 'text', name: 'na\\u001bme', label: 'Name' }] }\n * ```\n */\nexport function sanitizeSchema(schema: FormSchema): FormSchema {\n\tconst groups = schema.groups?.map((group) => ({\n\t\tname: group.name,\n\t\tlabel: sanitizeDisplayText(group.label),\n\t\t...(group.help !== undefined ? { help: sanitizeDisplayText(group.help) } : {}),\n\t}))\n\tconst fields: FormField[] = []\n\tfor (const source of schema.fields) {\n\t\tconst { meta: _meta, ...field } = source\n\t\tconst rule =\n\t\t\tfield.rule === undefined\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\t...field.rule,\n\t\t\t\t\t\t...(field.rule.pattern !== undefined\n\t\t\t\t\t\t\t? { pattern: sanitizeDisplayText(field.rule.pattern) }\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t}\n\t\tconst shared = {\n\t\t\tname: field.name,\n\t\t\t...(field.label !== undefined ? { label: sanitizeDisplayText(field.label) } : {}),\n\t\t\t...(field.help !== undefined ? { help: sanitizeDisplayText(field.help) } : {}),\n\t\t\t...(field.group !== undefined ? { group: field.group } : {}),\n\t\t\t...(rule !== undefined ? { rule } : {}),\n\t\t}\n\n\t\tswitch (field.control) {\n\t\t\tcase 'text':\n\t\t\tcase 'editor': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\t...(field.placeholder !== undefined\n\t\t\t\t\t\t? { placeholder: sanitizeDisplayText(field.placeholder) }\n\t\t\t\t\t\t: {}),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'password': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\t...(field.mask !== undefined ? { mask: sanitizeDisplayText(field.mask) } : {}),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'number': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\t...(field.placeholder !== undefined\n\t\t\t\t\t\t? { placeholder: sanitizeDisplayText(field.placeholder) }\n\t\t\t\t\t\t: {}),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'date':\n\t\t\tcase 'time':\n\t\t\tcase 'datetime':\n\t\t\tcase 'color': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'confirm': {\n\t\t\t\tfields.push({ ...field, ...shared })\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'select': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\tchoices: field.choices.map((choice) => ({\n\t\t\t\t\t\t...choice,\n\t\t\t\t\t\tvalue: choice.value,\n\t\t\t\t\t\tlabel: sanitizeDisplayText(choice.label),\n\t\t\t\t\t\t...(choice.help !== undefined ? { help: sanitizeDisplayText(choice.help) } : {}),\n\t\t\t\t\t})),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'checkbox': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\tchoices: field.choices.map((choice) => ({\n\t\t\t\t\t\t...choice,\n\t\t\t\t\t\tvalue: choice.value,\n\t\t\t\t\t\tlabel: sanitizeDisplayText(choice.label),\n\t\t\t\t\t\t...(choice.help !== undefined ? { help: sanitizeDisplayText(choice.help) } : {}),\n\t\t\t\t\t})),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'file': {\n\t\t\t\tfields.push({\n\t\t\t\t\t...field,\n\t\t\t\t\t...shared,\n\t\t\t\t\t...(field.accept !== undefined ? { accept: field.accept.map(sanitizeDisplayText) } : {}),\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\treturn {\n\t\t...(schema.name !== undefined ? { name: schema.name } : {}),\n\t\t...(schema.label !== undefined ? { label: sanitizeDisplayText(schema.label) } : {}),\n\t\t...(schema.help !== undefined ? { help: sanitizeDisplayText(schema.help) } : {}),\n\t\t...(groups !== undefined ? { groups } : {}),\n\t\tfields,\n\t}\n}\n\n/**\n * Sanitize every glyph a wire-supplied {@link PromptThemeOptions} carries for a single-line display\n * slot. Only the icons need it: a role is guard-narrowed to a console {@link Style}, whose colors\n * and attributes are fixed name sets, so no role can carry a byte a terminal would act on.\n *\n * @param theme - The narrowed theme options a remote prompt supplied\n * @returns The same theme with every supplied glyph sanitized for a single-line display slot\n */\nexport function sanitizeThemeIcons(theme: PromptThemeOptions): PromptThemeOptions {\n\tconst icons = theme.icons\n\tif (icons === undefined) return theme\n\tconst sanitized: Record<string, string> = {}\n\tfor (const [icon, glyph] of Object.entries(icons)) sanitized[icon] = sanitizeDisplayText(glyph)\n\treturn { ...theme, icons: sanitized }\n}\n\n// === Shared view helpers\n\n/** The styled prompt-message header (`? message`) — the leading line every active prompt view shares, themed by the `question` + `message` roles. */\nexport function promptHeader(styler: StylerInterface, theme: PromptTheme, message: string): string {\n\treturn `${styler.render(theme.roles.question, theme.icons.question)} ${styler.render(theme.roles.message, message)}`\n}\n\n/**\n * Render a prompt header followed by a key hint painted with the `hint` role, or the header alone\n * when no hint is supplied.\n *\n * @param styler - The console styler that renders each role\n * @param theme - The resolved prompt theme\n * @param message - The prompt's question text\n * @param hint - The optional key hint to append\n * @returns The rendered header with the optional hint\n */\nexport function hintedHeader(\n\tstyler: StylerInterface,\n\ttheme: PromptTheme,\n\tmessage: string,\n\thint?: string,\n): string {\n\tconst head = promptHeader(styler, theme, message)\n\treturn hint === undefined ? head : `${head} ${styler.render(theme.roles.hint, hint)}`\n}\n\n/** The styled submit line (`✔ message`) — the committed header an interactive prompt shows once resolved, themed by the `success` + `message` roles. */\nexport function submitHeader(styler: StylerInterface, theme: PromptTheme, message: string): string {\n\treturn `${styler.render(theme.roles.success, theme.icons.success)} ${styler.render(theme.roles.message, message)}`\n}\n\n/** The styled error line (`✖ message`) a form driver appends for a field failure. */\nexport function errorLine(styler: StylerInterface, theme: PromptTheme, message: string): string {\n\treturn `${styler.render(theme.roles.error, theme.icons.error)} ${styler.render(theme.roles.error, message)}`\n}\n\n// === Input prompt\n\n/**\n * Build the initial text-field key state.\n *\n * @param field - The text field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createInputState(\n\tfield: TextField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tdefault: field.default ?? '',\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t\tvalue: '',\n\t}\n}\n\n/** Render a text-field key state as a styled view. */\nexport function inputView(state: ReturnType<typeof createInputState>): string {\n\tconst content = state.value.length > 0 ? state.value : state.default\n\tconst role = state.value.length > 0 ? state.theme.roles.content : state.theme.roles.hint\n\tconst shown = state.styler.render(role, sanitizeDisplayText(content))\n\treturn `${promptHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)} ${shown}`\n}\n\n/**\n * Advance an input prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`\n * reducer. Printable characters extend the value; backspace shrinks it; ctrl-u clears it; ctrl-c\n * cancels; return produces the candidate value, with an empty line falling back to the default.\n */\nexport function inputReduce(\n\tstate: ReturnType<typeof createInputState>,\n\tkey: KeyEvent,\n): PromptStep<string, ReturnType<typeof createInputState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: inputView(state), status: 'cancel' }\n\n\tif (key.name === 'return') {\n\t\tconst answer = state.value.length > 0 ? state.value : state.default\n\t\tconst next = { ...state, value: answer }\n\t\treturn {\n\t\t\tstate: next,\n\t\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, sanitizeDisplayText(answer))}`,\n\t\t\tstatus: 'submit',\n\t\t\tvalue: answer,\n\t\t}\n\t}\n\n\tconst value = editLine(state.value, key)\n\tif (value === undefined) return { state, view: inputView(state), status: 'active' }\n\tconst next = { ...state, value }\n\treturn { state: next, view: inputView(next), status: 'active' }\n}\n\n// === Password prompt\n\n/**\n * Build the initial password-field key state.\n *\n * @param field - The password field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createPasswordState(\n\tfield: PasswordField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tmask: sanitizeDisplayText(field.mask ?? DEFAULT_MASK),\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t\tvalue: '',\n\t}\n}\n\n/** Render a password-field key state as a styled view. */\nexport function passwordView(state: ReturnType<typeof createPasswordState>): string {\n\tconst masked = state.styler.render(\n\t\tstate.theme.roles.content,\n\t\tstate.mask.repeat(state.value.length),\n\t)\n\treturn `${promptHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)} ${masked}`\n}\n\n/**\n * Advance a password prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`\n * reducer. Identical line-editing to {@link inputReduce} (printable extends, backspace shrinks,\n * ctrl-u clears, ctrl-c cancels) but the view masks the value. Return produces the candidate value.\n */\nexport function passwordReduce(\n\tstate: ReturnType<typeof createPasswordState>,\n\tkey: KeyEvent,\n): PromptStep<string, ReturnType<typeof createPasswordState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: passwordView(state), status: 'cancel' }\n\n\tif (key.name === 'return') {\n\t\treturn {\n\t\t\tstate,\n\t\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, state.mask.repeat(state.value.length))}`,\n\t\t\tstatus: 'submit',\n\t\t\tvalue: state.value,\n\t\t}\n\t}\n\n\tconst value = editLine(state.value, key)\n\tif (value === undefined) return { state, view: passwordView(state), status: 'active' }\n\tconst next = { ...state, value }\n\treturn { state: next, view: passwordView(next), status: 'active' }\n}\n\n// === Confirm prompt\n\n/**\n * Build the initial confirm-field key state.\n *\n * @param field - The confirm field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createConfirmState(\n\tfield: ConfirmField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tdefault: field.default ?? false,\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t}\n}\n\n/**\n * Render a confirm-field key state as a styled view. The selected role paints the default letter.\n */\nexport function confirmView(state: ReturnType<typeof createConfirmState>): string {\n\tconst head = promptHeader(state.styler, state.theme, state.message)\n\tconst answer = state.default\n\t\t? `${state.styler.render(state.theme.roles.selected, 'Y')}${state.styler.render(state.theme.roles.hint, '/n')}`\n\t\t: `${state.styler.render(state.theme.roles.hint, 'y/')}${state.styler.render(state.theme.roles.selected, 'N')}`\n\treturn `${head} ${state.styler.render(state.theme.roles.hint, '(')}${answer}${state.styler.render(state.theme.roles.hint, ')')}`\n}\n\n/**\n * Advance a confirm prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<boolean>`\n * reducer. `y` / `Y` submits `true`, `n` / `N` submits `false`, return on an empty line submits\n * the `default`, ctrl-c cancels; any other key is ignored (stays active).\n */\nexport function confirmReduce(\n\tstate: ReturnType<typeof createConfirmState>,\n\tkey: KeyEvent,\n): PromptStep<boolean, ReturnType<typeof createConfirmState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: confirmView(state), status: 'cancel' }\n\n\tlet answer: boolean | undefined\n\tconst choice = key.name.toLowerCase()\n\tif (key.name === 'return') answer = state.default\n\telse if (choice === 'y') answer = true\n\telse if (choice === 'n') answer = false\n\n\tif (answer === undefined) return { state, view: confirmView(state), status: 'active' }\n\treturn {\n\t\tstate,\n\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, answer ? 'yes' : 'no')}`,\n\t\tstatus: 'submit',\n\t\tvalue: answer,\n\t}\n}\n\n// === Select prompt\n\n/**\n * Build the initial select-field key state.\n *\n * @param field - The select field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createSelectState(\n\tfield: SelectField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\tconst choices = [...field.choices]\n\tconst index = choices.findIndex((choice) => choice.value === field.default)\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tchoices,\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t\tfocused: index >= 0 ? index : 0,\n\t}\n}\n\n/** Render a select-field key state as a multi-line styled view. */\nexport function selectView(state: ReturnType<typeof createSelectState>): string {\n\tconst lines = state.choices.map((choice, index) => {\n\t\tconst active = index === state.focused\n\t\tconst pointer = active\n\t\t\t? state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)\n\t\t\t: ' '\n\t\tconst marker = active\n\t\t\t? state.styler.render(state.theme.roles.selected, state.theme.icons.selected)\n\t\t\t: state.styler.render(state.theme.roles.muted, state.theme.icons.dot)\n\t\tconst label = active\n\t\t\t? state.styler.render(state.theme.roles.focus, choice.label)\n\t\t\t: state.styler.render(state.theme.roles.content, choice.label)\n\t\tconst description =\n\t\t\tchoice.help === undefined\n\t\t\t\t? ''\n\t\t\t\t: ` ${state.styler.render(state.theme.roles.description, choice.help)}`\n\t\treturn `${pointer} ${marker} ${label}${description}`\n\t})\n\treturn [promptHeader(state.styler, state.theme, state.message), ...lines].join('\\n')\n}\n\n/**\n * Advance a select prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`\n * reducer. `up` / `down` (and `k` / `j`) move the focus, WRAPPING at the ends; return submits the\n * focused choice's `value`; ctrl-c cancels. An empty choice list can never submit (a higher layer\n * guards against it); any other key is ignored.\n */\nexport function selectReduce(\n\tstate: ReturnType<typeof createSelectState>,\n\tkey: KeyEvent,\n): PromptStep<string, ReturnType<typeof createSelectState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: selectView(state), status: 'cancel' }\n\n\tconst count = state.choices.length\n\tif (count === 0) return { state, view: selectView(state), status: 'active' }\n\n\tif (key.name === 'up' || key.name === 'k') {\n\t\tconst next = { ...state, focused: (state.focused - 1 + count) % count }\n\t\treturn { state: next, view: selectView(next), status: 'active' }\n\t}\n\tif (key.name === 'down' || key.name === 'j') {\n\t\tconst next = { ...state, focused: (state.focused + 1) % count }\n\t\treturn { state: next, view: selectView(next), status: 'active' }\n\t}\n\tif (key.name === 'return') {\n\t\tconst choice = state.choices[state.focused]\n\t\tconst value = choice?.value ?? ''\n\t\treturn {\n\t\t\tstate,\n\t\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, choice?.label ?? '')}`,\n\t\t\tstatus: 'submit',\n\t\t\tvalue,\n\t\t}\n\t}\n\treturn { state, view: selectView(state), status: 'active' }\n}\n\n// === Checkbox prompt\n\n/**\n * Build the initial checkbox-field key state.\n *\n * @param field - The checkbox field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createCheckboxState(\n\tfield: CheckboxField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\tconst choices = [...field.choices]\n\tconst checked: readonly number[] = choices.reduce<number[]>((indices, choice, index) => {\n\t\tif (field.default?.includes(choice.value) === true) indices.push(index)\n\t\treturn indices\n\t}, [])\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tchoices,\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t\tfocused: 0,\n\t\tchecked,\n\t}\n}\n\n/** Render a checkbox-field key state as a multi-line styled view. */\nexport function checkboxView(state: ReturnType<typeof createCheckboxState>): string {\n\tconst lines = state.choices.map((choice, index) => {\n\t\tconst active = index === state.focused\n\t\tconst ticked = state.checked.includes(index)\n\t\tconst pointer = active\n\t\t\t? state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)\n\t\t\t: ' '\n\t\tconst box = ticked\n\t\t\t? state.styler.render(state.theme.roles.selected, state.theme.icons.checked)\n\t\t\t: state.styler.render(state.theme.roles.muted, state.theme.icons.unchecked)\n\t\tconst label = active\n\t\t\t? state.styler.render(state.theme.roles.focus, choice.label)\n\t\t\t: state.styler.render(state.theme.roles.content, choice.label)\n\t\tconst description =\n\t\t\tchoice.help === undefined\n\t\t\t\t? ''\n\t\t\t\t: ` ${state.styler.render(state.theme.roles.description, choice.help)}`\n\t\treturn `${pointer} ${box} ${label}${description}`\n\t})\n\tconst summary = state.styler.render(state.theme.roles.hint, `${state.checked.length} selected`)\n\tconst body = [promptHeader(state.styler, state.theme, state.message), ...lines, summary].join(\n\t\t'\\n',\n\t)\n\treturn body\n}\n\n/**\n * Advance a checkbox prompt by one {@link KeyEvent} — the pure\n * `(state, key) → PromptStep<readonly string[]>` reducer. `up` / `down` (and `k` / `j`) move the\n * focus (wrapping); `space` toggles the focused index in the checked set; return submits the\n * checked values in choice order; ctrl-c cancels. The form applies selection-count rules.\n */\nexport function checkboxReduce(\n\tstate: ReturnType<typeof createCheckboxState>,\n\tkey: KeyEvent,\n): PromptStep<readonly string[], ReturnType<typeof createCheckboxState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: checkboxView(state), status: 'cancel' }\n\n\tconst count = state.choices.length\n\n\tif ((key.name === 'up' || key.name === 'k') && count > 0) {\n\t\tconst next = {\n\t\t\t...state,\n\t\t\tfocused: (state.focused - 1 + count) % count,\n\t\t}\n\t\treturn { state: next, view: checkboxView(next), status: 'active' }\n\t}\n\tif ((key.name === 'down' || key.name === 'j') && count > 0) {\n\t\tconst next = { ...state, focused: (state.focused + 1) % count }\n\t\treturn { state: next, view: checkboxView(next), status: 'active' }\n\t}\n\tif (key.name === 'space' && count > 0) {\n\t\tconst checked = toggleIndex(state.checked, state.focused)\n\t\tconst next = { ...state, checked }\n\t\treturn { state: next, view: checkboxView(next), status: 'active' }\n\t}\n\tif (key.name === 'return') {\n\t\tconst ordered = [...state.checked].sort((a, b) => a - b)\n\t\tconst values = ordered\n\t\t\t.map((index) => state.choices[index]?.value)\n\t\t\t.filter((value): value is string => value !== undefined)\n\t\tconst summary = ordered\n\t\t\t.map((index) => state.choices[index]?.label)\n\t\t\t.filter((name): name is string => name !== undefined)\n\t\t\t.join(', ')\n\t\treturn {\n\t\t\tstate,\n\t\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, summary)}`,\n\t\t\tstatus: 'submit',\n\t\t\tvalue: values,\n\t\t}\n\t}\n\treturn { state, view: checkboxView(state), status: 'active' }\n}\n\n/** Toggle `index` in a readonly index list — copy-on-write, returning the new sorted-by-insertion list. */\nexport function toggleIndex(indices: readonly number[], index: number): readonly number[] {\n\treturn indices.includes(index) ? indices.filter((i) => i !== index) : [...indices, index]\n}\n\n// === Editor prompt\n\n/**\n * Build the initial editor-field key state.\n *\n * @param field - The editor field to render\n * @param styler - The styler used to render the view\n * @param theme - The optional terminal theme\n * @returns The initial immutable key state\n */\nexport function createEditorState(\n\tfield: EditorField,\n\tstyler: StylerInterface = createStyler(),\n\ttheme?: PromptThemeOptions,\n) {\n\tconst lines: readonly string[] = []\n\treturn {\n\t\tmessage: sanitizeDisplayText(field.label ?? field.name),\n\t\tdefault: field.default ?? '',\n\t\tstyler,\n\t\ttheme: createPromptTheme(theme),\n\t\tlines,\n\t\tcurrent: '',\n\t}\n}\n\n/**\n * Render an editor-field key state as a multi-line styled view with its finish hint.\n */\nexport function editorView(state: ReturnType<typeof createEditorState>): string {\n\tconst head = hintedHeader(state.styler, state.theme, state.message, '(Ctrl+D to finish)')\n\tconst pointer = state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)\n\tconst committed = state.lines.map((line) => state.styler.render(state.theme.roles.content, line))\n\tconst body = [\n\t\t...committed,\n\t\t`${pointer} ${state.styler.render(state.theme.roles.content, state.current)}`,\n\t]\n\treturn [head, ...body].join('\\n')\n}\n\n/**\n * Advance an editor prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`\n * reducer. Printable characters extend the current line; backspace shrinks it; return commits the\n * current line and starts a fresh one; ctrl-d FINISHES (joining all lines, falling back to the\n * default when empty); ctrl-c cancels. The form validates the candidate after the driver fills it.\n */\nexport function editorReduce(\n\tstate: ReturnType<typeof createEditorState>,\n\tkey: KeyEvent,\n): PromptStep<string, ReturnType<typeof createEditorState>> {\n\tif (key.ctrl && key.name === 'c') return { state, view: editorView(state), status: 'cancel' }\n\n\tif (key.ctrl && key.name === 'd') {\n\t\tconst lines = state.current.length > 0 ? [...state.lines, state.current] : state.lines\n\t\tconst joined = lines.join('\\n')\n\t\tconst answer = joined.length > 0 ? joined : state.default\n\t\treturn {\n\t\t\tstate,\n\t\t\tview: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, `${String(lines.length)} line${lines.length === 1 ? '' : 's'}`)}`,\n\t\t\tstatus: 'submit',\n\t\t\tvalue: answer,\n\t\t}\n\t}\n\n\tif (key.name === 'return') {\n\t\tconst next = {\n\t\t\t...state,\n\t\t\tlines: [...state.lines, state.current],\n\t\t\tcurrent: '',\n\t\t}\n\t\treturn { state: next, view: editorView(next), status: 'active' }\n\t}\n\n\tconst current = editLine(state.current, key)\n\tif (current === undefined) return { state, view: editorView(state), status: 'active' }\n\tconst next = { ...state, current }\n\treturn { state: next, view: editorView(next), status: 'active' }\n}\n\n// === Shared reducer helpers\n\n/**\n * Apply a single line-editing {@link KeyEvent} to a text buffer — the editing shared by input /\n * password / editor. A printable key appends its character; `backspace` drops the last character;\n * `space` appends a space; ctrl-u clears the line. Returns the new buffer, or `undefined` when the\n * key does not edit the line (so the caller can leave the state untouched).\n */\nexport function editLine(value: string, key: KeyEvent): string | undefined {\n\tif (key.ctrl && key.name === 'u') return ''\n\tif (key.name === 'backspace') return value.slice(0, -1)\n\tif (key.name === 'space') return `${value} `\n\t// A printable key that is not a control / navigation key — `name` is the literal character. Count\n\t// CODE POINTS (not UTF-16 units) so an astral printable (an emoji, a surrogate pair — `name.length`\n\t// 2 but ONE code point) appends instead of being dropped, while a multi-char control name (`up`,\n\t// `return`) is still rejected.\n\tif (!key.ctrl && !key.meta && [...key.name].length === 1 && isPrintable(key.name)) {\n\t\treturn `${value}${key.sequence}`\n\t}\n\treturn undefined\n}\n\n// === Broker + bridge wiring helpers (T-b)\n\n/**\n * The default {@link import('./types.js').TimerHandler} — a thin host `setTimeout` / `clearTimeout`\n * wrapper that arms `callback` after `ms` and returns a {@link TimerCancel}. The deadline seam\n * behind both the {@link import('./Prompt.js').Prompt} broker (its expiry) and the\n * {@link import('./PromptClient.js').PromptClient} (its reconnect backoff); a test injects a\n * deterministic timer instead, so neither entity touches real time.\n */\nexport function defaultTimer(callback: () => void, ms: number): TimerCancel {\n\tconst handle = setTimeout(callback, ms)\n\treturn () => clearTimeout(handle)\n}\n\n/** The default {@link import('./types.js').FetchHandler} — the global `fetch`, adapted to the minimal injected shape the {@link import('./PromptClient.js').PromptClient} uses. */\nexport function globalFetch(input: string, init?: FetchInit): Promise<Response> {\n\treturn fetch(input, init)\n}\n\n/**\n * Whether a caught value is an `AbortError` — the {@link import('./PromptClient.js').PromptClient}\n * distinguishes a deliberate `disconnect` / teardown (an aborted `fetch`) from a real fault, so it\n * exits its connect loop quietly instead of emitting `error` / reconnecting.\n */\nexport function isAbortError(error: unknown): boolean {\n\treturn (error instanceof DOMException || error instanceof Error) && error.name === 'AbortError'\n}\n\n/**\n * Whether `url` is an INSECURE remote endpoint — a plain `http://` URL whose host is NOT a\n * loopback address. Pure string parsing (no `URL` global), so it stays total on malformed input.\n *\n * @remarks\n * A loopback host (`localhost`, `127.0.0.1`, `[::1]`) over `http://` is exempt (local\n * development has no network hop to eavesdrop on); every other `http://` host is insecure.\n * An `https://` URL (or any non-`http://` scheme) is never flagged.\n *\n * @param url - The candidate endpoint URL\n * @returns `true` when `url` is a non-loopback `http://` endpoint\n *\n * @example\n * ```ts\n * isInsecureRemote('http://example.com') // true\n * isInsecureRemote('http://localhost:3000') // false\n * isInsecureRemote('https://example.com') // false\n * ```\n */\nexport function isInsecureRemote(url: string): boolean {\n\tconst prefix = 'http://'\n\tif (!url.startsWith(prefix)) return false\n\tconst rest = url.slice(prefix.length)\n\tconst hostEnd = rest.search(/[/?#]/)\n\tconst authority = hostEnd === -1 ? rest : rest.slice(0, hostEnd)\n\tconst host = authority.includes('@') ? authority.slice(authority.indexOf('@') + 1) : authority\n\tconst hostname = host.startsWith('[')\n\t\t? host.slice(0, host.indexOf(']') + 1)\n\t\t: (host.split(':')[0] ?? '')\n\treturn hostname !== 'localhost' && hostname !== '127.0.0.1' && hostname !== '[::1]'\n}\n\n// === Terminal manager wire seams (transport-neutral, no http dependency)\n\n/** Serialize a parked {@link PendingForm} into a {@link WireEvent}. */\nexport function serializePending(form: PendingForm): WireEvent {\n\treturn { event: 'pending', data: JSON.stringify(form), id: form.id }\n}\n\n/** Serialize a parked prompt's expiry into a {@link WireEvent} — event `'expire'`, `data` the JSON-stringified `{ id }` payload. */\nexport function serializeExpire(id: string): WireEvent {\n\treturn { event: 'expire', data: JSON.stringify({ id }) }\n}\n\n/** The {@link WireEvent} a broker/manager sends when it is going away — event `'shutdown'`, no payload. */\nexport function serializeShutdown(): WireEvent {\n\treturn { event: 'shutdown', data: '' }\n}\n","import type {\n\tAnswerError,\n\tParked,\n\tParkRequest,\n\tPendingForm,\n\tPromptEventMap,\n\tPromptInterface,\n\tPromptOptions,\n\tTimerHandler,\n} from './types.js'\nimport type { Result } from '@orkestrel/contract'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport type { FieldError, FormInterface, FormResult, FormValues } from '@orkestrel/form'\nimport { DEFAULT_PROMPT_TIMEOUT_MS } from './constants.js'\nimport { TerminalError } from './errors.js'\nimport { defaultTimer } from './helpers.js'\nimport { attempt } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { isFieldError, isFormError, serializeForm } from '@orkestrel/form'\n\n/**\n * The headless form broker. It parks live forms, exposes their serialized schemas, and applies\n * remote answers to the authoritative form.\n *\n * @remarks\n * A parked record carries one call to `serializeForm`. A failed fill or submit leaves the record\n * parked for another answer. A successful submit settles the form once, emits `answer`, and removes\n * the record. Timeout and teardown abandon every unsettled form through its own `destroy` method.\n *\n * @example\n * ```ts\n * const form = createForm({ fields: [{ control: 'text', name: 'name' }] })\n * const prompt = createPrompt()\n * const id = prompt.park(form)\n * prompt.answer(id, { name: 'Ada' })\n * await form.answer // { name: 'Ada' }\n * ```\n */\nexport class Prompt implements PromptInterface {\n\treadonly #timeout: number\n\treadonly #timer: TimerHandler\n\treadonly #cap: number | undefined\n\treadonly #parked = new Map<string, Parked>()\n\treadonly #emitter: Emitter<PromptEventMap>\n\t#destroyed = false\n\n\tconstructor(options?: PromptOptions) {\n\t\tthis.#timeout = options?.timeout ?? DEFAULT_PROMPT_TIMEOUT_MS\n\t\tthis.#timer = options?.timer ?? defaultTimer\n\t\tthis.#cap = options?.cap\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options?.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options?.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t}\n\n\tget emitter(): EmitterInterface<PromptEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget count(): number {\n\t\treturn this.#parked.size\n\t}\n\n\tpending(): readonly PendingForm[]\n\tpending(id: string): PendingForm | undefined\n\tpending(id?: string): readonly PendingForm[] | PendingForm | undefined {\n\t\tif (id !== undefined) return this.#parked.get(id)?.pending\n\t\tconst forms: PendingForm[] = []\n\t\tfor (const parked of this.#parked.values()) forms.push(parked.pending)\n\t\treturn forms\n\t}\n\n\tpark(form: FormInterface, request?: ParkRequest): string {\n\t\tif (this.#destroyed) {\n\t\t\tform.destroy()\n\t\t\tthrow new TerminalError('EXPIRE', 'The broker has been destroyed')\n\t\t}\n\t\tif (this.#cap !== undefined && this.#parked.size >= this.#cap) {\n\t\t\tform.destroy()\n\t\t\tthrow new TerminalError('LIMIT', `The parked-form cap (${String(this.#cap)}) was reached`, {\n\t\t\t\tcap: this.#cap,\n\t\t\t})\n\t\t}\n\n\t\tconst id = crypto.randomUUID()\n\t\tconst pending: PendingForm = {\n\t\t\tid,\n\t\t\tschema: serializeForm(form.schema),\n\t\t\tstatus: 'pending',\n\t\t\ttime: Date.now(),\n\t\t\t...(request?.from !== undefined ? { from: request.from } : {}),\n\t\t\t...(request?.to !== undefined ? { to: request.to } : {}),\n\t\t}\n\t\tconst cancel = this.#timer(() => this.#expire(id), this.#timeout)\n\t\tthis.#parked.set(id, { form, pending, cancel })\n\t\tthis.#emitter.emit('pending', pending)\n\t\treturn id\n\t}\n\n\tanswer(id: string, values: FormValues): Result<FormValues, AnswerError> {\n\t\tconst outcome = attempt(() => this.#answer(id, values))\n\t\tif (outcome.success) return outcome.value\n\t\treturn {\n\t\t\tsuccess: false,\n\t\t\terror: {\n\t\t\t\treason: 'rejected',\n\t\t\t\terrors: [{ field: 'form', message: 'The form rejected the answer' }],\n\t\t\t},\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tfor (const id of [...this.#parked.keys()]) this.#expire(id)\n\t\tthis.#emitter.destroy()\n\t}\n\n\t#answer(id: string, values: FormValues): Result<FormValues, AnswerError> {\n\t\tconst parked = this.#parked.get(id)\n\t\tif (parked === undefined || parked.pending.status !== 'pending') {\n\t\t\treturn { success: false, error: { reason: 'unknown' } }\n\t\t}\n\n\t\tconst outcome = attempt(() => this.#submit(parked.form, values))\n\t\tif (!outcome.success) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { reason: 'rejected', errors: this.#errors(outcome.error, parked.form) },\n\t\t\t}\n\t\t}\n\t\tif (!outcome.value.success) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t\terror: { reason: 'rejected', errors: outcome.value.error },\n\t\t\t}\n\t\t}\n\n\t\tparked.cancel()\n\t\tconst answered: Parked = {\n\t\t\t...parked,\n\t\t\tpending: { ...parked.pending, status: 'answered' },\n\t\t}\n\t\tthis.#parked.set(id, answered)\n\t\tthis.#emitter.emit('answer', id, outcome.value.value)\n\t\tthis.#parked.delete(id)\n\t\treturn outcome.value\n\t}\n\n\t#submit(form: FormInterface, values: FormValues): FormResult {\n\t\tfor (const [field, value] of Object.entries(values)) {\n\t\t\tconst outcome = attempt(() => form.fill(field, value))\n\t\t\tif (!outcome.success) {\n\t\t\t\treturn { success: false, error: this.#errors(outcome.error, form, field) }\n\t\t\t}\n\t\t}\n\t\treturn form.submit()\n\t}\n\n\t#errors(error: unknown, form: FormInterface, field?: string): readonly FieldError[] {\n\t\tif (isFormError(error)) {\n\t\t\tif (isFieldError(error.context)) return [error.context]\n\t\t\tconst named = error.context?.field\n\t\t\treturn [\n\t\t\t\t{\n\t\t\t\t\tfield: typeof named === 'string' ? named : this.#field(form, field),\n\t\t\t\t\tmessage: error.message,\n\t\t\t\t},\n\t\t\t]\n\t\t}\n\t\treturn [\n\t\t\t{\n\t\t\t\tfield: this.#field(form, field),\n\t\t\t\tmessage: 'The form rejected the answer',\n\t\t\t},\n\t\t]\n\t}\n\n\t#field(form: FormInterface, field?: string): string {\n\t\treturn field ?? form.schema.fields[0]?.name ?? form.schema.name ?? 'form'\n\t}\n\n\t#expire(id: string): void {\n\t\tconst parked = this.#parked.get(id)\n\t\tif (parked === undefined || parked.pending.status !== 'pending') return\n\t\tparked.cancel()\n\t\tconst expired: Parked = {\n\t\t\t...parked,\n\t\t\tpending: { ...parked.pending, status: 'expired' },\n\t\t}\n\t\tthis.#parked.set(id, expired)\n\t\tparked.form.destroy()\n\t\tthis.#emitter.emit('expire', id)\n\t\tthis.#parked.delete(id)\n\t}\n}\n","import type {\n\tFetchHandler,\n\tPromptClientEventMap,\n\tPromptClientInterface,\n\tPromptClientOptions,\n\tTimerCancel,\n\tTimerHandler,\n} from './types.js'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport type { FieldError, FormInterface, FormSchema, FormValues } from '@orkestrel/form'\nimport type { SSEEvent } from '@orkestrel/sse'\nimport {\n\tACCEPT_EVENT_STREAM,\n\tDEFAULT_RECONNECT_DELAY_MS,\n\tHEADER_TOKEN,\n\tSSE_BUFFER_LIMIT,\n\tSSE_EVENTS,\n} from './constants.js'\nimport {\n\tdefaultTimer,\n\tglobalFetch,\n\tisAbortError,\n\tisInsecureRemote,\n\tsanitizeDisplayText,\n\tsanitizeSchema,\n} from './helpers.js'\nimport { isPendingForm } from './validators.js'\nimport { arrayOf, isBoolean, isRecord, isString, parseJSON } from '@orkestrel/contract'\nimport { Emitter } from '@orkestrel/emitter'\nimport { createForm, isFieldError, parseForm } from '@orkestrel/form'\nimport { createSSEParser } from '@orkestrel/sse'\n\n/**\n * The SSE form bridge. It ingests serialized forms from a remote broker, renders them through a\n * local terminal, and posts answers back without blocking the event stream.\n *\n * @remarks\n * - **Connect + reconnect.** {@link connect} opens the SSE stream and reconnects after a transport\n * drop with the injected backoff unless reconnect is disabled, the client was destroyed, or\n * {@link disconnect} deliberately stopped it.\n * - **Ingest + render.** Each `pending` envelope passes through `isPendingForm`, Form's `parseForm`,\n * and terminal's `sanitizeSchema`, then enters a serial render queue. The SSE reader never awaits\n * that queue, so `expire` and `shutdown` remain live while a person is answering.\n * - **Safe local form.** The rendering copy omits every wire `pattern`, because Form compiles a\n * pattern during local evaluation. The broker's parked form retains it and remains authoritative.\n * - **Refusal retry.** A structured `rejected` response seeds a new rendering form with the values\n * just submitted, applies every {@link FieldError} through `invalidate`, and asks again. No retry\n * counter truncates the loop; acceptance, expiry, and shutdown are its bounds.\n * - **Replay safety.** A replayed id is skipped while it is queued, rendering, or posting. Once an\n * attempt ends, a later delivery of that id may be rendered again.\n *\n * @example\n * ```ts\n * const client = createPromptClient({\n * \turl: 'http://localhost:3001/prompts',\n * \tterminal: createTerminal(),\n * })\n * await client.connect()\n * ```\n */\nexport class PromptClient implements PromptClientInterface {\n\treadonly url: string\n\treadonly #terminal: PromptClientOptions['terminal']\n\treadonly #token: string | undefined\n\treadonly #reconnect: boolean\n\treadonly #delay: number\n\treadonly #fetch: FetchHandler\n\treadonly #timer: TimerHandler\n\treadonly #emitter: Emitter<PromptClientEventMap>\n\t#controller: AbortController | undefined\n\t#backoff: TimerCancel | undefined\n\t#wake: (() => void) | undefined\n\t#connecting = false\n\t#connected = false\n\t#destroyed = false\n\t#draining = false\n\t#warnedInsecureToken = false\n\treadonly #seen = new Set<string>()\n\treadonly #queue = new Map<string, FormSchema>()\n\t#active:\n\t\t| { readonly id: string; readonly form: FormInterface; readonly stopped: boolean }\n\t\t| undefined\n\n\tconstructor(options: PromptClientOptions) {\n\t\tthis.url = options.url\n\t\tthis.#terminal = options.terminal\n\t\tthis.#token = options.token\n\t\tthis.#reconnect = options.reconnect ?? true\n\t\tthis.#delay = options.delay ?? DEFAULT_RECONNECT_DELAY_MS\n\t\tthis.#fetch = options.fetch ?? globalFetch\n\t\tthis.#timer = options.timer ?? defaultTimer\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t}\n\n\tget emitter(): EmitterInterface<PromptClientEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget connected(): boolean {\n\t\treturn this.#connected\n\t}\n\n\tasync connect(): Promise<void> {\n\t\tif (this.#destroyed || this.#connecting) return\n\t\tthis.#connecting = true\n\t\twhile (this.#connecting && !this.#destroyed) {\n\t\t\ttry {\n\t\t\t\tawait this.#stream()\n\t\t\t} catch (error) {\n\t\t\t\tthis.#markDisconnected()\n\t\t\t\tif (this.#destroyed || isAbortError(error)) return\n\t\t\t\tthis.#emitter.emit('error', error)\n\t\t\t}\n\t\t\tif (!this.#reconnect || !this.#connecting || this.#destroyed) return\n\t\t\tawait this.#wait(this.#delay)\n\t\t}\n\t}\n\n\tdisconnect(): void {\n\t\tthis.#connecting = false\n\t\tthis.#controller?.abort()\n\t\tthis.#controller = undefined\n\t\tthis.#backoff?.()\n\t\tthis.#backoff = undefined\n\t\tconst wake = this.#wake\n\t\tthis.#wake = undefined\n\t\twake?.()\n\t\tthis.#markDisconnected()\n\t}\n\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tthis.disconnect()\n\t\tthis.#interrupt()\n\t\tthis.#emitter.destroy()\n\t}\n\n\tasync #stream(): Promise<void> {\n\t\tif (this.#token !== undefined && isInsecureRemote(this.url) && !this.#warnedInsecureToken) {\n\t\t\tthis.#warnedInsecureToken = true\n\t\t\tthis.#emitter.emit(\n\t\t\t\t'error',\n\t\t\t\tnew Error('auth token sent as cleartext over insecure http; use https'),\n\t\t\t)\n\t\t}\n\t\tconst controller = new AbortController()\n\t\tthis.#controller = controller\n\t\tconst response = await this.#fetch(this.url, {\n\t\t\theaders: this.#headers({ Accept: ACCEPT_EVENT_STREAM }),\n\t\t\tsignal: controller.signal,\n\t\t})\n\t\tif (!response.ok) throw new Error(`broker returned ${String(response.status)}`)\n\t\tconst body = response.body\n\t\tif (body === null) throw new Error('broker sent no stream')\n\n\t\tthis.#connected = true\n\t\tthis.#emitter.emit('connect')\n\n\t\tconst reader = body.getReader()\n\t\tconst decoder = new TextDecoder()\n\t\tconst parser = createSSEParser({ limit: SSE_BUFFER_LIMIT })\n\t\ttry {\n\t\t\tfor (;;) {\n\t\t\t\tconst { done, value } = await reader.read()\n\t\t\t\tif (done) break\n\t\t\t\tfor (const event of parser.parse(decoder.decode(value, { stream: true }))) {\n\t\t\t\t\tthis.#handle(event)\n\t\t\t\t\tif (!this.#connecting) break\n\t\t\t\t}\n\t\t\t\tif (!this.#connecting) break\n\t\t\t}\n\t\t} finally {\n\t\t\treader.releaseLock()\n\t\t}\n\t\tthis.#markDisconnected()\n\t}\n\n\t#handle(event: SSEEvent): void {\n\t\tif (event.event === SSE_EVENTS.pending) {\n\t\t\tconst parsed = parseJSON(event.data)\n\t\t\tif (!isPendingForm(parsed) || this.#seen.has(parsed.id)) return\n\t\t\tconst schema = parseForm(parsed.schema)\n\t\t\tif (schema === undefined) {\n\t\t\t\tthis.#emitter.emit(\n\t\t\t\t\t'error',\n\t\t\t\t\tnew Error(`broker sent an invalid form schema for ${parsed.id}`),\n\t\t\t\t)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tthis.#seen.add(parsed.id)\n\t\t\tthis.#queue.set(parsed.id, sanitizeSchema(schema))\n\t\t\tvoid this.#drain()\n\t\t\treturn\n\t\t}\n\t\tif (event.event === SSE_EVENTS.expire) {\n\t\t\tconst parsed = parseJSON(event.data)\n\t\t\tif (isRecord(parsed) && isString(parsed.id)) this.#expire(parsed.id)\n\t\t\treturn\n\t\t}\n\t\tif (event.event === SSE_EVENTS.shutdown) {\n\t\t\tthis.disconnect()\n\t\t\tthis.#interrupt()\n\t\t}\n\t}\n\n\tasync #drain(): Promise<void> {\n\t\tif (this.#draining) return\n\t\tthis.#draining = true\n\t\ttry {\n\t\t\twhile (!this.#destroyed) {\n\t\t\t\tlet queued: readonly [string, FormSchema] | undefined\n\t\t\t\tfor (const entry of this.#queue) {\n\t\t\t\t\tqueued = entry\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tif (queued === undefined) return\n\t\t\t\tconst [id, schema] = queued\n\t\t\t\tthis.#queue.delete(id)\n\t\t\t\ttry {\n\t\t\t\t\tawait this.#render(id, schema)\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconst active = this.#active\n\t\t\t\t\tif (active?.id !== id || !active.stopped) this.#emitter.emit('error', error)\n\t\t\t\t} finally {\n\t\t\t\t\tconst active = this.#active\n\t\t\t\t\tif (active?.id === id) {\n\t\t\t\t\t\tactive.form.destroy()\n\t\t\t\t\t\tthis.#active = undefined\n\t\t\t\t\t}\n\t\t\t\t\tif (!this.#queue.has(id)) this.#seen.delete(id)\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.#draining = false\n\t\t}\n\t}\n\n\tasync #render(id: string, schema: FormSchema): Promise<void> {\n\t\tlet values: FormValues | undefined\n\t\tlet errors: readonly FieldError[] = []\n\t\twhile (this.#seen.has(id) && !this.#destroyed) {\n\t\t\tconst form = this.#createRenderingForm(schema, values)\n\t\t\tthis.#active = { id, form, stopped: false }\n\t\t\tfor (const error of errors) form.invalidate(error.field, sanitizeDisplayText(error.message))\n\t\t\tconst submitted = await this.#terminal.ask(form)\n\t\t\tconst active = this.#active\n\t\t\tif (active?.id !== id || active.stopped) return\n\t\t\tconst rejected = await this.#post(id, submitted)\n\t\t\tconst posted = this.#active\n\t\t\tif (posted?.id !== id || posted.stopped || rejected === undefined) return\n\t\t\tvalues = submitted\n\t\t\terrors = rejected\n\t\t\tform.destroy()\n\t\t\tthis.#active = undefined\n\t\t}\n\t}\n\n\t#createRenderingForm(schema: FormSchema, values?: FormValues): FormInterface {\n\t\tconst fields = schema.fields.map((field) => {\n\t\t\tif (field.rule?.pattern === undefined) return field\n\t\t\tconst { pattern: _pattern, ...rule } = field.rule\n\t\t\treturn { ...field, rule }\n\t\t})\n\t\tconst form = createForm({ ...schema, fields }, values === undefined ? undefined : { values })\n\t\tvoid form.answer.catch(() => undefined)\n\t\treturn form\n\t}\n\n\tasync #post(id: string, values: FormValues): Promise<readonly FieldError[] | undefined> {\n\t\tconst response = await this.#fetch(this.url, {\n\t\t\tmethod: 'POST',\n\t\t\theaders: this.#headers({ 'Content-Type': 'application/json' }),\n\t\t\tbody: JSON.stringify({ id, values }),\n\t\t})\n\t\tif (!response.ok) this.#emitter.emit('error', new Error(`broker rejected answer ${id}`))\n\t\tconst parsed = parseJSON(await response.text())\n\t\tif (!isRecord(parsed) || !isBoolean(parsed.success)) {\n\t\t\tthis.#emitter.emit('error', new Error(`broker returned an invalid answer result for ${id}`))\n\t\t\treturn undefined\n\t\t}\n\t\tif (parsed.success) return undefined\n\t\tconst error = parsed.error\n\t\tif (!isRecord(error) || !isString(error.reason)) {\n\t\t\tthis.#emitter.emit('error', new Error(`broker returned an invalid answer error for ${id}`))\n\t\t\treturn undefined\n\t\t}\n\t\tif (error.reason === 'unknown') return undefined\n\t\tif (error.reason === 'rejected' && arrayOf(isFieldError)(error.errors)) return error.errors\n\t\tthis.#emitter.emit('error', new Error(`broker returned an invalid answer refusal for ${id}`))\n\t\treturn undefined\n\t}\n\n\t#expire(id: string): void {\n\t\tconst active = this.#active\n\t\tif (active?.id === id) {\n\t\t\tthis.#active = { ...active, stopped: true }\n\t\t\tthis.#seen.delete(id)\n\t\t\tactive.form.destroy()\n\t\t} else if (this.#queue.delete(id)) this.#seen.delete(id)\n\t\tthis.#emitter.emit('expire', id)\n\t}\n\n\t#interrupt(): void {\n\t\tthis.#queue.clear()\n\t\tthis.#seen.clear()\n\t\tconst active = this.#active\n\t\tif (active === undefined) return\n\t\tthis.#active = { ...active, stopped: true }\n\t\tactive.form.destroy()\n\t}\n\n\t#markDisconnected(): void {\n\t\tif (!this.#connected) return\n\t\tthis.#connected = false\n\t\tthis.#emitter.emit('disconnect')\n\t}\n\n\t#headers(base: Record<string, string>): Record<string, string> {\n\t\tif (this.#token !== undefined) return { ...base, [HEADER_TOKEN]: this.#token }\n\t\treturn { ...base }\n\t}\n\n\t#wait(ms: number): Promise<void> {\n\t\treturn new Promise((resolve) => {\n\t\t\tconst settle = this.#createSettler(resolve)\n\t\t\tthis.#wake = settle\n\t\t\tthis.#backoff = this.#timer(settle, ms)\n\t\t})\n\t}\n\n\t#createSettler(resolve: () => void): () => void {\n\t\treturn () => {\n\t\t\tthis.#backoff = undefined\n\t\t\tthis.#wake = undefined\n\t\t\tresolve()\n\t\t}\n\t}\n}\n","import type {\n\tPendingForm,\n\tPromptInterface,\n\tPromptOptions,\n\tTerminalAnswerError,\n\tTerminalManagerEventMap,\n\tTerminalManagerInterface,\n\tTerminalManagerOptions,\n\tTerminalSnapshot,\n\tTerminalStoreInterface,\n\tTimerHandler,\n} from './types.js'\nimport type { Result } from '@orkestrel/contract'\nimport type { EmitterInterface } from '@orkestrel/emitter'\nimport type { FormInterface, FormValues } from '@orkestrel/form'\nimport { TerminalError } from './errors.js'\nimport { createPrompt } from './factories.js'\nimport { Emitter } from '@orkestrel/emitter'\nimport { isArray } from '@orkestrel/contract'\n\n/**\n * The multi-endpoint terminal MANAGER — a registry of named {@link PromptInterface} brokers (one\n * per endpoint), so several parties can `ask` forms of each other by NAME with a `from` → `to`\n * attribution edge on every parked form, and a transitive DEADLOCK check across all in-flight\n * asks.\n *\n * @remarks\n * - **Registry.** `add(name, options?)` mints (or, if `name` is already mounted, returns the\n * EXISTING broker UNCHANGED — idempotent, never clobbers a live/parked endpoint). Every mounted\n * broker's `pending` / `answer` / `expire` events are re-emitted on the manager, attributed by\n * `name`.\n * - **`ask`.** The target must already be mounted via {@link add} — `ask` never auto-adds it;\n * rejects `TARGET` for an unknown `to` (listing the known names). Rejects `DEADLOCK` when parking\n * `from → to` would close a cycle over the CURRENT in-flight edge set (walked transitively);\n * otherwise parks the caller's live form through the target's broker and returns that form's own\n * `answer` promise. Edge cleanup never alters the value or rejection the caller observes.\n * - **Durable open / save.** `open(name)` restores an EMPTY broker from the `store` (parked\n * Promises are process-bound and never resurrected); `save(name)` persists the endpoint's\n * configured `timeout`.\n * - **Removal.** `remove` drops one endpoint, a batch (§9.2, array overload FIRST), or every\n * endpoint when called without an argument. It destroys each broker, which expires every form\n * still parked on it. `destroy` is idempotent.\n *\n * @example\n * ```ts\n * const form = createForm({ fields: [{ control: 'text', name: 'name' }] })\n * const manager = new TerminalManager()\n * manager.add('agent')\n * const answer = manager.ask('user', 'agent', form)\n * manager.answer('agent', manager.pending('agent')[0].id, { name: 'Ada' })\n * await answer // { name: 'Ada' }\n * ```\n */\nexport class TerminalManager implements TerminalManagerInterface {\n\treadonly #terminals = new Map<string, PromptInterface>()\n\treadonly #config = new Map<string, PromptOptions>()\n\t// The handlers subscribed on a mounted broker's emitter — kept so `remove` can `off` them\n\t// explicitly (on top of the broker's own `destroy`, which already renders its emitter inert).\n\treadonly #listeners = new Map<\n\t\tstring,\n\t\t{\n\t\t\treadonly pending: (form: PendingForm) => void\n\t\t\treadonly answer: (id: string, values: FormValues) => void\n\t\t\treadonly expire: (id: string) => void\n\t\t}\n\t>()\n\t// In-flight `ask` edges, keyed by the parked form's id — the deadlock graph. `from` asked\n\t// `to`; cleanup on settle (answer / expire / destroy / remove) removes EXACTLY the edge that\n\t// call created.\n\treadonly #edges = new Map<string, { readonly from: string; readonly to: string }>()\n\treadonly #store: TerminalStoreInterface | undefined\n\treadonly #timeout: number | undefined\n\treadonly #timer: TimerHandler | undefined\n\treadonly #cap: number | undefined\n\treadonly #emitter: Emitter<TerminalManagerEventMap>\n\t#destroyed = false\n\n\tconstructor(options?: TerminalManagerOptions) {\n\t\tthis.#store = options?.store\n\t\tthis.#timeout = options?.timeout\n\t\tthis.#timer = options?.timer\n\t\tthis.#cap = options?.cap\n\t\tthis.#emitter = new Emitter({\n\t\t\t...(options?.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options?.error !== undefined ? { error: options.error } : {}),\n\t\t})\n\t}\n\n\tget emitter(): EmitterInterface<TerminalManagerEventMap> {\n\t\treturn this.#emitter\n\t}\n\n\tget count(): number {\n\t\treturn this.#terminals.size\n\t}\n\n\t// === Accessors (§9.1)\n\n\tterminal(name: string): PromptInterface | undefined {\n\t\treturn this.#terminals.get(name)\n\t}\n\n\tterminals(): readonly string[] {\n\t\treturn [...this.#terminals.keys()]\n\t}\n\n\t// === Registry\n\n\tadd(name: string, options?: PromptOptions): PromptInterface {\n\t\tif (this.#destroyed) throw new TerminalError('DESTROYED', 'manager destroyed')\n\t\tconst existing = this.#terminals.get(name)\n\t\tif (existing !== undefined) return existing\n\t\tconst timeout = options?.timeout ?? this.#timeout\n\t\tconst timer = options?.timer ?? this.#timer\n\t\tconst cap = options?.cap ?? this.#cap\n\t\tconst promptOptions: PromptOptions = {\n\t\t\t...(options?.on !== undefined ? { on: options.on } : {}),\n\t\t\t...(options?.error !== undefined ? { error: options.error } : {}),\n\t\t\t...(timeout !== undefined ? { timeout } : {}),\n\t\t\t...(timer !== undefined ? { timer } : {}),\n\t\t\t...(cap !== undefined ? { cap } : {}),\n\t\t}\n\t\tconst broker = createPrompt(promptOptions)\n\t\tconst listeners = {\n\t\t\tpending: this.#createPendingListener(),\n\t\t\tanswer: this.#createAnswerListener(name),\n\t\t\texpire: this.#createExpireListener(name),\n\t\t}\n\t\tbroker.emitter.on('pending', listeners.pending)\n\t\tbroker.emitter.on('answer', listeners.answer)\n\t\tbroker.emitter.on('expire', listeners.expire)\n\t\tthis.#terminals.set(name, broker)\n\t\tthis.#config.set(name, { ...options })\n\t\tthis.#listeners.set(name, listeners)\n\t\treturn broker\n\t}\n\n\t// === Ask\n\n\task(from: string, to: string, form: FormInterface): Promise<FormValues> {\n\t\tconst broker = this.#terminals.get(to)\n\t\tif (broker === undefined) {\n\t\t\tconst known = this.terminals()\n\t\t\treturn Promise.reject(\n\t\t\t\tnew TerminalError(\n\t\t\t\t\t'TARGET',\n\t\t\t\t\t`unknown terminal '${to}' (known: ${known.length > 0 ? known.join(', ') : 'none'})`,\n\t\t\t\t\t{ to, known },\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t\tconst cycle = this.#findCycle(from, to)\n\t\tif (cycle !== undefined) {\n\t\t\treturn Promise.reject(\n\t\t\t\tnew TerminalError(\n\t\t\t\t\t'DEADLOCK',\n\t\t\t\t\t`ask ${from} -> ${to} would deadlock: ${cycle.join(' -> ')}`,\n\t\t\t\t\t{\n\t\t\t\t\t\tfrom,\n\t\t\t\t\t\tto,\n\t\t\t\t\t\tpath: cycle,\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t)\n\t\t}\n\t\tconst id = broker.park(form, { from, to })\n\t\tif (broker.pending(id) !== undefined) {\n\t\t\tthis.#edges.set(id, { from, to })\n\t\t\tform.answer.then(this.#createEdgeClear(id), this.#createEdgeClear(id))\n\t\t}\n\t\treturn form.answer\n\t}\n\n\t// === Pending accessors (§9.1)\n\n\tpending(): readonly PendingForm[]\n\tpending(to: string): readonly PendingForm[]\n\tpending(to?: string): readonly PendingForm[] {\n\t\tif (to !== undefined) {\n\t\t\tconst broker = this.#terminals.get(to)\n\t\t\treturn broker === undefined ? [] : broker.pending()\n\t\t}\n\t\tconst result: PendingForm[] = []\n\t\tfor (const broker of this.#terminals.values()) result.push(...broker.pending())\n\t\treturn result\n\t}\n\n\t// === Answer\n\n\tanswer(to: string, id: string, values: FormValues): Result<FormValues, TerminalAnswerError> {\n\t\tconst broker = this.#terminals.get(to)\n\t\tif (broker === undefined) return { success: false, error: { reason: 'terminal' } }\n\t\tconst result = broker.answer(id, values)\n\t\tif (result.success) this.#edges.delete(id)\n\t\treturn result\n\t}\n\n\t// === Durable open / save\n\n\tasync open(name: string): Promise<PromptInterface | undefined> {\n\t\tif (this.#destroyed) throw new TerminalError('DESTROYED', 'manager destroyed')\n\t\tconst existing = this.#terminals.get(name)\n\t\tif (existing !== undefined) return existing\n\t\tif (this.#store === undefined) return undefined\n\t\tconst snapshot = await this.#store.get(name)\n\t\tif (this.#destroyed) throw new TerminalError('DESTROYED', 'manager destroyed')\n\t\tif (snapshot === undefined) return undefined\n\t\treturn this.add(name, snapshot.timeout !== undefined ? { timeout: snapshot.timeout } : {})\n\t}\n\n\tasync save(name: string): Promise<boolean> {\n\t\tconst broker = this.#terminals.get(name)\n\t\tif (this.#store === undefined || broker === undefined) return false\n\t\tconst config = this.#config.get(name)\n\t\tconst snapshot: TerminalSnapshot = {\n\t\t\tid: name,\n\t\t\t...(config?.timeout !== undefined ? { timeout: config.timeout } : {}),\n\t\t}\n\t\tawait this.#store.set(snapshot)\n\t\treturn true\n\t}\n\n\t// === Removal (§9.2: the array overload FIRST)\n\n\tremove(names: readonly string[]): boolean\n\tremove(name: string): boolean\n\tremove(): void\n\tremove(names?: string | readonly string[]): boolean | void {\n\t\tif (names === undefined) {\n\t\t\tfor (const name of [...this.#terminals.keys()]) this.#removeOne(name)\n\t\t\treturn\n\t\t}\n\t\tif (isArray(names)) {\n\t\t\tlet removed = false\n\t\t\tfor (const name of names) {\n\t\t\t\tif (this.#removeOne(name)) removed = true\n\t\t\t}\n\t\t\treturn removed\n\t\t}\n\t\treturn this.#removeOne(names)\n\t}\n\n\tdestroy(): void {\n\t\tif (this.#destroyed) return\n\t\tthis.#destroyed = true\n\t\tthis.remove()\n\t\tthis.#edges.clear()\n\t\tthis.#emitter.destroy()\n\t}\n\n\t// === Private helpers\n\n\t#createPendingListener(): (form: PendingForm) => void {\n\t\treturn (form) => this.#emitter.emit('pending', form)\n\t}\n\n\t#createAnswerListener(name: string): (id: string, values: FormValues) => void {\n\t\treturn (id, values) => {\n\t\t\tthis.#edges.delete(id)\n\t\t\tthis.#emitter.emit('answer', name, id, values)\n\t\t}\n\t}\n\n\t#createExpireListener(name: string): (id: string) => void {\n\t\treturn (id) => {\n\t\t\tthis.#edges.delete(id)\n\t\t\tthis.#emitter.emit('expire', name, id)\n\t\t}\n\t}\n\n\t#createEdgeClear(id: string): () => void {\n\t\treturn () => {\n\t\t\tthis.#edges.delete(id)\n\t\t}\n\t}\n\n\t// Drop one endpoint: destroy its broker FIRST (its expire loop re-emits `expire` for every\n\t// still-parked form through the manager's listeners — still attached at this point, so\n\t// each settles on the manager emitter too), THEN unsubscribe the manager's listeners and\n\t// remove it from every registry map. `false` when `name` was not mounted.\n\t#removeOne(name: string): boolean {\n\t\tconst broker = this.#terminals.get(name)\n\t\tif (broker === undefined) return false\n\t\tbroker.destroy()\n\t\tconst listeners = this.#listeners.get(name)\n\t\tif (listeners !== undefined) {\n\t\t\tbroker.emitter.off('pending', listeners.pending)\n\t\t\tbroker.emitter.off('answer', listeners.answer)\n\t\t\tbroker.emitter.off('expire', listeners.expire)\n\t\t}\n\t\tthis.#terminals.delete(name)\n\t\tthis.#config.delete(name)\n\t\tthis.#listeners.delete(name)\n\t\tthis.#clearEdges(name)\n\t\treturn true\n\t}\n\n\t#clearEdges(to: string): void {\n\t\tfor (const [id, edge] of this.#edges) {\n\t\t\tif (edge.to === to) this.#edges.delete(id)\n\t\t}\n\t}\n\n\t// Walk the in-flight edge graph forward from `to`, looking for `from` — a hit means parking\n\t// `from -> to` would close a cycle. Returns the closing cycle path (`from` first and last),\n\t// or `undefined` when no cycle would form.\n\t#findCycle(from: string, to: string): readonly string[] | undefined {\n\t\tif (from === to) return [from, to]\n\t\tconst visited = new Set<string>([to])\n\t\tconst queue: Array<readonly string[]> = [[to]]\n\t\twhile (queue.length > 0) {\n\t\t\tconst path = queue.shift()\n\t\t\tif (path === undefined) break\n\t\t\tconst last = path[path.length - 1]\n\t\t\tif (last === undefined) continue\n\t\t\tfor (const edge of this.#edges.values()) {\n\t\t\t\tif (edge.from !== last) continue\n\t\t\t\tif (edge.to === from) return [from, ...path, from]\n\t\t\t\tif (visited.has(edge.to)) continue\n\t\t\t\tvisited.add(edge.to)\n\t\t\t\tqueue.push([...path, edge.to])\n\t\t\t}\n\t\t}\n\t\treturn undefined\n\t}\n}\n","import type { TerminalSnapshot, TerminalStoreInterface } from './types.js'\n\n/**\n * The in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of\n * {@link TerminalSnapshot}s keyed by endpoint id, the DEFAULT store\n * {@link import('./factories.js').createMemoryTerminalStore} builds. The EXACT twin of\n * {@link import('./DatabaseTerminalStore.js').DatabaseTerminalStore}.\n *\n * @remarks\n * A plain `Map<string, TerminalSnapshot>` (AGENTS §21 — the snapshot is already pure, self-contained\n * CONFIG-only JSON, so no encoding is needed for the memory tier). There is NO idle-TTL and NO\n * eviction: a persisted config lives until an explicit `delete`. A durable backend (JSON / SQLite /\n * IndexedDB) swaps in through the SAME interface without touching the manager — its\n * driver-pluggable twin is {@link import('./DatabaseTerminalStore.js').DatabaseTerminalStore} (the\n * snapshot as one opaque JSON column).\n *\n * - **`get` resolves the persisted snapshot for an id**, or `undefined` if none is stored.\n * - **`set` inserts / replaces under the snapshot's OWN `id`** (no separate id param).\n * - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).\n *\n * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method\n * bijection with {@link TerminalStoreInterface}). Hydration is a caller concern: `open` always\n * restores an EMPTY broker — parked Promises are process-bound and never resurrected.\n *\n * @example\n * ```ts\n * import { createMemoryTerminalStore } from '@src/core'\n *\n * const store = createMemoryTerminalStore()\n * await store.set({ id: 'shell', timeout: 5000 }) // persist a config\n * const snapshot = await store.get('shell')\n * await store.delete('shell') // drop it\n * ```\n */\nexport class MemoryTerminalStore implements TerminalStoreInterface {\n\treadonly #snapshots = new Map<string, TerminalSnapshot>()\n\n\tget(id: string): Promise<TerminalSnapshot | undefined> {\n\t\treturn Promise.resolve(this.#snapshots.get(id))\n\t}\n\n\tset(snapshot: TerminalSnapshot): Promise<void> {\n\t\t// Insert / replace under the snapshot's OWN id (no separate id param).\n\t\tthis.#snapshots.set(snapshot.id, snapshot)\n\t\treturn Promise.resolve()\n\t}\n\n\tdelete(id: string): Promise<void> {\n\t\t// Drop by id; `Map.delete` of an absent id is already a no-op (no throw).\n\t\tthis.#snapshots.delete(id)\n\t\treturn Promise.resolve()\n\t}\n}\n","import type { TerminalSnapshot, TerminalSnapshotRow, TerminalStoreInterface } from './types.js'\nimport type { TableInterface } from '@orkestrel/database'\nimport { isTerminalSnapshot } from './validators.js'\n\n/**\n * A {@link TerminalStoreInterface} backed by one table of the `databases` layer — an endpoint's\n * durable CONFIG state IS a row, so persistence reduces to keyed point-access (`get` / `set` /\n * `delete`) over a {@link TableInterface}, the driver-pluggable twin of the plain-`Map`\n * {@link import('./MemoryTerminalStore.js').MemoryTerminalStore}.\n *\n * @remarks\n * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,\n * JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /\n * IndexedDB backend swaps in WITHOUT touching the manager — the same seam as\n * {@link import('./MemoryTerminalStore.js').MemoryTerminalStore}. The driver defaults to memory\n * ({@link import('./factories.js').createDatabaseTerminalStore} passes `createMemoryDriver()`), so\n * it ALSO works in memory out of the box; you opt into the durable plumbing by passing a JSON /\n * SQLite / IndexedDB driver.\n *\n * The {@link TerminalSnapshot} is stored as ONE OPAQUE JSON COLUMN — the table is a row of\n * `{ id; snapshot }` ({@link TerminalSnapshotRow}). The snapshot is already a COMPLETE,\n * self-contained, pure-JSON CONFIG payload (no live broker state), so storing it whole is lossless\n * AND keeps the row type flat (`snapshot` reads back as `unknown`).\n *\n * - **`set(snapshot)` upserts under the snapshot's OWN `id`** (no separate id param) — it writes\n * the row `{ id: snapshot.id, snapshot }`.\n * - **`get(id)` resolves the stored snapshot for an id**, narrowing the opaque JSON column back to\n * a {@link TerminalSnapshot} ({@link import('./validators.js').isTerminalSnapshot} — the AGENTS §14\n * boundary narrow for an untrusted storage read), or `undefined` if none is stored.\n * - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).\n *\n * There is NO idle-TTL / eviction — a persisted config lives until an explicit `delete`. The public\n * surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method bijection with\n * {@link TerminalStoreInterface}). Hydration stays a caller concern: `open` always restores an EMPTY\n * broker — parked Promises are process-bound and never resurrected.\n *\n * @example\n * ```ts\n * import { createDatabaseTerminalStore, createMemoryDriver } from '@src/core'\n *\n * const store = createDatabaseTerminalStore(createMemoryDriver()) // a durable driver swaps in here\n * await store.set({ id: 'shell', timeout: 5000 }) // persist the config (one JSON column)\n * const snapshot = await store.get('shell')\n * await store.delete('shell') // drop it\n * ```\n */\nexport class DatabaseTerminalStore implements TerminalStoreInterface {\n\treadonly #table: TableInterface<TerminalSnapshotRow>\n\n\t/**\n\t * Wrap a table as a terminal store.\n\t *\n\t * @param table - The {@link TableInterface} holding the snapshots — its row is the\n\t * {@link TerminalSnapshotRow} `{ id; snapshot }` shape (the snapshot one opaque JSON column)\n\t */\n\tconstructor(table: TableInterface<TerminalSnapshotRow>) {\n\t\tthis.#table = table\n\t}\n\n\t/** Resolve the persisted snapshot for `id`, narrowing the opaque JSON column back to a `TerminalSnapshot`. */\n\tasync get(id: string): Promise<TerminalSnapshot | undefined> {\n\t\tconst row = await this.#table.get(id)\n\t\tif (row === undefined) return undefined\n\t\t// The snapshot crosses back as an untrusted storage read (a structured clone / a JSON row),\n\t\t// so narrow the opaque JSON column with the boundary guard rather than a cast (AGENTS §14);\n\t\t// a malformed blob resolves `undefined`, never a broken config.\n\t\treturn isTerminalSnapshot(row.snapshot) ? row.snapshot : undefined\n\t}\n\n\t/** Insert or replace under the snapshot's OWN `id` (no separate id param) — the row is `{ id, snapshot }`. */\n\tasync set(snapshot: TerminalSnapshot): Promise<void> {\n\t\tawait this.#table.set({ id: snapshot.id, snapshot })\n\t}\n\n\t/** Drop a snapshot by id; an absent id is a no-op (no throw). */\n\tasync delete(id: string): Promise<void> {\n\t\tawait this.#table.remove(id)\n\t}\n}\n","import type {\n\tPromptClientInterface,\n\tPromptClientOptions,\n\tPromptInterface,\n\tPromptOptions,\n\tTerminalManagerInterface,\n\tTerminalManagerOptions,\n\tTerminalSnapshotRow,\n\tTerminalStoreInterface,\n} from './types.js'\nimport type { DriverInterface, TableInterface } from '@orkestrel/database'\nimport { Prompt } from './Prompt.js'\nimport { PromptClient } from './PromptClient.js'\nimport { TerminalManager } from './TerminalManager.js'\nimport { MemoryTerminalStore } from './MemoryTerminalStore.js'\nimport { DatabaseTerminalStore } from './DatabaseTerminalStore.js'\nimport { createDatabase, createMemoryDriver } from '@orkestrel/database'\nimport { rawShape, stringShape } from '@orkestrel/contract'\n\n/**\n * Create the headless {@link PromptInterface} broker. It parks live forms and applies remote\n * answers to the authoritative instances.\n *\n * @param options - See {@link PromptOptions}\n * @returns A {@link PromptInterface}\n *\n * @remarks\n * The caller awaits the parked form's own `answer`. Timeout or teardown destroys the form, so that\n * promise rejects with the Form package's `ABANDONED` error. Inject `options.timer` to drive\n * expiry without real time.\n *\n * @example\n * ```ts\n * import { createPrompt } from '@src/core'\n * import { createForm } from '@orkestrel/form'\n *\n * const prompt = createPrompt()\n * const form = createForm({ fields: [{ control: 'text', name: 'name' }] })\n * const id = prompt.park(form)\n * prompt.answer(id, { name: 'Ada' })\n * ```\n */\nexport function createPrompt(options?: PromptOptions): PromptInterface {\n\treturn new Prompt(options)\n}\n\n/**\n * Create the SSE prompt {@link PromptClientInterface} BRIDGE — it connects to a remote broker's SSE\n * endpoint, dispatches each received form to a local {@link import('./types.js').TerminalInterface},\n * and POSTs the answer back. Universal — `fetch` / SSE are web-standard.\n *\n * @param options - See {@link PromptClientOptions} (`url` + `terminal` required)\n * @returns A {@link PromptClientInterface}\n *\n * @remarks\n * - **Connect + reconnect.** `await client.connect()` streams remote prompts until the stream\n * ends; it reconnects with the `delay` backoff unless `reconnect` is `false` / the client was\n * `destroy`ed. Inject `options.fetch` (a scripted `fetch`) and `options.timer` to drive it\n * deterministically in tests — no real network.\n * - **§14 wire narrowing.** Every decoded prompt is guard-narrowed before dispatch (never an `as`).\n *\n * @example\n * ```ts\n * import { createPromptClient } from '@src/core'\n *\n * const client = createPromptClient({ url: 'http://host/prompts', terminal })\n * await client.connect()\n * ```\n */\nexport function createPromptClient(options: PromptClientOptions): PromptClientInterface {\n\treturn new PromptClient(options)\n}\n\n/**\n * Create the multi-endpoint {@link TerminalManager} — a named registry of\n * {@link PromptInterface} brokers so several parties can `ask` prompts of each other by name,\n * with a transitive DEADLOCK check across every in-flight ask.\n *\n * @param options - See {@link TerminalManagerOptions}\n * @returns A {@link TerminalManager}\n *\n * @example\n * ```ts\n * import { createTerminalManager } from '@src/core'\n *\n * const manager = createTerminalManager()\n * manager.add('agent')\n * ```\n */\nexport function createTerminalManager(options?: TerminalManagerOptions): TerminalManagerInterface {\n\treturn new TerminalManager(options)\n}\n\n/**\n * Create the in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of endpoint\n * config snapshots, the default store backing a {@link TerminalManagerInterface}'s `open` / `save`.\n *\n * @returns A {@link TerminalStoreInterface}\n *\n * @example\n * ```ts\n * import { createMemoryTerminalStore } from '@src/core'\n *\n * const store = createMemoryTerminalStore()\n * ```\n */\nexport function createMemoryTerminalStore(): TerminalStoreInterface {\n\treturn new MemoryTerminalStore()\n}\n\n/**\n * Create a {@link TerminalStoreInterface} backed by one table of the `databases` layer — the\n * driver-pluggable twin of {@link createMemoryTerminalStore}, storing each endpoint's config\n * snapshot as one opaque JSON column.\n *\n * @param driver - The {@link DriverInterface} backing the table (default an in-memory driver)\n * @returns A {@link TerminalStoreInterface}\n *\n * @example\n * ```ts\n * import { createDatabaseTerminalStore } from '@src/core'\n *\n * const store = createDatabaseTerminalStore() // in-memory by default\n * ```\n */\nexport function createDatabaseTerminalStore(\n\tdriver: DriverInterface = createMemoryDriver(),\n): TerminalStoreInterface {\n\t// The snapshot is stored as ONE OPAQUE JSON column (`rawShape`), so the row infers FLAT —\n\t// `{ id: string; snapshot: unknown }` = TerminalSnapshotRow.\n\tconst columns = { id: stringShape(), snapshot: rawShape({}) }\n\tconst database = createDatabase({ driver, tables: { terminals: columns } })\n\tconst table: TableInterface<TerminalSnapshotRow> = database.table('terminals')\n\treturn new DatabaseTerminalStore(table)\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","names":["#input","#output","#styler","#theme","#handlers","#queue","#report","#walk","#editable","#ended","#close","#group","#locked","#read","#bind","#password","#confirm","#editor","#select","#checkbox","#file","#text","#drive","#line","#prompt","#block","#unavailable","#list","#hint","#createHandler","#enterRaw","#interrupt","#render","#leaveRaw","#next","#reader","#taker","#interface","#readline","#accept","#finish"],"sources":["../../../src/server/constants.ts","../../../src/server/helpers.ts","../../../src/server/Terminal.ts","../../../src/server/factories.ts"],"sourcesContent":["// Server-terminals constants — the cursor and line-clear ANSI sequences the interactive `Terminal`\n// driver writes to redraw a field view IN PLACE, plus the copy the walk shows around those views:\n// the per-control format hints, the readline-fallback prompts, and the marks for a locked field and\n// an unavailable choice. UPPER_SNAKE, every member exported. Sequences are built from a named ESC\n// byte through `String.fromCharCode` so no raw control character appears in source (the core\n// terminals / console-module idiom).\n\nimport type { FieldControl } from '@orkestrel/form'\n\n/** The Escape byte (ESC, U+001B) — the lead byte of every CSI cursor-control sequence below. */\nexport const ESCAPE = String.fromCharCode(27)\n\n/** The Control Sequence Introducer (`ESC[`) — the prefix of every cursor / erase sequence. */\nexport const CSI = `${ESCAPE}[`\n\n/**\n * The cursor-UP sequence TEMPLATE (`ESC[{count}A`) — {@link import('./helpers.js').moveUp}\n * interpolates the `{count}` placeholder with the number of lines to climb. Kept as a template so\n * the count stays out of the constant.\n */\nexport const CSI_UP = `${CSI}{count}A`\n\n/**\n * Hide the cursor (`ESC[?25l`) — written before the driver starts redrawing a prompt so the cursor\n * does not flicker across the view during an in-place re-render; paired with {@link CURSOR_SHOW}.\n */\nexport const CURSOR_HIDE = `${CSI}?25l`\n\n/** Show the cursor (`ESC[?25h`) — restores the cursor after a prompt resolves / cancels (the {@link CURSOR_HIDE} pair). */\nexport const CURSOR_SHOW = `${CSI}?25h`\n\n/**\n * Erase from the cursor down to the end of the screen (`ESC[J`) — wipes the WHOLE previous (possibly\n * multi-line `select` / `checkbox`) view in one write before the new view is rendered, so a redraw\n * never leaves orphaned rows below.\n */\nexport const CLEAR_DOWN = `${CSI}J`\n\n/** A carriage return (`\\r`, U+000D) — returns the cursor to column 0 so a redraw starts at the line's left edge. */\nexport const CARRIAGE_RETURN = String.fromCharCode(13)\n\n/** A line feed (`\\n`, U+000A) — the line terminator the driver writes after the final committed prompt view. */\nexport const LINE_FEED = String.fromCharCode(10)\n\n/**\n * The numbered-list prompt the non-TTY {@link import('./Terminal.js').Terminal} `select` fallback\n * appends — a piped (non-terminal) stream cannot navigate with arrow keys, so the choices are\n * printed numbered and the user types one number on a single readline line.\n */\nexport const FALLBACK_SELECT_HINT = 'Enter a number'\n\n/** The comma-separated multi-select hint the non-TTY `checkbox` fallback shows (the user types one or more numbers). */\nexport const FALLBACK_CHECKBOX_HINT = 'Enter numbers separated by commas'\n\n/** The hint the non-TTY `editor` fallback shows — a piped stream has no ctrl-d, so end of input finishes the block. */\nexport const FALLBACK_EDITOR_HINT = '(end of input finishes)'\n\n/** The hint the non-TTY `confirm` fallback shows — a piped stream sends a whole line, so the answer is typed rather than pressed. */\nexport const FALLBACK_CONFIRM_HINT = '(y/n)'\n\n/**\n * The format cue appended to a field's label for each control the walk reads as a line of text —\n * the terminal has no date picker, no color well, and no file chooser, so the accepted shape is\n * stated instead. A control with no entry needs none: `text` and `editor` accept any line,\n * `password` masks one, and `confirm`, `select`, and `checkbox` are answered by key rather than by\n * format. The form's own rules still decide whether the typed value is acceptable.\n */\nexport const CONTROL_HINTS: Readonly<Partial<Record<FieldControl, string>>> = Object.freeze({\n\tnumber: '(number)',\n\tdate: '(YYYY-MM-DD)',\n\ttime: '(HH:MM)',\n\tdatetime: '(YYYY-MM-DDTHH:MM)',\n\tcolor: '(#rrggbb)',\n\tfile: '(path)',\n})\n\n/** The instruction a `file` field with `multiple` shows before its entries — one path per line, and a blank line ends the list. */\nexport const FILE_HINT = 'One path per line, blank to finish'\n\n/** The lead on the line listing an open `select`'s offered values, which a typed answer may ignore. */\nexport const SUGGESTION_LEAD = 'Suggestions'\n\n/** The lead on the line listing the choices a `select` or `checkbox` shows but refuses, so a reader sees why one is missing from the list below. */\nexport const UNAVAILABLE_LEAD = 'Unavailable'\n\n/** The mark on a locked field's line — the walk renders its value and moves on, because the form refuses an edit there. */\nexport const LOCKED_MARK = '(locked)'\n\n/**\n * What a field is told when the walk read an answer the control cannot hold — a word typed into a\n * `number`, an off-list value typed into an open `select` whose choice is refused. The value binds\n * as absence and this message is invalidated onto the field, so the walk re-asks it with the reason\n * on screen.\n */\nexport const REFUSAL_MESSAGE = 'Enter a value this field accepts'\n","// Pure helpers for the server terminal driver — every function here is exported and unit-tested.\n// Three families, all total: the stream-boundary guards that narrow `process.stdin` /\n// `process.stdout` / any injected stream without an assertion; the cursor math the driver uses to\n// redraw a field view IN PLACE (count a view's lines, build the cursor-up sequence, assemble the\n// reposition-and-clear prefix); and the projections and line renderers the whole-form walk needs\n// that no reducer owns — a control read as text, a value shown read-only, the choices a field\n// actually offers, and the group, locked, suggestion, unavailable, and numbered-list lines. The\n// impure driver only feeds bytes into the reducers and writes the strings these helpers build.\n\nimport type { FieldChoice, FieldValue, FormField, TextField } from '@orkestrel/form'\nimport type { PromptTheme } from '@src/core'\nimport type { StylerInterface } from '@orkestrel/console'\nimport type { InputStreamInterface, OutputStreamInterface } from './types.js'\nimport {\n\tCARRIAGE_RETURN,\n\tCLEAR_DOWN,\n\tCONTROL_HINTS,\n\tCSI_UP,\n\tLOCKED_MARK,\n\tSUGGESTION_LEAD,\n\tUNAVAILABLE_LEAD,\n} from './constants.js'\n\n/**\n * Whether `value` is a usable {@link InputStreamInterface} — a record with callable `on` / `off`\n * `'data'` subscription methods. A total type guard (AGENTS §14): it NEVER throws and returns `false`\n * for anything off-shape, so it narrows the one unavoidable input boundary (the real `process.stdin`,\n * or a fake TTY a test injects) to the exact slice the driver reads — no `as`.\n *\n * @remarks\n * Only `on` / `off` are required (the irreducible event seam); `setRawMode` / `resume` / `pause` /\n * `isTTY` are optional on {@link InputStreamInterface}, so their absence does not disqualify a stream\n * — a piped, non-TTY stream is still a valid input, just one the driver reads through the readline\n * fallback rather than raw mode.\n *\n * @param value - Any value crossing the boundary (a process stream, an injected fake, `unknown`)\n * @returns `true` when `value` has callable `on` and `off`\n */\nexport function isInputStream(value: unknown): value is InputStreamInterface {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'on' in value &&\n\t\ttypeof value.on === 'function' &&\n\t\t'off' in value &&\n\t\ttypeof value.off === 'function'\n\t)\n}\n\n/**\n * Whether `value` is a usable {@link OutputStreamInterface} — a record with a callable `write`. A\n * total type guard (AGENTS §14): it NEVER throws and returns `false` for anything off-shape, so it\n * narrows the output boundary (the real `process.stdout`, or a recording fake a test injects) to the\n * one method the driver writes through — no `as`.\n *\n * @param value - Any value crossing the boundary (a process stream, an injected fake, `unknown`)\n * @returns `true` when `value` has a callable `write`\n */\nexport function isOutputStream(value: unknown): value is OutputStreamInterface {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'write' in value &&\n\t\ttypeof value.write === 'function'\n\t)\n}\n\n/**\n * Whether `value` is a Node {@link NodeJS.ReadableStream} — a total structural guard (AGENTS §14)\n * checking for the callable `read` / `pipe` / `on` that `node:readline`'s `createInterface` requires\n * as its `input`. The non-TTY fallback narrows the resolved input stream through this before handing\n * it to readline (never an `as`), so a real piped `process.stdin` (or a `PassThrough` a test injects)\n * crosses into the readline boundary honestly. Never throws; returns `false` for a minimal fake that\n * isn't a full readable.\n *\n * @param value - The resolved input stream (or any value crossing the boundary)\n * @returns `true` when `value` has the readable methods readline needs\n */\nexport function isReadable(value: unknown): value is NodeJS.ReadableStream {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'read' in value &&\n\t\ttypeof value.read === 'function' &&\n\t\t'pipe' in value &&\n\t\ttypeof value.pipe === 'function'\n\t)\n}\n\n/**\n * Whether an input stream can be driven in RAW mode — it both reports `isTTY === true` AND exposes a\n * callable `setRawMode`. The {@link import('./Terminal.js').Terminal} probes this to choose its path:\n * `true` ⇒ the interactive raw-mode prompts (arrow-key navigation, live re-render); `false` ⇒ the\n * `node:readline` line-input fallback (a piped / non-terminal stream cannot enter raw mode). Total —\n * never throws.\n *\n * @param input - The resolved {@link InputStreamInterface}\n * @returns `true` when the stream is a TTY with `setRawMode`\n */\nexport function rawCapable(input: InputStreamInterface): boolean {\n\treturn input.isTTY === true && typeof input.setRawMode === 'function'\n}\n\n/**\n * The number of terminal LINES a rendered prompt `view` occupies — one more than its newline count\n * (a view with no newline is a single line; N newlines span N+1 lines). The basis of the in-place\n * re-render: the driver records the line count of the view it just wrote so the next redraw knows how\n * far up to move the cursor before overwriting. Total; an empty string is one (empty) line.\n *\n * @param view - The rendered (possibly multi-line, possibly ANSI-styled) view string\n * @returns The number of lines the view spans (always at least 1)\n */\nexport function lineCount(view: string): number {\n\tlet lines = 1\n\tfor (const character of view) {\n\t\tif (character === '\\n') lines += 1\n\t}\n\treturn lines\n}\n\n/**\n * The cursor-UP control sequence that moves the cursor up `count` lines (`ESC[{count}A`) — or the\n * empty string when `count` is zero or negative (no movement needed, and `ESC[0A` is a wasted write).\n * The pure step the in-place re-render uses to climb back over the previous view before clearing it.\n * Total.\n *\n * @param count - How many lines to move the cursor up\n * @returns The `ESC[{count}A` sequence, or `''` when `count <= 0`\n */\nexport function moveUp(count: number): string {\n\tif (count <= 0) return ''\n\treturn `${CSI_UP.replace('{count}', String(count))}`\n}\n\n/**\n * The full reposition-and-clear prefix to write BEFORE re-rendering a prompt view in place — given\n * the line count of the PREVIOUS view, it moves the cursor up over those lines, returns it to column\n * 0, and erases everything from there to the end of the screen, so the next view is drawn on a clean\n * region (no orphaned rows from a taller previous view). Pure; the driver writes this immediately\n * followed by the new view.\n *\n * @remarks\n * For the FIRST render `previousLines` is `1` (the cursor sits on the line the prompt opened on) so\n * the prefix is just a carriage return + clear-down — the prompt draws from the current line. For a\n * subsequent render it climbs `previousLines - 1` lines (the cursor is on the LAST line of the prior\n * view) before clearing. Keeping the math here (not in the driver) makes the re-render unit-testable\n * without a real terminal.\n *\n * @param previousLines - The line count of the view currently on screen (from {@link lineCount})\n * @returns The control-sequence prefix to write before the new view\n */\nexport function redrawPrefix(previousLines: number): string {\n\treturn `${moveUp(previousLines - 1)}${CARRIAGE_RETURN}${CLEAR_DOWN}`\n}\n\n/**\n * Project any field the walk reads as a LINE OF TEXT into the {@link TextField} the text reducer\n * takes — `text` itself, and the six controls a terminal has no widget for: `number`, `date`,\n * `time`, `datetime`, `color`, and one `file` entry. The label carries that control's format cue\n * from {@link CONTROL_HINTS}, and a declared `default` becomes the line a bare return submits. The\n * projection carries no rule, because the AUTHORITATIVE form still evaluates the answer this line\n * binds; it exists only so one reducer can render seven controls.\n *\n * @param field - The field being read\n * @returns The text field the reducer renders for it\n *\n * @example\n * ```ts\n * fieldToText({ control: 'date', name: 'born', label: 'Birthday' })\n * // { control: 'text', name: 'born', label: 'Birthday (YYYY-MM-DD)' }\n * ```\n */\nexport function fieldToText(field: FormField): TextField {\n\tconst label = field.label ?? field.name\n\tconst hint = CONTROL_HINTS[field.control]\n\tconst seed = 'default' in field ? field.default : undefined\n\tconst text = typeof seed === 'number' ? String(seed) : seed\n\treturn {\n\t\tcontrol: 'text',\n\t\tname: field.name,\n\t\tlabel: hint === undefined ? label : `${label} ${hint}`,\n\t\t...(typeof text === 'string' ? { default: text } : {}),\n\t}\n}\n\n/**\n * Project one held answer into the text a read-only line shows — a scalar as itself, a boolean as\n * `yes` / `no` (the word the confirm reducer commits), and a list joined by commas. Absence renders\n * as nothing, because a locked field nobody has answered has nothing to show.\n *\n * @param value - The answer the form holds for a field, or absence\n * @returns The text to render for it\n */\nexport function valueToText(value: FieldValue | undefined): string {\n\tif (value === undefined) return ''\n\tif (typeof value === 'string') return value\n\tif (typeof value === 'number') return String(value)\n\tif (typeof value === 'boolean') return value ? 'yes' : 'no'\n\treturn value.join(', ')\n}\n\n/**\n * The choices a `select` or `checkbox` field actually OFFERS — the form refuses a disabled choice's\n * value at every door, including a fill, so the walk never puts one in front of the cursor. Pair\n * with {@link disabledChoices} to tell the reader what was withheld.\n *\n * @param choices - The field's declared choices\n * @returns The choices the walk offers, in declared order\n */\nexport function enabledChoices(choices: readonly FieldChoice[]): readonly FieldChoice[] {\n\treturn choices.filter((choice) => choice.disabled !== true)\n}\n\n/**\n * The choices a `select` or `checkbox` field SHOWS but refuses — the complement of\n * {@link enabledChoices}, rendered by {@link unavailableLine} above the list so a reader sees why a\n * declared choice is missing from it.\n *\n * @param choices - The field's declared choices\n * @returns The refused choices, in declared order\n */\nexport function disabledChoices(choices: readonly FieldChoice[]): readonly FieldChoice[] {\n\treturn choices.filter((choice) => choice.disabled === true)\n}\n\n/** The section header the walk writes when it enters a new field group, painted by the `message` role. */\nexport function groupHeader(styler: StylerInterface, theme: PromptTheme, label: string): string {\n\treturn styler.render(theme.roles.message, label)\n}\n\n/**\n * The read-only line a LOCKED field renders — its label, the {@link LOCKED_MARK}, and the answer the\n * form already holds. The walk writes this instead of a prompt, because the field is still\n * validated and still submitted but must not be edited here.\n *\n * @param styler - The console styler that renders each role\n * @param theme - The resolved prompt theme\n * @param label - The field's label\n * @param value - The held answer, from {@link valueToText}\n * @returns The rendered line, with no trailing space when there is nothing to show\n */\nexport function lockedLine(\n\tstyler: StylerInterface,\n\ttheme: PromptTheme,\n\tlabel: string,\n\tvalue: string,\n): string {\n\tconst head = `${styler.render(theme.roles.muted, theme.icons.dot)} ${styler.render(theme.roles.message, label)} ${styler.render(theme.roles.hint, LOCKED_MARK)}`\n\treturn value.length === 0 ? head : `${head} ${styler.render(theme.roles.content, value)}`\n}\n\n/** The line listing an OPEN select's offered values above its text prompt — a suggestion list, because an open select admits an answer the list does not offer. */\nexport function suggestionLine(\n\tstyler: StylerInterface,\n\ttheme: PromptTheme,\n\tchoices: readonly FieldChoice[],\n): string {\n\tconst values = choices.map((choice) => choice.value).join(', ')\n\treturn styler.render(theme.roles.hint, `${SUGGESTION_LEAD}: ${values}`)\n}\n\n/** The line naming the choices a field shows but refuses, written above the list the walk drives. */\nexport function unavailableLine(\n\tstyler: StylerInterface,\n\ttheme: PromptTheme,\n\tchoices: readonly FieldChoice[],\n): string {\n\tconst labels = choices.map((choice) => choice.label).join(', ')\n\treturn styler.render(theme.roles.muted, `${UNAVAILABLE_LEAD}: ${labels}`)\n}\n\n/**\n * The numbered choice list the non-TTY fallback prints — a piped stream cannot navigate with arrow\n * keys, so each offered choice is printed with the number the reader types back. One line per\n * choice, with no trailing newline.\n *\n * @param styler - The console styler that renders each role\n * @param theme - The resolved prompt theme\n * @param choices - The choices the walk offers, from {@link enabledChoices}\n * @returns The rendered list\n */\nexport function numberedList(\n\tstyler: StylerInterface,\n\ttheme: PromptTheme,\n\tchoices: readonly FieldChoice[],\n): string {\n\treturn choices\n\t\t.map(\n\t\t\t(choice, index) =>\n\t\t\t\t` ${styler.render(theme.roles.muted, `${String(index + 1)})`)} ${styler.render(theme.roles.content, choice.label)}`,\n\t\t)\n\t\t.join('\\n')\n}\n","import type {\n\tFieldChoice,\n\tFieldError,\n\tFieldValue,\n\tFormField,\n\tFormInterface,\n\tFormValues,\n} from '@orkestrel/form'\nimport type {\n\tCheckboxField,\n\tConfirmField,\n\tEditorField,\n\tFileField,\n\tPasswordField,\n\tSelectField,\n} from '@orkestrel/form'\nimport type { KeyEvent, PromptStep, PromptTheme, TerminalInterface } from '@src/core'\nimport type { StylerInterface } from '@orkestrel/console'\nimport type { Interface } from 'node:readline'\nimport type { InputStreamInterface, OutputStreamInterface, TerminalOptions } from './types.js'\nimport {\n\tcheckboxReduce,\n\tconfirmReduce,\n\tcreateCheckboxState,\n\tcreateConfirmState,\n\tcreateEditorState,\n\tcreateInputState,\n\tcreatePasswordState,\n\tcreatePromptTheme,\n\tcreateSelectState,\n\teditorReduce,\n\terrorLine,\n\thintedHeader,\n\tinputReduce,\n\tparseKey,\n\tpasswordReduce,\n\tpromptHeader,\n\tsanitizeDisplayText,\n\tselectReduce,\n\tTerminalError,\n} from '@src/core'\nimport { matchesAnswer, parseValue } from '@orkestrel/form'\nimport { createStyler } from '@orkestrel/console'\nimport { createInterface } from 'node:readline'\nimport { stdin, stdout } from 'node:process'\nimport {\n\tCURSOR_HIDE,\n\tCURSOR_SHOW,\n\tFALLBACK_CHECKBOX_HINT,\n\tFALLBACK_CONFIRM_HINT,\n\tFALLBACK_EDITOR_HINT,\n\tFALLBACK_SELECT_HINT,\n\tFILE_HINT,\n\tLINE_FEED,\n\tREFUSAL_MESSAGE,\n} from './constants.js'\nimport {\n\tdisabledChoices,\n\tenabledChoices,\n\tfieldToText,\n\tgroupHeader,\n\tisInputStream,\n\tisOutputStream,\n\tisReadable,\n\tlineCount,\n\tlockedLine,\n\tnumberedList,\n\trawCapable,\n\tredrawPrefix,\n\tsuggestionLine,\n\tunavailableLine,\n\tvalueToText,\n} from './helpers.js'\n\n/**\n * The interactive terminal form DRIVER — the {@link TerminalInterface} implementation for a human at\n * this machine's keyboard, and the only impure part of the terminal stack. {@link ask} walks one\n * form's fields in schema order, feeds raw-mode stdin bytes through `parseKey` into the matching\n * pure reducer, renders each returned view in place, and binds every answer through the form's own\n * `fill`. It owns no form logic: the schema, the rules, the values, and the settlement all belong to\n * the form it is given, and this class owns only raw mode, the cursor, and the re-render.\n *\n * @remarks\n * See {@link TerminalInterface} for the driving contract. The walk itself:\n *\n * - **Twelve controls, seven reducers.** `text`, `number`, `date`, `time`, `datetime`, `color`, and\n * each `file` entry are read as one line of text through {@link fieldToText}, which appends that\n * control's format cue to the label. `password`, `confirm`, `editor`, `select`, and `checkbox`\n * each drive their own reducer. An open `select` is a suggestion list plus a typed line, because\n * `open` means the answer need not come from the list.\n * - **The binding projects through `matchesAnswer`.** Every answer is filled as\n * `fill(name, matchesAnswer(value) ? value : undefined)` after `parseValue` has coerced it to the\n * control's own shape, so a bare return on a field with no default binds as ABSENCE and the\n * form's `required` rule refuses it. A typed answer the control cannot hold binds as absence and\n * invalidates the field, so the walk asks again with the reason on screen.\n * - **Visibility is honored.** A `hidden` field and a field currently in `form.disabled` are\n * skipped; a `locked` field renders read-only; entering a new group writes its label as a section\n * header.\n * - **Refusal re-asks.** After the walk the form is submitted. A refusal re-walks only the erroring\n * fields the walk can edit and submits again. When every erroring field is one the walk cannot\n * edit — hidden, locked, or disabled — the form is abandoned instead, because asking again could\n * not change the answer.\n * - **Raw-mode leak-free.** Raw mode is entered once per field and always cleaned up: on submit, on\n * cancel, on a throw, and when the form is abandoned under an active read.\n * - **Non-TTY fallback.** When `input` is not a TTY, the same walk runs over `node:readline` line\n * input: `select` and `checkbox` print a numbered list, and `editor` reads to end of input.\n */\nexport class Terminal implements TerminalInterface {\n\treadonly #input: InputStreamInterface\n\treadonly #output: OutputStreamInterface\n\treadonly #styler: StylerInterface\n\treadonly #theme: PromptTheme\n\treadonly #handlers = new Map<object, (chunk: string | Uint8Array) => void>()\n\treadonly #queue: string[] = []\n\t#interface: Interface | undefined\n\t#taker: ((line: string | undefined) => void) | undefined\n\t#ended = false\n\n\tconstructor(options?: TerminalOptions) {\n\t\t// Resolve each stream through its guard: a present, well-shaped injected stream is used as is;\n\t\t// otherwise the real process stream — no assertion, and an absent option falls through.\n\t\tthis.#input = isInputStream(options?.input) ? options.input : stdin\n\t\tthis.#output = isOutputStream(options?.output) ? options.output : stdout\n\t\tthis.#styler = createStyler()\n\t\tthis.#theme = createPromptTheme(options?.theme)\n\t}\n\n\t// === The contract\n\n\tasync ask(form: FormInterface): Promise<FormValues> {\n\t\ttry {\n\t\t\tthis.#report(form, form.errors)\n\t\t\tawait this.#walk(form, form.schema.fields)\n\t\t\tfor (;;) {\n\t\t\t\tif (form.status !== 'editing') return await form.answer\n\t\t\t\tconst result = form.submit()\n\t\t\t\tif (result.success) return await form.answer\n\t\t\t\tthis.#report(form, result.error)\n\t\t\t\tconst again = this.#editable(form, result.error)\n\t\t\t\t// Nothing the walk can edit, or an input stream that has already ended: asking again would\n\t\t\t\t// render the same fields and read the same answers forever, so abandon the form instead.\n\t\t\t\t// The failures are on screen either way, so the reader sees what could not be answered.\n\t\t\t\tif (again.length === 0 || this.#ended) {\n\t\t\t\t\tform.destroy()\n\t\t\t\t\treturn await form.answer\n\t\t\t\t}\n\t\t\t\tawait this.#walk(form, again)\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.#close()\n\t\t}\n\t}\n\n\t// === The walk\n\n\t/**\n\t * Ask `fields` in the order given, skipping what the walk must not touch and rendering what it\n\t * must not edit. Returns early the moment the form stops being editable, so an abandoned form\n\t * ends the walk between fields as well as under an active read.\n\t */\n\tasync #walk(form: FormInterface, fields: readonly FormField[]): Promise<void> {\n\t\tlet group: string | undefined\n\t\tfor (const field of fields) {\n\t\t\tif (form.status !== 'editing') return\n\t\t\tif (field.hidden === true) continue\n\t\t\tif (form.disabled.has(field.name)) continue\n\t\t\tif (field.group !== group) {\n\t\t\t\tgroup = field.group\n\t\t\t\tif (group !== undefined) this.#group(form, group)\n\t\t\t}\n\t\t\tif (field.locked === true) {\n\t\t\t\tthis.#locked(form, field)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst raw = await this.#read(form, field)\n\t\t\tif (form.status !== 'editing') return\n\t\t\tthis.#bind(form, field, raw)\n\t\t}\n\t}\n\n\t/** Write a group's label as a section header, resolving the schema's declared label and falling back to the group's own name. */\n\t#group(form: FormInterface, name: string): void {\n\t\tconst label = form.schema.groups?.find((group) => group.name === name)?.label ?? name\n\t\tthis.#output.write(\n\t\t\t`${LINE_FEED}${groupHeader(this.#styler, this.#theme, sanitizeDisplayText(label))}${LINE_FEED}`,\n\t\t)\n\t}\n\n\t/** Render a locked field read-only — its label, its mark, and the answer the form already holds. */\n\t#locked(form: FormInterface, field: FormField): void {\n\t\tconst line = lockedLine(\n\t\t\tthis.#styler,\n\t\t\tthis.#theme,\n\t\t\tsanitizeDisplayText(field.label ?? field.name),\n\t\t\tsanitizeDisplayText(valueToText(form.values[field.name])),\n\t\t)\n\t\tthis.#output.write(`${line}${LINE_FEED}`)\n\t}\n\n\t/** Read one field through the reducer its control names, resolving the raw answer the binding projects. */\n\t#read(form: FormInterface, field: FormField): Promise<FieldValue | undefined> {\n\t\tif (field.control === 'password') return this.#password(form, field)\n\t\tif (field.control === 'confirm') return this.#confirm(form, field)\n\t\tif (field.control === 'editor') return this.#editor(form, field)\n\t\tif (field.control === 'select') return this.#select(form, field)\n\t\tif (field.control === 'checkbox') return this.#checkbox(form, field)\n\t\tif (field.control === 'file') return this.#file(form, field)\n\t\treturn this.#text(form, field)\n\t}\n\n\t/**\n\t * Bind one raw answer to the form — the single binding, and the only place this driver writes a\n\t * value. `parseValue` coerces the raw answer to the control's own shape and `matchesAnswer`\n\t * projects a blank one to absence, which is what keeps `required` refusing a bare return. A raw\n\t * answer the control cannot hold binds as absence and invalidates the field, so the field comes\n\t * back on the next pass carrying the reason rather than vanishing silently.\n\t */\n\t#bind(form: FormInterface, field: FormField, raw: FieldValue | undefined): void {\n\t\tform.touch(field.name)\n\t\tconst value = raw === undefined ? undefined : parseValue(field, raw)\n\t\tform.fill(field.name, matchesAnswer(value) ? value : undefined)\n\t\tif (value === undefined && matchesAnswer(raw)) form.invalidate(field.name, REFUSAL_MESSAGE)\n\t}\n\n\t/** The erroring fields the walk can ask again — every field the walk skips or renders read-only is excluded, because a second pass could not change its answer. */\n\t#editable(form: FormInterface, errors: readonly FieldError[]): readonly FormField[] {\n\t\tconst fields: FormField[] = []\n\t\tfor (const error of errors) {\n\t\t\tconst field = form.field(error.field)\n\t\t\tif (field === undefined) continue\n\t\t\tif (field.hidden === true || field.locked === true) continue\n\t\t\tif (form.disabled.has(field.name)) continue\n\t\t\tif (fields.some((held) => held.name === field.name)) continue\n\t\t\tfields.push(field)\n\t\t}\n\t\treturn fields\n\t}\n\n\t/** Write every supplied failure against its field's label. */\n\t#report(form: FormInterface, errors: readonly FieldError[]): void {\n\t\tfor (const error of errors) {\n\t\t\tconst label = sanitizeDisplayText(form.field(error.field)?.label ?? error.field)\n\t\t\tconst message = sanitizeDisplayText(error.message)\n\t\t\tconst line = errorLine(this.#styler, this.#theme, `${label}: ${message}`)\n\t\t\tthis.#output.write(`${line}${LINE_FEED}`)\n\t\t}\n\t}\n\n\t// === The controls\n\n\t/** Read a field as one line of text — `text` itself and the six controls a terminal has no widget for. */\n\t#text(form: FormInterface, field: FormField): Promise<string> {\n\t\tconst state = createInputState(fieldToText(field), this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, inputReduce)\n\t\treturn this.#line(form, state.message, state.default)\n\t}\n\n\t/** Read a secret — masked live in raw mode, and read without echo through readline on a stream that cannot enter it. */\n\t#password(form: FormInterface, field: PasswordField): Promise<string> {\n\t\tconst state = createPasswordState(field, this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, passwordReduce)\n\t\treturn this.#prompt(form, promptHeader(this.#styler, this.#theme, state.message))\n\t}\n\n\t/**\n\t * Read a yes or no. The fallback accepts `y` / `yes` / `n` / `no` in any case and takes the\n\t * field's default for a bare line; anything else is returned as typed, so the binding refuses it\n\t * and the walk asks again rather than silently reading it as no.\n\t */\n\tasync #confirm(form: FormInterface, field: ConfirmField): Promise<FieldValue> {\n\t\tconst state = createConfirmState(field, this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, confirmReduce)\n\t\tconst header = hintedHeader(this.#styler, this.#theme, state.message, FALLBACK_CONFIRM_HINT)\n\t\tconst line = await this.#prompt(form, header)\n\t\tconst answer = line.trim().toLowerCase()\n\t\tif (answer.length === 0) return state.default\n\t\tif (answer === 'y' || answer === 'yes') return true\n\t\tif (answer === 'n' || answer === 'no') return false\n\t\treturn line.trim()\n\t}\n\n\t/** Read text over many lines — ctrl-d finishes in raw mode, and end of input finishes on a piped stream. */\n\t#editor(form: FormInterface, field: EditorField): Promise<string> {\n\t\tconst state = createEditorState(field, this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, editorReduce)\n\t\treturn this.#block(form, state.message, state.default)\n\t}\n\n\t/**\n\t * Read one choice. A disabled choice is named above the list and never offered, because the form\n\t * refuses its value at every door. An open select is a suggestion list plus a typed line, since\n\t * `open` admits an answer the list does not offer; a closed select with nothing left to offer\n\t * resolves absence and lets the form's own rules report it.\n\t */\n\tasync #select(form: FormInterface, field: SelectField): Promise<FieldValue | undefined> {\n\t\tconst choices = enabledChoices(field.choices)\n\t\tthis.#unavailable(field.choices)\n\t\tif (field.open === true) {\n\t\t\tif (choices.length > 0) {\n\t\t\t\tconst display = choices.map((choice) => ({\n\t\t\t\t\t...choice,\n\t\t\t\t\tvalue: sanitizeDisplayText(choice.value),\n\t\t\t\t}))\n\t\t\t\tthis.#output.write(`${suggestionLine(this.#styler, this.#theme, display)}${LINE_FEED}`)\n\t\t\t}\n\t\t\treturn this.#text(form, field)\n\t\t}\n\t\tif (choices.length === 0) return undefined\n\t\tconst state = createSelectState({ ...field, choices }, this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, selectReduce)\n\t\tthis.#list(state.message, choices)\n\t\tconst line = await this.#prompt(form, this.#hint(`${FALLBACK_SELECT_HINT}:`))\n\t\treturn choices[Number.parseInt(line.trim(), 10) - 1]?.value\n\t}\n\n\t/**\n\t * Read any number of choices. Disabled choices are named above the list and never offered, so a\n\t * box the form would refuse can never be ticked. An empty answer is an answered \"none of them\",\n\t * which is what `matchesAnswer` says an empty list means.\n\t */\n\tasync #checkbox(form: FormInterface, field: CheckboxField): Promise<FieldValue> {\n\t\tconst choices = enabledChoices(field.choices)\n\t\tthis.#unavailable(field.choices)\n\t\tconst state = createCheckboxState({ ...field, choices }, this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, checkboxReduce)\n\t\tthis.#list(state.message, choices)\n\t\tconst line = await this.#prompt(form, this.#hint(`${FALLBACK_CHECKBOX_HINT}:`))\n\t\treturn line\n\t\t\t.split(',')\n\t\t\t.map((part) => choices[Number.parseInt(part.trim(), 10) - 1]?.value)\n\t\t\t.filter((value): value is string => value !== undefined)\n\t}\n\n\t/**\n\t * Read file paths — names only, because bytes never enter a form. A `multiple` field collects one\n\t * path per line until a blank one, and a single field takes one. No path at all is absence rather\n\t * than an empty list, because the reader answered a blank line.\n\t */\n\tasync #file(form: FormInterface, field: FileField): Promise<FieldValue | undefined> {\n\t\tif (field.multiple === true) this.#output.write(`${this.#hint(FILE_HINT)}${LINE_FEED}`)\n\t\tconst paths: string[] = []\n\t\tfor (;;) {\n\t\t\tconst entry = await this.#text(form, field)\n\t\t\tif (entry.length === 0) break\n\t\t\tpaths.push(entry)\n\t\t\tif (field.multiple !== true || this.#ended) break\n\t\t}\n\t\treturn paths.length > 0 ? paths : undefined\n\t}\n\n\t/** Name the choices a field shows but refuses, above the list the walk drives. */\n\t#unavailable(choices: readonly FieldChoice[]): void {\n\t\tconst refused = disabledChoices(choices)\n\t\tif (refused.length === 0) return\n\t\tthis.#output.write(`${unavailableLine(this.#styler, this.#theme, refused)}${LINE_FEED}`)\n\t}\n\n\t/** Write a field's header above its numbered choice list — the non-TTY presentation of a choice field. */\n\t#list(message: string, choices: readonly FieldChoice[]): void {\n\t\tconst header = promptHeader(this.#styler, this.#theme, message)\n\t\tconst list = numberedList(this.#styler, this.#theme, choices)\n\t\tthis.#output.write(`${header}${LINE_FEED}${list}${LINE_FEED}`)\n\t}\n\n\t/** Paint one line of supplementary instruction through the `hint` role. */\n\t#hint(text: string): string {\n\t\treturn this.#styler.render(this.#theme.roles.hint, text)\n\t}\n\n\t// === The raw-mode kernel\n\n\t/**\n\t * The irreducible Node raw-mode primitive — the ONLY place raw mode is touched. Switches the input\n\t * into raw mode (each keypress delivered immediately, no echo), resumes its flow, and subscribes\n\t * `handler` to `'data'`. The paired {@link #leaveRaw} operation unsubscribes the exact handler,\n\t * leaves raw mode, and pauses the stream on submit, cancel, abandon, or throw.\n\t */\n\t#enterRaw(token: object, handler: (chunk: string | Uint8Array) => void): void {\n\t\tthis.#handlers.set(token, handler)\n\t\tthis.#input.setRawMode?.(true)\n\t\tthis.#input.resume?.()\n\t\tthis.#input.on('data', handler)\n\t}\n\n\t#leaveRaw(token: object): void {\n\t\tconst handler = this.#handlers.get(token)\n\t\tif (handler === undefined) return\n\t\tthis.#handlers.delete(token)\n\t\tthis.#input.off('data', handler)\n\t\tthis.#input.setRawMode?.(false)\n\t\tthis.#input.pause?.()\n\t}\n\n\t/**\n\t * Drive ONE field over raw-mode stdin — the generic engine every interactive control shares.\n\t * Renders the reducer's initial view, enters raw mode once, and on each keypress runs `parseKey` →\n\t * `reduce` → an in-place re-render; on `submit` it cleans up and resolves the reducer's value, on\n\t * `cancel` (ctrl-c) it cleans up and rejects a {@link TerminalError} coded `CANCEL`. Abandoning\n\t * the form ends the read too, through the rejection of its own `answer`. Raw mode is entered\n\t * exactly once and cleaned up on every exit path, so no raw mode and no `'data'` listener ever\n\t * leaks. The cursor is hidden for the duration and restored on exit.\n\t */\n\t#drive<T, S>(\n\t\tform: FormInterface,\n\t\tinitial: S,\n\t\treduce: (state: S, key: KeyEvent) => PromptStep<T, S>,\n\t): Promise<T> {\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\t// Render the first view, tracking how many lines it spans so the next redraw climbs over them.\n\t\t\tthis.#output.write(CURSOR_HIDE)\n\t\t\tlet firstView: string\n\t\t\ttry {\n\t\t\t\tfirstView = reduce(initial, parseKey('')).view\n\t\t\t\tthis.#output.write(firstView)\n\t\t\t} catch (error) {\n\t\t\t\t// Raw mode was never entered yet, but the cursor was hidden — restore it before rejecting.\n\t\t\t\tthis.#output.write(`${CURSOR_SHOW}${LINE_FEED}`)\n\t\t\t\treject(error)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst token = {}\n\t\t\tconst handler = this.#createHandler(\n\t\t\t\ttoken,\n\t\t\t\tinitial,\n\t\t\t\tlineCount(firstView),\n\t\t\t\treduce,\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t)\n\t\t\tthis.#enterRaw(token, handler)\n\t\t\t// An abandoned form ends the read: its own `answer` rejects, so release the terminal and fail\n\t\t\t// this field with the form's error. A read that already finished holds no token and is a no-op.\n\t\t\tvoid form.answer.catch((error: unknown) => this.#interrupt(token, reject, error))\n\t\t})\n\t}\n\n\t#createHandler<T, S>(\n\t\ttoken: object,\n\t\tinitial: S,\n\t\tinitialLines: number,\n\t\treduce: (state: S, key: KeyEvent) => PromptStep<T, S>,\n\t\tresolve: (value: T | PromiseLike<T>) => void,\n\t\treject: (reason?: unknown) => void,\n\t): (chunk: string | Uint8Array) => void {\n\t\tlet state = initial\n\t\tlet lines = initialLines\n\t\treturn (chunk) => {\n\t\t\ttry {\n\t\t\t\tconst step = reduce(state, parseKey(chunk))\n\t\t\t\tstate = step.state\n\t\t\t\tif (step.status === 'active') {\n\t\t\t\t\tthis.#render(step.view, lines)\n\t\t\t\t\tlines = lineCount(step.view)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// Terminal step (submit / cancel): paint the final committed view, then tear down.\n\t\t\t\tthis.#render(step.view, lines)\n\t\t\t\tthis.#leaveRaw(token)\n\t\t\t\tthis.#output.write(`${CURSOR_SHOW}${LINE_FEED}`)\n\t\t\t\tif (step.status === 'cancel') reject(new TerminalError('CANCEL', 'Prompt cancelled'))\n\t\t\t\telse if (step.status === 'submit' && step.value !== undefined) resolve(step.value)\n\t\t\t\telse reject(new TerminalError('DRIVER', 'submit produced no value'))\n\t\t\t} catch (error) {\n\t\t\t\t// A throw inside the reducer/styler: tear down raw mode + the listener, restore the cursor\n\t\t\t\t// exactly as the normal exit path does, then reject.\n\t\t\t\tthis.#leaveRaw(token)\n\t\t\t\tthis.#output.write(`${CURSOR_SHOW}${LINE_FEED}`)\n\t\t\t\treject(error)\n\t\t\t}\n\t\t}\n\t}\n\n\t/** End an active read that the form outlived — release raw mode exactly as a submit does, then fail the read with the form's own error. */\n\t#interrupt(token: object, reject: (reason?: unknown) => void, error: unknown): void {\n\t\tif (!this.#handlers.has(token)) return\n\t\tthis.#leaveRaw(token)\n\t\tthis.#output.write(`${CURSOR_SHOW}${LINE_FEED}`)\n\t\treject(error)\n\t}\n\n\t/** Redraw a field view in place — climb over the previous view's `previousLines`, clear, and write the new view (the pure cursor-math is {@link redrawPrefix}). */\n\t#render(view: string, previousLines: number): void {\n\t\tthis.#output.write(`${redrawPrefix(previousLines)}${view}`)\n\t}\n\n\t// === Non-TTY fallbacks (node:readline line input)\n\n\t/** Read one line for a text-shaped field, taking the field's default when the line is bare. */\n\tasync #line(form: FormInterface, message: string, seed: string): Promise<string> {\n\t\tconst answer = await this.#prompt(form, promptHeader(this.#styler, this.#theme, message))\n\t\treturn answer.length > 0 ? answer : seed\n\t}\n\n\t/**\n\t * Read a whole block for an `editor` field — a piped stream has no ctrl-d keypress, so end of\n\t * input is the terminator. It drains every remaining line, which is why nothing after an `editor`\n\t * field can be asked on the same stream.\n\t */\n\tasync #block(form: FormInterface, message: string, seed: string): Promise<string> {\n\t\tconst header = hintedHeader(this.#styler, this.#theme, message, FALLBACK_EDITOR_HINT)\n\t\tthis.#output.write(`${header}${LINE_FEED}`)\n\t\tconst collected: string[] = []\n\t\tfor (;;) {\n\t\t\tconst line = await this.#next(form)\n\t\t\tif (line === undefined) break\n\t\t\tcollected.push(line)\n\t\t}\n\t\tconst text = collected.join('\\n')\n\t\treturn text.length > 0 ? text : seed\n\t}\n\n\t/** Write one field's header and read back the line the reader answers it with, or `''` once the stream has ended. */\n\tasync #prompt(form: FormInterface, header: string): Promise<string> {\n\t\tthis.#output.write(`${header} `)\n\t\tconst line = await this.#next(form)\n\t\treturn line ?? ''\n\t}\n\n\t/**\n\t * Take the next line the input carries — from the buffer when the reader has already read ahead,\n\t * and otherwise by waiting for one. It resolves ABSENCE once the stream has ended, so a walk over\n\t * an exhausted stream settles instead of waiting forever, and it rejects when the form is\n\t * abandoned, so an unanswerable read ends with the form rather than outliving it.\n\t */\n\t#next(form: FormInterface): Promise<string | undefined> {\n\t\tconst buffered = this.#queue.shift()\n\t\tif (buffered !== undefined) return Promise.resolve(buffered)\n\t\tif (this.#ended) return Promise.resolve(undefined)\n\t\tthis.#reader()\n\t\treturn new Promise<string | undefined>((resolve, reject) => {\n\t\t\tthis.#taker = resolve\n\t\t\tvoid form.answer.catch((error: unknown) => {\n\t\t\t\tif (this.#taker !== resolve) return\n\t\t\t\tthis.#taker = undefined\n\t\t\t\treject(error)\n\t\t\t})\n\t\t})\n\t}\n\n\t/**\n\t * Open the walk's ONE readline interface, or keep the open one. A whole form is many questions\n\t * over one stream, and an interface reads ahead: a fresh interface per question would swallow\n\t * every line it read past the one it was asked for, so the walk holds a single reader and buffers\n\t * what arrives early. It is closed when the walk ends, so the process is free to exit.\n\t */\n\t#reader(): void {\n\t\tif (this.#interface !== undefined) return\n\t\tconst rl = createInterface(this.#readline())\n\t\trl.on('line', (line) => this.#accept(line))\n\t\trl.on('close', () => this.#finish())\n\t\tthis.#interface = rl\n\t}\n\n\t/** Hand a line to whoever is waiting for it, or buffer it for the next question. */\n\t#accept(line: string): void {\n\t\tconst taker = this.#taker\n\t\tif (taker === undefined) {\n\t\t\tthis.#queue.push(line)\n\t\t\treturn\n\t\t}\n\t\tthis.#taker = undefined\n\t\ttaker(line)\n\t}\n\n\t/** Record that no further line can arrive and release whoever was waiting for one. */\n\t#finish(): void {\n\t\tthis.#ended = true\n\t\tconst taker = this.#taker\n\t\tif (taker === undefined) return\n\t\tthis.#taker = undefined\n\t\ttaker(undefined)\n\t}\n\n\t/** Close the walk's reader and release a waiting question — the walk is over, so the stream must stop holding the process open. */\n\t#close(): void {\n\t\tconst taker = this.#taker\n\t\tthis.#taker = undefined\n\t\tif (taker !== undefined) taker(undefined)\n\t\tconst rl = this.#interface\n\t\tif (rl === undefined) return\n\t\tthis.#interface = undefined\n\t\t// Drop the close listener first: this close is the walk ending, not the stream ending, and\n\t\t// recording it as end of input would refuse the next walk its input.\n\t\trl.removeAllListeners('close')\n\t\trl.close()\n\t}\n\n\t/**\n\t * Narrow the resolved input to the `node:readline` `createInterface` boundary, never an assertion.\n\t * The fallback only runs on a real piped `process.stdin` (or a `PassThrough` a test injects), both\n\t * genuine readables; a minimal non-readable fake reaching here means the walk was driven with a\n\t * stream it cannot use, which fails loudly rather than silently. `terminal: false` leaves readline\n\t * as a line decoder and nothing else: the walk writes every prompt itself, through the same output\n\t * every other line goes to, so nothing is written twice and a secret is never echoed.\n\t */\n\t#readline(): { input: NodeJS.ReadableStream; terminal: boolean } {\n\t\t// Bind to a local first — a guard narrows a local, not a `#private` field access.\n\t\tconst input = this.#input\n\t\tif (!isReadable(input))\n\t\t\tthrow new TerminalError('DRIVER', 'Terminal fallback requires a readable input stream')\n\t\treturn { input, terminal: false }\n\t}\n}\n","import type { TerminalInterface } from '@src/core'\nimport type { TerminalOptions } from './types.js'\nimport { Terminal } from './Terminal.js'\n\n/**\n * Create the interactive terminal form driver — the local-keyboard arm of the terminal trio, beside\n * the core headless `createPrompt` broker and the SSE `createPromptClient` bridge. Where the broker\n * PARKS a live form until somebody elsewhere answers it, a `Terminal` answers one HERE: it walks the\n * form's fields in schema order, drives each control's pure reducer over raw-mode stdin, binds every\n * answer through the form's own `fill`, and submits. It is the only impure part of the terminal\n * stack.\n *\n * @param options - See {@link TerminalOptions}\n * @returns A {@link TerminalInterface} whose `ask` drives one whole form over the resolved streams\n *\n * @remarks\n * - **The form is the unit.** `ask` takes the caller's live form and returns its settled values. The\n * returned promise is that form's own `answer`, so a caller holding the form can await either one.\n * - **Every control renders.** Seven controls are read as a line of text with their format cue,\n * `password` masks, `confirm` takes a key, `editor` takes a block, `select` and `checkbox` drive a\n * list, and an open `select` accepts a value its list does not offer.\n * - **The form decides.** A blank answer binds as absence, the form evaluates, and a refusal\n * re-walks only the fields the walk can still edit.\n * - **Injectable and guard-narrowed.** `input` and `output` default to `process.stdin` and\n * `process.stdout` but accept any stream of the declared minimal shape, resolved through their\n * guards rather than an assertion, so a test drives a whole form with a fake TTY that emits\n * scripted key chunks and records every rendered byte.\n * - **Non-TTY fallback.** A piped stream cannot enter raw mode, so the same walk runs over\n * `node:readline` line input.\n *\n * @example\n * ```ts\n * import { createForm } from '@orkestrel/form'\n * import { createTerminal } from '@orkestrel/terminal/server'\n *\n * const terminal = createTerminal()\n * const values = await terminal.ask(\n * \tcreateForm({\n * \t\tlabel: 'Sign up',\n * \t\tfields: [\n * \t\t\t{ control: 'text', name: 'email', label: 'Email', rule: { required: true, email: true } },\n * \t\t\t{ control: 'confirm', name: 'terms', label: 'I accept the terms' },\n * \t\t],\n * \t}),\n * )\n * ```\n */\nexport function createTerminal(options?: TerminalOptions): TerminalInterface {\n\treturn new Terminal(options)\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":["#input","#output","#styler","#theme","#handlers","#queue","#report","#walk","#editable","#ended","#close","#group","#locked","#read","#bind","#password","#confirm","#editor","#select","#checkbox","#file","#text","#drive","#line","#prompt","#block","#unavailable","#list","#hint","#createHandler","#enterRaw","#interrupt","#render","#leaveRaw","#next","#reader","#taker","#interface","#readline","#accept","#finish"],"sources":["../../../src/server/constants.ts","../../../src/server/helpers.ts","../../../src/server/Terminal.ts","../../../src/server/factories.ts"],"sourcesContent":["// Server-terminals constants — the cursor and line-clear ANSI sequences the interactive `Terminal`\n// driver writes to redraw a field view IN PLACE, plus the copy the walk shows around those views:\n// the per-control format hints, the readline-fallback prompts, and the marks for a locked field and\n// an unavailable choice. UPPER_SNAKE, every member exported. Sequences are built from a named ESC\n// byte through `String.fromCharCode` so no raw control character appears in source (the core\n// terminals / console-module idiom).\n\nimport type { FieldControl } from '@orkestrel/form'\n\n/** The Escape byte (ESC, U+001B) — the lead byte of every CSI cursor-control sequence below. */\nexport const ESCAPE = String.fromCharCode(27)\n\n/** The Control Sequence Introducer (`ESC[`) — the prefix of every cursor / erase sequence. */\nexport const CSI = `${ESCAPE}[`\n\n/**\n * The cursor-UP sequence TEMPLATE (`ESC[{count}A`) — {@link import('./helpers.js').moveUp}\n * interpolates the `{count}` placeholder with the number of lines to climb. Kept as a template so\n * the count stays out of the constant.\n */\nexport const CSI_UP = `${CSI}{count}A`\n\n/**\n * Hide the cursor (`ESC[?25l`) — written before the driver starts redrawing a prompt so the cursor\n * does not flicker across the view during an in-place re-render; paired with {@link CURSOR_SHOW}.\n */\nexport const CURSOR_HIDE = `${CSI}?25l`\n\n/** Show the cursor (`ESC[?25h`) — restores the cursor after a prompt resolves / cancels (the {@link CURSOR_HIDE} pair). */\nexport const CURSOR_SHOW = `${CSI}?25h`\n\n/**\n * Erase from the cursor down to the end of the screen (`ESC[J`) — wipes the WHOLE previous (possibly\n * multi-line `select` / `checkbox`) view in one write before the new view is rendered, so a redraw\n * never leaves orphaned rows below.\n */\nexport const CLEAR_DOWN = `${CSI}J`\n\n/** A carriage return (`\\r`, U+000D) — returns the cursor to column 0 so a redraw starts at the line's left edge. */\nexport const CARRIAGE_RETURN = String.fromCharCode(13)\n\n/** A line feed (`\\n`, U+000A) — the line terminator the driver writes after the final committed prompt view. */\nexport const LINE_FEED = String.fromCharCode(10)\n\n/**\n * The numbered-list prompt the non-TTY {@link import('./Terminal.js').Terminal} `select` fallback\n * appends — a piped (non-terminal) stream cannot navigate with arrow keys, so the choices are\n * printed numbered and the user types one number on a single readline line.\n */\nexport const FALLBACK_SELECT_HINT = 'Enter a number'\n\n/** The comma-separated multi-select hint the non-TTY `checkbox` fallback shows (the user types one or more numbers). */\nexport const FALLBACK_CHECKBOX_HINT = 'Enter numbers separated by commas'\n\n/** The hint the non-TTY `editor` fallback shows — a piped stream has no ctrl-d, so end of input finishes the block. */\nexport const FALLBACK_EDITOR_HINT = '(end of input finishes)'\n\n/** The hint the non-TTY `confirm` fallback shows — a piped stream sends a whole line, so the answer is typed rather than pressed. */\nexport const FALLBACK_CONFIRM_HINT = '(y/n)'\n\n/**\n * The format cue appended to a field's label for each control the walk reads as a line of text —\n * the terminal has no date picker, no color well, and no file chooser, so the accepted shape is\n * stated instead. A control with no entry needs none: `text` and `editor` accept any line,\n * `password` masks one, and `confirm`, `select`, and `checkbox` are answered by key rather than by\n * format. The form's own rules still decide whether the typed value is acceptable.\n */\nexport const CONTROL_HINTS: Readonly<Partial<Record<FieldControl, string>>> = Object.freeze({\n\tnumber: '(number)',\n\tdate: '(YYYY-MM-DD)',\n\ttime: '(HH:MM)',\n\tdatetime: '(YYYY-MM-DDTHH:MM)',\n\tcolor: '(#rrggbb)',\n\tfile: '(path)',\n})\n\n/** The instruction a `file` field with `multiple` shows before its entries — one path per line, and a blank line ends the list. */\nexport const FILE_HINT = 'One path per line, blank to finish'\n\n/** The lead on the line listing an open `select`'s offered values, which a typed answer may ignore. */\nexport const SUGGESTION_LEAD = 'Suggestions'\n\n/** The lead on the line listing the choices a `select` or `checkbox` shows but refuses, so a reader sees why one is missing from the list below. */\nexport const UNAVAILABLE_LEAD = 'Unavailable'\n\n/** The mark on a locked field's line — the walk renders its value and moves on, because the form refuses an edit there. */\nexport const LOCKED_MARK = '(locked)'\n\n/**\n * What a field is told when the walk read an answer the control cannot hold — a word typed into a\n * `number`, an off-list value typed into an open `select` whose choice is refused. The value binds\n * as absence and this message is invalidated onto the field, so the walk re-asks it with the reason\n * on screen.\n */\nexport const REFUSAL_MESSAGE = 'Enter a value this field accepts'\n","// Pure helpers for the server terminal driver — every function here is exported and unit-tested.\n// Three families, all total: the stream-boundary guards that narrow `process.stdin` /\n// `process.stdout` / any injected stream without an assertion; the cursor math the driver uses to\n// redraw a field view IN PLACE (count a view's lines, build the cursor-up sequence, assemble the\n// reposition-and-clear prefix); and the projections and line renderers the whole-form walk needs\n// that no reducer owns — a control read as text, a value shown read-only, the choices a field\n// actually offers, and the group, locked, suggestion, unavailable, and numbered-list lines. The\n// impure driver only feeds bytes into the reducers and writes the strings these helpers build.\n\nimport type { FieldChoice, FieldValue, FormField, TextField } from '@orkestrel/form'\nimport type { PromptTheme } from '@src/core'\nimport type { StylerInterface } from '@orkestrel/console'\nimport type { InputStreamInterface, OutputStreamInterface } from './types.js'\nimport {\n\tCARRIAGE_RETURN,\n\tCLEAR_DOWN,\n\tCONTROL_HINTS,\n\tCSI_UP,\n\tLOCKED_MARK,\n\tSUGGESTION_LEAD,\n\tUNAVAILABLE_LEAD,\n} from './constants.js'\n\n/**\n * Whether `value` is a usable {@link InputStreamInterface} — a record with callable `on` / `off`\n * `'data'` subscription methods. A total type guard (AGENTS §14): it NEVER throws and returns `false`\n * for anything off-shape, so it narrows the one unavoidable input boundary (the real `process.stdin`,\n * or a fake TTY a test injects) to the exact slice the driver reads — no `as`.\n *\n * @remarks\n * Only `on` / `off` are required (the irreducible event seam); `setRawMode` / `resume` / `pause` /\n * `isTTY` are optional on {@link InputStreamInterface}, so their absence does not disqualify a stream\n * — a piped, non-TTY stream is still a valid input, just one the driver reads through the readline\n * fallback rather than raw mode.\n *\n * @param value - Any value crossing the boundary (a process stream, an injected fake, `unknown`)\n * @returns `true` when `value` has callable `on` and `off`\n */\nexport function isInputStream(value: unknown): value is InputStreamInterface {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'on' in value &&\n\t\ttypeof value.on === 'function' &&\n\t\t'off' in value &&\n\t\ttypeof value.off === 'function'\n\t)\n}\n\n/**\n * Whether `value` is a usable {@link OutputStreamInterface} — a record with a callable `write`. A\n * total type guard (AGENTS §14): it NEVER throws and returns `false` for anything off-shape, so it\n * narrows the output boundary (the real `process.stdout`, or a recording fake a test injects) to the\n * one method the driver writes through — no `as`.\n *\n * @param value - Any value crossing the boundary (a process stream, an injected fake, `unknown`)\n * @returns `true` when `value` has a callable `write`\n */\nexport function isOutputStream(value: unknown): value is OutputStreamInterface {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'write' in value &&\n\t\ttypeof value.write === 'function'\n\t)\n}\n\n/**\n * Whether `value` is a Node {@link NodeJS.ReadableStream} — a total structural guard (AGENTS §14)\n * checking for the callable `read` / `pipe` / `on` that `node:readline`'s `createInterface` requires\n * as its `input`. The non-TTY fallback narrows the resolved input stream through this before handing\n * it to readline (never an `as`), so a real piped `process.stdin` (or a `PassThrough` a test injects)\n * crosses into the readline boundary honestly. Never throws; returns `false` for a minimal fake that\n * isn't a full readable.\n *\n * @param value - The resolved input stream (or any value crossing the boundary)\n * @returns `true` when `value` has the readable methods readline needs\n */\nexport function isReadable(value: unknown): value is NodeJS.ReadableStream {\n\treturn (\n\t\ttypeof value === 'object' &&\n\t\tvalue !== null &&\n\t\t'read' in value &&\n\t\ttypeof value.read === 'function' &&\n\t\t'pipe' in value &&\n\t\ttypeof value.pipe === 'function'\n\t)\n}\n\n/**\n * Whether an input stream can be driven in RAW mode — it both reports `isTTY === true` AND exposes a\n * callable `setRawMode`. The {@link import('./Terminal.js').Terminal} probes this to choose its path:\n * `true` ⇒ the interactive raw-mode prompts (arrow-key navigation, live re-render); `false` ⇒ the\n * `node:readline` line-input fallback (a piped / non-terminal stream cannot enter raw mode). Total —\n * never throws.\n *\n * @param input - The resolved {@link InputStreamInterface}\n * @returns `true` when the stream is a TTY with `setRawMode`\n */\nexport function rawCapable(input: InputStreamInterface): boolean {\n\treturn input.isTTY === true && typeof input.setRawMode === 'function'\n}\n\n/**\n * The number of terminal LINES a rendered prompt `view` occupies — one more than its newline count\n * (a view with no newline is a single line; N newlines span N+1 lines). The basis of the in-place\n * re-render: the driver records the line count of the view it just wrote so the next redraw knows how\n * far up to move the cursor before overwriting. Total; an empty string is one (empty) line.\n *\n * @param view - The rendered (possibly multi-line, possibly ANSI-styled) view string\n * @returns The number of lines the view spans (always at least 1)\n */\nexport function lineCount(view: string): number {\n\tlet lines = 1\n\tfor (const character of view) {\n\t\tif (character === '\\n') lines += 1\n\t}\n\treturn lines\n}\n\n/**\n * The cursor-UP control sequence that moves the cursor up `count` lines (`ESC[{count}A`) — or the\n * empty string when `count` is zero or negative (no movement needed, and `ESC[0A` is a wasted write).\n * The pure step the in-place re-render uses to climb back over the previous view before clearing it.\n * Total.\n *\n * @param count - How many lines to move the cursor up\n * @returns The `ESC[{count}A` sequence, or `''` when `count <= 0`\n */\nexport function moveUp(count: number): string {\n\tif (count <= 0) return ''\n\treturn `${CSI_UP.replace('{count}', String(count))}`\n}\n\n/**\n * The full reposition-and-clear prefix to write BEFORE re-rendering a prompt view in place — given\n * the line count of the PREVIOUS view, it moves the cursor up over those lines, returns it to column\n * 0, and erases everything from there to the end of the screen, so the next view is drawn on a clean\n * region (no orphaned rows from a taller previous view). Pure; the driver writes this immediately\n * followed by the new view.\n *\n * @remarks\n * For the FIRST render `previousLines` is `1` (the cursor sits on the line the prompt opened on) so\n * the prefix is just a carriage return + clear-down — the prompt draws from the current line. For a\n * subsequent render it climbs `previousLines - 1` lines (the cursor is on the LAST line of the prior\n * view) before clearing. Keeping the math here (not in the driver) makes the re-render unit-testable\n * without a real terminal.\n *\n * @param previousLines - The line count of the view currently on screen (from {@link lineCount})\n * @returns The control-sequence prefix to write before the new view\n */\nexport function redrawPrefix(previousLines: number): string {\n\treturn `${moveUp(previousLines - 1)}${CARRIAGE_RETURN}${CLEAR_DOWN}`\n}\n\n/**\n * Project any field the walk reads as a LINE OF TEXT into the {@link TextField} the text reducer\n * takes — `text` itself, and the six controls a terminal has no widget for: `number`, `date`,\n * `time`, `datetime`, `color`, and one `file` entry. The label carries that control's format cue\n * from {@link CONTROL_HINTS}, and a declared `default` becomes the line a bare return submits. The\n * projection carries no rule, because the AUTHORITATIVE form still evaluates the answer this line\n * binds; it exists only so one reducer can render seven controls.\n *\n * @param field - The field being read\n * @returns The text field the reducer renders for it\n *\n * @example\n * ```ts\n * fieldToText({ control: 'date', name: 'born', label: 'Birthday' })\n * // { control: 'text', name: 'born', label: 'Birthday (YYYY-MM-DD)' }\n * ```\n */\nexport function fieldToText(field: FormField): TextField {\n\tconst label = field.label ?? field.name\n\tconst hint = CONTROL_HINTS[field.control]\n\tconst seed = 'default' in field ? field.default : undefined\n\tconst text = typeof seed === 'number' ? String(seed) : seed\n\treturn {\n\t\tcontrol: 'text',\n\t\tname: field.name,\n\t\tlabel: hint === undefined ? label : `${label} ${hint}`,\n\t\t...(typeof text === 'string' ? { default: text } : {}),\n\t}\n}\n\n/**\n * Project one held answer into the text a read-only line shows — a scalar as itself, a boolean as\n * `yes` / `no` (the word the confirm reducer commits), and a list joined by commas. Absence renders\n * as nothing, because a locked field nobody has answered has nothing to show.\n *\n * @param value - The answer the form holds for a field, or absence\n * @returns The text to render for it\n */\nexport function valueToText(value: FieldValue | undefined): string {\n\tif (value === undefined) return ''\n\tif (typeof value === 'string') return value\n\tif (typeof value === 'number') return String(value)\n\tif (typeof value === 'boolean') return value ? 'yes' : 'no'\n\treturn value.join(', ')\n}\n\n/**\n * The choices a `select` or `checkbox` field actually OFFERS — the form refuses a disabled choice's\n * value at every door, including a fill, so the walk never puts one in front of the cursor. Pair\n * with {@link disabledChoices} to tell the reader what was withheld.\n *\n * @param choices - The field's declared choices\n * @returns The choices the walk offers, in declared order\n */\nexport function enabledChoices(choices: readonly FieldChoice[]): readonly FieldChoice[] {\n\treturn choices.filter((choice) => choice.disabled !== true)\n}\n\n/**\n * The choices a `select` or `checkbox` field SHOWS but refuses — the complement of\n * {@link enabledChoices}, rendered by {@link unavailableLine} above the list so a reader sees why a\n * declared choice is missing from it.\n *\n * @param choices - The field's declared choices\n * @returns The refused choices, in declared order\n */\nexport function disabledChoices(choices: readonly FieldChoice[]): readonly FieldChoice[] {\n\treturn choices.filter((choice) => choice.disabled === true)\n}\n\n/** The section header the walk writes when it enters a new field group, painted by the `message` role. */\nexport function groupHeader(styler: StylerInterface, theme: PromptTheme, label: string): string {\n\treturn styler.render(theme.roles.message, label)\n}\n\n/**\n * The read-only line a LOCKED field renders — its label, the {@link LOCKED_MARK}, and the answer the\n * form already holds. The walk writes this instead of a prompt, because the field is still\n * validated and still submitted but must not be edited here.\n *\n * @param styler - The console styler that renders each role\n * @param theme - The resolved prompt theme\n * @param label - The field's label\n * @param value - The held answer, from {@link valueToText}\n * @returns The rendered line, with no trailing space when there is nothing to show\n */\nexport function lockedLine(\n\tstyler: StylerInterface,\n\ttheme: PromptTheme,\n\tlabel: string,\n\tvalue: string,\n): string {\n\tconst head = `${styler.render(theme.roles.muted, theme.icons.dot)} ${styler.render(theme.roles.message, label)} ${styler.render(theme.roles.hint, LOCKED_MARK)}`\n\treturn value.length === 0 ? head : `${head} ${styler.render(theme.roles.content, value)}`\n}\n\n/** The line listing an OPEN select's offered values above its text prompt — a suggestion list, because an open select admits an answer the list does not offer. */\nexport function suggestionLine(\n\tstyler: StylerInterface,\n\ttheme: PromptTheme,\n\tchoices: readonly FieldChoice[],\n): string {\n\tconst values = choices.map((choice) => choice.value).join(', ')\n\treturn styler.render(theme.roles.hint, `${SUGGESTION_LEAD}: ${values}`)\n}\n\n/** The line naming the choices a field shows but refuses, written above the list the walk drives. */\nexport function unavailableLine(\n\tstyler: StylerInterface,\n\ttheme: PromptTheme,\n\tchoices: readonly FieldChoice[],\n): string {\n\tconst labels = choices.map((choice) => choice.label).join(', ')\n\treturn styler.render(theme.roles.muted, `${UNAVAILABLE_LEAD}: ${labels}`)\n}\n\n/**\n * The numbered choice list the non-TTY fallback prints — a piped stream cannot navigate with arrow\n * keys, so each offered choice is printed with the number the reader types back. One line per\n * choice, with no trailing newline.\n *\n * @param styler - The console styler that renders each role\n * @param theme - The resolved prompt theme\n * @param choices - The choices the walk offers, from {@link enabledChoices}\n * @returns The rendered list\n */\nexport function numberedList(\n\tstyler: StylerInterface,\n\ttheme: PromptTheme,\n\tchoices: readonly FieldChoice[],\n): string {\n\treturn choices\n\t\t.map(\n\t\t\t(choice, index) =>\n\t\t\t\t` ${styler.render(theme.roles.muted, `${String(index + 1)})`)} ${styler.render(theme.roles.content, choice.label)}`,\n\t\t)\n\t\t.join('\\n')\n}\n","import type {\n\tFieldChoice,\n\tFieldError,\n\tFieldValue,\n\tFormField,\n\tFormInterface,\n\tFormValues,\n} from '@orkestrel/form'\nimport type {\n\tCheckboxField,\n\tConfirmField,\n\tEditorField,\n\tFileField,\n\tPasswordField,\n\tSelectField,\n} from '@orkestrel/form'\nimport type { KeyEvent, PromptStep, PromptTheme, TerminalInterface } from '@src/core'\nimport type { StylerInterface } from '@orkestrel/console'\nimport type { Interface } from 'node:readline'\nimport type { InputStreamInterface, OutputStreamInterface, TerminalOptions } from './types.js'\nimport {\n\tcheckboxReduce,\n\tconfirmReduce,\n\tcreateCheckboxState,\n\tcreateConfirmState,\n\tcreateEditorState,\n\tcreateInputState,\n\tcreatePasswordState,\n\tcreatePromptTheme,\n\tcreateSelectState,\n\teditorReduce,\n\terrorLine,\n\thintedHeader,\n\tinputReduce,\n\tparseKey,\n\tpasswordReduce,\n\tpromptHeader,\n\tsanitizeDisplayText,\n\tselectReduce,\n\tTerminalError,\n} from '@src/core'\nimport { matchesAnswer, parseValue } from '@orkestrel/form'\nimport { createStyler } from '@orkestrel/console'\nimport { createInterface } from 'node:readline'\nimport { stdin, stdout } from 'node:process'\nimport {\n\tCURSOR_HIDE,\n\tCURSOR_SHOW,\n\tFALLBACK_CHECKBOX_HINT,\n\tFALLBACK_CONFIRM_HINT,\n\tFALLBACK_EDITOR_HINT,\n\tFALLBACK_SELECT_HINT,\n\tFILE_HINT,\n\tLINE_FEED,\n\tREFUSAL_MESSAGE,\n} from './constants.js'\nimport {\n\tdisabledChoices,\n\tenabledChoices,\n\tfieldToText,\n\tgroupHeader,\n\tisInputStream,\n\tisOutputStream,\n\tisReadable,\n\tlineCount,\n\tlockedLine,\n\tnumberedList,\n\trawCapable,\n\tredrawPrefix,\n\tsuggestionLine,\n\tunavailableLine,\n\tvalueToText,\n} from './helpers.js'\n\n/**\n * The interactive terminal form DRIVER — the {@link TerminalInterface} implementation for a human at\n * this machine's keyboard, and the only impure part of the terminal stack. {@link ask} walks one\n * form's fields in schema order, feeds raw-mode stdin bytes through `parseKey` into the matching\n * pure reducer, renders each returned view in place, and binds every answer through the form's own\n * `fill`. It owns no form logic: the schema, the rules, the values, and the settlement all belong to\n * the form it is given, and this class owns only raw mode, the cursor, and the re-render.\n *\n * @remarks\n * See {@link TerminalInterface} for the driving contract. The walk itself:\n *\n * - **Twelve controls, seven reducers.** `text`, `number`, `date`, `time`, `datetime`, `color`, and\n * each `file` entry are read as one line of text through {@link fieldToText}, which appends that\n * control's format cue to the label. `password`, `confirm`, `editor`, `select`, and `checkbox`\n * each drive their own reducer. An open `select` is a suggestion list plus a typed line, because\n * `open` means the answer need not come from the list.\n * - **The binding projects through `matchesAnswer`.** Every answer is filled as\n * `fill(name, matchesAnswer(value) ? value : undefined)` after `parseValue` has coerced it to the\n * control's own shape, so a bare return on a field with no default binds as ABSENCE and the\n * form's `required` rule refuses it. A typed answer the control cannot hold binds as absence and\n * invalidates the field, so the walk asks again with the reason on screen.\n * - **Visibility is honored.** A `hidden` field and a field currently in `form.disabled` are\n * skipped; a `locked` field renders read-only; entering a new group writes its label as a section\n * header.\n * - **Refusal re-asks.** After the walk the form is submitted. A refusal re-walks only the erroring\n * fields the walk can edit and submits again. When every erroring field is one the walk cannot\n * edit — hidden, locked, or disabled — the form is abandoned instead, because asking again could\n * not change the answer.\n * - **Raw-mode leak-free.** Raw mode is entered once per field and always cleaned up: on submit, on\n * cancel, on a throw, and when the form is abandoned under an active read.\n * - **Non-TTY fallback.** When `input` is not a TTY, the same walk runs over `node:readline` line\n * input: `select` and `checkbox` print a numbered list, and `editor` reads to end of input.\n */\nexport class Terminal implements TerminalInterface {\n\treadonly #input: InputStreamInterface\n\treadonly #output: OutputStreamInterface\n\treadonly #styler: StylerInterface\n\treadonly #theme: PromptTheme\n\treadonly #handlers = new Map<object, (chunk: string | Uint8Array) => void>()\n\treadonly #queue: string[] = []\n\t#interface: Interface | undefined\n\t#taker: ((line: string | undefined) => void) | undefined\n\t#ended = false\n\n\tconstructor(options?: TerminalOptions) {\n\t\t// Resolve each stream through its guard: a present, well-shaped injected stream is used as is;\n\t\t// otherwise the real process stream — no assertion, and an absent option falls through.\n\t\tthis.#input = isInputStream(options?.input) ? options.input : stdin\n\t\tthis.#output = isOutputStream(options?.output) ? options.output : stdout\n\t\tthis.#styler = createStyler()\n\t\tthis.#theme = createPromptTheme(options?.theme)\n\t}\n\n\t// === The contract\n\n\tasync ask(form: FormInterface): Promise<FormValues> {\n\t\ttry {\n\t\t\tthis.#report(form, form.errors)\n\t\t\tawait this.#walk(form, form.schema.fields)\n\t\t\tfor (;;) {\n\t\t\t\tif (form.status !== 'editing') return await form.answer\n\t\t\t\tconst result = form.submit()\n\t\t\t\tif (result.success) return await form.answer\n\t\t\t\tthis.#report(form, result.error)\n\t\t\t\tconst again = this.#editable(form, result.error)\n\t\t\t\t// Nothing the walk can edit, or an input stream that has already ended: asking again would\n\t\t\t\t// render the same fields and read the same answers forever, so abandon the form instead.\n\t\t\t\t// The failures are on screen either way, so the reader sees what could not be answered.\n\t\t\t\tif (again.length === 0 || this.#ended) {\n\t\t\t\t\tform.destroy()\n\t\t\t\t\treturn await form.answer\n\t\t\t\t}\n\t\t\t\tawait this.#walk(form, again)\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.#close()\n\t\t}\n\t}\n\n\t// === The walk\n\n\t/**\n\t * Ask `fields` in the order given, skipping what the walk must not touch and rendering what it\n\t * must not edit. Returns early the moment the form stops being editable, so an abandoned form\n\t * ends the walk between fields as well as under an active read.\n\t */\n\tasync #walk(form: FormInterface, fields: readonly FormField[]): Promise<void> {\n\t\tlet group: string | undefined\n\t\tfor (const field of fields) {\n\t\t\tif (form.status !== 'editing') return\n\t\t\tif (field.hidden === true) continue\n\t\t\tif (form.disabled.has(field.name)) continue\n\t\t\tif (field.group !== group) {\n\t\t\t\tgroup = field.group\n\t\t\t\tif (group !== undefined) this.#group(form, group)\n\t\t\t}\n\t\t\tif (field.locked === true) {\n\t\t\t\tthis.#locked(form, field)\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tconst raw = await this.#read(form, field)\n\t\t\tif (form.status !== 'editing') return\n\t\t\tthis.#bind(form, field, raw)\n\t\t}\n\t}\n\n\t/** Write a group's label as a section header, resolving the schema's declared label and falling back to the group's own name. */\n\t#group(form: FormInterface, name: string): void {\n\t\tconst label = form.schema.groups?.find((group) => group.name === name)?.label ?? name\n\t\tthis.#output.write(\n\t\t\t`${LINE_FEED}${groupHeader(this.#styler, this.#theme, sanitizeDisplayText(label))}${LINE_FEED}`,\n\t\t)\n\t}\n\n\t/** Render a locked field read-only — its label, its mark, and the answer the form already holds. */\n\t#locked(form: FormInterface, field: FormField): void {\n\t\tconst line = lockedLine(\n\t\t\tthis.#styler,\n\t\t\tthis.#theme,\n\t\t\tsanitizeDisplayText(field.label ?? field.name),\n\t\t\tsanitizeDisplayText(valueToText(form.values[field.name])),\n\t\t)\n\t\tthis.#output.write(`${line}${LINE_FEED}`)\n\t}\n\n\t/** Read one field through the reducer its control names, resolving the raw answer the binding projects. */\n\t#read(form: FormInterface, field: FormField): Promise<FieldValue | undefined> {\n\t\tif (field.control === 'password') return this.#password(form, field)\n\t\tif (field.control === 'confirm') return this.#confirm(form, field)\n\t\tif (field.control === 'editor') return this.#editor(form, field)\n\t\tif (field.control === 'select') return this.#select(form, field)\n\t\tif (field.control === 'checkbox') return this.#checkbox(form, field)\n\t\tif (field.control === 'file') return this.#file(form, field)\n\t\treturn this.#text(form, field)\n\t}\n\n\t/**\n\t * Bind one raw answer to the form — the single binding, and the only place this driver writes a\n\t * value. `parseValue` coerces the raw answer to the control's own shape and `matchesAnswer`\n\t * projects a blank one to absence, which is what keeps `required` refusing a bare return. A raw\n\t * answer the control cannot hold binds as absence and invalidates the field, so the field comes\n\t * back on the next pass carrying the reason rather than vanishing silently.\n\t */\n\t#bind(form: FormInterface, field: FormField, raw: FieldValue | undefined): void {\n\t\tform.touch(field.name)\n\t\tconst value = raw === undefined ? undefined : parseValue(field, raw)\n\t\tform.fill(field.name, matchesAnswer(value) ? value : undefined)\n\t\tif (value === undefined && matchesAnswer(raw)) form.invalidate(field.name, REFUSAL_MESSAGE)\n\t}\n\n\t/** The erroring fields the walk can ask again — every field the walk skips or renders read-only is excluded, because a second pass could not change its answer. */\n\t#editable(form: FormInterface, errors: readonly FieldError[]): readonly FormField[] {\n\t\tconst fields: FormField[] = []\n\t\tfor (const error of errors) {\n\t\t\tconst field = form.field(error.field)\n\t\t\tif (field === undefined) continue\n\t\t\tif (field.hidden === true || field.locked === true) continue\n\t\t\tif (form.disabled.has(field.name)) continue\n\t\t\tif (fields.some((held) => held.name === field.name)) continue\n\t\t\tfields.push(field)\n\t\t}\n\t\treturn fields\n\t}\n\n\t/** Write every supplied failure against its field's label. */\n\t#report(form: FormInterface, errors: readonly FieldError[]): void {\n\t\tfor (const error of errors) {\n\t\t\tconst label = sanitizeDisplayText(form.field(error.field)?.label ?? error.field)\n\t\t\tconst message = sanitizeDisplayText(error.message)\n\t\t\tconst line = errorLine(this.#styler, this.#theme, `${label}: ${message}`)\n\t\t\tthis.#output.write(`${line}${LINE_FEED}`)\n\t\t}\n\t}\n\n\t// === The controls\n\n\t/** Read a field as one line of text — `text` itself and the six controls a terminal has no widget for. */\n\t#text(form: FormInterface, field: FormField): Promise<string> {\n\t\tconst state = createInputState(fieldToText(field), this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, inputReduce)\n\t\treturn this.#line(form, state.message, state.default)\n\t}\n\n\t/** Read a secret — masked live in raw mode, and read without echo through readline on a stream that cannot enter it. */\n\t#password(form: FormInterface, field: PasswordField): Promise<string> {\n\t\tconst state = createPasswordState(field, this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, passwordReduce)\n\t\treturn this.#prompt(form, promptHeader(this.#styler, this.#theme, state.message))\n\t}\n\n\t/**\n\t * Read a yes or no. The fallback accepts `y` / `yes` / `n` / `no` in any case and takes the\n\t * field's default for a bare line; anything else is returned as typed, so the binding refuses it\n\t * and the walk asks again rather than silently reading it as no.\n\t */\n\tasync #confirm(form: FormInterface, field: ConfirmField): Promise<FieldValue> {\n\t\tconst state = createConfirmState(field, this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, confirmReduce)\n\t\tconst header = hintedHeader(this.#styler, this.#theme, state.message, FALLBACK_CONFIRM_HINT)\n\t\tconst line = await this.#prompt(form, header)\n\t\tconst answer = line.trim().toLowerCase()\n\t\tif (answer.length === 0) return state.default\n\t\tif (answer === 'y' || answer === 'yes') return true\n\t\tif (answer === 'n' || answer === 'no') return false\n\t\treturn line.trim()\n\t}\n\n\t/** Read text over many lines — ctrl-d finishes in raw mode, and end of input finishes on a piped stream. */\n\t#editor(form: FormInterface, field: EditorField): Promise<string> {\n\t\tconst state = createEditorState(field, this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, editorReduce)\n\t\treturn this.#block(form, state.message, state.default)\n\t}\n\n\t/**\n\t * Read one choice. A disabled choice is named above the list and never offered, because the form\n\t * refuses its value at every door. An open select is a suggestion list plus a typed line, since\n\t * `open` admits an answer the list does not offer; a closed select with nothing left to offer\n\t * resolves absence and lets the form's own rules report it.\n\t */\n\tasync #select(form: FormInterface, field: SelectField): Promise<FieldValue | undefined> {\n\t\tconst choices = enabledChoices(field.choices)\n\t\tthis.#unavailable(field.choices)\n\t\tif (field.open === true) {\n\t\t\tif (choices.length > 0) {\n\t\t\t\tconst display = choices.map((choice) => ({\n\t\t\t\t\t...choice,\n\t\t\t\t\tvalue: sanitizeDisplayText(choice.value),\n\t\t\t\t}))\n\t\t\t\tthis.#output.write(`${suggestionLine(this.#styler, this.#theme, display)}${LINE_FEED}`)\n\t\t\t}\n\t\t\treturn this.#text(form, field)\n\t\t}\n\t\tif (choices.length === 0) return undefined\n\t\tconst state = createSelectState({ ...field, choices }, this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, selectReduce)\n\t\tthis.#list(state.message, choices)\n\t\tconst line = await this.#prompt(form, this.#hint(`${FALLBACK_SELECT_HINT}:`))\n\t\treturn choices[Number.parseInt(line.trim(), 10) - 1]?.value\n\t}\n\n\t/**\n\t * Read any number of choices. Disabled choices are named above the list and never offered, so a\n\t * box the form would refuse can never be ticked. An empty answer is an answered \"none of them\",\n\t * which is what `matchesAnswer` says an empty list means.\n\t */\n\tasync #checkbox(form: FormInterface, field: CheckboxField): Promise<FieldValue> {\n\t\tconst choices = enabledChoices(field.choices)\n\t\tthis.#unavailable(field.choices)\n\t\tconst state = createCheckboxState({ ...field, choices }, this.#styler, this.#theme)\n\t\tif (rawCapable(this.#input)) return this.#drive(form, state, checkboxReduce)\n\t\tthis.#list(state.message, choices)\n\t\tconst line = await this.#prompt(form, this.#hint(`${FALLBACK_CHECKBOX_HINT}:`))\n\t\treturn line\n\t\t\t.split(',')\n\t\t\t.map((part) => choices[Number.parseInt(part.trim(), 10) - 1]?.value)\n\t\t\t.filter((value): value is string => value !== undefined)\n\t}\n\n\t/**\n\t * Read file paths — names only, because bytes never enter a form. A `multiple` field collects one\n\t * path per line until a blank one, and a single field takes one. No path at all is absence rather\n\t * than an empty list, because the reader answered a blank line.\n\t */\n\tasync #file(form: FormInterface, field: FileField): Promise<FieldValue | undefined> {\n\t\tif (field.multiple === true) this.#output.write(`${this.#hint(FILE_HINT)}${LINE_FEED}`)\n\t\tconst paths: string[] = []\n\t\tfor (;;) {\n\t\t\tconst entry = await this.#text(form, field)\n\t\t\tif (entry.length === 0) break\n\t\t\tpaths.push(entry)\n\t\t\tif (field.multiple !== true || this.#ended) break\n\t\t}\n\t\treturn paths.length > 0 ? paths : undefined\n\t}\n\n\t/** Name the choices a field shows but refuses, above the list the walk drives. */\n\t#unavailable(choices: readonly FieldChoice[]): void {\n\t\tconst refused = disabledChoices(choices)\n\t\tif (refused.length === 0) return\n\t\tthis.#output.write(`${unavailableLine(this.#styler, this.#theme, refused)}${LINE_FEED}`)\n\t}\n\n\t/** Write a field's header above its numbered choice list — the non-TTY presentation of a choice field. */\n\t#list(message: string, choices: readonly FieldChoice[]): void {\n\t\tconst header = promptHeader(this.#styler, this.#theme, message)\n\t\tconst list = numberedList(this.#styler, this.#theme, choices)\n\t\tthis.#output.write(`${header}${LINE_FEED}${list}${LINE_FEED}`)\n\t}\n\n\t/** Paint one line of supplementary instruction through the `hint` role. */\n\t#hint(text: string): string {\n\t\treturn this.#styler.render(this.#theme.roles.hint, text)\n\t}\n\n\t// === The raw-mode kernel\n\n\t/**\n\t * The irreducible Node raw-mode primitive — the ONLY place raw mode is touched. Switches the input\n\t * into raw mode (each keypress delivered immediately, no echo), resumes its flow, and subscribes\n\t * `handler` to `'data'`. The paired {@link #leaveRaw} operation unsubscribes the exact handler,\n\t * leaves raw mode, and pauses the stream on submit, cancel, abandon, or throw.\n\t */\n\t#enterRaw(token: object, handler: (chunk: string | Uint8Array) => void): void {\n\t\tthis.#handlers.set(token, handler)\n\t\tthis.#input.setRawMode?.(true)\n\t\tthis.#input.resume?.()\n\t\tthis.#input.on('data', handler)\n\t}\n\n\t#leaveRaw(token: object): void {\n\t\tconst handler = this.#handlers.get(token)\n\t\tif (handler === undefined) return\n\t\tthis.#handlers.delete(token)\n\t\tthis.#input.off('data', handler)\n\t\tthis.#input.setRawMode?.(false)\n\t\tthis.#input.pause?.()\n\t}\n\n\t/**\n\t * Drive ONE field over raw-mode stdin — the generic engine every interactive control shares.\n\t * Renders the reducer's initial view, enters raw mode once, and on each keypress runs `parseKey` →\n\t * `reduce` → an in-place re-render; on `submit` it cleans up and resolves the reducer's value, on\n\t * `cancel` (ctrl-c) it cleans up and rejects a {@link TerminalError} coded `CANCEL`. Abandoning\n\t * the form ends the read too, through the rejection of its own `answer`. Raw mode is entered\n\t * exactly once and cleaned up on every exit path, so no raw mode and no `'data'` listener ever\n\t * leaks. The cursor is hidden for the duration and restored on exit.\n\t */\n\t#drive<T, S>(\n\t\tform: FormInterface,\n\t\tinitial: S,\n\t\treduce: (state: S, key: KeyEvent) => PromptStep<T, S>,\n\t): Promise<T> {\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\t// Render the first view, tracking how many lines it spans so the next redraw climbs over them.\n\t\t\tthis.#output.write(CURSOR_HIDE)\n\t\t\tlet firstView: string\n\t\t\ttry {\n\t\t\t\tfirstView = reduce(initial, parseKey('')).view\n\t\t\t\tthis.#output.write(firstView)\n\t\t\t} catch (error) {\n\t\t\t\t// Raw mode was never entered yet, but the cursor was hidden — restore it before rejecting.\n\t\t\t\tthis.#output.write(`${CURSOR_SHOW}${LINE_FEED}`)\n\t\t\t\treject(error)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tconst token = {}\n\t\t\tconst handler = this.#createHandler(\n\t\t\t\ttoken,\n\t\t\t\tinitial,\n\t\t\t\tlineCount(firstView),\n\t\t\t\treduce,\n\t\t\t\tresolve,\n\t\t\t\treject,\n\t\t\t)\n\t\t\tthis.#enterRaw(token, handler)\n\t\t\t// An abandoned form ends the read: its own `answer` rejects, so release the terminal and fail\n\t\t\t// this field with the form's error. A read that already finished holds no token and is a no-op.\n\t\t\tvoid form.answer.catch((error: unknown) => this.#interrupt(token, reject, error))\n\t\t})\n\t}\n\n\t#createHandler<T, S>(\n\t\ttoken: object,\n\t\tinitial: S,\n\t\tinitialLines: number,\n\t\treduce: (state: S, key: KeyEvent) => PromptStep<T, S>,\n\t\tresolve: (value: T | PromiseLike<T>) => void,\n\t\treject: (reason?: unknown) => void,\n\t): (chunk: string | Uint8Array) => void {\n\t\tlet state = initial\n\t\tlet lines = initialLines\n\t\treturn (chunk) => {\n\t\t\ttry {\n\t\t\t\tconst step = reduce(state, parseKey(chunk))\n\t\t\t\tstate = step.state\n\t\t\t\tif (step.status === 'active') {\n\t\t\t\t\tthis.#render(step.view, lines)\n\t\t\t\t\tlines = lineCount(step.view)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t\t// Terminal step (submit / cancel): paint the final committed view, then tear down.\n\t\t\t\tthis.#render(step.view, lines)\n\t\t\t\tthis.#leaveRaw(token)\n\t\t\t\tthis.#output.write(`${CURSOR_SHOW}${LINE_FEED}`)\n\t\t\t\tif (step.status === 'cancel') reject(new TerminalError('CANCEL', 'Prompt cancelled'))\n\t\t\t\telse if (step.status === 'submit' && step.value !== undefined) resolve(step.value)\n\t\t\t\telse reject(new TerminalError('DRIVER', 'submit produced no value'))\n\t\t\t} catch (error) {\n\t\t\t\t// A throw inside the reducer/styler: tear down raw mode + the listener, restore the cursor\n\t\t\t\t// exactly as the normal exit path does, then reject.\n\t\t\t\tthis.#leaveRaw(token)\n\t\t\t\tthis.#output.write(`${CURSOR_SHOW}${LINE_FEED}`)\n\t\t\t\treject(error)\n\t\t\t}\n\t\t}\n\t}\n\n\t/** End an active read that the form outlived — release raw mode exactly as a submit does, then fail the read with the form's own error. */\n\t#interrupt(token: object, reject: (reason?: unknown) => void, error: unknown): void {\n\t\tif (!this.#handlers.has(token)) return\n\t\tthis.#leaveRaw(token)\n\t\tthis.#output.write(`${CURSOR_SHOW}${LINE_FEED}`)\n\t\treject(error)\n\t}\n\n\t/** Redraw a field view in place — climb over the previous view's `previousLines`, clear, and write the new view (the pure cursor-math is {@link redrawPrefix}). */\n\t#render(view: string, previousLines: number): void {\n\t\tthis.#output.write(`${redrawPrefix(previousLines)}${view}`)\n\t}\n\n\t// === Non-TTY fallbacks (node:readline line input)\n\n\t/** Read one line for a text-shaped field, taking the field's default when the line is bare. */\n\tasync #line(form: FormInterface, message: string, seed: string): Promise<string> {\n\t\tconst answer = await this.#prompt(form, promptHeader(this.#styler, this.#theme, message))\n\t\treturn answer.length > 0 ? answer : seed\n\t}\n\n\t/**\n\t * Read a whole block for an `editor` field — a piped stream has no ctrl-d keypress, so end of\n\t * input is the terminator. It drains every remaining line, which is why nothing after an `editor`\n\t * field can be asked on the same stream.\n\t */\n\tasync #block(form: FormInterface, message: string, seed: string): Promise<string> {\n\t\tconst header = hintedHeader(this.#styler, this.#theme, message, FALLBACK_EDITOR_HINT)\n\t\tthis.#output.write(`${header}${LINE_FEED}`)\n\t\tconst collected: string[] = []\n\t\tfor (;;) {\n\t\t\tconst line = await this.#next(form)\n\t\t\tif (line === undefined) break\n\t\t\tcollected.push(line)\n\t\t}\n\t\tconst text = collected.join('\\n')\n\t\treturn text.length > 0 ? text : seed\n\t}\n\n\t/** Write one field's header and read back the line the reader answers it with, or `''` once the stream has ended. */\n\tasync #prompt(form: FormInterface, header: string): Promise<string> {\n\t\tthis.#output.write(`${header} `)\n\t\tconst line = await this.#next(form)\n\t\treturn line ?? ''\n\t}\n\n\t/**\n\t * Take the next line the input carries — from the buffer when the reader has already read ahead,\n\t * and otherwise by waiting for one. It resolves ABSENCE once the stream has ended, so a walk over\n\t * an exhausted stream settles instead of waiting forever, and it rejects when the form is\n\t * abandoned, so an unanswerable read ends with the form rather than outliving it.\n\t */\n\t#next(form: FormInterface): Promise<string | undefined> {\n\t\tconst buffered = this.#queue.shift()\n\t\tif (buffered !== undefined) return Promise.resolve(buffered)\n\t\tif (this.#ended) return Promise.resolve(undefined)\n\t\tthis.#reader()\n\t\treturn new Promise<string | undefined>((resolve, reject) => {\n\t\t\tthis.#taker = resolve\n\t\t\tvoid form.answer.catch((error: unknown) => {\n\t\t\t\tif (this.#taker !== resolve) return\n\t\t\t\tthis.#taker = undefined\n\t\t\t\treject(error)\n\t\t\t})\n\t\t})\n\t}\n\n\t/**\n\t * Open the walk's ONE readline interface, or keep the open one. A whole form is many questions\n\t * over one stream, and an interface reads ahead: a fresh interface per question would swallow\n\t * every line it read past the one it was asked for, so the walk holds a single reader and buffers\n\t * what arrives early. It is closed when the walk ends, so the process is free to exit.\n\t */\n\t#reader(): void {\n\t\tif (this.#interface !== undefined) return\n\t\tconst rl = createInterface(this.#readline())\n\t\trl.on('line', (line) => this.#accept(line))\n\t\trl.on('close', () => this.#finish())\n\t\tthis.#interface = rl\n\t}\n\n\t/** Hand a line to whoever is waiting for it, or buffer it for the next question. */\n\t#accept(line: string): void {\n\t\tconst taker = this.#taker\n\t\tif (taker === undefined) {\n\t\t\tthis.#queue.push(line)\n\t\t\treturn\n\t\t}\n\t\tthis.#taker = undefined\n\t\ttaker(line)\n\t}\n\n\t/** Record that no further line can arrive and release whoever was waiting for one. */\n\t#finish(): void {\n\t\tthis.#ended = true\n\t\tconst taker = this.#taker\n\t\tif (taker === undefined) return\n\t\tthis.#taker = undefined\n\t\ttaker(undefined)\n\t}\n\n\t/** Close the walk's reader and release a waiting question — the walk is over, so the stream must stop holding the process open. */\n\t#close(): void {\n\t\tconst taker = this.#taker\n\t\tthis.#taker = undefined\n\t\tif (taker !== undefined) taker(undefined)\n\t\tconst rl = this.#interface\n\t\tif (rl === undefined) return\n\t\tthis.#interface = undefined\n\t\t// Drop the close listener first: this close is the walk ending, not the stream ending, and\n\t\t// recording it as end of input would refuse the next walk its input.\n\t\trl.removeAllListeners('close')\n\t\trl.close()\n\t}\n\n\t/**\n\t * Narrow the resolved input to the `node:readline` `createInterface` boundary, never an assertion.\n\t * The fallback only runs on a real piped `process.stdin` (or a `PassThrough` a test injects), both\n\t * genuine readables; a minimal non-readable fake reaching here means the walk was driven with a\n\t * stream it cannot use, which fails loudly rather than silently. `terminal: false` leaves readline\n\t * as a line decoder and nothing else: the walk writes every prompt itself, through the same output\n\t * every other line goes to, so nothing is written twice and a secret is never echoed.\n\t */\n\t#readline(): { input: NodeJS.ReadableStream; terminal: boolean } {\n\t\t// Bind to a local first — a guard narrows a local, not a `#private` field access.\n\t\tconst input = this.#input\n\t\tif (!isReadable(input))\n\t\t\tthrow new TerminalError('DRIVER', 'Terminal fallback requires a readable input stream')\n\t\treturn { input, terminal: false }\n\t}\n}\n","import type { TerminalInterface } from '@src/core'\nimport type { TerminalOptions } from './types.js'\nimport { Terminal } from './Terminal.js'\n\n/**\n * Create the interactive terminal form driver — the local-keyboard arm of the terminal trio, beside\n * the core headless `createPrompt` broker and the SSE `createPromptClient` bridge. Where the broker\n * PARKS a live form until somebody elsewhere answers it, a `Terminal` answers one HERE: it walks the\n * form's fields in schema order, drives each control's pure reducer over raw-mode stdin, binds every\n * answer through the form's own `fill`, and submits. It is the only impure part of the terminal\n * stack.\n *\n * @param options - See {@link TerminalOptions}\n * @returns A {@link TerminalInterface} whose `ask` drives one whole form over the resolved streams\n *\n * @remarks\n * - **The form is the unit.** `ask` takes the caller's live form and returns its settled values. The\n * returned promise is that form's own `answer`, so a caller holding the form can await either one.\n * - **Every control renders.** Seven controls are read as a line of text with their format cue,\n * `password` masks, `confirm` takes a key, `editor` takes a block, `select` and `checkbox` drive a\n * list, and an open `select` accepts a value its list does not offer.\n * - **The form decides.** A blank answer binds as absence, the form evaluates, and a refusal\n * re-walks only the fields the walk can still edit.\n * - **Injectable and guard-narrowed.** `input` and `output` default to `process.stdin` and\n * `process.stdout` but accept any stream of the declared minimal shape, resolved through their\n * guards rather than an assertion, so a test drives a whole form with a fake TTY that emits\n * scripted key chunks and records every rendered byte.\n * - **Non-TTY fallback.** A piped stream cannot enter raw mode, so the same walk runs over\n * `node:readline` line input.\n *\n * @example\n * ```ts\n * import { createForm } from '@orkestrel/form'\n * import { createTerminal } from '@orkestrel/terminal/server'\n *\n * const terminal = createTerminal()\n * const values = await terminal.ask(\n * \tcreateForm({\n * \t\tlabel: 'Sign up',\n * \t\tfields: [\n * \t\t\t{ control: 'text', name: 'email', label: 'Email', rule: { required: true, email: true } },\n * \t\t\t{ control: 'confirm', name: 'terms', label: 'I accept the terms' },\n * \t\t],\n * \t}),\n * )\n * ```\n */\nexport function createTerminal(options?: TerminalOptions): TerminalInterface {\n\treturn new Terminal(options)\n}\n"],"mappings":";;;;;;;AAUA,IAAa,SAAS,OAAO,aAAa,EAAE;;AAG5C,IAAa,MAAM;;;;;;AAOnB,IAAa,SAAS,GAAG,IAAI;;;;;AAM7B,IAAa,cAAc,GAAG,IAAI;;AAGlC,IAAa,cAAc,GAAG,IAAI;;;;;;AAOlC,IAAa,aAAa,GAAG,IAAI;;AAGjC,IAAa,kBAAkB,OAAO,aAAa,EAAE;;AAGrD,IAAa,YAAY,OAAO,aAAa,EAAE;;;;;;AAO/C,IAAa,uBAAuB;;AAGpC,IAAa,yBAAyB;;AAGtC,IAAa,uBAAuB;;AAGpC,IAAa,wBAAwB;;;;;;;;AASrC,IAAa,gBAAiE,OAAO,OAAO;CAC3F,QAAQ;CACR,MAAM;CACN,MAAM;CACN,UAAU;CACV,OAAO;CACP,MAAM;AACP,CAAC;;AAGD,IAAa,YAAY;;AAGzB,IAAa,kBAAkB;;AAG/B,IAAa,mBAAmB;;AAGhC,IAAa,cAAc;;;;;;;AAQ3B,IAAa,kBAAkB;;;;;;;;;;;;;;;;;;ACxD/B,SAAgB,cAAc,OAA+C;CAC5E,OACC,OAAO,UAAU,YACjB,UAAU,QACV,QAAQ,SACR,OAAO,MAAM,OAAO,cACpB,SAAS,SACT,OAAO,MAAM,QAAQ;AAEvB;;;;;;;;;;AAWA,SAAgB,eAAe,OAAgD;CAC9E,OACC,OAAO,UAAU,YACjB,UAAU,QACV,WAAW,SACX,OAAO,MAAM,UAAU;AAEzB;;;;;;;;;;;;AAaA,SAAgB,WAAW,OAAgD;CAC1E,OACC,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACV,OAAO,MAAM,SAAS,cACtB,UAAU,SACV,OAAO,MAAM,SAAS;AAExB;;;;;;;;;;;AAYA,SAAgB,WAAW,OAAsC;CAChE,OAAO,MAAM,UAAU,QAAQ,OAAO,MAAM,eAAe;AAC5D;;;;;;;;;;AAWA,SAAgB,UAAU,MAAsB;CAC/C,IAAI,QAAQ;CACZ,KAAK,MAAM,aAAa,MACvB,IAAI,cAAc,MAAM,SAAS;CAElC,OAAO;AACR;;;;;;;;;;AAWA,SAAgB,OAAO,OAAuB;CAC7C,IAAI,SAAS,GAAG,OAAO;CACvB,OAAO,GAAG,OAAO,QAAQ,WAAW,OAAO,KAAK,CAAC;AAClD;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,aAAa,eAA+B;CAC3D,OAAO,GAAG,OAAO,gBAAgB,CAAC,MAAsB;AACzD;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,YAAY,OAA6B;CACxD,MAAM,QAAQ,MAAM,SAAS,MAAM;CACnC,MAAM,OAAO,cAAc,MAAM;CACjC,MAAM,OAAO,aAAa,QAAQ,MAAM,UAAU,KAAA;CAClD,MAAM,OAAO,OAAO,SAAS,WAAW,OAAO,IAAI,IAAI;CACvD,OAAO;EACN,SAAS;EACT,MAAM,MAAM;EACZ,OAAO,SAAS,KAAA,IAAY,QAAQ,GAAG,MAAM,GAAG;EAChD,GAAI,OAAO,SAAS,WAAW,EAAE,SAAS,KAAK,IAAI,CAAC;CACrD;AACD;;;;;;;;;AAUA,SAAgB,YAAY,OAAuC;CAClE,IAAI,UAAU,KAAA,GAAW,OAAO;CAChC,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,KAAK;CAClD,IAAI,OAAO,UAAU,WAAW,OAAO,QAAQ,QAAQ;CACvD,OAAO,MAAM,KAAK,IAAI;AACvB;;;;;;;;;AAUA,SAAgB,eAAe,SAAyD;CACvF,OAAO,QAAQ,QAAQ,WAAW,OAAO,aAAa,IAAI;AAC3D;;;;;;;;;AAUA,SAAgB,gBAAgB,SAAyD;CACxF,OAAO,QAAQ,QAAQ,WAAW,OAAO,aAAa,IAAI;AAC3D;;AAGA,SAAgB,YAAY,QAAyB,OAAoB,OAAuB;CAC/F,OAAO,OAAO,OAAO,MAAM,MAAM,SAAS,KAAK;AAChD;;;;;;;;;;;;AAaA,SAAgB,WACf,QACA,OACA,OACA,OACS;CACT,MAAM,OAAO,GAAG,OAAO,OAAO,MAAM,MAAM,OAAO,MAAM,MAAM,GAAG,EAAE,GAAG,OAAO,OAAO,MAAM,MAAM,SAAS,KAAK,EAAE,GAAG,OAAO,OAAO,MAAM,MAAM,MAAM,WAAW;CAC7J,OAAO,MAAM,WAAW,IAAI,OAAO,GAAG,KAAK,GAAG,OAAO,OAAO,MAAM,MAAM,SAAS,KAAK;AACvF;;AAGA,SAAgB,eACf,QACA,OACA,SACS;CACT,MAAM,SAAS,QAAQ,KAAK,WAAW,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI;CAC9D,OAAO,OAAO,OAAO,MAAM,MAAM,MAAM,GAAG,gBAAgB,IAAI,QAAQ;AACvE;;AAGA,SAAgB,gBACf,QACA,OACA,SACS;CACT,MAAM,SAAS,QAAQ,KAAK,WAAW,OAAO,KAAK,CAAC,CAAC,KAAK,IAAI;CAC9D,OAAO,OAAO,OAAO,MAAM,MAAM,OAAO,GAAG,iBAAiB,IAAI,QAAQ;AACzE;;;;;;;;;;;AAYA,SAAgB,aACf,QACA,OACA,SACS;CACT,OAAO,QACL,KACC,QAAQ,UACR,KAAK,OAAO,OAAO,MAAM,MAAM,OAAO,GAAG,OAAO,QAAQ,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,OAAO,MAAM,MAAM,SAAS,OAAO,KAAK,GACnH,CAAC,CACA,KAAK,IAAI;AACZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACzLA,IAAa,WAAb,MAAmD;CAClD;CACA;CACA;CACA;CACA,4BAAqB,IAAI,IAAkD;CAC3E,SAA4B,CAAC;CAC7B;CACA;CACA,SAAS;CAET,YAAY,SAA2B;EAGtC,KAAKA,SAAS,cAAc,SAAS,KAAK,IAAI,QAAQ,QAAQ;EAC9D,KAAKC,UAAU,eAAe,SAAS,MAAM,IAAI,QAAQ,SAAS;EAClE,KAAKC,UAAU,aAAa;EAC5B,KAAKC,SAAS,kBAAkB,SAAS,KAAK;CAC/C;CAIA,MAAM,IAAI,MAA0C;EACnD,IAAI;GACH,KAAKG,QAAQ,MAAM,KAAK,MAAM;GAC9B,MAAM,KAAKC,MAAM,MAAM,KAAK,OAAO,MAAM;GACzC,SAAS;IACR,IAAI,KAAK,WAAW,WAAW,OAAO,MAAM,KAAK;IACjD,MAAM,SAAS,KAAK,OAAO;IAC3B,IAAI,OAAO,SAAS,OAAO,MAAM,KAAK;IACtC,KAAKD,QAAQ,MAAM,OAAO,KAAK;IAC/B,MAAM,QAAQ,KAAKE,UAAU,MAAM,OAAO,KAAK;IAI/C,IAAI,MAAM,WAAW,KAAK,KAAKC,QAAQ;KACtC,KAAK,QAAQ;KACb,OAAO,MAAM,KAAK;IACnB;IACA,MAAM,KAAKF,MAAM,MAAM,KAAK;GAC7B;EACD,UAAU;GACT,KAAKG,OAAO;EACb;CACD;;;;;;CASA,MAAMH,MAAM,MAAqB,QAA6C;EAC7E,IAAI;EACJ,KAAK,MAAM,SAAS,QAAQ;GAC3B,IAAI,KAAK,WAAW,WAAW;GAC/B,IAAI,MAAM,WAAW,MAAM;GAC3B,IAAI,KAAK,SAAS,IAAI,MAAM,IAAI,GAAG;GACnC,IAAI,MAAM,UAAU,OAAO;IAC1B,QAAQ,MAAM;IACd,IAAI,UAAU,KAAA,GAAW,KAAKI,OAAO,MAAM,KAAK;GACjD;GACA,IAAI,MAAM,WAAW,MAAM;IAC1B,KAAKC,QAAQ,MAAM,KAAK;IACxB;GACD;GACA,MAAM,MAAM,MAAM,KAAKC,MAAM,MAAM,KAAK;GACxC,IAAI,KAAK,WAAW,WAAW;GAC/B,KAAKC,MAAM,MAAM,OAAO,GAAG;EAC5B;CACD;;CAGA,OAAO,MAAqB,MAAoB;EAC/C,MAAM,QAAQ,KAAK,OAAO,QAAQ,MAAM,UAAU,MAAM,SAAS,IAAI,CAAC,EAAE,SAAS;EACjF,KAAKb,QAAQ,MACZ;EAAe,YAAY,KAAKC,SAAS,KAAKC,QAAQ,oBAAoB,KAAK,CAAC;CACjF;CACD;;CAGA,QAAQ,MAAqB,OAAwB;EACpD,MAAM,OAAO,WACZ,KAAKD,SACL,KAAKC,QACL,oBAAoB,MAAM,SAAS,MAAM,IAAI,GAC7C,oBAAoB,YAAY,KAAK,OAAO,MAAM,KAAK,CAAC,CACzD;EACA,KAAKF,QAAQ,MAAM,GAAG;CAAkB;CACzC;;CAGA,MAAM,MAAqB,OAAmD;EAC7E,IAAI,MAAM,YAAY,YAAY,OAAO,KAAKc,UAAU,MAAM,KAAK;EACnE,IAAI,MAAM,YAAY,WAAW,OAAO,KAAKC,SAAS,MAAM,KAAK;EACjE,IAAI,MAAM,YAAY,UAAU,OAAO,KAAKC,QAAQ,MAAM,KAAK;EAC/D,IAAI,MAAM,YAAY,UAAU,OAAO,KAAKC,QAAQ,MAAM,KAAK;EAC/D,IAAI,MAAM,YAAY,YAAY,OAAO,KAAKC,UAAU,MAAM,KAAK;EACnE,IAAI,MAAM,YAAY,QAAQ,OAAO,KAAKC,MAAM,MAAM,KAAK;EAC3D,OAAO,KAAKC,MAAM,MAAM,KAAK;CAC9B;;;;;;;;CASA,MAAM,MAAqB,OAAkB,KAAmC;EAC/E,KAAK,MAAM,MAAM,IAAI;EACrB,MAAM,QAAQ,QAAQ,KAAA,IAAY,KAAA,IAAY,WAAW,OAAO,GAAG;EACnE,KAAK,KAAK,MAAM,MAAM,cAAc,KAAK,IAAI,QAAQ,KAAA,CAAS;EAC9D,IAAI,UAAU,KAAA,KAAa,cAAc,GAAG,GAAG,KAAK,WAAW,MAAM,MAAM,eAAe;CAC3F;;CAGA,UAAU,MAAqB,QAAqD;EACnF,MAAM,SAAsB,CAAC;EAC7B,KAAK,MAAM,SAAS,QAAQ;GAC3B,MAAM,QAAQ,KAAK,MAAM,MAAM,KAAK;GACpC,IAAI,UAAU,KAAA,GAAW;GACzB,IAAI,MAAM,WAAW,QAAQ,MAAM,WAAW,MAAM;GACpD,IAAI,KAAK,SAAS,IAAI,MAAM,IAAI,GAAG;GACnC,IAAI,OAAO,MAAM,SAAS,KAAK,SAAS,MAAM,IAAI,GAAG;GACrD,OAAO,KAAK,KAAK;EAClB;EACA,OAAO;CACR;;CAGA,QAAQ,MAAqB,QAAqC;EACjE,KAAK,MAAM,SAAS,QAAQ;GAC3B,MAAM,QAAQ,oBAAoB,KAAK,MAAM,MAAM,KAAK,CAAC,EAAE,SAAS,MAAM,KAAK;GAC/E,MAAM,UAAU,oBAAoB,MAAM,OAAO;GACjD,MAAM,OAAO,UAAU,KAAKnB,SAAS,KAAKC,QAAQ,GAAG,MAAM,IAAI,SAAS;GACxE,KAAKF,QAAQ,MAAM,GAAG;CAAkB;EACzC;CACD;;CAKA,MAAM,MAAqB,OAAmC;EAC7D,MAAM,QAAQ,iBAAiB,YAAY,KAAK,GAAG,KAAKC,SAAS,KAAKC,MAAM;EAC5E,IAAI,WAAW,KAAKH,MAAM,GAAG,OAAO,KAAKsB,OAAO,MAAM,OAAO,WAAW;EACxE,OAAO,KAAKC,MAAM,MAAM,MAAM,SAAS,MAAM,OAAO;CACrD;;CAGA,UAAU,MAAqB,OAAuC;EACrE,MAAM,QAAQ,oBAAoB,OAAO,KAAKrB,SAAS,KAAKC,MAAM;EAClE,IAAI,WAAW,KAAKH,MAAM,GAAG,OAAO,KAAKsB,OAAO,MAAM,OAAO,cAAc;EAC3E,OAAO,KAAKE,QAAQ,MAAM,aAAa,KAAKtB,SAAS,KAAKC,QAAQ,MAAM,OAAO,CAAC;CACjF;;;;;;CAOA,MAAMa,SAAS,MAAqB,OAA0C;EAC7E,MAAM,QAAQ,mBAAmB,OAAO,KAAKd,SAAS,KAAKC,MAAM;EACjE,IAAI,WAAW,KAAKH,MAAM,GAAG,OAAO,KAAKsB,OAAO,MAAM,OAAO,aAAa;EAC1E,MAAM,SAAS,aAAa,KAAKpB,SAAS,KAAKC,QAAQ,MAAM,SAAS,qBAAqB;EAC3F,MAAM,OAAO,MAAM,KAAKqB,QAAQ,MAAM,MAAM;EAC5C,MAAM,SAAS,KAAK,KAAK,CAAC,CAAC,YAAY;EACvC,IAAI,OAAO,WAAW,GAAG,OAAO,MAAM;EACtC,IAAI,WAAW,OAAO,WAAW,OAAO,OAAO;EAC/C,IAAI,WAAW,OAAO,WAAW,MAAM,OAAO;EAC9C,OAAO,KAAK,KAAK;CAClB;;CAGA,QAAQ,MAAqB,OAAqC;EACjE,MAAM,QAAQ,kBAAkB,OAAO,KAAKtB,SAAS,KAAKC,MAAM;EAChE,IAAI,WAAW,KAAKH,MAAM,GAAG,OAAO,KAAKsB,OAAO,MAAM,OAAO,YAAY;EACzE,OAAO,KAAKG,OAAO,MAAM,MAAM,SAAS,MAAM,OAAO;CACtD;;;;;;;CAQA,MAAMP,QAAQ,MAAqB,OAAqD;EACvF,MAAM,UAAU,eAAe,MAAM,OAAO;EAC5C,KAAKQ,aAAa,MAAM,OAAO;EAC/B,IAAI,MAAM,SAAS,MAAM;GACxB,IAAI,QAAQ,SAAS,GAAG;IACvB,MAAM,UAAU,QAAQ,KAAK,YAAY;KACxC,GAAG;KACH,OAAO,oBAAoB,OAAO,KAAK;IACxC,EAAE;IACF,KAAKzB,QAAQ,MAAM,GAAG,eAAe,KAAKC,SAAS,KAAKC,QAAQ,OAAO;CAAe;GACvF;GACA,OAAO,KAAKkB,MAAM,MAAM,KAAK;EAC9B;EACA,IAAI,QAAQ,WAAW,GAAG,OAAO,KAAA;EACjC,MAAM,QAAQ,kBAAkB;GAAE,GAAG;GAAO;EAAQ,GAAG,KAAKnB,SAAS,KAAKC,MAAM;EAChF,IAAI,WAAW,KAAKH,MAAM,GAAG,OAAO,KAAKsB,OAAO,MAAM,OAAO,YAAY;EACzE,KAAKK,MAAM,MAAM,SAAS,OAAO;EACjC,MAAM,OAAO,MAAM,KAAKH,QAAQ,MAAM,KAAKI,MAAM,GAAG,qBAAqB,EAAE,CAAC;EAC5E,OAAO,QAAQ,OAAO,SAAS,KAAK,KAAK,GAAG,EAAE,IAAI,EAAE,EAAE;CACvD;;;;;;CAOA,MAAMT,UAAU,MAAqB,OAA2C;EAC/E,MAAM,UAAU,eAAe,MAAM,OAAO;EAC5C,KAAKO,aAAa,MAAM,OAAO;EAC/B,MAAM,QAAQ,oBAAoB;GAAE,GAAG;GAAO;EAAQ,GAAG,KAAKxB,SAAS,KAAKC,MAAM;EAClF,IAAI,WAAW,KAAKH,MAAM,GAAG,OAAO,KAAKsB,OAAO,MAAM,OAAO,cAAc;EAC3E,KAAKK,MAAM,MAAM,SAAS,OAAO;EAEjC,QAAO,MADY,KAAKH,QAAQ,MAAM,KAAKI,MAAM,GAAG,uBAAuB,EAAE,CAAC,EAAA,CAE5E,MAAM,GAAG,CAAC,CACV,KAAK,SAAS,QAAQ,OAAO,SAAS,KAAK,KAAK,GAAG,EAAE,IAAI,EAAE,EAAE,KAAK,CAAC,CACnE,QAAQ,UAA2B,UAAU,KAAA,CAAS;CACzD;;;;;;CAOA,MAAMR,MAAM,MAAqB,OAAmD;EACnF,IAAI,MAAM,aAAa,MAAM,KAAKnB,QAAQ,MAAM,GAAG,KAAK2B,MAAM,SAAS;CAAe;EACtF,MAAM,QAAkB,CAAC;EACzB,SAAS;GACR,MAAM,QAAQ,MAAM,KAAKP,MAAM,MAAM,KAAK;GAC1C,IAAI,MAAM,WAAW,GAAG;GACxB,MAAM,KAAK,KAAK;GAChB,IAAI,MAAM,aAAa,QAAQ,KAAKZ,QAAQ;EAC7C;EACA,OAAO,MAAM,SAAS,IAAI,QAAQ,KAAA;CACnC;;CAGA,aAAa,SAAuC;EACnD,MAAM,UAAU,gBAAgB,OAAO;EACvC,IAAI,QAAQ,WAAW,GAAG;EAC1B,KAAKR,QAAQ,MAAM,GAAG,gBAAgB,KAAKC,SAAS,KAAKC,QAAQ,OAAO;CAAe;CACxF;;CAGA,MAAM,SAAiB,SAAuC;EAC7D,MAAM,SAAS,aAAa,KAAKD,SAAS,KAAKC,QAAQ,OAAO;EAC9D,MAAM,OAAO,aAAa,KAAKD,SAAS,KAAKC,QAAQ,OAAO;EAC5D,KAAKF,QAAQ,MAAM,GAAG;EAAqB;CAAkB;CAC9D;;CAGA,MAAM,MAAsB;EAC3B,OAAO,KAAKC,QAAQ,OAAO,KAAKC,OAAO,MAAM,MAAM,IAAI;CACxD;;;;;;;CAUA,UAAU,OAAe,SAAqD;EAC7E,KAAKC,UAAU,IAAI,OAAO,OAAO;EACjC,KAAKJ,OAAO,aAAa,IAAI;EAC7B,KAAKA,OAAO,SAAS;EACrB,KAAKA,OAAO,GAAG,QAAQ,OAAO;CAC/B;CAEA,UAAU,OAAqB;EAC9B,MAAM,UAAU,KAAKI,UAAU,IAAI,KAAK;EACxC,IAAI,YAAY,KAAA,GAAW;EAC3B,KAAKA,UAAU,OAAO,KAAK;EAC3B,KAAKJ,OAAO,IAAI,QAAQ,OAAO;EAC/B,KAAKA,OAAO,aAAa,KAAK;EAC9B,KAAKA,OAAO,QAAQ;CACrB;;;;;;;;;;CAWA,OACC,MACA,SACA,QACa;EACb,OAAO,IAAI,SAAY,SAAS,WAAW;GAE1C,KAAKC,QAAQ,MAAM,WAAW;GAC9B,IAAI;GACJ,IAAI;IACH,YAAY,OAAO,SAAS,SAAS,EAAE,CAAC,CAAC,CAAC;IAC1C,KAAKA,QAAQ,MAAM,SAAS;GAC7B,SAAS,OAAO;IAEf,KAAKA,QAAQ,MAAM,GAAG;CAAyB;IAC/C,OAAO,KAAK;IACZ;GACD;GACA,MAAM,QAAQ,CAAC;GACf,MAAM,UAAU,KAAK4B,eACpB,OACA,SACA,UAAU,SAAS,GACnB,QACA,SACA,MACD;GACA,KAAKC,UAAU,OAAO,OAAO;GAG7B,KAAU,OAAO,OAAO,UAAmB,KAAKC,WAAW,OAAO,QAAQ,KAAK,CAAC;EACjF,CAAC;CACF;CAEA,eACC,OACA,SACA,cACA,QACA,SACA,QACuC;EACvC,IAAI,QAAQ;EACZ,IAAI,QAAQ;EACZ,QAAQ,UAAU;GACjB,IAAI;IACH,MAAM,OAAO,OAAO,OAAO,SAAS,KAAK,CAAC;IAC1C,QAAQ,KAAK;IACb,IAAI,KAAK,WAAW,UAAU;KAC7B,KAAKC,QAAQ,KAAK,MAAM,KAAK;KAC7B,QAAQ,UAAU,KAAK,IAAI;KAC3B;IACD;IAEA,KAAKA,QAAQ,KAAK,MAAM,KAAK;IAC7B,KAAKC,UAAU,KAAK;IACpB,KAAKhC,QAAQ,MAAM,GAAG;CAAyB;IAC/C,IAAI,KAAK,WAAW,UAAU,OAAO,IAAI,cAAc,UAAU,kBAAkB,CAAC;SAC/E,IAAI,KAAK,WAAW,YAAY,KAAK,UAAU,KAAA,GAAW,QAAQ,KAAK,KAAK;SAC5E,OAAO,IAAI,cAAc,UAAU,0BAA0B,CAAC;GACpE,SAAS,OAAO;IAGf,KAAKgC,UAAU,KAAK;IACpB,KAAKhC,QAAQ,MAAM,GAAG;CAAyB;IAC/C,OAAO,KAAK;GACb;EACD;CACD;;CAGA,WAAW,OAAe,QAAoC,OAAsB;EACnF,IAAI,CAAC,KAAKG,UAAU,IAAI,KAAK,GAAG;EAChC,KAAK6B,UAAU,KAAK;EACpB,KAAKhC,QAAQ,MAAM,GAAG;CAAyB;EAC/C,OAAO,KAAK;CACb;;CAGA,QAAQ,MAAc,eAA6B;EAClD,KAAKA,QAAQ,MAAM,GAAG,aAAa,aAAa,IAAI,MAAM;CAC3D;;CAKA,MAAMsB,MAAM,MAAqB,SAAiB,MAA+B;EAChF,MAAM,SAAS,MAAM,KAAKC,QAAQ,MAAM,aAAa,KAAKtB,SAAS,KAAKC,QAAQ,OAAO,CAAC;EACxF,OAAO,OAAO,SAAS,IAAI,SAAS;CACrC;;;;;;CAOA,MAAMsB,OAAO,MAAqB,SAAiB,MAA+B;EACjF,MAAM,SAAS,aAAa,KAAKvB,SAAS,KAAKC,QAAQ,SAAS,oBAAoB;EACpF,KAAKF,QAAQ,MAAM,GAAG;CAAoB;EAC1C,MAAM,YAAsB,CAAC;EAC7B,SAAS;GACR,MAAM,OAAO,MAAM,KAAKiC,MAAM,IAAI;GAClC,IAAI,SAAS,KAAA,GAAW;GACxB,UAAU,KAAK,IAAI;EACpB;EACA,MAAM,OAAO,UAAU,KAAK,IAAI;EAChC,OAAO,KAAK,SAAS,IAAI,OAAO;CACjC;;CAGA,MAAMV,QAAQ,MAAqB,QAAiC;EACnE,KAAKvB,QAAQ,MAAM,GAAG,OAAO,EAAE;EAE/B,OAAO,MADY,KAAKiC,MAAM,IAAI,KACnB;CAChB;;;;;;;CAQA,MAAM,MAAkD;EACvD,MAAM,WAAW,KAAK7B,OAAO,MAAM;EACnC,IAAI,aAAa,KAAA,GAAW,OAAO,QAAQ,QAAQ,QAAQ;EAC3D,IAAI,KAAKI,QAAQ,OAAO,QAAQ,QAAQ,KAAA,CAAS;EACjD,KAAK0B,QAAQ;EACb,OAAO,IAAI,SAA6B,SAAS,WAAW;GAC3D,KAAKC,SAAS;GACd,KAAU,OAAO,OAAO,UAAmB;IAC1C,IAAI,KAAKA,WAAW,SAAS;IAC7B,KAAKA,SAAS,KAAA;IACd,OAAO,KAAK;GACb,CAAC;EACF,CAAC;CACF;;;;;;;CAQA,UAAgB;EACf,IAAI,KAAKC,eAAe,KAAA,GAAW;EACnC,MAAM,KAAK,gBAAgB,KAAKC,UAAU,CAAC;EAC3C,GAAG,GAAG,SAAS,SAAS,KAAKC,QAAQ,IAAI,CAAC;EAC1C,GAAG,GAAG,eAAe,KAAKC,QAAQ,CAAC;EACnC,KAAKH,aAAa;CACnB;;CAGA,QAAQ,MAAoB;EAC3B,MAAM,QAAQ,KAAKD;EACnB,IAAI,UAAU,KAAA,GAAW;GACxB,KAAK/B,OAAO,KAAK,IAAI;GACrB;EACD;EACA,KAAK+B,SAAS,KAAA;EACd,MAAM,IAAI;CACX;;CAGA,UAAgB;EACf,KAAK3B,SAAS;EACd,MAAM,QAAQ,KAAK2B;EACnB,IAAI,UAAU,KAAA,GAAW;EACzB,KAAKA,SAAS,KAAA;EACd,MAAM,KAAA,CAAS;CAChB;;CAGA,SAAe;EACd,MAAM,QAAQ,KAAKA;EACnB,KAAKA,SAAS,KAAA;EACd,IAAI,UAAU,KAAA,GAAW,MAAM,KAAA,CAAS;EACxC,MAAM,KAAK,KAAKC;EAChB,IAAI,OAAO,KAAA,GAAW;EACtB,KAAKA,aAAa,KAAA;EAGlB,GAAG,mBAAmB,OAAO;EAC7B,GAAG,MAAM;CACV;;;;;;;;;CAUA,YAAiE;EAEhE,MAAM,QAAQ,KAAKrC;EACnB,IAAI,CAAC,WAAW,KAAK,GACpB,MAAM,IAAI,cAAc,UAAU,oDAAoD;EACvF,OAAO;GAAE;GAAO,UAAU;EAAM;CACjC;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3iBA,SAAgB,eAAe,SAA8C;CAC5E,OAAO,IAAI,SAAS,OAAO;AAC5B"}