@orkestrel/terminal 0.0.6 → 0.0.8

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.
@@ -3,6 +3,8 @@ import { EmitterErrorHandler } from '@orkestrel/emitter';
3
3
  import { EmitterHooks } from '@orkestrel/emitter';
4
4
  import { EmitterInterface } from '@orkestrel/emitter';
5
5
  import { Guard } from '@orkestrel/contract';
6
+ import { Result } from '@orkestrel/contract';
7
+ import { Style } from '@orkestrel/console';
6
8
  import { StylerInterface } from '@orkestrel/console';
7
9
  import { TableInterface } from '@orkestrel/database';
8
10
 
@@ -15,15 +17,6 @@ export declare const ALPHANUMERIC_PATTERN: RegExp;
15
17
  /** The rejection reason a bare {@link PromptInterface.answer} returns — `'unknown'` (no such parked prompt) or `'rejected'` (failed validation / type-check). */
16
18
  export declare type AnswerError = 'unknown' | 'rejected';
17
19
 
18
- /** The outcome of a bare {@link PromptInterface.answer} call — the accepted `value` on success, else the {@link AnswerError}. */
19
- export declare type AnswerResult = {
20
- readonly success: true;
21
- readonly value: unknown;
22
- } | {
23
- readonly success: false;
24
- readonly error: AnswerError;
25
- };
26
-
27
20
  /**
28
21
  * Append a rule-backed {@link Validator} to `validators` when the rule is enabled — a `false` /
29
22
  * `undefined` `check` is skipped, a function `check` is added verbatim (the custom override), and
@@ -52,14 +45,17 @@ export declare interface CheckboxChoice {
52
45
  * `choices` accepts bare strings or full {@link CheckboxChoice} objects (with an optional
53
46
  * initial `checked`); {@link import('./helpers.js').createCheckboxState} normalizes them.
54
47
  * `min` / `max` gate submission — a submit with fewer than `min` or more than `max` selected
55
- * is rejected (the prompt stays active with the reason in the view).
48
+ * is rejected (the prompt stays active with the reason in the view). `hint` adds a key hint after
49
+ * the message (no computed default) and reaches the server driver's numbered fallback too.
56
50
  */
57
51
  export declare interface CheckboxOptions {
58
52
  readonly message: string;
59
- readonly choices: readonly (string | CheckboxChoice)[];
53
+ readonly choices: ReadonlyArray<string | CheckboxChoice>;
60
54
  readonly min?: number;
61
55
  readonly max?: number;
56
+ readonly hint?: string;
62
57
  readonly styler?: StylerInterface;
58
+ readonly theme?: PromptThemeOptions;
63
59
  }
64
60
 
65
61
  /**
@@ -72,8 +68,9 @@ export declare interface CheckboxOptions {
72
68
  export declare function checkboxReduce(state: CheckboxState, key: KeyEvent): PromptStep<readonly string[], CheckboxState>;
73
69
 
74
70
  /**
75
- * The immutable state of a checkbox prompt — the normalized choices, the styler, the `focused`
76
- * index, the set of `checked` indices, the optional `min` / `max` gate, and the current `error`.
71
+ * The immutable state of a checkbox prompt — the normalized choices, the optional hint, the
72
+ * resolved styler + theme, the `focused` index, the set of `checked` indices, the optional
73
+ * `min` / `max` gate, and the current `error`.
77
74
  *
78
75
  * @remarks
79
76
  * Built by {@link import('./helpers.js').createCheckboxState}; advanced by
@@ -85,7 +82,9 @@ export declare function checkboxReduce(state: CheckboxState, key: KeyEvent): Pro
85
82
  export declare interface CheckboxState {
86
83
  readonly message: string;
87
84
  readonly choices: readonly CheckboxChoice[];
85
+ readonly hint?: string;
88
86
  readonly styler: StylerInterface;
87
+ readonly theme: PromptTheme;
89
88
  readonly focused: number;
90
89
  readonly checked: readonly number[];
91
90
  readonly min?: number;
@@ -93,7 +92,7 @@ export declare interface CheckboxState {
93
92
  readonly error?: string;
94
93
  }
95
94
 
96
- /** Render a {@link CheckboxState} as a MULTI-LINE styled view — the header, one box per choice (focused + checked marked), a count, and any error. */
95
+ /** Render a {@link CheckboxState} as a MULTI-LINE styled view — the header (plus any hint), one box per choice (focused + checked marked), a count, and any error. */
97
96
  export declare function checkboxView(state: CheckboxState): string;
98
97
 
99
98
  /**
@@ -103,11 +102,20 @@ export declare function checkboxView(state: CheckboxState): string;
103
102
  */
104
103
  export declare function composeValidators(...validators: Validator[]): Validator;
105
104
 
106
- /** Options for a yes/no {@link import('./helpers.js').confirmReduce} confirmation prompt. */
105
+ /**
106
+ * Options for a yes/no {@link import('./helpers.js').confirmReduce} confirmation prompt.
107
+ *
108
+ * @remarks
109
+ * `hint` replaces the computed `(Y/n)` group in full, parentheses included, and is painted with
110
+ * the theme's `hint` role. The accepted KEYS stay `y` / `n` / `enter` whatever the hint says, so a
111
+ * hint that advertises other keys is the consumer's own contradiction.
112
+ */
107
113
  export declare interface ConfirmOptions {
108
114
  readonly message: string;
109
115
  readonly default?: boolean;
116
+ readonly hint?: string;
110
117
  readonly styler?: StylerInterface;
118
+ readonly theme?: PromptThemeOptions;
111
119
  }
112
120
 
113
121
  /**
@@ -118,21 +126,28 @@ export declare interface ConfirmOptions {
118
126
  export declare function confirmReduce(state: ConfirmState, key: KeyEvent): PromptStep<boolean, ConfirmState>;
119
127
 
120
128
  /**
121
- * The immutable state of a confirm prompt — its message, the default answer, and the styler.
129
+ * The immutable state of a confirm prompt — its message, the default answer, the optional hint
130
+ * override, and the resolved styler + theme.
122
131
  *
123
132
  * @remarks
124
133
  * Built by {@link import('./helpers.js').createConfirmState}; advanced by
125
134
  * {@link import('./helpers.js').confirmReduce}. `y` / `Y` submits `true`, `n` / `N` submits
126
- * `false`, and `enter` takes the `default` (rendered with the active letter capitalized in the
127
- * `(Y/n)` hint).
135
+ * `false`, and `enter` takes the `default` (rendered with the active letter emphasized in the
136
+ * `(Y/n)` hint, unless `hint` replaces that group).
128
137
  */
