@orkestrel/terminal 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/core/index.cjs +572 -58
- package/dist/src/core/index.cjs.map +1 -1
- package/dist/src/core/index.d.cts +424 -7
- package/dist/src/core/index.d.ts +424 -7
- package/dist/src/core/index.js +563 -60
- package/dist/src/core/index.js.map +1 -1
- package/dist/src/server/index.cjs +12 -11
- package/dist/src/server/index.cjs.map +1 -1
- package/dist/src/server/index.d.cts +12 -12
- package/dist/src/server/index.d.ts +12 -12
- package/dist/src/server/index.js +12 -11
- package/dist/src/server/index.js.map +1 -1
- package/package.json +7 -6
package/dist/src/core/index.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { DriverInterface } from '@orkestrel/database';
|
|
1
2
|
import { EmitterErrorHandler } from '@orkestrel/emitter';
|
|
2
3
|
import { EmitterHooks } from '@orkestrel/emitter';
|
|
3
4
|
import { EmitterInterface } from '@orkestrel/emitter';
|
|
4
5
|
import { Guard } from '@orkestrel/contract';
|
|
5
6
|
import { StylerInterface } from '@orkestrel/console';
|
|
7
|
+
import { TableInterface } from '@orkestrel/database';
|
|
6
8
|
|
|
7
9
|
/** The `Accept` header value that opens the broker's SSE stream. */
|
|
8
10
|
export declare const ACCEPT_EVENT_STREAM = "text/event-stream";
|
|
@@ -10,6 +12,18 @@ export declare const ACCEPT_EVENT_STREAM = "text/event-stream";
|
|
|
10
12
|
/** Matches an alphanumeric string (letters and digits only). The `alphanumeric` rule tests against this. */
|
|
11
13
|
export declare const ALPHANUMERIC_PATTERN: RegExp;
|
|
12
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
|
+
|
|
13
27
|
/**
|
|
14
28
|
* Append a rule-backed {@link Validator} to `validators` when the rule is enabled — a `false` /
|
|
15
29
|
* `undefined` `check` is skipped, a function `check` is added verbatim (the custom override), and
|
|
@@ -143,12 +157,44 @@ export declare function createCheckboxState(options: CheckboxOptions): CheckboxS
|
|
|
143
157
|
/** Build the initial {@link ConfirmState} from {@link ConfirmOptions} — defaulting the answer to `false`. */
|
|
144
158
|
export declare function createConfirmState(options: ConfirmOptions): ConfirmState;
|
|
145
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
|
+
|
|
146
177
|
/** Build the initial {@link EditorState} from {@link EditorOptions} — resolving the validator + styler, seeding empty lines. */
|
|
147
178
|
export declare function createEditorState(options: EditorOptions): EditorState;
|
|
148
179
|
|
|
149
180
|
/** Build the initial {@link InputState} from {@link InputOptions} — resolving the validator + styler, seeding an empty value. */
|
|
150
181
|
export declare function createInputState(options: InputOptions): InputState;
|
|
151
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
|
+
|
|
152
198
|
/** Build the initial {@link PasswordState} from {@link PasswordOptions} — resolving the validator + styler + mask. */
|
|
153
199
|
export declare function createPasswordState(options: PasswordOptions): PasswordState;
|
|
154
200
|
|
|
@@ -210,6 +256,24 @@ export declare function createPromptClient(options: PromptClientOptions): Prompt
|
|
|
210
256
|
/** Build the initial {@link SelectState} from {@link SelectOptions} — normalizing choices and pre-focusing the default. */
|
|
211
257
|
export declare function createSelectState(options: SelectOptions): SelectState;
|
|
212
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
|
+
|
|
213
277
|
/** Ctrl+A (SOH, U+0001) — move to start of line. */
|
|
214
278
|
export declare const CTRL_A: string;
|
|
215
279
|
|
|
@@ -225,6 +289,65 @@ export declare const CTRL_E: string;
|
|
|
225
289
|
/** Ctrl+U (NAK, U+0015) — clear the current line. */
|
|
226
290
|
export declare const CTRL_U: string;
|
|
227
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
|
+
|
|
228
351
|
/** The default mask glyph a {@link import('./types.js').PasswordState} renders each input character as — `*`. */
|
|
229
352
|
export declare const DEFAULT_MASK = "*";
|
|
230
353
|
|
|
@@ -411,6 +534,12 @@ export declare const INTEGER_PATTERN: RegExp;
|
|
|
411
534
|
*/
|
|
412
535
|
export declare function isAbortError(error: unknown): boolean;
|
|
413
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
|
+
|
|
414
543
|
/** Narrow an unknown value to a {@link CheckboxChoice} — the `recordOf` shape inlined so no non-exported member lingers (§5). */
|
|
415
544
|
export declare function isCheckboxChoice(value: unknown): value is CheckboxChoice;
|
|
416
545
|
|
|
@@ -470,6 +599,9 @@ export declare const isPromptType: Guard<PromptType>;
|
|
|
470
599
|
*/
|
|
471
600
|
export declare function isTerminalError(value: unknown): value is TerminalError;
|
|
472
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
|
+
|
|
473
605
|
/**
|
|
474
606
|
* The Control Sequence Introducer lead (`ESC[`) for the navigation keys — the prefix of the
|
|
475
607
|
* arrow / home / end / delete sequences {@link SEQUENCE_NAMES} is keyed by. Named `KEY_CSI`
|
|
@@ -508,6 +640,45 @@ export declare interface KeyEvent {
|
|
|
508
640
|
readonly shift: boolean;
|
|
509
641
|
}
|
|
510
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
|
+
|
|
511
682
|
/** Line feed (`\n`, U+000A) — Enter on some terminals / pasted input. */
|
|
512
683
|
export declare const NEWLINE: string;
|
|
513
684
|
|
|
@@ -535,6 +706,23 @@ export declare interface Parked {
|
|
|
535
706
|
readonly cancel: TimerCancel;
|
|
536
707
|
}
|
|
537
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
|
+
|
|
538
726
|
/**
|
|
539
727
|
* Decode one keypress's bytes into a {@link KeyEvent} — total, never throws. A `Uint8Array` is
|
|
540
728
|
* read as UTF-8; the resulting string is matched against the known control bytes
|
|
@@ -631,6 +819,9 @@ export declare function passwordView(state: PasswordState): string;
|
|
|
631
819
|
* from the rules via {@link resolveValidation}.
|
|
632
820
|
* - `status` — the current {@link PendingPromptStatus}.
|
|
633
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).
|
|
634
825
|
*/
|
|
635
826
|
export declare interface PendingPrompt {
|
|
636
827
|
readonly id: string;
|
|
@@ -639,6 +830,8 @@ export declare interface PendingPrompt {
|
|
|
639
830
|
readonly options: Readonly<Record<string, unknown>>;
|
|
640
831
|
readonly status: PendingPromptStatus;
|
|
641
832
|
readonly time: number;
|
|
833
|
+
readonly from?: string;
|
|
834
|
+
readonly to?: string;
|
|
642
835
|
}
|
|
643
836
|
|
|
644
837
|
/**
|
|
@@ -693,7 +886,8 @@ export declare class Prompt implements PromptInterface {
|
|
|
693
886
|
get count(): number;
|
|
694
887
|
pending(): readonly PendingPrompt[];
|
|
695
888
|
pending(id: string): PendingPrompt | undefined;
|
|
696
|
-
answer(id: string, value: unknown):
|
|
889
|
+
answer(id: string, value: unknown): AnswerResult;
|
|
890
|
+
park(request: ParkRequest): Ticket;
|
|
697
891
|
input(options: InputOptions): Promise<string>;
|
|
698
892
|
password(options: PasswordOptions): Promise<string>;
|
|
699
893
|
confirm(options: ConfirmOptions): Promise<boolean>;
|
|
@@ -749,8 +943,10 @@ export declare interface PromptChoice {
|
|
|
749
943
|
* never an `as`), dispatched to `terminal`, and its resolved value POSTed back to `url`.
|
|
750
944
|
* Dispatch is strictly SERIAL: the read loop drives the terminal for ONE prompt at a time and
|
|
751
945
|
* only reads/dispatches the next event after the current prompt fully settles (its answer
|
|
752
|
-
* POSTed). A prompt id redelivered
|
|
753
|
-
*
|
|
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.
|
|
754
950
|
* - **Server signals.** An `expire` event (the broker dropped a parked prompt) emits `expire`; a
|
|
755
951
|
* `shutdown` event calls {@link disconnect} (not {@link destroy}) — the client stops streaming
|
|
756
952
|
* without auto-reconnect but stays reusable; a later {@link connect} recovers it.
|
|
@@ -890,6 +1086,12 @@ export declare interface PromptFormInterface {
|
|
|
890
1086
|
editor(options: EditorOptions): Promise<string>;
|
|
891
1087
|
}
|
|
892
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
|
+
|
|
893
1095
|
/** The styled prompt-message header (`? message`) — the leading line every active prompt view shares. */
|
|
894
1096
|
export declare function promptHeader(styler: StylerInterface, message: string): string;
|
|
895
1097
|
|
|
@@ -902,10 +1104,11 @@ export declare function promptHeader(styler: StylerInterface, message: string):
|
|
|
902
1104
|
*
|
|
903
1105
|
* @remarks
|
|
904
1106
|
* - **Park-as-Promise.** Each `input` / `password` / … call mints an id, parks a
|
|
905
|
-
* {@link PendingPrompt}, emits `pending`, and returns an unresolved Promise.
|
|
1107
|
+
* {@link PendingPrompt}, emits `pending`, and returns an unresolved Promise. {@link park} is the
|
|
1108
|
+
* general entry point the six form methods wrap.
|
|
906
1109
|
* - **Answer validates.** {@link answer} validates `value` against the prompt's resolved
|
|
907
1110
|
* validator AND type-checks it to the prompt form before accepting; a bad answer is rejected
|
|
908
|
-
* (
|
|
1111
|
+
* (an {@link AnswerResult} failure, the prompt stays `pending`).
|
|
909
1112
|
* - **Timeout → expire → reject.** An unanswered prompt expires after `timeout` ms — `expire`
|
|
910
1113
|
* fires and the parked Promise rejects (a {@link import('./errors.js').TerminalError}). The
|
|
911
1114
|
* timer is injectable for deterministic tests.
|
|
@@ -914,9 +1117,10 @@ export declare function promptHeader(styler: StylerInterface, message: string):
|
|
|
914
1117
|
export declare interface PromptInterface extends PromptFormInterface {
|
|
915
1118
|
readonly emitter: EmitterInterface<PromptEventMap>;
|
|
916
1119
|
readonly count: number;
|
|
1120
|
+
park(request: ParkRequest): Ticket;
|
|
917
1121
|
pending(): readonly PendingPrompt[];
|
|
918
1122
|
pending(id: string): PendingPrompt | undefined;
|
|
919
|
-
answer(id: string, value: unknown):
|
|
1123
|
+
answer(id: string, value: unknown): AnswerResult;
|
|
920
1124
|
destroy(): void;
|
|
921
1125
|
}
|
|
922
1126
|
|
|
@@ -930,12 +1134,17 @@ export declare interface PromptInterface extends PromptFormInterface {
|
|
|
930
1134
|
* {@link import('./constants.js').DEFAULT_PROMPT_TIMEOUT_MS}).
|
|
931
1135
|
* - `timer` — the injected {@link TimerHandler} (default the host `setTimeout`); supply a
|
|
932
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.
|
|
933
1141
|
*/
|
|
934
1142
|
export declare interface PromptOptions {
|
|
935
1143
|
readonly on?: EmitterHooks<PromptEventMap>;
|
|
936
1144
|
readonly error?: EmitterErrorHandler;
|
|
937
1145
|
readonly timeout?: number;
|
|
938
1146
|
readonly timer?: TimerHandler;
|
|
1147
|
+
readonly cap?: number;
|
|
939
1148
|
}
|
|
940
1149
|
|
|
941
1150
|
/**
|
|
@@ -980,6 +1189,13 @@ export declare interface PromptStep<T, S> {
|
|
|
980
1189
|
*/
|
|
981
1190
|
export declare type PromptType = 'input' | 'password' | 'confirm' | 'select' | 'checkbox' | 'editor';
|
|
982
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
|
+
|
|
983
1199
|
/**
|
|
984
1200
|
* Rebuild a wire-decoded `validate` payload into a {@link ValidationRules} bag — the inverse of
|
|
985
1201
|
* {@link serializeValidationRules}. Keeps only the primitive rule values (`boolean` / `number` /
|
|
@@ -1112,6 +1328,12 @@ export declare const SEQUENCE_NAMES: Readonly<Record<string, string>>;
|
|
|
1112
1328
|
/** Strip functions from a `choices` option — each choice keeps its plain fields; a bare string passes through. */
|
|
1113
1329
|
export declare function serializeChoices(choices: unknown): readonly unknown[];
|
|
1114
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
|
+
|
|
1115
1337
|
/**
|
|
1116
1338
|
* Produce the WIRE-SAFE form of a prompt's options — the {@link PendingPrompt.options} a broker
|
|
1117
1339
|
* serializes over SSE. Drops everything that cannot cross the wire (a `styler`, and any
|
|
@@ -1135,6 +1357,9 @@ export declare function serializeChoices(choices: unknown): readonly unknown[];
|
|
|
1135
1357
|
*/
|
|
1136
1358
|
export declare function serializePromptOptions(options: object): Readonly<Record<string, unknown>>;
|
|
1137
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
|
+
|
|
1138
1363
|
/**
|
|
1139
1364
|
* Flatten a `validate` option to its wire-safe {@link ValidationRules} DATA — a function rule
|
|
1140
1365
|
* becomes `true` (its built-in check survives; its body cannot cross the wire). A bare-function
|
|
@@ -1174,6 +1399,18 @@ export declare function submitHeader(styler: StylerInterface, message: string):
|
|
|
1174
1399
|
/** Tab (`\t`, U+0009). */
|
|
1175
1400
|
export declare const TAB: string;
|
|
1176
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
|
+
|
|
1177
1414
|
/**
|
|
1178
1415
|
* An error a {@link import('./Prompt.js').Prompt} broker rejects a parked prompt's Promise with.
|
|
1179
1416
|
*
|
|
@@ -1201,8 +1438,181 @@ export declare class TerminalError extends Error {
|
|
|
1201
1438
|
* `destroy`ed while it was still pending); the prompt's Promise rejects with this.
|
|
1202
1439
|
* - `CANCEL` — the user aborted an interactive prompt (ctrl-c) at the server `Terminal` (T-c)
|
|
1203
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).
|
|
1204
1572
|
*/
|
|
1205
|
-
export declare
|
|
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
|
+
}
|
|
1206
1616
|
|
|
1207
1617
|
/** Cancel a pending {@link TimerHandler} deadline — idempotent, safe to call after the timer fired. */
|
|
1208
1618
|
export declare type TimerCancel = () => void;
|
|
@@ -1270,4 +1680,11 @@ export declare interface ValidationRules {
|
|
|
1270
1680
|
*/
|
|
1271
1681
|
export declare type Validator = (input: string) => true | string;
|
|
1272
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
|
+
|
|
1273
1690
|
export { }
|