@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.
- package/dist/src/core/index.cjs +336 -88
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +294 -88
- package/dist/src/core/index.d.ts +294 -88
- package/dist/src/core/index.js +330 -88
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +17 -20
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +7 -7
- package/dist/src/server/index.d.ts +7 -7
- package/dist/src/server/index.js +18 -21
- package/dist/src/server/index.js.map +1 -1
- package/package.json +8 -6
package/dist/src/core/index.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
let _orkestrel_contract = require("@orkestrel/contract");
|
|
3
2
|
let _orkestrel_console = require("@orkestrel/console");
|
|
3
|
+
let _orkestrel_contract = require("@orkestrel/contract");
|
|
4
4
|
let _orkestrel_emitter = require("@orkestrel/emitter");
|
|
5
5
|
let _orkestrel_sse = require("@orkestrel/sse");
|
|
6
6
|
let _orkestrel_database = require("@orkestrel/database");
|
|
@@ -130,9 +130,10 @@ var CONTROL_NAMES = Object.freeze({
|
|
|
130
130
|
});
|
|
131
131
|
/** The default mask glyph a {@link import('./types.js').PasswordState} renders each input character as — `*`. */
|
|
132
132
|
var DEFAULT_MASK = "*";
|
|
133
|
-
/**
|
|
134
|
-
|
|
135
|
-
|
|
133
|
+
/**
|
|
134
|
+
* Matches an HTTP(S) URL. The `url` rule tests against this. Kept locally because it is
|
|
135
|
+
* narrower than `FORMAT_PATTERNS.uri`, which accepts other URI schemes.
|
|
136
|
+
*/
|
|
136
137
|
var URL_PATTERN = /^https?:\/\/.+/;
|
|
137
138
|
/** Matches a numeric value (integer or decimal, optional sign). The `numeric` rule tests against this. */
|
|
138
139
|
var NUMERIC_PATTERN = /^-?\d+(\.\d+)?$/;
|
|
@@ -159,11 +160,8 @@ var RULE_MESSAGES = Object.freeze({
|
|
|
159
160
|
invalid: "Invalid input"
|
|
160
161
|
});
|
|
161
162
|
/**
|
|
162
|
-
* The
|
|
163
|
-
*
|
|
164
|
-
* {@link import('@orkestrel/console').StylerInterface} at render time, never baked into the
|
|
165
|
-
* constant (AGENTS — styling orthogonal to data; the rework fixes the terminal's ANSI-in-the-icon).
|
|
166
|
-
* Frozen.
|
|
163
|
+
* The six default glyphs {@link DEFAULT_PROMPT_THEME} assembles its `icons` from. Read only when
|
|
164
|
+
* the default theme is assembled; a view reads its resolved theme and never this constant. Frozen.
|
|
167
165
|
*
|
|
168
166
|
* @remarks
|
|
169
167
|
* - `question` — the leading mark on a prompt's message line.
|
|
@@ -179,6 +177,79 @@ var PROMPT_ICONS = Object.freeze({
|
|
|
179
177
|
checked: "☑",
|
|
180
178
|
unchecked: "☐"
|
|
181
179
|
});
|
|
180
|
+
/**
|
|
181
|
+
* Every {@link import('./types.js').PromptRole}, in one frozen list — the role axis's source of
|
|
182
|
+
* truth. {@link import('./helpers.js').createPromptTheme} walks it to merge a partial theme, and
|
|
183
|
+
* a consumer building a complete role map reads it rather than retyping every name.
|
|
184
|
+
*/
|
|
185
|
+
var PROMPT_ROLES = Object.freeze([
|
|
186
|
+
"question",
|
|
187
|
+
"pointer",
|
|
188
|
+
"message",
|
|
189
|
+
"content",
|
|
190
|
+
"success",
|
|
191
|
+
"error",
|
|
192
|
+
"selected",
|
|
193
|
+
"focus",
|
|
194
|
+
"hint",
|
|
195
|
+
"muted",
|
|
196
|
+
"description"
|
|
197
|
+
]);
|
|
198
|
+
/**
|
|
199
|
+
* The {@link import('./types.js').PromptTheme} every prompt renders with unless its options supply
|
|
200
|
+
* another — the glyph set assembled from {@link PROMPT_ICONS} plus the console
|
|
201
|
+
* {@link import('@orkestrel/console').STATUS_ICONS} `success` / `error` marks, and the console
|
|
202
|
+
* {@link import('@orkestrel/console').Style} each role is painted with. Deeply frozen through the
|
|
203
|
+
* console module's own {@link import('@orkestrel/console').freezeStyle}; the baseline
|
|
204
|
+
* {@link import('./helpers.js').createPromptTheme} merges a partial theme over.
|
|
205
|
+
*
|
|
206
|
+
* @remarks
|
|
207
|
+
* The default roles reproduce the views' historical coloring exactly: `question` / `pointer` cyan,
|
|
208
|
+
* `message` / `focus` bold, `success` / `selected` green, `error` red, `hint` / `muted` /
|
|
209
|
+
* `description` dim, and `content` the EMPTY style — an empty style renders bare text, so primary
|
|
210
|
+
* content keeps the bytes it had before it became themeable.
|
|
211
|
+
* Two roles sharing a style today are still two roles — re-mapping one leaves the other alone.
|
|
212
|
+
*/
|
|
213
|
+
var DEFAULT_PROMPT_THEME = Object.freeze({
|
|
214
|
+
icons: Object.freeze({
|
|
215
|
+
question: PROMPT_ICONS.question,
|
|
216
|
+
pointer: PROMPT_ICONS.pointer,
|
|
217
|
+
dot: PROMPT_ICONS.dot,
|
|
218
|
+
selected: PROMPT_ICONS.selected,
|
|
219
|
+
checked: PROMPT_ICONS.checked,
|
|
220
|
+
unchecked: PROMPT_ICONS.unchecked,
|
|
221
|
+
success: _orkestrel_console.STATUS_ICONS.success,
|
|
222
|
+
error: _orkestrel_console.STATUS_ICONS.error
|
|
223
|
+
}),
|
|
224
|
+
roles: Object.freeze({
|
|
225
|
+
question: (0, _orkestrel_console.freezeStyle)({
|
|
226
|
+
foreground: "cyan",
|
|
227
|
+
attributes: []
|
|
228
|
+
}),
|
|
229
|
+
pointer: (0, _orkestrel_console.freezeStyle)({
|
|
230
|
+
foreground: "cyan",
|
|
231
|
+
attributes: []
|
|
232
|
+
}),
|
|
233
|
+
message: (0, _orkestrel_console.freezeStyle)({ attributes: ["bold"] }),
|
|
234
|
+
content: (0, _orkestrel_console.freezeStyle)({ attributes: [] }),
|
|
235
|
+
success: (0, _orkestrel_console.freezeStyle)({
|
|
236
|
+
foreground: "green",
|
|
237
|
+
attributes: []
|
|
238
|
+
}),
|
|
239
|
+
error: (0, _orkestrel_console.freezeStyle)({
|
|
240
|
+
foreground: "red",
|
|
241
|
+
attributes: []
|
|
242
|
+
}),
|
|
243
|
+
selected: (0, _orkestrel_console.freezeStyle)({
|
|
244
|
+
foreground: "green",
|
|
245
|
+
attributes: []
|
|
246
|
+
}),
|
|
247
|
+
focus: (0, _orkestrel_console.freezeStyle)({ attributes: ["bold"] }),
|
|
248
|
+
hint: (0, _orkestrel_console.freezeStyle)({ attributes: ["dim"] }),
|
|
249
|
+
muted: (0, _orkestrel_console.freezeStyle)({ attributes: ["dim"] }),
|
|
250
|
+
description: (0, _orkestrel_console.freezeStyle)({ attributes: ["dim"] })
|
|
251
|
+
})
|
|
252
|
+
});
|
|
182
253
|
/** How long (ms) the {@link import('./types.js').PromptInterface} broker parks an unanswered prompt before it expires — 5 minutes. */
|
|
183
254
|
var DEFAULT_PROMPT_TIMEOUT_MS = 3e5;
|
|
184
255
|
/** How long (ms) the {@link import('./types.js').PromptClientInterface} waits before each reconnect attempt — 2 seconds. */
|
|
@@ -272,6 +343,63 @@ var isPendingPrompt = (0, _orkestrel_contract.recordOf)({
|
|
|
272
343
|
from: _orkestrel_contract.isString,
|
|
273
344
|
to: _orkestrel_contract.isString
|
|
274
345
|
}, ["from", "to"]);
|
|
346
|
+
/**
|
|
347
|
+
* Narrow an unknown value to a console {@link Style} — the value every
|
|
348
|
+
* {@link import('./types.js').PromptRole} carries, built from the console module's own
|
|
349
|
+
* {@link import('@orkestrel/console').COLORS} + {@link import('@orkestrel/console').ATTRIBUTES} so
|
|
350
|
+
* the style vocabulary has ONE source.
|
|
351
|
+
*
|
|
352
|
+
* @remarks
|
|
353
|
+
* The record is CLOSED and matches the `Style` contract exactly: `foreground` and `background` are
|
|
354
|
+
* optional and each must name a color (`default` included, as the console `Color` union has it),
|
|
355
|
+
* `attributes` is REQUIRED and must be an array over the attribute set, and any other key rejects
|
|
356
|
+
* the whole value.
|
|
357
|
+
*/
|
|
358
|
+
var isStyle = (0, _orkestrel_contract.recordOf)({
|
|
359
|
+
foreground: (0, _orkestrel_contract.literalOf)(..._orkestrel_console.COLORS, "default"),
|
|
360
|
+
background: (0, _orkestrel_contract.literalOf)(..._orkestrel_console.COLORS, "default"),
|
|
361
|
+
attributes: (0, _orkestrel_contract.arrayOf)((0, _orkestrel_contract.literalOf)(..._orkestrel_console.ATTRIBUTES))
|
|
362
|
+
}, ["foreground", "background"]);
|
|
363
|
+
/**
|
|
364
|
+
* Narrow an unknown wire value to a {@link PromptThemeOptions} — the §14 guard a remote prompt's
|
|
365
|
+
* `theme` option passes before it reaches a local prompt.
|
|
366
|
+
*
|
|
367
|
+
* @remarks
|
|
368
|
+
* The shape is CLOSED at every level: an unknown icon slot, an unknown role, a non-string glyph, or
|
|
369
|
+
* a role whose value is not a {@link isStyle}-shaped console style rejects the whole theme, so a
|
|
370
|
+
* hostile payload degrades to the default theme rather than partially applying. Glyphs still carry
|
|
371
|
+
* arbitrary text at this point — {@link import('./helpers.js').sanitizeThemeIcons} strips their
|
|
372
|
+
* control bytes on dispatch.
|
|
373
|
+
*
|
|
374
|
+
* The icons and roles shapes are checked against their complete union-keyed guard records. A slot
|
|
375
|
+
* added to either union without an entry here is a compile error rather than a wire theme that is
|
|
376
|
+
* silently refused.
|
|
377
|
+
*/
|
|
378
|
+
var isPromptThemeOptions = (0, _orkestrel_contract.recordOf)({
|
|
379
|
+
icons: (0, _orkestrel_contract.recordOf)({
|
|
380
|
+
question: _orkestrel_contract.isString,
|
|
381
|
+
pointer: _orkestrel_contract.isString,
|
|
382
|
+
dot: _orkestrel_contract.isString,
|
|
383
|
+
selected: _orkestrel_contract.isString,
|
|
384
|
+
checked: _orkestrel_contract.isString,
|
|
385
|
+
unchecked: _orkestrel_contract.isString,
|
|
386
|
+
success: _orkestrel_contract.isString,
|
|
387
|
+
error: _orkestrel_contract.isString
|
|
388
|
+
}, true),
|
|
389
|
+
roles: (0, _orkestrel_contract.recordOf)({
|
|
390
|
+
question: isStyle,
|
|
391
|
+
pointer: isStyle,
|
|
392
|
+
message: isStyle,
|
|
393
|
+
content: isStyle,
|
|
394
|
+
success: isStyle,
|
|
395
|
+
error: isStyle,
|
|
396
|
+
selected: isStyle,
|
|
397
|
+
focus: isStyle,
|
|
398
|
+
hint: isStyle,
|
|
399
|
+
description: isStyle,
|
|
400
|
+
muted: isStyle
|
|
401
|
+
}, true)
|
|
402
|
+
}, true);
|
|
275
403
|
/** Narrow an unknown value to a {@link TerminalSnapshot}. */
|
|
276
404
|
var isTerminalSnapshot = (0, _orkestrel_contract.recordOf)({
|
|
277
405
|
id: _orkestrel_contract.isNonEmptyString,
|
|
@@ -396,7 +524,7 @@ function evaluateRule(rule, check, input) {
|
|
|
396
524
|
}
|
|
397
525
|
break;
|
|
398
526
|
case "email":
|
|
399
|
-
if (check === true && !
|
|
527
|
+
if (check === true && !_orkestrel_contract.FORMAT_PATTERNS.email.test(input)) return RULE_MESSAGES.email;
|
|
400
528
|
break;
|
|
401
529
|
case "url":
|
|
402
530
|
if (check === true && !URL_PATTERN.test(input)) return RULE_MESSAGES.url;
|
|
@@ -501,33 +629,116 @@ function normalizeCheckboxChoice(choice) {
|
|
|
501
629
|
value: choice
|
|
502
630
|
} : choice;
|
|
503
631
|
}
|
|
504
|
-
/**
|
|
505
|
-
|
|
506
|
-
|
|
632
|
+
/**
|
|
633
|
+
* Build a complete {@link PromptTheme} by merging a partial one over
|
|
634
|
+
* {@link DEFAULT_PROMPT_THEME}, leaf by leaf — each supplied icon replaces that glyph, each
|
|
635
|
+
* supplied role replaces that {@link Style}, and everything else keeps its default. Each supplied
|
|
636
|
+
* style is snapshotted through the console module's own
|
|
637
|
+
* {@link import('@orkestrel/console').freezeStyle}, so the result is deeply frozen and a caller
|
|
638
|
+
* mutating its own attribute list afterwards cannot reach into a built theme.
|
|
639
|
+
*
|
|
640
|
+
* @param options - The partial theme to merge, or `undefined` for the defaults
|
|
641
|
+
* @returns The resolved, deeply frozen theme every prompt state carries
|
|
642
|
+
*
|
|
643
|
+
* @example
|
|
644
|
+
* ```ts
|
|
645
|
+
* createPromptTheme() // the defaults
|
|
646
|
+
* createPromptTheme({
|
|
647
|
+
* icons: { pointer: '=>' },
|
|
648
|
+
* roles: { message: { foreground: 'magenta', attributes: ['bold'] } },
|
|
649
|
+
* })
|
|
650
|
+
* ```
|
|
651
|
+
*/
|
|
652
|
+
function createPromptTheme(options) {
|
|
653
|
+
const icons = {
|
|
654
|
+
...DEFAULT_PROMPT_THEME.icons,
|
|
655
|
+
...options?.icons
|
|
656
|
+
};
|
|
657
|
+
const roles = { ...DEFAULT_PROMPT_THEME.roles };
|
|
658
|
+
for (const role of PROMPT_ROLES) {
|
|
659
|
+
const style = options?.roles?.[role];
|
|
660
|
+
if (style !== void 0) roles[role] = (0, _orkestrel_console.freezeStyle)(style);
|
|
661
|
+
}
|
|
662
|
+
return Object.freeze({
|
|
663
|
+
icons: Object.freeze(icons),
|
|
664
|
+
roles: Object.freeze(roles)
|
|
665
|
+
});
|
|
507
666
|
}
|
|
508
|
-
/**
|
|
509
|
-
|
|
510
|
-
|
|
667
|
+
/**
|
|
668
|
+
* Sanitize text for one single-line display slot. Composes console's {@link stripControls} pass
|
|
669
|
+
* with removal of tab, line feed, and carriage return, so no C0 control or DEL survives.
|
|
670
|
+
*
|
|
671
|
+
* @param text - The text to sanitize for a glyph or hint slot
|
|
672
|
+
* @returns The text with every C0 control character and DEL removed
|
|
673
|
+
*
|
|
674
|
+
* @example
|
|
675
|
+
* ```ts
|
|
676
|
+
* sanitizeDisplayText('Q\rOVERWRITE\nNEXT\tX') // 'QOVERWRITENEXTX'
|
|
677
|
+
* ```
|
|
678
|
+
*/
|
|
679
|
+
function sanitizeDisplayText(text) {
|
|
680
|
+
return (0, _orkestrel_console.stripControls)(text).replaceAll(" ", "").replaceAll("\n", "").replaceAll("\r", "");
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Sanitize every glyph a wire-supplied {@link PromptThemeOptions} carries for a single-line display
|
|
684
|
+
* slot. Only the icons need it: a role is guard-narrowed to a console {@link Style}, whose colors
|
|
685
|
+
* and attributes are fixed name sets, so no role can carry a byte a terminal would act on.
|
|
686
|
+
*
|
|
687
|
+
* @param theme - The narrowed theme options a remote prompt supplied
|
|
688
|
+
* @returns The same theme with every supplied glyph sanitized for a single-line display slot
|
|
689
|
+
*/
|
|
690
|
+
function sanitizeThemeIcons(theme) {
|
|
691
|
+
const icons = theme.icons;
|
|
692
|
+
if (icons === void 0) return theme;
|
|
693
|
+
const sanitized = {};
|
|
694
|
+
for (const [icon, glyph] of Object.entries(icons)) sanitized[icon] = sanitizeDisplayText(glyph);
|
|
695
|
+
return {
|
|
696
|
+
...theme,
|
|
697
|
+
icons: sanitized
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
/** The styled prompt-message header (`? message`) — the leading line every active prompt view shares, themed by the `question` + `message` roles. */
|
|
701
|
+
function promptHeader(styler, theme, message) {
|
|
702
|
+
return `${styler.render(theme.roles.question, theme.icons.question)} ${styler.render(theme.roles.message, message)}`;
|
|
703
|
+
}
|
|
704
|
+
/**
|
|
705
|
+
* Render a prompt header followed by a key hint painted with the `hint` role, or the header alone
|
|
706
|
+
* when no hint is supplied.
|
|
707
|
+
*
|
|
708
|
+
* @param styler - The console styler that renders each role
|
|
709
|
+
* @param theme - The resolved prompt theme
|
|
710
|
+
* @param message - The prompt's question text
|
|
711
|
+
* @param hint - The optional key hint to append
|
|
712
|
+
* @returns The rendered header with the optional hint
|
|
713
|
+
*/
|
|
714
|
+
function hintedHeader(styler, theme, message, hint) {
|
|
715
|
+
const head = promptHeader(styler, theme, message);
|
|
716
|
+
return hint === void 0 ? head : `${head} ${styler.render(theme.roles.hint, hint)}`;
|
|
717
|
+
}
|
|
718
|
+
/** The styled submit line (`✔ message`) — the committed header an interactive prompt shows once resolved, themed by the `success` + `message` roles. */
|
|
719
|
+
function submitHeader(styler, theme, message) {
|
|
720
|
+
return `${styler.render(theme.roles.success, theme.icons.success)} ${styler.render(theme.roles.message, message)}`;
|
|
511
721
|
}
|
|
512
|
-
/** The styled error line (`✖ message`) — appended beneath a prompt view when the last submit failed validation. */
|
|
513
|
-
function errorLine(styler, message) {
|
|
514
|
-
return `${styler.
|
|
722
|
+
/** The styled error line (`✖ message`) — appended beneath a prompt view when the last submit failed validation, themed by the `error` role. */
|
|
723
|
+
function errorLine(styler, theme, message) {
|
|
724
|
+
return `${styler.render(theme.roles.error, theme.icons.error)} ${styler.render(theme.roles.error, message)}`;
|
|
515
725
|
}
|
|
516
|
-
/** Build the initial {@link InputState} from {@link InputOptions} — resolving the validator + styler, seeding an empty value. */
|
|
726
|
+
/** Build the initial {@link InputState} from {@link InputOptions} — resolving the validator + styler + theme, seeding an empty value. */
|
|
517
727
|
function createInputState(options) {
|
|
518
728
|
return {
|
|
519
729
|
message: options.message,
|
|
520
730
|
default: options.default ?? "",
|
|
521
731
|
validator: resolveValidation(options.validate),
|
|
522
732
|
styler: options.styler ?? (0, _orkestrel_console.createStyler)(),
|
|
733
|
+
theme: createPromptTheme(options.theme),
|
|
523
734
|
value: ""
|
|
524
735
|
};
|
|
525
736
|
}
|
|
526
|
-
/** Render an {@link InputState} as a styled view — the header, the typed value (or
|
|
737
|
+
/** 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. */
|
|
527
738
|
function inputView(state) {
|
|
528
|
-
const shown = state.value.length > 0 ? state.value : state.styler.
|
|
529
|
-
const head = `${promptHeader(state.styler, state.message)} ${state.styler.
|
|
530
|
-
return state.error === void 0 ? head : `${head}\n${errorLine(state.styler, state.error)}`;
|
|
739
|
+
const shown = state.value.length > 0 ? state.styler.render(state.theme.roles.content, state.value) : state.styler.render(state.theme.roles.hint, state.default);
|
|
740
|
+
const head = `${promptHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)} ${shown}`;
|
|
741
|
+
return state.error === void 0 ? head : `${head}\n${errorLine(state.styler, state.theme, state.error)}`;
|
|
531
742
|
}
|
|
532
743
|
/**
|
|
533
744
|
* Advance an input prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`
|
|
@@ -561,7 +772,7 @@ function inputReduce(state, key) {
|
|
|
561
772
|
...clear,
|
|
562
773
|
value: answer
|
|
563
774
|
},
|
|
564
|
-
view: `${submitHeader(state.styler, state.message)} ${state.styler.
|
|
775
|
+
view: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, answer)}`,
|
|
565
776
|
status: "submit",
|
|
566
777
|
value: answer
|
|
567
778
|
};
|
|
@@ -582,21 +793,22 @@ function inputReduce(state, key) {
|
|
|
582
793
|
status: "active"
|
|
583
794
|
};
|
|
584
795
|
}
|
|
585
|
-
/** Build the initial {@link PasswordState} from {@link PasswordOptions} — resolving the validator + styler + mask. */
|
|
796
|
+
/** Build the initial {@link PasswordState} from {@link PasswordOptions} — resolving the validator + styler + theme + mask. */
|
|
586
797
|
function createPasswordState(options) {
|
|
587
798
|
return {
|
|
588
799
|
message: options.message,
|
|
589
800
|
mask: options.mask ?? "*",
|
|
590
801
|
validator: resolveValidation(options.validate),
|
|
591
802
|
styler: options.styler ?? (0, _orkestrel_console.createStyler)(),
|
|
803
|
+
theme: createPromptTheme(options.theme),
|
|
592
804
|
value: ""
|
|
593
805
|
};
|
|
594
806
|
}
|
|
595
|
-
/** Render a {@link PasswordState} as a styled view — the header, the value masked to `mask` repeated, and any error. */
|
|
807
|
+
/** 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. */
|
|
596
808
|
function passwordView(state) {
|
|
597
|
-
const masked = state.mask.repeat(state.value.length);
|
|
598
|
-
const head = `${promptHeader(state.styler, state.message)} ${state.styler.
|
|
599
|
-
return state.error === void 0 ? head : `${head}\n${errorLine(state.styler, state.error)}`;
|
|
809
|
+
const masked = state.styler.render(state.theme.roles.content, state.mask.repeat(state.value.length));
|
|
810
|
+
const head = `${promptHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer)} ${masked}`;
|
|
811
|
+
return state.error === void 0 ? head : `${head}\n${errorLine(state.styler, state.theme, state.error)}`;
|
|
600
812
|
}
|
|
601
813
|
/**
|
|
602
814
|
* Advance a password prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`
|
|
@@ -626,7 +838,7 @@ function passwordReduce(state, key) {
|
|
|
626
838
|
}
|
|
627
839
|
return {
|
|
628
840
|
state: clear,
|
|
629
|
-
view: `${submitHeader(state.styler, state.message)} ${state.styler.
|
|
841
|
+
view: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, state.mask.repeat(state.value.length))}`,
|
|
630
842
|
status: "submit",
|
|
631
843
|
value: state.value
|
|
632
844
|
};
|
|
@@ -647,18 +859,26 @@ function passwordReduce(state, key) {
|
|
|
647
859
|
status: "active"
|
|
648
860
|
};
|
|
649
861
|
}
|
|
650
|
-
/** Build the initial {@link ConfirmState} from {@link ConfirmOptions} — defaulting the answer to `false
|
|
862
|
+
/** Build the initial {@link ConfirmState} from {@link ConfirmOptions} — defaulting the answer to `false`, resolving the styler + theme, carrying any hint override. */
|
|
651
863
|
function createConfirmState(options) {
|
|
652
864
|
return {
|
|
653
865
|
message: options.message,
|
|
654
866
|
default: options.default ?? false,
|
|
655
|
-
|
|
867
|
+
...options.hint !== void 0 ? { hint: options.hint } : {},
|
|
868
|
+
styler: options.styler ?? (0, _orkestrel_console.createStyler)(),
|
|
869
|
+
theme: createPromptTheme(options.theme)
|
|
656
870
|
};
|
|
657
871
|
}
|
|
658
|
-
/**
|
|
872
|
+
/**
|
|
873
|
+
* Render a {@link ConfirmState} as a styled view — the header plus the `(Y/n)` group with the
|
|
874
|
+
* default letter painted by the `selected` role. A supplied `hint` replaces that whole group,
|
|
875
|
+
* parentheses included, painted by the `hint` role.
|
|
876
|
+
*/
|
|
659
877
|
function confirmView(state) {
|
|
660
|
-
|
|
661
|
-
|
|
878
|
+
if (state.hint !== void 0) return hintedHeader(state.styler, state.theme, state.message, state.hint);
|
|
879
|
+
const head = promptHeader(state.styler, state.theme, state.message);
|
|
880
|
+
const answer = state.default ? `${state.styler.render(state.theme.roles.selected, "Y")}${state.styler.render(state.theme.roles.hint, "/n")}` : `${state.styler.render(state.theme.roles.hint, "y/")}${state.styler.render(state.theme.roles.selected, "N")}`;
|
|
881
|
+
return `${head} ${state.styler.render(state.theme.roles.hint, "(")}${answer}${state.styler.render(state.theme.roles.hint, ")")}`;
|
|
662
882
|
}
|
|
663
883
|
/**
|
|
664
884
|
* Advance a confirm prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<boolean>`
|
|
@@ -683,29 +903,31 @@ function confirmReduce(state, key) {
|
|
|
683
903
|
};
|
|
684
904
|
return {
|
|
685
905
|
state,
|
|
686
|
-
view: `${submitHeader(state.styler, state.message)} ${state.styler.
|
|
906
|
+
view: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, answer ? "yes" : "no")}`,
|
|
687
907
|
status: "submit",
|
|
688
908
|
value: answer
|
|
689
909
|
};
|
|
690
910
|
}
|
|
691
|
-
/** Build the initial {@link SelectState} from {@link SelectOptions} — normalizing choices and pre-focusing the default. */
|
|
911
|
+
/** Build the initial {@link SelectState} from {@link SelectOptions} — normalizing choices, resolving the styler + theme, carrying any hint, and pre-focusing the default. */
|
|
692
912
|
function createSelectState(options) {
|
|
693
913
|
const choices = options.choices.map(normalizeChoice);
|
|
694
914
|
const index = choices.findIndex((choice) => choice.value === options.default);
|
|
695
915
|
return {
|
|
696
916
|
message: options.message,
|
|
697
917
|
choices,
|
|
918
|
+
...options.hint !== void 0 ? { hint: options.hint } : {},
|
|
698
919
|
styler: options.styler ?? (0, _orkestrel_console.createStyler)(),
|
|
920
|
+
theme: createPromptTheme(options.theme),
|
|
699
921
|
focused: index >= 0 ? index : 0
|
|
700
922
|
};
|
|
701
923
|
}
|
|
702
|
-
/** Render a {@link SelectState} as a MULTI-LINE styled view — the header followed by one row per choice, the focused row marked. */
|
|
924
|
+
/** 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. */
|
|
703
925
|
function selectView(state) {
|
|
704
926
|
const lines = state.choices.map((choice, index) => {
|
|
705
927
|
const active = index === state.focused;
|
|
706
|
-
return `${active ? state.styler.
|
|
928
|
+
return `${active ? state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer) : " "} ${active ? state.styler.render(state.theme.roles.selected, state.theme.icons.selected) : state.styler.render(state.theme.roles.muted, state.theme.icons.dot)} ${active ? state.styler.render(state.theme.roles.focus, choice.name) : state.styler.render(state.theme.roles.content, choice.name)}${choice.description === void 0 ? "" : ` ${state.styler.render(state.theme.roles.description, choice.description)}`}`;
|
|
707
929
|
});
|
|
708
|
-
return [
|
|
930
|
+
return [hintedHeader(state.styler, state.theme, state.message, state.hint), ...lines].join("\n");
|
|
709
931
|
}
|
|
710
932
|
/**
|
|
711
933
|
* Advance a select prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`
|
|
@@ -752,7 +974,7 @@ function selectReduce(state, key) {
|
|
|
752
974
|
const value = choice?.value ?? "";
|
|
753
975
|
return {
|
|
754
976
|
state,
|
|
755
|
-
view: `${submitHeader(state.styler, state.message)} ${state.styler.
|
|
977
|
+
view: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, choice?.name ?? "")}`,
|
|
756
978
|
status: "submit",
|
|
757
979
|
value
|
|
758
980
|
};
|
|
@@ -763,7 +985,7 @@ function selectReduce(state, key) {
|
|
|
763
985
|
status: "active"
|
|
764
986
|
};
|
|
765
987
|
}
|
|
766
|
-
/** Build the initial {@link CheckboxState} from {@link CheckboxOptions} — normalizing choices, seeding the checked set, carrying min/max. */
|
|
988
|
+
/** Build the initial {@link CheckboxState} from {@link CheckboxOptions} — normalizing choices, resolving the styler + theme, carrying any hint, seeding the checked set, carrying min/max. */
|
|
767
989
|
function createCheckboxState(options) {
|
|
768
990
|
const choices = options.choices.map(normalizeCheckboxChoice);
|
|
769
991
|
const checked = choices.reduce((indices, choice, index) => {
|
|
@@ -773,27 +995,29 @@ function createCheckboxState(options) {
|
|
|
773
995
|
return {
|
|
774
996
|
message: options.message,
|
|
775
997
|
choices,
|
|
998
|
+
...options.hint !== void 0 ? { hint: options.hint } : {},
|
|
776
999
|
styler: options.styler ?? (0, _orkestrel_console.createStyler)(),
|
|
1000
|
+
theme: createPromptTheme(options.theme),
|
|
777
1001
|
focused: 0,
|
|
778
1002
|
checked,
|
|
779
1003
|
...options.min !== void 0 ? { min: options.min } : {},
|
|
780
1004
|
...options.max !== void 0 ? { max: options.max } : {}
|
|
781
1005
|
};
|
|
782
1006
|
}
|
|
783
|
-
/** Render a {@link CheckboxState} as a MULTI-LINE styled view — the header, one box per choice (focused + checked marked), a count, and any error. */
|
|
1007
|
+
/** 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. */
|
|
784
1008
|
function checkboxView(state) {
|
|
785
1009
|
const lines = state.choices.map((choice, index) => {
|
|
786
1010
|
const active = index === state.focused;
|
|
787
1011
|
const ticked = state.checked.includes(index);
|
|
788
|
-
return `${active ? state.styler.
|
|
1012
|
+
return `${active ? state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer) : " "} ${ticked ? state.styler.render(state.theme.roles.selected, state.theme.icons.checked) : state.styler.render(state.theme.roles.muted, state.theme.icons.unchecked)} ${active ? state.styler.render(state.theme.roles.focus, choice.name) : state.styler.render(state.theme.roles.content, choice.name)}${choice.description === void 0 ? "" : ` ${state.styler.render(state.theme.roles.description, choice.description)}`}`;
|
|
789
1013
|
});
|
|
790
|
-
const summary = state.styler.
|
|
1014
|
+
const summary = state.styler.render(state.theme.roles.hint, `${state.checked.length} selected`);
|
|
791
1015
|
const body = [
|
|
792
|
-
|
|
1016
|
+
hintedHeader(state.styler, state.theme, state.message, state.hint),
|
|
793
1017
|
...lines,
|
|
794
1018
|
summary
|
|
795
1019
|
].join("\n");
|
|
796
|
-
return state.error === void 0 ? body : `${body}\n${errorLine(state.styler, state.error)}`;
|
|
1020
|
+
return state.error === void 0 ? body : `${body}\n${errorLine(state.styler, state.theme, state.error)}`;
|
|
797
1021
|
}
|
|
798
1022
|
/**
|
|
799
1023
|
* Advance a checkbox prompt by one {@link KeyEvent} — the pure
|
|
@@ -862,7 +1086,7 @@ function checkboxReduce(state, key) {
|
|
|
862
1086
|
const summary = ordered.map((index) => state.choices[index]?.name).filter((name) => name !== void 0).join(", ");
|
|
863
1087
|
return {
|
|
864
1088
|
state: clear,
|
|
865
|
-
view: `${submitHeader(state.styler, state.message)} ${state.styler.
|
|
1089
|
+
view: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, summary)}`,
|
|
866
1090
|
status: "submit",
|
|
867
1091
|
value: values
|
|
868
1092
|
};
|
|
@@ -882,21 +1106,29 @@ function gateSelection(count, min, max) {
|
|
|
882
1106
|
if (min !== void 0 && count < min) return `Select at least ${String(min)} option${min === 1 ? "" : "s"}`;
|
|
883
1107
|
if (max !== void 0 && count > max) return `Select no more than ${String(max)} option${max === 1 ? "" : "s"}`;
|
|
884
1108
|
}
|
|
885
|
-
/** Build the initial {@link EditorState} from {@link EditorOptions} — resolving the validator + styler, seeding empty lines. */
|
|
1109
|
+
/** Build the initial {@link EditorState} from {@link EditorOptions} — resolving the validator + styler + theme, carrying any hint override, seeding empty lines. */
|
|
886
1110
|
function createEditorState(options) {
|
|
887
1111
|
return {
|
|
888
1112
|
message: options.message,
|
|
889
1113
|
default: options.default ?? "",
|
|
1114
|
+
...options.hint !== void 0 ? { hint: options.hint } : {},
|
|
890
1115
|
validator: resolveValidation(options.validate),
|
|
891
1116
|
styler: options.styler ?? (0, _orkestrel_console.createStyler)(),
|
|
1117
|
+
theme: createPromptTheme(options.theme),
|
|
892
1118
|
lines: [],
|
|
893
1119
|
current: ""
|
|
894
1120
|
};
|
|
895
1121
|
}
|
|
896
|
-
/**
|
|
1122
|
+
/**
|
|
1123
|
+
* Render an {@link EditorState} as a MULTI-LINE styled view — the header with its finish hint, the
|
|
1124
|
+
* committed and in-progress lines painted by the `content` role, and any error. A supplied `hint`
|
|
1125
|
+
* replaces `(Ctrl+D to finish)` in full; the finish key stays ctrl-d.
|
|
1126
|
+
*/
|
|
897
1127
|
function editorView(state) {
|
|
898
|
-
const
|
|
899
|
-
|
|
1128
|
+
const head = hintedHeader(state.styler, state.theme, state.message, state.hint ?? "(Ctrl+D to finish)");
|
|
1129
|
+
const pointer = state.styler.render(state.theme.roles.pointer, state.theme.icons.pointer);
|
|
1130
|
+
const view = [head, ...[...state.lines.map((line) => state.styler.render(state.theme.roles.content, line)), `${pointer} ${state.styler.render(state.theme.roles.content, state.current)}`]].join("\n");
|
|
1131
|
+
return state.error === void 0 ? view : `${view}\n${errorLine(state.styler, state.theme, state.error)}`;
|
|
900
1132
|
}
|
|
901
1133
|
/**
|
|
902
1134
|
* Advance an editor prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`
|
|
@@ -930,7 +1162,7 @@ function editorReduce(state, key) {
|
|
|
930
1162
|
}
|
|
931
1163
|
return {
|
|
932
1164
|
state: clear,
|
|
933
|
-
view: `${submitHeader(state.styler, state.message)} ${state.styler.
|
|
1165
|
+
view: `${submitHeader(state.styler, state.theme, state.message)} ${state.styler.render(state.theme.roles.hint, `${String(lines.length)} line${lines.length === 1 ? "" : "s"}`)}`,
|
|
934
1166
|
status: "submit",
|
|
935
1167
|
value: answer
|
|
936
1168
|
};
|
|
@@ -980,7 +1212,8 @@ function editLine(value, key) {
|
|
|
980
1212
|
* serializes over SSE. Drops everything that cannot cross the wire (a `styler`, and any
|
|
981
1213
|
* function-valued `validate` rule), while KEEPING the declarative data a remote client needs to
|
|
982
1214
|
* reconstruct the prompt: the {@link ValidationRules} as data, plus `message` / `choices` /
|
|
983
|
-
* `default` / `mask` / `min` / `max`. This is WHY T-a's validation is
|
|
1215
|
+
* `default` / `mask` / `min` / `max` / `hint` / `theme`. This is WHY T-a's validation is
|
|
1216
|
+
* rules-as-data, and why a theme is data too: a `Validator`
|
|
984
1217
|
* FUNCTION can't be serialized, but its declarative rules can — the client rebuilds the validator
|
|
985
1218
|
* from them via {@link resolveValidation}.
|
|
986
1219
|
*
|
|
@@ -1114,6 +1347,13 @@ function sanitizeChoiceLabels(choices) {
|
|
|
1114
1347
|
* §14-narrowed, never an `as`; the validator rebuilt from rules via {@link reconstructValidationRules}),
|
|
1115
1348
|
* then calls the matching prompt form and returns its resolved value.
|
|
1116
1349
|
*
|
|
1350
|
+
* @remarks
|
|
1351
|
+
* `theme` and `hint` are plain data, so they cross the wire with the rest of the options bag and
|
|
1352
|
+
* are reconstructed here for every form that accepts them: the theme is narrowed by
|
|
1353
|
+
* {@link import('./validators.js').isPromptThemeOptions} (an off-shape theme is dropped, leaving
|
|
1354
|
+
* the defaults), then every glyph and hint is passed through {@link sanitizeDisplayText}. Choice
|
|
1355
|
+
* labels use the stream-safe {@link sanitizeChoiceLabels} treatment instead.
|
|
1356
|
+
*
|
|
1117
1357
|
* @param terminal - The local {@link PromptFormInterface} to drive
|
|
1118
1358
|
* @param pending - The decoded pending prompt to dispatch
|
|
1119
1359
|
* @returns The prompt's resolved value (a `string` / `boolean` / `readonly string[]` per form)
|
|
@@ -1122,13 +1362,18 @@ function dispatchPendingPrompt(terminal, pending) {
|
|
|
1122
1362
|
const options = pending.options;
|
|
1123
1363
|
const validate = reconstructValidationRules(options.validate);
|
|
1124
1364
|
const message = (0, _orkestrel_console.stripControls)(pending.message);
|
|
1365
|
+
const supplied = resolveOption(options, "theme", isPromptThemeOptions);
|
|
1366
|
+
const theme = supplied === void 0 ? void 0 : sanitizeThemeIcons(supplied);
|
|
1367
|
+
const raw = resolveOption(options, "hint", _orkestrel_contract.isString);
|
|
1368
|
+
const hint = raw === void 0 ? void 0 : sanitizeDisplayText(raw);
|
|
1125
1369
|
switch (pending.form) {
|
|
1126
1370
|
case "input": {
|
|
1127
1371
|
const value = resolveOption(options, "default", _orkestrel_contract.isString);
|
|
1128
1372
|
return terminal.input({
|
|
1129
1373
|
message,
|
|
1130
1374
|
...value !== void 0 ? { default: (0, _orkestrel_console.stripControls)(value) } : {},
|
|
1131
|
-
...validate !== void 0 ? { validate } : {}
|
|
1375
|
+
...validate !== void 0 ? { validate } : {},
|
|
1376
|
+
...theme !== void 0 ? { theme } : {}
|
|
1132
1377
|
});
|
|
1133
1378
|
}
|
|
1134
1379
|
case "password": {
|
|
@@ -1136,14 +1381,17 @@ function dispatchPendingPrompt(terminal, pending) {
|
|
|
1136
1381
|
return terminal.password({
|
|
1137
1382
|
message,
|
|
1138
1383
|
...value !== void 0 ? { mask: (0, _orkestrel_console.stripControls)(value) } : {},
|
|
1139
|
-
...validate !== void 0 ? { validate } : {}
|
|
1384
|
+
...validate !== void 0 ? { validate } : {},
|
|
1385
|
+
...theme !== void 0 ? { theme } : {}
|
|
1140
1386
|
});
|
|
1141
1387
|
}
|
|
1142
1388
|
case "confirm": {
|
|
1143
1389
|
const value = resolveOption(options, "default", _orkestrel_contract.isBoolean);
|
|
1144
1390
|
return terminal.confirm({
|
|
1145
1391
|
message,
|
|
1146
|
-
...value !== void 0 ? { default: value } : {}
|
|
1392
|
+
...value !== void 0 ? { default: value } : {},
|
|
1393
|
+
...hint !== void 0 ? { hint } : {},
|
|
1394
|
+
...theme !== void 0 ? { theme } : {}
|
|
1147
1395
|
});
|
|
1148
1396
|
}
|
|
1149
1397
|
case "select": {
|
|
@@ -1151,7 +1399,9 @@ function dispatchPendingPrompt(terminal, pending) {
|
|
|
1151
1399
|
return terminal.select({
|
|
1152
1400
|
message,
|
|
1153
1401
|
choices: sanitizeChoiceLabels(resolveChoices(options, isPromptChoice)),
|
|
1154
|
-
...value !== void 0 ? { default: (0, _orkestrel_console.stripControls)(value) } : {}
|
|
1402
|
+
...value !== void 0 ? { default: (0, _orkestrel_console.stripControls)(value) } : {},
|
|
1403
|
+
...hint !== void 0 ? { hint } : {},
|
|
1404
|
+
...theme !== void 0 ? { theme } : {}
|
|
1155
1405
|
});
|
|
1156
1406
|
}
|
|
1157
1407
|
case "checkbox": {
|
|
@@ -1161,7 +1411,9 @@ function dispatchPendingPrompt(terminal, pending) {
|
|
|
1161
1411
|
message,
|
|
1162
1412
|
choices: sanitizeChoiceLabels(resolveChoices(options, isCheckboxChoice)),
|
|
1163
1413
|
...min !== void 0 ? { min } : {},
|
|
1164
|
-
...max !== void 0 ? { max } : {}
|
|
1414
|
+
...max !== void 0 ? { max } : {},
|
|
1415
|
+
...hint !== void 0 ? { hint } : {},
|
|
1416
|
+
...theme !== void 0 ? { theme } : {}
|
|
1165
1417
|
});
|
|
1166
1418
|
}
|
|
1167
1419
|
case "editor": {
|
|
@@ -1169,7 +1421,9 @@ function dispatchPendingPrompt(terminal, pending) {
|
|
|
1169
1421
|
return terminal.editor({
|
|
1170
1422
|
message,
|
|
1171
1423
|
...value !== void 0 ? { default: (0, _orkestrel_console.stripControls)(value) } : {},
|
|
1172
|
-
...validate !== void 0 ? { validate } : {}
|
|
1424
|
+
...validate !== void 0 ? { validate } : {},
|
|
1425
|
+
...hint !== void 0 ? { hint } : {},
|
|
1426
|
+
...theme !== void 0 ? { theme } : {}
|
|
1173
1427
|
});
|
|
1174
1428
|
}
|
|
1175
1429
|
}
|
|
@@ -1198,19 +1452,6 @@ function isAbortError(error) {
|
|
|
1198
1452
|
return (error instanceof DOMException || error instanceof Error) && error.name === "AbortError";
|
|
1199
1453
|
}
|
|
1200
1454
|
/**
|
|
1201
|
-
* Parse a JSON wire string TOTAL — a malformed / empty payload yields `undefined` (the caller's
|
|
1202
|
-
* guard then rejects it), never a throw. The {@link import('./PromptClient.js').PromptClient}
|
|
1203
|
-
* decodes every SSE `data` field through this before §14-narrowing it.
|
|
1204
|
-
*/
|
|
1205
|
-
function parseWireJSON(text) {
|
|
1206
|
-
if (text.length === 0) return void 0;
|
|
1207
|
-
try {
|
|
1208
|
-
return JSON.parse(text);
|
|
1209
|
-
} catch {
|
|
1210
|
-
return;
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
/**
|
|
1214
1455
|
* Whether `url` is an INSECURE remote endpoint — a plain `http://` URL whose host is NOT a
|
|
1215
1456
|
* loopback address. Pure string parsing (no `URL` global), so it stays total on malformed input.
|
|
1216
1457
|
*
|
|
@@ -1281,9 +1522,9 @@ function isAnswerPayload(value) {
|
|
|
1281
1522
|
* ({@link serializePromptOptions}) so a transport can forward them as-is.
|
|
1282
1523
|
* - **Answer validates + type-checks.** {@link answer} runs the prompt's per-form gate: it
|
|
1283
1524
|
* type-checks `value` to the form (string / boolean / string[]) AND, for the text forms, runs
|
|
1284
|
-
* the validator resolved from the original `validate` rules. A rejected answer returns
|
|
1285
|
-
* and the prompt stays `pending`; an accepted answer resolves the
|
|
1286
|
-
* removes the prompt.
|
|
1525
|
+
* the validator resolved from the original `validate` rules. A rejected answer returns a failure
|
|
1526
|
+
* `Result` with error `'rejected'` and the prompt stays `pending`; an accepted answer resolves the
|
|
1527
|
+
* Promise, emits `answer`, and removes the prompt.
|
|
1287
1528
|
* - **Timeout → expire → reject.** An unanswered prompt expires after `timeout` ms (via the
|
|
1288
1529
|
* INJECTED timer): `expire` fires and the parked Promise rejects with a {@link TerminalError}
|
|
1289
1530
|
* (`code: 'EXPIRE'`). {@link destroy} expires every still-pending prompt the same way.
|
|
@@ -1632,12 +1873,12 @@ var PromptClient = class {
|
|
|
1632
1873
|
}
|
|
1633
1874
|
async #handle(event) {
|
|
1634
1875
|
if (event.event === SSE_EVENTS.pending) {
|
|
1635
|
-
const parsed =
|
|
1876
|
+
const parsed = (0, _orkestrel_contract.parseJSON)(event.data);
|
|
1636
1877
|
if (isPendingPrompt(parsed) && !this.#seen.has(parsed.id)) await this.#dispatch(parsed.id, parsed);
|
|
1637
1878
|
return;
|
|
1638
1879
|
}
|
|
1639
1880
|
if (event.event === SSE_EVENTS.expire) {
|
|
1640
|
-
const parsed =
|
|
1881
|
+
const parsed = (0, _orkestrel_contract.parseJSON)(event.data);
|
|
1641
1882
|
if ((0, _orkestrel_contract.isRecord)(parsed) && (0, _orkestrel_contract.isString)(parsed.id)) {
|
|
1642
1883
|
this.#seen.delete(parsed.id);
|
|
1643
1884
|
this.#emitter.emit("expire", parsed.id);
|
|
@@ -1715,9 +1956,9 @@ var PromptClient = class {
|
|
|
1715
1956
|
* - **Durable open / save.** `open(name)` restores an EMPTY broker from the `store` (parked
|
|
1716
1957
|
* Promises are process-bound and never resurrected); `save(name)` persists the endpoint's
|
|
1717
1958
|
* configured `timeout`.
|
|
1718
|
-
* - **Removal.** `remove` drops one endpoint
|
|
1719
|
-
*
|
|
1720
|
-
* idempotent.
|
|
1959
|
+
* - **Removal.** `remove` drops one endpoint, a batch (§9.2, array overload FIRST), or every
|
|
1960
|
+
* endpoint when called without an argument. It destroys each broker, which expires every prompt
|
|
1961
|
+
* still parked on it. `destroy` is idempotent.
|
|
1721
1962
|
*
|
|
1722
1963
|
* @example
|
|
1723
1964
|
* ```ts
|
|
@@ -1856,6 +2097,10 @@ var TerminalManager = class {
|
|
|
1856
2097
|
return true;
|
|
1857
2098
|
}
|
|
1858
2099
|
remove(names) {
|
|
2100
|
+
if (names === void 0) {
|
|
2101
|
+
for (const name of [...this.#terminals.keys()]) this.#removeOne(name);
|
|
2102
|
+
return;
|
|
2103
|
+
}
|
|
1859
2104
|
if ((0, _orkestrel_contract.isArray)(names)) {
|
|
1860
2105
|
let removed = false;
|
|
1861
2106
|
for (const name of names) if (this.#removeOne(name)) removed = true;
|
|
@@ -1863,13 +2108,10 @@ var TerminalManager = class {
|
|
|
1863
2108
|
}
|
|
1864
2109
|
return this.#removeOne(names);
|
|
1865
2110
|
}
|
|
1866
|
-
clear() {
|
|
1867
|
-
for (const name of [...this.#terminals.keys()]) this.#removeOne(name);
|
|
1868
|
-
}
|
|
1869
2111
|
destroy() {
|
|
1870
2112
|
if (this.#destroyed) return;
|
|
1871
2113
|
this.#destroyed = true;
|
|
1872
|
-
this.
|
|
2114
|
+
this.remove();
|
|
1873
2115
|
this.#emitter.destroy();
|
|
1874
2116
|
}
|
|
1875
2117
|
#createPendingListener() {
|
|
@@ -2174,11 +2416,11 @@ exports.CTRL_D = CTRL_D;
|
|
|
2174
2416
|
exports.CTRL_E = CTRL_E;
|
|
2175
2417
|
exports.CTRL_U = CTRL_U;
|
|
2176
2418
|
exports.DEFAULT_MASK = DEFAULT_MASK;
|
|
2419
|
+
exports.DEFAULT_PROMPT_THEME = DEFAULT_PROMPT_THEME;
|
|
2177
2420
|
exports.DEFAULT_PROMPT_TIMEOUT_MS = DEFAULT_PROMPT_TIMEOUT_MS;
|
|
2178
2421
|
exports.DEFAULT_RECONNECT_DELAY_MS = DEFAULT_RECONNECT_DELAY_MS;
|
|
2179
2422
|
exports.DELETE = DELETE;
|
|
2180
2423
|
exports.DatabaseTerminalStore = DatabaseTerminalStore;
|
|
2181
|
-
exports.EMAIL_PATTERN = EMAIL_PATTERN;
|
|
2182
2424
|
exports.ESCAPE = ESCAPE;
|
|
2183
2425
|
exports.HEADER_TOKEN = HEADER_TOKEN;
|
|
2184
2426
|
exports.INTEGER_PATTERN = INTEGER_PATTERN;
|
|
@@ -2188,6 +2430,7 @@ exports.MemoryTerminalStore = MemoryTerminalStore;
|
|
|
2188
2430
|
exports.NEWLINE = NEWLINE;
|
|
2189
2431
|
exports.NUMERIC_PATTERN = NUMERIC_PATTERN;
|
|
2190
2432
|
exports.PROMPT_ICONS = PROMPT_ICONS;
|
|
2433
|
+
exports.PROMPT_ROLES = PROMPT_ROLES;
|
|
2191
2434
|
exports.Prompt = Prompt;
|
|
2192
2435
|
exports.PromptClient = PromptClient;
|
|
2193
2436
|
exports.RETURN = RETURN;
|
|
@@ -2216,6 +2459,7 @@ exports.createMemoryTerminalStore = createMemoryTerminalStore;
|
|
|
2216
2459
|
exports.createPasswordState = createPasswordState;
|
|
2217
2460
|
exports.createPrompt = createPrompt;
|
|
2218
2461
|
exports.createPromptClient = createPromptClient;
|
|
2462
|
+
exports.createPromptTheme = createPromptTheme;
|
|
2219
2463
|
exports.createSelectState = createSelectState;
|
|
2220
2464
|
exports.createTerminalManager = createTerminalManager;
|
|
2221
2465
|
exports.defaultTimer = defaultTimer;
|
|
@@ -2227,6 +2471,7 @@ exports.errorLine = errorLine;
|
|
|
2227
2471
|
exports.evaluateRule = evaluateRule;
|
|
2228
2472
|
exports.gateSelection = gateSelection;
|
|
2229
2473
|
exports.globalFetch = globalFetch;
|
|
2474
|
+
exports.hintedHeader = hintedHeader;
|
|
2230
2475
|
exports.inputReduce = inputReduce;
|
|
2231
2476
|
exports.inputView = inputView;
|
|
2232
2477
|
exports.isAbortError = isAbortError;
|
|
@@ -2237,13 +2482,14 @@ exports.isPendingPrompt = isPendingPrompt;
|
|
|
2237
2482
|
exports.isPendingPromptStatus = isPendingPromptStatus;
|
|
2238
2483
|
exports.isPrintable = isPrintable;
|
|
2239
2484
|
exports.isPromptChoice = isPromptChoice;
|
|
2485
|
+
exports.isPromptThemeOptions = isPromptThemeOptions;
|
|
2240
2486
|
exports.isPromptType = isPromptType;
|
|
2487
|
+
exports.isStyle = isStyle;
|
|
2241
2488
|
exports.isTerminalError = isTerminalError;
|
|
2242
2489
|
exports.isTerminalSnapshot = isTerminalSnapshot;
|
|
2243
2490
|
exports.normalizeCheckboxChoice = normalizeCheckboxChoice;
|
|
2244
2491
|
exports.normalizeChoice = normalizeChoice;
|
|
2245
2492
|
exports.parseKey = parseKey;
|
|
2246
|
-
exports.parseWireJSON = parseWireJSON;
|
|
2247
2493
|
exports.passing = passing;
|
|
2248
2494
|
exports.passwordReduce = passwordReduce;
|
|
2249
2495
|
exports.passwordView = passwordView;
|
|
@@ -2253,6 +2499,8 @@ exports.resolveChoices = resolveChoices;
|
|
|
2253
2499
|
exports.resolveOption = resolveOption;
|
|
2254
2500
|
exports.resolveValidation = resolveValidation;
|
|
2255
2501
|
exports.sanitizeChoiceLabels = sanitizeChoiceLabels;
|
|
2502
|
+
exports.sanitizeDisplayText = sanitizeDisplayText;
|
|
2503
|
+
exports.sanitizeThemeIcons = sanitizeThemeIcons;
|
|
2256
2504
|
exports.selectReduce = selectReduce;
|
|
2257
2505
|
exports.selectView = selectView;
|
|
2258
2506
|
exports.serializeChoices = serializeChoices;
|