129
138
  export declare interface ConfirmState {
130
139
  readonly message: string;
131
140
  readonly default: boolean;
141
+ readonly hint?: string;
132
142
  readonly styler: StylerInterface;
143
+ readonly theme: PromptTheme;
133
144
  }
134
145
 
135
- /** Render a {@link ConfirmState} as a styled view — the header plus a `(Y/n)` hint with the default letter emphasized. */
146
+ /**
147
+ * Render a {@link ConfirmState} as a styled view — the header plus the `(Y/n)` group with the
148
+ * default letter painted by the `selected` role. A supplied `hint` replaces that whole group,
149
+ * parentheses included, painted by the `hint` role.
150
+ */
136
151
  export declare function confirmView(state: ConfirmState): string;
137
152
 
138
153
  /**
@@ -151,10 +166,10 @@ export declare const CONTROL_NAMES: Readonly<Record<string, {
151
166
  readonly ctrl: boolean;
152
167
  }>>;
153
168
 
154
- /** Build the initial {@link CheckboxState} from {@link CheckboxOptions} — normalizing choices, seeding the checked set, carrying min/max. */
169
+ /** Build the initial {@link CheckboxState} from {@link CheckboxOptions} — normalizing choices, resolving the styler + theme, carrying any hint, seeding the checked set, carrying min/max. */
155
170
  export declare function createCheckboxState(options: CheckboxOptions): CheckboxState;
156
171
 
157
- /** Build the initial {@link ConfirmState} from {@link ConfirmOptions} — defaulting the answer to `false`. */
172
+ /** Build the initial {@link ConfirmState} from {@link ConfirmOptions} — defaulting the answer to `false`, resolving the styler + theme, carrying any hint override. */
158
173
  export declare function createConfirmState(options: ConfirmOptions): ConfirmState;
159
174
 
160
175
  /**
@@ -174,10 +189,10 @@ export declare function createConfirmState(options: ConfirmOptions): ConfirmStat
174
189
  */
175
190
  export declare function createDatabaseTerminalStore(driver?: DriverInterface): TerminalStoreInterface;
176
191
 
177
- /** Build the initial {@link EditorState} from {@link EditorOptions} — resolving the validator + styler, seeding empty lines. */
192
+ /** Build the initial {@link EditorState} from {@link EditorOptions} — resolving the validator + styler + theme, carrying any hint override, seeding empty lines. */
178
193
  export declare function createEditorState(options: EditorOptions): EditorState;
179
194
 
180
- /** Build the initial {@link InputState} from {@link InputOptions} — resolving the validator + styler, seeding an empty value. */
195
+ /** Build the initial {@link InputState} from {@link InputOptions} — resolving the validator + styler + theme, seeding an empty value. */
181
196
  export declare function createInputState(options: InputOptions): InputState;
182
197
 
183
198
  /**
@@ -195,7 +210,7 @@ export declare function createInputState(options: InputOptions): InputState;
195
210
  */
196
211
  export declare function createMemoryTerminalStore(): TerminalStoreInterface;
197
212
 
198
- /** Build the initial {@link PasswordState} from {@link PasswordOptions} — resolving the validator + styler + mask. */
213
+ /** Build the initial {@link PasswordState} from {@link PasswordOptions} — resolving the validator + styler + theme + mask. */
199
214
  export declare function createPasswordState(options: PasswordOptions): PasswordState;
200
215
 
201
216
  /**
@@ -253,7 +268,29 @@ export declare function createPrompt(options?: PromptOptions): PromptInterface;
253
268
  */
254
269
  export declare function createPromptClient(options: PromptClientOptions): PromptClientInterface;
255
270
 
256
- /** Build the initial {@link SelectState} from {@link SelectOptions} — normalizing choices and pre-focusing the default. */
271
+ /**
272
+ * Build a complete {@link PromptTheme} by merging a partial one over
273
+ * {@link DEFAULT_PROMPT_THEME}, leaf by leaf — each supplied icon replaces that glyph, each
274
+ * supplied role replaces that {@link Style}, and everything else keeps its default. Each supplied
275
+ * style is snapshotted through the console module's own
276
+ * {@link import('@orkestrel/console').freezeStyle}, so the result is deeply frozen and a caller
277
+ * mutating its own attribute list afterwards cannot reach into a built theme.
278
+ *
279
+ * @param options - The partial theme to merge, or `undefined` for the defaults
280
+ * @returns The resolved, deeply frozen theme every prompt state carries
281
+ *
282
+ * @example
283
+ * ```ts
284
+ * createPromptTheme() // the defaults
285
+ * createPromptTheme({
286
+ * icons: { pointer: '=>' },
287
+ * roles: { message: { foreground: 'magenta', attributes: ['bold'] } },
288
+ * })
289
+ * ```
290
+ */
291
+ export declare function createPromptTheme(options?: PromptThemeOptions): PromptTheme;
292
+
293
+ /** Build the initial {@link SelectState} from {@link SelectOptions} — normalizing choices, resolving the styler + theme, carrying any hint, and pre-focusing the default. */
257
294
  export declare function createSelectState(options: SelectOptions): SelectState;
258
295
 
259
296
  /**
@@ -351,6 +388,23 @@ export declare class DatabaseTerminalStore implements TerminalStoreInterface {
351
388
  /** The default mask glyph a {@link import('./types.js').PasswordState} renders each input character as — `*`. */
352
389
  export declare const DEFAULT_MASK = "*";
353
390
 
