@orkestrel/terminal 0.0.10 → 0.0.11

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.
@@ -232,7 +232,7 @@ var DEFAULT_RECONNECT_DELAY_MS = 2e3;
232
232
  *
233
233
  * @remarks
234
234
  * - `pending` — a serialized {@link import('./types.js').PendingForm} to dispatch and answer.
235
- * - `expire` — an `{ id }` payload: the broker expired a parked prompt (the client drops it).
235
+ * - `expire` — an `{ id }` payload: the broker expired or released a parked prompt (the client drops it).
236
236
  * - `shutdown` — the broker is going away; the client disconnects (no auto-reconnect) but stays reusable.
237
237
  */
238
238
  var SSE_EVENTS = Object.freeze({
@@ -562,13 +562,11 @@ function sanitizeSchema(schema) {
562
562
  }))
563
563
  });
564
564
  break;
565
- case "file":
566
- fields.push({
567
- ...field,
568
- ...shared,
569
- ...field.accept !== void 0 ? { accept: field.accept.map(sanitizeDisplayText) } : {}
570
- });
571
- break;
565
+ case "file": fields.push({
566
+ ...field,
567
+ ...shared,
568
+ ...field.accept !== void 0 ? { accept: field.accept.map(sanitizeDisplayText) } : {}
569
+ });
572
570
  }
573
571
  }
574
572
  return {
@@ -1129,7 +1127,7 @@ function serializePending(form) {
1129
1127
  id: form.id
1130
1128
  };
1131
1129
  }
