termkit 2.0.2 → 2.2.0

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 (73) hide show
  1. package/README.md +582 -37
  2. package/dist/config.d.ts +11 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/index.d.ts +49 -96
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +2584 -170
  7. package/dist/index.mjs +2563 -165
  8. package/dist/models/Bar.d.ts +125 -0
  9. package/dist/models/Bar.d.ts.map +1 -0
  10. package/dist/models/Chart.d.ts +106 -0
  11. package/dist/models/Chart.d.ts.map +1 -0
  12. package/dist/models/Column.d.ts +20 -0
  13. package/dist/models/Column.d.ts.map +1 -0
  14. package/dist/models/Command.d.ts +38 -0
  15. package/dist/models/Command.d.ts.map +1 -0
  16. package/dist/models/Input.d.ts +58 -0
  17. package/dist/models/Input.d.ts.map +1 -0
  18. package/dist/models/Log.d.ts +24 -0
  19. package/dist/models/Log.d.ts.map +1 -0
  20. package/dist/models/Markup.d.ts +17 -0
  21. package/dist/models/Markup.d.ts.map +1 -0
  22. package/dist/models/MultiBar.d.ts +17 -0
  23. package/dist/models/MultiBar.d.ts.map +1 -0
  24. package/dist/models/MultiSelect.d.ts +45 -0
  25. package/dist/models/MultiSelect.d.ts.map +1 -0
  26. package/dist/models/Option.d.ts +17 -0
  27. package/dist/models/Option.d.ts.map +1 -0
  28. package/dist/models/Scrollbox.d.ts +20 -0
  29. package/dist/models/Scrollbox.d.ts.map +1 -0
  30. package/dist/models/Select.d.ts +39 -0
  31. package/dist/models/Select.d.ts.map +1 -0
  32. package/dist/models/Spinner.d.ts +67 -0
  33. package/dist/models/Spinner.d.ts.map +1 -0
  34. package/dist/models/Table.d.ts +26 -0
  35. package/dist/models/Table.d.ts.map +1 -0
  36. package/dist/models/TermKit.d.ts +19 -0
  37. package/dist/models/TermKit.d.ts.map +1 -0
  38. package/dist/models/Variable.d.ts +28 -0
  39. package/dist/models/Variable.d.ts.map +1 -0
  40. package/dist/types.d.ts +10 -0
  41. package/dist/types.d.ts.map +1 -0
  42. package/dist/utils/cleanup.d.ts +2 -0
  43. package/dist/utils/cleanup.d.ts.map +1 -0
  44. package/dist/utils/color.d.ts +29 -0
  45. package/dist/utils/color.d.ts.map +1 -0
  46. package/dist/utils/findCommand.d.ts +3 -0
  47. package/dist/utils/findCommand.d.ts.map +1 -0
  48. package/dist/utils/findCommandVariables.d.ts +3 -0
  49. package/dist/utils/findCommandVariables.d.ts.map +1 -0
  50. package/dist/utils/findOption.d.ts +3 -0
  51. package/dist/utils/findOption.d.ts.map +1 -0
  52. package/dist/utils/findOptions.d.ts +3 -0
  53. package/dist/utils/findOptions.d.ts.map +1 -0
  54. package/dist/utils/findVariable.d.ts +5 -0
  55. package/dist/utils/findVariable.d.ts.map +1 -0
  56. package/dist/utils/findVariables.d.ts +3 -0
  57. package/dist/utils/findVariables.d.ts.map +1 -0
  58. package/dist/utils/getVariables.d.ts +3 -0
  59. package/dist/utils/getVariables.d.ts.map +1 -0
  60. package/dist/utils/padLeft.d.ts +2 -0
  61. package/dist/utils/padLeft.d.ts.map +1 -0
  62. package/dist/utils/padRight.d.ts +2 -0
  63. package/dist/utils/padRight.d.ts.map +1 -0
  64. package/dist/utils/padSides.d.ts +2 -0
  65. package/dist/utils/padSides.d.ts.map +1 -0
  66. package/dist/utils/stringLength.d.ts +2 -0
  67. package/dist/utils/stringLength.d.ts.map +1 -0
  68. package/dist/utils/truncate.d.ts +2 -0
  69. package/dist/utils/truncate.d.ts.map +1 -0
  70. package/dist/utils/wrap.d.ts +2 -0
  71. package/dist/utils/wrap.d.ts.map +1 -0
  72. package/package.json +35 -7
  73. package/dist/index.d.mts +0 -99
package/dist/index.mjs CHANGED
@@ -1,60 +1,738 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/config.ts
8
+ var isLegacyTerminal = process.env.TERM === "dumb" || process.platform === "win32" && !process.env.WT_SESSION && process.env.TERM_PROGRAM !== "vscode" && process.env.TERM_PROGRAM !== "Hyper";
9
+ var config = {
10
+ color: "cyan",
11
+ pulseColors: ["#06b6d4", "#67e8f9"],
12
+ glyphs: !isLegacyTerminal,
13
+ interactive: false
14
+ };
15
+ function configure(opts) {
16
+ if (opts.color) config.color = opts.color;
17
+ if (opts.pulseColors) config.pulseColors = opts.pulseColors;
18
+ if (opts.glyphs !== void 0) config.glyphs = opts.glyphs;
19
+ if (opts.interactive !== void 0) config.interactive = opts.interactive;
20
+ }
21
+
1
22
  // src/models/Command.ts
2
23
  import cosmetic from "cosmetic";
3
24
 