391
+ /**
392
+ * The {@link import('./types.js').PromptTheme} every prompt renders with unless its options supply
393
+ * another — the glyph set assembled from {@link PROMPT_ICONS} plus the console
394
+ * {@link import('@orkestrel/console').STATUS_ICONS} `success` / `error` marks, and the console
395
+ * {@link import('@orkestrel/console').Style} each role is painted with. Deeply frozen through the
396
+ * console module's own {@link import('@orkestrel/console').freezeStyle}; the baseline
397
+ * {@link import('./helpers.js').createPromptTheme} merges a partial theme over.
398
+ *
399
+ * @remarks
400
+ * The default roles reproduce the views' historical coloring exactly: `question` / `pointer` cyan,
401
+ * `message` / `focus` bold, `success` / `selected` green, `error` red, `hint` / `muted` /
402
+ * `description` dim, and `content` the EMPTY style — an empty style renders bare text, so primary
403
+ * content keeps the bytes it had before it became themeable.
404
+ * Two roles sharing a style today are still two roles — re-mapping one leaves the other alone.
405
+ */
406
+ export declare const DEFAULT_PROMPT_THEME: PromptTheme;
407
+
354
408
  /** How long (ms) the {@link import('./types.js').PromptInterface} broker parks an unanswered prompt before it expires — 5 minutes. */
355
409
  export declare const DEFAULT_PROMPT_TIMEOUT_MS = 300000;
356
410
 
@@ -376,6 +430,13 @@ export declare const DELETE: string;
376
430
  * §14-narrowed, never an `as`; the validator rebuilt from rules via {@link reconstructValidationRules}),
377
431
  * then calls the matching prompt form and returns its resolved value.
378
432
  *
433
+ * @remarks
434
+ * `theme` and `hint` are plain data, so they cross the wire with the rest of the options bag and
435
+ * are reconstructed here for every form that accepts them: the theme is narrowed by
436
+ * {@link import('./validators.js').isPromptThemeOptions} (an off-shape theme is dropped, leaving
437
+ * the defaults), then every glyph and hint is passed through {@link sanitizeDisplayText}. Choice
438
+ * labels use the stream-safe {@link sanitizeChoiceLabels} treatment instead.
439
+ *
379
440
  * @param terminal - The local {@link PromptFormInterface} to drive
380
441
  * @param pending - The decoded pending prompt to dispatch
381
442
  * @returns The prompt's resolved value (a `string` / `boolean` / `readonly string[]` per form)