1132
- /** Serialize a parked prompt's expiry into a {@link WireEvent} — event `'expire'`, `data` the JSON-stringified `{ id }` payload. */
1130
+ /** Serialize a parked prompt's expiry or release into a {@link WireEvent} — event `'expire'`, `data` the JSON-stringified `{ id }` payload. */
1133
1131
  function serializeExpire(id) {
1134
1132
  return {
1135
1133
  event: "expire",
@@ -1152,7 +1150,8 @@ function serializeShutdown() {
1152
1150
  * @remarks
1153
1151
  * A parked record carries one call to `serializeForm`. A failed fill or submit leaves the record
1154
1152
  * parked for another answer. A successful submit settles the form once, emits `answer`, and removes
1155
- * the record. Timeout and teardown abandon every unsettled form through its own `destroy` method.
1153
+ * the record. Timeout, `stop`, and teardown abandon unsettled forms through their own `destroy`
1154
+ * method.
1156
1155
  *
1157
1156
  * @example
1158
1157
  * ```ts
@@ -1232,6 +1231,22 @@ var Prompt = class {
1232
1231
  }
1233
1232
  };
1234
1233
  }
1234
+ stop(ids) {
1235
+ if (ids === void 0) {
1236
+ for (const id of [...this.#parked.keys()]) this.#expire(id);
1237
+ return;
1238
+ }
1239
+ if ((0, _orkestrel_contract.isArray)(ids)) {
1240
+ let stopped = true;
1241
+ for (const id of ids) {
1242
+ const parked = this.#parked.get(id);
1243
+ if (parked === void 0 || parked.pending.status !== "pending") stopped = false;
1244
+ }
1245
+ for (const id of ids) this.#expire(id);
1246
+ return stopped;
1247
+ }
1248
+ return this.#expire(ids);
1249
+ }
1235
1250
  destroy() {
1236
1251
  if (this.#destroyed) return;
1237
1252
  this.#destroyed = true;
@@ -1301,7 +1316,7 @@ var Prompt = class {
1301
1316
  }
1302
1317
  #expire(id) {
1303
1318
  const parked = this.#parked.get(id);
1304
- if (parked === void 0 || parked.pending.status !== "pending") return;
1319
+ if (parked === void 0 || parked.pending.status !== "pending") return false;
1305
1320
  parked.cancel();
1306
1321
  const expired = {
1307
1322
  ...parked,
@@ -1314,6 +1329,7 @@ var Prompt = class {
1314
1329
  parked.form.destroy();
1315
1330
  this.#emitter.emit("expire", id);
1316
1331
  this.#parked.delete(id);
1332
+ return true;
1317
1333
  }
1318
1334
  };
1319
1335
  //#endregion
@@ -1996,9 +2012,9 @@ var DatabaseTerminalStore = class {
1996
2012
  * @returns A {@link PromptInterface}
1997
2013
  *
1998
2014
  * @remarks
1999
- * The caller awaits the parked form's own `answer`. Timeout or teardown destroys the form, so that
2000
- * promise rejects with the Form package's `ABANDONED` error. Inject `options.timer` to drive
2001
- * expiry without real time.
2015
+ * The caller awaits the parked form's own `answer`. Timeout, `stop`, or teardown destroys the form,
2016
+ * so that promise rejects with the Form package's `ABANDONED` error. Inject `options.timer` to
2017
+ * drive expiry without real time.
2002
2018
  *
2003
2019
  * @example
2004
2020
  * ```ts
@@ -2091,12 +2107,13 @@ function createMemoryTerminalStore() {
2091
2107
  * ```
2092
2108
  */
2093
2109
  function createDatabaseTerminalStore(driver = (0, _orkestrel_database.createMemoryDriver)()) {
2110
+ const columns = {
2111
+ id: (0, _orkestrel_contract.stringShape)(),
2112
+ snapshot: (0, _orkestrel_contract.rawShape)({})
2113
+ };
2094
2114
  return new DatabaseTerminalStore((0, _orkestrel_database.createDatabase)({
2095
2115
  driver,
2096
- tables: { terminals: {
2097
- id: (0, _orkestrel_contract.stringShape)(),
2098
- snapshot: (0, _orkestrel_contract.rawShape)({})
2099
- } }
2116
+ tables: { terminals: columns }
2100
2117
  }).table("terminals"));
2101
2118
  }
2102
2119
  //#endregion
@@ -0,0 +1 @@
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 or released 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 or release 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, isArray } 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, `stop`, and teardown abandon unsettled forms through their own `destroy`\n * 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\tstop(ids: readonly string[]): boolean\n\tstop(id: string): boolean\n\tstop(): void\n\tstop(ids?: string | readonly string[]): boolean | void {\n\t\tif (ids === undefined) {\n\t\t\tfor (const id of [...this.#parked.keys()]) this.#expire(id)\n\t\t\treturn\n\t\t}\n\t\tif (isArray(ids)) {\n\t\t\tlet stopped = true\n\t\t\tfor (const id of ids) {\n\t\t\t\tconst parked = this.#parked.get(id)\n\t\t\t\tif (parked === undefined || parked.pending.status !== 'pending') stopped = false\n\t\t\t}\n\t\t\tfor (const id of ids) this.#expire(id)\n\t\t\treturn stopped\n\t\t}\n\t\treturn this.#expire(ids)\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): boolean {\n\t\tconst parked = this.#parked.get(id)\n\t\tif (parked === undefined || parked.pending.status !== 'pending') return false\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\treturn true\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, `stop`, or teardown destroys the form,\n * so that promise rejects with the Form package's `ABANDONED` error. Inject `options.timer` to\n * drive 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":";;;;;;;;;AAUA,IAAa,SAAS,OAAO,aAAa,EAAE;;AAE5C,IAAa,UAAU,OAAO,aAAa,EAAE;;AAE7C,IAAa,MAAM,OAAO,aAAa,CAAC;;AAExC,IAAa,SAAS,OAAO,aAAa,EAAE;;AAE5C,IAAa,YAAY,OAAO,aAAa,CAAC;;AAE9C,IAAa,SAAS,OAAO,aAAa,GAAG;;AAE7C,IAAa,QAAQ;;AAErB,IAAa,SAAS,OAAO,aAAa,CAAC;;AAE3C,IAAa,SAAS,OAAO,aAAa,CAAC;;AAE3C,IAAa,SAAS,OAAO,aAAa,EAAE;;AAE5C,IAAa,SAAS,OAAO,aAAa,CAAC;;AAE3C,IAAa,SAAS,OAAO,aAAa,CAAC;;;;;;;AAQ3C,IAAa,UAAU;;AAEvB,IAAa,UAAU;;;;;;;;;;;;;AAcvB,IAAa,iBAAmD,OAAO,OAAO;EAC5E,GAAG,QAAQ,KAAK;EAChB,GAAG,QAAQ,KAAK;EAChB,GAAG,QAAQ,KAAK;EAChB,GAAG,QAAQ,KAAK;EAChB,GAAG,QAAQ,KAAK;EAChB,GAAG,QAAQ,KAAK;EAChB,GAAG,QAAQ,KAAK;EAChB,GAAG,QAAQ,KAAK;EAChB,GAAG,QAAQ,KAAK;EAChB,GAAG,QAAQ,KAAK;EAChB,GAAG,QAAQ,MAAM;EACjB,GAAG,QAAQ,MAAM;EACjB,GAAG,QAAQ,MAAM;EACjB,GAAG,QAAQ,MAAM;EACjB,GAAG,QAAQ,MAAM;AACnB,CAAC;;;;;;;;;;;;AAaD,IAAa,gBAET,OAAO,OAAO;EACP,OAAA,OAAO,OAAO;EAAE,MAAM;EAAU,MAAM;CAAM,CAAC;EAC5C,OAAA,OAAO,OAAO;EAAE,MAAM;EAAU,MAAM;CAAM,CAAC;EACjD,MAAA,OAAO,OAAO;EAAE,MAAM;EAAO,MAAM;CAAM,CAAC;EACvC,SAAA,OAAO,OAAO;EAAE,MAAM;EAAU,MAAM;CAAM,CAAC;EAC1C,OAAA,OAAO,OAAO;EAAE,MAAM;EAAa,MAAM;CAAM,CAAC;EACnD,MAAA,OAAO,OAAO;EAAE,MAAM;EAAa,MAAM;CAAM,CAAC;EACjD,MAAA,OAAO,OAAO;EAAE,MAAM;EAAS,MAAM;CAAM,CAAC;EAC3C,MAAA,OAAO,OAAO;EAAE,MAAM;EAAK,MAAM;CAAK,CAAC;EACvC,MAAA,OAAO,OAAO;EAAE,MAAM;EAAK,MAAM;CAAK,CAAC;EACvC,MAAA,OAAO,OAAO;EAAE,MAAM;EAAK,MAAM;CAAK,CAAC;EACvC,MAAA,OAAO,OAAO;EAAE,MAAM;EAAK,MAAM;CAAK,CAAC;EACvC,MAAA,OAAO,OAAO;EAAE,MAAM;EAAK,MAAM;CAAK,CAAC;AAClD,CAAC;;AAKD,IAAa,eAAe;;;;;;;;;;;AAc5B,IAAa,eAAe,OAAO,OAAO;CACzC,UAAU;CACV,SAAS;CACT,KAAK;CACL,UAAU;CACV,SAAS;CACT,WAAW;AACZ,CAAC;;;;;;AASD,IAAa,eAAsC,OAAO,OAAO;CAChE;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACD,CAAC;;;;;;;;;;;;;;;;AAiBD,IAAa,uBAAoC,OAAO,OAAO;CAC9D,OAAO,OAAO,OAAO;EACpB,UAAU,aAAa;EACvB,SAAS,aAAa;EACtB,KAAK,aAAa;EAClB,UAAU,aAAa;EACvB,SAAS,aAAa;EACtB,WAAW,aAAa;EACxB,SAAS,mBAAA,aAAa;EACtB,OAAO,mBAAA,aAAa;CACrB,CAAC;CACD,OAAO,OAAO,OAAO;EACpB,WAAA,GAAU,mBAAA,YAAA,CAAY;GAAE,YAAY;GAAQ,YAAY,CAAC;EAAE,CAAC;EAC5D,UAAA,GAAS,mBAAA,YAAA,CAAY;GAAE,YAAY;GAAQ,YAAY,CAAC;EAAE,CAAC;EAC3D,UAAA,GAAS,mBAAA,YAAA,CAAY,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC;EAC7C,UAAA,GAAS,mBAAA,YAAA,CAAY,EAAE,YAAY,CAAC,EAAE,CAAC;EACvC,UAAA,GAAS,mBAAA,YAAA,CAAY;GAAE,YAAY;GAAS,YAAY,CAAC;EAAE,CAAC;EAC5D,QAAA,GAAO,mBAAA,YAAA,CAAY;GAAE,YAAY;GAAO,YAAY,CAAC;EAAE,CAAC;EACxD,WAAA,GAAU,mBAAA,YAAA,CAAY;GAAE,YAAY;GAAS,YAAY,CAAC;EAAE,CAAC;EAC7D,QAAA,GAAO,mBAAA,YAAA,CAAY,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC;EAC3C,OAAA,GAAM,mBAAA,YAAA,CAAY,EAAE,YAAY,CAAC,KAAK,EAAE,CAAC;EACzC,QAAA,GAAO,mBAAA,YAAA,CAAY,EAAE,YAAY,CAAC,KAAK,EAAE,CAAC;EAC1C,cAAA,GAAa,mBAAA,YAAA,CAAY,EAAE,YAAY,CAAC,KAAK,EAAE,CAAC;CACjD,CAAC;AACF,CAAC;;AAKD,IAAa,4BAA4B;;AAGzC,IAAa,6BAA6B;;;;;;;;;;AAW1C,IAAa,aAAa,OAAO,OAAO;CACvC,SAAS;CACT,QAAQ;CACR,UAAU;AACX,CAAC;;AAGD,IAAa,eAAe;;AAG5B,IAAa,sBAAsB;;;;;;;AAQnC,IAAa,mBAAmB;;;;;;;;;;;;;;AChNhC,IAAa,gBAAb,cAAmC,MAAM;;CAExC;;CAEA;CAEA,YACC,MACA,SACA,SACC;EACD,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,OAAO;EACZ,IAAI,YAAY,KAAA,GAAW,KAAK,UAAU;CAC3C;AACD;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,gBAAgB,OAAwC;CACvE,OAAO,iBAAiB;AACzB;;;;AC1CA,IAAa,uBAAA,GAAgD,oBAAA,UAAA,CAC5D,WACA,YACA,SACD;;;;;;;;;;;AAYA,SAAgB,cAAc,OAAsC;CACnE,QAAA,GAAO,oBAAA,SAAA,CACN;EACC,IAAI,oBAAA;EACJ,QAAQ,oBAAA;EACR,QAAQ;EACR,MAAM,oBAAA;EACN,MAAM,oBAAA;EACN,IAAI,oBAAA;CACL,GACA,CAAC,QAAQ,IAAI,CACd,CAAC,CAAC,KAAK;AACR;;;;;;;AAQA,IAAa,eAAA,GAAgC,oBAAA,SAAA,CAC5C;CAAE,OAAO,oBAAA;CAAU,MAAM,oBAAA;CAAU,IAAI,oBAAA;AAAS,GAChD,CAAC,IAAI,CACN;;AAGA,IAAa,sBAAA,GAA8C,oBAAA,SAAA,CAC1D;CAAE,IAAI,oBAAA;CAAkB,SAAS,oBAAA;AAAS,GAC1C,CAAC,SAAS,CACX;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACcA,SAAgB,SAAS,OAAsC;CAC9D,MAAM,YAAA,GAAW,oBAAA,SAAA,CAAS,KAAK,IAAI,QAAQ,IAAI,YAAY,CAAC,CAAC,OAAO,KAAK;CAGzE,MAAM,eAAe,eAAe;CACpC,IAAI,iBAAiB,KAAA,GACpB,OAAO;EAAE,MAAM;EAAc;EAAU,MAAM;EAAO,MAAM;EAAM,OAAO;CAAM;CAI9E,MAAM,UAAU,cAAc;CAC9B,IAAI,YAAY,KAAA,GACf,OAAO;EAAE,MAAM,QAAQ;EAAM;EAAU,MAAM,QAAQ;EAAM,MAAM;EAAO,OAAO;CAAM;CAKtF,MAAM,QAAQ,CADE,GAAG,QACL,CAAA,CAAO;CACrB,IAAI,UAAU,KAAA,KAAa,YAAY,KAAK,GAC3C,OAAO;EAAE,MAAM;EAAO;EAAU,MAAM;EAAO,MAAM;EAAO,OAAO,UAAU,MAAM,YAAY;CAAE;CAIhG,OAAO;EAAE,MAAM;EAAI;EAAU,MAAM;EAAO,MAAM;EAAO,OAAO;CAAM;AACrE;;AAGA,SAAgB,YAAY,WAA4B;CACvD,IAAI,UAAU,WAAW,GAAG,OAAO;CACnC,MAAM,OAAO,UAAU,YAAY,CAAC;CACpC,IAAI,SAAS,KAAA,GAAW,OAAO;CAE/B,OAAO,QAAQ,MAAM,SAAS;AAC/B;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,kBAAkB,SAA2C;CAC5E,MAAM,QAAoC;EAAE,GAAG,qBAAqB;EAAO,GAAG,SAAS;CAAM;CAC7F,MAAM,QAAmC,EAAE,GAAG,qBAAqB,MAAM;CACzE,KAAK,MAAM,QAAQ,cAAc;EAChC,MAAM,QAAQ,SAAS,QAAQ;EAC/B,IAAI,UAAU,KAAA,GAAW,MAAM,SAAA,GAAQ,mBAAA,YAAA,CAAY,KAAK;CACzD;CACA,OAAO,OAAO,OAAO;EAAE,OAAO,OAAO,OAAO,KAAK;EAAG,OAAO,OAAO,OAAO,KAAK;CAAE,CAAC;AAClF;;;;;;;;;;;;;AAcA,SAAgB,oBAAoB,MAAsB;CACzD,QAAA,GAAO,mBAAA,cAAA,EAAA,GAAc,mBAAA,MAAA,CAAM,IAAI,CAAC,CAAC,CAAC,WAAW,KAAM,EAAE,CAAC,CAAC,WAAW,MAAM,EAAE,CAAC,CAAC,WAAW,MAAM,EAAE;AAChG;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,eAAe,QAAgC;CAC9D,MAAM,SAAS,OAAO,QAAQ,KAAK,WAAW;EAC7C,MAAM,MAAM;EACZ,OAAO,oBAAoB,MAAM,KAAK;EACtC,GAAI,MAAM,SAAS,KAAA,IAAY,EAAE,MAAM,oBAAoB,MAAM,IAAI,EAAE,IAAI,CAAC;CAC7E,EAAE;CACF,MAAM,SAAsB,CAAC;CAC7B,KAAK,MAAM,UAAU,OAAO,QAAQ;EACnC,MAAM,EAAE,MAAM,OAAO,GAAG,UAAU;EAClC,MAAM,OACL,MAAM,SAAS,KAAA,IACZ,KAAA,IACA;GACA,GAAG,MAAM;GACT,GAAI,MAAM,KAAK,YAAY,KAAA,IACxB,EAAE,SAAS,oBAAoB,MAAM,KAAK,OAAO,EAAE,IACnD,CAAC;EACL;EACH,MAAM,SAAS;GACd,MAAM,MAAM;GACZ,GAAI,MAAM,UAAU,KAAA,IAAY,EAAE,OAAO,oBAAoB,MAAM,KAAK,EAAE,IAAI,CAAC;GAC/E,GAAI,MAAM,SAAS,KAAA,IAAY,EAAE,MAAM,oBAAoB,MAAM,IAAI,EAAE,IAAI,CAAC;GAC5E,GAAI,MAAM,UAAU,KAAA,IAAY,EAAE,OAAO,MAAM,MAAM,IAAI,CAAC;GAC1D,GAAI,SAAS,KAAA,IAAY,EAAE,KAAK,IAAI,CAAC;EACtC;EAEA,QAAQ,MAAM,SAAd;GACC,KAAK;GACL,KAAK;IACJ,OAAO,KAAK;KACX,GAAG;KACH,GAAG;KACH,GAAI,MAAM,gBAAgB,KAAA,IACvB,EAAE,aAAa,oBAAoB,MAAM,WAAW,EAAE,IACtD,CAAC;IACL,CAAC;IACD;GAED,KAAK;IACJ,OAAO,KAAK;KACX,GAAG;KACH,GAAG;KACH,GAAI,MAAM,SAAS,KAAA,IAAY,EAAE,MAAM,oBAAoB,MAAM,IAAI,EAAE,IAAI,CAAC;IAC7E,CAAC;IACD;GAED,KAAK;IACJ,OAAO,KAAK;KACX,GAAG;KACH,GAAG;KACH,GAAI,MAAM,gBAAgB,KAAA,IACvB,EAAE,aAAa,oBAAoB,MAAM,WAAW,EAAE,IACtD,CAAC;IACL,CAAC;IACD;GAED,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;IACJ,OAAO,KAAK;KACX,GAAG;KACH,GAAG;IACJ,CAAC;IACD;GAED,KAAK;IACJ,OAAO,KAAK;KAAE,GAAG;KAAO,GAAG;IAAO,CAAC;IACnC;GAED,KAAK;IACJ,OAAO,KAAK;KACX,GAAG;KACH,GAAG;KACH,SAAS,MAAM,QAAQ,KAAK,YAAY;MACvC,GAAG;MACH,OAAO,OAAO;MACd,OAAO,oBAAoB,OAAO,KAAK;MACvC,GAAI,OAAO,SAAS,KAAA,IAAY,EAAE,MAAM,oBAAoB,OAAO,IAAI,EAAE,IAAI,CAAC;KAC/E,EAAE;IACH,CAAC;IACD;GAED,KAAK;IACJ,OAAO,KAAK;KACX,GAAG;KACH,GAAG;KACH,SAAS,MAAM,QAAQ,KAAK,YAAY;MACvC,GAAG;MACH,OAAO,OAAO;MACd,OAAO,oBAAoB,OAAO,KAAK;MACvC,GAAI,OAAO,SAAS,KAAA,IAAY,EAAE,MAAM,oBAAoB,OAAO,IAAI,EAAE,IAAI,CAAC;KAC/E,EAAE;IACH,CAAC;IACD;GAED,KAAK,QACJ,OAAO,KAAK;IACX,GAAG;IACH,GAAG;IACH,GAAI,MAAM,WAAW,KAAA,IAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,mBAAmB,EAAE,IAAI,CAAC;GACvF,CAAC;EAGH;CACD;CAEA,OAAO;EACN,GAAI,OAAO,SAAS,KAAA,IAAY,EAAE,MAAM,OAAO,KAAK,IAAI,CAAC;EACzD,GAAI,OAAO,UAAU,KAAA,IAAY,EAAE,OAAO,oBAAoB,OAAO,KAAK,EAAE,IAAI,CAAC;EACjF,GAAI,OAAO,SAAS,KAAA,IAAY,EAAE,MAAM,oBAAoB,OAAO,IAAI,EAAE,IAAI,CAAC;EAC9E,GAAI,WAAW,KAAA,IAAY,EAAE,OAAO,IAAI,CAAC;EACzC;CACD;AACD;;;;;;;;;AAUA,SAAgB,mBAAmB,OAA+C;CACjF,MAAM,QAAQ,MAAM;CACpB,IAAI,UAAU,KAAA,GAAW,OAAO;CAChC,MAAM,YAAoC,CAAC;CAC3C,KAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,GAAG,UAAU,QAAQ,oBAAoB,KAAK;CAC9F,OAAO;EAAE,GAAG;EAAO,OAAO;CAAU;AACrC;;AAKA,SAAgB,aAAa,QAAyB,OAAoB,SAAyB;CAClG,OAAO,GAAG,OAAO,OAAO,MAAM,MAAM,UAAU,MAAM,MAAM,QAAQ,EAAE,GAAG,OAAO,OAAO,MAAM,MAAM,SAAS,OAAO;AAClH;;;;;;;;;;;AAYA,SAAgB,aACf,QACA,OACA,SACA,MACS;CACT,MAAM,OAAO,aAAa,QAAQ,OAAO,OAAO;CAChD,OAAO,SAAS,KAAA,IAAY,OAAO,GAAG,KAAK,GAAG,OAAO,OAAO,MAAM,MAAM,MAAM,IAAI;AACnF;;AAGA,SAAgB,aAAa,QAAyB,OAAoB,SAAyB;CAClG,OAAO,GAAG,OAAO,OAAO,MAAM,MAAM,SAAS,MAAM,MAAM,OAAO,EAAE,GAAG,OAAO,OAAO,MAAM,MAAM,SAAS,OAAO;AAChH;;AAGA,SAAgB,UAAU,QAAyB,OAAoB,SAAyB;CAC/F,OAAO,GAAG,OAAO,OAAO,MAAM,MAAM,OAAO,MAAM,MAAM,KAAK,EAAE,GAAG,OAAO,OAAO,MAAM,MAAM,OAAO,OAAO;AAC1G;;;;;;;;;AAYA,SAAgB,iBACf,OACA,UAAA,GAA0B,mBAAA,aAAA,CAAa,GACvC,OACC;CACD,OAAO;EACN,SAAS,oBAAoB,MAAM,SAAS,MAAM,IAAI;EACtD,SAAS,MAAM,WAAW;EAC1B;EACA,OAAO,kBAAkB,KAAK;EAC9B,OAAO;CACR;AACD;;AAGA,SAAgB,UAAU,OAAoD;CAC7E,MAAM,UAAU,MAAM,MAAM,SAAS,IAAI,MAAM,QAAQ,MAAM;CAC7D,MAAM,OAAO,MAAM,MAAM,SAAS,IAAI,MAAM,MAAM,MAAM,UAAU,MAAM,MAAM,MAAM;CACpF,MAAM,QAAQ,MAAM,OAAO,OAAO,MAAM,oBAAoB,OAAO,CAAC;CACpE,OAAO,GAAG,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,EAAE,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,SAAS,MAAM,MAAM,MAAM,OAAO,EAAE,GAAG;AAClJ;;;;;;AAOA,SAAgB,YACf,OACA,KAC0D;CAC1D,IAAI,IAAI,QAAQ,IAAI,SAAS,KAAK,OAAO;EAAE;EAAO,MAAM,UAAU,KAAK;EAAG,QAAQ;CAAS;CAE3F,IAAI,IAAI,SAAS,UAAU;EAC1B,MAAM,SAAS,MAAM,MAAM,SAAS,IAAI,MAAM,QAAQ,MAAM;EAE5D,OAAO;GACN,OAAO;IAFO,GAAG;IAAO,OAAO;GAExB;GACP,MAAM,GAAG,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,EAAE,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,oBAAoB,MAAM,CAAC;GAC1I,QAAQ;GACR,OAAO;EACR;CACD;CAEA,MAAM,QAAQ,SAAS,MAAM,OAAO,GAAG;CACvC,IAAI,UAAU,KAAA,GAAW,OAAO;EAAE;EAAO,MAAM,UAAU,KAAK;EAAG,QAAQ;CAAS;CAClF,MAAM,OAAO;EAAE,GAAG;EAAO;CAAM;CAC/B,OAAO;EAAE,OAAO;EAAM,MAAM,UAAU,IAAI;EAAG,QAAQ;CAAS;AAC/D;;;;;;;;;AAYA,SAAgB,oBACf,OACA,UAAA,GAA0B,mBAAA,aAAA,CAAa,GACvC,OACC;CACD,OAAO;EACN,SAAS,oBAAoB,MAAM,SAAS,MAAM,IAAI;EACtD,MAAM,oBAAoB,MAAM,QAAA,GAAoB;EACpD;EACA,OAAO,kBAAkB,KAAK;EAC9B,OAAO;CACR;AACD;;AAGA,SAAgB,aAAa,OAAuD;CACnF,MAAM,SAAS,MAAM,OAAO,OAC3B,MAAM,MAAM,MAAM,SAClB,MAAM,KAAK,OAAO,MAAM,MAAM,MAAM,CACrC;CACA,OAAO,GAAG,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,EAAE,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,SAAS,MAAM,MAAM,MAAM,OAAO,EAAE,GAAG;AAClJ;;;;;;AAOA,SAAgB,eACf,OACA,KAC6D;CAC7D,IAAI,IAAI,QAAQ,IAAI,SAAS,KAAK,OAAO;EAAE;EAAO,MAAM,aAAa,KAAK;EAAG,QAAQ;CAAS;CAE9F,IAAI,IAAI,SAAS,UAChB,OAAO;EACN;EACA,MAAM,GAAG,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,EAAE,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,MAAM,KAAK,OAAO,MAAM,MAAM,MAAM,CAAC;EACpJ,QAAQ;EACR,OAAO,MAAM;CACd;CAGD,MAAM,QAAQ,SAAS,MAAM,OAAO,GAAG;CACvC,IAAI,UAAU,KAAA,GAAW,OAAO;EAAE;EAAO,MAAM,aAAa,KAAK;EAAG,QAAQ;CAAS;CACrF,MAAM,OAAO;EAAE,GAAG;EAAO;CAAM;CAC/B,OAAO;EAAE,OAAO;EAAM,MAAM,aAAa,IAAI;EAAG,QAAQ;CAAS;AAClE;;;;;;;;;AAYA,SAAgB,mBACf,OACA,UAAA,GAA0B,mBAAA,aAAA,CAAa,GACvC,OACC;CACD,OAAO;EACN,SAAS,oBAAoB,MAAM,SAAS,MAAM,IAAI;EACtD,SAAS,MAAM,WAAW;EAC1B;EACA,OAAO,kBAAkB,KAAK;CAC/B;AACD;;;;AAKA,SAAgB,YAAY,OAAsD;CACjF,MAAM,OAAO,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO;CAClE,MAAM,SAAS,MAAM,UAClB,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,UAAU,GAAG,IAAI,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,IAAI,MAC1G,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,IAAI,IAAI,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,UAAU,GAAG;CAC7G,OAAO,GAAG,KAAK,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,GAAG,IAAI,SAAS,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,GAAG;AAC9H;;;;;;AAOA,SAAgB,cACf,OACA,KAC6D;CAC7D,IAAI,IAAI,QAAQ,IAAI,SAAS,KAAK,OAAO;EAAE;EAAO,MAAM,YAAY,KAAK;EAAG,QAAQ;CAAS;CAE7F,IAAI;CACJ,MAAM,SAAS,IAAI,KAAK,YAAY;CACpC,IAAI,IAAI,SAAS,UAAU,SAAS,MAAM;MACrC,IAAI,WAAW,KAAK,SAAS;MAC7B,IAAI,WAAW,KAAK,SAAS;CAElC,IAAI,WAAW,KAAA,GAAW,OAAO;EAAE;EAAO,MAAM,YAAY,KAAK;EAAG,QAAQ;CAAS;CACrF,OAAO;EACN;EACA,MAAM,GAAG,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,EAAE,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,SAAS,QAAQ,IAAI;EACpI,QAAQ;EACR,OAAO;CACR;AACD;;;;;;;;;AAYA,SAAgB,kBACf,OACA,UAAA,GAA0B,mBAAA,aAAA,CAAa,GACvC,OACC;CACD,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,MAAM,QAAQ,QAAQ,WAAW,WAAW,OAAO,UAAU,MAAM,OAAO;CAC1E,OAAO;EACN,SAAS,oBAAoB,MAAM,SAAS,MAAM,IAAI;EACtD;EACA;EACA,OAAO,kBAAkB,KAAK;EAC9B,SAAS,SAAS,IAAI,QAAQ;CAC/B;AACD;;AAGA,SAAgB,WAAW,OAAqD;CAC/E,MAAM,QAAQ,MAAM,QAAQ,KAAK,QAAQ,UAAU;EAClD,MAAM,SAAS,UAAU,MAAM;EAc/B,OAAO,GAbS,SACb,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,SAAS,MAAM,MAAM,MAAM,OAAO,IACxE,IAWe,GAVH,SACZ,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,UAAU,MAAM,MAAM,MAAM,QAAQ,IAC1E,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,OAAO,MAAM,MAAM,MAAM,GAAG,EAQzC,GAPd,SACX,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,OAAO,OAAO,KAAK,IACzD,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,SAAS,OAAO,KAAK,IAE7D,OAAO,SAAS,KAAA,IACb,KACA,KAAK,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,aAAa,OAAO,IAAI;CAExE,CAAC;CACD,OAAO,CAAC,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,GAAG,GAAG,KAAK,CAAC,CAAC,KAAK,IAAI;AACpF;;;;;;;AAQA,SAAgB,aACf,OACA,KAC2D;CAC3D,IAAI,IAAI,QAAQ,IAAI,SAAS,KAAK,OAAO;EAAE;EAAO,MAAM,WAAW,KAAK;EAAG,QAAQ;CAAS;CAE5F,MAAM,QAAQ,MAAM,QAAQ;CAC5B,IAAI,UAAU,GAAG,OAAO;EAAE;EAAO,MAAM,WAAW,KAAK;EAAG,QAAQ;CAAS;CAE3E,IAAI,IAAI,SAAS,QAAQ,IAAI,SAAS,KAAK;EAC1C,MAAM,OAAO;GAAE,GAAG;GAAO,UAAU,MAAM,UAAU,IAAI,SAAS;EAAM;EACtE,OAAO;GAAE,OAAO;GAAM,MAAM,WAAW,IAAI;GAAG,QAAQ;EAAS;CAChE;CACA,IAAI,IAAI,SAAS,UAAU,IAAI,SAAS,KAAK;EAC5C,MAAM,OAAO;GAAE,GAAG;GAAO,UAAU,MAAM,UAAU,KAAK;EAAM;EAC9D,OAAO;GAAE,OAAO;GAAM,MAAM,WAAW,IAAI;GAAG,QAAQ;EAAS;CAChE;CACA,IAAI,IAAI,SAAS,UAAU;EAC1B,MAAM,SAAS,MAAM,QAAQ,MAAM;EACnC,MAAM,QAAQ,QAAQ,SAAS;EAC/B,OAAO;GACN;GACA,MAAM,GAAG,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,EAAE,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,QAAQ,SAAS,EAAE;GAClI,QAAQ;GACR;EACD;CACD;CACA,OAAO;EAAE;EAAO,MAAM,WAAW,KAAK;EAAG,QAAQ;CAAS;AAC3D;;;;;;;;;AAYA,SAAgB,oBACf,OACA,UAAA,GAA0B,mBAAA,aAAA,CAAa,GACvC,OACC;CACD,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO;CACjC,MAAM,UAA6B,QAAQ,QAAkB,SAAS,QAAQ,UAAU;EACvF,IAAI,MAAM,SAAS,SAAS,OAAO,KAAK,MAAM,MAAM,QAAQ,KAAK,KAAK;EACtE,OAAO;CACR,GAAG,CAAC,CAAC;CACL,OAAO;EACN,SAAS,oBAAoB,MAAM,SAAS,MAAM,IAAI;EACtD;EACA;EACA,OAAO,kBAAkB,KAAK;EAC9B,SAAS;EACT;CACD;AACD;;AAGA,SAAgB,aAAa,OAAuD;CACnF,MAAM,QAAQ,MAAM,QAAQ,KAAK,QAAQ,UAAU;EAClD,MAAM,SAAS,UAAU,MAAM;EAC/B,MAAM,SAAS,MAAM,QAAQ,SAAS,KAAK;EAc3C,OAAO,GAbS,SACb,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,SAAS,MAAM,MAAM,MAAM,OAAO,IACxE,IAWe,GAVN,SACT,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,UAAU,MAAM,MAAM,MAAM,OAAO,IACzE,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,OAAO,MAAM,MAAM,MAAM,SAAS,EAQlD,GAPX,SACX,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,OAAO,OAAO,KAAK,IACzD,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,SAAS,OAAO,KAAK,IAE7D,OAAO,SAAS,KAAA,IACb,KACA,KAAK,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,aAAa,OAAO,IAAI;CAExE,CAAC;CACD,MAAM,UAAU,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,GAAG,MAAM,QAAQ,OAAO,UAAU;CAI9F,OAHa;EAAC,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO;EAAG,GAAG;EAAO;CAAO,CAAC,CAAC,KACxF,IAEM;AACR;;;;;;;AAQA,SAAgB,eACf,OACA,KACwE;CACxE,IAAI,IAAI,QAAQ,IAAI,SAAS,KAAK,OAAO;EAAE;EAAO,MAAM,aAAa,KAAK;EAAG,QAAQ;CAAS;CAE9F,MAAM,QAAQ,MAAM,QAAQ;CAE5B,KAAK,IAAI,SAAS,QAAQ,IAAI,SAAS,QAAQ,QAAQ,GAAG;EACzD,MAAM,OAAO;GACZ,GAAG;GACH,UAAU,MAAM,UAAU,IAAI,SAAS;EACxC;EACA,OAAO;GAAE,OAAO;GAAM,MAAM,aAAa,IAAI;GAAG,QAAQ;EAAS;CAClE;CACA,KAAK,IAAI,SAAS,UAAU,IAAI,SAAS,QAAQ,QAAQ,GAAG;EAC3D,MAAM,OAAO;GAAE,GAAG;GAAO,UAAU,MAAM,UAAU,KAAK;EAAM;EAC9D,OAAO;GAAE,OAAO;GAAM,MAAM,aAAa,IAAI;GAAG,QAAQ;EAAS;CAClE;CACA,IAAI,IAAI,SAAS,WAAW,QAAQ,GAAG;EACtC,MAAM,UAAU,YAAY,MAAM,SAAS,MAAM,OAAO;EACxD,MAAM,OAAO;GAAE,GAAG;GAAO;EAAQ;EACjC,OAAO;GAAE,OAAO;GAAM,MAAM,aAAa,IAAI;GAAG,QAAQ;EAAS;CAClE;CACA,IAAI,IAAI,SAAS,UAAU;EAC1B,MAAM,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;EACvD,MAAM,SAAS,QACb,KAAK,UAAU,MAAM,QAAQ,MAAM,EAAE,KAAK,CAAC,CAC3C,QAAQ,UAA2B,UAAU,KAAA,CAAS;EACxD,MAAM,UAAU,QACd,KAAK,UAAU,MAAM,QAAQ,MAAM,EAAE,KAAK,CAAC,CAC3C,QAAQ,SAAyB,SAAS,KAAA,CAAS,CAAC,CACpD,KAAK,IAAI;EACX,OAAO;GACN;GACA,MAAM,GAAG,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,EAAE,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,OAAO;GACtH,QAAQ;GACR,OAAO;EACR;CACD;CACA,OAAO;EAAE;EAAO,MAAM,aAAa,KAAK;EAAG,QAAQ;CAAS;AAC7D;;AAGA,SAAgB,YAAY,SAA4B,OAAkC;CACzF,OAAO,QAAQ,SAAS,KAAK,IAAI,QAAQ,QAAQ,MAAM,MAAM,KAAK,IAAI,CAAC,GAAG,SAAS,KAAK;AACzF;;;;;;;;;AAYA,SAAgB,kBACf,OACA,UAAA,GAA0B,mBAAA,aAAA,CAAa,GACvC,OACC;CAED,OAAO;EACN,SAAS,oBAAoB,MAAM,SAAS,MAAM,IAAI;EACtD,SAAS,MAAM,WAAW;EAC1B;EACA,OAAO,kBAAkB,KAAK;EAC9B,OAAA,CAAA;EACA,SAAS;CACV;AACD;;;;AAKA,SAAgB,WAAW,OAAqD;CAC/E,MAAM,OAAO,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,SAAS,oBAAoB;CACxF,MAAM,UAAU,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,SAAS,MAAM,MAAM,MAAM,OAAO;CAMxF,OAAO,CAAC,MAAM,GAAG,CAHhB,GAFiB,MAAM,MAAM,KAAK,SAAS,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,SAAS,IAAI,CAE3F,GACH,GAAG,QAAQ,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,SAAS,MAAM,OAAO,GAE1D,CAAI,CAAC,CAAC,KAAK,IAAI;AACjC;;;;;;;AAQA,SAAgB,aACf,OACA,KAC2D;CAC3D,IAAI,IAAI,QAAQ,IAAI,SAAS,KAAK,OAAO;EAAE;EAAO,MAAM,WAAW,KAAK;EAAG,QAAQ;CAAS;CAE5F,IAAI,IAAI,QAAQ,IAAI,SAAS,KAAK;EACjC,MAAM,QAAQ,MAAM,QAAQ,SAAS,IAAI,CAAC,GAAG,MAAM,OAAO,MAAM,OAAO,IAAI,MAAM;EACjF,MAAM,SAAS,MAAM,KAAK,IAAI;EAC9B,MAAM,SAAS,OAAO,SAAS,IAAI,SAAS,MAAM;EAClD,OAAO;GACN;GACA,MAAM,GAAG,aAAa,MAAM,QAAQ,MAAM,OAAO,MAAM,OAAO,EAAE,GAAG,MAAM,OAAO,OAAO,MAAM,MAAM,MAAM,MAAM,GAAG,OAAO,MAAM,MAAM,EAAE,OAAO,MAAM,WAAW,IAAI,KAAK,KAAK;GAC7K,QAAQ;GACR,OAAO;EACR;CACD;CAEA,IAAI,IAAI,SAAS,UAAU;EAC1B,MAAM,OAAO;GACZ,GAAG;GACH,OAAO,CAAC,GAAG,MAAM,OAAO,MAAM,OAAO;GACrC,SAAS;EACV;EACA,OAAO;GAAE,OAAO;GAAM,MAAM,WAAW,IAAI;GAAG,QAAQ;EAAS;CAChE;CAEA,MAAM,UAAU,SAAS,MAAM,SAAS,GAAG;CAC3C,IAAI,YAAY,KAAA,GAAW,OAAO;EAAE;EAAO,MAAM,WAAW,KAAK;EAAG,QAAQ;CAAS;CACrF,MAAM,OAAO;EAAE,GAAG;EAAO;CAAQ;CACjC,OAAO;EAAE,OAAO;EAAM,MAAM,WAAW,IAAI;EAAG,QAAQ;CAAS;AAChE;;;;;;;AAUA,SAAgB,SAAS,OAAe,KAAmC;CAC1E,IAAI,IAAI,QAAQ,IAAI,SAAS,KAAK,OAAO;CACzC,IAAI,IAAI,SAAS,aAAa,OAAO,MAAM,MAAM,GAAG,EAAE;CACtD,IAAI,IAAI,SAAS,SAAS,OAAO,GAAG,MAAM;CAK1C,IAAI,CAAC,IAAI,QAAQ,CAAC,IAAI,QAAQ,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,WAAW,KAAK,YAAY,IAAI,IAAI,GAC/E,OAAO,GAAG,QAAQ,IAAI;AAGxB;;;;;;;;AAWA,SAAgB,aAAa,UAAsB,IAAyB;CAC3E,MAAM,SAAS,WAAW,UAAU,EAAE;CACtC,aAAa,aAAa,MAAM;AACjC;;AAGA,SAAgB,YAAY,OAAe,MAAqC;CAC/E,OAAO,MAAM,OAAO,IAAI;AACzB;;;;;;AAOA,SAAgB,aAAa,OAAyB;CACrD,QAAQ,iBAAiB,gBAAgB,iBAAiB,UAAU,MAAM,SAAS;AACpF;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,iBAAiB,KAAsB;CAEtD,IAAI,CAAC,IAAI,WAAW,SAAM,GAAG,OAAO;CACpC,MAAM,OAAO,IAAI,MAAM,CAAa;CACpC,MAAM,UAAU,KAAK,OAAO,OAAO;CACnC,MAAM,YAAY,YAAY,KAAK,OAAO,KAAK,MAAM,GAAG,OAAO;CAC/D,MAAM,OAAO,UAAU,SAAS,GAAG,IAAI,UAAU,MAAM,UAAU,QAAQ,GAAG,IAAI,CAAC,IAAI;CACrF,MAAM,WAAW,KAAK,WAAW,GAAG,IACjC,KAAK,MAAM,GAAG,KAAK,QAAQ,GAAG,IAAI,CAAC,IAClC,KAAK,MAAM,GAAG,CAAC,CAAC,MAAM;CAC1B,OAAO,aAAa,eAAe,aAAa,eAAe,aAAa;AAC7E;;AAKA,SAAgB,iBAAiB,MAA8B;CAC9D,OAAO;EAAE,OAAO;EAAW,MAAM,KAAK,UAAU,IAAI;EAAG,IAAI,KAAK;CAAG;AACpE;;AAGA,SAAgB,gBAAgB,IAAuB;CACtD,OAAO;EAAE,OAAO;EAAU,MAAM,KAAK,UAAU,EAAE,GAAG,CAAC;CAAE;AACxD;;AAGA,SAAgB,oBAA+B;CAC9C,OAAO;EAAE,OAAO;EAAY,MAAM;CAAG;AACtC;;;;;;;;;;;;;;;;;;;;;;ACt1BA,IAAa,SAAb,MAA+C;CAC9C;CACA;CACA;CACA,0BAAmB,IAAI,IAAoB;CAC3C;CACA,aAAa;CAEb,YAAY,SAAyB;EACpC,KAAKA,WAAW,SAAS,WAAA;EACzB,KAAKC,SAAS,SAAS,SAAS;EAChC,KAAKC,OAAO,SAAS;EACrB,KAAKE,WAAW,IAAI,mBAAA,QAAQ;GAC3B,GAAI,SAAS,OAAO,KAAA,IAAY,EAAE,IAAI,QAAQ,GAAG,IAAI,CAAC;GACtD,GAAI,SAAS,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;EAChE,CAAC;CACF;CAEA,IAAI,UAA4C;EAC/C,OAAO,KAAKA;CACb;CAEA,IAAI,QAAgB;EACnB,OAAO,KAAKD,QAAQ;CACrB;CAIA,QAAQ,IAA+D;EACtE,IAAI,OAAO,KAAA,GAAW,OAAO,KAAKA,QAAQ,IAAI,EAAE,CAAC,EAAE;EACnD,MAAM,QAAuB,CAAC;EAC9B,KAAK,MAAM,UAAU,KAAKA,QAAQ,OAAO,GAAG,MAAM,KAAK,OAAO,OAAO;EACrE,OAAO;CACR;CAEA,KAAK,MAAqB,SAA+B;EACxD,IAAI,KAAKE,YAAY;GACpB,KAAK,QAAQ;GACb,MAAM,IAAI,cAAc,UAAU,+BAA+B;EAClE;EACA,IAAI,KAAKH,SAAS,KAAA,KAAa,KAAKC,QAAQ,QAAQ,KAAKD,MAAM;GAC9D,KAAK,QAAQ;GACb,MAAM,IAAI,cAAc,SAAS,wBAAwB,OAAO,KAAKA,IAAI,EAAE,gBAAgB,EAC1F,KAAK,KAAKA,KACX,CAAC;EACF;EAEA,MAAM,KAAK,OAAO,WAAW;EAC7B,MAAM,UAAuB;GAC5B;GACA,SAAA,GAAQ,gBAAA,cAAA,CAAc,KAAK,MAAM;GACjC,QAAQ;GACR,MAAM,KAAK,IAAI;GACf,GAAI,SAAS,SAAS,KAAA,IAAY,EAAE,MAAM,QAAQ,KAAK,IAAI,CAAC;GAC5D,GAAI,SAAS,OAAO,KAAA,IAAY,EAAE,IAAI,QAAQ,GAAG,IAAI,CAAC;EACvD;EACA,MAAM,SAAS,KAAKD,aAAa,KAAKK,QAAQ,EAAE,GAAG,KAAKN,QAAQ;EAChE,KAAKG,QAAQ,IAAI,IAAI;GAAE;GAAM;GAAS;EAAO,CAAC;EAC9C,KAAKC,SAAS,KAAK,WAAW,OAAO;EACrC,OAAO;CACR;CAEA,OAAO,IAAY,QAAqD;EACvE,MAAM,WAAA,GAAU,oBAAA,QAAA,OAAc,KAAKG,QAAQ,IAAI,MAAM,CAAC;EACtD,IAAI,QAAQ,SAAS,OAAO,QAAQ;EACpC,OAAO;GACN,SAAS;GACT,OAAO;IACN,QAAQ;IACR,QAAQ,CAAC;KAAE,OAAO;KAAQ,SAAS;IAA+B,CAAC;GACpE;EACD;CACD;CAKA,KAAK,KAAkD;EACtD,IAAI,QAAQ,KAAA,GAAW;GACtB,KAAK,MAAM,MAAM,CAAC,GAAG,KAAKJ,QAAQ,KAAK,CAAC,GAAG,KAAKG,QAAQ,EAAE;GAC1D;EACD;EACA,KAAA,GAAI,oBAAA,QAAA,CAAQ,GAAG,GAAG;GACjB,IAAI,UAAU;GACd,KAAK,MAAM,MAAM,KAAK;IACrB,MAAM,SAAS,KAAKH,QAAQ,IAAI,EAAE;IAClC,IAAI,WAAW,KAAA,KAAa,OAAO,QAAQ,WAAW,WAAW,UAAU;GAC5E;GACA,KAAK,MAAM,MAAM,KAAK,KAAKG,QAAQ,EAAE;GACrC,OAAO;EACR;EACA,OAAO,KAAKA,QAAQ,GAAG;CACxB;CAEA,UAAgB;EACf,IAAI,KAAKD,YAAY;EACrB,KAAKA,aAAa;EAClB,KAAK,MAAM,MAAM,CAAC,GAAG,KAAKF,QAAQ,KAAK,CAAC,GAAG,KAAKG,QAAQ,EAAE;EAC1D,KAAKF,SAAS,QAAQ;CACvB;CAEA,QAAQ,IAAY,QAAqD;EACxE,MAAM,SAAS,KAAKD,QAAQ,IAAI,EAAE;EAClC,IAAI,WAAW,KAAA,KAAa,OAAO,QAAQ,WAAW,WACrD,OAAO;GAAE,SAAS;GAAO,OAAO,EAAE,QAAQ,UAAU;EAAE;EAGvD,MAAM,WAAA,GAAU,oBAAA,QAAA,OAAc,KAAKK,QAAQ,OAAO,MAAM,MAAM,CAAC;EAC/D,IAAI,CAAC,QAAQ,SACZ,OAAO;GACN,SAAS;GACT,OAAO;IAAE,QAAQ;IAAY,QAAQ,KAAKC,QAAQ,QAAQ,OAAO,OAAO,IAAI;GAAE;EAC/E;EAED,IAAI,CAAC,QAAQ,MAAM,SAClB,OAAO;GACN,SAAS;GACT,OAAO;IAAE,QAAQ;IAAY,QAAQ,QAAQ,MAAM;GAAM;EAC1D;EAGD,OAAO,OAAO;EACd,MAAM,WAAmB;GACxB,GAAG;GACH,SAAS;IAAE,GAAG,OAAO;IAAS,QAAQ;GAAW;EAClD;EACA,KAAKN,QAAQ,IAAI,IAAI,QAAQ;EAC7B,KAAKC,SAAS,KAAK,UAAU,IAAI,QAAQ,MAAM,KAAK;EACpD,KAAKD,QAAQ,OAAO,EAAE;EACtB,OAAO,QAAQ;CAChB;CAEA,QAAQ,MAAqB,QAAgC;EAC5D,KAAK,MAAM,CAAC,OAAO,UAAU,OAAO,QAAQ,MAAM,GAAG;GACpD,MAAM,WAAA,GAAU,oBAAA,QAAA,OAAc,KAAK,KAAK,OAAO,KAAK,CAAC;GACrD,IAAI,CAAC,QAAQ,SACZ,OAAO;IAAE,SAAS;IAAO,OAAO,KAAKM,QAAQ,QAAQ,OAAO,MAAM,KAAK;GAAE;EAE3E;EACA,OAAO,KAAK,OAAO;CACpB;CAEA,QAAQ,OAAgB,MAAqB,OAAuC;EACnF,KAAA,GAAI,gBAAA,YAAA,CAAY,KAAK,GAAG;GACvB,KAAA,GAAI,gBAAA,aAAA,CAAa,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,OAAO;GACtD,MAAM,QAAQ,MAAM,SAAS;GAC7B,OAAO,CACN;IACC,OAAO,OAAO,UAAU,WAAW,QAAQ,KAAKC,OAAO,MAAM,KAAK;IAClE,SAAS,MAAM;GAChB,CACD;EACD;EACA,OAAO,CACN;GACC,OAAO,KAAKA,OAAO,MAAM,KAAK;GAC9B,SAAS;EACV,CACD;CACD;CAEA,OAAO,MAAqB,OAAwB;EACnD,OAAO,SAAS,KAAK,OAAO,OAAO,EAAE,EAAE,QAAQ,KAAK,OAAO,QAAQ;CACpE;CAEA,QAAQ,IAAqB;EAC5B,MAAM,SAAS,KAAKP,QAAQ,IAAI,EAAE;EAClC,IAAI,WAAW,KAAA,KAAa,OAAO,QAAQ,WAAW,WAAW,OAAO;EACxE,OAAO,OAAO;EACd,MAAM,UAAkB;GACvB,GAAG;GACH,SAAS;IAAE,GAAG,OAAO;IAAS,QAAQ;GAAU;EACjD;EACA,KAAKA,QAAQ,IAAI,IAAI,OAAO;EAC5B,OAAO,KAAK,QAAQ;EACpB,KAAKC,SAAS,KAAK,UAAU,EAAE;EAC/B,KAAKD,QAAQ,OAAO,EAAE;EACtB,OAAO;CACR;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC9JA,IAAa,eAAb,MAA2D;CAC1D;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,cAAc;CACd,aAAa;CACb,aAAa;CACb,YAAY;CACZ,uBAAuB;CACvB,wBAAiB,IAAI,IAAY;CACjC,yBAAkB,IAAI,IAAwB;CAC9C;CAIA,YAAY,SAA8B;EACzC,KAAK,MAAM,QAAQ;EACnB,KAAKQ,YAAY,QAAQ;EACzB,KAAKC,SAAS,QAAQ;EACtB,KAAKC,aAAa,QAAQ,aAAa;EACvC,KAAKC,SAAS,QAAQ,SAAA;EACtB,KAAKC,SAAS,QAAQ,SAAS;EAC/B,KAAKC,SAAS,QAAQ,SAAS;EAC/B,KAAKC,WAAW,IAAI,mBAAA,QAAQ;GAC3B,GAAI,QAAQ,OAAO,KAAA,IAAY,EAAE,IAAI,QAAQ,GAAG,IAAI,CAAC;GACrD,GAAI,QAAQ,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;EAC/D,CAAC;CACF;CAEA,IAAI,UAAkD;EACrD,OAAO,KAAKA;CACb;CAEA,IAAI,YAAqB;EACxB,OAAO,KAAKG;CACb;CAEA,MAAM,UAAyB;EAC9B,IAAI,KAAKC,cAAc,KAAKC,aAAa;EACzC,KAAKA,cAAc;EACnB,OAAO,KAAKA,eAAe,CAAC,KAAKD,YAAY;GAC5C,IAAI;IACH,MAAM,KAAKE,QAAQ;GACpB,SAAS,OAAO;IACf,KAAKC,kBAAkB;IACvB,IAAI,KAAKH,cAAc,aAAa,KAAK,GAAG;IAC5C,KAAKJ,SAAS,KAAK,SAAS,KAAK;GAClC;GACA,IAAI,CAAC,KAAKJ,cAAc,CAAC,KAAKS,eAAe,KAAKD,YAAY;GAC9D,MAAM,KAAKI,MAAM,KAAKX,MAAM;EAC7B;CACD;CAEA,aAAmB;EAClB,KAAKQ,cAAc;EACnB,KAAKI,aAAa,MAAM;EACxB,KAAKA,cAAc,KAAA;EACnB,KAAKC,WAAW;EAChB,KAAKA,WAAW,KAAA;EAChB,MAAM,OAAO,KAAKC;EAClB,KAAKA,QAAQ,KAAA;EACb,OAAO;EACP,KAAKJ,kBAAkB;CACxB;CAEA,UAAgB;EACf,IAAI,KAAKH,YAAY;EACrB,KAAKA,aAAa;EAClB,KAAK,WAAW;EAChB,KAAKQ,WAAW;EAChB,KAAKZ,SAAS,QAAQ;CACvB;CAEA,MAAMM,UAAyB;EAC9B,IAAI,KAAKX,WAAW,KAAA,KAAa,iBAAiB,KAAK,GAAG,KAAK,CAAC,KAAKkB,sBAAsB;GAC1F,KAAKA,uBAAuB;GAC5B,KAAKb,SAAS,KACb,yBACA,IAAI,MAAM,4DAA4D,CACvE;EACD;EACA,MAAM,aAAa,IAAI,gBAAgB;EACvC,KAAKS,cAAc;EACnB,MAAM,WAAW,MAAM,KAAKX,OAAO,KAAK,KAAK;GAC5C,SAAS,KAAKgB,SAAS,EAAE,QAAQ,oBAAoB,CAAC;GACtD,QAAQ,WAAW;EACpB,CAAC;EACD,IAAI,CAAC,SAAS,IAAI,MAAM,IAAI,MAAM,mBAAmB,OAAO,SAAS,MAAM,GAAG;EAC9E,MAAM,OAAO,SAAS;EACtB,IAAI,SAAS,MAAM,MAAM,IAAI,MAAM,uBAAuB;EAE1D,KAAKX,aAAa;EAClB,KAAKH,SAAS,KAAK,SAAS;EAE5B,MAAM,SAAS,KAAK,UAAU;EAC9B,MAAM,UAAU,IAAI,YAAY;EAChC,MAAM,UAAA,GAAS,eAAA,gBAAA,CAAgB,EAAE,OAAO,iBAAiB,CAAC;EAC1D,IAAI;GACH,SAAS;IACR,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;IAC1C,IAAI,MAAM;IACV,KAAK,MAAM,SAAS,OAAO,MAAM,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC,CAAC,GAAG;KAC1E,KAAKe,QAAQ,KAAK;KAClB,IAAI,CAAC,KAAKV,aAAa;IACxB;IACA,IAAI,CAAC,KAAKA,aAAa;GACxB;EACD,UAAU;GACT,OAAO,YAAY;EACpB;EACA,KAAKE,kBAAkB;CACxB;CAEA,QAAQ,OAAuB;EAC9B,IAAI,MAAM,UAAU,WAAW,SAAS;GACvC,MAAM,UAAA,GAAS,oBAAA,UAAA,CAAU,MAAM,IAAI;GACnC,IAAI,CAAC,cAAc,MAAM,KAAK,KAAKN,MAAM,IAAI,OAAO,EAAE,GAAG;GACzD,MAAM,UAAA,GAAS,gBAAA,UAAA,CAAU,OAAO,MAAM;GACtC,IAAI,WAAW,KAAA,GAAW;IACzB,KAAKD,SAAS,KACb,yBACA,IAAI,MAAM,0CAA0C,OAAO,IAAI,CAChE;IACA;GACD;GACA,KAAKC,MAAM,IAAI,OAAO,EAAE;GACxB,KAAKC,OAAO,IAAI,OAAO,IAAI,eAAe,MAAM,CAAC;GACjD,KAAUc,OAAO;GACjB;EACD;EACA,IAAI,MAAM,UAAU,WAAW,QAAQ;GACtC,MAAM,UAAA,GAAS,oBAAA,UAAA,CAAU,MAAM,IAAI;GACnC,KAAA,GAAI,oBAAA,SAAA,CAAS,MAAM,MAAA,GAAK,oBAAA,SAAA,CAAS,OAAO,EAAE,GAAG,KAAKC,QAAQ,OAAO,EAAE;GACnE;EACD;EACA,IAAI,MAAM,UAAU,WAAW,UAAU;GACxC,KAAK,WAAW;GAChB,KAAKL,WAAW;EACjB;CACD;CAEA,MAAMI,SAAwB;EAC7B,IAAI,KAAKE,WAAW;EACpB,KAAKA,YAAY;EACjB,IAAI;GACH,OAAO,CAAC,KAAKd,YAAY;IACxB,IAAI;IACJ,KAAK,MAAM,SAAS,KAAKF,QAAQ;KAChC,SAAS;KACT;IACD;IACA,IAAI,WAAW,KAAA,GAAW;IAC1B,MAAM,CAAC,IAAI,UAAU;IACrB,KAAKA,OAAO,OAAO,EAAE;IACrB,IAAI;KACH,MAAM,KAAKiB,QAAQ,IAAI,MAAM;IAC9B,SAAS,OAAO;KACf,MAAM,SAAS,KAAKC;KACpB,IAAI,QAAQ,OAAO,MAAM,CAAC,OAAO,SAAS,KAAKpB,SAAS,KAAK,SAAS,KAAK;IAC5E,UAAU;KACT,MAAM,SAAS,KAAKoB;KACpB,IAAI,QAAQ,OAAO,IAAI;MACtB,OAAO,KAAK,QAAQ;MACpB,KAAKA,UAAU,KAAA;KAChB;KACA,IAAI,CAAC,KAAKlB,OAAO,IAAI,EAAE,GAAG,KAAKD,MAAM,OAAO,EAAE;IAC/C;GACD;EACD,UAAU;GACT,KAAKiB,YAAY;EAClB;CACD;CAEA,MAAMC,QAAQ,IAAY,QAAmC;EAC5D,IAAI;EACJ,IAAI,SAAgC,CAAC;EACrC,OAAO,KAAKlB,MAAM,IAAI,EAAE,KAAK,CAAC,KAAKG,YAAY;GAC9C,MAAM,OAAO,KAAKiB,qBAAqB,QAAQ,MAAM;GACrD,KAAKD,UAAU;IAAE;IAAI;IAAM,SAAS;GAAM;GAC1C,KAAK,MAAM,SAAS,QAAQ,KAAK,WAAW,MAAM,OAAO,oBAAoB,MAAM,OAAO,CAAC;GAC3F,MAAM,YAAY,MAAM,KAAK1B,UAAU,IAAI,IAAI;GAC/C,MAAM,SAAS,KAAK0B;GACpB,IAAI,QAAQ,OAAO,MAAM,OAAO,SAAS;GACzC,MAAM,WAAW,MAAM,KAAKE,MAAM,IAAI,SAAS;GAC/C,MAAM,SAAS,KAAKF;GACpB,IAAI,QAAQ,OAAO,MAAM,OAAO,WAAW,aAAa,KAAA,GAAW;GACnE,SAAS;GACT,SAAS;GACT,KAAK,QAAQ;GACb,KAAKA,UAAU,KAAA;EAChB;CACD;CAEA,qBAAqB,QAAoB,QAAoC;EAC5E,MAAM,SAAS,OAAO,OAAO,KAAK,UAAU;GAC3C,IAAI,MAAM,MAAM,YAAY,KAAA,GAAW,OAAO;GAC9C,MAAM,EAAE,SAAS,UAAU,GAAG,SAAS,MAAM;GAC7C,OAAO;IAAE,GAAG;IAAO;GAAK;EACzB,CAAC;EACD,MAAM,QAAA,GAAO,gBAAA,WAAA,CAAW;GAAE,GAAG;GAAQ;EAAO,GAAG,WAAW,KAAA,IAAY,KAAA,IAAY,EAAE,OAAO,CAAC;EAC5F,KAAU,OAAO,YAAY,KAAA,CAAS;EACtC,OAAO;CACR;CAEA,MAAME,MAAM,IAAY,QAAgE;EACvF,MAAM,WAAW,MAAM,KAAKxB,OAAO,KAAK,KAAK;GAC5C,QAAQ;GACR,SAAS,KAAKgB,SAAS,EAAE,gBAAgB,mBAAmB,CAAC;GAC7D,MAAM,KAAK,UAAU;IAAE;IAAI;GAAO,CAAC;EACpC,CAAC;EACD,IAAI,CAAC,SAAS,IAAI,KAAKd,SAAS,KAAK,yBAAS,IAAI,MAAM,0BAA0B,IAAI,CAAC;EACvF,MAAM,UAAA,GAAS,oBAAA,UAAA,CAAU,MAAM,SAAS,KAAK,CAAC;EAC9C,IAAI,EAAA,GAAC,oBAAA,SAAA,CAAS,MAAM,KAAK,EAAA,GAAC,oBAAA,UAAA,CAAU,OAAO,OAAO,GAAG;GACpD,KAAKA,SAAS,KAAK,yBAAS,IAAI,MAAM,gDAAgD,IAAI,CAAC;GAC3F;EACD;EACA,IAAI,OAAO,SAAS,OAAO,KAAA;EAC3B,MAAM,QAAQ,OAAO;EACrB,IAAI,EAAA,GAAC,oBAAA,SAAA,CAAS,KAAK,KAAK,EAAA,GAAC,oBAAA,SAAA,CAAS,MAAM,MAAM,GAAG;GAChD,KAAKA,SAAS,KAAK,yBAAS,IAAI,MAAM,+CAA+C,IAAI,CAAC;GAC1F;EACD;EACA,IAAI,MAAM,WAAW,WAAW,OAAO,KAAA;EACvC,IAAI,MAAM,WAAW,eAAA,GAAc,oBAAA,QAAA,CAAQ,gBAAA,YAAY,CAAC,CAAC,MAAM,MAAM,GAAG,OAAO,MAAM;EACrF,KAAKA,SAAS,KAAK,yBAAS,IAAI,MAAM,iDAAiD,IAAI,CAAC;CAE7F;CAEA,QAAQ,IAAkB;EACzB,MAAM,SAAS,KAAKoB;EACpB,IAAI,QAAQ,OAAO,IAAI;GACtB,KAAKA,UAAU;IAAE,GAAG;IAAQ,SAAS;GAAK;GAC1C,KAAKnB,MAAM,OAAO,EAAE;GACpB,OAAO,KAAK,QAAQ;EACrB,OAAO,IAAI,KAAKC,OAAO,OAAO,EAAE,GAAG,KAAKD,MAAM,OAAO,EAAE;EACvD,KAAKD,SAAS,KAAK,UAAU,EAAE;CAChC;CAEA,aAAmB;EAClB,KAAKE,OAAO,MAAM;EAClB,KAAKD,MAAM,MAAM;EACjB,MAAM,SAAS,KAAKmB;EACpB,IAAI,WAAW,KAAA,GAAW;EAC1B,KAAKA,UAAU;GAAE,GAAG;GAAQ,SAAS;EAAK;EAC1C,OAAO,KAAK,QAAQ;CACrB;CAEA,oBAA0B;EACzB,IAAI,CAAC,KAAKjB,YAAY;EACtB,KAAKA,aAAa;EAClB,KAAKH,SAAS,KAAK,YAAY;CAChC;CAEA,SAAS,MAAsD;EAC9D,IAAI,KAAKL,WAAW,KAAA,GAAW,OAAO;GAAE,GAAG;IAAO,eAAe,KAAKA;EAAO;EAC7E,OAAO,EAAE,GAAG,KAAK;CAClB;CAEA,MAAM,IAA2B;EAChC,OAAO,IAAI,SAAS,YAAY;GAC/B,MAAM,SAAS,KAAK4B,eAAe,OAAO;GAC1C,KAAKZ,QAAQ;GACb,KAAKD,WAAW,KAAKX,OAAO,QAAQ,EAAE;EACvC,CAAC;CACF;CAEA,eAAe,SAAiC;EAC/C,aAAa;GACZ,KAAKW,WAAW,KAAA;GAChB,KAAKC,QAAQ,KAAA;GACb,QAAQ;EACT;CACD;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChSA,IAAa,kBAAb,MAAiE;CAChE,6BAAsB,IAAI,IAA6B;CACvD,0BAAmB,IAAI,IAA2B;CAGlD,6BAAsB,IAAI,IAOxB;CAIF,yBAAkB,IAAI,IAA4D;CAClF;CACA;CACA;CACA;CACA;CACA,aAAa;CAEb,YAAY,SAAkC;EAC7C,KAAKiB,SAAS,SAAS;EACvB,KAAKC,WAAW,SAAS;EACzB,KAAKC,SAAS,SAAS;EACvB,KAAKC,OAAO,SAAS;EACrB,KAAKC,WAAW,IAAI,mBAAA,QAAQ;GAC3B,GAAI,SAAS,OAAO,KAAA,IAAY,EAAE,IAAI,QAAQ,GAAG,IAAI,CAAC;GACtD,GAAI,SAAS,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;EAChE,CAAC;CACF;CAEA,IAAI,UAAqD;EACxD,OAAO,KAAKA;CACb;CAEA,IAAI,QAAgB;EACnB,OAAO,KAAKR,WAAW;CACxB;CAIA,SAAS,MAA2C;EACnD,OAAO,KAAKA,WAAW,IAAI,IAAI;CAChC;CAEA,YAA+B;EAC9B,OAAO,CAAC,GAAG,KAAKA,WAAW,KAAK,CAAC;CAClC;CAIA,IAAI,MAAc,SAA0C;EAC3D,IAAI,KAAKS,YAAY,MAAM,IAAI,cAAc,aAAa,mBAAmB;EAC7E,MAAM,WAAW,KAAKT,WAAW,IAAI,IAAI;EACzC,IAAI,aAAa,KAAA,GAAW,OAAO;EACnC,MAAM,UAAU,SAAS,WAAW,KAAKK;EACzC,MAAM,QAAQ,SAAS,SAAS,KAAKC;EACrC,MAAM,MAAM,SAAS,OAAO,KAAKC;EAQjC,MAAM,SAAS,aAAa;GAN3B,GAAI,SAAS,OAAO,KAAA,IAAY,EAAE,IAAI,QAAQ,GAAG,IAAI,CAAC;GACtD,GAAI,SAAS,UAAU,KAAA,IAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;GAC/D,GAAI,YAAY,KAAA,IAAY,EAAE,QAAQ,IAAI,CAAC;GAC3C,GAAI,UAAU,KAAA,IAAY,EAAE,MAAM,IAAI,CAAC;GACvC,GAAI,QAAQ,KAAA,IAAY,EAAE,IAAI,IAAI,CAAC;EAER,CAAa;EACzC,MAAM,YAAY;GACjB,SAAS,KAAKG,uBAAuB;GACrC,QAAQ,KAAKC,sBAAsB,IAAI;GACvC,QAAQ,KAAKC,sBAAsB,IAAI;EACxC;EACA,OAAO,QAAQ,GAAG,WAAW,UAAU,OAAO;EAC9C,OAAO,QAAQ,GAAG,UAAU,UAAU,MAAM;EAC5C,OAAO,QAAQ,GAAG,UAAU,UAAU,MAAM;EAC5C,KAAKZ,WAAW,IAAI,MAAM,MAAM;EAChC,KAAKC,QAAQ,IAAI,MAAM,EAAE,GAAG,QAAQ,CAAC;EACrC,KAAKC,WAAW,IAAI,MAAM,SAAS;EACnC,OAAO;CACR;CAIA,IAAI,MAAc,IAAY,MAA0C;EACvE,MAAM,SAAS,KAAKF,WAAW,IAAI,EAAE;EACrC,IAAI,WAAW,KAAA,GAAW;GACzB,MAAM,QAAQ,KAAK,UAAU;GAC7B,OAAO,QAAQ,OACd,IAAI,cACH,UACA,qBAAqB,GAAG,YAAY,MAAM,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,IACjF;IAAE;IAAI;GAAM,CACb,CACD;EACD;EACA,MAAM,QAAQ,KAAKa,WAAW,MAAM,EAAE;EACtC,IAAI,UAAU,KAAA,GACb,OAAO,QAAQ,OACd,IAAI,cACH,YACA,OAAO,KAAK,MAAM,GAAG,mBAAmB,MAAM,KAAK,MAAM,KACzD;GACC;GACA;GACA,MAAM;EACP,CACD,CACD;EAED,MAAM,KAAK,OAAO,KAAK,MAAM;GAAE;GAAM;EAAG,CAAC;EACzC,IAAI,OAAO,QAAQ,EAAE,MAAM,KAAA,GAAW;GACrC,KAAKV,OAAO,IAAI,IAAI;IAAE;IAAM;GAAG,CAAC;GAChC,KAAK,OAAO,KAAK,KAAKW,iBAAiB,EAAE,GAAG,KAAKA,iBAAiB,EAAE,CAAC;EACtE;EACA,OAAO,KAAK;CACb;CAMA,QAAQ,IAAqC;EAC5C,IAAI,OAAO,KAAA,GAAW;GACrB,MAAM,SAAS,KAAKd,WAAW,IAAI,EAAE;GACrC,OAAO,WAAW,KAAA,IAAY,CAAC,IAAI,OAAO,QAAQ;EACnD;EACA,MAAM,SAAwB,CAAC;EAC/B,KAAK,MAAM,UAAU,KAAKA,WAAW,OAAO,GAAG,OAAO,KAAK,GAAG,OAAO,QAAQ,CAAC;EAC9E,OAAO;CACR;CAIA,OAAO,IAAY,IAAY,QAA6D;EAC3F,MAAM,SAAS,KAAKA,WAAW,IAAI,EAAE;EACrC,IAAI,WAAW,KAAA,GAAW,OAAO;GAAE,SAAS;GAAO,OAAO,EAAE,QAAQ,WAAW;EAAE;EACjF,MAAM,SAAS,OAAO,OAAO,IAAI,MAAM;EACvC,IAAI,OAAO,SAAS,KAAKG,OAAO,OAAO,EAAE;EACzC,OAAO;CACR;CAIA,MAAM,KAAK,MAAoD;EAC9D,IAAI,KAAKM,YAAY,MAAM,IAAI,cAAc,aAAa,mBAAmB;EAC7E,MAAM,WAAW,KAAKT,WAAW,IAAI,IAAI;EACzC,IAAI,aAAa,KAAA,GAAW,OAAO;EACnC,IAAI,KAAKI,WAAW,KAAA,GAAW,OAAO,KAAA;EACtC,MAAM,WAAW,MAAM,KAAKA,OAAO,IAAI,IAAI;EAC3C,IAAI,KAAKK,YAAY,MAAM,IAAI,cAAc,aAAa,mBAAmB;EAC7E,IAAI,aAAa,KAAA,GAAW,OAAO,KAAA;EACnC,OAAO,KAAK,IAAI,MAAM,SAAS,YAAY,KAAA,IAAY,EAAE,SAAS,SAAS,QAAQ,IAAI,CAAC,CAAC;CAC1F;CAEA,MAAM,KAAK,MAAgC;EAC1C,MAAM,SAAS,KAAKT,WAAW,IAAI,IAAI;EACvC,IAAI,KAAKI,WAAW,KAAA,KAAa,WAAW,KAAA,GAAW,OAAO;EAC9D,MAAM,SAAS,KAAKH,QAAQ,IAAI,IAAI;EACpC,MAAM,WAA6B;GAClC,IAAI;GACJ,GAAI,QAAQ,YAAY,KAAA,IAAY,EAAE,SAAS,OAAO,QAAQ,IAAI,CAAC;EACpE;EACA,MAAM,KAAKG,OAAO,IAAI,QAAQ;EAC9B,OAAO;CACR;CAOA,OAAO,OAAoD;EAC1D,IAAI,UAAU,KAAA,GAAW;GACxB,KAAK,MAAM,QAAQ,CAAC,GAAG,KAAKJ,WAAW,KAAK,CAAC,GAAG,KAAKe,WAAW,IAAI;GACpE;EACD;EACA,KAAA,GAAI,oBAAA,QAAA,CAAQ,KAAK,GAAG;GACnB,IAAI,UAAU;GACd,KAAK,MAAM,QAAQ,OAClB,IAAI,KAAKA,WAAW,IAAI,GAAG,UAAU;GAEtC,OAAO;EACR;EACA,OAAO,KAAKA,WAAW,KAAK;CAC7B;CAEA,UAAgB;EACf,IAAI,KAAKN,YAAY;EACrB,KAAKA,aAAa;EAClB,KAAK,OAAO;EACZ,KAAKN,OAAO,MAAM;EAClB,KAAKK,SAAS,QAAQ;CACvB;CAIA,yBAAsD;EACrD,QAAQ,SAAS,KAAKA,SAAS,KAAK,WAAW,IAAI;CACpD;CAEA,sBAAsB,MAAwD;EAC7E,QAAQ,IAAI,WAAW;GACtB,KAAKL,OAAO,OAAO,EAAE;GACrB,KAAKK,SAAS,KAAK,UAAU,MAAM,IAAI,MAAM;EAC9C;CACD;CAEA,sBAAsB,MAAoC;EACzD,QAAQ,OAAO;GACd,KAAKL,OAAO,OAAO,EAAE;GACrB,KAAKK,SAAS,KAAK,UAAU,MAAM,EAAE;EACtC;CACD;CAEA,iBAAiB,IAAwB;EACxC,aAAa;GACZ,KAAKL,OAAO,OAAO,EAAE;EACtB;CACD;CAMA,WAAW,MAAuB;EACjC,MAAM,SAAS,KAAKH,WAAW,IAAI,IAAI;EACvC,IAAI,WAAW,KAAA,GAAW,OAAO;EACjC,OAAO,QAAQ;EACf,MAAM,YAAY,KAAKE,WAAW,IAAI,IAAI;EAC1C,IAAI,cAAc,KAAA,GAAW;GAC5B,OAAO,QAAQ,IAAI,WAAW,UAAU,OAAO;GAC/C,OAAO,QAAQ,IAAI,UAAU,UAAU,MAAM;GAC7C,OAAO,QAAQ,IAAI,UAAU,UAAU,MAAM;EAC9C;EACA,KAAKF,WAAW,OAAO,IAAI;EAC3B,KAAKC,QAAQ,OAAO,IAAI;EACxB,KAAKC,WAAW,OAAO,IAAI;EAC3B,KAAKc,YAAY,IAAI;EACrB,OAAO;CACR;CAEA,YAAY,IAAkB;EAC7B,KAAK,MAAM,CAAC,IAAI,SAAS,KAAKb,QAC7B,IAAI,KAAK,OAAO,IAAI,KAAKA,OAAO,OAAO,EAAE;CAE3C;CAKA,WAAW,MAAc,IAA2C;EACnE,IAAI,SAAS,IAAI,OAAO,CAAC,MAAM,EAAE;EACjC,MAAM,0BAAU,IAAI,IAAY,CAAC,EAAE,CAAC;EACpC,MAAM,QAAkC,CAAC,CAAC,EAAE,CAAC;EAC7C,OAAO,MAAM,SAAS,GAAG;GACxB,MAAM,OAAO,MAAM,MAAM;GACzB,IAAI,SAAS,KAAA,GAAW;GACxB,MAAM,OAAO,KAAK,KAAK,SAAS;GAChC,IAAI,SAAS,KAAA,GAAW;GACxB,KAAK,MAAM,QAAQ,KAAKA,OAAO,OAAO,GAAG;IACxC,IAAI,KAAK,SAAS,MAAM;IACxB,IAAI,KAAK,OAAO,MAAM,OAAO;KAAC;KAAM,GAAG;KAAM;IAAI;IACjD,IAAI,QAAQ,IAAI,KAAK,EAAE,GAAG;IAC1B,QAAQ,IAAI,KAAK,EAAE;IACnB,MAAM,KAAK,CAAC,GAAG,MAAM,KAAK,EAAE,CAAC;GAC9B;EACD;CAED;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACnSA,IAAa,sBAAb,MAAmE;CAClE,6BAAsB,IAAI,IAA8B;CAExD,IAAI,IAAmD;EACtD,OAAO,QAAQ,QAAQ,KAAKc,WAAW,IAAI,EAAE,CAAC;CAC/C;CAEA,IAAI,UAA2C;EAE9C,KAAKA,WAAW,IAAI,SAAS,IAAI,QAAQ;EACzC,OAAO,QAAQ,QAAQ;CACxB;CAEA,OAAO,IAA2B;EAEjC,KAAKA,WAAW,OAAO,EAAE;EACzB,OAAO,QAAQ,QAAQ;CACxB;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACNA,IAAa,wBAAb,MAAqE;CACpE;;;;;;;CAQA,YAAY,OAA4C;EACvD,KAAKC,SAAS;CACf;;CAGA,MAAM,IAAI,IAAmD;EAC5D,MAAM,MAAM,MAAM,KAAKA,OAAO,IAAI,EAAE;EACpC,IAAI,QAAQ,KAAA,GAAW,OAAO,KAAA;EAI9B,OAAO,mBAAmB,IAAI,QAAQ,IAAI,IAAI,WAAW,KAAA;CAC1D;;CAGA,MAAM,IAAI,UAA2C;EACpD,MAAM,KAAKA,OAAO,IAAI;GAAE,IAAI,SAAS;GAAI;EAAS,CAAC;CACpD;;CAGA,MAAM,OAAO,IAA2B;EACvC,MAAM,KAAKA,OAAO,OAAO,EAAE;CAC5B;AACD;;;;;;;;;;;;;;;;;;;;;;;;;;ACpCA,SAAgB,aAAa,SAA0C;CACtE,OAAO,IAAI,OAAO,OAAO;AAC1B;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,SAAgB,mBAAmB,SAAqD;CACvF,OAAO,IAAI,aAAa,OAAO;AAChC;;;;;;;;;;;;;;;;;AAkBA,SAAgB,sBAAsB,SAA4D;CACjG,OAAO,IAAI,gBAAgB,OAAO;AACnC;;;;;;;;;;;;;;AAeA,SAAgB,4BAAoD;CACnE,OAAO,IAAI,oBAAoB;AAChC;;;;;;;;;;;;;;;;AAiBA,SAAgB,4BACf,UAAA,GAA0B,oBAAA,mBAAA,CAAmB,GACpB;CAGzB,MAAM,UAAU;EAAE,KAAA,GAAI,oBAAA,YAAA,CAAY;EAAG,WAAA,GAAU,oBAAA,SAAA,CAAS,CAAC,CAAC;CAAE;CAG5D,OAAO,IAAI,uBADL,GADW,oBAAA,eAAA,CAAe;EAAE;EAAQ,QAAQ,EAAE,WAAW,QAAQ;CAAE,CACtB,CAAA,CAAS,MAAM,WACjC,CAAK;AACvC"}
@@ -204,9 +204,9 @@ export declare function createPasswordState(field: PasswordField, styler?: Style
204
204
  * @returns A {@link PromptInterface}
205
205
  *
206
206
  * @remarks
207
- * The caller awaits the parked form's own `answer`. Timeout or teardown destroys the form, so that
208
- * promise rejects with the Form package's `ABANDONED` error. Inject `options.timer` to drive
209
- * expiry without real time.
207
+ * The caller awaits the parked form's own `answer`. Timeout, `stop`, or teardown destroys the form,
208
+ * so that promise rejects with the Form package's `ABANDONED` error. Inject `options.timer` to
209
+ * drive expiry without real time.
210
210
  *
211
211
  * @example
212
212
  * ```ts
@@ -747,7 +747,7 @@ export declare interface PendingForm {
747
747
  * @remarks
748
748
  * - `pending` — parked, awaiting {@link PromptInterface.answer}.
749
749
  * - `answered` — answered and accepted, so the parked form settled.
750
- * - `expired` — timed out, or torn down by `destroy`, before an answer.
750
+ * - `expired` — timed out, released by `stop`, or torn down by `destroy`, before an answer.
751
751
  */
752
752
  export declare type PendingFormStatus = 'pending' | 'answered' | 'expired';
753
753
 
@@ -758,7 +758,8 @@ export declare type PendingFormStatus = 'pending' | 'answered' | 'expired';
758
758
  * @remarks
759
759
  * A parked record carries one call to `serializeForm`. A failed fill or submit leaves the record
760
760
  * parked for another answer. A successful submit settles the form once, emits `answer`, and removes
761
- * the record. Timeout and teardown abandon every unsettled form through its own `destroy` method.
761
+ * the record. Timeout, `stop`, and teardown abandon unsettled forms through their own `destroy`
762
+ * method.
762
763
  *
763
764
  * @example
764
765
  * ```ts
@@ -778,6 +779,9 @@ export declare class Prompt implements PromptInterface {
778
779
  pending(id: string): PendingForm | undefined;
779
780
  park(form: FormInterface, request?: ParkRequest): string;
780
781
  answer(id: string, values: FormValues): Result<FormValues, AnswerError>;
782
+ stop(ids: readonly string[]): boolean;
783
+ stop(id: string): boolean;
784
+ stop(): void;
781
785
  destroy(): void;
782
786
  }
783
787
 
@@ -929,7 +933,7 @@ export declare interface PromptClientOptions {
929
933
  * @remarks
930
934
  * - `pending` — a form was parked; a transport forwards the wire record to remote clients.
931
935
  * - `answer` — a parked form was answered and accepted, carrying its id and the settled values.
932
- * - `expire` — a parked form timed out or was torn down unanswered, carrying its id.
936
+ * - `expire` — a parked form timed out or was released unanswered, carrying its id.
933
937
  */
934
938
  export declare type PromptEventMap = {
935
939
  readonly pending: readonly [form: PendingForm];
@@ -969,6 +973,19 @@ export declare type PromptIcon = 'question' | 'pointer' | 'dot' | 'selected' | '
969
973
  * - **Timeout abandons.** An unanswered form is destroyed after `timeout` ms; `expire` fires and
970
974
  * the caller's promise rejects on the form's own lifecycle. The timer is injectable.
971
975
  * - **Accessors.** `pending()` lists the parked records; `pending(id)` looks one up.
976
+ * - **Batch stop.** The array overload is declared first: `stop(ids)` releases each listed parked
977
+ * form and reports whether all ids were parked; `stop(id)` releases one; `stop()` releases every
978
+ * parked form without destroying the broker. Release uses the existing expiry semantics.
979
+ *
980
+ * @example
981
+ * ```ts
982
+ * const prompt = createPrompt()
983
+ * const first = prompt.park(createForm({ fields: [{ control: 'text', name: 'first' }] }))
984
+ * const second = prompt.park(createForm({ fields: [{ control: 'text', name: 'second' }] }))
985
+ * prompt.stop(first) // true
986
+ * prompt.stop([second, 'missing']) // false; `second` was still released
987
+ * prompt.stop() // release every remaining form; the broker stays usable
988
+ * ```
972
989
  */
973
990
  export declare interface PromptInterface {
974
991
  readonly emitter: EmitterInterface<PromptEventMap>;
@@ -977,6 +994,9 @@ export declare interface PromptInterface {
977
994
  pending(): readonly PendingForm[];
978
995
  pending(id: string): PendingForm | undefined;
979
996
  answer(id: string, values: FormValues): Result<FormValues, AnswerError>;
997
+ stop(ids: readonly string[]): boolean;
998
+ stop(id: string): boolean;
999
+ stop(): void;
980
1000
  destroy(): void;
981
1001
  }
982
1002
 
@@ -1159,7 +1179,7 @@ export declare function selectView(state: ReturnType<typeof createSelectState>):
1159
1179
  */
1160
1180
  export declare const SEQUENCE_NAMES: Readonly<Record<string, string>>;
1161
1181
 
1162
- /** Serialize a parked prompt's expiry into a {@link WireEvent} — event `'expire'`, `data` the JSON-stringified `{ id }` payload. */
1182
+ /** Serialize a parked prompt's expiry or release into a {@link WireEvent} — event `'expire'`, `data` the JSON-stringified `{ id }` payload. */
1163
1183
  export declare function serializeExpire(id: string): WireEvent;
1164
1184
 
1165
1185
  /** Serialize a parked {@link PendingForm} into a {@link WireEvent}. */
@@ -1185,7 +1205,7 @@ export declare const SSE_BUFFER_LIMIT = 1048576;
1185
1205
  *
1186
1206
  * @remarks
1187
1207
  * - `pending` — a serialized {@link import('./types.js').PendingForm} to dispatch and answer.
1188
- * - `expire` — an `{ id }` payload: the broker expired a parked prompt (the client drops it).
1208
+ * - `expire` — an `{ id }` payload: the broker expired or released a parked prompt (the client drops it).
1189
1209
  * - `shutdown` — the broker is going away; the client disconnects (no auto-reconnect) but stays reusable.
1190
1210
  */
1191
1211
  export declare const SSE_EVENTS: Readonly<{
@@ -204,9 +204,9 @@ export declare function createPasswordState(field: PasswordField, styler?: Style
204
204
  * @returns A {@link PromptInterface}
205
205
  *
206
206
  * @remarks
207
- * The caller awaits the parked form's own `answer`. Timeout or teardown destroys the form, so that
208
- * promise rejects with the Form package's `ABANDONED` error. Inject `options.timer` to drive
209
- * expiry without real time.
207
+ * The caller awaits the parked form's own `answer`. Timeout, `stop`, or teardown destroys the form,
208
+ * so that promise rejects with the Form package's `ABANDONED` error. Inject `options.timer` to
209
+ * drive expiry without real time.
210
210
  *
211
211
  * @example
212
212
  * ```ts
@@ -747,7 +747,7 @@ export declare interface PendingForm {
747
747
  * @remarks
748
748
  * - `pending` — parked, awaiting {@link PromptInterface.answer}.
749
749
  * - `answered` — answered and accepted, so the parked form settled.
750
- * - `expired` — timed out, or torn down by `destroy`, before an answer.
750
+ * - `expired` — timed out, released by `stop`, or torn down by `destroy`, before an answer.
751
751
  */
752
752
  export declare type PendingFormStatus = 'pending' | 'answered' | 'expired';
753
753
 
@@ -758,7 +758,8 @@ export declare type PendingFormStatus = 'pending' | 'answered' | 'expired';
758
758
  * @remarks
759
759
  * A parked record carries one call to `serializeForm`. A failed fill or submit leaves the record
760
760
  * parked for another answer. A successful submit settles the form once, emits `answer`, and removes
761
- * the record. Timeout and teardown abandon every unsettled form through its own `destroy` method.
761
+ * the record. Timeout, `stop`, and teardown abandon unsettled forms through their own `destroy`
762
+ * method.
762
763
  *
763
764
  * @example
764
765
  * ```ts
@@ -778,6 +779,9 @@ export declare class Prompt implements PromptInterface {
778
779
  pending(id: string): PendingForm | undefined;
779
780
  park(form: FormInterface, request?: ParkRequest): string;
780
781
  answer(id: string, values: FormValues): Result<FormValues, AnswerError>;
782
+ stop(ids: readonly string[]): boolean;
783
+ stop(id: string): boolean;
784
+ stop(): void;
781
785
  destroy(): void;
782
786
  }
783
787
 
@@ -929,7 +933,7 @@ export declare interface PromptClientOptions {
929
933
  * @remarks
930
934
  * - `pending` — a form was parked; a transport forwards the wire record to remote clients.
931
935
  * - `answer` — a parked form was answered and accepted, carrying its id and the settled values.
932
- * - `expire` — a parked form timed out or was torn down unanswered, carrying its id.
936
+ * - `expire` — a parked form timed out or was released unanswered, carrying its id.
933
937
  */
934
938
  export declare type PromptEventMap = {
935
939
  readonly pending: readonly [form: PendingForm];
@@ -969,6 +973,19 @@ export declare type PromptIcon = 'question' | 'pointer' | 'dot' | 'selected' | '
969
973
  * - **Timeout abandons.** An unanswered form is destroyed after `timeout` ms; `expire` fires and
970
974
  * the caller's promise rejects on the form's own lifecycle. The timer is injectable.
971
975
  * - **Accessors.** `pending()` lists the parked records; `pending(id)` looks one up.
976
+ * - **Batch stop.** The array overload is declared first: `stop(ids)` releases each listed parked
977
+ * form and reports whether all ids were parked; `stop(id)` releases one; `stop()` releases every
978
+ * parked form without destroying the broker. Release uses the existing expiry semantics.
979
+ *
980
+ * @example
981
+ * ```ts
982
+ * const prompt = createPrompt()
983
+ * const first = prompt.park(createForm({ fields: [{ control: 'text', name: 'first' }] }))
984
+ * const second = prompt.park(createForm({ fields: [{ control: 'text', name: 'second' }] }))
985
+ * prompt.stop(first) // true
986
+ * prompt.stop([second, 'missing']) // false; `second` was still released
987
+ * prompt.stop() // release every remaining form; the broker stays usable
988
+ * ```
972
989
  */
973
990
  export declare interface PromptInterface {
974
991
  readonly emitter: EmitterInterface<PromptEventMap>;
@@ -977,6 +994,9 @@ export declare interface PromptInterface {
977
994
  pending(): readonly PendingForm[];
978
995
  pending(id: string): PendingForm | undefined;
979
996
  answer(id: string, values: FormValues): Result<FormValues, AnswerError>;
997
+ stop(ids: readonly string[]): boolean;
998
+ stop(id: string): boolean;
999
+ stop(): void;
980
1000
  destroy(): void;
981
1001
  }
982
1002
 
@@ -1159,7 +1179,7 @@ export declare function selectView(state: ReturnType<typeof createSelectState>):
1159
1179
  */
1160
1180
  export declare const SEQUENCE_NAMES: Readonly<Record<string, string>>;
1161
1181
 
1162
- /** Serialize a parked prompt's expiry into a {@link WireEvent} — event `'expire'`, `data` the JSON-stringified `{ id }` payload. */
1182
+ /** Serialize a parked prompt's expiry or release into a {@link WireEvent} — event `'expire'`, `data` the JSON-stringified `{ id }` payload. */
1163
1183
  export declare function serializeExpire(id: string): WireEvent;
1164
1184
 
1165
1185
  /** Serialize a parked {@link PendingForm} into a {@link WireEvent}. */
@@ -1185,7 +1205,7 @@ export declare const SSE_BUFFER_LIMIT = 1048576;
1185
1205
  *
1186
1206
  * @remarks
1187
1207
  * - `pending` — a serialized {@link import('./types.js').PendingForm} to dispatch and answer.
1188
- * - `expire` — an `{ id }` payload: the broker expired a parked prompt (the client drops it).
1208
+ * - `expire` — an `{ id }` payload: the broker expired or released a parked prompt (the client drops it).
1189
1209
  * - `shutdown` — the broker is going away; the client disconnects (no auto-reconnect) but stays reusable.
1190
1210
  */
1191
1211
  export declare const SSE_EVENTS: Readonly<{