@orkestrel/terminal 0.0.1
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/LICENSE +21 -0
- package/README.md +77 -0
- package/dist/src/core/index.cjs +1739 -0
- package/dist/src/core/index.cjs.map +1 -0
- package/dist/src/core/index.d.cts +1273 -0
- package/dist/src/core/index.d.ts +1273 -0
- package/dist/src/core/index.js +1651 -0
- package/dist/src/core/index.js.map +1 -0
- package/dist/src/server/index.cjs +478 -0
- package/dist/src/server/index.cjs.map +1 -0
- package/dist/src/server/index.d.cts +321 -0
- package/dist/src/server/index.d.ts +321 -0
- package/dist/src/server/index.js +458 -0
- package/dist/src/server/index.js.map +1 -0
- package/package.json +97 -0
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { CheckboxOptions } from '../core/index.js';
|
|
2
|
+
import { ConfirmOptions } from '../core/index.js';
|
|
3
|
+
import { EditorOptions } from '../core/index.js';
|
|
4
|
+
import { InputOptions } from '../core/index.js';
|
|
5
|
+
import { PasswordOptions } from '../core/index.js';
|
|
6
|
+
import { PromptFormInterface } from '../core/index.js';
|
|
7
|
+
import { SelectOptions } from '../core/index.js';
|
|
8
|
+
|
|
9
|
+
/** A carriage return (`\r`, U+000D) — returns the cursor to column 0 so a redraw starts at the line's left edge. */
|
|
10
|
+
export declare const CARRIAGE_RETURN: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Erase from the cursor down to the end of the screen (`ESC[J`) — wipes the WHOLE previous (possibly
|
|
14
|
+
* multi-line `select` / `checkbox`) view in one write before the new view is rendered, so a redraw
|
|
15
|
+
* never leaves orphaned rows below.
|
|
16
|
+
*/
|
|
17
|
+
export declare const CLEAR_DOWN: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Create the interactive terminal prompt {@link TerminalInterface} (T-c) — the local-TTY arm of the
|
|
21
|
+
* prompt tri-surface, the env-symmetric sibling of the core headless `createPrompt` broker and the
|
|
22
|
+
* SSE `createPromptClient` bridge. A `Terminal` answers each prompt LOCALLY at this machine's
|
|
23
|
+
* keyboard: it reads raw-mode stdin, drives the pure core `*Reduce` reducers, renders each `view` in
|
|
24
|
+
* place, and resolves on submit / rejects with a {@link import('../core/index.js').TerminalError} (`CANCEL`)
|
|
25
|
+
* on ctrl-c. It is the ONLY impure part of the prompt stack.
|
|
26
|
+
*
|
|
27
|
+
* @param options - See {@link TerminalOptions}
|
|
28
|
+
* @returns A {@link TerminalInterface} — the six async prompt forms (`input` / `password` / `confirm`
|
|
29
|
+
* / `select` / `checkbox` / `editor`) driven over the resolved streams
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* - **Drives the pure reducers.** Each prompt builds its initial state (`create*State`), enters raw
|
|
33
|
+
* mode ONCE, and feeds each keypress through `parseKey` → the reducer → an in-place re-render; the
|
|
34
|
+
* driver owns no prompt logic itself (state / view / validation / cancel all come from the core).
|
|
35
|
+
* - **Raw-mode leak-free.** Raw mode is entered exactly once per prompt and ALWAYS cleaned up — on
|
|
36
|
+
* submit, on cancel, and on a throw — leaving no raw mode and no leaked `'data'` listener.
|
|
37
|
+
* - **Injectable + guard-narrowed.** `options.input` / `options.output` default to `process.stdin` /
|
|
38
|
+
* `process.stdout` but accept ANY {@link import('./types.js').InputStreamInterface} /
|
|
39
|
+
* {@link import('./types.js').OutputStreamInterface}, resolved through their §14 guards (never an
|
|
40
|
+
* `as`), so a test drives every prompt with a fake TTY that emits scripted key chunks and records
|
|
41
|
+
* the rendered output — and asserts the resolved value, cancel-on-ctrl-c, and no leaked raw mode.
|
|
42
|
+
* - **Non-TTY fallback.** When `input` is not a TTY (piped), raw mode is unavailable, so the prompts
|
|
43
|
+
* fall back to `node:readline` line input (still validating); `select` / `checkbox` present a
|
|
44
|
+
* numbered list, and `editor` reads lines until EOF.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { createTerminal } from '@src/server'
|
|
49
|
+
*
|
|
50
|
+
* const terminal = createTerminal()
|
|
51
|
+
* const name = await terminal.input({ message: 'Your name' })
|
|
52
|
+
* const proceed = await terminal.confirm({ message: 'Continue?', default: true })
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function createTerminal(options?: TerminalOptions): TerminalInterface;
|
|
56
|
+
|
|
57
|
+
/** The Control Sequence Introducer (`ESC[`) — the prefix of every cursor / erase sequence. */
|
|
58
|
+
export declare const CSI: string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The cursor-UP sequence TEMPLATE (`ESC[{count}A`) — {@link import('./helpers.js').moveUp}
|
|
62
|
+
* interpolates `{count}` with the number of lines to climb (the `{count}` placeholder idiom the core
|
|
63
|
+
* terminals' `RULE_MESSAGES` uses). Kept as a template so the count stays out of the constant.
|
|
64
|
+
*/
|
|
65
|
+
export declare const CSI_UP: string;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Hide the cursor (`ESC[?25l`) — written before the driver starts redrawing a prompt so the cursor
|
|
69
|
+
* does not flicker across the view during an in-place re-render; paired with {@link CURSOR_SHOW}.
|
|
70
|
+
*/
|
|
71
|
+
export declare const CURSOR_HIDE: string;
|
|
72
|
+
|
|
73
|
+
/** Show the cursor (`ESC[?25h`) — restores the cursor after a prompt resolves / cancels (the {@link CURSOR_HIDE} pair). */
|
|
74
|
+
export declare const CURSOR_SHOW: string;
|
|
75
|
+
|
|
76
|
+
/** The Escape byte (ESC, U+001B) — the lead byte of every CSI cursor-control sequence below. */
|
|
77
|
+
export declare const ESCAPE: string;
|
|
78
|
+
|
|
79
|
+
/** The comma-separated multi-select hint the non-TTY `checkbox` fallback shows (the user types one or more numbers). */
|
|
80
|
+
export declare const FALLBACK_CHECKBOX_HINT = "Enter numbers separated by commas";
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The numbered-list prompt the non-TTY {@link import('./Terminal.js').Terminal} `select` / `checkbox`
|
|
84
|
+
* fallback appends — a piped (non-terminal) stream cannot navigate with arrow keys, so the choices are
|
|
85
|
+
* printed numbered and the user types the number(s) on a single readline line.
|
|
86
|
+
*/
|
|
87
|
+
export declare const FALLBACK_SELECT_HINT = "Enter a number";
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The minimal input-stream shape the {@link TerminalInterface} reads — exactly the slice of a Node
|
|
91
|
+
* `tty.ReadStream` / `process.stdin` it touches, and no more (AGENTS §21 — minimal interface). A
|
|
92
|
+
* {@link TerminalOptions} `input` is narrowed to this via
|
|
93
|
+
* {@link import('./helpers.js').isInputStream} (AGENTS §14 — narrow the boundary, never `as`), so a
|
|
94
|
+
* test drives every prompt with a hand-built fake stream that emits scripted key chunks and never
|
|
95
|
+
* touches the real `process.stdin` — and asserts raw mode is entered exactly once and always
|
|
96
|
+
* cleaned up (no leak).
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* - `on(event, listener)` / `off(event, listener)` — subscribe / unsubscribe a `'data'` chunk
|
|
100
|
+
* listener (the irreducible event seam; a `Buffer` / string / `Uint8Array` chunk arrives). The two
|
|
101
|
+
* required methods.
|
|
102
|
+
* - `setRawMode(mode)` — switch the TTY in / out of raw mode (each keypress delivered immediately,
|
|
103
|
+
* no line buffering, no echo). Present on a real `tty.ReadStream`; ABSENT on a piped, non-TTY
|
|
104
|
+
* stream — its absence (or `isTTY !== true`) selects the {@link import('node:readline').Interface}
|
|
105
|
+
* line-input fallback. The ONLY place raw mode is touched is {@link import('./Terminal.js').Terminal}'s
|
|
106
|
+
* `#enterRaw`.
|
|
107
|
+
* - `resume()` / `pause()` — start / stop the flow of `'data'` events. The raw-mode primitive
|
|
108
|
+
* `resume()`s on enter and `pause()`s on cleanup; optional (a fake may omit them).
|
|
109
|
+
* - `isTTY` — `true` on a real terminal, absent / `false` when piped to a file or another process.
|
|
110
|
+
* The driver reads it to choose the raw-mode path (interactive arrow-key prompts) vs. the readline
|
|
111
|
+
* fallback (numbered / line input).
|
|
112
|
+
*/
|
|
113
|
+
export declare interface InputStreamInterface {
|
|
114
|
+
on(event: 'data', listener: (chunk: string | Uint8Array) => void): void;
|
|
115
|
+
off(event: 'data', listener: (chunk: string | Uint8Array) => void): void;
|
|
116
|
+
setRawMode?(mode: boolean): void;
|
|
117
|
+
resume?(): void;
|
|
118
|
+
pause?(): void;
|
|
119
|
+
readonly isTTY?: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Whether `value` is a usable {@link InputStreamInterface} — a record with callable `on` / `off`
|
|
124
|
+
* `'data'` subscription methods. A total type guard (AGENTS §14): it NEVER throws and returns `false`
|
|
125
|
+
* for anything off-shape, so it narrows the one unavoidable input boundary (the real `process.stdin`,
|
|
126
|
+
* or a fake TTY a test injects) to the exact slice the driver reads — no `as`.
|
|
127
|
+
*
|
|
128
|
+
* @remarks
|
|
129
|
+
* Only `on` / `off` are required (the irreducible event seam); `setRawMode` / `resume` / `pause` /
|
|
130
|
+
* `isTTY` are optional on {@link InputStreamInterface}, so their absence does not disqualify a stream
|
|
131
|
+
* — a piped, non-TTY stream is still a valid input, just one the driver reads through the readline
|
|
132
|
+
* fallback rather than raw mode.
|
|
133
|
+
*
|
|
134
|
+
* @param value - Any value crossing the boundary (a process stream, an injected fake, `unknown`)
|
|
135
|
+
* @returns `true` when `value` has callable `on` and `off`
|
|
136
|
+
*/
|
|
137
|
+
export declare function isInputStream(value: unknown): value is InputStreamInterface;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Whether `value` is a usable {@link OutputStreamInterface} — a record with a callable `write`. A
|
|
141
|
+
* total type guard (AGENTS §14): it NEVER throws and returns `false` for anything off-shape, so it
|
|
142
|
+
* narrows the output boundary (the real `process.stdout`, or a recording fake a test injects) to the
|
|
143
|
+
* one method the driver writes through — no `as`.
|
|
144
|
+
*
|
|
145
|
+
* @param value - Any value crossing the boundary (a process stream, an injected fake, `unknown`)
|
|
146
|
+
* @returns `true` when `value` has a callable `write`
|
|
147
|
+
*/
|
|
148
|
+
export declare function isOutputStream(value: unknown): value is OutputStreamInterface;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Whether an input stream can be driven in RAW mode — it both reports `isTTY === true` AND exposes a
|
|
152
|
+
* callable `setRawMode`. The {@link import('./Terminal.js').Terminal} probes this to choose its path:
|
|
153
|
+
* `true` ⇒ the interactive raw-mode prompts (arrow-key navigation, live re-render); `false` ⇒ the
|
|
154
|
+
* `node:readline` line-input fallback (a piped / non-terminal stream cannot enter raw mode). Total —
|
|
155
|
+
* never throws.
|
|
156
|
+
*
|
|
157
|
+
* @param input - The resolved {@link InputStreamInterface}
|
|
158
|
+
* @returns `true` when the stream is a TTY with `setRawMode`
|
|
159
|
+
*/
|
|
160
|
+
export declare function isRawCapable(input: InputStreamInterface): boolean;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Whether `value` is a Node {@link NodeJS.ReadableStream} — a total structural guard (AGENTS §14)
|
|
164
|
+
* checking for the callable `read` / `pipe` / `on` that `node:readline`'s `createInterface` requires
|
|
165
|
+
* as its `input`. The non-TTY fallback narrows the resolved input stream through this before handing
|
|
166
|
+
* it to readline (never an `as`), so a real piped `process.stdin` (or a `PassThrough` a test injects)
|
|
167
|
+
* crosses into the readline boundary honestly. Never throws; returns `false` for a minimal fake that
|
|
168
|
+
* isn't a full readable.
|
|
169
|
+
*
|
|
170
|
+
* @param value - The resolved input stream (or any value crossing the boundary)
|
|
171
|
+
* @returns `true` when `value` has the readable methods readline needs
|
|
172
|
+
*/
|
|
173
|
+
export declare function isReadable(value: unknown): value is NodeJS.ReadableStream;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Whether `value` is a Node {@link NodeJS.WritableStream} — a total structural guard (AGENTS §14)
|
|
177
|
+
* checking for the callable `write` / `end` that `node:readline`'s `createInterface` accepts as its
|
|
178
|
+
* `output`. Paired with {@link isReadable} so the non-TTY fallback narrows BOTH streams to the
|
|
179
|
+
* readline boundary without an `as`. Never throws.
|
|
180
|
+
*
|
|
181
|
+
* @param value - The resolved output stream (or any value crossing the boundary)
|
|
182
|
+
* @returns `true` when `value` has the writable methods readline needs
|
|
183
|
+
*/
|
|
184
|
+
export declare function isWritable(value: unknown): value is NodeJS.WritableStream;
|
|
185
|
+
|
|
186
|
+
/** A line feed (`\n`, U+000A) — the line terminator the driver writes after the final committed prompt view. */
|
|
187
|
+
export declare const LINE_FEED: string;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The number of terminal LINES a rendered prompt `view` occupies — one more than its newline count
|
|
191
|
+
* (a view with no newline is a single line; N newlines span N+1 lines). The basis of the in-place
|
|
192
|
+
* re-render: the driver records the line count of the view it just wrote so the next redraw knows how
|
|
193
|
+
* far up to move the cursor before overwriting. Total; an empty string is one (empty) line.
|
|
194
|
+
*
|
|
195
|
+
* @param view - The rendered (possibly multi-line, possibly ANSI-styled) view string
|
|
196
|
+
* @returns The number of lines the view spans (always at least 1)
|
|
197
|
+
*/
|
|
198
|
+
export declare function lineCount(view: string): number;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* The cursor-UP control sequence that moves the cursor up `count` lines (`ESC[{count}A`) — or the
|
|
202
|
+
* empty string when `count` is zero or negative (no movement needed, and `ESC[0A` is a wasted write).
|
|
203
|
+
* The pure step the in-place re-render uses to climb back over the previous view before clearing it.
|
|
204
|
+
* Total.
|
|
205
|
+
*
|
|
206
|
+
* @param count - How many lines to move the cursor up
|
|
207
|
+
* @returns The `ESC[{count}A` sequence, or `''` when `count <= 0`
|
|
208
|
+
*/
|
|
209
|
+
export declare function moveUp(count: number): string;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* The minimal output-stream shape the {@link TerminalInterface} writes — exactly the slice of a Node
|
|
213
|
+
* `tty.WriteStream` / `process.stdout` it touches (AGENTS §21). A {@link TerminalOptions} `output`
|
|
214
|
+
* is narrowed to this via {@link import('./helpers.js').isOutputStream} (AGENTS §14), so a test
|
|
215
|
+
* records every byte the driver renders (the prompt view, the cursor-management sequences) with a
|
|
216
|
+
* fake stream and asserts the rendered content (ANSI stripped) and the resolved value.
|
|
217
|
+
*
|
|
218
|
+
* @remarks
|
|
219
|
+
* - `write(text)` — the one required method: push a chunk (a rendered prompt view, a cursor / clear
|
|
220
|
+
* escape sequence) to the stream. A real stream returns a backpressure boolean; the driver ignores
|
|
221
|
+
* the return (a prompt is human-paced, never backpressured), so a fake may return `void`.
|
|
222
|
+
* - `isTTY` — present and `true` on a real terminal. The driver does not branch its rendering on it
|
|
223
|
+
* (the styler already decided color); it is part of the minimal shape for symmetry with the input
|
|
224
|
+
* stream and so a consumer may inspect it.
|
|
225
|
+
*/
|
|
226
|
+
export declare interface OutputStreamInterface {
|
|
227
|
+
write(text: string): boolean | void;
|
|
228
|
+
readonly isTTY?: boolean;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* The full reposition-and-clear prefix to write BEFORE re-rendering a prompt view in place — given
|
|
233
|
+
* the line count of the PREVIOUS view, it moves the cursor up over those lines, returns it to column
|
|
234
|
+
* 0, and erases everything from there to the end of the screen, so the next view is drawn on a clean
|
|
235
|
+
* region (no orphaned rows from a taller previous view). Pure; the driver writes this immediately
|
|
236
|
+
* followed by the new view.
|
|
237
|
+
*
|
|
238
|
+
* @remarks
|
|
239
|
+
* For the FIRST render `previousLines` is `1` (the cursor sits on the line the prompt opened on) so
|
|
240
|
+
* the prefix is just a carriage return + clear-down — the prompt draws from the current line. For a
|
|
241
|
+
* subsequent render it climbs `previousLines - 1` lines (the cursor is on the LAST line of the prior
|
|
242
|
+
* view) before clearing. Keeping the math here (not in the driver) makes the re-render unit-testable
|
|
243
|
+
* without a real terminal.
|
|
244
|
+
*
|
|
245
|
+
* @param previousLines - The line count of the view currently on screen (from {@link lineCount})
|
|
246
|
+
* @returns The control-sequence prefix to write before the new view
|
|
247
|
+
*/
|
|
248
|
+
export declare function redrawPrefix(previousLines: number): string;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The interactive terminal prompt driver (T-c) — the third {@link TerminalInterface} surface (beside
|
|
252
|
+
* the core headless `Prompt` broker and the SSE `PromptClient` bridge), and the ONLY impure part of
|
|
253
|
+
* the prompt stack. It reads the TTY and DRIVES the pure core `*Reduce` reducers: it feeds raw-mode
|
|
254
|
+
* stdin bytes through `parseKey` into the matching reducer, renders the returned `view` in place, and
|
|
255
|
+
* resolves on a `submit` step / rejects with a {@link TerminalError} (`CANCEL`) on ctrl-c. It owns no
|
|
256
|
+
* prompt logic of its own — state, view, validation, and the cancel signal all come from the pure
|
|
257
|
+
* core; this class owns ONLY the cursor + raw-mode + in-place re-render mechanics.
|
|
258
|
+
*
|
|
259
|
+
* @remarks
|
|
260
|
+
* See {@link TerminalInterface} for the behavioral contract (raw-mode leak-freedom, the in-place
|
|
261
|
+
* re-render, the non-TTY readline fallback, event-free).
|
|
262
|
+
*/
|
|
263
|
+
export declare class Terminal implements TerminalInterface {
|
|
264
|
+
#private;
|
|
265
|
+
constructor(options?: TerminalOptions);
|
|
266
|
+
input(options: InputOptions): Promise<string>;
|
|
267
|
+
password(options: PasswordOptions): Promise<string>;
|
|
268
|
+
confirm(options: ConfirmOptions): Promise<boolean>;
|
|
269
|
+
select(options: SelectOptions): Promise<string>;
|
|
270
|
+
checkbox(options: CheckboxOptions): Promise<readonly string[]>;
|
|
271
|
+
editor(options: EditorOptions): Promise<string>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* The interactive terminal prompt DRIVER (the third {@link PromptFormInterface} surface) — reads the
|
|
276
|
+
* TTY and DRIVES the pure core `*Reduce` reducers, the ONLY impure part of the prompt stack. Where
|
|
277
|
+
* the core `Prompt` broker PARKS each prompt and the `PromptClient` bridges one over SSE, a
|
|
278
|
+
* `Terminal` answers each prompt LOCALLY at this machine's keyboard: it feeds raw-mode stdin bytes
|
|
279
|
+
* through `parseKey` into the matching reducer, renders the returned `view` in place (tracking the
|
|
280
|
+
* previous view's line count to overwrite it), and resolves on a `submit` step / rejects with a
|
|
281
|
+
* {@link import('../core/index.js').TerminalError} (`CANCEL`) on ctrl-c.
|
|
282
|
+
*
|
|
283
|
+
* @remarks
|
|
284
|
+
* - **Drives the pure reducers.** Each method builds the initial state (`create*State(options)`),
|
|
285
|
+
* enters raw mode once, and on each keypress runs `parseKey` → the reducer → an in-place re-render;
|
|
286
|
+
* it owns NO prompt logic of its own (state, view, validation, and the cancel signal all come from
|
|
287
|
+
* the pure core).
|
|
288
|
+
* - **Raw-mode leak-free.** Raw mode is entered exactly once per prompt and ALWAYS cleaned up — on
|
|
289
|
+
* submit, on cancel, and on a throw — leaving no raw mode and no leaked `'data'` listener.
|
|
290
|
+
* - **In-place re-render.** Between keystrokes the cursor is moved up over the previous view's lines,
|
|
291
|
+
* the screen cleared down, and the new view written — so a `select` / `checkbox` list redraws live;
|
|
292
|
+
* the cursor is hidden during the prompt and restored after.
|
|
293
|
+
* - **Non-TTY fallback.** When `input` is not a TTY, raw mode is unavailable, so the prompts fall
|
|
294
|
+
* back to `node:readline` line input (still validating) — `select` / `checkbox` present a numbered
|
|
295
|
+
* list read via a readline line, and `editor` reads lines until EOF.
|
|
296
|
+
* - **Event-free.** A `Terminal` is a request / response driver — each prompt is a Promise; there is
|
|
297
|
+
* no observable lifecycle worth an emitter, so (unlike the broker / bridge) it carries none.
|
|
298
|
+
*/
|
|
299
|
+
export declare interface TerminalInterface extends PromptFormInterface {
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Options for {@link import('./factories.js').createTerminal} — both streams optional, so a bare
|
|
304
|
+
* `createTerminal()` drives the real `process.stdin` / `process.stdout`.
|
|
305
|
+
*
|
|
306
|
+
* @remarks
|
|
307
|
+
* - `input` — the stream keystrokes are read from; defaults to `process.stdin`. Any
|
|
308
|
+
* {@link InputStreamInterface}-shaped stream is accepted (resolved through
|
|
309
|
+
* {@link import('./helpers.js').isInputStream}, never `as`), so a test injects a fake TTY that
|
|
310
|
+
* emits scripted `'data'` chunks. When the stream is not a TTY (no `setRawMode` / `isTTY !== true`),
|
|
311
|
+
* the prompts fall back to `node:readline` line input.
|
|
312
|
+
* - `output` — the stream the prompt view is rendered to; defaults to `process.stdout`. Any
|
|
313
|
+
* {@link OutputStreamInterface}-shaped stream is accepted (resolved through
|
|
314
|
+
* {@link import('./helpers.js').isOutputStream}), so a test records the rendered output.
|
|
315
|
+
*/
|
|
316
|
+
export declare interface TerminalOptions {
|
|
317
|
+
readonly input?: InputStreamInterface;
|
|
318
|
+
readonly output?: OutputStreamInterface;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export { }
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { CheckboxOptions } from '../core/index.js';
|
|
2
|
+
import { ConfirmOptions } from '../core/index.js';
|
|
3
|
+
import { EditorOptions } from '../core/index.js';
|
|
4
|
+
import { InputOptions } from '../core/index.js';
|
|
5
|
+
import { PasswordOptions } from '../core/index.js';
|
|
6
|
+
import { PromptFormInterface } from '../core/index.js';
|
|
7
|
+
import { SelectOptions } from '../core/index.js';
|
|
8
|
+
|
|
9
|
+
/** A carriage return (`\r`, U+000D) — returns the cursor to column 0 so a redraw starts at the line's left edge. */
|
|
10
|
+
export declare const CARRIAGE_RETURN: string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Erase from the cursor down to the end of the screen (`ESC[J`) — wipes the WHOLE previous (possibly
|
|
14
|
+
* multi-line `select` / `checkbox`) view in one write before the new view is rendered, so a redraw
|
|
15
|
+
* never leaves orphaned rows below.
|
|
16
|
+
*/
|
|
17
|
+
export declare const CLEAR_DOWN: string;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Create the interactive terminal prompt {@link TerminalInterface} (T-c) — the local-TTY arm of the
|
|
21
|
+
* prompt tri-surface, the env-symmetric sibling of the core headless `createPrompt` broker and the
|
|
22
|
+
* SSE `createPromptClient` bridge. A `Terminal` answers each prompt LOCALLY at this machine's
|
|
23
|
+
* keyboard: it reads raw-mode stdin, drives the pure core `*Reduce` reducers, renders each `view` in
|
|
24
|
+
* place, and resolves on submit / rejects with a {@link import('../core/index.js').TerminalError} (`CANCEL`)
|
|
25
|
+
* on ctrl-c. It is the ONLY impure part of the prompt stack.
|
|
26
|
+
*
|
|
27
|
+
* @param options - See {@link TerminalOptions}
|
|
28
|
+
* @returns A {@link TerminalInterface} — the six async prompt forms (`input` / `password` / `confirm`
|
|
29
|
+
* / `select` / `checkbox` / `editor`) driven over the resolved streams
|
|
30
|
+
*
|
|
31
|
+
* @remarks
|
|
32
|
+
* - **Drives the pure reducers.** Each prompt builds its initial state (`create*State`), enters raw
|
|
33
|
+
* mode ONCE, and feeds each keypress through `parseKey` → the reducer → an in-place re-render; the
|
|
34
|
+
* driver owns no prompt logic itself (state / view / validation / cancel all come from the core).
|
|
35
|
+
* - **Raw-mode leak-free.** Raw mode is entered exactly once per prompt and ALWAYS cleaned up — on
|
|
36
|
+
* submit, on cancel, and on a throw — leaving no raw mode and no leaked `'data'` listener.
|
|
37
|
+
* - **Injectable + guard-narrowed.** `options.input` / `options.output` default to `process.stdin` /
|
|
38
|
+
* `process.stdout` but accept ANY {@link import('./types.js').InputStreamInterface} /
|
|
39
|
+
* {@link import('./types.js').OutputStreamInterface}, resolved through their §14 guards (never an
|
|
40
|
+
* `as`), so a test drives every prompt with a fake TTY that emits scripted key chunks and records
|
|
41
|
+
* the rendered output — and asserts the resolved value, cancel-on-ctrl-c, and no leaked raw mode.
|
|
42
|
+
* - **Non-TTY fallback.** When `input` is not a TTY (piped), raw mode is unavailable, so the prompts
|
|
43
|
+
* fall back to `node:readline` line input (still validating); `select` / `checkbox` present a
|
|
44
|
+
* numbered list, and `editor` reads lines until EOF.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* ```ts
|
|
48
|
+
* import { createTerminal } from '@src/server'
|
|
49
|
+
*
|
|
50
|
+
* const terminal = createTerminal()
|
|
51
|
+
* const name = await terminal.input({ message: 'Your name' })
|
|
52
|
+
* const proceed = await terminal.confirm({ message: 'Continue?', default: true })
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function createTerminal(options?: TerminalOptions): TerminalInterface;
|
|
56
|
+
|
|
57
|
+
/** The Control Sequence Introducer (`ESC[`) — the prefix of every cursor / erase sequence. */
|
|
58
|
+
export declare const CSI: string;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* The cursor-UP sequence TEMPLATE (`ESC[{count}A`) — {@link import('./helpers.js').moveUp}
|
|
62
|
+
* interpolates `{count}` with the number of lines to climb (the `{count}` placeholder idiom the core
|
|
63
|
+
* terminals' `RULE_MESSAGES` uses). Kept as a template so the count stays out of the constant.
|
|
64
|
+
*/
|
|
65
|
+
export declare const CSI_UP: string;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Hide the cursor (`ESC[?25l`) — written before the driver starts redrawing a prompt so the cursor
|
|
69
|
+
* does not flicker across the view during an in-place re-render; paired with {@link CURSOR_SHOW}.
|
|
70
|
+
*/
|
|
71
|
+
export declare const CURSOR_HIDE: string;
|
|
72
|
+
|
|
73
|
+
/** Show the cursor (`ESC[?25h`) — restores the cursor after a prompt resolves / cancels (the {@link CURSOR_HIDE} pair). */
|
|
74
|
+
export declare const CURSOR_SHOW: string;
|
|
75
|
+
|
|
76
|
+
/** The Escape byte (ESC, U+001B) — the lead byte of every CSI cursor-control sequence below. */
|
|
77
|
+
export declare const ESCAPE: string;
|
|
78
|
+
|
|
79
|
+
/** The comma-separated multi-select hint the non-TTY `checkbox` fallback shows (the user types one or more numbers). */
|
|
80
|
+
export declare const FALLBACK_CHECKBOX_HINT = "Enter numbers separated by commas";
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* The numbered-list prompt the non-TTY {@link import('./Terminal.js').Terminal} `select` / `checkbox`
|
|
84
|
+
* fallback appends — a piped (non-terminal) stream cannot navigate with arrow keys, so the choices are
|
|
85
|
+
* printed numbered and the user types the number(s) on a single readline line.
|
|
86
|
+
*/
|
|
87
|
+
export declare const FALLBACK_SELECT_HINT = "Enter a number";
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The minimal input-stream shape the {@link TerminalInterface} reads — exactly the slice of a Node
|
|
91
|
+
* `tty.ReadStream` / `process.stdin` it touches, and no more (AGENTS §21 — minimal interface). A
|
|
92
|
+
* {@link TerminalOptions} `input` is narrowed to this via
|
|
93
|
+
* {@link import('./helpers.js').isInputStream} (AGENTS §14 — narrow the boundary, never `as`), so a
|
|
94
|
+
* test drives every prompt with a hand-built fake stream that emits scripted key chunks and never
|
|
95
|
+
* touches the real `process.stdin` — and asserts raw mode is entered exactly once and always
|
|
96
|
+
* cleaned up (no leak).
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* - `on(event, listener)` / `off(event, listener)` — subscribe / unsubscribe a `'data'` chunk
|
|
100
|
+
* listener (the irreducible event seam; a `Buffer` / string / `Uint8Array` chunk arrives). The two
|
|
101
|
+
* required methods.
|
|
102
|
+
* - `setRawMode(mode)` — switch the TTY in / out of raw mode (each keypress delivered immediately,
|
|
103
|
+
* no line buffering, no echo). Present on a real `tty.ReadStream`; ABSENT on a piped, non-TTY
|
|
104
|
+
* stream — its absence (or `isTTY !== true`) selects the {@link import('node:readline').Interface}
|
|
105
|
+
* line-input fallback. The ONLY place raw mode is touched is {@link import('./Terminal.js').Terminal}'s
|
|
106
|
+
* `#enterRaw`.
|
|
107
|
+
* - `resume()` / `pause()` — start / stop the flow of `'data'` events. The raw-mode primitive
|
|
108
|
+
* `resume()`s on enter and `pause()`s on cleanup; optional (a fake may omit them).
|
|
109
|
+
* - `isTTY` — `true` on a real terminal, absent / `false` when piped to a file or another process.
|
|
110
|
+
* The driver reads it to choose the raw-mode path (interactive arrow-key prompts) vs. the readline
|
|
111
|
+
* fallback (numbered / line input).
|
|
112
|
+
*/
|
|
113
|
+
export declare interface InputStreamInterface {
|
|
114
|
+
on(event: 'data', listener: (chunk: string | Uint8Array) => void): void;
|
|
115
|
+
off(event: 'data', listener: (chunk: string | Uint8Array) => void): void;
|
|
116
|
+
setRawMode?(mode: boolean): void;
|
|
117
|
+
resume?(): void;
|
|
118
|
+
pause?(): void;
|
|
119
|
+
readonly isTTY?: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Whether `value` is a usable {@link InputStreamInterface} — a record with callable `on` / `off`
|
|
124
|
+
* `'data'` subscription methods. A total type guard (AGENTS §14): it NEVER throws and returns `false`
|
|
125
|
+
* for anything off-shape, so it narrows the one unavoidable input boundary (the real `process.stdin`,
|
|
126
|
+
* or a fake TTY a test injects) to the exact slice the driver reads — no `as`.
|
|
127
|
+
*
|
|
128
|
+
* @remarks
|
|
129
|
+
* Only `on` / `off` are required (the irreducible event seam); `setRawMode` / `resume` / `pause` /
|
|
130
|
+
* `isTTY` are optional on {@link InputStreamInterface}, so their absence does not disqualify a stream
|
|
131
|
+
* — a piped, non-TTY stream is still a valid input, just one the driver reads through the readline
|
|
132
|
+
* fallback rather than raw mode.
|
|
133
|
+
*
|
|
134
|
+
* @param value - Any value crossing the boundary (a process stream, an injected fake, `unknown`)
|
|
135
|
+
* @returns `true` when `value` has callable `on` and `off`
|
|
136
|
+
*/
|
|
137
|
+
export declare function isInputStream(value: unknown): value is InputStreamInterface;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Whether `value` is a usable {@link OutputStreamInterface} — a record with a callable `write`. A
|
|
141
|
+
* total type guard (AGENTS §14): it NEVER throws and returns `false` for anything off-shape, so it
|
|
142
|
+
* narrows the output boundary (the real `process.stdout`, or a recording fake a test injects) to the
|
|
143
|
+
* one method the driver writes through — no `as`.
|
|
144
|
+
*
|
|
145
|
+
* @param value - Any value crossing the boundary (a process stream, an injected fake, `unknown`)
|
|
146
|
+
* @returns `true` when `value` has a callable `write`
|
|
147
|
+
*/
|
|
148
|
+
export declare function isOutputStream(value: unknown): value is OutputStreamInterface;
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Whether an input stream can be driven in RAW mode — it both reports `isTTY === true` AND exposes a
|
|
152
|
+
* callable `setRawMode`. The {@link import('./Terminal.js').Terminal} probes this to choose its path:
|
|
153
|
+
* `true` ⇒ the interactive raw-mode prompts (arrow-key navigation, live re-render); `false` ⇒ the
|
|
154
|
+
* `node:readline` line-input fallback (a piped / non-terminal stream cannot enter raw mode). Total —
|
|
155
|
+
* never throws.
|
|
156
|
+
*
|
|
157
|
+
* @param input - The resolved {@link InputStreamInterface}
|
|
158
|
+
* @returns `true` when the stream is a TTY with `setRawMode`
|
|
159
|
+
*/
|
|
160
|
+
export declare function isRawCapable(input: InputStreamInterface): boolean;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Whether `value` is a Node {@link NodeJS.ReadableStream} — a total structural guard (AGENTS §14)
|
|
164
|
+
* checking for the callable `read` / `pipe` / `on` that `node:readline`'s `createInterface` requires
|
|
165
|
+
* as its `input`. The non-TTY fallback narrows the resolved input stream through this before handing
|
|
166
|
+
* it to readline (never an `as`), so a real piped `process.stdin` (or a `PassThrough` a test injects)
|
|
167
|
+
* crosses into the readline boundary honestly. Never throws; returns `false` for a minimal fake that
|
|
168
|
+
* isn't a full readable.
|
|
169
|
+
*
|
|
170
|
+
* @param value - The resolved input stream (or any value crossing the boundary)
|
|
171
|
+
* @returns `true` when `value` has the readable methods readline needs
|
|
172
|
+
*/
|
|
173
|
+
export declare function isReadable(value: unknown): value is NodeJS.ReadableStream;
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Whether `value` is a Node {@link NodeJS.WritableStream} — a total structural guard (AGENTS §14)
|
|
177
|
+
* checking for the callable `write` / `end` that `node:readline`'s `createInterface` accepts as its
|
|
178
|
+
* `output`. Paired with {@link isReadable} so the non-TTY fallback narrows BOTH streams to the
|
|
179
|
+
* readline boundary without an `as`. Never throws.
|
|
180
|
+
*
|
|
181
|
+
* @param value - The resolved output stream (or any value crossing the boundary)
|
|
182
|
+
* @returns `true` when `value` has the writable methods readline needs
|
|
183
|
+
*/
|
|
184
|
+
export declare function isWritable(value: unknown): value is NodeJS.WritableStream;
|
|
185
|
+
|
|
186
|
+
/** A line feed (`\n`, U+000A) — the line terminator the driver writes after the final committed prompt view. */
|
|
187
|
+
export declare const LINE_FEED: string;
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* The number of terminal LINES a rendered prompt `view` occupies — one more than its newline count
|
|
191
|
+
* (a view with no newline is a single line; N newlines span N+1 lines). The basis of the in-place
|
|
192
|
+
* re-render: the driver records the line count of the view it just wrote so the next redraw knows how
|
|
193
|
+
* far up to move the cursor before overwriting. Total; an empty string is one (empty) line.
|
|
194
|
+
*
|
|
195
|
+
* @param view - The rendered (possibly multi-line, possibly ANSI-styled) view string
|
|
196
|
+
* @returns The number of lines the view spans (always at least 1)
|
|
197
|
+
*/
|
|
198
|
+
export declare function lineCount(view: string): number;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* The cursor-UP control sequence that moves the cursor up `count` lines (`ESC[{count}A`) — or the
|
|
202
|
+
* empty string when `count` is zero or negative (no movement needed, and `ESC[0A` is a wasted write).
|
|
203
|
+
* The pure step the in-place re-render uses to climb back over the previous view before clearing it.
|
|
204
|
+
* Total.
|
|
205
|
+
*
|
|
206
|
+
* @param count - How many lines to move the cursor up
|
|
207
|
+
* @returns The `ESC[{count}A` sequence, or `''` when `count <= 0`
|
|
208
|
+
*/
|
|
209
|
+
export declare function moveUp(count: number): string;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* The minimal output-stream shape the {@link TerminalInterface} writes — exactly the slice of a Node
|
|
213
|
+
* `tty.WriteStream` / `process.stdout` it touches (AGENTS §21). A {@link TerminalOptions} `output`
|
|
214
|
+
* is narrowed to this via {@link import('./helpers.js').isOutputStream} (AGENTS §14), so a test
|
|
215
|
+
* records every byte the driver renders (the prompt view, the cursor-management sequences) with a
|
|
216
|
+
* fake stream and asserts the rendered content (ANSI stripped) and the resolved value.
|
|
217
|
+
*
|
|
218
|
+
* @remarks
|
|
219
|
+
* - `write(text)` — the one required method: push a chunk (a rendered prompt view, a cursor / clear
|
|
220
|
+
* escape sequence) to the stream. A real stream returns a backpressure boolean; the driver ignores
|
|
221
|
+
* the return (a prompt is human-paced, never backpressured), so a fake may return `void`.
|
|
222
|
+
* - `isTTY` — present and `true` on a real terminal. The driver does not branch its rendering on it
|
|
223
|
+
* (the styler already decided color); it is part of the minimal shape for symmetry with the input
|
|
224
|
+
* stream and so a consumer may inspect it.
|
|
225
|
+
*/
|
|
226
|
+
export declare interface OutputStreamInterface {
|
|
227
|
+
write(text: string): boolean | void;
|
|
228
|
+
readonly isTTY?: boolean;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* The full reposition-and-clear prefix to write BEFORE re-rendering a prompt view in place — given
|
|
233
|
+
* the line count of the PREVIOUS view, it moves the cursor up over those lines, returns it to column
|
|
234
|
+
* 0, and erases everything from there to the end of the screen, so the next view is drawn on a clean
|
|
235
|
+
* region (no orphaned rows from a taller previous view). Pure; the driver writes this immediately
|
|
236
|
+
* followed by the new view.
|
|
237
|
+
*
|
|
238
|
+
* @remarks
|
|
239
|
+
* For the FIRST render `previousLines` is `1` (the cursor sits on the line the prompt opened on) so
|
|
240
|
+
* the prefix is just a carriage return + clear-down — the prompt draws from the current line. For a
|
|
241
|
+
* subsequent render it climbs `previousLines - 1` lines (the cursor is on the LAST line of the prior
|
|
242
|
+
* view) before clearing. Keeping the math here (not in the driver) makes the re-render unit-testable
|
|
243
|
+
* without a real terminal.
|
|
244
|
+
*
|
|
245
|
+
* @param previousLines - The line count of the view currently on screen (from {@link lineCount})
|
|
246
|
+
* @returns The control-sequence prefix to write before the new view
|
|
247
|
+
*/
|
|
248
|
+
export declare function redrawPrefix(previousLines: number): string;
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* The interactive terminal prompt driver (T-c) — the third {@link TerminalInterface} surface (beside
|
|
252
|
+
* the core headless `Prompt` broker and the SSE `PromptClient` bridge), and the ONLY impure part of
|
|
253
|
+
* the prompt stack. It reads the TTY and DRIVES the pure core `*Reduce` reducers: it feeds raw-mode
|
|
254
|
+
* stdin bytes through `parseKey` into the matching reducer, renders the returned `view` in place, and
|
|
255
|
+
* resolves on a `submit` step / rejects with a {@link TerminalError} (`CANCEL`) on ctrl-c. It owns no
|
|
256
|
+
* prompt logic of its own — state, view, validation, and the cancel signal all come from the pure
|
|
257
|
+
* core; this class owns ONLY the cursor + raw-mode + in-place re-render mechanics.
|
|
258
|
+
*
|
|
259
|
+
* @remarks
|
|
260
|
+
* See {@link TerminalInterface} for the behavioral contract (raw-mode leak-freedom, the in-place
|
|
261
|
+
* re-render, the non-TTY readline fallback, event-free).
|
|
262
|
+
*/
|
|
263
|
+
export declare class Terminal implements TerminalInterface {
|
|
264
|
+
#private;
|
|
265
|
+
constructor(options?: TerminalOptions);
|
|
266
|
+
input(options: InputOptions): Promise<string>;
|
|
267
|
+
password(options: PasswordOptions): Promise<string>;
|
|
268
|
+
confirm(options: ConfirmOptions): Promise<boolean>;
|
|
269
|
+
select(options: SelectOptions): Promise<string>;
|
|
270
|
+
checkbox(options: CheckboxOptions): Promise<readonly string[]>;
|
|
271
|
+
editor(options: EditorOptions): Promise<string>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* The interactive terminal prompt DRIVER (the third {@link PromptFormInterface} surface) — reads the
|
|
276
|
+
* TTY and DRIVES the pure core `*Reduce` reducers, the ONLY impure part of the prompt stack. Where
|
|
277
|
+
* the core `Prompt` broker PARKS each prompt and the `PromptClient` bridges one over SSE, a
|
|
278
|
+
* `Terminal` answers each prompt LOCALLY at this machine's keyboard: it feeds raw-mode stdin bytes
|
|
279
|
+
* through `parseKey` into the matching reducer, renders the returned `view` in place (tracking the
|
|
280
|
+
* previous view's line count to overwrite it), and resolves on a `submit` step / rejects with a
|
|
281
|
+
* {@link import('../core/index.js').TerminalError} (`CANCEL`) on ctrl-c.
|
|
282
|
+
*
|
|
283
|
+
* @remarks
|
|
284
|
+
* - **Drives the pure reducers.** Each method builds the initial state (`create*State(options)`),
|
|
285
|
+
* enters raw mode once, and on each keypress runs `parseKey` → the reducer → an in-place re-render;
|
|
286
|
+
* it owns NO prompt logic of its own (state, view, validation, and the cancel signal all come from
|
|
287
|
+
* the pure core).
|
|
288
|
+
* - **Raw-mode leak-free.** Raw mode is entered exactly once per prompt and ALWAYS cleaned up — on
|
|
289
|
+
* submit, on cancel, and on a throw — leaving no raw mode and no leaked `'data'` listener.
|
|
290
|
+
* - **In-place re-render.** Between keystrokes the cursor is moved up over the previous view's lines,
|
|
291
|
+
* the screen cleared down, and the new view written — so a `select` / `checkbox` list redraws live;
|
|
292
|
+
* the cursor is hidden during the prompt and restored after.
|
|
293
|
+
* - **Non-TTY fallback.** When `input` is not a TTY, raw mode is unavailable, so the prompts fall
|
|
294
|
+
* back to `node:readline` line input (still validating) — `select` / `checkbox` present a numbered
|
|
295
|
+
* list read via a readline line, and `editor` reads lines until EOF.
|
|
296
|
+
* - **Event-free.** A `Terminal` is a request / response driver — each prompt is a Promise; there is
|
|
297
|
+
* no observable lifecycle worth an emitter, so (unlike the broker / bridge) it carries none.
|
|
298
|
+
*/
|
|
299
|
+
export declare interface TerminalInterface extends PromptFormInterface {
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Options for {@link import('./factories.js').createTerminal} — both streams optional, so a bare
|
|
304
|
+
* `createTerminal()` drives the real `process.stdin` / `process.stdout`.
|
|
305
|
+
*
|
|
306
|
+
* @remarks
|
|
307
|
+
* - `input` — the stream keystrokes are read from; defaults to `process.stdin`. Any
|
|
308
|
+
* {@link InputStreamInterface}-shaped stream is accepted (resolved through
|
|
309
|
+
* {@link import('./helpers.js').isInputStream}, never `as`), so a test injects a fake TTY that
|
|
310
|
+
* emits scripted `'data'` chunks. When the stream is not a TTY (no `setRawMode` / `isTTY !== true`),
|
|
311
|
+
* the prompts fall back to `node:readline` line input.
|
|
312
|
+
* - `output` — the stream the prompt view is rendered to; defaults to `process.stdout`. Any
|
|
313
|
+
* {@link OutputStreamInterface}-shaped stream is accepted (resolved through
|
|
314
|
+
* {@link import('./helpers.js').isOutputStream}), so a test records the rendered output.
|
|
315
|
+
*/
|
|
316
|
+
export declare interface TerminalOptions {
|
|
317
|
+
readonly input?: InputStreamInterface;
|
|
318
|
+
readonly output?: OutputStreamInterface;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export { }
|