@@ -390,12 +451,21 @@ export declare function dispatchPendingPrompt(terminal: PromptFormInterface, pen
390
451
  */
391
452
  export declare function editLine(value: string, key: KeyEvent): string | undefined;
392
453
 
393
- /** Options for a multi-line {@link import('./helpers.js').editorReduce} editor prompt (terminated by ctrl-d). */
454
+ /**
455
+ * Options for a multi-line {@link import('./helpers.js').editorReduce} editor prompt (terminated
456
+ * by ctrl-d).
457
+ *
458
+ * @remarks
459
+ * `hint` replaces the computed `(Ctrl+D to finish)` group in full, parentheses included. The
460
+ * finish KEY stays ctrl-d whatever the hint says.
461
+ */
394
462
  export declare interface EditorOptions {
395
463
  readonly message: string;
396
464
  readonly default?: string;
465
+ readonly hint?: string;
397
466
  readonly validate?: Validator | ValidationRules;
398
467
  readonly styler?: StylerInterface;
468
+ readonly theme?: PromptThemeOptions;
399
469
  }
400
470
 
401
471
  /**
@@ -409,7 +479,8 @@ export declare function editorReduce(state: EditorState, key: KeyEvent): PromptS
409
479
 
410
480
  /**
411
481
  * The immutable state of an editor prompt — the committed `lines`, the in-progress `current`
412
- * line, plus the resolved validator + styler, the default, and the current `error`.
482
+ * line, plus the resolved validator + styler + theme, the default, the optional hint override,
483
+ * and the current `error`.
413
484
  *
414
485
  * @remarks
415
486
  * Built by {@link import('./helpers.js').createEditorState}; advanced by
@@ -421,21 +492,24 @@ export declare function editorReduce(state: EditorState, key: KeyEvent): PromptS
421
492
  export declare interface EditorState {
422
493
  readonly message: string;
423
494
  readonly default: string;
495
+ readonly hint?: string;
424
496
  readonly validator: Validator;
425
497
  readonly styler: StylerInterface;
498
+ readonly theme: PromptTheme;
426
499
  readonly lines: readonly string[];
427
500
  readonly current: string;
428
501
  readonly error?: string;
429
502
  }
430
503
 
431
- /** Render an {@link EditorState} as a MULTI-LINE styled view — the header (with a Ctrl+D hint), the committed lines, the in-progress line, and any error. */
504
+ /**
505
+ * Render an {@link EditorState} as a MULTI-LINE styled view — the header with its finish hint, the
506
+ * committed and in-progress lines painted by the `content` role, and any error. A supplied `hint`
507
+ * replaces `(Ctrl+D to finish)` in full; the finish key stays ctrl-d.
508
+ */
432
509
  export declare function editorView(state: EditorState): string;
433
510
 
434
- /** Matches an email address — a non-trivial `local@domain.tld` shape. The `email` rule tests against this. */
435
- export declare const EMAIL_PATTERN: RegExp;
436
-
437
- /** The styled error line (`✖ message`) — appended beneath a prompt view when the last submit failed validation. */
438
- export declare function errorLine(styler: StylerInterface, message: string): string;
511
+ /** The styled error line (`✖ message`) — appended beneath a prompt view when the last submit failed validation, themed by the `error` role. */
512
+ export declare function errorLine(styler: StylerInterface, theme: PromptTheme, message: string): string;
439
513
 
440
514
  /** Escape (ESC, U+001B) — the lone byte, and the lead byte of every CSI / SS3 sequence. */
441
515
  export declare const ESCAPE: string;
@@ -486,12 +560,25 @@ export declare function globalFetch(input: string, init?: FetchInit): Promise<Re
486
560
  /** The auth-token request header the {@link import('./types.js').PromptClient} sends when a `token` is configured. */
487
561
  export declare const HEADER_TOKEN = "x-orkestrel-token";
488
562
 
563
+ /**
564
+ * Render a prompt header followed by a key hint painted with the `hint` role, or the header alone
565
+ * when no hint is supplied.
566
+ *
567
+ * @param styler - The console styler that renders each role
568
+ * @param theme - The resolved prompt theme
569
+ * @param message - The prompt's question text
570
+ * @param hint - The optional key hint to append
571
+ * @returns The rendered header with the optional hint
572
+ */
573
+ export declare function hintedHeader(styler: StylerInterface, theme: PromptTheme, message: string, hint?: string): string;
574
+
489
575
  /** Options for a single-line text {@link import('./helpers.js').inputReduce} prompt. */
490
576
  export declare interface InputOptions {
491
577
  readonly message: string;
492
578
  readonly default?: string;
493
579
  readonly validate?: Validator | ValidationRules;
494
580
  readonly styler?: StylerInterface;
581
+ readonly theme?: PromptThemeOptions;
495
582
  }
496
583
 
497
584
  /**
@@ -503,8 +590,8 @@ export declare interface InputOptions {
503
590
  export declare function inputReduce(state: InputState, key: KeyEvent): PromptStep<string, InputState>;
504
591
 
505
592
  /**
506
- * The immutable state of a text input prompt — its options, the resolved validator + styler,
507
- * the accumulated `value`, and the current `error` (when the last submit failed validation).
593
+ * The immutable state of a text input prompt — its options, the resolved validator + styler +
594
+ * theme, the accumulated `value`, and the current `error` (when the last submit failed validation).
508
595
  *
509
596
  * @remarks
510
597
  * Built by {@link import('./helpers.js').createInputState}; advanced by
@@ -517,11 +604,12 @@ export declare interface InputState {
517
604
  readonly default: string;
518
605
  readonly validator: Validator;
519
606
  readonly styler: StylerInterface;
607
+ readonly theme: PromptTheme;
520
608
  readonly value: string;
521
609
  readonly error?: string;
522
610
  }
523
611
 
524
- /** Render an {@link InputState} as a styled view — the header, the typed value (or dimmed default hint), and any error. */
612
+ /** Render an {@link InputState} as a styled view — the header, the typed value painted by the `content` role (or the default painted as a hint), and any error. */
525
613
  export declare function inputView(state: InputState): string;
526
614
 
527
615
  /** Matches an integer (optional sign). The `integer` rule tests against this. */
@@ -581,9 +669,40 @@ export declare function isPrintable(character: string): boolean;
581
669
  /** Narrow an unknown value to a {@link PromptChoice} — the `recordOf` shape inlined so no non-exported member lingers (§5). */
582
670
  export declare function isPromptChoice(value: unknown): value is PromptChoice;
583
671
 
672
+ /**
673
+ * Narrow an unknown wire value to a {@link PromptThemeOptions} — the §14 guard a remote prompt's
674
+ * `theme` option passes before it reaches a local prompt.
675
+ *
676
+ * @remarks
677
+ * The shape is CLOSED at every level: an unknown icon slot, an unknown role, a non-string glyph, or
678
+ * a role whose value is not a {@link isStyle}-shaped console style rejects the whole theme, so a
679
+ * hostile payload degrades to the default theme rather than partially applying. Glyphs still carry
680
+ * arbitrary text at this point — {@link import('./helpers.js').sanitizeThemeIcons} strips their
681
+ * control bytes on dispatch.
682
+ *
683
+ * The icons and roles shapes are checked against their complete union-keyed guard records. A slot
684
+ * added to either union without an entry here is a compile error rather than a wire theme that is
685
+ * silently refused.
686
+ */
687
+ export declare const isPromptThemeOptions: Guard<PromptThemeOptions>;
688
+
584
689
  /** Narrow an unknown value to a {@link PromptType} — one of the six prompt forms. */
585
690
  export declare const isPromptType: Guard<PromptType>;
586
691
 
692
+ /**
693
+ * Narrow an unknown value to a console {@link Style} — the value every
694
+ * {@link import('./types.js').PromptRole} carries, built from the console module's own
695
+ * {@link import('@orkestrel/console').COLORS} + {@link import('@orkestrel/console').ATTRIBUTES} so
696
+ * the style vocabulary has ONE source.
697
+ *
698
+ * @remarks
699
+ * The record is CLOSED and matches the `Style` contract exactly: `foreground` and `background` are
700
+ * optional and each must name a color (`default` included, as the console `Color` union has it),
701
+ * `attributes` is REQUIRED and must be an array over the attribute set, and any other key rejects
702
+ * the whole value.
703
+ */
704
+ export declare const isStyle: Guard<Style>;
705
+
587
706
  /**
588
707
  * Narrow an unknown caught value to a {@link TerminalError}.
589
708
  *
@@ -758,13 +877,6 @@ export declare interface ParkRequest {
758
877
  */
759
878
  export declare function parseKey(input: string | Uint8Array): KeyEvent;
760
879
 
761
- /**
762
- * Parse a JSON wire string TOTAL — a malformed / empty payload yields `undefined` (the caller's
763
- * guard then rejects it), never a throw. The {@link import('./PromptClient.js').PromptClient}
764
- * decodes every SSE `data` field through this before §14-narrowing it.
765
- */
766
- export declare function parseWireJSON(text: string): unknown;
767
-
768
880
  /** The always-passing {@link Validator} — the resolved validator when no rules were supplied. */
769
881
  export declare function passing(_input: string): true;
770
882
 
@@ -774,6 +886,7 @@ export declare interface PasswordOptions {
774
886
  readonly mask?: string;
775
887
  readonly validate?: Validator | ValidationRules;
776
888
  readonly styler?: StylerInterface;
889
+ readonly theme?: PromptThemeOptions;
777
890
  }
778
891
 
779
892
  /**
@@ -798,11 +911,12 @@ export declare interface PasswordState {
798
911
  readonly mask: string;
799
912
  readonly validator: Validator;
800
913
  readonly styler: StylerInterface;
914
+ readonly theme: PromptTheme;
801
915
  readonly value: string;
802
916
  readonly error?: string;
803
917
  }
804
918
 
805
- /** Render a {@link PasswordState} as a styled view — the header, the value masked to `mask` repeated, and any error. */
919
+ /** Render a {@link PasswordState} as a styled view — the header, the value masked to `mask` repeated and painted by the `content` role, and any error. */
806
920
  export declare function passwordView(state: PasswordState): string;
807
921
 
808
922
  /**
@@ -816,7 +930,7 @@ export declare function passwordView(state: PasswordState): string;
816
930
  * dispatches on (named for its axis — the prompt form — never `kind` / `type`).
817
931
  * - `message` — the prompt's question (lifted out of `options` for direct display).
818
932
  * - `options` — the WIRE-SAFE options (a `validate` FUNCTION dropped; the declarative
819
- * {@link ValidationRules} data + `choices` / `default` / `mask` kept — see
933
+ * {@link ValidationRules} data + `choices` / `default` / `mask` / `hint` / `theme` kept — see
820
934
  * {@link import('./helpers.js').serializePromptOptions}). A client reconstructs the validator
821
935
  * from the rules via {@link resolveValidation}.
822
936
  * - `status` — the current {@link PendingPromptStatus}.
@@ -862,9 +976,9 @@ export declare type PendingPromptStatus = 'pending' | 'answered' | 'expired';
862
976
  * ({@link serializePromptOptions}) so a transport can forward them as-is.
863
977
  * - **Answer validates + type-checks.** {@link answer} runs the prompt's per-form gate: it
864
978
  * type-checks `value` to the form (string / boolean / string[]) AND, for the text forms, runs
865
- * the validator resolved from the original `validate` rules. A rejected answer returns `false`
866
- * and the prompt stays `pending`; an accepted answer resolves the Promise, emits `answer`, and
867
- * removes the prompt.
979
+ * the validator resolved from the original `validate` rules. A rejected answer returns a failure
980
+ * `Result` with error `'rejected'` and the prompt stays `pending`; an accepted answer resolves the
981
+ * Promise, emits `answer`, and removes the prompt.
868
982
  * - **Timeout → expire → reject.** An unanswered prompt expires after `timeout` ms (via the
869
983
  * INJECTED timer): `expire` fires and the parked Promise rejects with a {@link TerminalError}
870
984
  * (`code: 'EXPIRE'`). {@link destroy} expires every still-pending prompt the same way.
@@ -888,7 +1002,7 @@ export declare class Prompt implements PromptInterface {
888
1002
  get count(): number;
889
1003
  pending(): readonly PendingPrompt[];
890
1004
  pending(id: string): PendingPrompt | undefined;
891
- answer(id: string, value: unknown): AnswerResult;
1005
+ answer(id: string, value: unknown): Result<unknown, AnswerError>;
892
1006
  park(request: ParkRequest): Ticket;
893
1007
  input(options: InputOptions): Promise<string>;
894
1008
  password(options: PasswordOptions): Promise<string>;
@@ -900,11 +1014,8 @@ export declare class Prompt implements PromptInterface {
900
1014
  }
901
1015
 
902
1016
  /**
903
- * The prompt-view icon glyphs the reducers render the prompt line and choice rows with. PLAIN
904
- * glyphs — color is applied by the {@link import('./types.js').PromptState}'s
905
- * {@link import('@orkestrel/console').StylerInterface} at render time, never baked into the
906
- * constant (AGENTS — styling orthogonal to data; the rework fixes the terminal's ANSI-in-the-icon).
907
- * Frozen.
1017
+ * The six default glyphs {@link DEFAULT_PROMPT_THEME} assembles its `icons` from. Read only when
1018
+ * the default theme is assembled; a view reads its resolved theme and never this constant. Frozen.
908
1019
  *
909
1020
  * @remarks
910
1021
  * - `question` — the leading mark on a prompt's message line.
@@ -921,6 +1032,13 @@ export declare const PROMPT_ICONS: Readonly<{
921
1032
  unchecked: "☐";
922
1033
  }>;
923
1034
 
1035
+ /**
1036
+ * Every {@link import('./types.js').PromptRole}, in one frozen list — the role axis's source of
1037
+ * truth. {@link import('./helpers.js').createPromptTheme} walks it to merge a partial theme, and
1038
+ * a consumer building a complete role map reads it rather than retyping every name.
1039
+ */
1040
+ export declare const PROMPT_ROLES: readonly PromptRole[];
1041
+
924
1042
  /** A choice item in a {@link SelectOptions} prompt — its displayed `name`, its resolved `value`, and an optional one-line `description`. */
925
1043
  export declare interface PromptChoice {
926
1044
  readonly name: string;
@@ -1094,8 +1212,21 @@ export declare interface PromptFormInterface {
1094
1212
  */
1095
1213
  export declare type PromptFormOptions = InputOptions | PasswordOptions | ConfirmOptions | SelectOptions | CheckboxOptions | EditorOptions;
1096
1214
 
1097
- /** The styled prompt-message header (`? message`) — the leading line every active prompt view shares. */
1098
- export declare function promptHeader(styler: StylerInterface, message: string): string;
1215
+ /** The styled prompt-message header (`? message`) — the leading line every active prompt view shares, themed by the `question` + `message` roles. */
1216
+ export declare function promptHeader(styler: StylerInterface, theme: PromptTheme, message: string): string;
1217
+
1218
+ /**
1219
+ * One glyph slot a prompt view renders — the icon axis of a {@link PromptTheme}. A named value
1220
+ * set (which marks a view can draw), not a toggle, so it stays a union.
1221
+ *
1222
+ * @remarks
1223
+ * - `question` — the leading mark on a prompt's message line.
1224
+ * - `pointer` — the cursor before the input / the focused choice row.
1225
+ * - `dot` / `selected` — an unfocused / focused row marker in a select list.
1226
+ * - `checked` / `unchecked` — a checked / unchecked box in a checkbox list.
1227
+ * - `success` / `error` — the mark on a resolved prompt's submit line / its validation error line.
1228
+ */
1229
+ export declare type PromptIcon = 'question' | 'pointer' | 'dot' | 'selected' | 'checked' | 'unchecked' | 'success' | 'error';
1099
1230
 
1100
1231
  /**
1101
1232
  * The headless prompt BROKER (observable §13) — implements {@link PromptFormInterface} by
@@ -1110,7 +1241,7 @@ export declare function promptHeader(styler: StylerInterface, message: string):
1110
1241
  * general entry point the six form methods wrap.
1111
1242
  * - **Answer validates.** {@link answer} validates `value` against the prompt's resolved
1112
1243
  * validator AND type-checks it to the prompt form before accepting; a bad answer is rejected
1113
- * (an {@link AnswerResult} failure, the prompt stays `pending`).
1244
+ * (a {@link Result}<unknown, {@link AnswerError}> failure, the prompt stays `pending`).
1114
1245
  * - **Timeout → expire → reject.** An unanswered prompt expires after `timeout` ms — `expire`
1115
1246
  * fires and the parked Promise rejects (a {@link import('./errors.js').TerminalError}). The
1116
1247
  * timer is injectable for deterministic tests.
@@ -1122,7 +1253,7 @@ export declare interface PromptInterface extends PromptFormInterface {
1122
1253
  park(request: ParkRequest): Ticket;
1123
1254
  pending(): readonly PendingPrompt[];
1124
1255
  pending(id: string): PendingPrompt | undefined;
1125
- answer(id: string, value: unknown): AnswerResult;
1256
+ answer(id: string, value: unknown): Result<unknown, AnswerError>;
1126
1257
  destroy(): void;
1127
1258
  }
1128
1259
 
@@ -1149,6 +1280,27 @@ export declare interface PromptOptions {
1149
1280
  readonly cap?: number;
1150
1281
  }
1151
1282
 
1283
+ /**
1284
+ * One styling slot a prompt view renders through — the SEMANTIC axis of a {@link PromptTheme}.
1285
+ * A role says what a fragment MEANS; the theme decides what that meaning looks like, so a
1286
+ * consumer re-maps the styled fragments by naming roles rather than reimplementing a view.
1287
+ *
1288
+ * @remarks
1289
+ * - `question` — the leading question mark on an active prompt's line.
1290
+ * - `pointer` — the cursor before the input / the focused choice row.
1291
+ * - `message` — the prompt's own question text.
1292
+ * - `content` — the prompt's primary content: the typed value, the mask run, an unfocused choice
1293
+ * label, a committed editor line, an in-progress editor line, or a fallback choice name. Its
1294
+ * default is the EMPTY style, so an unthemed prompt renders this content as bare text.
1295
+ * - `success` / `error` — a resolved prompt's mark / a validation-error mark and its message.
1296
+ * - `selected` — a chosen value: the checked box, the focused select marker, the confirm default letter.
1297
+ * - `focus` — the label of the row the cursor is on.
1298
+ * - `hint` — dim supplementary text: a default value, a key hint, a selection count, a committed answer.
1299
+ * - `muted` — a dim off-state mark: an unfocused select marker, an unchecked box, a fallback index.
1300
+ * - `description` — a choice's one-line description.
1301
+ */
1302
+ export declare type PromptRole = 'question' | 'pointer' | 'message' | 'content' | 'success' | 'error' | 'selected' | 'focus' | 'hint' | 'muted' | 'description';
1303
+
1152
1304
  /**
1153
1305
  * The discriminant of a {@link PromptStep} — where the prompt stands after a key. `active`:
1154
1306
  * keep prompting (the input was consumed, or rejected by validation). `submit`: the prompt
@@ -1185,6 +1337,35 @@ export declare interface PromptStep<T, S> {
1185
1337
  readonly value?: T;
1186
1338
  }
1187
1339
 
1340
+ /**
1341
+ * A prompt's resolved PRESENTATION — the glyph for every {@link PromptIcon} and the console
1342
+ * {@link Style} for every {@link PromptRole}. Plain JSON data (no functions), so it crosses the wire
1343
+ * with the prompt it decorates. Built by {@link import('./helpers.js').createPromptTheme}; carried
1344
+ * resolved on every prompt state, so a view never reads a hardcoded glyph or color.
1345
+ *
1346
+ * @remarks
1347
+ * A role's value is the console module's own {@link Style} — the one style model the whole console
1348
+ * / terminal system shares — so a view paints a role through
1349
+ * {@link StylerInterface.render} and this package holds no second style vocabulary. A `Style`
1350
+ * carries a `foreground`, a `background`, and an attribute list, so a role can express a background
1351
+ * color, which the styler's accessor chain cannot name.
1352
+ */
1353
+ export declare interface PromptTheme {
1354
+ readonly icons: Readonly<Record<PromptIcon, string>>;
1355
+ readonly roles: Readonly<Record<PromptRole, Style>>;
1356
+ }
1357
+
1358
+ /**
1359
+ * The PARTIAL {@link PromptTheme} a prompt option bag carries — every icon and every role is
1360
+ * optional, and {@link import('./helpers.js').createPromptTheme} merges what is supplied over
1361
+ * {@link import('./constants.js').DEFAULT_PROMPT_THEME} leaf by leaf. Supplying one icon or one
1362
+ * role leaves every other slot at its default.
1363
+ */
1364
+ export declare interface PromptThemeOptions {
1365
+ readonly icons?: Readonly<Partial<Record<PromptIcon, string>>>;
1366
+ readonly roles?: Readonly<Partial<Record<PromptRole, Style>>>;
1367
+ }
1368
+
1188
1369
  /**
1189
1370
  * The six prompt KINDS this core provides — the value family a higher-level broker (T-b)
1190
1371
  * dispatches on. Names the prompt axis; a named value set (not a toggle), so it stays a union.
@@ -1207,7 +1388,7 @@ export declare type PromptValue = string | boolean | readonly string[];
1207
1388
  export declare function reconstructValidationRules(value: unknown): ValidationRules | undefined;
1208
1389
 
1209
1390
  /** Read a `choices` option as a list of bare strings / full choices — each element narrowed by `guard`, off-shape elements stringified. */
1210
- export declare function resolveChoices<TChoice extends PromptChoice | CheckboxChoice>(options: Readonly<Record<string, unknown>>, guard: Guard<TChoice>): readonly (string | TChoice)[];
1391
+ export declare function resolveChoices<TChoice extends PromptChoice | CheckboxChoice>(options: Readonly<Record<string, unknown>>, guard: Guard<TChoice>): ReadonlyArray<string | TChoice>;
1211
1392
 
1212
1393
  /** Read one option by key, narrowed by `guard` — `undefined` when absent or off-shape (§14, never an `as`). */
1213
1394
  export declare function resolveOption<T>(options: Readonly<Record<string, unknown>>, key: string, guard: Guard<T>): T | undefined;
@@ -1269,7 +1450,31 @@ export declare const RULE_MESSAGES: Readonly<{
1269
1450
  * {@link CheckboxChoice} objects) as returned by {@link resolveChoices}
1270
1451
  * @returns The same choices with every `name` / `description` control-stripped
1271
1452
  */
1272
- export declare function sanitizeChoiceLabels<TChoice extends PromptChoice | CheckboxChoice>(choices: readonly (string | TChoice)[]): readonly (string | TChoice)[];
1453
+ export declare function sanitizeChoiceLabels<TChoice extends PromptChoice | CheckboxChoice>(choices: ReadonlyArray<string | TChoice>): ReadonlyArray<string | TChoice>;
1454
+
1455
+ /**
1456
+ * Sanitize text for one single-line display slot. Composes console's {@link stripControls} pass
1457
+ * with removal of tab, line feed, and carriage return, so no C0 control or DEL survives.
1458
+ *
1459
+ * @param text - The text to sanitize for a glyph or hint slot
1460
+ * @returns The text with every C0 control character and DEL removed
1461
+ *
1462
+ * @example
1463
+ * ```ts
1464
+ * sanitizeDisplayText('Q\rOVERWRITE\nNEXT\tX') // 'QOVERWRITENEXTX'
1465
+ * ```
1466
+ */
1467
+ export declare function sanitizeDisplayText(text: string): string;
1468
+
1469
+ /**
1470
+ * Sanitize every glyph a wire-supplied {@link PromptThemeOptions} carries for a single-line display
1471
+ * slot. Only the icons need it: a role is guard-narrowed to a console {@link Style}, whose colors
1472
+ * and attributes are fixed name sets, so no role can carry a byte a terminal would act on.
1473
+ *
1474
+ * @param theme - The narrowed theme options a remote prompt supplied
1475
+ * @returns The same theme with every supplied glyph sanitized for a single-line display slot
1476
+ */
1477
+ export declare function sanitizeThemeIcons(theme: PromptThemeOptions): PromptThemeOptions;
1273
1478
 
1274
1479
  /**
1275
1480
  * Options for a single-selection {@link import('./helpers.js').selectReduce} prompt.
@@ -1277,13 +1482,17 @@ export declare function sanitizeChoiceLabels<TChoice extends PromptChoice | Chec
1277
1482
  * @remarks
1278
1483
  * `choices` accepts bare strings (used as both `name` and `value`) or full {@link PromptChoice}
1279
1484
  * objects; {@link import('./helpers.js').createSelectState} normalizes them. `default` pre-focuses
1280
- * the choice whose `value` matches it.
1485
+ * the choice whose `value` matches it. `hint` adds a key hint after the message — the list is
1486
+ * self-explanatory at a TTY, so there is no computed default; the server driver shows it on the
1487
+ * numbered fallback too.
1281
1488
  */
1282
1489
  export declare interface SelectOptions {
1283
1490
  readonly message: string;
1284
- readonly choices: readonly (string | PromptChoice)[];
1491
+ readonly choices: ReadonlyArray<string | PromptChoice>;
1285
1492
  readonly default?: string;
1493
+ readonly hint?: string;
1286
1494
  readonly styler?: StylerInterface;
1495
+ readonly theme?: PromptThemeOptions;
1287
1496
  }
1288
1497
 
1289
1498
  /**
@@ -1295,8 +1504,8 @@ export declare interface SelectOptions {
1295
1504
  export declare function selectReduce(state: SelectState, key: KeyEvent): PromptStep<string, SelectState>;
1296
1505
 
1297
1506
  /**
1298
- * The immutable state of a select prompt — the normalized choices, the styler, and the
1299
- * `focused` index (the highlighted row).
1507
+ * The immutable state of a select prompt — the normalized choices, the optional hint, the
1508
+ * resolved styler + theme, and the `focused` index (the highlighted row).
1300
1509
  *
1301
1510
  * @remarks
1302
1511
  * Built by {@link import('./helpers.js').createSelectState}; advanced by
@@ -1306,11 +1515,13 @@ export declare function selectReduce(state: SelectState, key: KeyEvent): PromptS
1306
1515
  export declare interface SelectState {
1307
1516
  readonly message: string;
1308
1517
  readonly choices: readonly PromptChoice[];
1518
+ readonly hint?: string;
1309
1519
  readonly styler: StylerInterface;
1520
+ readonly theme: PromptTheme;
1310
1521
  readonly focused: number;
1311
1522
  }
1312
1523
 
1313
- /** Render a {@link SelectState} as a MULTI-LINE styled view — the header followed by one row per choice, the focused row marked. */
1524
+ /** Render a {@link SelectState} as a MULTI-LINE styled view — the header (plus any hint) followed by one row per choice, the focused row marked. */
1314
1525
  export declare function selectView(state: SelectState): string;
1315
1526
 
1316
1527
  /**
@@ -1341,7 +1552,8 @@ export declare function serializePending(prompt: PendingPrompt): WireEvent;
1341
1552
  * serializes over SSE. Drops everything that cannot cross the wire (a `styler`, and any
1342
1553
  * function-valued `validate` rule), while KEEPING the declarative data a remote client needs to
1343
1554
  * reconstruct the prompt: the {@link ValidationRules} as data, plus `message` / `choices` /
1344
- * `default` / `mask` / `min` / `max`. This is WHY T-a's validation is rules-as-data: a `Validator`
1555
+ * `default` / `mask` / `min` / `max` / `hint` / `theme`. This is WHY T-a's validation is
1556
+ * rules-as-data, and why a theme is data too: a `Validator`
1345
1557
  * FUNCTION can't be serialized, but its declarative rules can — the client rebuilds the validator
1346
1558
  * from them via {@link resolveValidation}.
1347
1559
  *
@@ -1395,8 +1607,8 @@ export declare const SSE_EVENTS: Readonly<{
1395
1607
  shutdown: "shutdown";
1396
1608
  }>;
1397
1609
 
1398
- /** The styled submit line (`✔ message`) — the committed header an interactive prompt shows once resolved. */
1399
- export declare function submitHeader(styler: StylerInterface, message: string): string;
1610
+ /** The styled submit line (`✔ message`) — the committed header an interactive prompt shows once resolved, themed by the `success` + `message` roles. */
1611
+ export declare function submitHeader(styler: StylerInterface, theme: PromptTheme, message: string): string;
1400
1612
 
1401
1613
  /** Tab (`\t`, U+0009). */
1402
1614
  export declare const TAB: string;
@@ -1404,15 +1616,6 @@ export declare const TAB: string;
1404
1616
  /** The rejection reason a {@link TerminalManagerInterface.answer} call returns — an {@link AnswerError}, plus `'terminal'` (no such endpoint). */
1405
1617
  export declare type TerminalAnswerError = AnswerError | 'terminal';
1406
1618
 
1407
- /** The outcome of a {@link TerminalManagerInterface.answer} call — the accepted `value` on success, else the {@link TerminalAnswerError}. */
1408
- export declare type TerminalAnswerResult = {
1409
- readonly success: true;
1410
- readonly value: unknown;
1411
- } | {
1412
- readonly success: false;
1413
- readonly error: TerminalAnswerError;
1414
- };
1415
-
1416
1619
  /**
1417
1620
  * An error a {@link import('./Prompt.js').Prompt} broker rejects a parked prompt's Promise with.
1418
1621
  *
@@ -1466,9 +1669,9 @@ export declare type TerminalErrorCode = 'EXPIRE' | 'CANCEL' | 'DRIVER' | 'DEADLO
1466
1669
  * - **Durable open / save.** `open(name)` restores an EMPTY broker from the `store` (parked
1467
1670
  * Promises are process-bound and never resurrected); `save(name)` persists the endpoint's
1468
1671
  * configured `timeout`.
1469
- * - **Removal.** `remove` drops one endpoint or a batch (§9.2, array overload FIRST), destroying
1470
- * each broker (which expires every prompt still parked on it). `clear` drops all; `destroy` is
1471
- * idempotent.
1672
+ * - **Removal.** `remove` drops one endpoint, a batch (§9.2, array overload FIRST), or every
1673
+ * endpoint when called without an argument. It destroys each broker, which expires every prompt
1674
+ * still parked on it. `destroy` is idempotent.
1472
1675
  *
1473
1676
  * @example
1474
1677
  * ```ts
@@ -1493,12 +1696,12 @@ export declare class TerminalManager implements TerminalManagerInterface {
1493
1696
  ask(from: string, to: string, form: 'checkbox', options: CheckboxOptions): Promise<readonly string[]>;
1494
1697
  pending(): readonly PendingPrompt[];
1495
1698
  pending(to: string): readonly PendingPrompt[];
1496
- answer(to: string, id: string, value: unknown): TerminalAnswerResult;
1699
+ answer(to: string, id: string, value: unknown): Result<unknown, TerminalAnswerError>;
1497
1700
  open(name: string): Promise<PromptInterface | undefined>;
1498
1701
  save(name: string): Promise<boolean>;
1499
1702
  remove(names: readonly string[]): boolean;
1500
1703
  remove(name: string): boolean;
1501
- clear(): void;
1704
+ remove(): void;
1502
1705
  destroy(): void;
1503
1706
  }
1504
1707
 
@@ -1536,9 +1739,9 @@ export declare type TerminalManagerEventMap = {
1536
1739
  * - **`save`** persists an endpoint's config snapshot to the `store` (`false` when there is no
1537
1740
  * store, or `name` is unknown).
1538
1741
  * - **Batch `remove` (§9.2).** The array overload is declared FIRST — `remove(names)` removes each
1539
- * listed endpoint (`true` when any of the named terminals was removed); `remove(name)` removes one.
1540
- * - **`clear`** removes every endpoint without destroying the manager; **`destroy`** tears down
1541
- * every broker, then the manager's own emitter.
1742
+ * listed endpoint (`true` when any named terminal was removed); `remove(name)` removes one;
1743
+ * `remove()` removes every endpoint without destroying the manager.
1744
+ * - **`destroy`** tears down every broker, then the manager's own emitter.
1542
1745
  */
1543
1746
  export declare interface TerminalManagerInterface {
1544
1747
  readonly emitter: EmitterInterface<TerminalManagerEventMap>;
@@ -1552,12 +1755,12 @@ export declare interface TerminalManagerInterface {
1552
1755
  ask(from: string, to: string, form: 'checkbox', options: CheckboxOptions): Promise<readonly string[]>;
1553
1756
  pending(): readonly PendingPrompt[];
1554
1757
  pending(to: string): readonly PendingPrompt[];
1555
- answer(to: string, id: string, value: unknown): TerminalAnswerResult;
1758
+ answer(to: string, id: string, value: unknown): Result<unknown, TerminalAnswerError>;
1556
1759
  open(name: string): Promise<PromptInterface | undefined>;
1557
1760
  save(name: string): Promise<boolean>;
1558
1761
  remove(names: readonly string[]): boolean;
1559
1762
  remove(name: string): boolean;
1560
- clear(): void;
1763
+ remove(): void;
1561
1764
  destroy(): void;
1562
1765
  }
1563
1766
 
@@ -1631,7 +1834,10 @@ export { TimerHandler_2 as TimerHandler }
1631
1834
  /** Toggle `index` in a readonly index list — copy-on-write, returning the new sorted-by-insertion list. */
1632
1835
  export declare function toggleIndex(indices: readonly number[], index: number): readonly number[];
1633
1836
 
1634
- /** Matches an HTTP(S) URL. The `url` rule tests against this. */
1837
+ /**
1838
+ * Matches an HTTP(S) URL. The `url` rule tests against this. Kept locally because it is
1839
+ * narrower than `FORMAT_PATTERNS.uri`, which accepts other URI schemes.
1840
+ */
1635
1841
  export declare const URL_PATTERN: RegExp;
1636
1842
 
1637
1843
  /**