toolcraft-openapi 0.0.39 → 0.0.41

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 (62) hide show
  1. package/README.md +67 -0
  2. package/dist/bin/generate.d.ts +9 -0
  3. package/dist/bin/generate.js +122 -6
  4. package/dist/config.d.ts +53 -0
  5. package/dist/config.js +266 -0
  6. package/dist/define-client.js +4 -0
  7. package/dist/diagnose.d.ts +4 -0
  8. package/dist/diagnose.js +93 -0
  9. package/dist/diagnostics.d.ts +19 -0
  10. package/dist/diagnostics.js +19 -0
  11. package/dist/generate.d.ts +13 -1
  12. package/dist/generate.js +107 -4
  13. package/dist/http.d.ts +17 -26
  14. package/dist/http.js +99 -41
  15. package/dist/index.d.ts +6 -1
  16. package/dist/index.js +4 -1
  17. package/dist/runtime.d.ts +7 -0
  18. package/dist/runtime.js +19 -1
  19. package/node_modules/@poe-code/frontmatter/README.md +35 -0
  20. package/node_modules/@poe-code/frontmatter/dist/fences.d.ts +8 -0
  21. package/node_modules/@poe-code/frontmatter/dist/fences.js +72 -0
  22. package/node_modules/@poe-code/frontmatter/dist/index.d.ts +3 -0
  23. package/node_modules/@poe-code/frontmatter/dist/index.js +3 -0
  24. package/node_modules/@poe-code/frontmatter/dist/parse.d.ts +20 -0
  25. package/node_modules/@poe-code/frontmatter/dist/parse.js +137 -0
  26. package/node_modules/@poe-code/frontmatter/dist/stringify.d.ts +1 -0
  27. package/node_modules/@poe-code/frontmatter/dist/stringify.js +35 -0
  28. package/node_modules/@poe-code/frontmatter/package.json +25 -0
  29. package/node_modules/toolcraft-design/README.md +12 -0
  30. package/node_modules/toolcraft-design/dist/prompts/index.d.ts +39 -14
  31. package/node_modules/toolcraft-design/dist/prompts/index.js +10 -6
  32. package/node_modules/toolcraft-design/dist/prompts/interactive/cancel-symbol.d.ts +2 -0
  33. package/node_modules/toolcraft-design/dist/prompts/interactive/cancel-symbol.js +4 -0
  34. package/node_modules/toolcraft-design/dist/prompts/interactive/confirm.d.ts +9 -0
  35. package/node_modules/toolcraft-design/dist/prompts/interactive/confirm.js +47 -0
  36. package/node_modules/toolcraft-design/dist/prompts/interactive/core.d.ts +55 -0
  37. package/node_modules/toolcraft-design/dist/prompts/interactive/core.js +274 -0
  38. package/node_modules/toolcraft-design/dist/prompts/interactive/glyphs.d.ts +20 -0
  39. package/node_modules/toolcraft-design/dist/prompts/interactive/glyphs.js +53 -0
  40. package/node_modules/toolcraft-design/dist/prompts/interactive/index.d.ts +6 -0
  41. package/node_modules/toolcraft-design/dist/prompts/interactive/index.js +6 -0
  42. package/node_modules/toolcraft-design/dist/prompts/interactive/keys.d.ts +2 -0
  43. package/node_modules/toolcraft-design/dist/prompts/interactive/keys.js +28 -0
  44. package/node_modules/toolcraft-design/dist/prompts/interactive/multiselect.d.ts +13 -0
  45. package/node_modules/toolcraft-design/dist/prompts/interactive/multiselect.js +131 -0
  46. package/node_modules/toolcraft-design/dist/prompts/interactive/pagination.d.ts +10 -0
  47. package/node_modules/toolcraft-design/dist/prompts/interactive/pagination.js +52 -0
  48. package/node_modules/toolcraft-design/dist/prompts/interactive/password.d.ts +10 -0
  49. package/node_modules/toolcraft-design/dist/prompts/interactive/password.js +55 -0
  50. package/node_modules/toolcraft-design/dist/prompts/interactive/select.d.ts +18 -0
  51. package/node_modules/toolcraft-design/dist/prompts/interactive/select.js +89 -0
  52. package/node_modules/toolcraft-design/dist/prompts/interactive/test-helpers.d.ts +21 -0
  53. package/node_modules/toolcraft-design/dist/prompts/interactive/test-helpers.js +32 -0
  54. package/node_modules/toolcraft-design/dist/prompts/interactive/text.d.ts +12 -0
  55. package/node_modules/toolcraft-design/dist/prompts/interactive/text.js +60 -0
  56. package/node_modules/toolcraft-design/dist/prompts/interactive/wrap.d.ts +4 -0
  57. package/node_modules/toolcraft-design/dist/prompts/interactive/wrap.js +18 -0
  58. package/node_modules/toolcraft-design/dist/prompts/primitives/cancel.d.ts +1 -1
  59. package/node_modules/toolcraft-design/dist/prompts/primitives/cancel.js +1 -1
  60. package/node_modules/toolcraft-design/dist/terminal-markdown/parser/frontmatter.js +20 -453
  61. package/node_modules/toolcraft-design/package.json +6 -3
  62. package/package.json +7 -7