4
- // src/helpers/findCommand.ts
25
+ // src/models/Variable.ts
26
+ var Variable = class {
27
+ constructor(data) {
28
+ this.array = false;
29
+ this.default = null;
30
+ this.enum = null;
31
+ this.max = null;
32
+ this.min = null;
33
+ this.name = null;
34
+ this.raw = null;
35
+ this.required = false;
36
+ this.type = "string";
37
+ this.value = null;
38
+ if (!data) return;
39
+ if (data.array) this.array = data.array;
40
+ if (data.default !== void 0) this.default = data.default;
41
+ if (data.enum) this.enum = data.enum;
42
+ if (data.max !== void 0) this.max = data.max;
43
+ if (data.min !== void 0) this.min = data.min;
44
+ if (data.name) this.name = data.name;
45
+ if (data.raw) this.raw = data.raw;
46
+ if (data.required) this.required = data.required;
47
+ if (data.type) this.type = data.type;
48
+ if (this.array) this.value = [];
49
+ }
50
+ get hint() {
51
+ const parts = [];
52
+ if (this.type === "enum" && this.enum) parts.push(this.enum.join("|"));
53
+ if (this.min !== null && this.max !== null) parts.push(`${this.min}\u2013${this.max}`);
54
+ else if (this.min !== null) parts.push(`>= ${this.min}`);
55
+ else if (this.max !== null) parts.push(`<= ${this.max}`);
56
+ if (this.default !== null) parts.push(`default: ${this.default}`);
57
+ return parts.length > 0 ? `(${parts.join(", ")})` : null;
58
+ }
59
+ };
60
+
61
+ // src/utils/getVariables.ts
62
+ function parseName(raw) {
63
+ const colon = raw.indexOf(":");
64
+ if (colon === -1) return { name: raw, type: "string" };
65
+ const name = raw.slice(0, colon);
66
+ const rest = raw.slice(colon + 1);
67
+ const eqIdx = rest.lastIndexOf("=");
68
+ const typeStr = eqIdx !== -1 ? rest.slice(0, eqIdx) : rest;
69
+ const defaultValue = eqIdx !== -1 ? rest.slice(eqIdx + 1) : void 0;
70
+ const rangeMatch = typeStr.match(/^([a-z]+)\((-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?)\)$/);
71
+ if (rangeMatch) {
72
+ return { name, type: rangeMatch[1], min: Number(rangeMatch[2]), max: Number(rangeMatch[3]), default: defaultValue };
73
+ }
74
+ if (typeStr.includes("|")) {
75
+ return { name, type: "enum", enum: typeStr.split("|"), default: defaultValue };
76
+ }
77
+ return { name, type: typeStr, default: defaultValue };
78
+ }
79
+ function getVariables(string) {
80
+ const results = [];
81
+ for (const part of string.split(" ")) {
82
+ const trimmed = part.trim();
83
+ if (!trimmed) continue;
84
+ if (trimmed.startsWith("<") && trimmed.endsWith(">")) {
85
+ const { name, type, enum: enumValues, default: def, min, max } = parseName(trimmed.slice(1, -1));
86
+ results.push(new Variable({ default: def, enum: enumValues, max, min, name, raw: trimmed, required: true, type }));
87
+ } else if (trimmed.startsWith("[") && trimmed.endsWith("...]")) {
88
+ const { name, type, enum: enumValues, default: def, min, max } = parseName(trimmed.slice(1, -4));
89
+ results.push(new Variable({ array: true, default: def, enum: enumValues, max, min, name, raw: trimmed, type }));
90
+ } else if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
91
+ const { name, type, enum: enumValues, default: def, min, max } = parseName(trimmed.slice(1, -1));
92
+ results.push(new Variable({ default: def, enum: enumValues, max, min, name, raw: trimmed, type }));
93
+ } else {
94
+ throw new Error(`Unrecognized variable description: ${trimmed}`);
95
+ }
96
+ }
97
+ return results;
98
+ }
99
+
100
+ // src/models/Option.ts
101
+ var Option = class {
102
+ constructor(data) {
103
+ this.short = null;
104
+ this.long = null;
105
+ this.info = null;
106
+ this.variables = null;
107
+ if (!data) return;
108
+ if (data.short) this.short = data.short;
109
+ if (data.long) this.long = data.long;
110
+ if (data.info) this.info = data.info;
111
+ if (data.variables) this.variables = getVariables(data.variables);
112
+ }
113
+ description(info) {
114
+ this.info = info;
115
+ return this;
116
+ }
117
+ };
118
+
119
+ // src/utils/findCommand.ts
5
120
  function findCommand(array, commands) {
6
- for (const command2 of commands) {
7
- if (array[0] === command2.name) {
121
+ for (const command of commands) {
122
+ if (array[0] === command.name) {
8
123
  array.shift();
9
- return command2;
124
+ return command;
10
125
  }
11
126
  }
12
127
  return null;
13
128
  }
14
129
 
15
- // src/helpers/findVariable.ts
16
- function coerce(value, type) {
17
- if (type === "number") return Number(value);
130
+ // src/utils/color.ts
131
+ var RESET = "\x1B[0m";
132
+ var SHOW_CURSOR = "\x1B[?25h";
133
+ var HIDE_CURSOR = "\x1B[?25l";
134
+ var BOLD = "\x1B[1m";
135
+ var FAINT = "\x1B[2m";
136
+ var GREEN = "\x1B[32m";
137
+ var RED = "\x1B[31m";
138
+ var YELLOW = "\x1B[33m";
139
+ var BLUE = "\x1B[34m";
140
+ var MAGENTA = "\x1B[35m";
141
+ var CYAN = "\x1B[36m";
142
+ var DIM = 0.35;
143
+ var SHIMMER_SPEED = 0.5;
144
+ process.on("exit", () => {
145
+ if (process.stdout.isTTY) process.stdout.write(SHOW_CURSOR);
146
+ });
147
+ process.on("SIGINT", () => process.exit());
148
+ function parseHex(hex) {
149
+ const n = parseInt(hex.replace("#", ""), 16);
150
+ return { r: n >> 16 & 255, g: n >> 8 & 255, b: n & 255 };
151
+ }
152
+ function lerpColor(a, b, t) {
153
+ return {
154
+ r: Math.round(a.r + (b.r - a.r) * t),
155
+ g: Math.round(a.g + (b.g - a.g) * t),
156
+ b: Math.round(a.b + (b.b - a.b) * t)
157
+ };
158
+ }
159
+ function interpolateColor(colors, t) {
160
+ const clamped = Math.max(0, Math.min(1, t));
161
+ const segments = colors.length - 1;
162
+ const scaled = clamped * segments;
163
+ const i = Math.min(Math.floor(scaled), segments - 1);
164
+ return lerpColor(colors[i], colors[i + 1], scaled - i);
165
+ }
166
+ function formatColor(code, color) {
167
+ if (!process.stdout.isTTY) return "";
168
+ return `\x1B[${code};2;${color.r};${color.g};${color.b}m`;
169
+ }
170
+ function colorText(colorOrAnsi, text) {
171
+ if (!process.stdout.isTTY) return text;
172
+ if (colorOrAnsi.startsWith("#")) {
173
+ const c = parseHex(colorOrAnsi);
174
+ return `\x1B[38;2;${c.r};${c.g};${c.b}m${text}${RESET}`;
175
+ }
176
+ return `${colorOrAnsi}${text}${RESET}`;
177
+ }
178
+ function dimColor(c) {
179
+ return { r: Math.round(c.r * DIM), g: Math.round(c.g * DIM), b: Math.round(c.b * DIM) };
180
+ }
181
+ function shimmerFactor(t, phase, amplitude) {
182
+ const wave = 0.5 + 0.5 * Math.sin(2 * Math.PI * (t - phase));
183
+ return 1 - amplitude * (1 - wave);
184
+ }
185
+ function resolveColor(color) {
186
+ if (typeof color === "number") return `\x1B[38;5;${color}m`;
187
+ if (color.startsWith("#")) return color;
188
+ const map = {
189
+ black: "\x1B[30m",
190
+ red: "\x1B[31m",
191
+ green: "\x1B[32m",
192
+ yellow: "\x1B[33m",
193
+ blue: "\x1B[34m",
194
+ magenta: "\x1B[35m",
195
+ cyan: "\x1B[36m",
196
+ white: "\x1B[37m"
197
+ };
198
+ return map[color] ?? "\x1B[35m";
199
+ }
200
+ function applyShimmer(color, t, phase, amplitude) {
201
+ if (amplitude === 0) return color;
202
+ const factor = shimmerFactor(t, phase, amplitude);
203
+ return {
204
+ r: Math.round(color.r * factor),
205
+ g: Math.round(color.g * factor),
206
+ b: Math.round(color.b * factor)
207
+ };
208
+ }
209
+
210
+ // src/utils/stringLength.ts
211
+ var ANSI_PATTERN = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
212
+ var stringLength = (string) => {
213
+ if (!string) return 0;
214
+ return string.replace(ANSI_PATTERN, "").length;
215
+ };
216
+
217
+ // src/models/Input.ts
218
+ var CLEAR_LINE = "\x1B[2K";
219
+ var Input = class {
220
+ constructor(options = {}) {
221
+ this.promptColor = options.promptColor ?? GREEN;
222
+ this.promptGlyph = options.promptGlyph ?? (config.glyphs ? "\u25C6" : ">");
223
+ this.inputColor = options.inputColor ?? "";
224
+ this.errorColor = options.errorColor ?? RED;
225
+ this.placeholder = options.placeholder ?? "";
226
+ this.mask = options.mask ?? false;
227
+ this.inline = options.inline ?? false;
228
+ this.required = options.required ?? true;
229
+ this.type = options.type ?? "string";
230
+ this.defaultValue = options.default ?? null;
231
+ this.enumValues = options.enum ?? null;
232
+ this.match = options.match ?? null;
233
+ this.errorMsg = options.errorMessage ?? null;
234
+ this.regex = options.regex ?? null;
235
+ this.min = options.min ?? null;
236
+ this.max = options.max ?? null;
237
+ this.minLength = options.minLength ?? null;
238
+ this.maxLength = options.maxLength ?? null;
239
+ }
240
+ validate(value) {
241
+ const fail = (msg) => this.errorMsg ?? msg;
242
+ if (this.type === "number") {
243
+ const n = Number(value);
244
+ if (isNaN(n)) return fail("Must be a valid number");
245
+ if (this.min !== null && n < this.min) return fail(`Must be at least ${this.min}`);
246
+ if (this.max !== null && n > this.max) return fail(`Must be at most ${this.max}`);
247
+ return null;
248
+ }
249
+ if (this.type === "integer") {
250
+ const n = Number(value);
251
+ if (!Number.isInteger(n)) return fail("Must be a whole number");
252
+ if (this.min !== null && n < this.min) return fail(`Must be at least ${this.min}`);
253
+ if (this.max !== null && n > this.max) return fail(`Must be at most ${this.max}`);
254
+ return null;
255
+ }
256
+ if (this.type === "enum" && this.enumValues) {
257
+ if (!this.enumValues.includes(value)) return fail(`Must be one of: ${this.enumValues.join(", ")}`);
258
+ }
259
+ if (this.match !== null && value !== this.match) return fail("Does not match");
260
+ if (this.regex && !this.regex.test(value)) return fail("Invalid format");
261
+ if (this.minLength !== null && value.length < this.minLength) return fail(`Must be at least ${this.minLength} characters`);
262
+ if (this.maxLength !== null && value.length > this.maxLength) return fail(`Must be at most ${this.maxLength} characters`);
263
+ return null;
264
+ }
265
+ coerce(value) {
266
+ if (this.type === "number") return Number(value);
267
+ if (this.type === "integer") return parseInt(value, 10);
268
+ return value;
269
+ }
270
+ async ask(prompt) {
271
+ if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Input requires an interactive terminal");
272
+ if (this.type === "boolean") return this.askBoolean(prompt);
273
+ let inputStr = "";
274
+ let cursorPos = 0;
275
+ let error = null;
276
+ let hasErrorLine = false;
277
+ const glyph = this.promptGlyph ? `${colorText(this.promptColor, this.promptGlyph)} ` : "";
278
+ const indent = " ".repeat(this.promptGlyph ? stringLength(this.promptGlyph) + 1 : 0);
279
+ let promptLine = prompt;
280
+ if (this.type === "enum" && this.enumValues) {
281
+ promptLine += ` \x1B[2m(${this.enumValues.join("|")})\x1B[0m`;
282
+ }
283
+ if (!this.inline) process.stdout.write(`${glyph}${promptLine}
284
+ `);
285
+ const defaultStr = this.defaultValue !== null ? String(this.defaultValue) : "";
286
+ const getDisplayText = () => {
287
+ const raw = this.mask ? "\u2022".repeat(inputStr.length) : inputStr;
288
+ if (inputStr.length === 0 && defaultStr) return `\x1B[2m${this.placeholder || defaultStr}${RESET}`;
289
+ return this.inputColor ? colorText(this.inputColor, raw) : raw;
290
+ };
291
+ const renderInput = (redraw) => {
292
+ if (redraw && hasErrorLine) process.stdout.write("\x1B[1A");
293
+ const text = getDisplayText();
294
+ const line = this.inline ? `\r${CLEAR_LINE}${glyph}${promptLine} ${text}` : `\r${CLEAR_LINE}${indent}${text}`;
295
+ process.stdout.write(line);
296
+ if (error) {
297
+ process.stdout.write(`
298
+ \r${CLEAR_LINE}${indent}${colorText(this.errorColor, `\u2717 ${error}`)}`);
299
+ hasErrorLine = true;
300
+ } else {
301
+ if (hasErrorLine) {
302
+ process.stdout.write(`
303
+ \r${CLEAR_LINE}\x1B[1A${line}`);
304
+ }
305
+ hasErrorLine = false;
306
+ }
307
+ if (inputStr.length > 0 && cursorPos < inputStr.length && !error) {
308
+ process.stdout.write(`\x1B[${inputStr.length - cursorPos}D`);
309
+ }
310
+ };
311
+ renderInput(false);
312
+ return new Promise((resolve) => {
313
+ const cleanup = () => {
314
+ if (hasErrorLine) process.stdout.write(`\r${CLEAR_LINE}\x1B[1A`);
315
+ const text = getDisplayText();
316
+ const line = this.inline ? `\r${CLEAR_LINE}${glyph}${promptLine} ${text}` : `\r${CLEAR_LINE}${indent}${text}`;
317
+ process.stdout.write(`${line}
318
+ `);
319
+ process.stdin.setRawMode(false);
320
+ process.stdin.pause();
321
+ process.stdin.removeListener("data", onKey);
322
+ };
323
+ const onKey = (key) => {
324
+ const str = key.toString();
325
+ if (str === "\r" || str === "\n") {
326
+ const value = inputStr.length === 0 && defaultStr ? defaultStr : inputStr;
327
+ const err = this.validate(value);
328
+ if (err) {
329
+ error = err;
330
+ renderInput(true);
331
+ } else {
332
+ const usingDefault = inputStr.length === 0 && this.defaultValue !== null;
333
+ if (usingDefault) inputStr = defaultStr;
334
+ cleanup();
335
+ resolve(usingDefault ? this.defaultValue : this.coerce(value));
336
+ }
337
+ } else if (str === "\x1B[D") {
338
+ cursorPos = Math.max(0, cursorPos - 1);
339
+ renderInput(true);
340
+ } else if (str === "\x1B[C") {
341
+ cursorPos = Math.min(inputStr.length, cursorPos + 1);
342
+ renderInput(true);
343
+ } else if (str === "\x1B[H" || str === "\x1B[1~" || str === "") {
344
+ cursorPos = 0;
345
+ renderInput(true);
346
+ } else if (str === "\x1B[F" || str === "\x1B[4~" || str === "") {
347
+ cursorPos = inputStr.length;
348
+ renderInput(true);
349
+ } else if (str === "\x1B[3~") {
350
+ if (cursorPos < inputStr.length) {
351
+ inputStr = inputStr.slice(0, cursorPos) + inputStr.slice(cursorPos + 1);
352
+ error = null;
353
+ renderInput(true);
354
+ }
355
+ } else if (str === "\x1B") {
356
+ if (!this.required) {
357
+ cleanup();
358
+ resolve(null);
359
+ }
360
+ } else if (str === "") {
361
+ cleanup();
362
+ process.exit();
363
+ } else if (str === "\x7F" || str === "\b") {
364
+ if (cursorPos > 0) {
365
+ inputStr = inputStr.slice(0, cursorPos - 1) + inputStr.slice(cursorPos);
366
+ cursorPos--;
367
+ error = null;
368
+ renderInput(true);
369
+ }
370
+ } else if (str.charCodeAt(0) >= 32) {
371
+ if (this.maxLength !== null && inputStr.length >= this.maxLength) return;
372
+ inputStr = inputStr.slice(0, cursorPos) + str + inputStr.slice(cursorPos);
373
+ cursorPos++;
374
+ error = null;
375
+ renderInput(true);
376
+ }
377
+ };
378
+ process.stdin.setRawMode(true);
379
+ process.stdin.resume();
380
+ process.stdin.on("data", onKey);
381
+ });
382
+ }
383
+ async askBoolean(prompt) {
384
+ const hasDefault = this.defaultValue !== null;
385
+ const defaultBool = this.defaultValue === true || this.defaultValue === "y" || this.defaultValue === "Y" || this.defaultValue === 1;
386
+ const hint = hasDefault ? defaultBool ? "[Y/n]" : "[y/N]" : "[y/n]";
387
+ const glyph = this.promptGlyph ? `${colorText(this.promptColor, this.promptGlyph)} ` : "";
388
+ const indent = " ".repeat(this.promptGlyph ? stringLength(this.promptGlyph) + 1 : 0);
389
+ if (this.inline) {
390
+ process.stdout.write(`${glyph}${prompt} \x1B[2m${hint}${RESET} `);
391
+ } else {
392
+ process.stdout.write(`${glyph}${prompt} \x1B[2m${hint}${RESET}
393
+ `);
394
+ process.stdout.write(`${indent}`);
395
+ }
396
+ return new Promise((resolve) => {
397
+ const finish = (selection, value) => {
398
+ process.stdin.setRawMode(false);
399
+ process.stdin.pause();
400
+ process.stdin.removeListener("data", onKey);
401
+ if (this.inline) {
402
+ process.stdout.write(`\r${CLEAR_LINE}${glyph}${prompt} \x1B[2m${hint}${RESET} ${selection}
403
+ `);
404
+ } else {
405
+ process.stdout.write(`\r${CLEAR_LINE}${indent}${selection}
406
+ `);
407
+ }
408
+ resolve(value);
409
+ };
410
+ const onKey = (key) => {
411
+ const str = key.toString();
412
+ if (str === "\r" || str === "\n") {
413
+ if (hasDefault) finish(defaultBool ? "yes" : "no", defaultBool);
414
+ } else if (str === "y" || str === "Y") {
415
+ finish("yes", true);
416
+ } else if (str === "n" || str === "N") {
417
+ finish("no", false);
418
+ } else if (str === "\x1B") {
419
+ if (!this.required) finish("", null);
420
+ } else if (str === "") {
421
+ process.stdin.setRawMode(false);
422
+ process.stdin.pause();
423
+ process.stdin.removeListener("data", onKey);
424
+ process.exit();
425
+ }
426
+ };
427
+ process.stdin.setRawMode(true);
428
+ process.stdin.resume();
429
+ process.stdin.on("data", onKey);
430
+ });
431
+ }
432
+ };
433
+ async function input(prompt, options = {}) {
434
+ return new Input(options).ask(prompt);
435
+ }
436
+ async function confirm(prompt, options) {
437
+ return new Input({ ...options, type: "boolean" }).ask(prompt);
438
+ }
439
+
440
+ // src/utils/cleanup.ts
441
+ var fns = /* @__PURE__ */ new Set();
442
+ var installed = false;
443
+ function install() {
444
+ if (installed) return;
445
+ installed = true;
446
+ process.on("SIGINT", () => {
447
+ flush();
448
+ process.exit(130);
449
+ });
450
+ process.on("exit", flush);
451
+ }
452
+ function flush() {
453
+ for (const fn of fns) {
454
+ try {
455
+ fn();
456
+ } catch {
457
+ }
458
+ }
459
+ fns.clear();
460
+ }
461
+ function registerCleanup(fn) {
462
+ install();
463
+ fns.add(fn);
464
+ return () => {
465
+ fns.delete(fn);
466
+ };
467
+ }
468
+
469
+ // src/models/Select.ts
470
+ var CURSOR_UP = (n) => `\x1B[${n}A`;
471
+ var Select = class {
472
+ constructor(options = {}) {
473
+ this._colorOffset = 0;
474
+ this._shimmerPhase = 0;
475
+ this.promptColor = options.promptColor ?? resolveColor(config.color);
476
+ this.promptGlyph = options.promptGlyph ?? (config.glyphs ? "\u25C6" : ">");
477
+ this.descriptionColor = options.descriptionColor ?? BLUE;
478
+ this.skipLabel = options.skipLabel ?? "Skip";
479
+ this.selectedPrefix = options.selectedPrefix ?? ">";
480
+ this.selectedSuffix = options.selectedSuffix ?? "<";
481
+ this.colorCycle = options.colorCycle ?? 1;
482
+ this.shimmer = options.shimmer ?? 0;
483
+ this.interval = options.interval ?? 80;
484
+ this.searchEnabled = options.search ?? false;
485
+ this.maxHeight = options.maxHeight;
486
+ const colors = options.colors ?? config.pulseColors;
487
+ this._parsedColors = colors.length >= 2 ? colors.map(parseHex) : [];
488
+ }
489
+ pulseColor() {
490
+ if (this._parsedColors.length < 2) return "";
491
+ const t = (this._colorOffset % 1 + 1) % 1;
492
+ const base2 = interpolateColor(this._parsedColors, t);
493
+ const color = applyShimmer(base2, 0.5, this._shimmerPhase, this.shimmer);
494
+ return formatColor(38, color);
495
+ }
496
+ async ask(prompt, items) {
497
+ if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Select requires an interactive terminal");
498
+ let selectedIndex = 0;
499
+ let viewportOffset = 0;
500
+ let searchQuery = "";
501
+ let lastDrawnLines = 0;
502
+ const skipItem = { label: this.skipLabel };
503
+ const getFiltered = () => {
504
+ if (!this.searchEnabled || searchQuery === "") return items;
505
+ const q = searchQuery.toLowerCase();
506
+ return items.filter((item) => item.label.toLowerCase().includes(q) || (item.description?.toLowerCase().includes(q) ?? false));
507
+ };
508
+ process.stdout.write(HIDE_CURSOR);
509
+ const glyph = this.promptGlyph ? `${colorText(this.promptColor, this.promptGlyph)} ` : "";
510
+ const indent = " ".repeat(this.promptGlyph ? stringLength(this.promptGlyph) + 1 : 0);
511
+ process.stdout.write(`${glyph}${prompt}
512
+ `);
513
+ const renderList = (redraw) => {
514
+ const filtered = getFiltered();
515
+ const allItems = [...filtered, skipItem];
516
+ if (selectedIndex >= allItems.length) selectedIndex = allItems.length - 1;
517
+ if (this.maxHeight) {
518
+ if (selectedIndex < viewportOffset) viewportOffset = selectedIndex;
519
+ else if (selectedIndex >= viewportOffset + this.maxHeight) viewportOffset = selectedIndex - this.maxHeight + 1;
520
+ viewportOffset = Math.max(0, Math.min(viewportOffset, Math.max(0, allItems.length - this.maxHeight)));
521
+ }
522
+ const visibleStart = this.maxHeight ? viewportOffset : 0;
523
+ const visibleEnd = this.maxHeight ? Math.min(allItems.length, viewportOffset + this.maxHeight) : allItems.length;
524
+ if (redraw) {
525
+ if (lastDrawnLines > 0) process.stdout.write(CURSOR_UP(lastDrawnLines));
526
+ process.stdout.write("\r\x1B[0J");
527
+ }
528
+ lastDrawnLines = 0;
529
+ if (this.searchEnabled) {
530
+ process.stdout.write(`\r${indent}${colorText(this.promptColor, "/")} ${searchQuery}|
531
+ `);
532
+ lastDrawnLines++;
533
+ }
534
+ const pulse = this.pulseColor();
535
+ for (let i = visibleStart; i < visibleEnd; i++) {
536
+ const item = allItems[i];
537
+ const isSelected = i === selectedIndex;
538
+ const isSkip = i === filtered.length;
539
+ const relativeNum = i - visibleStart + 1;
540
+ const numStr = isSkip ? "0." : `${relativeNum}.`;
541
+ const desc = item.description ? ` ${colorText(this.descriptionColor, `\u2014 ${item.description}`)}` : "";
542
+ let marker, tail;
543
+ if (isSelected && pulse) {
544
+ marker = `${pulse}${this.selectedPrefix}${RESET}`;
545
+ tail = ` ${pulse}${this.selectedSuffix}${RESET}`;
546
+ } else {
547
+ const fallback = isSelected ? this.promptColor : "";
548
+ marker = fallback ? colorText(fallback, this.selectedPrefix) : " ".repeat(stringLength(this.selectedPrefix));
549
+ tail = isSelected ? ` ${colorText(this.promptColor, this.selectedSuffix)}` : "";
550
+ }
551
+ process.stdout.write(`\r${indent}${marker} ${numStr} ${item.label}${desc}${tail}
552
+ `);
553
+ lastDrawnLines++;
554
+ }
555
+ };
556
+ renderList(false);
557
+ return new Promise((resolve) => {
558
+ let timer = null;
559
+ const deregisterCleanup = registerCleanup(() => {
560
+ if (timer) {
561
+ clearInterval(timer);
562
+ timer = null;
563
+ }
564
+ process.stdin.setRawMode(false);
565
+ process.stdin.pause();
566
+ process.stdin.removeListener("data", onKey);
567
+ process.stdout.write(SHOW_CURSOR);
568
+ });
569
+ const cleanup = () => {
570
+ deregisterCleanup();
571
+ if (timer) {
572
+ clearInterval(timer);
573
+ timer = null;
574
+ }
575
+ process.stdin.setRawMode(false);
576
+ process.stdin.pause();
577
+ process.stdin.removeListener("data", onKey);
578
+ process.stdout.write(SHOW_CURSOR);
579
+ };
580
+ if (this._parsedColors.length >= 2) {
581
+ timer = setInterval(() => {
582
+ this._colorOffset = (this._colorOffset + this.colorCycle * this.interval / 1e3) % 1;
583
+ if (this.shimmer > 0) {
584
+ this._shimmerPhase = (this._shimmerPhase + SHIMMER_SPEED * this.interval / 1e3) % 1;
585
+ }
586
+ renderList(true);
587
+ }, this.interval);
588
+ }
589
+ const onKey = (key) => {
590
+ const str = key.toString();
591
+ const filtered = getFiltered();
592
+ const allItems = [...filtered, skipItem];
593
+ if (str === "\x1B[A") {
594
+ selectedIndex = (selectedIndex - 1 + allItems.length) % allItems.length;
595
+ renderList(true);
596
+ } else if (str === "\x1B[B") {
597
+ selectedIndex = (selectedIndex + 1) % allItems.length;
598
+ renderList(true);
599
+ } else if (str === "\r" || str === "\n") {
600
+ cleanup();
601
+ resolve(selectedIndex === filtered.length ? null : filtered[selectedIndex] ?? null);
602
+ } else if (str === "") {
603
+ cleanup();
604
+ process.exit(130);
605
+ } else if (this.searchEnabled) {
606
+ if (str === "\x7F" || str === "\b") {
607
+ searchQuery = searchQuery.slice(0, -1);
608
+ const newFiltered = getFiltered();
609
+ if (selectedIndex >= newFiltered.length + 1) selectedIndex = Math.max(0, newFiltered.length);
610
+ viewportOffset = 0;
611
+ renderList(true);
612
+ } else if (str.length === 1 && str >= " ") {
613
+ searchQuery += str;
614
+ selectedIndex = 0;
615
+ viewportOffset = 0;
616
+ renderList(true);
617
+ }
618
+ } else {
619
+ const n = parseInt(str);
620
+ if (!isNaN(n) && n >= 0 && n <= Math.min(items.length, 9)) {
621
+ const visibleStart = this.maxHeight ? viewportOffset : 0;
622
+ selectedIndex = n === 0 ? allItems.length - 1 : visibleStart + n - 1;
623
+ selectedIndex = Math.max(0, Math.min(selectedIndex, allItems.length - 1));
624
+ renderList(true);
625
+ }
626
+ }
627
+ };
628
+ process.stdin.setRawMode(true);
629
+ process.stdin.resume();
630
+ process.stdin.on("data", onKey);
631
+ });
632
+ }
633
+ };
634
+ async function select(prompt, items, options) {
635
+ return new Select(options).ask(prompt, items);
636
+ }
637
+
638
+ // src/utils/findVariable.ts
639
+ function coerce(value, type, enumValues, min = null, max = null) {
640
+ if (type === "number" || type === "integer") {
641
+ const n = Number(value);
642
+ if (type === "integer" && !Number.isInteger(n)) throw new Error(`Invalid value "${value}" \u2014 expected an integer`);
643
+ if (min !== null && n < min) throw new Error(`Invalid value "${value}" \u2014 must be >= ${min}`);
644
+ if (max !== null && n > max) throw new Error(`Invalid value "${value}" \u2014 must be <= ${max}`);
645
+ return n;
646
+ }
647
+ if (type === "string") {
648
+ if (min !== null && value.length < min) throw new Error(`Invalid value "${value}" \u2014 must be at least ${min} characters`);
649
+ if (max !== null && value.length > max) throw new Error(`Invalid value "${value}" \u2014 must be at most ${max} characters`);
650
+ return value;
651
+ }
18
652
  if (type === "boolean") return value === "true";
653
+ if (type === "enum" && enumValues) {
654
+ if (!enumValues.includes(value)) {
655
+ throw new Error(`Invalid value "${value}" \u2014 expected one of: ${enumValues.join(", ")}`);
656
+ }
657
+ }
19
658
  return value;
20
659
  }
21
- function findVariable(array, variable, commands) {
660
+ async function promptForVariable(variable) {
661
+ const promptColor = resolveColor(config.color);
662
+ if (variable.type === "enum" && variable.enum) {
663
+ const items = variable.enum.map((label) => ({ label }));
664
+ const result = await new Select({ promptColor }).ask(`<${variable.name}>`, items);
665
+ return result !== null ? result.label : null;
666
+ }
667
+ const isNumeric = variable.type === "number" || variable.type === "integer";
668
+ return new Input({
669
+ type: variable.type,
670
+ promptColor,
671
+ min: isNumeric ? variable.min ?? void 0 : void 0,
672
+ max: isNumeric ? variable.max ?? void 0 : void 0,
673
+ minLength: !isNumeric ? variable.min ?? void 0 : void 0,
674
+ maxLength: !isNumeric ? variable.max ?? void 0 : void 0,
675
+ required: true
676
+ }).ask(`<${variable.name}>`);
677
+ }
678
+ async function findVariable(array, variable, commands) {
22
679
  if (variable.array) {
23
680
  const result = [];
24
681
  while (array.length > 0 && !array[0].startsWith("-")) {
25
682
  if (commands.includes(array[0])) break;
26
- result.push(coerce(array.shift(), variable.type));
683
+ result.push(coerce(array.shift(), variable.type, variable.enum, variable.min, variable.max));
684
+ }
685
+ if (result.length === 0 && variable.required) {
686
+ if (config.interactive && process.stdout.isTTY) {
687
+ try {
688
+ const value = await promptForVariable(variable);
689
+ if (value !== null) return [value];
690
+ } catch {
691
+ throw new Error(`Missing required variable <${variable.name}> \u2014 stdin is not interactive`);
692
+ }
693
+ }
694
+ throw new Error(`Missing required variable <${variable.name}>`);
27
695
  }
28
- if (result.length === 0 && variable.required) throw new Error(`Missing required variable <${variable.name}>`);
29
696
  return result.length > 0 ? result : true;
30
697
  }
31
698
  if (array.length > 0 && !array[0].startsWith("-")) {
32
699
  if ((!commands.includes(array[0]) || variable.required) && array[0] !== "help") {
33
- return coerce(array.shift(), variable.type);
700
+ return coerce(array.shift(), variable.type, variable.enum, variable.min, variable.max);
701
+ }
702
+ }
703
+ if (variable.required) {
704
+ if (config.interactive && process.stdout.isTTY) {
705
+ try {
706
+ const value = await promptForVariable(variable);
707
+ if (value !== null) return value;
708
+ } catch {
709
+ throw new Error(`Missing required variable <${variable.name}> \u2014 stdin is not interactive`);
710
+ }
34
711
  }
712
+ throw new Error(`Missing required variable <${variable.name}>`);
35
713
  }
36
- if (variable.required) throw new Error(`Missing required variable <${variable.name}>`);
714
+ if (variable.default !== null) return coerce(variable.default, variable.type, variable.enum);
37
715
  return true;
38
716
  }
39
717
 
40
- // src/helpers/findCommandVariables.ts
41
- function findCommandVariables(array, command2) {
42
- if (!command2.variables) return null;
718
+ // src/utils/findCommandVariables.ts
719
+ async function findCommandVariables(array, command) {
720
+ if (!command.variables) return null;
43
721
  const result = {};
44
- for (const variable of command2.variables) {
45
- const value = findVariable(array, variable, command2.commandStrings);
722
+ for (const variable of command.variables) {
723
+ const value = await findVariable(array, variable, command.commandStrings);
46
724
  if (value !== true) result[variable.name] = value;
47
725
  }
48
726
  return Object.keys(result).length > 0 ? result : null;
49
727
  }
50
728
 
51
- // src/helpers/findOption.ts
729
+ // src/utils/findOption.ts
52
730
  function findOption(string, options) {
53
731
  return options.find((o) => o.short === string || o.long === string);
54
732
  }
55
733
 
56
- // src/helpers/findVariables.ts
57
- function findVariables(base2, array, variables, commands) {
734
+ // src/utils/findVariables.ts
735
+ async function findVariables(base2, array, variables, commands) {
58
736
  const result = {};
59
737
  if (!variables) {
60
738
  if (base2) result[base2] = true;
@@ -62,7 +740,7 @@ function findVariables(base2, array, variables, commands) {
62
740
  }
63
741
  if (variables.length > 1 && base2) result[base2] = {};
64
742
  for (const variable of variables) {
65
- const value = findVariable(array, variable, commands);
743
+ const value = await findVariable(array, variable, commands);
66
744
  if (variables.length > 1 && base2) {
67
745
  ;
68
746
  result[base2][variable.name] = value;
@@ -75,33 +753,41 @@ function findVariables(base2, array, variables, commands) {
75
753
  return result;
76
754
  }
77
755
 
78
- // src/helpers/findOptions.ts
79
- function findOptions(array, command2) {
756
+ // src/utils/findOptions.ts
757
+ async function findOptions(array, command) {
80
758
  const result = {};
81
759
  while (array.length > 0 && array[0].startsWith("-")) {
82
760
  if (array[0].startsWith("--")) {
83
761
  const raw = array.shift().slice(2);
84
- const option2 = findOption(raw, command2.optionsArray);
85
- if (!option2) throw new Error(`Unknown Option: --${raw}`);
762
+ if (raw.startsWith("no-")) {
763
+ const longName = raw.slice(3);
764
+ const negated = findOption(longName, command.optionsArray);
765
+ if (negated?.long) {
766
+ result[negated.long] = false;
767
+ continue;
768
+ }
769
+ }
770
+ const option = findOption(raw, command.optionsArray);
771
+ if (!option) throw new Error(`Unknown Option: --${raw}`);
86
772
  try {
87
- Object.assign(result, findVariables(option2.long, array, option2.variables, command2.commandStrings));
773
+ Object.assign(result, await findVariables(option.long, array, option.variables, command.commandStrings));
88
774
  } catch (err) {
89
775
  ;
90
- err.message += ` for --${option2.long}`;
776
+ err.message += ` for --${option.long}`;
91
777
  throw err;
92
778
  }
93
779
  } else {
94
780
  let string = array.shift();
95
781
  const short = string.slice(1, 2);
96
- const option2 = findOption(short, command2.optionsArray);
97
- if (!option2) throw new Error(`Unknown Option: -${short}`);
98
- string = string.replace(short, "");
782
+ const option = findOption(short, command.optionsArray);
783
+ if (!option) throw new Error(`Unknown Option: -${short}`);
784
+ string = "-" + string.slice(2);
99
785
  if (string !== "-") array.unshift(string);
100
786
  try {
101
- Object.assign(result, findVariables(option2.long, array, option2.variables, command2.commandStrings));
787
+ Object.assign(result, await findVariables(option.long, array, option.variables, command.commandStrings));
102
788
  } catch (err) {
103
789
  ;
104
- err.message += ` for --${option2.long}`;
790
+ err.message += ` for --${option.long}`;
105
791
  throw err;
106
792
  }
107
793
  }
@@ -109,74 +795,6 @@ function findOptions(array, command2) {
109
795
  return result;
110
796
  }
111
797
 
112
- // src/models/Variable.ts
113
- var Variable = class {
114
- constructor(data) {
115
- this.array = false;
116
- this.name = null;
117
- this.raw = null;
118
- this.required = false;
119
- this.type = "string";
120
- this.value = null;
121
- if (!data) return;
122
- if (data.array) this.array = data.array;
123
- if (data.name) this.name = data.name;
124
- if (data.raw) this.raw = data.raw;
125
- if (data.required) this.required = data.required;
126
- if (data.type) this.type = data.type;
127
- if (this.array) this.value = [];
128
- }
129
- };
130
-
131
- // src/helpers/getVariables.ts
132
- function parseName(raw) {
133
- const colon = raw.indexOf(":");
134
- if (colon === -1) return { name: raw, type: "string" };
135
- return {
136
- name: raw.slice(0, colon),
137
- type: raw.slice(colon + 1)
138
- };
139
- }
140
- function getVariables(string) {
141
- const results = [];
142
- for (const part of string.split(" ")) {
143
- const trimmed = part.trim();
144
- if (!trimmed) continue;
145
- if (trimmed.startsWith("<") && trimmed.endsWith(">")) {
146
- const { name, type } = parseName(trimmed.slice(1, -1));
147
- results.push(new Variable({ name, raw: trimmed, required: true, type }));
148
- } else if (trimmed.startsWith("[") && trimmed.endsWith("...]")) {
149
- const { name, type } = parseName(trimmed.slice(1, -4));
150
- results.push(new Variable({ array: true, name, raw: trimmed, type }));
151
- } else if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
152
- const { name, type } = parseName(trimmed.slice(1, -1));
153
- results.push(new Variable({ name, raw: trimmed, type }));
154
- } else {
155
- throw new Error(`Unrecognized variable description: ${trimmed}`);
156
- }
157
- }
158
- return results;
159
- }
160
-
161
- // src/models/Option.ts
162
- var Option = class {
163
- constructor(data) {
164
- this.short = null;
165
- this.long = null;
166
- this.info = null;
167
- this.variables = null;
168
- if (!data) return;
169
- if (data.short) this.short = data.short;
170
- if (data.long) this.long = data.long;
171
- if (data.info) this.info = data.info;
172
- if (data.variables) this.variables = getVariables(data.variables);
173
- }
174
- description(info) {
175
- this.info = info;
176
- return this;
177
- }
178
- };
179
-
180
798
  // src/models/Command.ts
181
799
  var Command = class {
182
800
  constructor(data) {
@@ -228,8 +846,8 @@ var Command = class {
228
846
  this.middlewaresArray.push(fn);
229
847
  return this;
230
848
  }
231
- middlewares(fns) {
232
- this.middlewaresArray.push(...fns);
849
+ middlewares(fns2) {
850
+ this.middlewaresArray.push(...fns2);
233
851
  return this;
234
852
  }
235
853
  option(short, long, variables, info) {
@@ -244,9 +862,17 @@ var Command = class {
244
862
  this.versionString = v;
245
863
  return this;
246
864
  }
247
- help(_source) {
865
+ buildInfo(info, variables) {
866
+ const hints = variables?.map((v) => v.hint).filter(Boolean) ?? [];
867
+ return [info, ...hints].filter(Boolean).join(" ");
868
+ }
869
+ help(source) {
870
+ const recursive = source?.includes("-r") === true || source?.includes("--recursive") === true;
871
+ this.printHelp(this.name ?? "Program", recursive);
872
+ }
873
+ printHelp(fullName, recursive) {
248
874
  const table = [];
249
- let program = this.name ?? "Program";
875
+ let program = fullName;
250
876
  if (this.variables) for (const v of this.variables) program += ` ${v.raw}`;
251
877
  if (this.optionsArray.length > 0) program += " [...options]";
252
878
  table.push({ title: "\nCommand", info: program, data: [] });
@@ -260,7 +886,7 @@ var Command = class {
260
886
  if (opt.short && opt.long) name += ", ";
261
887
  if (opt.long) name += `--${opt.long}`;
262
888
  if (opt.variables) for (const v of opt.variables) name += ` ${v.raw}`;
263
- section.data.push([name, opt.info ?? ""]);
889
+ section.data.push([name, this.buildInfo(opt.info, opt.variables)]);
264
890
  }
265
891
  table.push(section);
266
892
  }
@@ -269,7 +895,7 @@ var Command = class {
269
895
  for (const cmd of this.commandsArray) {
270
896
  let name = cmd.name ?? "";
271
897
  if (cmd.variables) for (const v of cmd.variables) name += ` ${v.raw}`;
272
- section.data.push([name, cmd.info ?? ""]);
898
+ section.data.push([name, this.buildInfo(cmd.info, cmd.variables)]);
273
899
  }
274
900
  table.push(section);
275
901
  }
@@ -283,7 +909,8 @@ var Command = class {
283
909
  }
284
910
  const lines = [];
285
911
  for (const section of table) {
286
- lines.push(section.title ? cosmetic.cyan.underline.encoder(section.title) : "");
912
+ const styled = typeof config.color === "number" ? cosmetic.xterm(config.color) : config.color.startsWith("#") ? cosmetic.hex(config.color) : cosmetic[config.color];
913
+ lines.push(section.title ? styled.underline.encoder(section.title) : "");
287
914
  if (section.info) lines.push(section.info);
288
915
  for (const row of section.data) {
289
916
  let line = "";
@@ -296,27 +923,37 @@ var Command = class {
296
923
  lines.push("");
297
924
  }
298
925
  for (const line of lines) console.log(line);
926
+ if (recursive) {
927
+ for (const cmd of this.commandsArray) {
928
+ cmd.printHelp(`${fullName} ${cmd.name ?? ""}`, true);
929
+ }
930
+ }
299
931
  }
300
- async parse(input) {
301
- const array = [...input];
932
+ async parse(input2) {
933
+ const array = [...input2];
302
934
  array.splice(0, 2);
303
- let command2 = this;
935
+ let command = this;
304
936
  const options = { _source: Array.from(array) };
937
+ const ddIdx = array.indexOf("--");
938
+ if (ddIdx !== -1) {
939
+ options._ = array.splice(ddIdx + 1);
940
+ array.splice(ddIdx, 1);
941
+ }
305
942
  while (array.length) {
306
943
  if (!array.includes("help")) {
307
- Object.assign(options, findOptions(array, command2));
308
- const cmdVars = findCommandVariables(array, command2);
944
+ Object.assign(options, await findOptions(array, command));
945
+ const cmdVars = await findCommandVariables(array, command);
309
946
  if (cmdVars) Object.assign(options, cmdVars);
310
- Object.assign(options, findOptions(array, command2));
947
+ Object.assign(options, await findOptions(array, command));
311
948
  }
312
949
  if (array.length) {
313
950
  if (!array.includes("help")) {
314
- for (const mw of command2.middlewaresArray) await mw(options);
951
+ for (const mw of command.middlewaresArray) await mw(options);
315
952
  }
316
- const next = findCommand(array, command2.commandsArray);
317
- if (!next && array[0] === "help") return command2.help(options._source);
953
+ const next = findCommand(array, command.commandsArray);
954
+ if (!next && array[0] === "help") return command.help(options._source);
318
955
  if (!next) throw new SyntaxError(`Unknown command: ${array[0]}`);
319
- const name = command2.name ?? "_base";
956
+ const name = command.name ?? "_base";
320
957
  if (!options._parents) options._parents = {};
321
958
  options._parents[name] = {};
322
959
  for (const key of Object.keys(options)) {
@@ -325,69 +962,1830 @@ var Command = class {
325
962
  delete options[key];
326
963
  }
327
964
  }
328
- command2 = next;
965
+ command = next;
966
+ }
967
+ }
968
+ for (const opt of command.optionsArray) {
969
+ if (!opt.long || !opt.variables) continue;
970
+ for (const v of opt.variables) {
971
+ if (v.default !== null && !(opt.long in options)) {
972
+ options[opt.long] = coerce(v.default, v.type, v.enum, v.min, v.max);
973
+ }
329
974
  }
330
975
  }
331
- for (const mw of command2.middlewaresArray) await mw(options);
332
- if (command2.actionFunction) return command2.actionFunction(options);
333
- if (options._source.length === 2) return command2.help(options._source);
334
- throw new Error(`No action for command: ${command2.name ?? "_base"}`);
976
+ for (const mw of command.middlewaresArray) await mw(options);
977
+ if (command.actionFunction) return command.actionFunction(options);
978
+ if (options._source.length === 2) return command.help(options._source);
979
+ throw new Error(`No action for command: ${command.name ?? "_base"}`);
335
980
  }
336
981
  };
337
982
 
338
- // src/models/TermKit.ts
339
- var _TermKit = class _TermKit {
340
- static set defaults(obj) {
341
- _TermKit.commandDefaults = obj;
983
+ // src/models/Bar.ts
984
+ var Bar = class {
985
+ constructor(options = {}) {
986
+ // used by MultiBar — not intended for direct external use
987
+ this._isManaged = false;
988
+ this._managedFinalLine = null;
989
+ this._colors = [];
990
+ this._parsedColors = [];
991
+ this._dimmedColors = [];
992
+ this._bgColors = [];
993
+ this._parsedBgColors = [];
994
+ this._colorOffset = 0;
995
+ this._shimmerPhase = 0;
996
+ this._completed = false;
997
+ this._resizeListener = null;
998
+ this._cleanupDeregister = null;
999
+ this._total = null;
1000
+ this._tickCount = 0;
1001
+ this._startTime = null;
1002
+ this._etaSuffix = "";
1003
+ this.running = false;
1004
+ this.forwardMotion = true;
1005
+ this._autoLength = options.length === void 0;
1006
+ this.length = options.length ?? process.stdout.columns ?? 80;
1007
+ this.prefixString = options.prefix ?? "[";
1008
+ this.suffixString = options.suffix ?? "]";
1009
+ this.character = options.character ?? "\u2500\u2500";
1010
+ this.beforeEmpty = options.before ?? " ";
1011
+ this.afterEmpty = options.after ?? " ";
1012
+ this.position = 1;
1013
+ this.interval = options.interval ?? 35;
1014
+ this.mode = options.mode ?? "bounce";
1015
+ this.progress = options.progress;
1016
+ this.colorFill = options.colorFill ?? false;
1017
+ this.colorCycle = options.colorCycle ?? 0.5;
1018
+ this.shimmer = options.shimmer ?? 0;
1019
+ this.text = options.text ?? "";
1020
+ this.reverse = options.reverse ?? false;
1021
+ this.onBounce = options.onBounce;
1022
+ this.onLoop = options.onLoop;
1023
+ this.onComplete = options.onComplete;
1024
+ this.colors = options.colors ?? ["#c026d3", "#e879f9"];
1025
+ this.bgColors = options.bgColors ?? [];
1026
+ this._successColor = options.successColor ?? GREEN;
1027
+ this._failColor = options.failColor ?? RED;
1028
+ this._warnColor = options.warnColor ?? YELLOW;
1029
+ this._infoColor = options.infoColor ?? BLUE;
1030
+ this._glyphs = options.glyphs ?? true;
1031
+ this._showRate = options.showRate ?? false;
1032
+ this._showEta = options.showEta ?? false;
1033
+ this._rateUnit = options.rateUnit ?? "";
342
1034
  }
343
- static setDefaults(obj) {
344
- _TermKit.commandDefaults = obj;
1035
+ get colors() {
1036
+ return this._colors;
345
1037
  }
346
- static command(name, variables, info) {
347
- const cmd = new Command(Object.assign({ name, variables, info }, _TermKit.commandDefaults));
348
- if (!_TermKit.base) _TermKit.base = cmd;
349
- return cmd;
1038
+ set colors(value) {
1039
+ this._colors = value;
1040
+ this._parsedColors = value.length > 1 ? value.map(parseHex) : [];
1041
+ this._dimmedColors = this._parsedColors.map(dimColor);
350
1042
  }
351
- static middleware(action) {
352
- return action;
1043
+ get bgColors() {
1044
+ return this._bgColors;
353
1045
  }
354
- static option(short, long, variables, info) {
355
- return new Option({ short, long, variables, info });
1046
+ set bgColors(value) {
1047
+ this._bgColors = value;
1048
+ this._parsedBgColors = value.length > 1 ? value.map(parseHex) : [];
356
1049
  }
357
- static parse(arr) {
358
- if (!_TermKit.base) throw new Error("No command defined");
359
- return _TermKit.base.parse(arr);
1050
+ set prefix(string) {
1051
+ if (stringLength(string) > stringLength(this.prefixString)) {
1052
+ this.position -= stringLength(string) - 1;
1053
+ if (this.position < 1) this.position = 1;
1054
+ } else {
1055
+ this.position += stringLength(this.prefixString) - 1;
1056
+ }
1057
+ this.prefixString = string;
1058
+ }
1059
+ set suffix(string) {
1060
+ const length = this.length - stringLength(this.prefixString) - stringLength(this.character) - stringLength(string);
1061
+ if (this.position > length) {
1062
+ this.position = length;
1063
+ if (this.forwardMotion) this.forwardMotion = false;
1064
+ }
1065
+ this.suffixString = string;
1066
+ }
1067
+ set before(string) {
1068
+ this.beforeEmpty = stringLength(string) > 1 ? string.charAt(0) : string;
1069
+ }
1070
+ set after(string) {
1071
+ this.afterEmpty = stringLength(string) > 1 ? string.charAt(0) : string;
1072
+ }
1073
+ set empty(string) {
1074
+ const char = stringLength(string) > 1 ? string.charAt(0) : string;
1075
+ this.beforeEmpty = char;
1076
+ this.afterEmpty = char;
1077
+ }
1078
+ start() {
1079
+ if (this._isManaged) return;
1080
+ if (!process.stdout.isTTY) return;
1081
+ this.running = true;
1082
+ process.stdout.write(HIDE_CURSOR);
1083
+ this._cleanupDeregister = registerCleanup(() => {
1084
+ this.running = false;
1085
+ if (this._resizeListener) {
1086
+ process.stdout.off("resize", this._resizeListener);
1087
+ this._resizeListener = null;
1088
+ }
1089
+ process.stdout.clearLine?.(0);
1090
+ process.stdout.write(SHOW_CURSOR);
1091
+ });
1092
+ if (this._autoLength) {
1093
+ this._resizeListener = () => {
1094
+ this.length = process.stdout.columns ?? 80;
1095
+ process.stdout.write("\x1B[0J");
1096
+ };
1097
+ process.stdout.on("resize", this._resizeListener);
1098
+ }
1099
+ this.run();
1100
+ }
1101
+ stop(message) {
1102
+ this.running = false;
1103
+ if (this._isManaged) {
1104
+ this._managedFinalLine = message ?? "";
1105
+ return this;
1106
+ }
1107
+ this._cleanupDeregister?.();
1108
+ this._cleanupDeregister = null;
1109
+ if (process.stdout.isTTY) {
1110
+ if (this._resizeListener) {
1111
+ process.stdout.off("resize", this._resizeListener);
1112
+ this._resizeListener = null;
1113
+ }
1114
+ this.clear();
1115
+ process.stdout.write(SHOW_CURSOR);
1116
+ }
1117
+ if (message) process.stdout.write(`${message}
1118
+ `);
1119
+ return this;
1120
+ }
1121
+ message(string) {
1122
+ this.text = string;
1123
+ return this;
1124
+ }
1125
+ track(total, options) {
1126
+ this._total = total;
1127
+ this._tickCount = 0;
1128
+ this._startTime = Date.now();
1129
+ this._etaSuffix = "";
1130
+ if (options?.unit !== void 0) this._rateUnit = options.unit;
1131
+ if (options?.showRate !== void 0) this._showRate = options.showRate;
1132
+ if (options?.showEta !== void 0) this._showEta = options.showEta;
1133
+ if (!this._showRate && !this._showEta) {
1134
+ this._showRate = true;
1135
+ this._showEta = true;
1136
+ }
1137
+ return this;
1138
+ }
1139
+ tick(n = 1) {
1140
+ this._tickCount += n;
1141
+ if (this._total !== null && this._startTime !== null) {
1142
+ this.progress = Math.min(1, this._tickCount / this._total);
1143
+ const elapsed = (Date.now() - this._startTime) / 1e3;
1144
+ const rate = elapsed > 0 ? this._tickCount / elapsed : 0;
1145
+ const remaining = this._total - this._tickCount;
1146
+ const parts = [];
1147
+ if (this._showRate) {
1148
+ const rateStr = rate >= 1e3 ? `${(rate / 1e3).toFixed(1)}k` : rate >= 1 ? rate.toFixed(1) : rate.toFixed(2);
1149
+ parts.push(`${rateStr}/s${this._rateUnit ? ` ${this._rateUnit}` : ""}`);
1150
+ }
1151
+ if (this._showEta && remaining > 0) {
1152
+ const eta = rate > 0 ? remaining / rate : 0;
1153
+ const etaStr = eta >= 3600 ? `${Math.floor(eta / 3600)}h${Math.floor(eta % 3600 / 60)}m` : eta >= 60 ? `${Math.floor(eta / 60)}m${Math.floor(eta % 60)}s` : `${Math.ceil(eta)}s`;
1154
+ parts.push(`ETA ${etaStr}`);
1155
+ }
1156
+ this._etaSuffix = parts.join(" \xB7 ");
1157
+ }
1158
+ return this;
1159
+ }
1160
+ get rate() {
1161
+ if (this._startTime === null || this._tickCount === 0) return 0;
1162
+ const elapsed = (Date.now() - this._startTime) / 1e3;
1163
+ return elapsed > 0 ? this._tickCount / elapsed : 0;
1164
+ }
1165
+ get eta() {
1166
+ if (this._total === null || this.rate === 0) return 0;
1167
+ return Math.max(0, (this._total - this._tickCount) / this.rate);
1168
+ }
1169
+ succeed(string) {
1170
+ this.running = false;
1171
+ if (this._isManaged) {
1172
+ const glyph = this._glyphs ? colorText(this._successColor, "\u2714") + " " : "";
1173
+ this._managedFinalLine = `${glyph}${string ?? ""}`;
1174
+ return this;
1175
+ }
1176
+ this._cleanupDeregister?.();
1177
+ this._cleanupDeregister = null;
1178
+ if (process.stdout.isTTY) {
1179
+ if (this._resizeListener) {
1180
+ process.stdout.off("resize", this._resizeListener);
1181
+ this._resizeListener = null;
1182
+ }
1183
+ this.clear();
1184
+ process.stdout.write(`${SHOW_CURSOR}${colorText(this._successColor, "\u2714")}${string ? ` ${string}` : ""}
1185
+ `);
1186
+ } else {
1187
+ process.stdout.write(`${this._glyphs ? `\u2714${string ? ` ${string}` : ""}` : string ?? ""}
1188
+ `);
1189
+ }
1190
+ return this;
1191
+ }
1192
+ fail(string) {
1193
+ this.running = false;
1194
+ if (this._isManaged) {
1195
+ const glyph = this._glyphs ? colorText(this._failColor, "\u2716") + " " : "";
1196
+ this._managedFinalLine = `${glyph}${string ?? ""}`;
1197
+ return this;
1198
+ }
1199
+ this._cleanupDeregister?.();
1200
+ this._cleanupDeregister = null;
1201
+ if (process.stdout.isTTY) {
1202
+ if (this._resizeListener) {
1203
+ process.stdout.off("resize", this._resizeListener);
1204
+ this._resizeListener = null;
1205
+ }
1206
+ this.clear();
1207
+ process.stdout.write(`${SHOW_CURSOR}${colorText(this._failColor, "\u2716")}${string ? ` ${string}` : ""}
1208
+ `);
1209
+ } else {
1210
+ process.stdout.write(`${this._glyphs ? `\u2716${string ? ` ${string}` : ""}` : string ?? ""}
1211
+ `);
1212
+ }
1213
+ return this;
1214
+ }
1215
+ warn(string) {
1216
+ this.running = false;
1217
+ if (this._isManaged) {
1218
+ const glyph = this._glyphs ? colorText(this._warnColor, "\u26A0") + " " : "";
1219
+ this._managedFinalLine = `${glyph}${string ?? ""}`;
1220
+ return this;
1221
+ }
1222
+ this._cleanupDeregister?.();
1223
+ this._cleanupDeregister = null;
1224
+ if (process.stdout.isTTY) {
1225
+ if (this._resizeListener) {
1226
+ process.stdout.off("resize", this._resizeListener);
1227
+ this._resizeListener = null;
1228
+ }
1229
+ this.clear();
1230
+ process.stdout.write(`${SHOW_CURSOR}${colorText(this._warnColor, "\u26A0")}${string ? ` ${string}` : ""}
1231
+ `);
1232
+ } else {
1233
+ process.stdout.write(`${this._glyphs ? `\u26A0${string ? ` ${string}` : ""}` : string ?? ""}
1234
+ `);
1235
+ }
1236
+ return this;
1237
+ }
1238
+ info(string) {
1239
+ this.running = false;
1240
+ if (this._isManaged) {
1241
+ const glyph = this._glyphs ? colorText(this._infoColor, "\u2139") + " " : "";
1242
+ this._managedFinalLine = `${glyph}${string ?? ""}`;
1243
+ return this;
1244
+ }
1245
+ this._cleanupDeregister?.();
1246
+ this._cleanupDeregister = null;
1247
+ if (process.stdout.isTTY) {
1248
+ if (this._resizeListener) {
1249
+ process.stdout.off("resize", this._resizeListener);
1250
+ this._resizeListener = null;
1251
+ }
1252
+ this.clear();
1253
+ process.stdout.write(`${SHOW_CURSOR}${colorText(this._infoColor, "\u2139")}${string ? ` ${string}` : ""}
1254
+ `);
1255
+ } else {
1256
+ process.stdout.write(`${this._glyphs ? `\u2139${string ? ` ${string}` : ""}` : string ?? ""}
1257
+ `);
1258
+ }
1259
+ return this;
1260
+ }
1261
+ // Returns the rendered bar line string for the current animation frame.
1262
+ // width overrides this.length for use by MultiBar.
1263
+ renderLine(width) {
1264
+ return this.buildLine(width);
1265
+ }
1266
+ // Advances animation state (color cycle, shimmer, indeterminate position).
1267
+ // Called by MultiBar after reading renderLine() each tick.
1268
+ advanceFrame() {
1269
+ const totalLength = this.length;
1270
+ const textReserved = this.text ? stringLength(this.text) + 1 : 0;
1271
+ const suffixReserved = this._etaSuffix ? stringLength(this._etaSuffix) + 1 : 0;
1272
+ const length = Math.max(1, totalLength - textReserved - suffixReserved - stringLength(this.prefixString) - stringLength(this.character) - stringLength(this.suffixString));
1273
+ if (this.progress === void 0) this.advanceIndeterminate(length);
1274
+ if (this.colorCycle > 0) this._colorOffset = (this._colorOffset + this.colorCycle * this.interval / 1e3) % 1;
1275
+ if (this.shimmer > 0) this._shimmerPhase = (this._shimmerPhase + SHIMMER_SPEED * this.interval / 1e3) % 1;
1276
+ }
1277
+ clear() {
1278
+ process.stdout.clearLine?.(0);
1279
+ }
1280
+ effectiveT(t) {
1281
+ if (this.colorCycle === 0) return t;
1282
+ return ((t + this._colorOffset) % 1 + 1) % 1;
1283
+ }
1284
+ coloredChar(colors, code, t) {
1285
+ const et = this.effectiveT(t);
1286
+ const base2 = interpolateColor(colors, et);
1287
+ const shimmered = applyShimmer(base2, t, this._shimmerPhase, this.shimmer);
1288
+ return formatColor(code, shimmered);
1289
+ }
1290
+ colorChar(t) {
1291
+ const fg = this._parsedColors.length >= 2 ? this.coloredChar(this._parsedColors, 38, t) : "";
1292
+ const bg = this._parsedBgColors.length >= 2 ? this.coloredChar(this._parsedBgColors, 48, t) : "";
1293
+ return fg || bg ? fg + bg + this.character + RESET : this.character;
1294
+ }
1295
+ colorFillChar(char, t) {
1296
+ const fg = this.colorFill && this._dimmedColors.length >= 2 ? this.coloredChar(this._dimmedColors, 38, t) : "";
1297
+ const bg = this._parsedBgColors.length >= 2 ? this.coloredChar(this._parsedBgColors, 48, t) : "";
1298
+ return fg || bg ? fg + bg + char + RESET : char;
1299
+ }
1300
+ buildDeterminate(length) {
1301
+ const charWidth = stringLength(this.character);
1302
+ const clamped = Math.max(0, Math.min(1, this.progress));
1303
+ const filled = Math.round(clamped * length);
1304
+ let working = this.prefixString;
1305
+ for (let i = 0; i < filled; i++) {
1306
+ const t = length > 1 ? i / (length - 1) : 0;
1307
+ working += this.colorChar(t);
1308
+ }
1309
+ for (let i = filled; i < length; i++) {
1310
+ const t = length > 1 ? i / (length - 1) : 0;
1311
+ for (let j = 0; j < charWidth; j++) {
1312
+ working += this.colorFillChar(this.afterEmpty, t);
1313
+ }
1314
+ }
1315
+ working += this.suffixString;
1316
+ if (clamped >= 1 && !this._completed) {
1317
+ this._completed = true;
1318
+ this.onComplete?.();
1319
+ } else if (clamped < 1) {
1320
+ this._completed = false;
1321
+ }
1322
+ return working;
1323
+ }
1324
+ buildIndeterminate(length) {
1325
+ const pos = Math.max(1, Math.min(length, this.position));
1326
+ let working = this.prefixString;
1327
+ let i = 1;
1328
+ while (i < pos) {
1329
+ const t = length > 1 ? (i - 1) / (length - 1) : 0;
1330
+ working += this.colorFillChar(this.beforeEmpty, t);
1331
+ i++;
1332
+ }
1333
+ const charT = length > 1 ? (pos - 1) / (length - 1) : 0;
1334
+ working += this.colorChar(charT);
1335
+ i++;
1336
+ while (i <= length) {
1337
+ const t = length > 1 ? (i - 1) / (length - 1) : 0;
1338
+ working += this.colorFillChar(this.afterEmpty, t);
1339
+ i++;
1340
+ }
1341
+ working += this.suffixString;
1342
+ return working;
1343
+ }
1344
+ advanceIndeterminate(length) {
1345
+ if (this.position > length) {
1346
+ this.position = length;
1347
+ this.forwardMotion = false;
1348
+ }
1349
+ if (this.position < 1) {
1350
+ this.position = 1;
1351
+ this.forwardMotion = true;
1352
+ }
1353
+ if (this.mode === "loop") {
1354
+ this.position++;
1355
+ if (this.position > length) {
1356
+ this.position = 1;
1357
+ this.onLoop?.();
1358
+ }
1359
+ } else if (this.mode === "loop-reverse") {
1360
+ this.position--;
1361
+ if (this.position < 1) {
1362
+ this.position = length;
1363
+ this.onLoop?.();
1364
+ }
1365
+ } else {
1366
+ if (this.forwardMotion) {
1367
+ this.position++;
1368
+ if (this.position >= length) {
1369
+ this.forwardMotion = false;
1370
+ this.onBounce?.();
1371
+ }
1372
+ } else {
1373
+ this.position--;
1374
+ if (this.position <= 1) {
1375
+ this.forwardMotion = true;
1376
+ this.onBounce?.();
1377
+ }
1378
+ }
1379
+ }
1380
+ }
1381
+ buildLine(width) {
1382
+ const totalLength = width ?? this.length;
1383
+ const charWidth = stringLength(this.character);
1384
+ const textReserved = this.text ? stringLength(this.text) + 1 : 0;
1385
+ const suffixReserved = this._etaSuffix ? stringLength(this._etaSuffix) + 1 : 0;
1386
+ const available = totalLength - textReserved - suffixReserved - stringLength(this.prefixString) - stringLength(this.suffixString);
1387
+ const length = this.progress !== void 0 ? (
1388
+ // Determinate: every position (filled or empty) is charWidth wide → constant bar width
1389
+ Math.max(1, Math.floor((available - 1) / charWidth))
1390
+ ) : (
1391
+ // Indeterminate: one position uses character, rest use 1-char fill (unchanged formula)
1392
+ Math.max(1, available - charWidth)
1393
+ );
1394
+ const working = this.progress !== void 0 ? this.buildDeterminate(length) : this.buildIndeterminate(length);
1395
+ const t = this.text;
1396
+ const suffix = this._etaSuffix ? ` ${this._etaSuffix}` : "";
1397
+ return this.reverse ? t ? `${t} ${working}` : working : t ? `${working} ${t}${suffix}` : `${working}${suffix}`;
1398
+ }
1399
+ run() {
1400
+ process.stdout.write(`${this.buildLine()}\x1B[K\r`);
1401
+ this.advanceFrame();
1402
+ setTimeout(() => {
1403
+ if (this.running) this.run();
1404
+ }, this.interval);
1405
+ }
1406
+ };
1407
+ Bar.COLORS = {
1408
+ blueRed: ["#0000ff", "#ff0000"],
1409
+ redBlue: ["#ff0000", "#0000ff"],
1410
+ rainbow: ["#ff0000", "#ff7f00", "#ffff00", "#00ff00", "#0000ff", "#8b00ff"],
1411
+ heat: ["#0000ff", "#00ffff", "#ffff00", "#ff0000"],
1412
+ cool: ["#00ffff", "#0000ff", "#8b00ff"],
1413
+ sunset: ["#8b00ff", "#ff0000", "#ff7f00"]
1414
+ };
1415
+
1416
+ // src/models/Chart.ts
1417
+ var Chart_exports = {};
1418
+ __export(Chart_exports, {
1419
+ Bar: () => Bar2,
1420
+ Heatmap: () => Heatmap,
1421
+ Line: () => Line,
1422
+ Scatter: () => Scatter,
1423
+ Sparkline: () => Sparkline,
1424
+ VerticalBar: () => VerticalBar
1425
+ });
1426
+ import Color from "cosmetic";
1427
+
1428
+ // src/utils/padLeft.ts
1429
+ var padLeft = (string, padding) => {
1430
+ while (stringLength(string) < padding) string = ` ${string}`;
1431
+ return string;
1432
+ };
1433
+
1434
+ // src/utils/padRight.ts
1435
+ var padRight = (string, padding) => {
1436
+ while (stringLength(string) < padding) string += " ";
1437
+ return string;
1438
+ };
1439
+
1440
+ // src/models/Chart.ts
1441
+ function formatNum(n) {
1442
+ if (Number.isInteger(n)) return String(n);
1443
+ return parseFloat(n.toFixed(2)).toString();
1444
+ }
1445
+ function applyConfigColor(s) {
1446
+ const c = config.color;
1447
+ if (typeof c === "number") return Color.xterm(c).encoder(s);
1448
+ if (c.startsWith("#")) return Color.hex(c).encoder(s);
1449
+ return Color[c].encoder(s);
1450
+ }
1451
+ function applyPadding(str, paddingX, paddingY) {
1452
+ const lines = str.split("\n");
1453
+ if (lines[lines.length - 1] === "") lines.pop();
1454
+ const indented = lines.map((l) => " ".repeat(paddingX) + l).join("\n") + "\n";
1455
+ return "\n".repeat(paddingY) + indented + "\n".repeat(paddingY);
1456
+ }
1457
+ var BLOCKS = [" ", "\u2581", "\u2582", "\u2583", "\u2584", "\u2585", "\u2586", "\u2587", "\u2588"];
1458
+ var Bar2 = class {
1459
+ constructor(data, options = {}) {
1460
+ this.string = "";
1461
+ const paddingX = options.paddingX ?? 0;
1462
+ const paddingY = options.paddingY ?? 0;
1463
+ let maxKeyLen = 0;
1464
+ let maxValue = 0;
1465
+ let maxValueLen = 0;
1466
+ for (const item of data) {
1467
+ if (!item) continue;
1468
+ if (item.key) maxKeyLen = Math.max(maxKeyLen, stringLength(item.key));
1469
+ maxValue = Math.max(maxValue, item.value);
1470
+ maxValueLen = Math.max(maxValueLen, String(item.value).length);
1471
+ }
1472
+ const cols = options.width ?? process.stdout.columns ?? 80;
1473
+ const available = cols - maxKeyLen - maxValueLen - 3;
1474
+ const scale = maxValue > 0 && available > 0 ? available / maxValue : 0;
1475
+ const encodeKey = (s) => typeof config.color === "number" ? Color.xterm(config.color).encoder(s) : config.color.startsWith("#") ? Color.hex(config.color).encoder(s) : Color[config.color].encoder(s);
1476
+ for (const item of data) {
1477
+ if (!item) {
1478
+ this.string += "\n";
1479
+ continue;
1480
+ }
1481
+ const rawKey = item.key ?? "";
1482
+ const keyPart = (rawKey ? encodeKey(rawKey) : "") + " ".repeat(maxKeyLen - stringLength(rawKey));
1483
+ const barWidth = Math.max(1, Math.floor(item.value * scale));
1484
+ let bar = (item.character ?? " ").repeat(barWidth);
1485
+ bar = item.style ? item.style(bar) : Color.background.white.encoder(bar);
1486
+ this.string += `${keyPart}|${bar} ${item.value}
1487
+ `;
1488
+ }
1489
+ if (paddingX > 0 || paddingY > 0) this.string = applyPadding(this.string, paddingX, paddingY);
1490
+ }
1491
+ print() {
1492
+ process.stdout.write(this.string);
1493
+ }
1494
+ toString() {
1495
+ return this.string;
1496
+ }
1497
+ };
1498
+ var VerticalBar = class {
1499
+ constructor(data, options = {}) {
1500
+ this.string = "";
1501
+ const paddingX = options.paddingX ?? 0;
1502
+ const paddingY = options.paddingY ?? 0;
1503
+ const height = options.height ?? 10;
1504
+ const colWidth = options.colWidth ?? (options.width ? Math.max(1, Math.floor(options.width / data.length)) : 2);
1505
+ let maxValue = 0;
1506
+ for (const item of data) {
1507
+ if (item) maxValue = Math.max(maxValue, item.value);
1508
+ }
1509
+ for (let row = height; row >= 1; row--) {
1510
+ let line = "";
1511
+ for (const item of data) {
1512
+ if (!item) {
1513
+ line += " ".repeat(colWidth);
1514
+ continue;
1515
+ }
1516
+ const barHeight = maxValue > 0 ? item.value / maxValue * height : 0;
1517
+ const full = Math.floor(barHeight);
1518
+ const frac = barHeight - full;
1519
+ let chars;
1520
+ if (row <= full) {
1521
+ chars = "\u2588".repeat(colWidth);
1522
+ } else if (row === full + 1 && frac > 0) {
1523
+ chars = (BLOCKS[Math.round(frac * 8)] ?? " ").repeat(colWidth);
1524
+ } else {
1525
+ chars = " ".repeat(colWidth);
1526
+ }
1527
+ if (item.style && chars.trim()) chars = item.style(chars);
1528
+ line += chars;
1529
+ }
1530
+ this.string += line + "\n";
1531
+ }
1532
+ this.string += "\u2500".repeat(data.length * colWidth) + "\n";
1533
+ if (data.some((item) => item?.key)) {
1534
+ const encodeLabel = (s) => typeof config.color === "number" ? Color.xterm(config.color).encoder(s) : config.color.startsWith("#") ? Color.hex(config.color).encoder(s) : Color[config.color].encoder(s);
1535
+ let labels = "";
1536
+ for (const item of data) {
1537
+ if (!item?.key) {
1538
+ labels += " ".repeat(colWidth);
1539
+ } else {
1540
+ const key = item.key.length > colWidth ? item.key.slice(0, colWidth) : item.key;
1541
+ labels += encodeLabel(key) + " ".repeat(colWidth - key.length);
1542
+ }
1543
+ }
1544
+ this.string += labels + "\n";
1545
+ }
1546
+ if (paddingX > 0 || paddingY > 0) this.string = applyPadding(this.string, paddingX, paddingY);
1547
+ }
1548
+ print() {
1549
+ process.stdout.write(this.string);
1550
+ }
1551
+ toString() {
1552
+ return this.string;
1553
+ }
1554
+ };
1555
+ var Heatmap = class {
1556
+ constructor(data, options = {}) {
1557
+ this.string = "";
1558
+ const paddingX = options.paddingX ?? 0;
1559
+ const paddingY = options.paddingY ?? 0;
1560
+ const cellWidth = options.cellWidth ?? 2;
1561
+ const parsedColors = (options.colors ?? ["#0000ff", "#ff0000"]).map(parseHex);
1562
+ let min = options.min;
1563
+ let max = options.max;
1564
+ for (const row of data) {
1565
+ for (const val of row) {
1566
+ if (min === void 0 || val < min) min = val;
1567
+ if (max === void 0 || val > max) max = val;
1568
+ }
1569
+ }
1570
+ const lo = min ?? 0;
1571
+ const hi = max ?? 1;
1572
+ const range = hi - lo || 1;
1573
+ const rowLabelWidth = options.rowLabels ? Math.max(...options.rowLabels.map((l) => stringLength(l))) + 1 : 0;
1574
+ if (options.colLabels) {
1575
+ this.string += " ".repeat(rowLabelWidth);
1576
+ for (const label of options.colLabels) {
1577
+ this.string += label.length > cellWidth ? label.slice(0, cellWidth) : label.padEnd(cellWidth);
1578
+ }
1579
+ this.string += "\n";
1580
+ }
1581
+ for (let r = 0; r < data.length; r++) {
1582
+ if (options.rowLabels) {
1583
+ this.string += padRight(options.rowLabels[r] ?? "", rowLabelWidth - 1) + " ";
1584
+ }
1585
+ for (const val of data[r]) {
1586
+ const t = (val - lo) / range;
1587
+ const color = interpolateColor(parsedColors, t);
1588
+ this.string += `${formatColor(48, color)}${" ".repeat(cellWidth)}${RESET}`;
1589
+ }
1590
+ this.string += "\n";
1591
+ }
1592
+ if (paddingX > 0 || paddingY > 0) this.string = applyPadding(this.string, paddingX, paddingY);
1593
+ }
1594
+ print() {
1595
+ process.stdout.write(this.string);
1596
+ }
1597
+ toString() {
1598
+ return this.string;
1599
+ }
1600
+ };
1601
+ var Scatter = class {
1602
+ constructor(data, options = {}) {
1603
+ this.string = "";
1604
+ const paddingX = options.paddingX ?? 0;
1605
+ const paddingY = options.paddingY ?? 0;
1606
+ const defaultChar = options.character ?? "\u2022";
1607
+ const showAxes = options.axes ?? true;
1608
+ let xMin = options.xMin ?? (data.length ? Math.min(...data.map((p) => p.x)) : 0);
1609
+ let xMax = options.xMax ?? (data.length ? Math.max(...data.map((p) => p.x)) : 1);
1610
+ let yMin = options.yMin ?? (data.length ? Math.min(...data.map((p) => p.y)) : 0);
1611
+ let yMax = options.yMax ?? (data.length ? Math.max(...data.map((p) => p.y)) : 1);
1612
+ if (xMin === xMax) {
1613
+ xMin -= 1;
1614
+ xMax += 1;
1615
+ }
1616
+ if (yMin === yMax) {
1617
+ yMin -= 1;
1618
+ yMax += 1;
1619
+ }
1620
+ const totalWidth = options.width ?? process.stdout.columns ?? 80;
1621
+ const totalHeight = options.height ?? 20;
1622
+ const plotWidth = showAxes ? Math.max(1, totalWidth - Math.max(formatNum(yMax).length, formatNum(yMin).length, formatNum((yMin + yMax) / 2).length) - 1) : totalWidth;
1623
+ const plotHeight = showAxes ? Math.max(1, totalHeight - 2) : totalHeight;
1624
+ const grid = Array.from({ length: plotHeight }, () => Array(plotWidth).fill(" "));
1625
+ for (const point of data) {
1626
+ const col = Math.round((point.x - xMin) / (xMax - xMin) * (plotWidth - 1));
1627
+ const row = plotHeight - 1 - Math.round((point.y - yMin) / (yMax - yMin) * (plotHeight - 1));
1628
+ if (col >= 0 && col < plotWidth && row >= 0 && row < plotHeight) {
1629
+ const char = point.character ?? defaultChar;
1630
+ grid[row][col] = point.style ? point.style(char) : char;
1631
+ }
1632
+ }
1633
+ if (showAxes) {
1634
+ const yAxisWidth = Math.max(formatNum(yMax).length, formatNum(yMin).length, formatNum((yMin + yMax) / 2).length);
1635
+ const midRow = Math.floor((plotHeight - 1) / 2);
1636
+ for (let r = 0; r < plotHeight; r++) {
1637
+ let yLabel = "";
1638
+ if (r === 0) yLabel = formatNum(yMax);
1639
+ else if (r === midRow) yLabel = formatNum((yMin + yMax) / 2);
1640
+ else if (r === plotHeight - 1) yLabel = formatNum(yMin);
1641
+ const coloredLabel = yLabel ? applyConfigColor(yLabel) : "";
1642
+ this.string += padLeft(coloredLabel, yAxisWidth) + "\u2502" + grid[r].join("") + "\n";
1643
+ }
1644
+ this.string += " ".repeat(yAxisWidth) + "\u2514" + "\u2500".repeat(plotWidth) + "\n";
1645
+ const xMinRaw = formatNum(xMin);
1646
+ const xMidRaw = formatNum((xMin + xMax) / 2);
1647
+ const xMaxRaw = formatNum(xMax);
1648
+ const midCol = Math.floor(plotWidth / 2) - Math.floor(xMidRaw.length / 2);
1649
+ const gap1 = Math.max(0, midCol - xMinRaw.length);
1650
+ const gap2 = Math.max(0, plotWidth - xMinRaw.length - gap1 - xMidRaw.length - xMaxRaw.length);
1651
+ this.string += " ".repeat(yAxisWidth + 1) + applyConfigColor(xMinRaw) + " ".repeat(gap1) + applyConfigColor(xMidRaw) + " ".repeat(gap2) + applyConfigColor(xMaxRaw) + "\n";
1652
+ } else {
1653
+ for (const row of grid) {
1654
+ this.string += row.join("") + "\n";
1655
+ }
1656
+ }
1657
+ if (paddingX > 0 || paddingY > 0) this.string = applyPadding(this.string, paddingX, paddingY);
1658
+ }
1659
+ print() {
1660
+ process.stdout.write(this.string);
1661
+ }
1662
+ toString() {
1663
+ return this.string;
1664
+ }
1665
+ };
1666
+ var Line = class {
1667
+ constructor(data, options = {}) {
1668
+ this.string = "";
1669
+ const paddingX = options.paddingX ?? 0;
1670
+ const paddingY = options.paddingY ?? 0;
1671
+ const defaultChar = options.character ?? "\u2022";
1672
+ const showAxes = options.axes ?? true;
1673
+ const fill = options.fill ?? false;
1674
+ let xMin = options.xMin ?? (data.length ? Math.min(...data.map((p) => p.x)) : 0);
1675
+ let xMax = options.xMax ?? (data.length ? Math.max(...data.map((p) => p.x)) : 1);
1676
+ let yMin = options.yMin ?? (data.length ? Math.min(...data.map((p) => p.y)) : 0);
1677
+ let yMax = options.yMax ?? (data.length ? Math.max(...data.map((p) => p.y)) : 1);
1678
+ if (xMin === xMax) {
1679
+ xMin -= 1;
1680
+ xMax += 1;
1681
+ }
1682
+ if (yMin === yMax) {
1683
+ yMin -= 1;
1684
+ yMax += 1;
1685
+ }
1686
+ const totalWidth = options.width ?? process.stdout.columns ?? 80;
1687
+ const totalHeight = options.height ?? 20;
1688
+ const yAxisWidth = showAxes ? Math.max(formatNum(yMax).length, formatNum(yMin).length, formatNum((yMin + yMax) / 2).length) : 0;
1689
+ const plotWidth = showAxes ? Math.max(1, totalWidth - yAxisWidth - 1) : totalWidth;
1690
+ const plotHeight = showAxes ? Math.max(1, totalHeight - 2) : totalHeight;
1691
+ const grid = Array.from({ length: plotHeight }, () => Array(plotWidth).fill(" "));
1692
+ const sorted = [...data].sort((a, b) => a.x - b.x);
1693
+ const xRange = xMax - xMin;
1694
+ const yRange = yMax - yMin;
1695
+ for (let col = 0; col < plotWidth; col++) {
1696
+ const xVal = xMin + col / Math.max(1, plotWidth - 1) * xRange;
1697
+ let yVal = null;
1698
+ let pointStyle;
1699
+ for (let pi = 0; pi < sorted.length; pi++) {
1700
+ const p = sorted[pi];
1701
+ const next = sorted[pi + 1];
1702
+ if (next === void 0) {
1703
+ if (Math.abs(p.x - xVal) <= xRange / plotWidth) {
1704
+ yVal = p.y;
1705
+ pointStyle = p.style;
1706
+ }
1707
+ break;
1708
+ }
1709
+ if (p.x <= xVal && next.x >= xVal) {
1710
+ const t = next.x === p.x ? 0 : (xVal - p.x) / (next.x - p.x);
1711
+ yVal = p.y + t * (next.y - p.y);
1712
+ if (t < 0.5 && p.style) pointStyle = p.style;
1713
+ else if (t >= 0.5 && next.style) pointStyle = next.style;
1714
+ break;
1715
+ }
1716
+ }
1717
+ if (yVal !== null) {
1718
+ const row = Math.round((1 - (yVal - yMin) / yRange) * (plotHeight - 1));
1719
+ const clampedRow = Math.max(0, Math.min(plotHeight - 1, row));
1720
+ const char = defaultChar;
1721
+ grid[clampedRow][col] = pointStyle ? pointStyle(char) : char;
1722
+ if (fill) {
1723
+ for (let r = clampedRow + 1; r < plotHeight; r++) {
1724
+ if (grid[r][col] === " ") grid[r][col] = "\u2591";
1725
+ }
1726
+ }
1727
+ }
1728
+ }
1729
+ if (showAxes) {
1730
+ const midRow = Math.floor((plotHeight - 1) / 2);
1731
+ for (let r = 0; r < plotHeight; r++) {
1732
+ let yLabel = "";
1733
+ if (r === 0) yLabel = formatNum(yMax);
1734
+ else if (r === midRow) yLabel = formatNum((yMin + yMax) / 2);
1735
+ else if (r === plotHeight - 1) yLabel = formatNum(yMin);
1736
+ const coloredLabel = yLabel ? applyConfigColor(yLabel) : "";
1737
+ this.string += padLeft(coloredLabel, yAxisWidth) + "\u2502" + grid[r].join("") + "\n";
1738
+ }
1739
+ this.string += " ".repeat(yAxisWidth) + "\u2514" + "\u2500".repeat(plotWidth) + "\n";
1740
+ const xMinRaw = formatNum(xMin);
1741
+ const xMidRaw = formatNum((xMin + xMax) / 2);
1742
+ const xMaxRaw = formatNum(xMax);
1743
+ const midCol = Math.floor(plotWidth / 2) - Math.floor(xMidRaw.length / 2);
1744
+ const gap1 = Math.max(0, midCol - xMinRaw.length);
1745
+ const gap2 = Math.max(0, plotWidth - xMinRaw.length - gap1 - xMidRaw.length - xMaxRaw.length);
1746
+ this.string += " ".repeat(yAxisWidth + 1) + applyConfigColor(xMinRaw) + " ".repeat(gap1) + applyConfigColor(xMidRaw) + " ".repeat(gap2) + applyConfigColor(xMaxRaw) + "\n";
1747
+ } else {
1748
+ for (const row of grid) {
1749
+ this.string += row.join("") + "\n";
1750
+ }
1751
+ }
1752
+ if (paddingX > 0 || paddingY > 0) this.string = applyPadding(this.string, paddingX, paddingY);
1753
+ }
1754
+ print() {
1755
+ process.stdout.write(this.string);
1756
+ }
1757
+ toString() {
1758
+ return this.string;
1759
+ }
1760
+ };
1761
+ function Sparkline(data, options = {}) {
1762
+ const lo = options.min ?? Math.min(...data);
1763
+ const hi = options.max ?? Math.max(...data);
1764
+ const range = hi === lo ? 1 : hi - lo;
1765
+ const chars = data.map((v) => {
1766
+ const idx = Math.min(8, Math.round(Math.max(0, Math.min(1, (v - lo) / range)) * 8));
1767
+ return BLOCKS[idx] ?? "\u2588";
1768
+ }).join("");
1769
+ return options.style ? options.style(chars) : chars;
1770
+ }
1771
+
1772
+ // src/models/Column.ts
1773
+ var Column = class {
1774
+ constructor(data) {
1775
+ if (typeof data === "string") data = { key: data };
1776
+ this.key = data.key ?? "";
1777
+ this.title = data.title ?? this.key;
1778
+ this.padding = data.padding ?? 0;
1779
+ this.align = data.align;
1780
+ this.hidden = data.hidden;
1781
+ if (stringLength(this.title) > this.padding) this.padding = stringLength(this.title);
1782
+ if (data.minimumPadding && data.minimumPadding > this.padding) this.padding = data.minimumPadding;
1783
+ this.value = data.value ?? ((v) => v == null ? "" : String(v));
1784
+ }
1785
+ };
1786
+
1787
+ // src/models/Markup.ts
1788
+ var TAB = " ";
1789
+ function markup(data, options = {}) {
1790
+ const translations = options.translations ?? {};
1791
+ const styles = {
1792
+ date: options.styles?.date ?? ((v) => colorText(MAGENTA, v)),
1793
+ null: options.styles?.null ?? ((v) => colorText(BOLD, v)),
1794
+ undefined: options.styles?.undefined ?? ((v) => colorText(FAINT, v)),
1795
+ number: options.styles?.number ?? ((v) => colorText(YELLOW, v)),
1796
+ bigint: options.styles?.bigint ?? ((v) => colorText(YELLOW, v)),
1797
+ boolean: options.styles?.boolean ?? ((v) => colorText(CYAN, v)),
1798
+ string: options.styles?.string ?? ((v) => colorText(GREEN, v)),
1799
+ symbol: options.styles?.symbol ?? ((v) => colorText(BLUE, v))
1800
+ };
1801
+ let result = "";
1802
+ function formatPrimitive(value) {
1803
+ if (value instanceof Date) return styles.date(String(value));
1804
+ if (value === null) return styles.null("null");
1805
+ if (value === void 0) return styles.undefined("undefined");
1806
+ if (typeof value === "number") return styles.number(String(value));
1807
+ if (typeof value === "bigint") return styles.bigint(String(value));
1808
+ if (typeof value === "boolean") return styles.boolean(String(value));
1809
+ if (typeof value === "string") return styles.string(value);
1810
+ if (typeof value === "symbol") return styles.symbol(String(value));
1811
+ return String(value);
1812
+ }
1813
+ function isPrimitive(value) {
1814
+ return !Array.isArray(value) && (value === null || value === void 0 || typeof value !== "object" || value instanceof Date);
1815
+ }
1816
+ function isPlainObject(value) {
1817
+ return typeof value === "object" && value !== null && !Array.isArray(value) && !(value instanceof Date);
1818
+ }
1819
+ function formatObjectContents(obj, pad) {
1820
+ const keys = Object.keys(obj);
1821
+ for (const [i, key] of keys.entries()) {
1822
+ result += `${pad}${TAB}${key}: `;
1823
+ let val = obj[key];
1824
+ if (translations[key]) val = translations[key](val);
1825
+ if (typeof val === "object" && val !== null) {
1826
+ format(val, `${pad}${TAB}`);
1827
+ } else {
1828
+ format(val, "");
1829
+ }
1830
+ result += i === keys.length - 1 ? "\n" : ",\n";
1831
+ }
1832
+ }
1833
+ function format(value, pad) {
1834
+ if (Array.isArray(value)) {
1835
+ if (value.length === 0) {
1836
+ result += result.endsWith(": ") ? "[]" : `${pad}[]`;
1837
+ } else if (value.every(isPrimitive)) {
1838
+ const inline = `[${value.map(formatPrimitive).join(", ")}]`;
1839
+ result += result.endsWith(": ") ? inline : `${pad}${inline}`;
1840
+ } else if (value.every(isPlainObject)) {
1841
+ const prefix = result.endsWith(": ") ? "" : pad;
1842
+ for (const [i, item] of value.entries()) {
1843
+ result += i === 0 ? `${prefix}[{
1844
+ ` : `${pad}},{
1845
+ `;
1846
+ formatObjectContents(item, pad);
1847
+ }
1848
+ result += `${pad}}]`;
1849
+ } else {
1850
+ result += result.endsWith(": ") ? "[" : `${pad}[`;
1851
+ result += "\n";
1852
+ for (const [i, item] of value.entries()) {
1853
+ format(item, `${pad}${TAB}`);
1854
+ result += i === value.length - 1 ? "\n" : ",\n";
1855
+ }
1856
+ result += `${pad}]`;
1857
+ }
1858
+ } else if (value instanceof Date) {
1859
+ result += styles.date(String(value));
1860
+ } else if (value === null) {
1861
+ result += styles.null("null");
1862
+ } else if (value === void 0) {
1863
+ result += styles.undefined("undefined");
1864
+ } else if (isPlainObject(value)) {
1865
+ result += result.endsWith(": ") ? "{" : `${pad}{`;
1866
+ const keys = Object.keys(value);
1867
+ if (keys.length === 0) {
1868
+ result += "}";
1869
+ } else {
1870
+ result += "\n";
1871
+ formatObjectContents(value, pad);
1872
+ result += `${pad}}`;
1873
+ }
1874
+ } else if (typeof value === "number") {
1875
+ result += styles.number(`${pad}${value}`);
1876
+ } else if (typeof value === "bigint") {
1877
+ result += styles.bigint(`${pad}${value}`);
1878
+ } else if (typeof value === "boolean") {
1879
+ result += styles.boolean(String(value));
1880
+ } else if (typeof value === "string") {
1881
+ result += styles.string(`${pad}${value}`);
1882
+ } else if (typeof value === "symbol") {
1883
+ result += styles.symbol(String(value));
1884
+ }
1885
+ }
1886
+ format(data, "");
1887
+ return result;
1888
+ }
1889
+
1890
+ // src/models/Log.ts
1891
+ var Log = class {
1892
+ constructor(options = {}) {
1893
+ this._successColor = options.successColor ?? GREEN;
1894
+ this._failColor = options.failColor ?? RED;
1895
+ this._warnColor = options.warnColor ?? YELLOW;
1896
+ this._infoColor = options.infoColor ?? BLUE;
1897
+ this._glyphs = options.glyphs ?? true;
1898
+ }
1899
+ write(glyph, color, message) {
1900
+ if (process.stdout.isTTY) {
1901
+ process.stdout.write(`${colorText(color, glyph)}${message ? ` ${message}` : ""}
1902
+ `);
1903
+ } else {
1904
+ process.stdout.write(`${this._glyphs ? `${glyph}${message ? ` ${message}` : ""}` : message ?? ""}
1905
+ `);
1906
+ }
1907
+ }
1908
+ succeed(message) {
1909
+ this.write("\u2714", this._successColor, message);
1910
+ }
1911
+ fail(message) {
1912
+ this.write("\u2716", this._failColor, message);
1913
+ }
1914
+ warn(message) {
1915
+ this.write("\u26A0", this._warnColor, message);
1916
+ }
1917
+ info(message) {
1918
+ this.write("\u2139", this._infoColor, message);
1919
+ }
1920
+ data(value, options) {
1921
+ process.stdout.write(`${markup(value, options)}
1922
+ `);
1923
+ }
1924
+ };
1925
+ var log = new Log();
1926
+
1927
+ // src/models/MultiBar.ts
1928
+ var CURSOR_UP2 = (n) => `\x1B[${n}A`;
1929
+ var MultiBar = class {
1930
+ constructor(options = {}) {
1931
+ this._bars = [];
1932
+ this._running = false;
1933
+ this._linesWritten = 0;
1934
+ this._cleanupDeregister = null;
1935
+ this._interval = options.interval ?? 35;
1936
+ }
1937
+ // Add a bar to the group. Must be called before start().
1938
+ // Returns the Bar instance — use .message(), .progress, .tick(), .succeed(), etc.
1939
+ add(options = {}) {
1940
+ const bar = new Bar(options);
1941
+ bar._isManaged = true;
1942
+ this._bars.push(bar);
1943
+ return bar;
1944
+ }
1945
+ start() {
1946
+ if (!process.stdout.isTTY) return;
1947
+ this._running = true;
1948
+ this._linesWritten = 0;
1949
+ process.stdout.write(HIDE_CURSOR);
1950
+ this._cleanupDeregister = registerCleanup(() => {
1951
+ this._running = false;
1952
+ if (this._linesWritten > 0) process.stdout.write(CURSOR_UP2(this._linesWritten));
1953
+ process.stdout.write("\x1B[0J");
1954
+ process.stdout.write(SHOW_CURSOR);
1955
+ });
1956
+ this.render();
1957
+ }
1958
+ stop() {
1959
+ this._running = false;
1960
+ this._cleanupDeregister?.();
1961
+ this._cleanupDeregister = null;
1962
+ if (process.stdout.isTTY) process.stdout.write(SHOW_CURSOR);
1963
+ }
1964
+ render() {
1965
+ const width = Math.max(20, (process.stdout.columns ?? 80) - 1);
1966
+ if (this._linesWritten > 0) {
1967
+ process.stdout.write(CURSOR_UP2(this._linesWritten));
1968
+ }
1969
+ for (const bar of this._bars) {
1970
+ if (bar._managedFinalLine !== null) {
1971
+ process.stdout.write(`\r${bar._managedFinalLine}\x1B[K
1972
+ `);
1973
+ } else {
1974
+ process.stdout.write(`\r${bar.renderLine(width)}\x1B[K
1975
+ `);
1976
+ bar.advanceFrame();
1977
+ }
1978
+ }
1979
+ this._linesWritten = this._bars.length;
1980
+ if (!this._running) return;
1981
+ if (this._bars.every((b) => b._managedFinalLine !== null)) {
1982
+ this._running = false;
1983
+ this._cleanupDeregister?.();
1984
+ this._cleanupDeregister = null;
1985
+ process.stdout.write(SHOW_CURSOR);
1986
+ return;
1987
+ }
1988
+ setTimeout(() => {
1989
+ if (this._running) this.render();
1990
+ }, this._interval);
1991
+ }
1992
+ };
1993
+
1994
+ // src/models/MultiSelect.ts
1995
+ var CLEAR_LINE2 = "\x1B[2K";
1996
+ var CURSOR_UP3 = (n) => `\x1B[${n}A`;
1997
+ var DIM2 = "\x1B[2m";
1998
+ var MultiSelect = class {
1999
+ constructor(options = {}) {
2000
+ this._colorOffset = 0;
2001
+ this._shimmerPhase = 0;
2002
+ this.promptColor = options.promptColor ?? resolveColor(config.color);
2003
+ this.promptGlyph = options.promptGlyph ?? (config.glyphs ? "\u25C6" : ">");
2004
+ this.descriptionColor = options.descriptionColor ?? BLUE;
2005
+ this.errorColor = options.errorColor ?? RED;
2006
+ this.checkedPrefix = options.checkedPrefix ?? (config.glyphs ? "\u25C9" : "[x]");
2007
+ this.uncheckedPrefix = options.uncheckedPrefix ?? (config.glyphs ? "\u25CB" : "[ ]");
2008
+ this.colorCycle = options.colorCycle ?? 1;
2009
+ this.shimmer = options.shimmer ?? 0;
2010
+ this.interval = options.interval ?? 80;
2011
+ this.min = options.min ?? 0;
2012
+ this.max = options.max ?? null;
2013
+ this.allowSkip = options.allowSkip ?? false;
2014
+ this.searchEnabled = options.search ?? false;
2015
+ this.maxHeight = options.maxHeight;
2016
+ const colors = options.colors ?? config.pulseColors;
2017
+ this._parsedColors = colors.length >= 2 ? colors.map(parseHex) : [];
2018
+ }
2019
+ pulseColor() {
2020
+ if (this._parsedColors.length < 2) return "";
2021
+ const t = (this._colorOffset % 1 + 1) % 1;
2022
+ const base2 = interpolateColor(this._parsedColors, t);
2023
+ const color = applyShimmer(base2, 0.5, this._shimmerPhase, this.shimmer);
2024
+ return formatColor(38, color);
2025
+ }
2026
+ async ask(prompt, items) {
2027
+ if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("MultiSelect requires an interactive terminal");
2028
+ let cursor = 0;
2029
+ let viewportOffset = 0;
2030
+ let searchQuery = "";
2031
+ const checked = /* @__PURE__ */ new Set();
2032
+ let error = null;
2033
+ let lastDrawnLines = 0;
2034
+ process.stdout.write(HIDE_CURSOR);
2035
+ const glyph = this.promptGlyph ? `${colorText(this.promptColor, this.promptGlyph)} ` : "";
2036
+ const indent = " ".repeat(this.promptGlyph ? stringLength(this.promptGlyph) + 1 : 0);
2037
+ process.stdout.write(`${glyph}${prompt}
2038
+ `);
2039
+ const getFiltered = () => {
2040
+ if (!this.searchEnabled || searchQuery === "") return items.map((item, i) => ({ item, originalIndex: i }));
2041
+ const q = searchQuery.toLowerCase();
2042
+ return items.map((item, i) => ({ item, originalIndex: i })).filter(({ item }) => item.label.toLowerCase().includes(q) || (item.description?.toLowerCase().includes(q) ?? false));
2043
+ };
2044
+ const renderList = (redraw) => {
2045
+ const filtered = getFiltered();
2046
+ if (cursor >= filtered.length) cursor = Math.max(0, filtered.length - 1);
2047
+ if (this.maxHeight) {
2048
+ if (cursor < viewportOffset) viewportOffset = cursor;
2049
+ else if (cursor >= viewportOffset + this.maxHeight) viewportOffset = cursor - this.maxHeight + 1;
2050
+ viewportOffset = Math.max(0, Math.min(viewportOffset, Math.max(0, filtered.length - this.maxHeight)));
2051
+ }
2052
+ const visibleStart = this.maxHeight ? viewportOffset : 0;
2053
+ const visibleEnd = this.maxHeight ? Math.min(filtered.length, viewportOffset + this.maxHeight) : filtered.length;
2054
+ if (redraw) {
2055
+ if (lastDrawnLines > 0) process.stdout.write(CURSOR_UP3(lastDrawnLines));
2056
+ process.stdout.write("\r\x1B[0J");
2057
+ }
2058
+ lastDrawnLines = 0;
2059
+ if (this.searchEnabled) {
2060
+ process.stdout.write(`\r${indent}${colorText(this.promptColor, "/")} ${searchQuery}|
2061
+ `);
2062
+ lastDrawnLines++;
2063
+ }
2064
+ const pulse = this.pulseColor();
2065
+ for (let vi = visibleStart; vi < visibleEnd; vi++) {
2066
+ const { item, originalIndex } = filtered[vi];
2067
+ const isCursor = vi === cursor;
2068
+ const isChecked = checked.has(originalIndex);
2069
+ const desc = item.description ? ` ${colorText(this.descriptionColor, `\u2014 ${item.description}`)}` : "";
2070
+ const checkMark = isChecked ? pulse ? `${pulse}${this.checkedPrefix}${RESET}` : colorText(this.promptColor, this.checkedPrefix) : this.uncheckedPrefix;
2071
+ const label = isCursor ? pulse ? `${pulse}${item.label}${RESET}` : colorText(this.promptColor, item.label) : item.label;
2072
+ process.stdout.write(`\r${indent}${checkMark} ${label}${desc}
2073
+ `);
2074
+ lastDrawnLines++;
2075
+ }
2076
+ const hintContent = `\u2191\u2193 move space/tab toggle \u2190\u2192 deselect/select${this.searchEnabled ? " type to filter" : " a all"} enter confirm`;
2077
+ const maxHintCols = Math.max(10, (process.stdout.columns ?? 80) - stringLength(indent) - 1);
2078
+ const hint = stringLength(hintContent) > maxHintCols ? hintContent.slice(0, maxHintCols) : hintContent;
2079
+ process.stdout.write(`\r${indent}${DIM2}${hint}${RESET}
2080
+ `);
2081
+ lastDrawnLines++;
2082
+ if (error) {
2083
+ process.stdout.write(`\r${indent}${colorText(this.errorColor, `\u2717 ${error}`)}
2084
+ `);
2085
+ lastDrawnLines++;
2086
+ }
2087
+ };
2088
+ renderList(false);
2089
+ return new Promise((resolve) => {
2090
+ let timer = null;
2091
+ const deregisterCleanup = registerCleanup(() => {
2092
+ if (timer) {
2093
+ clearInterval(timer);
2094
+ timer = null;
2095
+ }
2096
+ process.stdin.setRawMode(false);
2097
+ process.stdin.pause();
2098
+ process.stdin.removeListener("data", onKey);
2099
+ process.stdout.write(SHOW_CURSOR);
2100
+ });
2101
+ const cleanup = (result) => {
2102
+ deregisterCleanup();
2103
+ if (timer) {
2104
+ clearInterval(timer);
2105
+ timer = null;
2106
+ }
2107
+ if (lastDrawnLines > 0) process.stdout.write(CURSOR_UP3(lastDrawnLines));
2108
+ process.stdout.write("\x1B[0J");
2109
+ const bulletWidth = stringLength(this.checkedPrefix) + 1;
2110
+ for (let i = 0; i < items.length; i++) {
2111
+ const item = items[i];
2112
+ const bullet = checked.has(i) ? `${colorText(this.promptColor, this.checkedPrefix)} ` : " ".repeat(bulletWidth);
2113
+ process.stdout.write(`\r${indent}${bullet}${item.label}
2114
+ `);
2115
+ }
2116
+ process.stdout.write(`\r${CLEAR_LINE2}`);
2117
+ process.stdin.setRawMode(false);
2118
+ process.stdin.pause();
2119
+ process.stdin.removeListener("data", onKey);
2120
+ process.stdout.write(SHOW_CURSOR);
2121
+ resolve(result);
2122
+ };
2123
+ if (this._parsedColors.length >= 2) {
2124
+ timer = setInterval(() => {
2125
+ this._colorOffset = (this._colorOffset + this.colorCycle * this.interval / 1e3) % 1;
2126
+ if (this.shimmer > 0) this._shimmerPhase = (this._shimmerPhase + SHIMMER_SPEED * this.interval / 1e3) % 1;
2127
+ renderList(true);
2128
+ }, this.interval);
2129
+ }
2130
+ const onKey = (key) => {
2131
+ const str = key.toString();
2132
+ const filtered = getFiltered();
2133
+ const safeLen = Math.max(1, filtered.length);
2134
+ if (str === "\x1B[A" || str === "\x1B[Z") {
2135
+ error = null;
2136
+ cursor = (cursor - 1 + safeLen) % safeLen;
2137
+ renderList(true);
2138
+ } else if (str === "\x1B[B") {
2139
+ error = null;
2140
+ cursor = (cursor + 1) % safeLen;
2141
+ renderList(true);
2142
+ } else if (str === " " || str === " ") {
2143
+ const entry = filtered[cursor];
2144
+ if (!entry) return;
2145
+ const oi = entry.originalIndex;
2146
+ if (checked.has(oi)) {
2147
+ error = null;
2148
+ checked.delete(oi);
2149
+ } else if (this.max === null || checked.size < this.max) {
2150
+ error = null;
2151
+ checked.add(oi);
2152
+ } else {
2153
+ error = `Maximum ${this.max} item${this.max !== 1 ? "s" : ""} allowed`;
2154
+ }
2155
+ renderList(true);
2156
+ } else if (str === "\x1B[C") {
2157
+ const entry = filtered[cursor];
2158
+ if (!entry) return;
2159
+ const oi = entry.originalIndex;
2160
+ if (!checked.has(oi)) {
2161
+ if (this.max === null || checked.size < this.max) {
2162
+ error = null;
2163
+ checked.add(oi);
2164
+ } else {
2165
+ error = `Maximum ${this.max} item${this.max !== 1 ? "s" : ""} allowed`;
2166
+ }
2167
+ renderList(true);
2168
+ }
2169
+ } else if (str === "\x1B[D") {
2170
+ const entry = filtered[cursor];
2171
+ if (!entry) return;
2172
+ const oi = entry.originalIndex;
2173
+ if (checked.has(oi)) {
2174
+ error = null;
2175
+ checked.delete(oi);
2176
+ renderList(true);
2177
+ }
2178
+ } else if (str === "a" && !this.searchEnabled) {
2179
+ if (checked.size === items.length) {
2180
+ checked.clear();
2181
+ error = null;
2182
+ } else if (this.max !== null && items.length > this.max) {
2183
+ error = `Maximum ${this.max} item${this.max !== 1 ? "s" : ""} allowed`;
2184
+ } else {
2185
+ for (let i = 0; i < items.length; i++) checked.add(i);
2186
+ error = null;
2187
+ }
2188
+ renderList(true);
2189
+ } else if (str === "\r" || str === "\n") {
2190
+ const entry = filtered[cursor];
2191
+ if (checked.size === 0 && entry) checked.add(entry.originalIndex);
2192
+ if (checked.size < this.min) {
2193
+ error = `Select at least ${this.min} item${this.min !== 1 ? "s" : ""}`;
2194
+ renderList(true);
2195
+ return;
2196
+ }
2197
+ cleanup(items.filter((_, i) => checked.has(i)));
2198
+ } else if (str === "\x1B") {
2199
+ if (this.allowSkip) cleanup(null);
2200
+ } else if (str === "") {
2201
+ deregisterCleanup();
2202
+ if (timer) {
2203
+ clearInterval(timer);
2204
+ timer = null;
2205
+ }
2206
+ process.stdin.setRawMode(false);
2207
+ process.stdin.pause();
2208
+ process.stdin.removeListener("data", onKey);
2209
+ process.stdout.write(SHOW_CURSOR);
2210
+ process.exit(130);
2211
+ } else if (this.searchEnabled) {
2212
+ if (str === "\x7F" || str === "\b") {
2213
+ searchQuery = searchQuery.slice(0, -1);
2214
+ cursor = 0;
2215
+ viewportOffset = 0;
2216
+ error = null;
2217
+ renderList(true);
2218
+ } else if (str.length === 1 && str >= " ") {
2219
+ searchQuery += str;
2220
+ cursor = 0;
2221
+ viewportOffset = 0;
2222
+ error = null;
2223
+ renderList(true);
2224
+ }
2225
+ } else {
2226
+ const n = parseInt(str);
2227
+ if (!isNaN(n) && n >= 1 && n <= Math.min(filtered.length, 9)) {
2228
+ error = null;
2229
+ cursor = viewportOffset + n - 1;
2230
+ renderList(true);
2231
+ }
2232
+ }
2233
+ };
2234
+ process.stdin.setRawMode(true);
2235
+ process.stdin.resume();
2236
+ process.stdin.on("data", onKey);
2237
+ });
2238
+ }
2239
+ };
2240
+ async function multiSelect(prompt, items, options) {
2241
+ return new MultiSelect(options).ask(prompt, items);
2242
+ }
2243
+
2244
+ // src/utils/truncate.ts
2245
+ var ANSI_RE = /\x1b\[[0-9;]*[A-Za-z]/g;
2246
+ var RESET2 = "\x1B[0m";
2247
+ function truncate(str, maxLength, suffix = "\u2026") {
2248
+ if (stringLength(str) <= maxLength) return str;
2249
+ const hasAnsi = ANSI_RE.test(str);
2250
+ ANSI_RE.lastIndex = 0;
2251
+ const suffixLen = stringLength(suffix);
2252
+ const target = Math.max(0, maxLength - suffixLen);
2253
+ let visible = 0;
2254
+ let i = 0;
2255
+ while (i < str.length && visible < target) {
2256
+ if (str[i] === "\x1B") {
2257
+ const m = str.slice(i).match(ANSI_RE);
2258
+ if (m) {
2259
+ i += m[0].length;
2260
+ continue;
2261
+ }
2262
+ }
2263
+ visible++;
2264
+ i++;
2265
+ }
2266
+ return str.slice(0, i) + (hasAnsi ? RESET2 : "") + suffix;
2267
+ }
2268
+
2269
+ // src/utils/wrap.ts
2270
+ function wrap(str, width) {
2271
+ const words = str.split(" ");
2272
+ const lines = [];
2273
+ let current = "";
2274
+ let currentLen = 0;
2275
+ for (const word of words) {
2276
+ const wordLen = stringLength(word);
2277
+ if (currentLen === 0) {
2278
+ current = word;
2279
+ currentLen = wordLen;
2280
+ } else if (currentLen + 1 + wordLen <= width) {
2281
+ current += " " + word;
2282
+ currentLen += 1 + wordLen;
2283
+ } else {
2284
+ lines.push(current);
2285
+ current = word;
2286
+ currentLen = wordLen;
2287
+ }
2288
+ }
2289
+ if (current) lines.push(current);
2290
+ return lines.join("\n");
2291
+ }
2292
+
2293
+ // src/models/Scrollbox.ts
2294
+ var CURSOR_UP4 = (n) => `\x1B[${n}A`;
2295
+ var DIM3 = "\x1B[2m";
2296
+ var Scrollbox = class {
2297
+ constructor(options = {}) {
2298
+ this.height = options.height ?? 10;
2299
+ this.title = options.title;
2300
+ this.lineNumbers = options.lineNumbers ?? false;
2301
+ this.showScrollbar = options.scrollbar ?? true;
2302
+ this.borderColor = options.borderColor ?? DIM3;
2303
+ this.wrapLines = options.wrapLines ?? false;
2304
+ }
2305
+ async show(lines) {
2306
+ if (!process.stdin.isTTY || !process.stdout.isTTY) throw new Error("Scrollbox requires an interactive terminal");
2307
+ const termWidth = process.stdout.columns ?? 80;
2308
+ const lineNumWidth = this.lineNumbers ? String(lines.length).length + 2 : 0;
2309
+ const gutterWidth = this.showScrollbar ? 1 : 0;
2310
+ const contentWidth = Math.max(10, termWidth - lineNumWidth - gutterWidth);
2311
+ const displayLines = this.wrapLines ? lines.flatMap((line) => wrap(line, contentWidth).split("\n")) : lines;
2312
+ const total = displayLines.length;
2313
+ let offset = 0;
2314
+ let lastDrawnLines = 0;
2315
+ process.stdout.write(HIDE_CURSOR);
2316
+ const render = (redraw) => {
2317
+ offset = Math.max(0, Math.min(offset, Math.max(0, total - this.height)));
2318
+ if (redraw && lastDrawnLines > 0) {
2319
+ process.stdout.write(CURSOR_UP4(lastDrawnLines));
2320
+ process.stdout.write("\x1B[0J");
2321
+ }
2322
+ lastDrawnLines = 0;
2323
+ if (this.title) {
2324
+ process.stdout.write(`\r${colorText(this.borderColor, this.title)}
2325
+ `);
2326
+ lastDrawnLines++;
2327
+ }
2328
+ let thumbStart = 0;
2329
+ let thumbEnd = this.height;
2330
+ if (this.showScrollbar && total > this.height) {
2331
+ const thumbSize = Math.max(1, Math.floor(this.height / total * this.height));
2332
+ thumbStart = Math.floor(offset / Math.max(1, total - this.height) * (this.height - thumbSize));
2333
+ thumbEnd = thumbStart + thumbSize;
2334
+ }
2335
+ const visibleEnd = Math.min(total, offset + this.height);
2336
+ for (let i = offset; i < visibleEnd; i++) {
2337
+ const relIdx = i - offset;
2338
+ const numStr = this.lineNumbers ? `${colorText(this.borderColor, String(i + 1).padStart(lineNumWidth - 1))} ` : "";
2339
+ const content = this.wrapLines ? displayLines[i] : truncate(displayLines[i], contentWidth);
2340
+ const paddedContent = padRight(content, contentWidth);
2341
+ const gutter = this.showScrollbar ? total > this.height && relIdx >= thumbStart && relIdx < thumbEnd ? "\u2588" : colorText(this.borderColor, "\u2595") : "";
2342
+ process.stdout.write(`\r${numStr}${paddedContent}${gutter}
2343
+ `);
2344
+ lastDrawnLines++;
2345
+ }
2346
+ const pct = total <= this.height ? "100%" : `${Math.round(offset / (total - this.height) * 100)}%`;
2347
+ process.stdout.write(`\r${DIM3}\u2191\u2193/jk line space/b page g/G top/end q close ${pct}${RESET}
2348
+ `);
2349
+ lastDrawnLines++;
2350
+ };
2351
+ render(false);
2352
+ return new Promise((resolve) => {
2353
+ const deregisterCleanup = registerCleanup(() => {
2354
+ process.stdin.setRawMode(false);
2355
+ process.stdin.pause();
2356
+ process.stdin.removeListener("data", onKey);
2357
+ process.stdout.write(SHOW_CURSOR);
2358
+ });
2359
+ const cleanup = () => {
2360
+ deregisterCleanup();
2361
+ process.stdin.setRawMode(false);
2362
+ process.stdin.pause();
2363
+ process.stdin.removeListener("data", onKey);
2364
+ process.stdout.write(SHOW_CURSOR);
2365
+ resolve();
2366
+ };
2367
+ const onKey = (key) => {
2368
+ const str = key.toString();
2369
+ if (str === "\x1B[A" || str === "k") {
2370
+ offset--;
2371
+ render(true);
2372
+ } else if (str === "\x1B[B" || str === "j") {
2373
+ offset++;
2374
+ render(true);
2375
+ } else if (str === " " || str === "\x1B[6~") {
2376
+ offset += this.height;
2377
+ render(true);
2378
+ } else if (str === "b" || str === "\x1B[5~") {
2379
+ offset -= this.height;
2380
+ render(true);
2381
+ } else if (str === "g") {
2382
+ offset = 0;
2383
+ render(true);
2384
+ } else if (str === "G") {
2385
+ offset = total;
2386
+ render(true);
2387
+ } else if (str === "q" || str === "\x1B" || str === "\r" || str === "\n") {
2388
+ cleanup();
2389
+ } else if (str === "") {
2390
+ cleanup();
2391
+ process.exit(130);
2392
+ }
2393
+ };
2394
+ process.stdin.setRawMode(true);
2395
+ process.stdin.resume();
2396
+ process.stdin.on("data", onKey);
2397
+ });
2398
+ }
2399
+ };
2400
+ async function scrollbox(lines, options) {
2401
+ return new Scrollbox(options).show(lines);
2402
+ }
2403
+
2404
+ // src/models/Spinner.ts
2405
+ var _Spinner = class _Spinner {
2406
+ constructor(options = {}) {
2407
+ this._colors = [];
2408
+ this._parsedColors = [];
2409
+ this._bgColors = [];
2410
+ this._parsedBgColors = [];
2411
+ this._colorOffset = 0;
2412
+ this._shimmerPhase = 0;
2413
+ this._lastLineLength = 0;
2414
+ this._cleanupDeregister = null;
2415
+ this.running = false;
2416
+ this.frameIndex = 0;
2417
+ this.frames = options.frames ?? (config.glyphs ? _Spinner.FRAMES.braille : _Spinner.FRAMES.line);
2418
+ this.prefixString = options.prefix ?? "";
2419
+ this.suffixString = options.suffix ?? "";
2420
+ this.text = options.text ?? "";
2421
+ this.reverse = options.reverse ?? false;
2422
+ this.interval = options.interval ?? 80;
2423
+ this.colorCycle = options.colorCycle ?? 1;
2424
+ this.shimmer = options.shimmer ?? 0;
2425
+ this.onSpin = options.onSpin;
2426
+ this.colors = options.colors ?? ["#c026d3", "#e879f9"];
2427
+ this.bgColors = options.bgColors ?? [];
2428
+ this._successColor = options.successColor ?? GREEN;
2429
+ this._failColor = options.failColor ?? RED;
2430
+ this._warnColor = options.warnColor ?? YELLOW;
2431
+ this._infoColor = options.infoColor ?? BLUE;
2432
+ this._glyphs = options.glyphs ?? config.glyphs;
2433
+ }
2434
+ get colors() {
2435
+ return this._colors;
2436
+ }
2437
+ set colors(value) {
2438
+ this._colors = value;
2439
+ this._parsedColors = value.length > 1 ? value.map(parseHex) : [];
2440
+ }
2441
+ get bgColors() {
2442
+ return this._bgColors;
2443
+ }
2444
+ set bgColors(value) {
2445
+ this._bgColors = value;
2446
+ this._parsedBgColors = value.length > 1 ? value.map(parseHex) : [];
2447
+ }
2448
+ start() {
2449
+ if (!process.stdout.isTTY) return;
2450
+ this.running = true;
2451
+ process.stdout.write(HIDE_CURSOR);
2452
+ this._cleanupDeregister = registerCleanup(() => {
2453
+ this.running = false;
2454
+ process.stdout.clearLine?.(0);
2455
+ process.stdout.write(SHOW_CURSOR);
2456
+ });
2457
+ this.run();
2458
+ }
2459
+ stop(message) {
2460
+ this.running = false;
2461
+ this._cleanupDeregister?.();
2462
+ this._cleanupDeregister = null;
2463
+ if (process.stdout.isTTY) {
2464
+ this.clear();
2465
+ process.stdout.write(SHOW_CURSOR);
2466
+ }
2467
+ if (message) process.stdout.write(`${message}
2468
+ `);
2469
+ return this;
2470
+ }
2471
+ message(string) {
2472
+ this.text = string;
2473
+ return this;
2474
+ }
2475
+ succeed(string) {
2476
+ this.running = false;
2477
+ this._cleanupDeregister?.();
2478
+ this._cleanupDeregister = null;
2479
+ if (process.stdout.isTTY) {
2480
+ this.clear();
2481
+ const glyph = this._glyphs ? colorText(this._successColor, "\u2714") + " " : "";
2482
+ process.stdout.write(`${SHOW_CURSOR}${glyph}${string ?? ""}
2483
+ `);
2484
+ } else {
2485
+ process.stdout.write(`${this._glyphs ? `\u2714 ${string ?? ""}` : string ?? ""}
2486
+ `);
2487
+ }
2488
+ return this;
2489
+ }
2490
+ fail(string) {
2491
+ this.running = false;
2492
+ this._cleanupDeregister?.();
2493
+ this._cleanupDeregister = null;
2494
+ if (process.stdout.isTTY) {
2495
+ this.clear();
2496
+ const glyph = this._glyphs ? colorText(this._failColor, "\u2716") + " " : "";
2497
+ process.stdout.write(`${SHOW_CURSOR}${glyph}${string ?? ""}
2498
+ `);
2499
+ } else {
2500
+ process.stdout.write(`${this._glyphs ? `\u2716 ${string ?? ""}` : string ?? ""}
2501
+ `);
2502
+ }
2503
+ return this;
2504
+ }
2505
+ warn(string) {
2506
+ this.running = false;
2507
+ this._cleanupDeregister?.();
2508
+ this._cleanupDeregister = null;
2509
+ if (process.stdout.isTTY) {
2510
+ this.clear();
2511
+ const glyph = this._glyphs ? colorText(this._warnColor, "\u26A0") + " " : "";
2512
+ process.stdout.write(`${SHOW_CURSOR}${glyph}${string ?? ""}
2513
+ `);
2514
+ } else {
2515
+ process.stdout.write(`${this._glyphs ? `\u26A0 ${string ?? ""}` : string ?? ""}
2516
+ `);
2517
+ }
2518
+ return this;
2519
+ }
2520
+ info(string) {
2521
+ this.running = false;
2522
+ this._cleanupDeregister?.();
2523
+ this._cleanupDeregister = null;
2524
+ if (process.stdout.isTTY) {
2525
+ this.clear();
2526
+ const glyph = this._glyphs ? colorText(this._infoColor, "\u2139") + " " : "";
2527
+ process.stdout.write(`${SHOW_CURSOR}${glyph}${string ?? ""}
2528
+ `);
2529
+ } else {
2530
+ process.stdout.write(`${this._glyphs ? `\u2139 ${string ?? ""}` : string ?? ""}
2531
+ `);
2532
+ }
2533
+ return this;
2534
+ }
2535
+ clear() {
2536
+ process.stdout.clearLine?.(0);
2537
+ this._lastLineLength = 0;
2538
+ }
2539
+ coloredFrame() {
2540
+ const t = this._parsedColors.length >= 2 && this.frames.length > 1 ? this.frameIndex / (this.frames.length - 1) : 0;
2541
+ const et = this.colorCycle > 0 ? ((t + this._colorOffset) % 1 + 1) % 1 : t;
2542
+ const frame = this.frames[this.frameIndex];
2543
+ const fg = this._parsedColors.length >= 2 ? formatColor(38, applyShimmer(interpolateColor(this._parsedColors, et), 0.5, this._shimmerPhase, this.shimmer)) : "";
2544
+ const bg = this._parsedBgColors.length >= 2 ? formatColor(48, applyShimmer(interpolateColor(this._parsedBgColors, et), 0.5, this._shimmerPhase, this.shimmer)) : "";
2545
+ return fg || bg ? fg + bg + frame + RESET : frame;
2546
+ }
2547
+ run() {
2548
+ const frame = this.coloredFrame();
2549
+ const t = this.text;
2550
+ const content = this.reverse ? t ? `${t} ${frame}` : frame : t ? `${frame} ${t}` : frame;
2551
+ const raw = `${this.prefixString}${content}${this.suffixString}`;
2552
+ const displayLen = stringLength(raw);
2553
+ const padding = " ".repeat(Math.max(0, this._lastLineLength - displayLen));
2554
+ this._lastLineLength = displayLen;
2555
+ process.stdout.write(`${raw}${padding}\r`);
2556
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
2557
+ if (this.frameIndex === 0) this.onSpin?.();
2558
+ if (this.colorCycle > 0) {
2559
+ this._colorOffset = (this._colorOffset + this.colorCycle * this.interval / 1e3) % 1;
2560
+ }
2561
+ if (this.shimmer > 0) {
2562
+ this._shimmerPhase = (this._shimmerPhase + SHIMMER_SPEED * this.interval / 1e3) % 1;
2563
+ }
2564
+ setTimeout(() => {
2565
+ if (this.running) this.run();
2566
+ }, this.interval);
2567
+ }
2568
+ };
2569
+ _Spinner.FRAMES = {
2570
+ braille: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
2571
+ dots: ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"],
2572
+ line: ["|", "/", "-", "\\"],
2573
+ arrow: ["\u2190", "\u2196", "\u2191", "\u2197", "\u2192", "\u2198", "\u2193", "\u2199"],
2574
+ bounce: ["\u2801", "\u2802", "\u2804", "\u2802"]
2575
+ };
2576
+ var Spinner = _Spinner;
2577
+
2578
+ // src/models/Table.ts
2579
+ import cosmetic2 from "cosmetic";
2580
+
2581
+ // src/utils/padSides.ts
2582
+ var padSides = (string, padding) => {
2583
+ let alt = false;
2584
+ while (stringLength(string) < padding) {
2585
+ if (alt) {
2586
+ string = ` ${string}`;
2587
+ } else {
2588
+ string += " ";
2589
+ }
2590
+ alt = !alt;
2591
+ }
2592
+ return string;
2593
+ };
2594
+
2595
+ // src/models/Table.ts
2596
+ var alignPad = (align) => {
2597
+ switch (align) {
2598
+ case "center":
2599
+ return padSides;
2600
+ case "right":
2601
+ return padLeft;
2602
+ default:
2603
+ return padRight;
2604
+ }
2605
+ };
2606
+ var Table = class {
2607
+ constructor(rows, options = {}) {
2608
+ this.rows = rows;
2609
+ this.columns = {};
2610
+ this.separator = options.separator ?? "|";
2611
+ this.align = options.align ?? "left";
2612
+ this.margin = options.margin ?? 0;
2613
+ this.string = "";
2614
+ if (options.title) this.title = options.title;
2615
+ if (options.columns) {
2616
+ for (const col of options.columns) {
2617
+ const column = new Column(col);
2618
+ if (!column.hidden) this.columns[column.key] = column;
2619
+ }
2620
+ }
2621
+ for (const row of this.rows) {
2622
+ for (const key of Object.keys(row)) {
2623
+ if (Object.keys(this.columns).length) {
2624
+ const column = this.columns[key];
2625
+ if (!column) continue;
2626
+ const cellLen = stringLength(column.value(row[key]));
2627
+ if (column.padding < cellLen) this.columns[key].padding = cellLen;
2628
+ } else {
2629
+ const keyLen = stringLength(key);
2630
+ const valLen = stringLength(String(row[key] ?? ""));
2631
+ this.columns[key] = new Column({ key, padding: Math.max(keyLen, valLen) });
2632
+ }
2633
+ }
2634
+ }
2635
+ if (options.meta) {
2636
+ this.meta = options.meta;
2637
+ for (const meta of options.meta) {
2638
+ for (const key of Object.keys(meta)) {
2639
+ const column = this.columns[key];
2640
+ if (!column) continue;
2641
+ const cellLen = stringLength(column.value(meta[key]));
2642
+ if (column.padding < cellLen) column.padding = cellLen;
2643
+ }
2644
+ }
2645
+ }
2646
+ if (this.title) this.string += `${alignPad(this.align)(this.title, this.width)}
2647
+
2648
+ `;
2649
+ const keys = Object.keys(this.columns);
2650
+ let header = "";
2651
+ for (const [i, key] of keys.entries()) {
2652
+ const column = this.columns[key];
2653
+ const pad = alignPad(column.align ?? this.align);
2654
+ header += pad(column.title, column.padding + this.margin);
2655
+ if (i < keys.length - 1) header += this.separator;
2656
+ }
2657
+ const styled = typeof config.color === "number" ? cosmetic2.xterm(config.color) : config.color.startsWith("#") ? cosmetic2.hex(config.color) : cosmetic2[config.color];
2658
+ this.string += `${styled.underline.encoder(header)}
2659
+ `;
2660
+ for (const [ri, row] of this.rows.entries()) {
2661
+ for (const [ci, key] of keys.entries()) {
2662
+ const column = this.columns[key];
2663
+ const pad = alignPad(column.align ?? this.align);
2664
+ const raw = row[column.key];
2665
+ this.string += pad(column.value(raw == null ? "" : raw), column.padding + this.margin);
2666
+ if (ci < keys.length - 1) this.string += this.separator;
2667
+ }
2668
+ if (ri < this.rows.length - 1) this.string += "\n";
2669
+ }
2670
+ if (this.meta) {
2671
+ this.string += "\n\n";
2672
+ for (const [mi, meta] of this.meta.entries()) {
2673
+ for (const [ci, key] of keys.entries()) {
2674
+ const column = this.columns[key];
2675
+ const pad = alignPad(column.align ?? this.align);
2676
+ const raw = meta[column.key];
2677
+ this.string += pad(column.value(raw == null ? "" : raw), column.padding + this.margin);
2678
+ if (ci < keys.length - 1) this.string += this.separator;
2679
+ }
2680
+ if (mi < this.meta.length - 1) this.string += "\n";
2681
+ }
2682
+ }
2683
+ }
2684
+ print() {
2685
+ process.stdout.write(this.string + "\n");
2686
+ }
2687
+ get width() {
2688
+ let width = 0;
2689
+ for (const key of Object.keys(this.columns)) {
2690
+ if (!this.columns[key].hidden) width += this.columns[key].padding + this.margin + 1;
2691
+ }
2692
+ return width - 1;
2693
+ }
2694
+ };
2695
+ Table.left = "left";
2696
+ Table.center = "center";
2697
+ Table.right = "right";
2698
+
2699
+ // src/models/TermKit.ts
2700
+ var _TermKit = class _TermKit {
2701
+ static set defaults(obj) {
2702
+ _TermKit.commandDefaults = obj;
2703
+ }
2704
+ static setDefaults(obj) {
2705
+ _TermKit.commandDefaults = obj;
2706
+ }
2707
+ static command(name, variables, info) {
2708
+ const cmd = new Command(Object.assign({ name, variables, info }, _TermKit.commandDefaults));
2709
+ if (!_TermKit.base) _TermKit.base = cmd;
2710
+ return cmd;
2711
+ }
2712
+ static middleware(action) {
2713
+ return action;
2714
+ }
2715
+ static option(short, long, variables, info) {
2716
+ return new Option({ short, long, variables, info });
2717
+ }
2718
+ static parse(arr) {
2719
+ if (!_TermKit.base) throw new Error("No command defined");
2720
+ return _TermKit.base.parse(arr);
2721
+ }
2722
+ };
2723
+ _TermKit.base = null;
2724
+ _TermKit.commandDefaults = {};
2725
+ var TermKit = _TermKit;
2726
+
2727
+ // src/index.ts
2728
+ import { default as default2 } from "cosmetic";
2729
+ var base = null;
2730
+ var commandDefaults = {};
2731
+ var Program = {
2732
+ command: (name, variables, info) => {
2733
+ const cmd = new Command(Object.assign({ name, variables, info }, commandDefaults));
2734
+ if (!base) base = cmd;
2735
+ return cmd;
2736
+ },
2737
+ option: (short, long, variables, info) => new Option({ short, long, variables, info }),
2738
+ middleware: (fn) => fn,
2739
+ parse: async (arr) => {
2740
+ if (!base) throw new Error("No command defined");
2741
+ try {
2742
+ await base.parse(arr);
2743
+ } catch (err) {
2744
+ const msg = err instanceof Error ? err.message : String(err);
2745
+ if (process.stderr.isTTY && config.glyphs) {
2746
+ process.stderr.write(`\x1B[31m\u2716\x1B[0m ${msg}
2747
+ `);
2748
+ } else {
2749
+ process.stderr.write(`Error: ${msg}
2750
+ `);
2751
+ }
2752
+ process.exit(1);
2753
+ }
2754
+ },
2755
+ setDefaults: (data) => {
2756
+ commandDefaults = data;
360
2757
  }
361
- };
362
- _TermKit.base = null;
363
- _TermKit.commandDefaults = {};
364
- var TermKit = _TermKit;
365
-
366
- // src/index.ts
367
- var base = null;
368
- var commandDefaults = {};
369
- var command = (name, variables, info) => {
370
- const cmd = new Command(Object.assign({ name, variables, info }, commandDefaults));
371
- if (!base) base = cmd;
372
- return cmd;
373
- };
374
- var middleware = (fn) => fn;
375
- var option = (short, long, variables, info) => new Option({ short, long, variables, info });
376
- var parse = (arr) => {
377
- if (!base) throw new Error("No command defined");
378
- return base.parse(arr);
379
- };
380
- var setDefaults = (data) => {
381
- commandDefaults = data;
382
2758
  };
383
2759
  export {
2760
+ Bar,
2761
+ Chart_exports as Chart,
2762
+ default2 as Color,
2763
+ Column,
384
2764
  Command,
2765
+ Input,
2766
+ Log,
2767
+ MultiBar,
2768
+ MultiSelect,
385
2769
  Option,
2770
+ Program,
2771
+ Scrollbox,
2772
+ Select,
2773
+ Spinner,
2774
+ Table,
386
2775
  TermKit,
387
2776
  Variable,
388
- command,
389
- middleware,
390
- option,
391
- parse,
392
- setDefaults
2777
+ configure,
2778
+ confirm,
2779
+ input,
2780
+ log,
2781
+ markup,
2782
+ multiSelect,
2783
+ padLeft,
2784
+ padRight,
2785
+ padSides,
2786
+ scrollbox,
2787
+ select,
2788
+ stringLength,
2789
+ truncate,
2790
+ wrap
393
2791
  };