@sdxc/cli 0.0.0-pre.1 → 0.0.0-stage

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.
Files changed (55) hide show
  1. package/README.md +2 -363
  2. package/package.json +5 -40
  3. package/LICENSE.md +0 -21
  4. package/dist/argument.d.ts +0 -120
  5. package/dist/argument.js +0 -104
  6. package/dist/cli.d.ts +0 -68
  7. package/dist/cli.js +0 -186
  8. package/dist/command.d.ts +0 -139
  9. package/dist/command.js +0 -79
  10. package/dist/context.d.ts +0 -138
  11. package/dist/context.js +0 -175
  12. package/dist/errors.d.ts +0 -67
  13. package/dist/errors.js +0 -82
  14. package/dist/exec.d.ts +0 -83
  15. package/dist/exec.js +0 -136
  16. package/dist/flag.d.ts +0 -175
  17. package/dist/flag.js +0 -91
  18. package/dist/handler.d.ts +0 -73
  19. package/dist/handler.js +0 -30
  20. package/dist/help.d.ts +0 -18
  21. package/dist/help.js +0 -141
  22. package/dist/index.d.ts +0 -35
  23. package/dist/index.js +0 -20
  24. package/dist/interactions.d.ts +0 -27
  25. package/dist/interactions.js +0 -373
  26. package/dist/keys.d.ts +0 -49
  27. package/dist/keys.js +0 -146
  28. package/dist/lazy.d.ts +0 -29
  29. package/dist/lazy.js +0 -23
  30. package/dist/middleware.d.ts +0 -78
  31. package/dist/middleware.js +0 -9
  32. package/dist/parse.d.ts +0 -38
  33. package/dist/parse.js +0 -218
  34. package/dist/prompt.d.ts +0 -153
  35. package/dist/prompt.js +0 -53
  36. package/dist/resolve.d.ts +0 -27
  37. package/dist/resolve.js +0 -294
  38. package/dist/schema.d.ts +0 -27
  39. package/dist/schema.js +0 -34
  40. package/dist/screen.d.ts +0 -42
  41. package/dist/screen.js +0 -114
  42. package/dist/session.d.ts +0 -84
  43. package/dist/session.js +0 -219
  44. package/dist/style.d.ts +0 -50
  45. package/dist/style.js +0 -72
  46. package/dist/suggest.d.ts +0 -15
  47. package/dist/suggest.js +0 -50
  48. package/dist/task.d.ts +0 -47
  49. package/dist/task.js +0 -213
  50. package/dist/terminal.d.ts +0 -21
  51. package/dist/terminal.js +0 -101
  52. package/dist/test.d.ts +0 -89
  53. package/dist/test.js +0 -140
  54. package/dist/tree.d.ts +0 -58
  55. package/dist/tree.js +0 -97
