@orkestrel/terminal 0.0.2 → 0.0.3

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.
@@ -1,1690 +0,0 @@
1
- import { DriverInterface } from '@orkestrel/database';
2
- import { EmitterErrorHandler } from '@orkestrel/emitter';
3
- import { EmitterHooks } from '@orkestrel/emitter';
4
- import { EmitterInterface } from '@orkestrel/emitter';
5
- import { Guard } from '@orkestrel/contract';
6
- import { StylerInterface } from '@orkestrel/console';
7
- import { TableInterface } from '@orkestrel/database';
8
-
9
- /** The `Accept` header value that opens the broker's SSE stream. */
10
- export declare const ACCEPT_EVENT_STREAM = "text/event-stream";
11
-
12
- /** Matches an alphanumeric string (letters and digits only). The `alphanumeric` rule tests against this. */
13
- export declare const ALPHANUMERIC_PATTERN: RegExp;
14
-
15
- /** The rejection reason a bare {@link PromptInterface.answer} returns — `'unknown'` (no such parked prompt) or `'rejected'` (failed validation / type-check). */
16
- export declare type AnswerError = 'unknown' | 'rejected';
17
-
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
- /**
28
- * Append a rule-backed {@link Validator} to `validators` when the rule is enabled — a `false` /
29
- * `undefined` `check` is skipped, a function `check` is added verbatim (the custom override), and
30
- * a primitive `check` is wrapped via {@link buildRuleValidator}. Mutates `validators` in place.
31
- */
32
- export declare function appendRule(validators: Validator[], rule: string, check: boolean | number | string | Validator | undefined): void;
33
-
34
- /** Backspace (BS, U+0008) — Ctrl+H / some terminals' Backspace. */
35
- export declare const BACKSPACE: string;
36
-
37
- /** Wrap a named rule + its primitive check into a {@link Validator} (returns `true` or the rule's message). */
38
- export declare function buildRuleValidator(rule: string, check: boolean | number | string): Validator;
39
-
40
- /** A choice item in a {@link CheckboxOptions} prompt — a {@link PromptChoice} plus an optional initial `checked` state. */
41
- export declare interface CheckboxChoice {
42
- readonly name: string;
43
- readonly value: string;
44
- readonly description?: string;
45
- readonly checked?: boolean;
46
- }
47
-
48
- /**
49
- * Options for a multi-selection {@link import('./helpers.js').checkboxReduce} prompt.
50
- *
51
- * @remarks
52
- * `choices` accepts bare strings or full {@link CheckboxChoice} objects (with an optional
53
- * initial `checked`); {@link import('./helpers.js').createCheckboxState} normalizes them.
54
- * `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).
56
- */
57
- export declare interface CheckboxOptions {
58
- readonly message: string;
59
- readonly choices: readonly (string | CheckboxChoice)[];
60
- readonly min?: number;
61
- readonly max?: number;
62
- readonly styler?: StylerInterface;
63
- }
64
-
65
- /**
66
- * Advance a checkbox prompt by one {@link KeyEvent} — the pure
67
- * `(state, key) → PromptStep<readonly string[]>` reducer. `up` / `down` (and `k` / `j`) move the
68
- * focus (wrapping); `space` toggles the focused index in the checked set; return submits the
69
- * checked values in CHOICE order — gated by `min` / `max` (an out-of-range count stays active with
70
- * the reason in the view); ctrl-c cancels.
71
- */
72
- export declare function checkboxReduce(state: CheckboxState, key: KeyEvent): PromptStep<readonly string[], CheckboxState>;
73
-
74
- /**
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`.
77
- *
78
- * @remarks
79
- * Built by {@link import('./helpers.js').createCheckboxState}; advanced by
80
- * {@link import('./helpers.js').checkboxReduce}. `up` / `down` move `focus` (wrapping); `space`
81
- * toggles the focused index in `checked`; `return` submits the checked values in choice order
82
- * (rejected, with `error`, when the count is outside `[min, max]`). `checked` is modelled as a
83
- * readonly index array (plain JSON data, copy-on-write — no `Set` to clone).
84
- */
85
- export declare interface CheckboxState {
86
- readonly message: string;
87
- readonly choices: readonly CheckboxChoice[];
88
- readonly styler: StylerInterface;
89
- readonly focused: number;
90
- readonly checked: readonly number[];
91
- readonly min?: number;
92
- readonly max?: number;
93
- readonly error?: string;
94
- }
95
-
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. */
97
- export declare function checkboxView(state: CheckboxState): string;
98
-
99
- /**
100
- * Compose several {@link Validator}s into ONE short-circuiting validator — it runs them in order
101
- * and returns the FIRST error message, or `true` when all pass. The empty composition always
102
- * passes.
103
- */
104
- export declare function composeValidators(...validators: Validator[]): Validator;
105
-
106
- /** Options for a yes/no {@link import('./helpers.js').confirmReduce} confirmation prompt. */
107
- export declare interface ConfirmOptions {
108
- readonly message: string;
109
- readonly default?: boolean;
110
- readonly styler?: StylerInterface;
111
- }
112
-
113
- /**
114
- * Advance a confirm prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<boolean>`
115
- * reducer. `y` / `Y` submits `true`, `n` / `N` submits `false`, return on an empty line submits
116
- * the `default`, ctrl-c cancels; any other key is ignored (stays active).
117
- */
118
- export declare function confirmReduce(state: ConfirmState, key: KeyEvent): PromptStep<boolean, ConfirmState>;
119
-
120
- /**
121
- * The immutable state of a confirm prompt — its message, the default answer, and the styler.
122
- *
123
- * @remarks
124
- * Built by {@link import('./helpers.js').createConfirmState}; advanced by
125
- * {@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).
128
- */
129
- export declare interface ConfirmState {
130
- readonly message: string;
131
- readonly default: boolean;
132
- readonly styler: StylerInterface;
133
- }
134
-
135
- /** Render a {@link ConfirmState} as a styled view — the header plus a `(Y/n)` hint with the default letter emphasized. */
136
- export declare function confirmView(state: ConfirmState): string;
137
-
138
- /**
139
- * The single control BYTE → key descriptor table {@link import('./helpers.js').parseKey}
140
- * consults for the one-byte keys. Each entry carries the canonical `name` and whether it is a
141
- * `ctrl` combination. The source of truth for the single-byte key decode; frozen.
142
- *
143
- * @remarks
144
- * `return` / `newline` map to `return` (one canonical Enter name); `delete` / `backspace` both
145
- * map to `backspace` (the two Backspace bytes); the Ctrl combos (`c` / `d` / `u` / `a` / `e`)
146
- * carry `ctrl: true` so a reducer can match `key.ctrl && key.name === 'c'`. `escape` / `tab` /
147
- * `space` are plain named keys.
148
- */
149
- export declare const CONTROL_NAMES: Readonly<Record<string, {
150
- readonly name: string;
151
- readonly ctrl: boolean;
152
- }>>;
153
-
154
- /** Build the initial {@link CheckboxState} from {@link CheckboxOptions} — normalizing choices, seeding the checked set, carrying min/max. */
155
- export declare function createCheckboxState(options: CheckboxOptions): CheckboxState;
156
-
157
- /** Build the initial {@link ConfirmState} from {@link ConfirmOptions} — defaulting the answer to `false`. */
158
- export declare function createConfirmState(options: ConfirmOptions): ConfirmState;
159
-
160
- /**
161
- * Create a {@link TerminalStoreInterface} backed by one table of the `databases` layer — the
162
- * driver-pluggable twin of {@link createMemoryTerminalStore}, storing each endpoint's config
163
- * snapshot as one opaque JSON column.
164
- *
165
- * @param driver - The {@link DriverInterface} backing the table (default an in-memory driver)
166
- * @returns A {@link TerminalStoreInterface}
167
- *
168
- * @example
169
- * ```ts
170
- * import { createDatabaseTerminalStore } from '@src/core'
171
- *
172
- * const store = createDatabaseTerminalStore() // in-memory by default
173
- * ```
174
- */
175
- export declare function createDatabaseTerminalStore(driver?: DriverInterface): TerminalStoreInterface;
176
-
177
- /** Build the initial {@link EditorState} from {@link EditorOptions} — resolving the validator + styler, seeding empty lines. */
178
- export declare function createEditorState(options: EditorOptions): EditorState;
179
-
180
- /** Build the initial {@link InputState} from {@link InputOptions} — resolving the validator + styler, seeding an empty value. */
181
- export declare function createInputState(options: InputOptions): InputState;
182
-
183
- /**
184
- * Create the in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of endpoint
185
- * config snapshots, the default store backing a {@link TerminalManagerInterface}'s `open` / `save`.
186
- *
187
- * @returns A {@link TerminalStoreInterface}
188
- *
189
- * @example
190
- * ```ts
191
- * import { createMemoryTerminalStore } from '@src/core'
192
- *
193
- * const store = createMemoryTerminalStore()
194
- * ```
195
- */
196
- export declare function createMemoryTerminalStore(): TerminalStoreInterface;
197
-
198
- /** Build the initial {@link PasswordState} from {@link PasswordOptions} — resolving the validator + styler + mask. */
199
- export declare function createPasswordState(options: PasswordOptions): PasswordState;
200
-
201
- /**
202
- * Create the headless prompt {@link PromptInterface} BROKER — it parks each prompt call as a
203
- * pending prompt and resolves it when {@link PromptInterface.answer} arrives (or rejects on
204
- * timeout). The tri-surface's headless arm: subscribe `emitter.on('pending', …)` to forward each
205
- * prompt to whoever can answer (an SSE transport, a remote terminal), then route the answer back
206
- * through `answer(id, value)`.
207
- *
208
- * @param options - See {@link PromptOptions}
209
- * @returns A {@link PromptInterface}
210
- *
211
- * @remarks
212
- * - **Park-as-Promise.** `await prompt.input({ message })` blocks until `answer(id, value)` accepts
213
- * a matching value; the value is validated (text forms) and type-checked to the form first.
214
- * - **Timeout → expire → reject (deterministic).** An unanswered prompt expires after
215
- * `options.timeout` (default {@link import('./constants.js').DEFAULT_PROMPT_TIMEOUT_MS}) and its
216
- * Promise rejects with a {@link import('./errors.js').TerminalError}; inject `options.timer` to
217
- * drive expiry without real time.
218
- *
219
- * @example
220
- * ```ts
221
- * import { createPrompt } from '@src/core'
222
- *
223
- * const prompt = createPrompt()
224
- * prompt.emitter.on('pending', (pending) => send(pending)) // forward to a remote client
225
- * const name = await prompt.input({ message: 'Your name', validate: { required: true } })
226
- * ```
227
- */
228
- export declare function createPrompt(options?: PromptOptions): PromptInterface;
229
-
230
- /**
231
- * Create the SSE prompt {@link PromptClientInterface} BRIDGE — it connects to a remote broker's SSE
232
- * endpoint, dispatches each received prompt to a LOCAL {@link import('./types.js').PromptFormInterface}
233
- * terminal (so a human at this machine answers a prompt parked elsewhere), and POSTs the answer
234
- * back. Universal — `fetch` / SSE are web-standard.
235
- *
236
- * @param options - See {@link PromptClientOptions} (`url` + `terminal` required)
237
- * @returns A {@link PromptClientInterface}
238
- *
239
- * @remarks
240
- * - **Connect + reconnect.** `await client.connect()` streams remote prompts until the stream
241
- * ends; it reconnects with the `delay` backoff unless `reconnect` is `false` / the client was
242
- * `destroy`ed. Inject `options.fetch` (a scripted `fetch`) and `options.timer` to drive it
243
- * deterministically in tests — no real network.
244
- * - **§14 wire narrowing.** Every decoded prompt is guard-narrowed before dispatch (never an `as`).
245
- *
246
- * @example
247
- * ```ts
248
- * import { createPromptClient } from '@src/core'
249
- *
250
- * const client = createPromptClient({ url: 'http://host/prompts', terminal })
251
- * await client.connect()
252
- * ```
253
- */
254
- export declare function createPromptClient(options: PromptClientOptions): PromptClientInterface;
255
-
256
- /** Build the initial {@link SelectState} from {@link SelectOptions} — normalizing choices and pre-focusing the default. */
257
- export declare function createSelectState(options: SelectOptions): SelectState;
258
-
259
- /**
260
- * Create the multi-endpoint {@link TerminalManagerInterface} — a named registry of
261
- * {@link PromptInterface} brokers so several parties can `ask` prompts of each other by name,
262
- * with a transitive DEADLOCK check across every in-flight ask.
263
- *
264
- * @param options - See {@link TerminalManagerOptions}
265
- * @returns A {@link TerminalManagerInterface}
266
- *
267
- * @example
268
- * ```ts
269
- * import { createTerminalManager } from '@src/core'
270
- *
271
- * const manager = createTerminalManager()
272
- * manager.add('agent')
273
- * ```
274
- */
275
- export declare function createTerminalManager(options?: TerminalManagerOptions): TerminalManagerInterface;
276
-
277
- /** Ctrl+A (SOH, U+0001) — move to start of line. */
278
- export declare const CTRL_A: string;
279
-
280
- /** Ctrl+C (ETX, U+0003) — interrupt / cancel. */
281
- export declare const CTRL_C: string;
282
-
283
- /** Ctrl+D (EOT, U+0004) — end-of-transmission / finish (the editor's commit key). */
284
- export declare const CTRL_D: string;
285
-
286
- /** Ctrl+E (ENQ, U+0005) — move to end of line. */
287
- export declare const CTRL_E: string;
288
-
289
- /** Ctrl+U (NAK, U+0015) — clear the current line. */
290
- export declare const CTRL_U: string;
291
-
292
- /**
293
- * A {@link TerminalStoreInterface} backed by one table of the `databases` layer — an endpoint's
294
- * durable CONFIG state IS a row, so persistence reduces to keyed point-access (`get` / `set` /
295
- * `delete`) over a {@link TableInterface}, the driver-pluggable twin of the plain-`Map`
296
- * {@link import('./MemoryTerminalStore.js').MemoryTerminalStore}.
297
- *
298
- * @remarks
299
- * The store is driver-agnostic: it holds a single {@link TableInterface} whose backend (memory,
300
- * JSON, SQLite, IndexedDB) is chosen by whoever builds it (the factories), so a JSON / SQLite /
301
- * IndexedDB backend swaps in WITHOUT touching the manager — the same seam as
302
- * {@link import('./MemoryTerminalStore.js').MemoryTerminalStore}. The driver defaults to memory
303
- * ({@link import('./factories.js').createDatabaseTerminalStore} passes `createMemoryDriver()`), so
304
- * it ALSO works in memory out of the box; you opt into the durable plumbing by passing a JSON /
305
- * SQLite / IndexedDB driver.
306
- *
307
- * The {@link TerminalSnapshot} is stored as ONE OPAQUE JSON COLUMN — the table is a row of
308
- * `{ id; snapshot }` ({@link TerminalSnapshotRow}). The snapshot is already a COMPLETE,
309
- * self-contained, pure-JSON CONFIG payload (no live broker state), so storing it whole is lossless
310
- * AND keeps the row type flat (`snapshot` reads back as `unknown`).
311
- *
312
- * - **`set(snapshot)` upserts under the snapshot's OWN `id`** (no separate id param) — it writes
313
- * the row `{ id: snapshot.id, snapshot }`.
314
- * - **`get(id)` resolves the stored snapshot for an id**, narrowing the opaque JSON column back to
315
- * a {@link TerminalSnapshot} ({@link import('./helpers.js').isTerminalSnapshot} — the AGENTS §14
316
- * boundary narrow for an untrusted storage read), or `undefined` if none is stored.
317
- * - **`delete(id)` drops a snapshot by id**; an absent id is a no-op (no throw).
318
- *
319
- * There is NO idle-TTL / eviction — a persisted config lives until an explicit `delete`. The public
320
- * surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method bijection with
321
- * {@link TerminalStoreInterface}). Hydration stays a caller concern: `open` always restores an EMPTY
322
- * broker — parked Promises are process-bound and never resurrected.
323
- *
324
- * @example
325
- * ```ts
326
- * import { createDatabaseTerminalStore, createMemoryDriver } from '@src/core'
327
- *
328
- * const store = createDatabaseTerminalStore(createMemoryDriver()) // a durable driver swaps in here
329
- * await store.set({ id: 'shell', timeout: 5000 }) // persist the config (one JSON column)
330
- * const snapshot = await store.get('shell')
331
- * await store.delete('shell') // drop it
332
- * ```
333
- */
334
- export declare class DatabaseTerminalStore implements TerminalStoreInterface {
335
- #private;
336
- /**
337
- * Wrap a table as a terminal store.
338
- *
339
- * @param table - The {@link TableInterface} holding the snapshots — its row is the
340
- * {@link TerminalSnapshotRow} `{ id; snapshot }` shape (the snapshot one opaque JSON column)
341
- */
342
- constructor(table: TableInterface<TerminalSnapshotRow>);
343
- /** Resolve the persisted snapshot for `id`, narrowing the opaque JSON column back to a `TerminalSnapshot`. */
344
- get(id: string): Promise<TerminalSnapshot | undefined>;
345
- /** Insert or replace under the snapshot's OWN `id` (no separate id param) — the row is `{ id, snapshot }`. */
346
- set(snapshot: TerminalSnapshot): Promise<void>;
347
- /** Drop a snapshot by id; an absent id is a no-op (no throw). */
348
- delete(id: string): Promise<void>;
349
- }
350
-
351
- /** The default mask glyph a {@link import('./types.js').PasswordState} renders each input character as — `*`. */
352
- export declare const DEFAULT_MASK = "*";
353
-
354
- /** How long (ms) the {@link import('./types.js').PromptInterface} broker parks an unanswered prompt before it expires — 5 minutes. */
355
- export declare const DEFAULT_PROMPT_TIMEOUT_MS = 300000;
356
-
357
- /** How long (ms) the {@link import('./types.js').PromptClientInterface} waits before each reconnect attempt — 2 seconds. */
358
- export declare const DEFAULT_RECONNECT_DELAY_MS = 2000;
359
-
360
- /**
361
- * The default {@link import('./types.js').TimerHandler} — a thin host `setTimeout` / `clearTimeout`
362
- * wrapper that arms `callback` after `ms` and returns a {@link TimerCancel}. The deadline seam
363
- * behind both the {@link import('./Prompt.js').Prompt} broker (its expiry) and the
364
- * {@link import('./PromptClient.js').PromptClient} (its reconnect backoff); a test injects a
365
- * deterministic timer instead, so neither entity touches real time.
366
- */
367
- export declare function defaultTimer(callback: () => void, ms: number): TimerCancel;
368
-
369
- /** Delete (DEL, U+007F) — the usual Backspace byte on a Unix TTY. */
370
- export declare const DELETE: string;
371
-
372
- /**
373
- * Dispatch a {@link PendingPrompt} to the matching {@link PromptFormInterface} method — the bridge
374
- * step a {@link PromptClient} runs to drive a LOCAL terminal with a prompt issued elsewhere.
375
- * Reconstructs typed options from the wire-safe {@link PendingPrompt.options} (every field
376
- * §14-narrowed, never an `as`; the validator rebuilt from rules via {@link reconstructValidationRules}),
377
- * then calls the matching prompt form and returns its resolved value.
378
- *
379
- * @param terminal - The local {@link PromptFormInterface} to drive
380
- * @param pending - The decoded pending prompt to dispatch
381
- * @returns The prompt's resolved value (a `string` / `boolean` / `readonly string[]` per form)
382
- */
383
- export declare function dispatchPendingPrompt(terminal: PromptFormInterface, pending: PendingPrompt): Promise<string | boolean | readonly string[]>;
384
-
385
- /**
386
- * Apply a single line-editing {@link KeyEvent} to a text buffer — the editing shared by input /
387
- * password / editor. A printable key appends its character; `backspace` drops the last character;
388
- * `space` appends a space; ctrl-u clears the line. Returns the new buffer, or `undefined` when the
389
- * key does not edit the line (so the caller can leave the state untouched).
390
- */
391
- export declare function editLine(value: string, key: KeyEvent): string | undefined;
392
-
393
- /** Options for a multi-line {@link import('./helpers.js').editorReduce} editor prompt (terminated by ctrl-d). */
394
- export declare interface EditorOptions {
395
- readonly message: string;
396
- readonly default?: string;
397
- readonly validate?: Validator | ValidationRules;
398
- readonly styler?: StylerInterface;
399
- }
400
-
401
- /**
402
- * Advance an editor prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`
403
- * reducer. Printable characters extend the current line; backspace shrinks it; return commits the
404
- * current line and starts a fresh one; ctrl-d FINISHES (joining all lines, falling back to the
405
- * default when empty) through the validator; ctrl-c cancels. An invalid finish stays active with
406
- * the error.
407
- */
408
- export declare function editorReduce(state: EditorState, key: KeyEvent): PromptStep<string, EditorState>;
409
-
410
- /**
411
- * 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`.
413
- *
414
- * @remarks
415
- * Built by {@link import('./helpers.js').createEditorState}; advanced by
416
- * {@link import('./helpers.js').editorReduce}. A printable key appends to `current`; `return`
417
- * commits `current` to `lines` and starts a fresh line; ctrl-d finishes, submitting
418
- * `lines + current` joined by newlines (or `default` when empty). The whole text is validated
419
- * on finish.
420
- */
421
- export declare interface EditorState {
422
- readonly message: string;
423
- readonly default: string;
424
- readonly validator: Validator;
425
- readonly styler: StylerInterface;
426
- readonly lines: readonly string[];
427
- readonly current: string;
428
- readonly error?: string;
429
- }
430
-
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. */
432
- export declare function editorView(state: EditorState): string;
433
-
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;
439
-
440
- /** Escape (ESC, U+001B) — the lone byte, and the lead byte of every CSI / SS3 sequence. */
441
- export declare const ESCAPE: string;
442
-
443
- /**
444
- * Evaluate ONE built-in validation rule against `input`, returning its error message when the
445
- * rule fails or `undefined` when it passes. The atomic check {@link buildRuleValidator} wraps
446
- * into a {@link Validator}. Pure.
447
- *
448
- * @remarks
449
- * A function `check` is the custom-override path: it is called and its `true` ⇒ pass, a string
450
- * ⇒ that message, anything else ⇒ the generic {@link RULE_MESSAGES.invalid}. A primitive `check`
451
- * runs the named built-in: `required` (non-empty trimmed), `minimum` / `maximum` (length
452
- * bounds, the message interpolated with the count), `pattern` (a regex source), and the
453
- * `email` / `url` / `numeric` / `integer` / `alphanumeric` pattern tests.
454
- *
455
- * @param rule - The rule name (`'required'`, `'minimum'`, …)
456
- * @param check - The configured value (a primitive toggle / bound / pattern, or a custom {@link Validator})
457
- * @param input - The input string to test
458
- * @returns The error message when the rule fails, else `undefined`
459
- */
460
- export declare function evaluateRule(rule: string, check: boolean | number | string | Validator, input: string): string | undefined;
461
-
462
- /**
463
- * A minimal `fetch` — the subset of the global `fetch` the {@link PromptClient} uses (open the
464
- * SSE stream, POST an answer). Injected so a test drives the client with a controlled
465
- * `Response` (a scripted SSE `ReadableStream`) instead of a real network.
466
- */
467
- export declare type FetchHandler = (input: string, init?: FetchInit) => Promise<Response>;
468
-
469
- /**
470
- * The request init the {@link PromptClient} passes to its {@link FetchHandler} — the `fetch`
471
- * `RequestInit` fields it actually sets (method / headers / body / abort signal).
472
- */
473
- export declare interface FetchInit {
474
- readonly method?: string;
475
- readonly headers?: Readonly<Record<string, string>>;
476
- readonly body?: string;
477
- readonly signal?: AbortSignal;
478
- }
479
-
480
- /** The min/max gate for a checkbox submit — the rejection message when `count` is out of range, else `undefined`. */
481
- export declare function gateSelection(count: number, min?: number, max?: number): string | undefined;
482
-
483
- /** The default {@link import('./types.js').FetchHandler} — the global `fetch`, adapted to the minimal injected shape the {@link import('./PromptClient.js').PromptClient} uses. */
484
- export declare function globalFetch(input: string, init?: FetchInit): Promise<Response>;
485
-
486
- /** The auth-token request header the {@link import('./types.js').PromptClient} sends when a `token` is configured. */
487
- export declare const HEADER_TOKEN = "x-orkestrel-token";
488
-
489
- /** Options for a single-line text {@link import('./helpers.js').inputReduce} prompt. */
490
- export declare interface InputOptions {
491
- readonly message: string;
492
- readonly default?: string;
493
- readonly validate?: Validator | ValidationRules;
494
- readonly styler?: StylerInterface;
495
- }
496
-
497
- /**
498
- * Advance an input prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`
499
- * reducer. Printable characters extend the value; backspace shrinks it; ctrl-u clears it; ctrl-c
500
- * cancels; return submits (the empty line falls back to the default) through the validator — an
501
- * invalid submit stays active with the error in the view.
502
- */
503
- export declare function inputReduce(state: InputState, key: KeyEvent): PromptStep<string, InputState>;
504
-
505
- /**
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).
508
- *
509
- * @remarks
510
- * Built by {@link import('./helpers.js').createInputState}; advanced by
511
- * {@link import('./helpers.js').inputReduce}. `value` accumulates printable characters and
512
- * shrinks on backspace; `error` holds the validation message shown in the view after a
513
- * rejected submit (cleared on the next keystroke).
514
- */
515
- export declare interface InputState {
516
- readonly message: string;
517
- readonly default: string;
518
- readonly validator: Validator;
519
- readonly styler: StylerInterface;
520
- readonly value: string;
521
- readonly error?: string;
522
- }
523
-
524
- /** Render an {@link InputState} as a styled view — the header, the typed value (or dimmed default hint), and any error. */
525
- export declare function inputView(state: InputState): string;
526
-
527
- /** Matches an integer (optional sign). The `integer` rule tests against this. */
528
- export declare const INTEGER_PATTERN: RegExp;
529
-
530
- /**
531
- * Whether a caught value is an `AbortError` — the {@link import('./PromptClient.js').PromptClient}
532
- * distinguishes a deliberate `disconnect` / teardown (an aborted `fetch`) from a real fault, so it
533
- * exits its connect loop quietly instead of emitting `error` / reconnecting.
534
- */
535
- export declare function isAbortError(error: unknown): boolean;
536
-
537
- /** Narrow an unknown wire payload to an answer POST body — a non-empty `id` string plus a `value` key (of any shape) present. */
538
- export declare function isAnswerPayload(value: unknown): value is {
539
- readonly id: string;
540
- readonly value: unknown;
541
- };
542
-
543
- /** Narrow an unknown value to a {@link CheckboxChoice} — the `recordOf` shape inlined so no non-exported member lingers (§5). */
544
- export declare function isCheckboxChoice(value: unknown): value is CheckboxChoice;
545
-
546
- /**
547
- * Whether `url` is an INSECURE remote endpoint — a plain `http://` URL whose host is NOT a
548
- * loopback address. Pure string parsing (no `URL` global), so it stays total on malformed input.
549
- *
550
- * @remarks
551
- * A loopback host (`localhost`, `127.0.0.1`, `[::1]`) over `http://` is exempt (local
552
- * development has no network hop to eavesdrop on); every other `http://` host is insecure.
553
- * An `https://` URL (or any non-`http://` scheme) is never flagged.
554
- *
555
- * @param url - The candidate endpoint URL
556
- * @returns `true` when `url` is a non-loopback `http://` endpoint
557
- *
558
- * @example
559
- * ```ts
560
- * isInsecureRemote('http://example.com') // true
561
- * isInsecureRemote('http://localhost:3000') // false
562
- * isInsecureRemote('https://example.com') // false
563
- * ```
564
- */
565
- export declare function isInsecureRemote(url: string): boolean;
566
-
567
- /**
568
- * Narrow an unknown wire value to a {@link PendingPrompt} — the §14 guard a {@link PromptClient}
569
- * applies to each decoded SSE `pending` payload before dispatching it (never an `as`).
570
- */
571
- export declare const isPendingPrompt: Guard<PendingPrompt>;
572
-
573
- /** Narrow an unknown value to a {@link PendingPromptStatus}. */
574
- export declare const isPendingPromptStatus: Guard<PendingPromptStatus>;
575
-
576
- /** Whether a single character is a printable (non-control) character — used by {@link parseKey}'s char fallback. */
577
- export declare function isPrintable(character: string): boolean;
578
-
579
- /** Narrow an unknown value to a {@link PromptChoice} — the `recordOf` shape inlined so no non-exported member lingers (§5). */
580
- export declare function isPromptChoice(value: unknown): value is PromptChoice;
581
-
582
- /** Narrow an unknown value to a {@link PromptType} — one of the six prompt forms. */
583
- export declare const isPromptType: Guard<PromptType>;
584
-
585
- /**
586
- * Narrow an unknown caught value to a {@link TerminalError}.
587
- *
588
- * @param value - The value to test (typically a `catch` binding or a rejected prompt call)
589
- * @returns `true` when `value` is a {@link TerminalError}
590
- *
591
- * @example
592
- * ```ts
593
- * try {
594
- * const name = await prompt.input({ message: 'Your name' })
595
- * } catch (error) {
596
- * if (isTerminalError(error) && error.code === 'EXPIRE') retryLater()
597
- * }
598
- * ```
599
- */
600
- export declare function isTerminalError(value: unknown): value is TerminalError;
601
-
602
- /** Narrow an unknown value to a {@link TerminalSnapshot} — a non-empty `id` plus an optional numeric `timeout`. */
603
- export declare const isTerminalSnapshot: Guard<TerminalSnapshot>;
604
-
605
- /**
606
- * The Control Sequence Introducer lead (`ESC[`) for the navigation keys — the prefix of the
607
- * arrow / home / end / delete sequences {@link SEQUENCE_NAMES} is keyed by. Named `KEY_CSI`
608
- * (not `CSI`) so it never collides with the console module's SGR `CSI` (both barrel through
609
- * `@src/core`).
610
- */
611
- export declare const KEY_CSI: string;
612
-
613
- /** The Single Shift Three lead (`ESCO`) — the alternate arrow-key prefix some terminals emit (`ESC O A`). */
614
- export declare const KEY_SS3: string;
615
-
616
- /**
617
- * One decoded keypress — the universal, TTY-agnostic representation of a single key, the
618
- * output of {@link import('./helpers.js').parseKey}. A reducer reads `name` (and the
619
- * modifier flags) to decide its transition; the raw `sequence` is preserved so a printable
620
- * character round-trips and an unknown escape is never lost.
621
- *
622
- * @remarks
623
- * - `name` — the canonical key name: a control / navigation key (`return`, `backspace`,
624
- * `tab`, `escape`, `up` / `down` / `left` / `right`, `space`, `home`, `end`, `delete`),
625
- * a named ctrl combo (`c` with `ctrl` true for ctrl-c, likewise `d` / `u` / `a` / `e`),
626
- * or the printable character itself (`'a'`, `'7'`, `'?'`). An UNRECOGNIZED sequence
627
- * yields `name: ''` (empty) — never a throw (the decoder is total).
628
- * - `sequence` — the exact input bytes as a string (a `Uint8Array` is decoded UTF-8). The
629
- * driver writes this verbatim for a printable key; a reducer that needs the literal char
630
- * reads it.
631
- * - `ctrl` / `meta` / `shift` — the modifier flags. `ctrl` is `true` for a C0 control byte
632
- * (ctrl-c / ctrl-d / ctrl-u / ctrl-a / ctrl-e and the like); `meta` is `true` for an
633
- * ESC-prefixed (Alt) sequence; `shift` is `true` for an uppercase-letter printable.
634
- */
635
- export declare interface KeyEvent {
636
- readonly name: string;
637
- readonly sequence: string;
638
- readonly ctrl: boolean;
639
- readonly meta: boolean;
640
- readonly shift: boolean;
641
- }
642
-
643
- /**
644
- * The in-memory {@link TerminalStoreInterface} — a process-lifetime `Map` of
645
- * {@link TerminalSnapshot}s keyed by endpoint id, the DEFAULT store
646
- * {@link import('./factories.js').createMemoryTerminalStore} builds. The EXACT twin of
647
- * {@link import('./DatabaseTerminalStore.js').DatabaseTerminalStore}.
648
- *
649
- * @remarks
650
- * A plain `Map<string, TerminalSnapshot>` (AGENTS §21 — the snapshot is already pure, self-contained
651
- * CONFIG-only JSON, so no encoding is needed for the memory tier). There is NO idle-TTL and NO
652
- * eviction: a persisted config lives until an explicit `delete`. A durable backend (JSON / SQLite /
653
- * IndexedDB) swaps in through the SAME interface without touching the manager — its
654
- * driver-pluggable twin is {@link import('./DatabaseTerminalStore.js').DatabaseTerminalStore} (the
655
- * snapshot as one opaque JSON column).
656
- *
657
- * - **`get` resolves the persisted snapshot for an id**, or `undefined` if none is stored.
658
- * - **`set` inserts / replaces under the snapshot's OWN `id`** (no separate id param).
659
- * - **`delete` drops a snapshot by id**; an absent id is a no-op (no throw).
660
- *
661
- * The public surface is EXACTLY `get` / `set` / `delete` — no extra members (the §22 method
662
- * bijection with {@link TerminalStoreInterface}). Hydration is a caller concern: `open` always
663
- * restores an EMPTY broker — parked Promises are process-bound and never resurrected.
664
- *
665
- * @example
666
- * ```ts
667
- * import { createMemoryTerminalStore } from '@src/core'
668
- *
669
- * const store = createMemoryTerminalStore()
670
- * await store.set({ id: 'shell', timeout: 5000 }) // persist a config
671
- * const snapshot = await store.get('shell')
672
- * await store.delete('shell') // drop it
673
- * ```
674
- */
675
- export declare class MemoryTerminalStore implements TerminalStoreInterface {
676
- #private;
677
- get(id: string): Promise<TerminalSnapshot | undefined>;
678
- set(snapshot: TerminalSnapshot): Promise<void>;
679
- delete(id: string): Promise<void>;
680
- }
681
-
682
- /** Line feed (`\n`, U+000A) — Enter on some terminals / pasted input. */
683
- export declare const NEWLINE: string;
684
-
685
- /** Normalize a checkbox choice input into a full {@link CheckboxChoice} (a bare string becomes both name and value). */
686
- export declare function normalizeCheckboxChoice(choice: string | CheckboxChoice): CheckboxChoice;
687
-
688
- /** Normalize a select choice input into a full {@link PromptChoice} (a bare string becomes both name and value). */
689
- export declare function normalizeChoice(choice: string | PromptChoice): PromptChoice;
690
-
691
- /** Matches a numeric value (integer or decimal, optional sign). The `numeric` rule tests against this. */
692
- export declare const NUMERIC_PATTERN: RegExp;
693
-
694
- /**
695
- * One parked prompt's runtime state inside the broker — the wire-safe {@link PendingPrompt} record
696
- * it exposes, plus the live machinery that settles that prompt's Promise. `respond` is the per-form
697
- * gate-and-resolve closure: it validates + type-checks an answer and (on accept) resolves the parked
698
- * Promise, returning whether it accepted; it closes over the form's precisely-typed `resolve`, so no
699
- * per-form generic leaks into `answer`. `expire` rejects the parked Promise; `cancel` clears the
700
- * injected expiry timer ({@link TimerCancel}).
701
- */
702
- export declare interface Parked {
703
- readonly prompt: PendingPrompt;
704
- readonly respond: (value: unknown) => unknown;
705
- readonly expire: () => void;
706
- readonly cancel: TimerCancel;
707
- }
708
-
709
- /**
710
- * The request to {@link PromptInterface.park} a prompt directly — the general form the six
711
- * `PromptFormInterface` methods each wrap via a private `gateFor(form, options)` dispatch.
712
- *
713
- * @remarks
714
- * - `form` — which {@link PromptType} to park.
715
- * - `options` — that form's options bag ({@link PromptFormOptions}).
716
- * - `from` / `to` — set ONLY by a {@link TerminalManagerInterface} (the attribution edge); a
717
- * direct broker caller leaves both `undefined`.
718
- */
719
- export declare interface ParkRequest {
720
- readonly form: PromptType;
721
- readonly options: PromptFormOptions;
722
- readonly from?: string;
723
- readonly to?: string;
724
- }
725
-
726
- /**
727
- * Decode one keypress's bytes into a {@link KeyEvent} — total, never throws. A `Uint8Array` is
728
- * read as UTF-8; the resulting string is matched against the known control bytes
729
- * ({@link CONTROL_NAMES}) and escape sequences ({@link SEQUENCE_NAMES}), falling back to a
730
- * single printable character. An unrecognized sequence yields `name: ''` with the raw `sequence`
731
- * preserved.
732
- *
733
- * @remarks
734
- * - **Single control byte.** A one-character control input (`return` / `backspace` / `tab` /
735
- * `escape` / `space`, or a Ctrl combo `c` / `d` / `u` / `a` / `e`) is looked up in
736
- * {@link CONTROL_NAMES}, carrying its `ctrl` flag.
737
- * - **Escape sequence.** A multi-byte ESC sequence (`up` / `down` / `left` / `right` in BOTH the
738
- * `ESC[A` and `ESCOA` forms, plus `home` / `end` / `delete`) is looked up in
739
- * {@link SEQUENCE_NAMES} and flagged `meta`.
740
- * - **Printable character.** A single printable character becomes `name` = that character, with
741
- * `shift` set when it is an uppercase letter. A multi-code-point printable (an emoji, a pasted
742
- * run) keeps its first code point as the name and the whole input as `sequence`.
743
- * - **Unknown.** Anything else (an unrecognized escape, an empty input) yields `name: ''` —
744
- * total, so the driver never crashes on a stray byte.
745
- *
746
- * @param input - The raw keypress bytes, as a string or `Uint8Array`
747
- * @returns The decoded {@link KeyEvent}
748
- *
749
- * @example
750
- * ```ts
751
- * parseKey('\r') // { name: 'return', sequence: '\r', ctrl: false, meta: false, shift: false }
752
- * parseKey('\x1b[A') // { name: 'up', sequence: '\x1b[A', ctrl: false, meta: true, shift: false }
753
- * parseKey('A') // { name: 'A', sequence: 'A', ctrl: false, meta: false, shift: true }
754
- * parseKey('\x03') // { name: 'c', sequence: '\x03', ctrl: true, meta: false, shift: false }
755
- * ```
756
- */
757
- export declare function parseKey(input: string | Uint8Array): KeyEvent;
758
-
759
- /**
760
- * Parse a JSON wire string TOTAL — a malformed / empty payload yields `undefined` (the caller's
761
- * guard then rejects it), never a throw. The {@link import('./PromptClient.js').PromptClient}
762
- * decodes every SSE `data` field through this before §14-narrowing it.
763
- */
764
- export declare function parseWireJSON(text: string): unknown;
765
-
766
- /** The always-passing {@link Validator} — the resolved validator when no rules were supplied. */
767
- export declare function passing(_input: string): true;
768
-
769
- /** Options for a masked password {@link import('./helpers.js').passwordReduce} prompt. */
770
- export declare interface PasswordOptions {
771
- readonly message: string;
772
- readonly mask?: string;
773
- readonly validate?: Validator | ValidationRules;
774
- readonly styler?: StylerInterface;
775
- }
776
-
777
- /**
778
- * Advance a password prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`
779
- * reducer. Identical line-editing to {@link inputReduce} (printable extends, backspace shrinks,
780
- * ctrl-u clears, ctrl-c cancels) but the view masks the value; return submits through the
781
- * validator (no default fallback — a password has no echoed default).
782
- */
783
- export declare function passwordReduce(state: PasswordState, key: KeyEvent): PromptStep<string, PasswordState>;
784
-
785
- /**
786
- * The immutable state of a password prompt — like {@link InputState} but with a `mask`
787
- * character the view renders in place of each input character.
788
- *
789
- * @remarks
790
- * Built by {@link import('./helpers.js').createPasswordState}; advanced by
791
- * {@link import('./helpers.js').passwordReduce}. The `value` is the real (unmasked) input;
792
- * the view shows `mask` repeated `value.length` times.
793
- */
794
- export declare interface PasswordState {
795
- readonly message: string;
796
- readonly mask: string;
797
- readonly validator: Validator;
798
- readonly styler: StylerInterface;
799
- readonly value: string;
800
- readonly error?: string;
801
- }
802
-
803
- /** Render a {@link PasswordState} as a styled view — the header, the value masked to `mask` repeated, and any error. */
804
- export declare function passwordView(state: PasswordState): string;
805
-
806
- /**
807
- * One prompt PARKED by the broker — an id-keyed, wire-safe record of a {@link PromptFormInterface}
808
- * call awaiting a remote answer. The value a `pending` listener receives and the broker serializes
809
- * over SSE to a {@link PromptClient}.
810
- *
811
- * @remarks
812
- * - `id` — the unique id (minted via `crypto.randomUUID()`); the key for {@link PromptInterface.answer}.
813
- * - `form` — which prompt form was called ({@link PromptType}); the discriminant a client
814
- * dispatches on (named for its axis — the prompt form — never `kind` / `type`).
815
- * - `message` — the prompt's question (lifted out of `options` for direct display).
816
- * - `options` — the WIRE-SAFE options (a `validate` FUNCTION dropped; the declarative
817
- * {@link ValidationRules} data + `choices` / `default` / `mask` kept — see
818
- * {@link import('./helpers.js').serializePromptOptions}). A client reconstructs the validator
819
- * from the rules via {@link resolveValidation}.
820
- * - `status` — the current {@link PendingPromptStatus}.
821
- * - `time` — the creation timestamp (ms since epoch).
822
- * - `from` / `to` — the OPTIONAL attribution edge a {@link TerminalManagerInterface} stamps on a
823
- * parked prompt (which endpoint asked, which endpoint must answer); absent for a bare broker
824
- * {@link PromptInterface} used directly (no manager attribution).
825
- */
826
- export declare interface PendingPrompt {
827
- readonly id: string;
828
- readonly form: PromptType;
829
- readonly message: string;
830
- readonly options: Readonly<Record<string, unknown>>;
831
- readonly status: PendingPromptStatus;
832
- readonly time: number;
833
- readonly from?: string;
834
- readonly to?: string;
835
- }
836
-
837
- /**
838
- * The lifecycle status of a parked {@link PendingPrompt} — where a brokered prompt stands.
839
- * Names its axis (the pending prompt's progression), never `kind` (AGENTS §4.4).
840
- *
841
- * @remarks
842
- * - `pending` — parked, awaiting an {@link PromptInterface.answer} (the Promise is unresolved).
843
- * - `answered` — answered and accepted (the Promise resolved with the validated value).
844
- * - `expired` — timed out (or torn down by `destroy`) before an answer (the Promise rejected).
845
- */
846
- export declare type PendingPromptStatus = 'pending' | 'answered' | 'expired';
847
-
848
- /**
849
- * The headless prompt BROKER (observable §13) — parks each {@link PromptInterface} call as a
850
- * pending prompt and returns a Promise that resolves when the prompt is {@link answer}ed (or
851
- * rejects on timeout / teardown). The tri-surface's headless arm: there is no terminal here, so a
852
- * transport forwards each `pending` event to whoever can answer, and {@link answer} resolves the
853
- * parked Promise — for environments where direct user access is unavailable (a headless server on
854
- * stdio, a browser with no TTY, a prompt issued on one machine answered on another).
855
- *
856
- * @remarks
857
- * - **Park-as-Promise.** Each `input` / `password` / `confirm` / `select` / `checkbox` / `editor`
858
- * mints an id (`crypto.randomUUID()`), parks a wire-safe {@link PendingPrompt}, emits `pending`,
859
- * and returns an unresolved Promise. The prompt's options are serialized
860
- * ({@link serializePromptOptions}) so a transport can forward them as-is.
861
- * - **Answer validates + type-checks.** {@link answer} runs the prompt's per-form gate: it
862
- * type-checks `value` to the form (string / boolean / string[]) AND, for the text forms, runs
863
- * the validator resolved from the original `validate` rules. A rejected answer returns `false`
864
- * and the prompt stays `pending`; an accepted answer resolves the Promise, emits `answer`, and
865
- * removes the prompt.
866
- * - **Timeout → expire → reject.** An unanswered prompt expires after `timeout` ms (via the
867
- * INJECTED timer): `expire` fires and the parked Promise rejects with a {@link TerminalError}
868
- * (`code: 'EXPIRE'`). {@link destroy} expires every still-pending prompt the same way.
869
- * - **Deterministic.** The timer is injectable ({@link import('./types.js').TimerHandler}); a test
870
- * supplies one that fires on demand, so expiry is driven without real time.
871
- *
872
- * @example
873
- * ```ts
874
- * const prompt = createPrompt({ timeout: 60_000 })
875
- * prompt.emitter.on('pending', (pending) => broadcast(pending)) // forward to a client
876
- *
877
- * const name = await prompt.input({ message: 'Your name' }) // parks; resolves on answer()
878
- * // ...elsewhere, a client POSTs the answer back:
879
- * prompt.answer(id, 'Ada') // resolves the awaited input() above
880
- * ```
881
- */
882
- export declare class Prompt implements PromptInterface {
883
- #private;
884
- constructor(options?: PromptOptions);
885
- get emitter(): EmitterInterface<PromptEventMap>;
886
- get count(): number;
887
- pending(): readonly PendingPrompt[];
888
- pending(id: string): PendingPrompt | undefined;
889
- answer(id: string, value: unknown): AnswerResult;
890
- park(request: ParkRequest): Ticket;
891
- input(options: InputOptions): Promise<string>;
892
- password(options: PasswordOptions): Promise<string>;
893
- confirm(options: ConfirmOptions): Promise<boolean>;
894
- select(options: SelectOptions): Promise<string>;
895
- checkbox(options: CheckboxOptions): Promise<readonly string[]>;
896
- editor(options: EditorOptions): Promise<string>;
897
- destroy(): void;
898
- }
899
-
900
- /**
901
- * The prompt-view icon glyphs the reducers render the prompt line and choice rows with. PLAIN
902
- * glyphs — color is applied by the {@link import('./types.js').PromptState}'s
903
- * {@link import('@orkestrel/console').StylerInterface} at render time, never baked into the
904
- * constant (AGENTS — styling orthogonal to data; the rework fixes the terminal's ANSI-in-the-icon).
905
- * Frozen.
906
- *
907
- * @remarks
908
- * - `question` — the leading mark on a prompt's message line.
909
- * - `pointer` — the cursor before the input / the focused choice row.
910
- * - `dot` / `selected` — an unfocused / focused row marker in a select list.
911
- * - `checked` / `unchecked` — a checked / unchecked box in a checkbox list.
912
- */
913
- export declare const PROMPT_ICONS: Readonly<{
914
- question: "?";
915
- pointer: "›";
916
- dot: "○";
917
- selected: "●";
918
- checked: "☑";
919
- unchecked: "☐";
920
- }>;
921
-
922
- /** A choice item in a {@link SelectOptions} prompt — its displayed `name`, its resolved `value`, and an optional one-line `description`. */
923
- export declare interface PromptChoice {
924
- readonly name: string;
925
- readonly value: string;
926
- readonly description?: string;
927
- }
928
-
929
- /**
930
- * The SSE prompt BRIDGE (observable §13) — the client-side counterpart to
931
- * {@link import('./Prompt.js').Prompt}. Connects to a remote broker's SSE endpoint, receives
932
- * serialized pending prompts, dispatches EACH to a LOCAL {@link PromptFormInterface} terminal (so
933
- * a human at THIS machine answers a prompt parked elsewhere), and POSTs the answer back.
934
- * Universal — `fetch` + SSE are web-standard, so it runs in a browser or on a server; the
935
- * injected `fetch` / timer make it fully deterministic in tests.
936
- *
937
- * @remarks
938
- * - **Connect + reconnect.** {@link connect} opens the SSE stream (via the injected `fetch` + the
939
- * core `SSEParser`) and loops, reconnecting after the stream drops with the `delay` backoff
940
- * (driven by the injected timer) — unless `reconnect` is `false`, the client was
941
- * {@link destroy}ed, or the drop was a deliberate {@link disconnect} (an abort).
942
- * - **Dispatch + answer.** Each decoded `pending` event is narrowed to a `PendingPrompt` (§14 —
943
- * never an `as`), dispatched to `terminal`, and its resolved value POSTed back to `url`.
944
- * Dispatch is strictly SERIAL: the read loop drives the terminal for ONE prompt at a time and
945
- * only reads/dispatches the next event after the current prompt fully settles (its answer
946
- * POSTed). A prompt id redelivered (e.g. after a reconnect) WHILE its prior dispatch is still
947
- * in flight is skipped (a `#seen` set tracks in-flight ids); once that dispatch settles (or the
948
- * broker sends `expire` for the id) the id is dropped from `#seen`, so a later redelivery of the
949
- * SAME id after completion is dispatched again — the client does not dedupe across completion.
950
- * - **Server signals.** An `expire` event (the broker dropped a parked prompt) emits `expire`; a
951
- * `shutdown` event calls {@link disconnect} (not {@link destroy}) — the client stops streaming
952
- * without auto-reconnect but stays reusable; a later {@link connect} recovers it.
953
- * - **Lean events (§13).** `connect` / `disconnect` / `expire` / `error` — errors are `unknown`.
954
- * `disconnect` fires exactly once per connected-to-disconnected transition, whether triggered by
955
- * the server ending the stream cleanly or by a deliberate {@link disconnect} / {@link destroy}.
956
- *
957
- * @example
958
- * ```ts
959
- * const client = createPromptClient({
960
- * url: 'http://localhost:3001/prompts',
961
- * terminal: createTerminal(), // a local PromptFormInterface (T-c)
962
- * on: { connect: () => log('connected') },
963
- * })
964
- * await client.connect() // streams remote prompts to the local terminal, POSTs answers back
965
- * ```
966
- */
967
- export declare class PromptClient implements PromptClientInterface {
968
- #private;
969
- readonly url: string;
970
- constructor(options: PromptClientOptions);
971
- get emitter(): EmitterInterface<PromptClientEventMap>;
972
- get connected(): boolean;
973
- connect(): Promise<void>;
974
- disconnect(): void;
975
- destroy(): void;
976
- }
977
-
978
- /**
979
- * The client's event map (AGENTS §13) — lean, errors `unknown`, no listener-error event.
980
- *
981
- * @remarks
982
- * - `connect` — the SSE stream opened.
983
- * - `disconnect` — the SSE stream closed (the server ended it, or {@link PromptClientInterface.disconnect}).
984
- * - `expire` — the remote broker signalled a parked prompt expired (carries its `id`).
985
- * - `error` — a connection / dispatch / POST fault (errors are `unknown`).
986
- */
987
- export declare type PromptClientEventMap = {
988
- connect: [];
989
- disconnect: [];
990
- expire: [id: string];
991
- error: [error: unknown];
992
- };
993
-
994
- /**
995
- * The SSE prompt BRIDGE (observable §13) — the client-side counterpart to {@link PromptInterface}.
996
- * Connects to a remote broker's SSE endpoint, receives serialized {@link PendingPrompt}s,
997
- * dispatches EACH to a local {@link PromptFormInterface} terminal, and POSTs the answer back —
998
- * so a human at this machine answers prompts a broker parked elsewhere.
999
- *
1000
- * @remarks
1001
- * - **Connect.** {@link connect} opens the SSE stream (via the injected `fetch` + the core
1002
- * `SSEParser`) and resolves when the stream ends; it reconnects with the `delay` backoff
1003
- * unless `reconnect` is `false` or the client was {@link destroy}ed.
1004
- * - **Dispatch + answer.** Each decoded prompt is narrowed (§14) and dispatched to `terminal`;
1005
- * the resolved value POSTs back to `url`.
1006
- * - **`connected`** reflects whether the stream is currently open.
1007
- */
1008
- export declare interface PromptClientInterface {
1009
- readonly emitter: EmitterInterface<PromptClientEventMap>;
1010
- readonly url: string;
1011
- readonly connected: boolean;
1012
- connect(): Promise<void>;
1013
- disconnect(): void;
1014
- destroy(): void;
1015
- }
1016
-
1017
- /**
1018
- * Options for {@link import('./factories.js').createPromptClient} / the {@link PromptClientInterface}.
1019
- *
1020
- * @remarks
1021
- * - `url` — the remote broker's SSE endpoint (GET opens the stream; answers POST back to it).
1022
- * - `terminal` — the LOCAL {@link PromptFormInterface} each remote prompt is dispatched to, so a
1023
- * human at THIS machine answers a prompt issued elsewhere.
1024
- * - `token` — an optional auth token, sent as the
1025
- * {@link import('./constants.js').HEADER_TOKEN} header on every request.
1026
- * - `reconnect` — whether to reconnect after the stream drops (default `true`).
1027
- * - `delay` — ms to wait before each reconnect attempt (default
1028
- * {@link import('./constants.js').DEFAULT_RECONNECT_DELAY_MS}).
1029
- * - `on` — initial {@link PromptClientEventMap} listeners (AGENTS §8/§13).
1030
- * - `error` — the emitter's listener-error handler (AGENTS §13).
1031
- * - `fetch` — the injected {@link FetchHandler} (default the global `fetch`); supply a scripted
1032
- * fetch to drive the client deterministically in tests.
1033
- * - `timer` — the injected {@link TimerHandler} for the reconnect backoff (default the host
1034
- * `setTimeout`); supply a deterministic timer to drive reconnection without real time.
1035
- */
1036
- export declare interface PromptClientOptions {
1037
- readonly url: string;
1038
- readonly terminal: PromptFormInterface;
1039
- readonly token?: string;
1040
- readonly reconnect?: boolean;
1041
- readonly delay?: number;
1042
- readonly on?: EmitterHooks<PromptClientEventMap>;
1043
- readonly error?: EmitterErrorHandler;
1044
- readonly fetch?: FetchHandler;
1045
- readonly timer?: TimerHandler;
1046
- }
1047
-
1048
- /**
1049
- * The broker's event map (AGENTS §13) — lean, errors `unknown`, no listener-error event.
1050
- *
1051
- * @remarks
1052
- * - `pending` — a prompt was parked (carries the wire-safe {@link PendingPrompt}); a transport
1053
- * forwards it to remote clients.
1054
- * - `answer` — a parked prompt was answered (carries its `id` + the accepted `value`).
1055
- * - `expire` — a parked prompt timed out (or was torn down) unanswered (carries its `id`).
1056
- */
1057
- export declare type PromptEventMap = {
1058
- pending: [prompt: PendingPrompt];
1059
- answer: [id: string, value: unknown];
1060
- expire: [id: string];
1061
- };
1062
-
1063
- /**
1064
- * The shared ASYNC prompt contract — the six prompt forms as Promise-returning methods. The
1065
- * ONE vocabulary BOTH the headless {@link PromptInterface} broker (this module) and the server
1066
- * `Terminal` driver (T-c) implement, so a prompt issued through this surface resolves the same
1067
- * way on every surface (local TTY, headless broker, remote bridge).
1068
- *
1069
- * @remarks
1070
- * Each method takes the prompt's `*Options` and resolves to that form's value type:
1071
- * - `input` / `password` / `select` / `editor` → a `string`
1072
- * - `confirm` → a `boolean`
1073
- * - `checkbox` → a `readonly string[]` (the checked values, in choice order)
1074
- *
1075
- * This is a behavioral CONTRACT (the method surface), not an observable entity — the broker and
1076
- * the driver add their own emitter / lifecycle on top. The {@link PromptClient} dispatches a
1077
- * remote {@link PendingPrompt} to a LOCAL `PromptFormInterface` (so a human at this machine
1078
- * answers a prompt parked elsewhere).
1079
- */
1080
- export declare interface PromptFormInterface {
1081
- input(options: InputOptions): Promise<string>;
1082
- password(options: PasswordOptions): Promise<string>;
1083
- confirm(options: ConfirmOptions): Promise<boolean>;
1084
- select(options: SelectOptions): Promise<string>;
1085
- checkbox(options: CheckboxOptions): Promise<readonly string[]>;
1086
- editor(options: EditorOptions): Promise<string>;
1087
- }
1088
-
1089
- /**
1090
- * The union of every prompt form's options bag — the `options` a {@link ParkRequest} carries,
1091
- * narrowed at the call site by the paired {@link PromptType}.
1092
- */
1093
- export declare type PromptFormOptions = InputOptions | PasswordOptions | ConfirmOptions | SelectOptions | CheckboxOptions | EditorOptions;
1094
-
1095
- /** The styled prompt-message header (`? message`) — the leading line every active prompt view shares. */
1096
- export declare function promptHeader(styler: StylerInterface, message: string): string;
1097
-
1098
- /**
1099
- * The headless prompt BROKER (observable §13) — implements {@link PromptFormInterface} by
1100
- * PARKING each call as a {@link PendingPrompt} and returning a Promise that resolves when the
1101
- * prompt is {@link answer}ed (or rejects on timeout). The local-TTY / headless / remote
1102
- * tri-surface's headless arm: no terminal here — a transport forwards each `pending` to whoever
1103
- * can answer, and {@link answer} resolves the parked Promise.
1104
- *
1105
- * @remarks
1106
- * - **Park-as-Promise.** Each `input` / `password` / … call mints an id, parks a
1107
- * {@link PendingPrompt}, emits `pending`, and returns an unresolved Promise. {@link park} is the
1108
- * general entry point the six form methods wrap.
1109
- * - **Answer validates.** {@link answer} validates `value` against the prompt's resolved
1110
- * validator AND type-checks it to the prompt form before accepting; a bad answer is rejected
1111
- * (an {@link AnswerResult} failure, the prompt stays `pending`).
1112
- * - **Timeout → expire → reject.** An unanswered prompt expires after `timeout` ms — `expire`
1113
- * fires and the parked Promise rejects (a {@link import('./errors.js').TerminalError}). The
1114
- * timer is injectable for deterministic tests.
1115
- * - **Accessors (§9.1).** `pending()` lists the parked prompts; `pending(id)` looks one up.
1116
- */
1117
- export declare interface PromptInterface extends PromptFormInterface {
1118
- readonly emitter: EmitterInterface<PromptEventMap>;
1119
- readonly count: number;
1120
- park(request: ParkRequest): Ticket;
1121
- pending(): readonly PendingPrompt[];
1122
- pending(id: string): PendingPrompt | undefined;
1123
- answer(id: string, value: unknown): AnswerResult;
1124
- destroy(): void;
1125
- }
1126
-
1127
- /**
1128
- * Options for {@link import('./factories.js').createPrompt} / the {@link PromptInterface} broker.
1129
- *
1130
- * @remarks
1131
- * - `on` — initial {@link PromptEventMap} listeners (AGENTS §8/§13).
1132
- * - `error` — the emitter's listener-error handler (AGENTS §13).
1133
- * - `timeout` — ms a parked prompt waits before it expires + its Promise rejects (default
1134
- * {@link import('./constants.js').DEFAULT_PROMPT_TIMEOUT_MS}).
1135
- * - `timer` — the injected {@link TimerHandler} (default the host `setTimeout`); supply a
1136
- * deterministic timer to drive expiry in tests without real time.
1137
- * - `cap` — the maximum number of prompts this broker will hold PARKED at once (default
1138
- * UNBOUNDED — no cap unless supplied). Once `count` reaches `cap`, a new park is rejected with
1139
- * a {@link import('./errors.js').TerminalError} (`code: 'LIMIT'`) WITHOUT parking, minting an
1140
- * id, emitting `pending`, or arming the expiry timer — the runaway-asker memory ceiling.
1141
- */
1142
- export declare interface PromptOptions {
1143
- readonly on?: EmitterHooks<PromptEventMap>;
1144
- readonly error?: EmitterErrorHandler;
1145
- readonly timeout?: number;
1146
- readonly timer?: TimerHandler;
1147
- readonly cap?: number;
1148
- }
1149
-
1150
- /**
1151
- * The discriminant of a {@link PromptStep} — where the prompt stands after a key. `active`:
1152
- * keep prompting (the input was consumed, or rejected by validation). `submit`: the prompt
1153
- * resolved with its `value`. `cancel`: the user aborted (ctrl-c). Names its axis (the prompt's
1154
- * progression), never `kind` (AGENTS §4.4).
1155
- */
1156
- export declare type PromptStatus = 'active' | 'submit' | 'cancel';
1157
-
1158
- /**
1159
- * The result of one reducer step — the next `state`, the rendered `view`, the `status`, and,
1160
- * on `submit`, the resolved `value`. The whole contract between a pure prompt reducer and the
1161
- * impure driver: the driver applies the next `state`, writes the `view`, and — when `status`
1162
- * is `submit` — reads `value`.
1163
- *
1164
- * @typeParam T - The prompt's resolved value type (`string` for input / password / select /
1165
- * editor, `boolean` for confirm, `readonly string[]` for checkbox).
1166
- * @typeParam S - The prompt's concrete state shape ({@link InputState}, {@link SelectState}, …) —
1167
- * carried directly so `state` stays precisely typed with no union narrowing or assertion.
1168
- *
1169
- * @remarks
1170
- * - `state` — the next immutable prompt state (feed it to the next reduce call). On `submit` /
1171
- * `cancel` it is the final state.
1172
- * - `view` — the styled string to render NOW (possibly MULTI-LINE for `select` / `checkbox`),
1173
- * built through the state's {@link StylerInterface}. On an invalid `submit` it carries the
1174
- * error; the driver re-renders it each step.
1175
- * - `status` — the {@link PromptStatus}: `active` to continue, `submit` when resolved, `cancel`
1176
- * on abort.
1177
- * - `value` — present ONLY on a `submit` step, carrying the prompt's resolved value.
1178
- */
1179
- export declare interface PromptStep<T, S> {
1180
- readonly state: S;
1181
- readonly view: string;
1182
- readonly status: PromptStatus;
1183
- readonly value?: T;
1184
- }
1185
-
1186
- /**
1187
- * The six prompt KINDS this core provides — the value family a higher-level broker (T-b)
1188
- * dispatches on. Names the prompt axis; a named value set (not a toggle), so it stays a union.
1189
- */
1190
- export declare type PromptType = 'input' | 'password' | 'confirm' | 'select' | 'checkbox' | 'editor';
1191
-
1192
- /**
1193
- * The union of a resolved prompt's value shapes — a `string` (`input` / `password` / `select` /
1194
- * `editor`), a `boolean` (`confirm`), or a `readonly string[]` (`checkbox`, the checked values in
1195
- * choice order). The type a {@link Ticket}'s `value` Promise resolves to.
1196
- */
1197
- export declare type PromptValue = string | boolean | readonly string[];
1198
-
1199
- /**
1200
- * Rebuild a wire-decoded `validate` payload into a {@link ValidationRules} bag — the inverse of
1201
- * {@link serializeValidationRules}. Keeps only the primitive rule values (`boolean` / `number` /
1202
- * `string`) a serialized prompt could carry; an empty / non-record / all-dropped payload yields
1203
- * `undefined` (no rules to apply). The client feeds the result back through {@link resolveValidation}.
1204
- */
1205
- export declare function reconstructValidationRules(value: unknown): ValidationRules | undefined;
1206
-
1207
- /** Read a `choices` option as a list of bare strings / full choices — each element narrowed by `guard`, off-shape elements stringified. */
1208
- export declare function resolveChoices<TChoice extends PromptChoice | CheckboxChoice>(options: Readonly<Record<string, unknown>>, guard: Guard<TChoice>): readonly (string | TChoice)[];
1209
-
1210
- /** Read one option by key, narrowed by `guard` — `undefined` when absent or off-shape (§14, never an `as`). */
1211
- export declare function resolveOption<T>(options: Readonly<Record<string, unknown>>, key: string, guard: Guard<T>): T | undefined;
1212
-
1213
- /**
1214
- * Compile a {@link Validator} or declarative {@link ValidationRules} (or nothing) into ONE
1215
- * composed {@link Validator}. A bare validator passes through; rules are appended in the fixed
1216
- * order (required → minimum → maximum → pattern → email → url → numeric → integer → alphanumeric
1217
- * → custom) and composed; absent / empty input yields an always-passing validator. Pure.
1218
- *
1219
- * @remarks
1220
- * Unlike a prior variant (which returned `Validator | undefined`), this ALWAYS returns a
1221
- * `Validator` — an absent or empty rule set yields a validator that returns `true` for every
1222
- * input. That keeps a prompt's state unconditional (it always holds a real validator to apply on
1223
- * submit), with no `undefined` branch at the call site.
1224
- *
1225
- * @param validate - A custom {@link Validator}, a {@link ValidationRules} bag, or `undefined`
1226
- * @returns The composed {@link Validator} (always-passing when nothing was supplied)
1227
- *
1228
- * @example
1229
- * ```ts
1230
- * const v = resolveValidation({ required: true, minimum: 3 })
1231
- * v('') // 'This field is required'
1232
- * v('ab') // 'Must be at least 3 characters'
1233
- * v('abc') // true
1234
- * ```
1235
- */
1236
- export declare function resolveValidation(validate?: Validator | ValidationRules): Validator;
1237
-
1238
- /** Carriage return (`\r`, U+000D) — Enter on most terminals. */
1239
- export declare const RETURN: string;
1240
-
1241
- /**
1242
- * Each built-in validation rule's default error message — what the composed {@link
1243
- * import('./types.js').Validator} returns when that rule fails (the `minimum` / `maximum`
1244
- * messages are interpolated with the configured length at build time). Frozen; the source of
1245
- * truth for the rule-failure copy.
1246
- */
1247
- export declare const RULE_MESSAGES: Readonly<{
1248
- required: "This field is required";
1249
- minimum: "Must be at least {count} characters";
1250
- maximum: "Must be at most {count} characters";
1251
- pattern: "Must match pattern: {pattern}";
1252
- email: "Must be a valid email address";
1253
- url: "Must be a valid URL";
1254
- numeric: "Must be a numeric value";
1255
- integer: "Must be an integer";
1256
- alphanumeric: "Must contain only letters and digits";
1257
- invalid: "Invalid input";
1258
- }>;
1259
-
1260
- /**
1261
- * Sanitize a list of resolved choices' human-readable labels (`name` + `description`) with
1262
- * {@link stripControls} — shared by the `select` and `checkbox` branches of
1263
- * {@link dispatchPendingPrompt} so a remote-supplied choice can never inject raw control bytes
1264
- * into the local terminal's rendered view.
1265
- *
1266
- * @param choices - The resolved choices (bare strings or full {@link PromptChoice} /
1267
- * {@link CheckboxChoice} objects) as returned by {@link resolveChoices}
1268
- * @returns The same choices with every `name` / `description` control-stripped
1269
- */
1270
- export declare function sanitizeChoiceLabels<TChoice extends PromptChoice | CheckboxChoice>(choices: readonly (string | TChoice)[]): readonly (string | TChoice)[];
1271
-
1272
- /**
1273
- * Options for a single-selection {@link import('./helpers.js').selectReduce} prompt.
1274
- *
1275
- * @remarks
1276
- * `choices` accepts bare strings (used as both `name` and `value`) or full {@link PromptChoice}
1277
- * objects; {@link import('./helpers.js').createSelectState} normalizes them. `default` pre-focuses
1278
- * the choice whose `value` matches it.
1279
- */
1280
- export declare interface SelectOptions {
1281
- readonly message: string;
1282
- readonly choices: readonly (string | PromptChoice)[];
1283
- readonly default?: string;
1284
- readonly styler?: StylerInterface;
1285
- }
1286
-
1287
- /**
1288
- * Advance a select prompt by one {@link KeyEvent} — the pure `(state, key) → PromptStep<string>`
1289
- * reducer. `up` / `down` (and `k` / `j`) move the focus, WRAPPING at the ends; return submits the
1290
- * focused choice's `value`; ctrl-c cancels. An empty choice list can never submit (a higher layer
1291
- * guards against it); any other key is ignored.
1292
- */
1293
- export declare function selectReduce(state: SelectState, key: KeyEvent): PromptStep<string, SelectState>;
1294
-
1295
- /**
1296
- * The immutable state of a select prompt — the normalized choices, the styler, and the
1297
- * `focused` index (the highlighted row).
1298
- *
1299
- * @remarks
1300
- * Built by {@link import('./helpers.js').createSelectState}; advanced by
1301
- * {@link import('./helpers.js').selectReduce}. `up` / `down` move `focused` (wrapping at the
1302
- * ends); `return` submits the focused choice's `value`.
1303
- */
1304
- export declare interface SelectState {
1305
- readonly message: string;
1306
- readonly choices: readonly PromptChoice[];
1307
- readonly styler: StylerInterface;
1308
- readonly focused: number;
1309
- }
1310
-
1311
- /** Render a {@link SelectState} as a MULTI-LINE styled view — the header followed by one row per choice, the focused row marked. */
1312
- export declare function selectView(state: SelectState): string;
1313
-
1314
- /**
1315
- * The exact escape SEQUENCE → canonical key NAME table {@link import('./helpers.js').parseKey}
1316
- * consults for the navigation / editing keys. Covers BOTH the CSI form (`ESC[A`…) and the SS3
1317
- * form (`ESCOA`…) of the four arrows, plus the `home` / `end` / `delete` CSI sequences (with
1318
- * their numeric-tilde variants). The source of truth for the multi-byte key decode; frozen.
1319
- *
1320
- * @remarks
1321
- * Terminals disagree on these: a cursor key is `ESC[A` (normal) or `ESCOA` (application mode),
1322
- * and Home / End / Delete each have a letter form (`ESC[H` / `ESC[F`) and a numeric form
1323
- * (`ESC[1~` / `ESC[4~` / `ESC[3~`). Every accepted spelling maps to one name so a reducer never
1324
- * sees the wire encoding.
1325
- */
1326
- export declare const SEQUENCE_NAMES: Readonly<Record<string, string>>;
1327
-
1328
- /** Strip functions from a `choices` option — each choice keeps its plain fields; a bare string passes through. */
1329
- export declare function serializeChoices(choices: unknown): readonly unknown[];
1330
-
1331
- /** Serialize a parked prompt's expiry into a {@link WireEvent} — event `'expire'`, `data` the JSON-stringified `{ id }` payload. */
1332
- export declare function serializeExpire(id: string): WireEvent;
1333
-
1334
- /** Serialize a parked {@link PendingPrompt} into a {@link WireEvent} — event `'pending'`, `data` the JSON-stringified prompt, `id` the prompt's own id (an SSE bridge sets its frame `id:` from this). */
1335
- export declare function serializePending(prompt: PendingPrompt): WireEvent;
1336
-
1337
- /**
1338
- * Produce the WIRE-SAFE form of a prompt's options — the {@link PendingPrompt.options} a broker
1339
- * serializes over SSE. Drops everything that cannot cross the wire (a `styler`, and any
1340
- * function-valued `validate` rule), while KEEPING the declarative data a remote client needs to
1341
- * reconstruct the prompt: the {@link ValidationRules} as data, plus `message` / `choices` /
1342
- * `default` / `mask` / `min` / `max`. This is WHY T-a's validation is rules-as-data: a `Validator`
1343
- * FUNCTION can't be serialized, but its declarative rules can — the client rebuilds the validator
1344
- * from them via {@link resolveValidation}.
1345
- *
1346
- * @remarks
1347
- * - **Functions are dropped.** A top-level function value (e.g. a bare-`Validator` `validate`) is
1348
- * omitted entirely; the `styler` (a fluent function-bearing object) is dropped by key.
1349
- * - **`validate` rules are flattened.** A {@link ValidationRules} bag is copied with each
1350
- * function rule replaced by `true` (the rule's INTENT survives as the built-in check; its
1351
- * custom function does not). A bare-function `validate` is dropped (no declarative form to keep).
1352
- * - **`choices` are function-stripped.** Each choice keeps its plain fields (`name` / `value` /
1353
- * `description` / `checked`); a bare string passes through.
1354
- *
1355
- * @param options - The raw prompt options bag (may hold functions / a styler)
1356
- * @returns A JSON-safe options record — only serializable, declarative data
1357
- */
1358
- export declare function serializePromptOptions(options: object): Readonly<Record<string, unknown>>;
1359
-
1360
- /** The {@link WireEvent} a broker/manager sends when it is going away — event `'shutdown'`, no payload. */
1361
- export declare function serializeShutdown(): WireEvent;
1362
-
1363
- /**
1364
- * Flatten a `validate` option to its wire-safe {@link ValidationRules} DATA — a function rule
1365
- * becomes `true` (its built-in check survives; its body cannot cross the wire). A bare-function
1366
- * `validate` (no rules object) has no declarative form, so it yields `undefined` (dropped).
1367
- */
1368
- export declare function serializeValidationRules(validate: unknown): Readonly<Record<string, unknown>> | undefined;
1369
-
1370
- /** Space (U+0020). */
1371
- export declare const SPACE = " ";
1372
-
1373
- /**
1374
- * The maximum number of characters the {@link import('./types.js').PromptClient} lets its
1375
- * SSE parser buffer before treating the stream as hostile — 1 MiB, comfortably above any
1376
- * legitimate prompt payload. Passed as the `limit` to `createSSEParser` so an unterminated
1377
- * or oversized `data:` field cannot grow the buffer without bound (a memory-exhaustion guard).
1378
- */
1379
- export declare const SSE_BUFFER_LIMIT = 1048576;
1380
-
1381
- /**
1382
- * The SSE `event:` names the broker emits and the {@link import('./types.js').PromptClient}
1383
- * dispatches on. Frozen; the source of truth for the wire event vocabulary.
1384
- *
1385
- * @remarks
1386
- * - `pending` — a serialized {@link import('./types.js').PendingPrompt} to dispatch + answer.
1387
- * - `expire` — an `{ id }` payload: the broker expired a parked prompt (the client drops it).
1388
- * - `shutdown` — the broker is going away; the client disconnects (no auto-reconnect) but stays reusable.
1389
- */
1390
- export declare const SSE_EVENTS: Readonly<{
1391
- pending: "pending";
1392
- expire: "expire";
1393
- shutdown: "shutdown";
1394
- }>;
1395
-
1396
- /** The styled submit line (`✔ message`) — the committed header an interactive prompt shows once resolved. */
1397
- export declare function submitHeader(styler: StylerInterface, message: string): string;
1398
-
1399
- /** Tab (`\t`, U+0009). */
1400
- export declare const TAB: string;
1401
-
1402
- /** The rejection reason a {@link TerminalManagerInterface.answer} call returns — an {@link AnswerError}, plus `'terminal'` (no such endpoint). */
1403
- export declare type TerminalAnswerError = AnswerError | 'terminal';
1404
-
1405
- /** The outcome of a {@link TerminalManagerInterface.answer} call — the accepted `value` on success, else the {@link TerminalAnswerError}. */
1406
- export declare type TerminalAnswerResult = {
1407
- readonly success: true;
1408
- readonly value: unknown;
1409
- } | {
1410
- readonly success: false;
1411
- readonly error: TerminalAnswerError;
1412
- };
1413
-
1414
- /**
1415
- * An error a {@link import('./Prompt.js').Prompt} broker rejects a parked prompt's Promise with.
1416
- *
1417
- * @remarks
1418
- * Carries a {@link TerminalErrorCode} and an optional `context` bag (the prompt `id`). Thrown —
1419
- * as a Promise rejection on the awaited prompt call — when a parked prompt is not answered before
1420
- * its `timeout`, or when the broker is `destroy`ed while the prompt is still `pending` (both
1421
- * `EXPIRE`); or when the user aborts an interactive server-`Terminal` prompt with ctrl-c
1422
- * (`CANCEL`). Narrow a caught value with {@link isTerminalError} and branch on `error.code`.
1423
- */
1424
- export declare class TerminalError extends Error {
1425
- /** The machine-readable condition — see {@link TerminalErrorCode}. */
1426
- readonly code: TerminalErrorCode;
1427
- /** An optional context bag naming the offending prompt id. */
1428
- readonly context?: Readonly<Record<string, unknown>>;
1429
- constructor(code: TerminalErrorCode, message: string, context?: Readonly<Record<string, unknown>>);
1430
- }
1431
-
1432
- /**
1433
- * The machine-readable condition carried by a {@link import('./errors.js').TerminalError} — the
1434
- * axis a `catch` branches on. Names its axis (the failure condition), never `kind` (AGENTS §4.4).
1435
- *
1436
- * @remarks
1437
- * - `EXPIRE` — a parked broker prompt was not answered before its `timeout` (or the broker was
1438
- * `destroy`ed while it was still pending); the prompt's Promise rejects with this.
1439
- * - `CANCEL` — the user aborted an interactive prompt (ctrl-c) at the server `Terminal` (T-c)
1440
- * driver; the awaited prompt call rejects with this so a caller can branch on `error.code`.
1441
- * - `LIMIT` — a broker's optional `cap` on concurrently-parked prompts was already reached; the
1442
- * new call is rejected WITHOUT parking (never counted, never emitted, no timer armed).
1443
- * - `DESTROYED` — a call reached an already-`destroy`ed {@link TerminalManagerInterface} (`add`
1444
- * at entry, or `open` whose `store` read resolved after a `destroy` happened in the gap).
1445
- */
1446
- export declare type TerminalErrorCode = 'EXPIRE' | 'CANCEL' | 'DRIVER' | 'DEADLOCK' | 'TARGET' | 'LIMIT' | 'DESTROYED';
1447
-
1448
- /**
1449
- * The multi-endpoint terminal MANAGER — a registry of named {@link PromptInterface} brokers (one
1450
- * per endpoint), so several parties can `ask` prompts of each other by NAME with a `from` → `to`
1451
- * attribution edge on every parked prompt, and a transitive DEADLOCK check across all in-flight
1452
- * asks.
1453
- *
1454
- * @remarks
1455
- * - **Registry.** `add(name, options?)` mints (or, if `name` is already mounted, returns the
1456
- * EXISTING broker UNCHANGED — idempotent, never clobbers a live/parked endpoint). Every mounted
1457
- * broker's `pending` / `answer` / `expire` events are re-emitted on the manager, attributed by
1458
- * `name`.
1459
- * - **`ask`.** The target must already be mounted via {@link add} — `ask` never auto-adds it;
1460
- * rejects `TARGET` for an unknown `to` (listing the known names). Rejects `DEADLOCK` when parking
1461
- * `from → to` would close a cycle over the CURRENT in-flight edge set (walked transitively);
1462
- * otherwise parks through the target's broker and resolves with the ORIGINAL ticket Promise (edge
1463
- * cleanup is attached via `.then`, never altering the value/rejection the caller observes).
1464
- * - **Durable open / save.** `open(name)` restores an EMPTY broker from the `store` (parked
1465
- * Promises are process-bound and never resurrected); `save(name)` persists the endpoint's
1466
- * configured `timeout`.
1467
- * - **Removal.** `remove` drops one endpoint or a batch (§9.2, array overload FIRST), destroying
1468
- * each broker (which expires every prompt still parked on it). `clear` drops all; `destroy` is
1469
- * idempotent.
1470
- *
1471
- * @example
1472
- * ```ts
1473
- * const manager = new TerminalManager()
1474
- * manager.add('agent')
1475
- * const name = manager.ask('user', 'agent', 'input', { message: 'Your name' })
1476
- * manager.answer('agent', manager.pending('agent')[0].id, 'Ada')
1477
- * await name // 'Ada'
1478
- * ```
1479
- */
1480
- export declare class TerminalManager implements TerminalManagerInterface {
1481
- #private;
1482
- constructor(options?: TerminalManagerOptions);
1483
- get emitter(): EmitterInterface<TerminalManagerEventMap>;
1484
- get count(): number;
1485
- terminal(name: string): PromptInterface | undefined;
1486
- terminals(): readonly string[];
1487
- add(name: string, options?: TerminalOptions): PromptInterface;
1488
- ask(from: string, to: string, form: 'input' | 'password' | 'editor', options: InputOptions | PasswordOptions | EditorOptions): Promise<string>;
1489
- ask(from: string, to: string, form: 'confirm', options: ConfirmOptions): Promise<boolean>;
1490
- ask(from: string, to: string, form: 'select', options: SelectOptions): Promise<string>;
1491
- ask(from: string, to: string, form: 'checkbox', options: CheckboxOptions): Promise<readonly string[]>;
1492
- pending(): readonly PendingPrompt[];
1493
- pending(to: string): readonly PendingPrompt[];
1494
- answer(to: string, id: string, value: unknown): TerminalAnswerResult;
1495
- open(name: string): Promise<PromptInterface | undefined>;
1496
- save(name: string): Promise<boolean>;
1497
- remove(names: readonly string[]): boolean;
1498
- remove(name: string): boolean;
1499
- clear(): void;
1500
- destroy(): void;
1501
- }
1502
-
1503
- /**
1504
- * The manager's event map (AGENTS §13) — the name-attributed re-emission of every mounted
1505
- * broker's events, so a caller subscribes once for ALL endpoints instead of per-broker.
1506
- *
1507
- * @remarks
1508
- * - `pending` — an endpoint parked a prompt (carries the {@link PendingPrompt}, itself carrying
1509
- * `from` / `to`).
1510
- * - `answer` — an endpoint's parked prompt was answered (`to` names the endpoint).
1511
- * - `expire` — an endpoint's parked prompt timed out (`to` names the endpoint).
1512
- */
1513
- export declare type TerminalManagerEventMap = {
1514
- pending: [prompt: PendingPrompt];
1515
- answer: [to: string, id: string, value: unknown];
1516
- expire: [to: string, id: string];
1517
- };
1518
-
1519
- /**
1520
- * The multi-endpoint terminal MANAGER (§9.1/§9.2) — a registry of named {@link PromptInterface}
1521
- * brokers (one per endpoint), so several parties (agents, tools, humans) can `ask` prompts of
1522
- * each other by NAME, attributed with a `from` → `to` edge on every parked {@link PendingPrompt}.
1523
- *
1524
- * @remarks
1525
- * - **Accessors (§9.1).** `terminal(name)` looks up one endpoint's broker; `terminals()` lists
1526
- * every mounted endpoint name.
1527
- * - **`add`** mints (or returns the existing) broker for `name` — idempotent, never clobbers a
1528
- * live endpoint.
1529
- * - **`ask`** is the attributed convenience: parks a prompt from `from` to `to` (auto-`add`ing
1530
- * `to` if absent) and resolves with the typed value, precisely overloaded per {@link PromptType}.
1531
- * - **`pending()`** lists every endpoint's parked prompts; `pending(to)` scopes to one endpoint.
1532
- * - **`answer`** routes to the named endpoint's broker.
1533
- * - **`open`** restores (or returns the live) broker for `name` from the `store`.
1534
- * - **`save`** persists an endpoint's config snapshot to the `store` (`false` when there is no
1535
- * store, or `name` is unknown).
1536
- * - **Batch `remove` (§9.2).** The array overload is declared FIRST — `remove(names)` removes each
1537
- * listed endpoint (`true` when any of the named terminals was removed); `remove(name)` removes one.
1538
- * - **`clear`** removes every endpoint without destroying the manager; **`destroy`** tears down
1539
- * every broker, then the manager's own emitter.
1540
- */
1541
- export declare interface TerminalManagerInterface {
1542
- readonly emitter: EmitterInterface<TerminalManagerEventMap>;
1543
- readonly count: number;
1544
- terminal(name: string): PromptInterface | undefined;
1545
- terminals(): readonly string[];
1546
- add(name: string, options?: TerminalOptions): PromptInterface;
1547
- ask(from: string, to: string, form: 'input' | 'password' | 'editor', options: InputOptions | PasswordOptions | EditorOptions): Promise<string>;
1548
- ask(from: string, to: string, form: 'confirm', options: ConfirmOptions): Promise<boolean>;
1549
- ask(from: string, to: string, form: 'select', options: SelectOptions): Promise<string>;
1550
- ask(from: string, to: string, form: 'checkbox', options: CheckboxOptions): Promise<readonly string[]>;
1551
- pending(): readonly PendingPrompt[];
1552
- pending(to: string): readonly PendingPrompt[];
1553
- answer(to: string, id: string, value: unknown): TerminalAnswerResult;
1554
- open(name: string): Promise<PromptInterface | undefined>;
1555
- save(name: string): Promise<boolean>;
1556
- remove(names: readonly string[]): boolean;
1557
- remove(name: string): boolean;
1558
- clear(): void;
1559
- destroy(): void;
1560
- }
1561
-
1562
- /**
1563
- * Options for {@link import('./factories.js').createTerminalManager} / the
1564
- * {@link TerminalManagerInterface}.
1565
- *
1566
- * @remarks
1567
- * - `store` — the optional {@link TerminalStoreInterface} backing `open` / `save`.
1568
- * - `timeout` / `timer` / `cap` — the manager-wide default for each endpoint's broker (overridable
1569
- * per {@link TerminalManagerInterface.add} call via {@link TerminalOptions}, exactly like
1570
- * `timeout` / `timer`).
1571
- * - `on` / `error` — the manager's {@link EmitterHooks} + {@link EmitterErrorHandler} (AGENTS §13).
1572
- */
1573
- export declare interface TerminalManagerOptions {
1574
- readonly store?: TerminalStoreInterface;
1575
- readonly timeout?: number;
1576
- readonly timer?: TimerHandler;
1577
- readonly cap?: number;
1578
- readonly on?: EmitterHooks<TerminalManagerEventMap>;
1579
- readonly error?: EmitterErrorHandler;
1580
- }
1581
-
1582
- /** Options for {@link import('./factories.js').createTerminal} / a manager-owned {@link PromptInterface} broker — the per-endpoint `timeout` + injected `timer` + optional `cap` on concurrently-parked prompts. */
1583
- export declare interface TerminalOptions {
1584
- readonly timeout?: number;
1585
- readonly timer?: TimerHandler;
1586
- readonly cap?: number;
1587
- }
1588
-
1589
- /** One endpoint's persisted CONFIG snapshot — `id` is the endpoint name; `timeout` its configured default. Parked Promises are process-bound and are never resurrected — `open` always restores an EMPTY broker. */
1590
- export declare interface TerminalSnapshot {
1591
- readonly id: string;
1592
- readonly timeout?: number;
1593
- }
1594
-
1595
- /** One opaque persisted row — the shape a `TableInterface<TerminalSnapshotRow>`-backed store reads/writes; `snapshot` is narrowed with {@link import('./helpers.js').isTerminalSnapshot} on read. */
1596
- export declare interface TerminalSnapshotRow {
1597
- readonly id: string;
1598
- readonly snapshot: unknown;
1599
- }
1600
-
1601
- /**
1602
- * The point-access persistence seam (AGENTS §5 — Stores) for a {@link TerminalManagerInterface}'s
1603
- * endpoint configs. Every primitive is async; `delete` of an absent id is a no-op.
1604
- */
1605
- export declare interface TerminalStoreInterface {
1606
- get(id: string): Promise<TerminalSnapshot | undefined>;
1607
- set(snapshot: TerminalSnapshot): Promise<void>;
1608
- delete(id: string): Promise<void>;
1609
- }
1610
-
1611
- /** The handle {@link PromptInterface.park} returns — the parked prompt's `id` plus the Promise that resolves (or rejects) with its {@link PromptValue}. */
1612
- export declare interface Ticket {
1613
- readonly id: string;
1614
- readonly value: Promise<PromptValue>;
1615
- }
1616
-
1617
- /** Cancel a pending {@link TimerHandler} deadline — idempotent, safe to call after the timer fired. */
1618
- export declare type TimerCancel = () => void;
1619
-
1620
- /**
1621
- * One injected timer — arms a deadline `callback` to fire after `ms`, returning a
1622
- * {@link TimerCancel} that cancels it. The broker's timeout seam: the default wraps the host
1623
- * `setTimeout` / `clearTimeout`; a test injects a deterministic timer that captures the callback
1624
- * and fires it on demand (no real time, no global fake-timer patching).
1625
- */
1626
- export declare type TimerHandler = (callback: () => void, ms: number) => TimerCancel;
1627
-
1628
- /** Toggle `index` in a readonly index list — copy-on-write, returning the new sorted-by-insertion list. */
1629
- export declare function toggleIndex(indices: readonly number[], index: number): readonly number[];
1630
-
1631
- /** Matches an HTTP(S) URL. The `url` rule tests against this. */
1632
- export declare const URL_PATTERN: RegExp;
1633
-
1634
- /**
1635
- * Declarative validation rules for a text prompt — each key toggles (or overrides) one
1636
- * built-in check. {@link import('./helpers.js').resolveValidation} compiles a `ValidationRules`
1637
- * (or a bare {@link Validator}) into ONE composed {@link Validator}.
1638
- *
1639
- * @remarks
1640
- * Each rule is EITHER a primitive that turns on the built-in check, OR a {@link Validator}
1641
- * that replaces it with custom logic:
1642
- *
1643
- * - `required` — `true` ⇒ input must be non-empty after trimming.
1644
- * - `minimum` — a number ⇒ input must be at least that many characters.
1645
- * - `maximum` — a number ⇒ input must be at most that many characters.
1646
- * - `pattern` — a string ⇒ input must match that regex source.
1647
- * - `email` — `true` ⇒ input must look like an email address.
1648
- * - `url` — `true` ⇒ input must look like an HTTP(S) URL.
1649
- * - `numeric` — `true` ⇒ input must be a number (integer or decimal).
1650
- * - `integer` — `true` ⇒ input must be an integer.
1651
- * - `alphanumeric` — `true` ⇒ input must contain only letters and digits.
1652
- * - `custom` — an arbitrary {@link Validator} escape hatch.
1653
- *
1654
- * Rules compose in the fixed order above; the FIRST failing rule short-circuits and its
1655
- * message is returned. A `false` / `undefined` rule is skipped.
1656
- */
1657
- export declare interface ValidationRules {
1658
- readonly required?: boolean | Validator;
1659
- readonly minimum?: number | Validator;
1660
- readonly maximum?: number | Validator;
1661
- readonly pattern?: string | Validator;
1662
- readonly email?: boolean | Validator;
1663
- readonly url?: boolean | Validator;
1664
- readonly numeric?: boolean | Validator;
1665
- readonly integer?: boolean | Validator;
1666
- readonly alphanumeric?: boolean | Validator;
1667
- readonly custom?: Validator;
1668
- }
1669
-
1670
- /**
1671
- * A single input validator — given the current input string, returns `true` when the input
1672
- * is valid, or an error MESSAGE string when it is not. The atomic unit the validation engine
1673
- * composes and the prompts apply on submit.
1674
- *
1675
- * @remarks
1676
- * A `Validator` is total and pure — it never throws and never mutates. The `true | string`
1677
- * shape (not `boolean`) is deliberate: an invalid result CARRIES its message, so a prompt
1678
- * can render the exact reason. {@link import('./helpers.js').composeValidators} runs several
1679
- * in order and returns the FIRST error (short-circuiting), so the most specific rule wins.
1680
- */
1681
- export declare type Validator = (input: string) => true | string;
1682
-
1683
- /** One SSE-shaped wire frame — the `event` name, its `data` payload (already JSON-stringified), and an optional `id`. The transport-neutral shape {@link import('./helpers.js').serializePending} / {@link import('./helpers.js').serializeExpire} / {@link import('./helpers.js').serializeShutdown} build, with no `http` dependency. */
1684
- export declare interface WireEvent {
1685
- readonly event: string;
1686
- readonly data: string;
1687
- readonly id?: string;
1688
- }
1689
-
1690
- export { }