@@ -0,0 +1,55 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { CANCEL } from "./cancel-symbol.js";
3
+ export type PromptStateName = "initial" | "active" | "submit" | "cancel" | "error";
4
+ export interface PromptState<Value> {
5
+ state: PromptStateName;
6
+ value: Value | undefined;
7
+ error: string;
8
+ cursor: number;
9
+ userInput: string;
10
+ }
11
+ export interface PromptOptions<Value> {
12
+ render: (state: Prompt<Value>) => string;
13
+ initialValue?: Value;
14
+ initialUserInput?: string;
15
+ validate?: (value: Value | undefined) => string | Error | undefined;
16
+ signal?: AbortSignal;
17
+ input?: NodeJS.ReadableStream;
18
+ output?: NodeJS.WritableStream;
19
+ }
20
+ type InputStream = NodeJS.ReadableStream & {
21
+ isTTY?: boolean;
22
+ setRawMode?: (enabled: boolean) => void;
23
+ unpipe?: () => void;
24
+ };
25
+ export declare class Prompt<Value> extends EventEmitter {
26
+ state: PromptStateName;
27
+ value: Value | undefined;
28
+ error: string;
29
+ userInput: string;
30
+ protected _cursor: number;
31
+ protected input: InputStream;
32
+ protected output: NodeJS.WritableStream;
33
+ private readonly renderFrame;
34
+ private readonly validate?;
35
+ private readonly signal?;
36
+ private readonly trackValue;
37
+ private previousFrame;
38
+ private readlineInterface?;
39
+ private abortListener?;
40
+ private closed;
41
+ constructor(opts: PromptOptions<Value>, trackValue?: boolean);
42
+ get cursor(): number;
43
+ prompt(): Promise<Value | typeof CANCEL>;
44
+ protected promptNonTty(): Promise<Value | typeof CANCEL>;
45
+ protected readNonTtyLine(): Promise<string>;
46
+ protected setValue(value: Value | undefined): void;
47
+ protected setError(message: string): void;
48
+ protected setUserInput(value: string): void;
49
+ protected clearUserInput(): void;
50
+ private readonly onKeypress;
51
+ private updateTrackedInput;
52
+ protected readonly render: () => void;
53
+ protected close(): void;
54
+ }
55
+ export {};
@@ -0,0 +1,274 @@
1
+ import { EventEmitter } from "node:events";
2
+ import * as readline from "node:readline";
3
+ import { CANCEL } from "./cancel-symbol.js";
4
+ import { mapKey } from "./keys.js";
5
+ import { wrapFrame } from "./wrap.js";
6
+ const cursor = {
7
+ hide: "\x1b[?25l",
8
+ show: "\x1b[?25h",
9
+ move: (x, y) => {
10
+ let output = "";
11
+ if (x < 0)
12
+ output += `\x1b[${-x}D`;
13
+ if (x > 0)
14
+ output += `\x1b[${x}C`;
15
+ if (y < 0)
16
+ output += `\x1b[${-y}A`;
17
+ if (y > 0)
18
+ output += `\x1b[${y}B`;
19
+ return output;
20
+ }
21
+ };
22
+ const erase = {
23
+ down: "\x1b[J"
24
+ };
25
+ export class Prompt extends EventEmitter {
26
+ state = "initial";
27
+ value;
28
+ error = "";
29
+ userInput = "";
30
+ _cursor = 0;
31
+ input;
32
+ output;
33
+ renderFrame;
34
+ validate;
35
+ signal;
36
+ trackValue;
37
+ previousFrame = "";
38
+ readlineInterface;
39
+ abortListener;
40
+ closed = false;
41
+ constructor(opts, trackValue = true) {
42
+ super();
43
+ this.input = (opts.input ?? process.stdin);
44
+ this.output = opts.output ?? process.stdout;
45
+ this.renderFrame = opts.render;
46
+ this.validate = opts.validate;
47
+ this.signal = opts.signal;
48
+ this.value = opts.initialValue;
49
+ this.trackValue = trackValue;
50
+ this.userInput = opts.initialUserInput ?? "";
51
+ this._cursor = this.userInput.length;
52
+ }
53
+ get cursor() {
54
+ return this._cursor;
55
+ }
56
+ prompt() {
57
+ if (this.signal?.aborted) {
58
+ this.state = "cancel";
59
+ return Promise.resolve(CANCEL);
60
+ }
61
+ if (this.input.isTTY !== true) {
62
+ return this.promptNonTty();
63
+ }
64
+ return new Promise((resolve) => {
65
+ const onSubmit = (value) => resolve(value);
66
+ const onCancel = () => resolve(CANCEL);
67
+ this.once("submit", onSubmit);
68
+ this.once("cancel", onCancel);
69
+ this.abortListener = () => {
70
+ this.state = "cancel";
71
+ this.emit("finalize");
72
+ this.render();
73
+ this.close();
74
+ };
75
+ this.signal?.addEventListener("abort", this.abortListener, { once: true });
76
+ this.readlineInterface = readline.createInterface({
77
+ input: this.input,
78
+ output: undefined,
79
+ tabSize: 2,
80
+ prompt: "",
81
+ escapeCodeTimeout: 50,
82
+ terminal: true
83
+ });
84
+ readline.emitKeypressEvents(this.input, this.readlineInterface);
85
+ this.readlineInterface.prompt();
86
+ this.input.on("keypress", this.onKeypress);
87
+ if (this.input.setRawMode) {
88
+ this.input.setRawMode(true);
89
+ }
90
+ this.output.on("resize", this.render);
91
+ this.render();
92
+ });
93
+ }
94
+ promptNonTty() {
95
+ return Promise.reject(new Error("Interactive prompt requires a TTY. Set POE_NO_PROMPT=1 to accept defaults non-interactively."));
96
+ }
97
+ readNonTtyLine() {
98
+ return new Promise((resolve) => {
99
+ const rl = readline.createInterface({ input: this.input, terminal: false });
100
+ let settled = false;
101
+ const settle = (value) => {
102
+ if (settled) {
103
+ return;
104
+ }
105
+ settled = true;
106
+ rl.close();
107
+ resolve(value);
108
+ };
109
+ rl.once("line", settle);
110
+ rl.once("close", () => settle(rl.line));
111
+ });
112
+ }
113
+ setValue(value) {
114
+ this.value = value;
115
+ this.emit("value", value);
116
+ }
117
+ setError(message) {
118
+ this.error = message;
119
+ }
120
+ setUserInput(value) {
121
+ this.userInput = value;
122
+ this._cursor = Math.min(this._cursor, this.userInput.length);
123
+ this.emit("userInput", this.userInput);
124
+ }
125
+ clearUserInput() {
126
+ this.userInput = "";
127
+ this._cursor = 0;
128
+ this.emit("userInput", this.userInput);
129
+ }
130
+ onKeypress = (char, key = {}) => {
131
+ let action = mapKey(key.name, char);
132
+ if (this.trackValue && char && char >= " " && key.name !== "return" && key.name !== "enter" && key.name !== "escape") {
133
+ action = undefined;
134
+ }
135
+ if (this.trackValue && action !== "enter") {
136
+ this.updateTrackedInput(char, key, action);
137
+ }
138
+ if (this.state === "error") {
139
+ this.state = "active";
140
+ this.error = "";
141
+ }
142
+ if (!this.trackValue && action) {
143
+ this.emit("cursor", action);
144
+ }
145
+ else if (this.trackValue && action && action !== "enter") {
146
+ this.emit("cursor", action);
147
+ }
148
+ if (char && /^[yn]$/i.test(char)) {
149
+ this.emit("confirm", char.toLowerCase() === "y");
150
+ }
151
+ if (char) {
152
+ this.emit("key", char.toLowerCase(), key);
153
+ }
154
+ if (action === "enter") {
155
+ const error = this.validate?.(this.value);
156
+ if (error) {
157
+ this.error = error instanceof Error ? error.message : error;
158
+ this.state = "error";
159
+ }
160
+ else {
161
+ this.state = "submit";
162
+ }
163
+ }
164
+ if (action === "cancel") {
165
+ this.state = "cancel";
166
+ }
167
+ if (this.state === "submit" || this.state === "cancel") {
168
+ this.emit("finalize");
169
+ }
170
+ this.render();
171
+ if (this.state === "submit" || this.state === "cancel") {
172
+ this.close();
173
+ }
174
+ };
175
+ updateTrackedInput(char, key, action) {
176
+ if (key.ctrl) {
177
+ if (key.name === "a") {
178
+ this._cursor = 0;
179
+ return;
180
+ }
181
+ if (key.name === "e") {
182
+ this._cursor = this.userInput.length;
183
+ return;
184
+ }
185
+ if (key.name === "u") {
186
+ this.userInput = this.userInput.slice(this._cursor);
187
+ this._cursor = 0;
188
+ this.emit("userInput", this.userInput);
189
+ return;
190
+ }
191
+ if (key.name === "k") {
192
+ this.userInput = this.userInput.slice(0, this._cursor);
193
+ this.emit("userInput", this.userInput);
194
+ return;
195
+ }
196
+ }
197
+ if (action === "left") {
198
+ this._cursor = Math.max(0, this._cursor - 1);
199
+ return;
200
+ }
201
+ if (action === "right") {
202
+ this._cursor = Math.min(this.userInput.length, this._cursor + 1);
203
+ return;
204
+ }
205
+ if (action === "cancel" || action === "up" || action === "down" || action === "space") {
206
+ return;
207
+ }
208
+ if (key.name === "backspace" || char === "\b" || char === "\x7f") {
209
+ if (this._cursor > 0) {
210
+ this.userInput = `${this.userInput.slice(0, this._cursor - 1)}${this.userInput.slice(this._cursor)}`;
211
+ this._cursor -= 1;
212
+ this.emit("userInput", this.userInput);
213
+ }
214
+ return;
215
+ }
216
+ if (key.name === "delete") {
217
+ if (this._cursor < this.userInput.length) {
218
+ this.userInput = `${this.userInput.slice(0, this._cursor)}${this.userInput.slice(this._cursor + 1)}`;
219
+ this.emit("userInput", this.userInput);
220
+ }
221
+ return;
222
+ }
223
+ if (!char || char < " " || key.ctrl) {
224
+ return;
225
+ }
226
+ this.userInput = `${this.userInput.slice(0, this._cursor)}${char}${this.userInput.slice(this._cursor)}`;
227
+ this._cursor += char.length;
228
+ this.emit("userInput", this.userInput);
229
+ }
230
+ render = () => {
231
+ if (this.closed) {
232
+ return;
233
+ }
234
+ const frame = wrapFrame(this.output, this.renderFrame(this) ?? "");
235
+ if (frame === this.previousFrame) {
236
+ return;
237
+ }
238
+ if (!this.previousFrame) {
239
+ this.output.write(`${cursor.hide}${frame}`);
240
+ this.previousFrame = frame;
241
+ if (this.state === "initial") {
242
+ this.state = "active";
243
+ }
244
+ return;
245
+ }
246
+ const previousLineCount = this.previousFrame.split("\n").length - 1;
247
+ this.output.write(`${cursor.move(-999, -previousLineCount)}${erase.down}${frame}`);
248
+ this.previousFrame = frame;
249
+ };
250
+ close() {
251
+ if (this.closed) {
252
+ return;
253
+ }
254
+ this.closed = true;
255
+ this.input.removeListener("keypress", this.onKeypress);
256
+ this.output.removeListener("resize", this.render);
257
+ if (this.abortListener) {
258
+ this.signal?.removeEventListener("abort", this.abortListener);
259
+ }
260
+ this.output.write(`${cursor.show}\n`);
261
+ if (!process.platform.startsWith("win") && this.input.setRawMode) {
262
+ this.input.setRawMode(false);
263
+ }
264
+ this.readlineInterface?.close();
265
+ this.input.unpipe?.();
266
+ if (this.state === "cancel") {
267
+ this.emit("cancel");
268
+ }
269
+ else {
270
+ this.emit("submit", this.value);
271
+ }
272
+ this.removeAllListeners();
273
+ }
274
+ }
@@ -0,0 +1,20 @@
1
+ import type { PromptStateName } from "./core.js";
2
+ export declare const UNICODE: boolean;
3
+ export declare const GLYPHS: {
4
+ readonly stepActive: string;
5
+ readonly stepCancel: string;
6
+ readonly stepError: string;
7
+ readonly stepSubmit: string;
8
+ readonly barStart: string;
9
+ readonly bar: string;
10
+ readonly barEnd: string;
11
+ readonly radioActive: string;
12
+ readonly radioInactive: string;
13
+ readonly checkboxActive: string;
14
+ readonly checkboxSelected: string;
15
+ readonly checkboxInactive: string;
16
+ readonly passwordMask: string;
17
+ readonly ellipsis: "...";
18
+ };
19
+ export declare function symbol(state: PromptStateName): string;
20
+ export declare function symbolBar(state: PromptStateName): string;
@@ -0,0 +1,53 @@
1
+ import { color } from "../../components/color.js";
2
+ function supportsUnicode() {
3
+ if (!process.platform.startsWith("win")) {
4
+ return process.env.TERM !== "linux";
5
+ }
6
+ return Boolean(process.env.CI ||
7
+ process.env.WT_SESSION ||
8
+ process.env.TERMINUS_SUBLIME ||
9
+ process.env.ConEmuTask === "{cmd::Cmder}" ||
10
+ process.env.TERM_PROGRAM === "Terminus-Sublime" ||
11
+ process.env.TERM_PROGRAM === "vscode" ||
12
+ process.env.TERM === "xterm-256color" ||
13
+ process.env.TERM === "alacritty" ||
14
+ process.env.TERMINAL_EMULATOR === "JetBrains-JediTerm");
15
+ }
16
+ export const UNICODE = supportsUnicode();
17
+ function glyph(unicode, ascii) {
18
+ return UNICODE ? unicode : ascii;
19
+ }
20
+ export const GLYPHS = {
21
+ stepActive: glyph("◆", "*"),
22
+ stepCancel: glyph("■", "x"),
23
+ stepError: glyph("▲", "x"),
24
+ stepSubmit: glyph("◇", "o"),
25
+ barStart: glyph("┌", "T"),
26
+ bar: glyph("│", "|"),
27
+ barEnd: glyph("└", "-"),
28
+ radioActive: glyph("●", ">"),
29
+ radioInactive: glyph("○", " "),
30
+ checkboxActive: glyph("◻", "[ ]"),
31
+ checkboxSelected: glyph("◼", "[+]"),
32
+ checkboxInactive: glyph("◻", "[ ]"),
33
+ passwordMask: glyph("•", "*"),
34
+ ellipsis: "..."
35
+ };
36
+ export function symbol(state) {
37
+ if (state === "cancel")
38
+ return color.red(GLYPHS.stepCancel);
39
+ if (state === "error")
40
+ return color.yellow(GLYPHS.stepError);
41
+ if (state === "submit")
42
+ return color.green(GLYPHS.stepSubmit);
43
+ return color.cyan(GLYPHS.stepActive);
44
+ }
45
+ export function symbolBar(state) {
46
+ if (state === "cancel")
47
+ return color.red(GLYPHS.bar);
48
+ if (state === "error")
49
+ return color.yellow(GLYPHS.bar);
50
+ if (state === "submit")
51
+ return color.green(GLYPHS.bar);
52
+ return color.cyan(GLYPHS.bar);
53
+ }
@@ -0,0 +1,6 @@
1
+ export { CANCEL, isCancel } from "./cancel-symbol.js";
2
+ export { textPrompt, type TextOptions } from "./text.js";
3
+ export { passwordPrompt, type PasswordOptions } from "./password.js";
4
+ export { confirmPrompt, type ConfirmOptions } from "./confirm.js";
5
+ export { selectPrompt, type SelectOption, type SelectOptions } from "./select.js";
6
+ export { multiselectPrompt, type MultiselectOptions } from "./multiselect.js";
@@ -0,0 +1,6 @@
1
+ export { CANCEL, isCancel } from "./cancel-symbol.js";
2
+ export { textPrompt } from "./text.js";
3
+ export { passwordPrompt } from "./password.js";
4
+ export { confirmPrompt } from "./confirm.js";
5
+ export { selectPrompt } from "./select.js";
6
+ export { multiselectPrompt } from "./multiselect.js";
@@ -0,0 +1,2 @@
1
+ export type Action = "up" | "down" | "left" | "right" | "space" | "enter" | "cancel";
2
+ export declare function mapKey(name: string | undefined, char: string | undefined): Action | undefined;
@@ -0,0 +1,28 @@
1
+ const aliases = {
2
+ k: "up",
3
+ j: "down",
4
+ h: "left",
5
+ l: "right"
6
+ };
7
+ const keyActions = {
8
+ up: "up",
9
+ down: "down",
10
+ left: "left",
11
+ right: "right",
12
+ space: "space",
13
+ return: "enter",
14
+ enter: "enter",
15
+ escape: "cancel"
16
+ };
17
+ export function mapKey(name, char) {
18
+ if (char === "\x03") {
19
+ return "cancel";
20
+ }
21
+ if (char === " ") {
22
+ return "space";
23
+ }
24
+ if (!name) {
25
+ return undefined;
26
+ }
27
+ return keyActions[name] ?? aliases[name];
28
+ }
@@ -0,0 +1,13 @@
1
+ import { CANCEL } from "./cancel-symbol.js";
2
+ import { type SelectOption } from "./select.js";
3
+ export interface MultiselectOptions<Value> {
4
+ message: string;
5
+ options: Array<SelectOption<Value>>;
6
+ initialValues?: Value[];
7
+ required?: boolean;
8
+ maxItems?: number;
9
+ signal?: AbortSignal;
10
+ input?: NodeJS.ReadableStream;
11
+ output?: NodeJS.WritableStream;
12
+ }
13
+ export declare function multiselectPrompt<Value>(opts: MultiselectOptions<Value>): Promise<Value[] | typeof CANCEL>;
@@ -0,0 +1,131 @@
1
+ import { color } from "../../components/color.js";
2
+ import { GLYPHS, symbol } from "./glyphs.js";
3
+ import { Prompt } from "./core.js";
4
+ import { limitOptions } from "./pagination.js";
5
+ import { findNonDisabled } from "./select.js";
6
+ class MultiselectPrompt extends Prompt {
7
+ options;
8
+ constructor(opts) {
9
+ if (opts.options.length === 0) {
10
+ throw new Error("Multiselect prompt requires at least one option.");
11
+ }
12
+ if (opts.options.every((option) => option.disabled)) {
13
+ throw new Error("Multiselect prompt requires at least one enabled option.");
14
+ }
15
+ const cursor = findNonDisabled(0, 1, opts.options);
16
+ super({
17
+ ...opts,
18
+ initialValue: [...(opts.initialValues ?? [])],
19
+ validate: (value) => {
20
+ if (opts.required && (!value || value.length === 0)) {
21
+ return "Please select at least one option.\nPress SPACE to select, ENTER to submit";
22
+ }
23
+ return undefined;
24
+ },
25
+ render: (prompt) => renderMultiselectPrompt(prompt, opts)
26
+ }, false);
27
+ this.options = opts.options;
28
+ this._cursor = cursor;
29
+ this.on("cursor", (action) => {
30
+ if (action === "up" || action === "left") {
31
+ this._cursor = findNonDisabled(this._cursor - 1, -1, this.options);
32
+ }
33
+ else if (action === "down" || action === "right") {
34
+ this._cursor = findNonDisabled(this._cursor + 1, 1, this.options);
35
+ }
36
+ else if (action === "space") {
37
+ this.toggleFocused();
38
+ }
39
+ });
40
+ this.on("key", (key) => {
41
+ if (key === "a") {
42
+ this.toggleAll();
43
+ }
44
+ else if (key === "i") {
45
+ this.invert();
46
+ }
47
+ });
48
+ }
49
+ get visibleOptions() {
50
+ return this.options;
51
+ }
52
+ enabledOptions() {
53
+ return this.options.filter((option) => !option.disabled);
54
+ }
55
+ toggleFocused() {
56
+ const option = this.options[this.cursor];
57
+ if (!option || option.disabled) {
58
+ return;
59
+ }
60
+ this.toggleValue(option.value);
61
+ }
62
+ toggleValue(value) {
63
+ const current = this.value ?? [];
64
+ this.setValue(current.includes(value)
65
+ ? current.filter((item) => item !== value)
66
+ : [...current, value]);
67
+ }
68
+ toggleAll() {
69
+ const enabledValues = this.enabledOptions().map((option) => option.value);
70
+ const current = this.value ?? [];
71
+ const allSelected = enabledValues.every((value) => current.includes(value));
72
+ this.setValue(allSelected ? [] : enabledValues);
73
+ }
74
+ invert() {
75
+ const current = this.value ?? [];
76
+ this.setValue(this.enabledOptions().map((option) => option.value).filter((value) => !current.includes(value)));
77
+ }
78
+ promptNonTty() {
79
+ if (process.env.POE_NO_PROMPT === "1") {
80
+ return Promise.resolve(this.value ?? []);
81
+ }
82
+ return super.promptNonTty();
83
+ }
84
+ }
85
+ function hasValue(values, value) {
86
+ return (values ?? []).includes(value);
87
+ }
88
+ function renderOption(option, values, active, submitted, cancelled) {
89
+ const selected = hasValue(values, option.value);
90
+ const hint = option.hint ? color.dim(` (${option.hint})`) : "";
91
+ if (submitted)
92
+ return color.dim(option.label);
93
+ if (cancelled)
94
+ return color.dim.strikethrough(option.label);
95
+ if (option.disabled)
96
+ return `${color.gray(GLYPHS.checkboxInactive)} ${color.gray.strikethrough(option.label)}${hint}`;
97
+ if (selected)
98
+ return `${color.green(GLYPHS.checkboxSelected)} ${active ? option.label : color.dim(option.label)}${hint}`;
99
+ if (active)
100
+ return `${color.cyan(GLYPHS.checkboxActive)} ${option.label}${hint}`;
101
+ return `${color.dim(GLYPHS.checkboxInactive)} ${color.dim(option.label)}${hint}`;
102
+ }
103
+ function renderMultiselectPrompt(prompt, opts) {
104
+ if (prompt.state === "submit" || prompt.state === "cancel") {
105
+ const labels = prompt.visibleOptions
106
+ .filter((option) => hasValue(prompt.value, option.value))
107
+ .map((option) => prompt.state === "submit" ? color.dim(option.label) : color.dim.strikethrough(option.label))
108
+ .join(", ");
109
+ const end = prompt.state === "submit" ? color.green(GLYPHS.barEnd) : color.red(GLYPHS.barEnd);
110
+ return `${color.gray(GLYPHS.barStart)} ${symbol(prompt.state)} ${opts.message}\n${color.gray(GLYPHS.bar)} ${labels}\n${end}`;
111
+ }
112
+ const lines = limitOptions({
113
+ cursor: prompt.cursor,
114
+ options: prompt.visibleOptions,
115
+ output: opts.output ?? process.stdout,
116
+ maxItems: opts.maxItems,
117
+ columnPadding: 3,
118
+ style: (option, active) => renderOption(option, prompt.value, active, false, false)
119
+ }).map((line) => `${prompt.state === "error" ? color.yellow(GLYPHS.bar) : color.cyan(GLYPHS.bar)} ${line}`);
120
+ const body = [`${color.gray(GLYPHS.barStart)} ${symbol(prompt.state)} ${opts.message}`, ...lines];
121
+ if (prompt.state === "error") {
122
+ body.push(`${color.yellow(GLYPHS.barEnd)} ${color.yellow(prompt.error)}`);
123
+ }
124
+ else {
125
+ body.push(color.cyan(GLYPHS.barEnd));
126
+ }
127
+ return body.join("\n");
128
+ }
129
+ export function multiselectPrompt(opts) {
130
+ return new MultiselectPrompt(opts).prompt();
131
+ }
@@ -0,0 +1,10 @@
1
+ export interface PaginationOptions<Option> {
2
+ cursor: number;
3
+ options: Option[];
4
+ style: (option: Option, active: boolean) => string;
5
+ output: NodeJS.WritableStream;
6
+ maxItems?: number;
7
+ columnPadding?: number;
8
+ rowPadding?: number;
9
+ }
10
+ export declare function limitOptions<Option>(opts: PaginationOptions<Option>): string[];
@@ -0,0 +1,52 @@
1
+ import { color } from "../../components/color.js";
2
+ import { GLYPHS } from "./glyphs.js";
3
+ import { getColumns, getRows } from "./wrap.js";
4
+ import { wrapAnsi } from "fast-wrap-ansi";
5
+ function countLines(values) {
6
+ return values.reduce((sum, value) => sum + value.split("\n").length, 0);
7
+ }
8
+ function trimToRows(values, cursorOffset, rows, hasTop, hasBottom) {
9
+ const output = [...values];
10
+ while (countLines(output) > rows && output.length > 1) {
11
+ const removeFromTop = hasTop && cursorOffset > 0;
12
+ const removeFromBottom = hasBottom && cursorOffset < output.length - 1;
13
+ if (removeFromTop) {
14
+ output.shift();
15
+ cursorOffset -= 1;
16
+ }
17
+ else if (removeFromBottom) {
18
+ output.pop();
19
+ }
20
+ else {
21
+ output.pop();
22
+ }
23
+ }
24
+ return output;
25
+ }
26
+ export function limitOptions(opts) {
27
+ const { cursor, options, style, output, maxItems = Number.POSITIVE_INFINITY, columnPadding = 0, rowPadding = 4 } = opts;
28
+ if (options.length === 0) {
29
+ return [];
30
+ }
31
+ const columns = Math.max(1, getColumns(output) - columnPadding);
32
+ const rowBudget = Math.max(getRows(output) - rowPadding, 0);
33
+ const visibleCount = Math.max(Math.min(maxItems, rowBudget), 5);
34
+ const cappedVisibleCount = Math.min(visibleCount, options.length);
35
+ let start = 0;
36
+ if (cursor >= cappedVisibleCount - 3) {
37
+ start = Math.max(Math.min(cursor - cappedVisibleCount + 3, options.length - cappedVisibleCount), 0);
38
+ }
39
+ const hasTopMarker = cappedVisibleCount < options.length && start > 0;
40
+ const hasBottomMarker = cappedVisibleCount < options.length && start + cappedVisibleCount < options.length;
41
+ const visible = options
42
+ .slice(start, start + cappedVisibleCount)
43
+ .map((option, index) => wrapAnsi(style(option, start + index === cursor), columns, { hard: true, trim: false }));
44
+ const trimmed = trimToRows(visible, Math.max(cursor - start, 0), Math.max(rowBudget - Number(hasTopMarker) - Number(hasBottomMarker), 1), hasTopMarker, hasBottomMarker);
45
+ if (hasTopMarker) {
46
+ trimmed.unshift(color.dim(GLYPHS.ellipsis));
47
+ }
48
+ if (hasBottomMarker) {
49
+ trimmed.push(color.dim(GLYPHS.ellipsis));
50
+ }
51
+ return trimmed;
52
+ }
@@ -0,0 +1,10 @@
1
+ import { CANCEL } from "./cancel-symbol.js";
2
+ export interface PasswordOptions {
3
+ message: string;
4
+ mask?: string;
5
+ validate?: (value: string) => string | Error | undefined;
6
+ signal?: AbortSignal;
7
+ input?: NodeJS.ReadableStream;
8
+ output?: NodeJS.WritableStream;
9
+ }
10
+ export declare function passwordPrompt(opts: PasswordOptions): Promise<string | typeof CANCEL>;