package/dist/resolve.js DELETED
@@ -1,294 +0,0 @@
1
- /**
2
- * Turns what the command line gave into the values a handler reads: each flag and argument
3
- * converted, checked by its schema, asked for when missing on a terminal, or defaulted. Every
4
- * value typed wrong is reported in one usage error before any question is asked.
5
- *
6
- * @author [Sergio Xalambrí](https://sergiodxa.com)
7
- * @copyright Sergio Xalambrí 2026
8
- */
9
- import { failure, isFailure, success } from "@sdxc/result";
10
- import { isGroup } from "./command.js";
11
- import { CancelledError, UsageError } from "./errors.js";
12
- import { validate } from "./schema.js";
13
- import { closest } from "./suggest.js";
14
- /** A value that failed, as one line of the usage error. */
15
- class Issues {
16
- lines = [];
17
- add(label, messages) {
18
- for (let message of messages)
19
- this.lines.push(`${label}: ${message}`);
20
- }
21
- }
22
- /**
23
- * The issue for a word a group's first argument rejects: the word was tried as a member's name
24
- * first, so it reads as a mistyped command, with the closest member suggested.
25
- */
26
- function unknownMember(entry, word) {
27
- let suggestion = closest(word, entry.children.keys());
28
- let hint = suggestion === undefined ? "" : `; did you mean "${suggestion}"?`;
29
- return `Unknown command "${word}" for ${entry.title}${hint}`;
30
- }
31
- /** Text read as a number, or `undefined` when it is not one. */
32
- function toNumber(text) {
33
- if (text.trim() === "")
34
- return undefined;
35
- let value = Number(text);
36
- return Number.isNaN(value) ? undefined : value;
37
- }
38
- /**
39
- * Converts and checks each item of one input: numbers read from text for a number flag, then
40
- * the schema. Answers the outputs, or the messages of every item that failed.
41
- */
42
- async function checkItems(items, kind, schema) {
43
- let outputs = [];
44
- let messages = [];
45
- for (let item of items) {
46
- let value = item;
47
- if (kind === "number" && typeof item === "string") {
48
- let number = toNumber(item);
49
- if (number === undefined) {
50
- messages.push(`expects a number, got ${JSON.stringify(item)}`);
51
- continue;
52
- }
53
- value = number;
54
- }
55
- let checked = await validate(schema, value);
56
- if (isFailure(checked))
57
- messages.push(...checked.error.messages);
58
- else
59
- outputs.push(checked.data);
60
- }
61
- if (messages.length > 0) {
62
- return failure(Object.assign(new Error(messages.join("; ")), { messages }));
63
- }
64
- return success(outputs);
65
- }
66
- /** Splits a comma list, dropping blanks. */
67
- function splitList(text) {
68
- return text
69
- .split(",")
70
- .map((part) => part.trim())
71
- .filter((part) => part !== "");
72
- }
73
- /** An answer as items: a list as it is, text split when the flag is a comma list. */
74
- function answerItems(answer, list) {
75
- if (Array.isArray(answer))
76
- return answer;
77
- if (list && typeof answer === "string")
78
- return splitList(answer);
79
- return [answer];
80
- }
81
- /**
82
- * Resolves `parsed`'s command into the values its handler reads. The parser's own issues lead
83
- * the usage error, followed by every value that failed its conversion or schema.
84
- *
85
- * @returns The inputs, a usage failure listing every problem, a cancelled failure, or the
86
- * failure of a scripted answer that was missing or rejected
87
- */
88
- export async function resolveInputs(parsed, session) {
89
- let entry = parsed.entry;
90
- let inputs = { arguments: {}, flags: {} };
91
- let issues = new Issues();
92
- issues.lines.push(...parsed.issues);
93
- let missing = [];
94
- let positionals = [...parsed.positionals];
95
- for (let { key, spec } of entry.arguments) {
96
- let label = `<${spec.valueName ?? key}>`;
97
- let given = spec.variadic ? positionals.splice(0) : positionals.splice(0, 1);
98
- let check = async (answer) => {
99
- let items = answerItems(answer, false);
100
- if (spec.variadic && items.length < spec.min) {
101
- return failure(new Error(`needs at least ${spec.min} value${spec.min === 1 ? "" : "s"}`));
102
- }
103
- if (spec.variadic && items.length > spec.max) {
104
- return failure(new Error(`takes at most ${spec.max} value${spec.max === 1 ? "" : "s"}`));
105
- }
106
- let checked = await checkItems(items, "string", spec.schema);
107
- if (isFailure(checked))
108
- return checked;
109
- return success(spec.variadic ? checked.data : checked.data[0]);
110
- };
111
- if (given.length === 0) {
112
- let fallback = spec.hasDefault
113
- ? { value: spec.default }
114
- : spec.optional
115
- ? { value: undefined }
116
- : spec.variadic && spec.min === 0
117
- ? { value: [] }
118
- : undefined;
119
- missing.push({
120
- label,
121
- names: [key],
122
- spec,
123
- assign: (value) => {
124
- inputs.arguments[key] = value;
125
- },
126
- check,
127
- fallback,
128
- });
129
- continue;
130
- }
131
- let checked = await check(spec.variadic ? given : given[0]);
132
- if (isFailure(checked) && isGroup(entry.node) && key === entry.arguments[0]?.key) {
133
- issues.lines.push(unknownMember(entry, given[0]));
134
- }
135
- else if (isFailure(checked))
136
- issues.add(label, [checked.error.message]);
137
- else
138
- inputs.arguments[key] = checked.data;
139
- }
140
- for (let extra of positionals)
141
- issues.lines.push(`Unexpected argument ${JSON.stringify(extra)}`);
142
- for (let { key, spec } of entry.flags) {
143
- let label = `--${spec.name}`;
144
- let occurrences = parsed.occurrences.get(key) ?? [];
145
- let many = spec.multiple || spec.list;
146
- let check = async (answer) => {
147
- if (spec.kind === "boolean")
148
- return success(answer === true);
149
- if (spec.optionalValue && answer === true)
150
- return success(true);
151
- let checked = await checkItems(answerItems(answer, spec.list), spec.kind, spec.schema);
152
- if (isFailure(checked))
153
- return checked;
154
- return success(many ? checked.data : checked.data[0]);
155
- };
156
- if (occurrences.length === 0) {
157
- let fallback = spec.hasDefault
158
- ? { value: spec.default }
159
- : spec.kind === "boolean"
160
- ? { value: false }
161
- : spec.required
162
- ? undefined
163
- : { value: many ? [] : undefined };
164
- missing.push({
165
- label,
166
- names: [key, spec.name],
167
- spec,
168
- assign: (value) => {
169
- inputs.flags[key] = value;
170
- },
171
- check,
172
- fallback,
173
- });
174
- continue;
175
- }
176
- if (spec.kind === "boolean") {
177
- let plain = occurrences.find((occurrence) => !occurrence.negated);
178
- let negated = occurrences.find((occurrence) => occurrence.negated);
179
- if (plain !== undefined && negated !== undefined) {
180
- issues.lines.push(`${plain.spelled} and ${negated.spelled} cannot be passed together`);
181
- continue;
182
- }
183
- inputs.flags[key] = !occurrences.at(-1).negated;
184
- continue;
185
- }
186
- let values = [];
187
- let bare = false;
188
- let broken = false;
189
- for (let occurrence of occurrences) {
190
- if (occurrence.value === true) {
191
- bare = true;
192
- continue;
193
- }
194
- if (!spec.list) {
195
- values.push(occurrence);
196
- continue;
197
- }
198
- let parts = splitList(occurrence.value);
199
- if (parts.length === 0) {
200
- issues.lines.push(`${occurrence.spelled} needs a value`);
201
- broken = true;
202
- }
203
- for (let part of parts)
204
- values.push({ ...occurrence, value: part });
205
- }
206
- if (broken)
207
- continue;
208
- if (bare) {
209
- inputs.flags[key] = true;
210
- continue;
211
- }
212
- if (!many)
213
- values = values.slice(-1);
214
- let outputs = [];
215
- for (let value of values) {
216
- let checked = await checkItems([value.value], spec.kind, spec.schema);
217
- if (isFailure(checked))
218
- issues.add(value.spelled, checked.error.messages);
219
- else
220
- outputs.push(checked.data[0]);
221
- }
222
- if (outputs.length === values.length)
223
- inputs.flags[key] = many ? outputs : outputs[0];
224
- }
225
- if (issues.lines.length > 0)
226
- return failure(new UsageError(issues.lines.join("\n")));
227
- for (let input of missing) {
228
- let declared = input.spec.prompt;
229
- let asks = declared !== undefined &&
230
- session.interactive &&
231
- (!input.spec.hasDefault ||
232
- input.spec.default === undefined ||
233
- declared.options.ask === "always");
234
- if (!asks || declared === undefined) {
235
- if (input.fallback !== undefined)
236
- input.assign(input.fallback.value);
237
- else if (declared !== undefined) {
238
- issues.lines.push(`${input.label} is required when stdin is not a terminal`);
239
- }
240
- else if (input.label.startsWith("<"))
241
- issues.lines.push(`Missing argument ${input.label}`);
242
- else
243
- issues.lines.push(`${input.label} is required`);
244
- continue;
245
- }
246
- if (issues.lines.length > 0)
247
- continue;
248
- let answered = await session.ask({
249
- kind: declared.kind,
250
- options: declared.options,
251
- names: input.names,
252
- label: input.label,
253
- initial: input.spec.hasDefault ? input.spec.default : undefined,
254
- check: input.check,
255
- });
256
- if (isFailure(answered))
257
- return answered;
258
- input.assign(answered.data);
259
- }
260
- if (issues.lines.length > 0)
261
- return failure(new UsageError(issues.lines.join("\n")));
262
- return success(inputs);
263
- }
264
- /** The `ctx.prompt` of one run: asks on a terminal or from a script, else answers the default. */
265
- export function createPrompter(session) {
266
- /** Asks one handler-called prompt. */
267
- let ask = async (kind, options) => {
268
- if (!session.interactive)
269
- return success(options.default);
270
- if (session.signal.aborted)
271
- return failure(new CancelledError());
272
- let request = {
273
- kind,
274
- options,
275
- names: options.name === undefined ? [] : [options.name],
276
- label: options.name ?? JSON.stringify(options.message),
277
- initial: "initial" in options ? options.initial : options.default,
278
- async check(answer) {
279
- let checked = await validate(options.schema, answer);
280
- return isFailure(checked) ? failure(new Error(checked.error.message)) : success(answer);
281
- },
282
- };
283
- return (await session.ask(request));
284
- };
285
- return {
286
- text: (options) => ask("text", options),
287
- password: (options) => ask("password", options),
288
- number: (options) => ask("number", options),
289
- confirm: (options) => ask("confirm", options),
290
- select: (options) => ask("select", options),
291
- multiselect: (options) => ask("multiselect", options),
292
- search: ((options) => ask("search", options)),
293
- };
294
- }
package/dist/schema.d.ts DELETED
@@ -1,27 +0,0 @@
1
- /**
2
- * Runs a Standard Schema over one command-line value, synchronous or asynchronous alike, and
3
- * answers its output or the issue messages, so every argument, flag and prompt answer is checked
4
- * by the schema it was declared with.
5
- *
6
- * @author [Sergio Xalambrí](https://sergiodxa.com)
7
- * @copyright Sergio Xalambrí 2026
8
- */
9
- import type { Result } from "@sdxc/result";
10
- import type { StandardSchemaV1 } from "@standard-schema/spec";
11
- /** A value's issues, each as the message the user reads after the input's name. */
12
- export declare class SchemaIssues extends Error {
13
- name: string;
14
- /** One message per issue, in the order the schema reported them. */
15
- messages: readonly string[];
16
- /** @param messages - The schema's issue messages */
17
- constructor(messages: readonly string[]);
18
- }
19
- /**
20
- * `value` checked by `schema`, or its issues. A missing schema accepts the value unchanged.
21
- *
22
- * @param schema - Any Standard Schema
23
- * @param value - What the command line, a prompt or a default supplied
24
- */
25
- export declare function validate(schema: StandardSchemaV1 | undefined, value: unknown): Promise<Result<unknown, SchemaIssues>>;
26
- /** The output type of a Standard Schema. */
27
- export type SchemaOutput<Schema> = Schema extends StandardSchemaV1<infer _Input, infer Output> ? Output : never;
package/dist/schema.js DELETED
@@ -1,34 +0,0 @@
1
- /**
2
- * Runs a Standard Schema over one command-line value, synchronous or asynchronous alike, and
3
- * answers its output or the issue messages, so every argument, flag and prompt answer is checked
4
- * by the schema it was declared with.
5
- *
6
- * @author [Sergio Xalambrí](https://sergiodxa.com)
7
- * @copyright Sergio Xalambrí 2026
8
- */
9
- import { failure, success } from "@sdxc/result";
10
- /** A value's issues, each as the message the user reads after the input's name. */
11
- export class SchemaIssues extends Error {
12
- name = "SchemaIssues";
13
- /** One message per issue, in the order the schema reported them. */
14
- messages;
15
- /** @param messages - The schema's issue messages */
16
- constructor(messages) {
17
- super(messages.join("; "));
18
- this.messages = messages;
19
- }
20
- }
21
- /**
22
- * `value` checked by `schema`, or its issues. A missing schema accepts the value unchanged.
23
- *
24
- * @param schema - Any Standard Schema
25
- * @param value - What the command line, a prompt or a default supplied
26
- */
27
- export async function validate(schema, value) {
28
- if (schema === undefined)
29
- return success(value);
30
- let outcome = await schema["~standard"].validate(value);
31
- if (outcome.issues === undefined)
32
- return success(outcome.value);
33
- return failure(new SchemaIssues(outcome.issues.map((issue) => issue.message)));
34
- }
package/dist/screen.d.ts DELETED
@@ -1,42 +0,0 @@
1
- /**
2
- * The one owner of the terminal during a run: a live region at the bottom of stderr that tasks
3
- * and prompts redraw in place, with every other write going above it. A write clears the region,
4
- * writes, and redraws it, so command output and spinner frames never interleave.
5
- *
6
- * @author [Sergio Xalambrí](https://sergiodxa.com)
7
- * @copyright Sergio Xalambrí 2026
8
- */
9
- /** A writable stream a CLI prints to; `process.stdout` and `process.stderr` are ones. */
10
- export interface Output {
11
- write(text: string): unknown;
12
- isTTY?: boolean;
13
- /** The terminal's width in columns. */
14
- columns?: number;
15
- }
16
- /** The live region on stderr and every write that goes around it. */
17
- export declare class Screen {
18
- #private;
19
- /** The stream the region is drawn on. */
20
- readonly stderr: Output;
21
- /** @param stderr - The stream the region is drawn on */
22
- constructor(stderr: Output);
23
- /** The terminal's width. */
24
- get columns(): number;
25
- /** Whether a prompt or a child process holds the region. */
26
- get held(): boolean;
27
- /** Sets what the region shows when nobody holds it: the running tasks. */
28
- onRefresh(refresh: () => void): void;
29
- /** Replaces the region with `lines`; an empty list clears it and shows the cursor. */
30
- paint(lines: readonly string[]): void;
31
- /**
32
- * Writes `text` to `target` above the region: the region is cleared first and redrawn
33
- * after, when `target` shares the terminal with it.
34
- */
35
- write(target: Output, text: string): void;
36
- /** Takes the region for a prompt or a child process, clearing what the tasks drew. */
37
- hold(): void;
38
- /** Gives the region back, and the tasks redraw it. */
39
- release(): void;
40
- /** Clears the region and shows the cursor, as any exit must leave the terminal. */
41
- restore(): void;
42
- }
package/dist/screen.js DELETED
@@ -1,114 +0,0 @@
1
- /**
2
- * The one owner of the terminal during a run: a live region at the bottom of stderr that tasks
3
- * and prompts redraw in place, with every other write going above it. A write clears the region,
4
- * writes, and redraws it, so command output and spinner frames never interleave.
5
- *
6
- * @author [Sergio Xalambrí](https://sergiodxa.com)
7
- * @copyright Sergio Xalambrí 2026
8
- */
9
- import { visibleWidth } from "./style.js";
10
- /** Hides the cursor while the region is drawn. */
11
- const HIDE_CURSOR = "\u001B[?25l";
12
- /** Shows it again. */
13
- const SHOW_CURSOR = "\u001B[?25h";
14
- /** Erases from the cursor to the end of the screen. */
15
- const ERASE_DOWN = "\u001B[J";
16
- /** The width assumed for a stream that does not report one. */
17
- const DEFAULT_COLUMNS = 80;
18
- /** The live region on stderr and every write that goes around it. */
19
- export class Screen {
20
- /** The stream the region is drawn on. */
21
- stderr;
22
- /** The lines the region shows now. */
23
- #lines = [];
24
- /** How many terminal rows those lines take, wrapping included. */
25
- #rows = 0;
26
- #cursorHidden = false;
27
- /** How many callers hold the region for themselves (a prompt, a child process). */
28
- #holds = 0;
29
- /** Redraws the region's usual content when nobody holds it. */
30
- #refresh = () => undefined;
31
- /** @param stderr - The stream the region is drawn on */
32
- constructor(stderr) {
33
- this.stderr = stderr;
34
- }
35
- /** The terminal's width. */
36
- get columns() {
37
- let columns = this.stderr.columns ?? 0;
38
- return columns > 0 ? columns : DEFAULT_COLUMNS;
39
- }
40
- /** Whether a prompt or a child process holds the region. */
41
- get held() {
42
- return this.#holds > 0;
43
- }
44
- /** Sets what the region shows when nobody holds it: the running tasks. */
45
- onRefresh(refresh) {
46
- this.#refresh = refresh;
47
- }
48
- /** Replaces the region with `lines`; an empty list clears it and shows the cursor. */
49
- paint(lines) {
50
- let text = this.#erase();
51
- if (lines.length === 0) {
52
- if (this.#cursorHidden)
53
- text += SHOW_CURSOR;
54
- this.#cursorHidden = false;
55
- this.#lines = [];
56
- if (text !== "")
57
- this.stderr.write(text);
58
- return;
59
- }
60
- if (!this.#cursorHidden)
61
- text += HIDE_CURSOR;
62
- this.#cursorHidden = true;
63
- text += lines.join("\n");
64
- this.#lines = lines;
65
- this.#rows = lines.reduce((rows, line) => rows + this.#rowsOf(line), 0);
66
- this.stderr.write(text);
67
- }
68
- /**
69
- * Writes `text` to `target` above the region: the region is cleared first and redrawn
70
- * after, when `target` shares the terminal with it.
71
- */
72
- write(target, text) {
73
- let shared = target === this.stderr || target.isTTY === true;
74
- if (this.#rows === 0 || !shared) {
75
- target.write(text);
76
- return;
77
- }
78
- let lines = this.#lines;
79
- this.paint([]);
80
- target.write(text);
81
- this.paint(lines);
82
- }
83
- /** Takes the region for a prompt or a child process, clearing what the tasks drew. */
84
- hold() {
85
- this.#holds += 1;
86
- if (this.#holds === 1)
87
- this.paint([]);
88
- }
89
- /** Gives the region back, and the tasks redraw it. */
90
- release() {
91
- this.#holds = Math.max(0, this.#holds - 1);
92
- if (this.#holds === 0)
93
- this.#refresh();
94
- }
95
- /** Clears the region and shows the cursor, as any exit must leave the terminal. */
96
- restore() {
97
- this.paint([]);
98
- if (this.#cursorHidden)
99
- this.stderr.write(SHOW_CURSOR);
100
- this.#cursorHidden = false;
101
- }
102
- /** The sequence that erases the region, leaving the cursor where it began. */
103
- #erase() {
104
- if (this.#rows === 0)
105
- return "";
106
- let up = this.#rows > 1 ? `\u001B[${this.#rows - 1}A` : "";
107
- this.#rows = 0;
108
- return `\r${up}${ERASE_DOWN}`;
109
- }
110
- /** How many rows `line` takes once the terminal wraps it. */
111
- #rowsOf(line) {
112
- return Math.max(1, Math.ceil(visibleWidth(line) / this.columns));
113
- }
114
- }
package/dist/session.d.ts DELETED
@@ -1,84 +0,0 @@
1
- /**
2
- * One run's process context: its working directory, environment and streams, whether it may
3
- * ask questions, the terminal owner tasks and prompts draw through, and the signal Ctrl+C
4
- * aborts. Built from `cli.run`'s options, each defaulting to the process's own.
5
- *
6
- * @author [Sergio Xalambrí](https://sergiodxa.com)
7
- * @copyright Sergio Xalambrí 2026
8
- */
9
- import type { Result } from "@sdxc/result";
10
- import type { Exec, ExecOptions, ExecOutput, ExecError } from "./exec.js";
11
- import type { Input, Keyboard } from "./keys.js";
12
- import type { PromptKind, PromptKinds } from "./prompt.js";
13
- import type { Output } from "./screen.js";
14
- import type { Env, Style } from "./style.js";
15
- import { CancelledError } from "./errors.js";
16
- import { Screen } from "./screen.js";
17
- import { Tasks } from "./task.js";
18
- /** What `cli.run` replaces of the process: any option left out is the process's own. */
19
- export interface RunIO {
20
- cwd?: string;
21
- env?: Env;
22
- stdin?: Input;
23
- stdout?: Output;
24
- stderr?: Output;
25
- /** Runs `ctx.exec`'s commands. */
26
- exec?: Exec;
27
- /**
28
- * Aborting it stops the run the way Ctrl+C does. Without one, the run listens for SIGINT and
29
- * SIGTERM itself while it lasts.
30
- */
31
- signal?: AbortSignal;
32
- }
33
- /** How a test harness answers prompts in place of a person. */
34
- export interface Script {
35
- /** By the name a prompt answers to, or in the order prompts are asked. */
36
- answers: Readonly<Record<string, unknown>> | readonly unknown[] | undefined;
37
- /** Reads keys from a virtual terminal; without one, prompts take scripted answers. */
38
- keyboard: (() => Keyboard) | undefined;
39
- /** Whether stdin counts as a terminal, which decides whether prompts are asked at all. */
40
- interactive: boolean;
41
- }
42
- /** One question to ask, in the shape both bound and handler-called prompts reduce to. */
43
- export interface PromptRequest {
44
- kind: PromptKind;
45
- options: PromptKinds[PromptKind];
46
- /** Names a scripted `answers` object may answer it by. */
47
- names: readonly string[];
48
- /** How errors about it name it: `--template`, `<directory>`, or its message. */
49
- label: string;
50
- /** The default, shown dimmed or preselected. */
51
- initial: unknown;
52
- /** Converts and checks an answer; the issue keeps the prompt open. */
53
- check(answer: unknown): Promise<Result<unknown, Error>>;
54
- }
55
- /** The process context of one run. */
56
- export interface Session {
57
- cwd: string;
58
- env: Env;
59
- stdin: Input;
60
- stdout: Output;
61
- stderr: Output;
62
- /** Styling for stdout, with stderr's under `stderr`. */
63
- style: Style & {
64
- readonly stderr: Style;
65
- };
66
- screen: Screen;
67
- tasks: Tasks;
68
- signal: AbortSignal;
69
- /** Whether prompts are asked; otherwise defaults apply. */
70
- interactive: boolean;
71
- /** Whether tasks animate, false once `--no-progress` is passed. */
72
- animate: boolean;
73
- ask(request: PromptRequest): Promise<Result<unknown, Error>>;
74
- exec(command: readonly string[], options?: ExecOptions): Promise<Result<ExecOutput, ExecError | CancelledError>>;
75
- /** Stops tasks, clears the frame, shows the cursor and stops listening for signals. */
76
- close(): void;
77
- }
78
- /**
79
- * Opens the session for one run.
80
- *
81
- * @param noProgress - Whether `--no-progress` was passed
82
- * @param script - How a test answers prompts; `undefined` for a person at a terminal
83
- */
84
- export declare function openSession(io: RunIO, noProgress: boolean, script: Script | undefined): Session;