ansimax 1.0.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.
package/dist/index.mjs ADDED
@@ -0,0 +1,1632 @@
1
+ // src/utils/ansi.ts
2
+ var ESC = "\x1B";
3
+ var CSI = `${ESC}[`;
4
+ var cursor = {
5
+ up: (n = 1) => `${CSI}${n}A`,
6
+ down: (n = 1) => `${CSI}${n}B`,
7
+ right: (n = 1) => `${CSI}${n}C`,
8
+ left: (n = 1) => `${CSI}${n}D`,
9
+ to: (x, y) => `${CSI}${y};${x}H`,
10
+ save: () => `${CSI}s`,
11
+ restore: () => `${CSI}u`,
12
+ hide: () => `${CSI}?25l`,
13
+ show: () => `${CSI}?25h`
14
+ };
15
+ var screen = {
16
+ clear: () => `${CSI}2J${CSI}H`,
17
+ clearLine: () => `${CSI}2K`,
18
+ clearRight: () => `${CSI}0K`,
19
+ clearDown: () => `${CSI}0J`,
20
+ scrollUp: (n = 1) => `${CSI}${n}S`,
21
+ scrollDown: (n = 1) => `${CSI}${n}T`
22
+ };
23
+ var FG = {
24
+ black: 30,
25
+ red: 31,
26
+ green: 32,
27
+ yellow: 33,
28
+ blue: 34,
29
+ magenta: 35,
30
+ cyan: 36,
31
+ white: 37,
32
+ brightBlack: 90,
33
+ brightRed: 91,
34
+ brightGreen: 92,
35
+ brightYellow: 93,
36
+ brightBlue: 94,
37
+ brightMagenta: 95,
38
+ brightCyan: 96,
39
+ brightWhite: 97
40
+ };
41
+ var BG = {
42
+ black: 40,
43
+ red: 41,
44
+ green: 42,
45
+ yellow: 43,
46
+ blue: 44,
47
+ magenta: 45,
48
+ cyan: 46,
49
+ white: 47,
50
+ brightBlack: 100,
51
+ brightRed: 101,
52
+ brightGreen: 102,
53
+ brightYellow: 103,
54
+ brightBlue: 104,
55
+ brightMagenta: 105,
56
+ brightCyan: 106,
57
+ brightWhite: 107
58
+ };
59
+ var STYLE = {
60
+ reset: 0,
61
+ bold: 1,
62
+ dim: 2,
63
+ italic: 3,
64
+ underline: 4,
65
+ blink: 5,
66
+ inverse: 7,
67
+ hidden: 8,
68
+ strikethrough: 9
69
+ };
70
+ var sgr = (...codes) => `${CSI}${codes.join(";")}m`;
71
+ var reset = () => sgr(STYLE.reset);
72
+ var fgRgb = (r, g, b) => `${CSI}38;2;${r};${g};${b}m`;
73
+ var bgRgb = (r, g, b) => `${CSI}48;2;${r};${g};${b}m`;
74
+ var fg256 = (n) => `${CSI}38;5;${n}m`;
75
+ var bg256 = (n) => `${CSI}48;5;${n}m`;
76
+ var supportsColor = () => {
77
+ if (process.env["NO_COLOR"]) return "none";
78
+ if (process.env["COLORTERM"] === "truecolor" || process.env["COLORTERM"] === "24bit") return "truecolor";
79
+ if (process.env["TERM_PROGRAM"] === "iTerm.app") return "truecolor";
80
+ if (process.env["TERM"]?.includes("256color")) return "256";
81
+ return "basic";
82
+ };
83
+ var sleep = (ms) => new Promise((r) => setTimeout(() => r(), ms));
84
+ var write = (str) => process.stdout.write(str);
85
+ var writeln = (str = "") => process.stdout.write(str + "\n");
86
+
87
+ // src/utils/helpers.ts
88
+ var clamp = (n, min, max) => Math.min(Math.max(n, min), max);
89
+ var lerp = (a, b, t) => a + (b - a) * t;
90
+ var clampByte = (v) => clamp(Math.round(v), 0, 255);
91
+ var HEX_RE = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
92
+ var isHexColor = (hex) => typeof hex === "string" && HEX_RE.test(hex.trim());
93
+ var hexToRgb = (hex) => {
94
+ if (!isHexColor(hex)) {
95
+ throw new Error(`Invalid hex color: "${hex}"`);
96
+ }
97
+ const clean = hex.trim().replace("#", "");
98
+ const full = clean.length === 3 ? clean.split("").map((c) => c + c).join("") : clean;
99
+ const int = parseInt(full, 16);
100
+ return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
101
+ };
102
+ var rgbToHex = (r, g, b) => "#" + [clampByte(r), clampByte(g), clampByte(b)].map((v) => v.toString(16).padStart(2, "0")).join("");
103
+ var lerpColor = (a, b, t) => {
104
+ const ct = clamp(t, 0, 1);
105
+ return {
106
+ r: Math.round(lerp(a.r, b.r, ct)),
107
+ g: Math.round(lerp(a.g, b.g, ct)),
108
+ b: Math.round(lerp(a.b, b.b, ct))
109
+ };
110
+ };
111
+ var rgbTo256 = (r, g, b) => {
112
+ const cr = clampByte(r), cg = clampByte(g), cb = clampByte(b);
113
+ if (cr === cg && cg === cb) {
114
+ if (cr < 8) return 16;
115
+ if (cr > 248) return 231;
116
+ return Math.round((cr - 8) / 247 * 24) + 232;
117
+ }
118
+ return 16 + 36 * Math.round(cr / 255 * 5) + 6 * Math.round(cg / 255 * 5) + Math.round(cb / 255 * 5);
119
+ };
120
+ var ANSI_RE = new RegExp(
121
+ [
122
+ "\\x1b\\[[0-9;?]*[a-zA-Z]",
123
+ // CSI
124
+ "\\x1b\\][^\\x07\\x1b]*(?:\\x07|\\x1b\\\\)",
125
+ // OSC
126
+ "\\x1b[NOMP78=>c]"
127
+ // single-char escapes
128
+ ].join("|"),
129
+ "g"
130
+ );
131
+ var stripAnsi = (str) => str.replace(ANSI_RE, "");
132
+ var visibleLen = (str) => stripAnsi(str).length;
133
+ var truncateAnsi = (str, width, ellipsis = "\u2026") => {
134
+ if (visibleLen(str) <= width) return str;
135
+ const ellipsisLen = visibleLen(ellipsis);
136
+ const target = Math.max(0, width - ellipsisLen);
137
+ let visible = 0;
138
+ let result = "";
139
+ let i = 0;
140
+ while (i < str.length && visible < target) {
141
+ if (str[i] === "\x1B") {
142
+ const match = str.slice(i).match(ANSI_RE);
143
+ if (match && match[0] && str.indexOf(match[0], i) === i) {
144
+ result += match[0];
145
+ i += match[0].length;
146
+ continue;
147
+ }
148
+ }
149
+ result += str[i];
150
+ visible++;
151
+ i++;
152
+ }
153
+ return result + ellipsis + "\x1B[0m";
154
+ };
155
+ var padEnd = (str, width, ch = " ") => {
156
+ const pad = width - visibleLen(str);
157
+ return pad > 0 ? str + ch.repeat(pad) : str;
158
+ };
159
+ var padStart = (str, width, ch = " ") => {
160
+ const pad = width - visibleLen(str);
161
+ return pad > 0 ? ch.repeat(pad) + str : str;
162
+ };
163
+ var center = (str, width, ch = " ") => {
164
+ const pad = width - visibleLen(str);
165
+ if (pad <= 0) return str;
166
+ const l = Math.floor(pad / 2);
167
+ const r = pad - l;
168
+ return ch.repeat(l) + str + ch.repeat(r);
169
+ };
170
+ var repeatVisible = (str, width) => {
171
+ if (!str || width <= 0) return "";
172
+ const unit = visibleLen(str);
173
+ if (unit === 0) return "";
174
+ const times = Math.ceil(width / unit);
175
+ return truncateAnsi(str.repeat(times), width, "");
176
+ };
177
+ var termSize = () => ({
178
+ cols: process.stdout.columns || 80,
179
+ rows: process.stdout.rows || 24
180
+ });
181
+ var wordWrap = (text, width) => {
182
+ if (width <= 0) return [text];
183
+ const words = text.split(" ");
184
+ const lines = [];
185
+ let current = "";
186
+ const breakLong = (word) => {
187
+ const chunks = [];
188
+ for (let i = 0; i < word.length; i += width) {
189
+ chunks.push(word.slice(i, i + width));
190
+ }
191
+ return chunks;
192
+ };
193
+ for (const raw of words) {
194
+ const tokens = raw.length > width ? breakLong(raw) : [raw];
195
+ for (const word of tokens) {
196
+ if (current.length + word.length + (current ? 1 : 0) <= width) {
197
+ current += (current ? " " : "") + word;
198
+ } else {
199
+ if (current) lines.push(current);
200
+ current = word;
201
+ }
202
+ }
203
+ }
204
+ if (current) lines.push(current);
205
+ return lines;
206
+ };
207
+
208
+ // src/colors/index.ts
209
+ var _noColor = null;
210
+ var setNoColor = (v) => {
211
+ _noColor = v;
212
+ };
213
+ var resetNoColor = () => {
214
+ _noColor = null;
215
+ };
216
+ var isNoColor = () => {
217
+ if (_noColor !== null) return _noColor;
218
+ return Boolean(process.env["NO_COLOR"]) || !process.stdout.isTTY;
219
+ };
220
+ var clampRgb = (n) => Math.max(0, Math.min(255, Math.round(n)));
221
+ var clamp256 = (n) => Math.max(0, Math.min(255, Math.round(n)));
222
+ var HEX_RE2 = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
223
+ var safeHex = (h) => {
224
+ if (!HEX_RE2.test(h.trim())) return null;
225
+ return hexToRgb(h);
226
+ };
227
+ var wrap = (open, text) => isNoColor() ? text : `${open}${text}${reset()}`;
228
+ var makeFg = (code) => (text) => wrap(sgr(code), text);
229
+ var makeBg = (code) => (text) => wrap(sgr(code), text);
230
+ var compose = (...fns) => (text) => {
231
+ if (isNoColor()) return text;
232
+ const opens = fns.map((fn) => {
233
+ const result = fn("");
234
+ return result.endsWith(reset()) ? result.slice(0, -reset().length) : result;
235
+ });
236
+ return opens.join("") + text + reset();
237
+ };
238
+ var gradient = (text, stops) => {
239
+ if (!text || isNoColor()) return text;
240
+ const colors = stops.map(safeHex).filter((c) => c !== null);
241
+ if (colors.length < 2) return text;
242
+ const chars = [...text];
243
+ const visible = chars.filter((c) => c !== " ").length;
244
+ if (visible === 0) return text;
245
+ let colorIdx = 0;
246
+ return chars.map((ch) => {
247
+ if (ch === " ") return ch;
248
+ const t = visible === 1 ? 0 : colorIdx / (visible - 1);
249
+ const scaled = t * (colors.length - 1);
250
+ const lo = Math.floor(scaled);
251
+ const hi = Math.min(lo + 1, colors.length - 1);
252
+ const { r, g, b } = lerpColor(colors[lo], colors[hi], scaled - lo);
253
+ colorIdx++;
254
+ return fgRgb(r, g, b) + ch + reset();
255
+ }).join("");
256
+ };
257
+ var RAINBOW = ["#ff0000", "#ff7f00", "#ffff00", "#00ff00", "#0000ff", "#8b00ff"];
258
+ var rainbow = (text) => gradient(text, RAINBOW);
259
+ var presets = {
260
+ sunset: (t) => gradient(t, ["#ff6b6b", "#feca57", "#48dbfb"]),
261
+ ocean: (t) => gradient(t, ["#0575e6", "#021b79"]),
262
+ fire: (t) => gradient(t, ["#f7971e", "#ffd200", "#ff0000"]),
263
+ neon: (t) => gradient(t, ["#f953c6", "#b91d73"]),
264
+ forest: (t) => gradient(t, ["#134e5e", "#71b280"]),
265
+ aurora: (t) => gradient(t, ["#00c6ff", "#0072ff", "#7e57c2"]),
266
+ candy: (t) => gradient(t, ["#fd79a8", "#a29bfe", "#74b9ff"]),
267
+ gold: (t) => gradient(t, ["#f7971e", "#ffd200"])
268
+ };
269
+ var color = {
270
+ // ── Named foreground colors ──
271
+ black: makeFg(FG.black),
272
+ red: makeFg(FG.red),
273
+ green: makeFg(FG.green),
274
+ yellow: makeFg(FG.yellow),
275
+ blue: makeFg(FG.blue),
276
+ magenta: makeFg(FG.magenta),
277
+ cyan: makeFg(FG.cyan),
278
+ white: makeFg(FG.white),
279
+ // ── Bright foreground ──
280
+ brightBlack: makeFg(FG.brightBlack),
281
+ brightRed: makeFg(FG.brightRed),
282
+ brightGreen: makeFg(FG.brightGreen),
283
+ brightYellow: makeFg(FG.brightYellow),
284
+ brightBlue: makeFg(FG.brightBlue),
285
+ brightMagenta: makeFg(FG.brightMagenta),
286
+ brightCyan: makeFg(FG.brightCyan),
287
+ brightWhite: makeFg(FG.brightWhite),
288
+ // ── Common aliases ──
289
+ gray: makeFg(FG.brightBlack),
290
+ grey: makeFg(FG.brightBlack),
291
+ orange: (t) => wrap(fgRgb(255, 165, 0), t),
292
+ purple: makeFg(FG.magenta),
293
+ // ── Named background colors ──
294
+ bgBlack: makeBg(BG.black),
295
+ bgRed: makeBg(BG.red),
296
+ bgGreen: makeBg(BG.green),
297
+ bgYellow: makeBg(BG.yellow),
298
+ bgBlue: makeBg(BG.blue),
299
+ bgMagenta: makeBg(BG.magenta),
300
+ bgCyan: makeBg(BG.cyan),
301
+ bgWhite: makeBg(BG.white),
302
+ // ── Text styles ──
303
+ bold: (t) => wrap(sgr(STYLE.bold), t),
304
+ dim: (t) => wrap(sgr(STYLE.dim), t),
305
+ italic: (t) => wrap(sgr(STYLE.italic), t),
306
+ underline: (t) => wrap(sgr(STYLE.underline), t),
307
+ blink: (t) => wrap(sgr(STYLE.blink), t),
308
+ // terminal support varies
309
+ inverse: (t) => wrap(sgr(STYLE.inverse), t),
310
+ strikethrough: (t) => wrap(sgr(STYLE.strikethrough), t),
311
+ hidden: (t) => wrap(sgr(STYLE.hidden), t),
312
+ // ── True-color (24-bit) — values clamped to 0–255 ──
313
+ rgb: (r, g, b) => (t) => wrap(fgRgb(clampRgb(r), clampRgb(g), clampRgb(b)), t),
314
+ bgRgb: (r, g, b) => (t) => wrap(bgRgb(clampRgb(r), clampRgb(g), clampRgb(b)), t),
315
+ // ── Hex — fail-soft: invalid hex → plain text ──
316
+ hex: (h) => (t) => {
317
+ const p = safeHex(h);
318
+ return p ? wrap(fgRgb(p.r, p.g, p.b), t) : t;
319
+ },
320
+ bgHex: (h) => (t) => {
321
+ const p = safeHex(h);
322
+ return p ? wrap(bgRgb(p.r, p.g, p.b), t) : t;
323
+ },
324
+ // ── 256-color — value clamped to 0–255 ──
325
+ color256: (n) => (t) => wrap(fg256(clamp256(n)), t),
326
+ bgColor256: (n) => (t) => wrap(bg256(clamp256(n)), t),
327
+ // ── Gradients ──
328
+ gradient,
329
+ rainbow,
330
+ ...presets
331
+ };
332
+
333
+ // src/animations/index.ts
334
+ var isTTY = () => Boolean(process.stdout.isTTY);
335
+ var resolveRgb = (c) => typeof c === "string" ? hexToRgb(c) : c;
336
+ var safeSteps = (n) => Math.max(1, n);
337
+ var typewriter = async (text, opts = {}) => {
338
+ const { speed = 50, newline = true, colorFn = null, signal, reducedMotion = false } = opts;
339
+ if (!isTTY() || reducedMotion) {
340
+ write(colorFn ? [...text].map(colorFn).join("") : text);
341
+ if (newline) writeln();
342
+ return;
343
+ }
344
+ write(cursor.hide());
345
+ try {
346
+ for (const ch of text) {
347
+ if (signal?.aborted) break;
348
+ write(colorFn ? colorFn(ch) : ch);
349
+ if (ch !== " ") await sleep(speed);
350
+ }
351
+ } finally {
352
+ write(cursor.show());
353
+ if (newline) writeln();
354
+ }
355
+ };
356
+ var fadeIn = async (text, opts = {}) => {
357
+ const {
358
+ duration = 800,
359
+ steps = 16,
360
+ newline = true,
361
+ color: baseColor = { r: 255, g: 255, b: 255 },
362
+ signal,
363
+ reducedMotion = false
364
+ } = opts;
365
+ if (!isTTY() || reducedMotion) {
366
+ write(text);
367
+ if (newline) writeln();
368
+ return;
369
+ }
370
+ const base = resolveRgb(baseColor);
371
+ const n = safeSteps(steps);
372
+ write(cursor.hide());
373
+ try {
374
+ for (let i = 0; i <= n; i++) {
375
+ if (signal?.aborted) break;
376
+ const t = i / n;
377
+ write(
378
+ cursor.save() + fgRgb(Math.round(base.r * t), Math.round(base.g * t), Math.round(base.b * t)) + text + reset() + cursor.restore()
379
+ );
380
+ await sleep(duration / n);
381
+ }
382
+ } finally {
383
+ write(cursor.show());
384
+ if (newline) writeln();
385
+ }
386
+ };
387
+ var fadeOut = async (text, opts = {}) => {
388
+ const {
389
+ duration = 800,
390
+ steps = 16,
391
+ newline = true,
392
+ color: baseColor = { r: 255, g: 255, b: 255 },
393
+ signal,
394
+ reducedMotion = false
395
+ } = opts;
396
+ if (!isTTY() || reducedMotion) {
397
+ if (newline) writeln();
398
+ return;
399
+ }
400
+ const base = resolveRgb(baseColor);
401
+ const n = safeSteps(steps);
402
+ write(cursor.hide());
403
+ try {
404
+ for (let i = n; i >= 0; i--) {
405
+ if (signal?.aborted) break;
406
+ const t = i / n;
407
+ write(
408
+ cursor.save() + fgRgb(Math.round(base.r * t), Math.round(base.g * t), Math.round(base.b * t)) + text + reset() + cursor.restore()
409
+ );
410
+ await sleep(duration / n);
411
+ }
412
+ } finally {
413
+ write(cursor.show());
414
+ if (newline) writeln();
415
+ }
416
+ };
417
+ var slide = async (text, opts = {}) => {
418
+ const { direction = "left", duration = 400, newline = true, signal, reducedMotion = false } = opts;
419
+ if (!isTTY() || reducedMotion) {
420
+ write(text);
421
+ if (newline) writeln();
422
+ return;
423
+ }
424
+ const len = text.length;
425
+ const steps = Math.min(Math.max(1, len), 40);
426
+ const delay = duration / steps;
427
+ write(cursor.hide());
428
+ try {
429
+ for (let i = 1; i <= steps; i++) {
430
+ if (signal?.aborted) break;
431
+ const shown = Math.floor(i / steps * len);
432
+ const line = direction === "right" ? " ".repeat(len - shown) + text.slice(0, shown) : text.slice(0, shown);
433
+ write(cursor.save() + screen.clearRight() + line + cursor.restore());
434
+ await sleep(delay);
435
+ }
436
+ write(cursor.save() + screen.clearRight() + text + cursor.restore());
437
+ } finally {
438
+ write(cursor.show());
439
+ if (newline) writeln();
440
+ }
441
+ };
442
+ var pulse = async (text, opts = {}) => {
443
+ const {
444
+ times = 3,
445
+ interval = 300,
446
+ color1 = { r: 255, g: 255, b: 255 },
447
+ color2 = { r: 100, g: 100, b: 100 },
448
+ newline = true,
449
+ signal,
450
+ reducedMotion = false
451
+ } = opts;
452
+ if (!isTTY() || reducedMotion) {
453
+ write(text);
454
+ if (newline) writeln();
455
+ return;
456
+ }
457
+ const c1 = resolveRgb(color1);
458
+ const c2 = resolveRgb(color2);
459
+ write(cursor.hide());
460
+ try {
461
+ for (let t = 0; t < times; t++) {
462
+ if (signal?.aborted) break;
463
+ write(cursor.save() + fgRgb(c1.r, c1.g, c1.b) + text + reset() + cursor.restore());
464
+ await sleep(interval);
465
+ if (signal?.aborted) break;
466
+ write(cursor.save() + fgRgb(c2.r, c2.g, c2.b) + text + reset() + cursor.restore());
467
+ await sleep(interval);
468
+ }
469
+ write(cursor.save() + fgRgb(c1.r, c1.g, c1.b) + text + reset() + cursor.restore());
470
+ } finally {
471
+ write(cursor.show());
472
+ if (newline) writeln();
473
+ }
474
+ };
475
+ var wave = async (text, opts = {}) => {
476
+ const {
477
+ duration = 2e3,
478
+ steps = 30,
479
+ colors = ["#ff0000", "#ff7f00", "#ffff00", "#00ff00", "#0000ff", "#8b00ff"],
480
+ newline = true,
481
+ signal,
482
+ reducedMotion = false
483
+ } = opts;
484
+ if (!isTTY() || reducedMotion) {
485
+ write(text);
486
+ if (newline) writeln();
487
+ return;
488
+ }
489
+ if (!text.length) {
490
+ if (newline) writeln();
491
+ return;
492
+ }
493
+ const palette = colors.map(hexToRgb);
494
+ const n = safeSteps(steps);
495
+ const delay = duration / n;
496
+ const chars = [...text];
497
+ const len = chars.length;
498
+ write(cursor.hide());
499
+ try {
500
+ for (let frame = 0; frame < n; frame++) {
501
+ if (signal?.aborted) break;
502
+ const offset = frame / n;
503
+ const colored = chars.map((ch, i) => {
504
+ if (ch === " ") return ch;
505
+ const t = (i / len + offset) % 1;
506
+ const scaled = t * (palette.length - 1);
507
+ const lo = Math.floor(scaled);
508
+ const hi = Math.min(lo + 1, palette.length - 1);
509
+ const { r, g, b } = lerpColor(palette[lo], palette[hi], scaled - lo);
510
+ return fgRgb(r, g, b) + ch + reset();
511
+ }).join("");
512
+ write(cursor.save() + screen.clearRight() + colored + cursor.restore());
513
+ await sleep(delay);
514
+ }
515
+ } finally {
516
+ write(cursor.show());
517
+ if (newline) writeln();
518
+ }
519
+ };
520
+ var glitch = async (text, opts = {}) => {
521
+ const { duration = 800, intensity = 3, newline = true, signal, reducedMotion = false } = opts;
522
+ if (!isTTY() || reducedMotion) {
523
+ write(text);
524
+ if (newline) writeln();
525
+ return;
526
+ }
527
+ const glitchChars = "!@#$%^&*[]{}|<>/\\~`\xB1\xA7";
528
+ const end = Date.now() + duration;
529
+ write(cursor.hide());
530
+ try {
531
+ while (Date.now() < end) {
532
+ if (signal?.aborted) break;
533
+ const out = [...text].map((ch) => {
534
+ if (ch === " ") return ch;
535
+ return Math.random() < intensity / 10 ? glitchChars[Math.floor(Math.random() * glitchChars.length)] : ch;
536
+ }).join("");
537
+ write(cursor.save() + screen.clearRight() + out + cursor.restore());
538
+ await sleep(40);
539
+ }
540
+ write(cursor.save() + screen.clearRight() + text + cursor.restore());
541
+ } finally {
542
+ write(cursor.show());
543
+ if (newline) writeln();
544
+ }
545
+ };
546
+ var reveal = async (text, opts = {}) => {
547
+ const {
548
+ duration = 1e3,
549
+ charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
550
+ newline = true,
551
+ signal,
552
+ reducedMotion = false
553
+ } = opts;
554
+ if (!isTTY() || reducedMotion) {
555
+ write(text);
556
+ if (newline) writeln();
557
+ return;
558
+ }
559
+ const len = text.length;
560
+ const n = safeSteps(20);
561
+ const delay = duration / n;
562
+ const solved = new Array(len).fill(false);
563
+ write(cursor.hide());
564
+ try {
565
+ for (let step = 0; step < n; step++) {
566
+ if (signal?.aborted) break;
567
+ const toSolve = Math.floor(step / n * len);
568
+ for (let i = 0; i < toSolve; i++) solved[i] = true;
569
+ const line = [...text].map((ch, i) => {
570
+ if (ch === " ") return " ";
571
+ if (solved[i]) return ch;
572
+ return charset[Math.floor(Math.random() * charset.length)];
573
+ }).join("");
574
+ write(cursor.save() + screen.clearRight() + line + cursor.restore());
575
+ await sleep(delay);
576
+ }
577
+ write(cursor.save() + screen.clearRight() + text + cursor.restore());
578
+ } finally {
579
+ write(cursor.show());
580
+ if (newline) writeln();
581
+ }
582
+ };
583
+ var animate = {
584
+ typewriter,
585
+ fadeIn,
586
+ fadeOut,
587
+ slide,
588
+ pulse,
589
+ wave,
590
+ glitch,
591
+ reveal
592
+ };
593
+
594
+ // src/ascii/index.ts
595
+ var BLOCK = {
596
+ " ": [" ", " ", " ", " ", " "],
597
+ A: [" \u2588\u2588\u2588 ", "\u2588 \u2588", "\u2588\u2588\u2588\u2588\u2588", "\u2588 \u2588", "\u2588 \u2588"],
598
+ B: ["\u2588\u2588\u2588\u2588 ", "\u2588 \u2588", "\u2588\u2588\u2588\u2588 ", "\u2588 \u2588", "\u2588\u2588\u2588\u2588 "],
599
+ C: [" \u2588\u2588\u2588 ", "\u2588 ", "\u2588 ", "\u2588 ", " \u2588\u2588\u2588 "],
600
+ D: ["\u2588\u2588\u2588\u2588 ", "\u2588 \u2588", "\u2588 \u2588", "\u2588 \u2588", "\u2588\u2588\u2588\u2588 "],
601
+ E: ["\u2588\u2588\u2588\u2588\u2588", "\u2588 ", "\u2588\u2588\u2588\u2588 ", "\u2588 ", "\u2588\u2588\u2588\u2588\u2588"],
602
+ F: ["\u2588\u2588\u2588\u2588\u2588", "\u2588 ", "\u2588\u2588\u2588\u2588 ", "\u2588 ", "\u2588 "],
603
+ G: [" \u2588\u2588\u2588\u2588", "\u2588 ", "\u2588 \u2588\u2588", "\u2588 \u2588", " \u2588\u2588\u2588\u2588"],
604
+ H: ["\u2588 \u2588", "\u2588 \u2588", "\u2588\u2588\u2588\u2588\u2588", "\u2588 \u2588", "\u2588 \u2588"],
605
+ I: ["\u2588\u2588\u2588\u2588\u2588", " \u2588 ", " \u2588 ", " \u2588 ", "\u2588\u2588\u2588\u2588\u2588"],
606
+ J: ["\u2588\u2588\u2588\u2588\u2588", " \u2588 ", " \u2588 ", "\u2588 \u2588 ", " \u2588\u2588 "],
607
+ K: ["\u2588 \u2588", "\u2588 \u2588 ", "\u2588\u2588\u2588 ", "\u2588 \u2588 ", "\u2588 \u2588"],
608
+ L: ["\u2588 ", "\u2588 ", "\u2588 ", "\u2588 ", "\u2588\u2588\u2588\u2588\u2588"],
609
+ M: ["\u2588 \u2588", "\u2588\u2588 \u2588\u2588", "\u2588 \u2588 \u2588", "\u2588 \u2588", "\u2588 \u2588"],
610
+ N: ["\u2588 \u2588", "\u2588\u2588 \u2588", "\u2588 \u2588 \u2588", "\u2588 \u2588\u2588", "\u2588 \u2588"],
611
+ O: [" \u2588\u2588\u2588 ", "\u2588 \u2588", "\u2588 \u2588", "\u2588 \u2588", " \u2588\u2588\u2588 "],
612
+ P: ["\u2588\u2588\u2588\u2588 ", "\u2588 \u2588", "\u2588\u2588\u2588\u2588 ", "\u2588 ", "\u2588 "],
613
+ Q: [" \u2588\u2588\u2588 ", "\u2588 \u2588", "\u2588 \u2588 \u2588", "\u2588 \u2588\u2588", " \u2588\u2588\u2588\u2588"],
614
+ R: ["\u2588\u2588\u2588\u2588 ", "\u2588 \u2588", "\u2588\u2588\u2588\u2588 ", "\u2588 \u2588 ", "\u2588 \u2588"],
615
+ S: [" \u2588\u2588\u2588\u2588", "\u2588 ", " \u2588\u2588\u2588 ", " \u2588", "\u2588\u2588\u2588\u2588 "],
616
+ T: ["\u2588\u2588\u2588\u2588\u2588", " \u2588 ", " \u2588 ", " \u2588 ", " \u2588 "],
617
+ U: ["\u2588 \u2588", "\u2588 \u2588", "\u2588 \u2588", "\u2588 \u2588", " \u2588\u2588\u2588 "],
618
+ V: ["\u2588 \u2588", "\u2588 \u2588", "\u2588 \u2588", " \u2588 \u2588 ", " \u2588 "],
619
+ W: ["\u2588 \u2588", "\u2588 \u2588", "\u2588 \u2588 \u2588", "\u2588\u2588 \u2588\u2588", "\u2588 \u2588"],
620
+ X: ["\u2588 \u2588", " \u2588 \u2588 ", " \u2588 ", " \u2588 \u2588 ", "\u2588 \u2588"],
621
+ Y: ["\u2588 \u2588", " \u2588 \u2588 ", " \u2588 ", " \u2588 ", " \u2588 "],
622
+ Z: ["\u2588\u2588\u2588\u2588\u2588", " \u2588 ", " \u2588 ", " \u2588 ", "\u2588\u2588\u2588\u2588\u2588"],
623
+ "0": [" \u2588\u2588\u2588 ", "\u2588 \u2588\u2588", "\u2588 \u2588 \u2588", "\u2588\u2588 \u2588", " \u2588\u2588\u2588 "],
624
+ "1": [" \u2588 ", " \u2588\u2588 ", " \u2588 ", " \u2588 ", "\u2588\u2588\u2588\u2588\u2588"],
625
+ "2": [" \u2588\u2588\u2588 ", "\u2588 \u2588", " \u2588\u2588 ", " \u2588 ", "\u2588\u2588\u2588\u2588\u2588"],
626
+ "3": ["\u2588\u2588\u2588\u2588 ", " \u2588", " \u2588\u2588\u2588 ", " \u2588", "\u2588\u2588\u2588\u2588 "],
627
+ "4": ["\u2588 \u2588", "\u2588 \u2588", "\u2588\u2588\u2588\u2588\u2588", " \u2588", " \u2588"],
628
+ "5": ["\u2588\u2588\u2588\u2588\u2588", "\u2588 ", "\u2588\u2588\u2588\u2588 ", " \u2588", "\u2588\u2588\u2588\u2588 "],
629
+ "6": [" \u2588\u2588\u2588 ", "\u2588 ", "\u2588\u2588\u2588\u2588 ", "\u2588 \u2588", " \u2588\u2588\u2588 "],
630
+ "7": ["\u2588\u2588\u2588\u2588\u2588", " \u2588 ", " \u2588 ", " \u2588 ", "\u2588 "],
631
+ "8": [" \u2588\u2588\u2588 ", "\u2588 \u2588", " \u2588\u2588\u2588 ", "\u2588 \u2588", " \u2588\u2588\u2588 "],
632
+ "9": [" \u2588\u2588\u2588 ", "\u2588 \u2588", " \u2588\u2588\u2588\u2588", " \u2588", " \u2588\u2588\u2588 "],
633
+ "!": [" \u2588 ", " \u2588 ", " \u2588 ", " ", " \u2588 "],
634
+ "?": [" \u2588\u2588\u2588 ", "\u2588 \u2588", " \u2588 ", " ", " \u2588 "],
635
+ ".": [" ", " ", " ", " ", " \u2588 "],
636
+ "-": [" ", " ", "\u2588\u2588\u2588\u2588 ", " ", " "],
637
+ "+": [" ", " \u2588 ", "\u2588\u2588\u2588\u2588\u2588", " \u2588 ", " "],
638
+ "#": [" \u2588 \u2588 ", "\u2588\u2588\u2588\u2588\u2588", " \u2588 \u2588 ", "\u2588\u2588\u2588\u2588\u2588", " \u2588 \u2588 "],
639
+ "@": [" \u2588\u2588\u2588 ", "\u2588 \u2588", "\u2588 \u2588\u2588 ", "\u2588 ", " \u2588\u2588\u2588\u2588"]
640
+ };
641
+ var SMALL = {
642
+ " ": [" ", " ", " "],
643
+ A: ["\u2584\u2580\u2584", "\u2588\u2580\u2588", "\u2580 \u2580"],
644
+ B: ["\u2588\u2580\u2584", "\u2588\u2580\u2584", "\u2580\u2580 "],
645
+ C: ["\u2584\u2580\u2580", "\u2588 ", "\u2580\u2580\u2584"],
646
+ D: ["\u2588\u2580\u2584", "\u2588 \u2588", "\u2580\u2580 "],
647
+ E: ["\u2588\u2580\u2580", "\u2588\u2580 ", "\u2580\u2580\u2580"],
648
+ F: ["\u2588\u2580\u2580", "\u2588\u2580 ", "\u2580 "],
649
+ G: ["\u2584\u2580\u2580", "\u2588 \u2584", "\u2580\u2580\u2598"],
650
+ H: ["\u2588 \u2588", "\u2588\u2588\u2588", "\u2580 \u2580"],
651
+ I: ["\u2580\u2588\u2580", " \u2588 ", "\u2580\u2588\u2580"],
652
+ J: [" \u2584\u2588", " \u2588", "\u2580\u2580 "],
653
+ K: ["\u2588\u2584\u2580", "\u2588\u2580\u2584", "\u2580 \u2580"],
654
+ L: ["\u2588 ", "\u2588 ", "\u2580\u2580\u2580"],
655
+ M: ["\u2588\u2584\u2588", "\u2588 \u2588", "\u2580 \u2580"],
656
+ N: ["\u2588\u2584\u2588", "\u2588\u2580\u2588", "\u2580 \u2580"],
657
+ O: ["\u2584\u2580\u2584", "\u2588 \u2588", "\u2580\u2584\u2580"],
658
+ P: ["\u2588\u2580\u2584", "\u2588\u2588 ", "\u2580 "],
659
+ Q: ["\u2584\u2580\u2584", "\u2588\u2584\u2588", "\u2580\u2584\u2580"],
660
+ R: ["\u2588\u2580\u2584", "\u2588\u2588\u2584", "\u2580 \u2580"],
661
+ S: ["\u2584\u2580\u2580", "\u2580\u2580\u2584", "\u2584\u2584\u2598"],
662
+ T: ["\u2580\u2588\u2580", " \u2588 ", " \u2580 "],
663
+ U: ["\u2588 \u2588", "\u2588 \u2588", "\u2580\u2584\u2580"],
664
+ V: ["\u2588 \u2588", "\u2588 \u2588", " \u2580 "],
665
+ W: ["\u2588 \u2588", "\u2588\u2584\u2588", "\u2580 \u2580"],
666
+ X: ["\u2580\u2584\u2580", " \u2588 ", "\u2580 \u2580"],
667
+ Y: ["\u2580\u2584\u2580", " \u2588 ", " \u2580 "],
668
+ Z: ["\u2580\u2580\u2588", " \u2588 ", "\u2588\u2580\u2580"],
669
+ "0": ["\u2584\u2580\u2584", "\u2588 \u2588", "\u2580\u2584\u2580"],
670
+ "1": [" \u2588 ", " \u2588 ", " \u2588 "],
671
+ "2": ["\u2584\u2580\u2584", " \u2584\u2580", "\u2580\u2580\u2580"],
672
+ "3": ["\u2580\u2580\u2584", " \u2580\u2584", "\u2584\u2584\u2598"],
673
+ "4": ["\u2588\u2584\u2588", " \u2588", " \u2580"],
674
+ "5": ["\u2588\u2580\u2580", "\u2580\u2580\u2584", "\u2584\u2584\u2598"],
675
+ "6": ["\u2584\u2580 ", "\u2588\u2580\u2584", "\u2580\u2584\u2580"],
676
+ "7": ["\u2580\u2580\u2588", " \u2588", " \u2580"],
677
+ "8": ["\u2584\u2580\u2584", "\u2584\u2580\u2584", "\u2580\u2584\u2580"],
678
+ "9": ["\u2584\u2580\u2584", "\u2580\u2580\u2588", " \u2584\u2598"],
679
+ "!": [" \u2588 ", " \u2588 ", " \u25AA "],
680
+ "?": ["\u2584\u2580\u2584", " \u2584\u2598", " \u25AA "],
681
+ ".": [" ", " ", " \u25AA "],
682
+ "-": [" ", "\u2500\u2500\u2500", " "],
683
+ ":": [" \u25AA ", " ", " \u25AA "]
684
+ };
685
+ var renderFont = (text, fontMap) => {
686
+ if (!text.length) return "";
687
+ const sampleChar = fontMap[" "];
688
+ const charWidth = sampleChar[0].length;
689
+ const empty = " ".repeat(charWidth);
690
+ const chars = text.toUpperCase().split("").map((c) => fontMap[c] ?? fontMap["?"] ?? [empty]);
691
+ const height = chars[0].length;
692
+ const lines = [];
693
+ for (let row = 0; row < height; row++) {
694
+ lines.push(chars.map((c) => c[row] ?? empty).join(" "));
695
+ }
696
+ return lines.join("\n");
697
+ };
698
+ var BOX_STYLES = {
699
+ single: { tl: "\u250C", tr: "\u2510", bl: "\u2514", br: "\u2518", h: "\u2500", v: "\u2502" },
700
+ double: { tl: "\u2554", tr: "\u2557", bl: "\u255A", br: "\u255D", h: "\u2550", v: "\u2551" },
701
+ rounded: { tl: "\u256D", tr: "\u256E", bl: "\u2570", br: "\u256F", h: "\u2500", v: "\u2502" },
702
+ heavy: { tl: "\u250F", tr: "\u2513", bl: "\u2517", br: "\u251B", h: "\u2501", v: "\u2503" },
703
+ dashed: { tl: "\u250C", tr: "\u2510", bl: "\u2514", br: "\u2518", h: "\u254C", v: "\u254E" },
704
+ ascii: { tl: "+", tr: "+", bl: "+", br: "+", h: "-", v: "|" }
705
+ };
706
+ var big = (text) => renderFont(text, BLOCK);
707
+ var small = (text) => renderFont(text, SMALL);
708
+ var figlet = (text, opts = {}) => opts.font === "small" ? small(text) : big(text);
709
+ var banner = (text, opts = {}) => {
710
+ const { font = "big", colorFn = null, align = "left" } = opts;
711
+ let rendered = font === "small" ? small(text) : big(text);
712
+ if (align === "center") {
713
+ const { cols } = termSize();
714
+ rendered = rendered.split("\n").map((l) => center(l, cols)).join("\n");
715
+ }
716
+ if (colorFn) rendered = rendered.split("\n").map(colorFn).join("\n");
717
+ return rendered;
718
+ };
719
+ var box = (text, opts = {}) => {
720
+ const { padding = 1, borderStyle = "rounded", width = null } = opts;
721
+ const b = BOX_STYLES[borderStyle] ?? BOX_STYLES.rounded;
722
+ const lines = text.split("\n");
723
+ const inner = width != null ? lines.map((l) => padEnd(truncateAnsi(l, width, ""), width)) : lines;
724
+ const w = Math.max(...inner.map((l) => visibleLen(l)), 0);
725
+ const pad = " ".repeat(padding);
726
+ const top = b.tl + b.h.repeat(w + padding * 2) + b.tr;
727
+ const bottom = b.bl + b.h.repeat(w + padding * 2) + b.br;
728
+ const emptyRow = b.v + " ".repeat(w + padding * 2) + b.v;
729
+ const rows = inner.map((l) => b.v + pad + padEnd(l, w) + pad + b.v);
730
+ const vPad = Array(padding).fill(emptyRow);
731
+ return [top, ...vPad, ...rows, ...vPad, bottom].join("\n");
732
+ };
733
+ var divider = (opts = {}) => {
734
+ const { char, width = null, label = null, style = "single" } = opts;
735
+ const { cols } = termSize();
736
+ const w = width ?? cols;
737
+ const b = BOX_STYLES[style] ?? BOX_STYLES.single;
738
+ const fill = char ?? b.h;
739
+ if (label) {
740
+ const labelLen = visibleLen(label);
741
+ const side = Math.max(0, Math.floor((w - labelLen - 2) / 2));
742
+ const trailLen = Math.max(0, w - side - labelLen - 2);
743
+ return fill.repeat(side) + " " + label + " " + fill.repeat(trailLen);
744
+ }
745
+ return fill.repeat(Math.max(0, w));
746
+ };
747
+ var logo = (text, opts = {}) => {
748
+ const { gradient: gfn = null, boxStyle = "double" } = opts;
749
+ const art = big(text);
750
+ const lines = art.split("\n").map((l) => gfn ? gfn(l) : l);
751
+ return box(lines.join("\n"), { borderStyle: boxStyle, padding: 1 });
752
+ };
753
+ var ascii = {
754
+ big,
755
+ small,
756
+ figlet,
757
+ banner,
758
+ box,
759
+ divider,
760
+ logo,
761
+ boxStyles: Object.keys(BOX_STYLES)
762
+ };
763
+
764
+ // src/loaders/index.ts
765
+ var isTTY2 = () => Boolean(process.stdout.isTTY);
766
+ var HEX_RE3 = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
767
+ var safeColor = (hex) => {
768
+ if (!hex || !HEX_RE3.test(hex.trim())) return null;
769
+ return hexToRgb(hex);
770
+ };
771
+ var SPINNERS = {
772
+ dots: ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"],
773
+ dots2: ["\u28FE", "\u28FD", "\u28FB", "\u28BF", "\u287F", "\u28DF", "\u28EF", "\u28F7"],
774
+ line: ["-", "\\", "|", "/"],
775
+ arrow: ["\u2190", "\u2196", "\u2191", "\u2197", "\u2192", "\u2198", "\u2193", "\u2199"],
776
+ bounce: ["\u2801", "\u2802", "\u2804", "\u2802"],
777
+ star: ["\u2736", "\u2738", "\u2739", "\u273A", "\u2739", "\u2737"],
778
+ moon: ["\u{1F311}", "\u{1F312}", "\u{1F313}", "\u{1F314}", "\u{1F315}", "\u{1F316}", "\u{1F317}", "\u{1F318}"],
779
+ clock: ["\u{1F55B}", "\u{1F550}", "\u{1F551}", "\u{1F552}", "\u{1F553}", "\u{1F554}", "\u{1F555}", "\u{1F556}", "\u{1F557}", "\u{1F558}", "\u{1F559}", "\u{1F55A}"],
780
+ pong: [
781
+ "\u2590\u2802 \u258C",
782
+ "\u2590\u2808 \u258C",
783
+ "\u2590 \u2802 \u258C",
784
+ "\u2590 \u2820 \u258C",
785
+ "\u2590 \u2840 \u258C",
786
+ "\u2590 \u2820 \u258C",
787
+ "\u2590 \u2802 \u258C",
788
+ "\u2590 \u2808 \u258C",
789
+ "\u2590 \u2802 \u258C",
790
+ "\u2590 \u2820 \u258C",
791
+ "\u2590 \u2840 \u258C",
792
+ "\u2590 \u2820 \u258C",
793
+ "\u2590 \u2802 \u258C",
794
+ "\u2590 \u2808 \u258C",
795
+ "\u2590 \u2802\u258C",
796
+ "\u2590 \u2820\u258C",
797
+ "\u2590 \u2840\u258C",
798
+ "\u2590 \u2820 \u258C",
799
+ "\u2590 \u2802 \u258C",
800
+ "\u2590 \u2808 \u258C"
801
+ ],
802
+ aesthetic: ["\u25B0\u25B1\u25B1\u25B1\u25B1\u25B1\u25B1", "\u25B0\u25B0\u25B1\u25B1\u25B1\u25B1\u25B1", "\u25B0\u25B0\u25B0\u25B1\u25B1\u25B1\u25B1", "\u25B0\u25B0\u25B0\u25B0\u25B1\u25B1\u25B1", "\u25B0\u25B0\u25B0\u25B0\u25B0\u25B1\u25B1", "\u25B0\u25B0\u25B0\u25B0\u25B0\u25B0\u25B1", "\u25B0\u25B0\u25B0\u25B0\u25B0\u25B0\u25B0"],
803
+ blocks: ["\u2588\u2592\u2592\u2592\u2592\u2592\u2592", "\u2588\u2588\u2592\u2592\u2592\u2592\u2592", "\u2588\u2588\u2588\u2592\u2592\u2592\u2592", "\u2588\u2588\u2588\u2588\u2592\u2592\u2592", "\u2588\u2588\u2588\u2588\u2588\u2592\u2592", "\u2588\u2588\u2588\u2588\u2588\u2588\u2592", "\u2588\u2588\u2588\u2588\u2588\u2588\u2588"]
804
+ };
805
+ var spin = (text = "Loading...", opts = {}) => {
806
+ const {
807
+ type = "dots",
808
+ interval = 80,
809
+ color: colorStr = null,
810
+ prefix = "",
811
+ suffix = "",
812
+ persist = false,
813
+ signal,
814
+ reducedMotion = false
815
+ } = opts;
816
+ if (!isTTY2() || reducedMotion) {
817
+ write(text + "\n");
818
+ return (message, success = true) => {
819
+ if (!message) return;
820
+ const icon = success ? "\u2713" : "\u2717";
821
+ const clr = success ? `${sgr(FG.green)}${icon}${reset()}` : `${sgr(FG.red)}${icon}${reset()}`;
822
+ writeln(`${clr} ${message}`);
823
+ };
824
+ }
825
+ const frames2 = SPINNERS[type] ?? SPINNERS.dots;
826
+ const rgb = safeColor(colorStr);
827
+ let i = 0;
828
+ let stopped = false;
829
+ let timer;
830
+ write(cursor.hide());
831
+ const stop = (message, success = true) => {
832
+ if (stopped) return;
833
+ stopped = true;
834
+ clearInterval(timer);
835
+ if (abortHandler) signal?.removeEventListener("abort", abortHandler);
836
+ write(cursor.show() + screen.clearLine() + "\r");
837
+ if (message) {
838
+ const icon = success ? "\u2713" : "\u2717";
839
+ const clr = success ? `${sgr(FG.green)}${icon}${reset()}` : `${sgr(FG.red)}${icon}${reset()}`;
840
+ writeln(`${clr} ${message}`);
841
+ } else if (persist) {
842
+ writeln(` ${text}`);
843
+ }
844
+ };
845
+ const abortHandler = signal ? () => stop("Cancelled", false) : null;
846
+ if (abortHandler) signal?.addEventListener("abort", abortHandler, { once: true });
847
+ timer = setInterval(() => {
848
+ if (stopped) return;
849
+ if (signal?.aborted) {
850
+ stop();
851
+ return;
852
+ }
853
+ const frame = frames2[i % frames2.length];
854
+ const colored = rgb ? fgRgb(rgb.r, rgb.g, rgb.b) + frame + reset() : frame;
855
+ write(cursor.save() + screen.clearLine() + `\r${prefix}${colored} ${text}${suffix}` + cursor.restore());
856
+ i++;
857
+ }, interval);
858
+ return stop;
859
+ };
860
+ var dots = (text = "Processing", opts = {}) => {
861
+ const { interval = 400, max = 3, signal } = opts;
862
+ if (!isTTY2()) {
863
+ write(text + "\n");
864
+ return () => {
865
+ };
866
+ }
867
+ let i = 0;
868
+ let stopped = false;
869
+ write(cursor.hide());
870
+ const stop = () => {
871
+ if (stopped) return;
872
+ stopped = true;
873
+ clearInterval(timer);
874
+ write(cursor.show() + screen.clearLine() + "\r");
875
+ };
876
+ if (signal) signal.addEventListener("abort", stop, { once: true });
877
+ const timer = setInterval(() => {
878
+ if (stopped) return;
879
+ const d = ".".repeat(i % max + 1).padEnd(max);
880
+ write(cursor.save() + screen.clearLine() + `\r${text}${d}` + cursor.restore());
881
+ i++;
882
+ }, interval);
883
+ return stop;
884
+ };
885
+ var progress = (percent, label = "", opts = {}) => {
886
+ const {
887
+ width = 30,
888
+ char = "\u2588",
889
+ emptyChar = "\u2591",
890
+ showPercentage = true,
891
+ color: colorStr = null
892
+ } = opts;
893
+ const safeWidth = Math.max(1, width);
894
+ const clamped = Math.min(100, Math.max(0, percent));
895
+ const filled = Math.round(clamped / 100 * safeWidth);
896
+ const empty = safeWidth - filled;
897
+ const rgb = safeColor(colorStr);
898
+ let filledStr = char.repeat(filled);
899
+ const emptyStr = emptyChar.repeat(empty);
900
+ if (rgb) filledStr = fgRgb(rgb.r, rgb.g, rgb.b) + filledStr + reset();
901
+ const pct = showPercentage ? ` ${String(Math.round(clamped)).padStart(3)}%` : "";
902
+ const lbl = label ? ` ${label}` : "";
903
+ write(screen.clearLine() + `\r[${filledStr}${emptyStr}]${pct}${lbl}`);
904
+ };
905
+ var progressAnimate = async (steps, label = "", opts = {}) => {
906
+ const { delay = 100, signal, ...barOpts } = opts;
907
+ const safeSteps2 = Math.max(1, steps);
908
+ write(cursor.hide());
909
+ try {
910
+ for (let i = 0; i <= safeSteps2; i++) {
911
+ if (signal?.aborted) break;
912
+ progress(i / safeSteps2 * 100, label, barOpts);
913
+ await sleep(delay);
914
+ }
915
+ writeln();
916
+ } finally {
917
+ write(cursor.show());
918
+ }
919
+ };
920
+ var tasks = async (taskList, opts = {}) => {
921
+ const { type = "dots", spinColor = "#00ff88", parallel = false } = opts;
922
+ if (!taskList.length) return [];
923
+ const runTask = async ({ text, fn }) => {
924
+ const stop = spin(text, { type, color: spinColor, reducedMotion: parallel });
925
+ try {
926
+ const result = await fn();
927
+ stop(text, true);
928
+ return { success: true, result };
929
+ } catch (err) {
930
+ stop(`${text} \u2014 ${err.message}`, false);
931
+ return { success: false, error: err };
932
+ }
933
+ };
934
+ if (parallel) {
935
+ return Promise.all(taskList.map(runTask));
936
+ }
937
+ const results = [];
938
+ for (const task of taskList) {
939
+ results.push(await runTask(task));
940
+ }
941
+ return results;
942
+ };
943
+ var custom = (frames2, text = "", opts = {}) => {
944
+ const { interval = 100, signal } = opts;
945
+ if (!frames2.length) throw new Error("custom: frames cannot be empty");
946
+ if (!isTTY2()) {
947
+ write(text + "\n");
948
+ return () => {
949
+ };
950
+ }
951
+ let i = 0;
952
+ let stopped = false;
953
+ write(cursor.hide());
954
+ const stop = () => {
955
+ if (stopped) return;
956
+ stopped = true;
957
+ clearInterval(timer);
958
+ write(cursor.show() + screen.clearLine() + "\r");
959
+ };
960
+ if (signal) signal.addEventListener("abort", stop, { once: true });
961
+ const timer = setInterval(() => {
962
+ if (stopped) return;
963
+ write(cursor.save() + screen.clearLine() + `\r${frames2[i % frames2.length]} ${text}` + cursor.restore());
964
+ i++;
965
+ }, interval);
966
+ return stop;
967
+ };
968
+ var countdown = async (seconds, opts = {}) => {
969
+ const { label = "Starting in", color: colorStr = "#ffd700", signal } = opts;
970
+ const rgb = safeColor(colorStr) ?? { r: 255, g: 215, b: 0 };
971
+ write(cursor.hide());
972
+ try {
973
+ for (let s = seconds; s >= 0; s--) {
974
+ if (signal?.aborted) break;
975
+ write(screen.clearLine() + `\r${label} ${fgRgb(rgb.r, rgb.g, rgb.b)}${s}${reset()}s`);
976
+ if (s > 0) await sleep(1e3);
977
+ }
978
+ write(screen.clearLine() + "\r");
979
+ } finally {
980
+ write(cursor.show());
981
+ }
982
+ };
983
+ var loader = {
984
+ spin,
985
+ dots,
986
+ progress,
987
+ progressAnimate,
988
+ tasks,
989
+ custom,
990
+ countdown,
991
+ spinners: SPINNERS
992
+ };
993
+
994
+ // src/frames/index.ts
995
+ var lineCount = (frame) => frame.split("\n").length;
996
+ var clearLines = (n) => {
997
+ for (let i = 0; i < n; i++) {
998
+ write("\r" + screen.clearLine() + cursor.up(1));
999
+ }
1000
+ };
1001
+ var play = async (frames2, opts = {}) => {
1002
+ const {
1003
+ interval = 100,
1004
+ repeat = 1,
1005
+ clearOnFinish = false,
1006
+ onFrame = null,
1007
+ signal
1008
+ } = opts;
1009
+ if (!frames2 || frames2.length === 0) return;
1010
+ const safeRepeat = Math.max(0, repeat);
1011
+ const infinite = repeat === 0;
1012
+ let lastLines = 0;
1013
+ let iteration = 0;
1014
+ const renderFrame = (frame, idx) => {
1015
+ if (lastLines > 0) clearLines(lastLines);
1016
+ const rendered = onFrame ? onFrame(frame, idx) : frame;
1017
+ write(rendered);
1018
+ lastLines = lineCount(rendered) + (rendered.endsWith("\n") ? 0 : 1);
1019
+ if (!rendered.endsWith("\n")) writeln();
1020
+ };
1021
+ write(cursor.hide());
1022
+ try {
1023
+ while (infinite || iteration < safeRepeat) {
1024
+ for (let i = 0; i < frames2.length; i++) {
1025
+ if (signal?.aborted) return;
1026
+ renderFrame(frames2[i], i);
1027
+ await sleep(interval);
1028
+ }
1029
+ iteration++;
1030
+ if (!infinite && iteration >= safeRepeat) break;
1031
+ }
1032
+ if (clearOnFinish && lastLines > 0) clearLines(lastLines);
1033
+ } finally {
1034
+ write(cursor.show());
1035
+ }
1036
+ };
1037
+ var generate = (count, fn) => Array.from({ length: Math.max(0, count) }, (_, i) => fn(i, count));
1038
+ var live = (opts = {}) => {
1039
+ const { fps = 12, autoStart = true } = opts;
1040
+ const safeFps = Math.max(1, fps);
1041
+ const interval = Math.floor(1e3 / safeFps);
1042
+ let currentFrame = "";
1043
+ let lastLines = 0;
1044
+ let running = false;
1045
+ let timer = null;
1046
+ const render = () => {
1047
+ if (lastLines > 0) clearLines(lastLines);
1048
+ write(currentFrame);
1049
+ lastLines = lineCount(currentFrame) + (currentFrame.endsWith("\n") ? 0 : 1);
1050
+ if (!currentFrame.endsWith("\n")) writeln();
1051
+ };
1052
+ const start = () => {
1053
+ if (running) return;
1054
+ running = true;
1055
+ write(cursor.hide());
1056
+ timer = setInterval(render, interval);
1057
+ };
1058
+ const stop = () => {
1059
+ running = false;
1060
+ if (timer) {
1061
+ clearInterval(timer);
1062
+ timer = null;
1063
+ }
1064
+ write(cursor.show());
1065
+ };
1066
+ const update = (newFrame) => {
1067
+ currentFrame = newFrame;
1068
+ if (running) render();
1069
+ };
1070
+ if (autoStart) start();
1071
+ return { start, stop, update };
1072
+ };
1073
+ var morph = (frameA, frameB, steps = 8, charset = "\u2591\u2592\u2593\u2588\u2593\u2592\u2591") => {
1074
+ const n = Math.max(2, steps);
1075
+ const len = Math.max(frameA.length, frameB.length);
1076
+ const a = frameA.padEnd(len);
1077
+ const b = frameB.padEnd(len);
1078
+ return generate(n, (i) => {
1079
+ const t = i / (n - 1);
1080
+ return [...Array(len)].map((_, ci) => {
1081
+ const ca = a[ci];
1082
+ const cb = b[ci];
1083
+ if (t === 0) return ca;
1084
+ if (t === 1) return cb;
1085
+ if (ca !== cb) {
1086
+ if (!charset.length) return "\u2591";
1087
+ const idx = Math.floor(t * charset.length) % charset.length;
1088
+ return charset[idx];
1089
+ }
1090
+ return ca;
1091
+ }).join("");
1092
+ });
1093
+ };
1094
+ var presets2 = {
1095
+ loadingBar: (opts = {}) => {
1096
+ const { width = 20, char = "\u2588", empty = "\u2591", label = "Loading" } = opts;
1097
+ return generate(width + 1, (i) => {
1098
+ const filled = char.repeat(i);
1099
+ const rest = empty.repeat(width - i);
1100
+ const pct = Math.round(i / width * 100);
1101
+ return `${label} [${filled}${rest}] ${pct}%`;
1102
+ });
1103
+ },
1104
+ ball: (opts = {}) => {
1105
+ const { width = 20, char = "\u25CF" } = opts;
1106
+ const forward = generate(width, (i) => " ".repeat(i) + char);
1107
+ const backward = generate(width, (i) => " ".repeat(width - i - 1) + char);
1108
+ return [...forward, ...backward.slice(1, -1).reverse()];
1109
+ },
1110
+ breathe: (text, opts = {}) => {
1111
+ const { steps = 8 } = opts;
1112
+ const shades = ["\u2591", "\u2592", "\u2593", "\u2588"];
1113
+ return generate(steps * 2, (i) => {
1114
+ const t = i < steps ? i / steps : 1 - (i - steps) / steps;
1115
+ const shade = shades[Math.min(shades.length - 1, Math.floor(t * shades.length))];
1116
+ return text.split("").map((ch) => ch === " " ? " " : shade).join("");
1117
+ });
1118
+ },
1119
+ typeDelete: (text, opts = {}) => {
1120
+ const { cursor: cur = "\u258C" } = opts;
1121
+ const typed = generate(text.length + 1, (i) => text.slice(0, i) + cur);
1122
+ const deleted = generate(text.length + 1, (i) => text.slice(0, text.length - i) + cur);
1123
+ return [...typed, ...deleted];
1124
+ }
1125
+ };
1126
+ var frames = { play, generate, live, morph, presets: presets2 };
1127
+
1128
+ // src/components/index.ts
1129
+ var TABLE_BORDERS = {
1130
+ single: { tl: "\u250C", tr: "\u2510", bl: "\u2514", br: "\u2518", h: "\u2500", v: "\u2502", ml: "\u251C", mr: "\u2524", mt: "\u252C", mb: "\u2534", cx: "\u253C" },
1131
+ double: { tl: "\u2554", tr: "\u2557", bl: "\u255A", br: "\u255D", h: "\u2550", v: "\u2551", ml: "\u2560", mr: "\u2563", mt: "\u2566", mb: "\u2569", cx: "\u256C" },
1132
+ rounded: { tl: "\u256D", tr: "\u256E", bl: "\u2570", br: "\u256F", h: "\u2500", v: "\u2502", ml: "\u251C", mr: "\u2524", mt: "\u252C", mb: "\u2534", cx: "\u253C" },
1133
+ heavy: { tl: "\u250F", tr: "\u2513", bl: "\u2517", br: "\u251B", h: "\u2501", v: "\u2503", ml: "\u2523", mr: "\u252B", mt: "\u2533", mb: "\u253B", cx: "\u254B" }
1134
+ };
1135
+ var table = (rows, opts = {}) => {
1136
+ const { header = true, borderStyle = "rounded", padding = 1 } = opts;
1137
+ if (!rows || rows.length === 0) return "";
1138
+ const b = TABLE_BORDERS[borderStyle] ?? TABLE_BORDERS.rounded;
1139
+ const pad = " ".repeat(padding);
1140
+ const cols = Math.max(...rows.map((r) => r.length), 0);
1141
+ const widths = Array.from(
1142
+ { length: cols },
1143
+ (_, ci) => Math.max(...rows.map((r) => visibleLen(String(r[ci] ?? ""))))
1144
+ );
1145
+ const rowSep = (left, mid, right, fill) => left + widths.map((w) => fill.repeat(w + padding * 2)).join(mid) + right;
1146
+ const renderRow = (row, isHeader = false) => {
1147
+ const cells = row.map((cell, ci) => {
1148
+ let s = padEnd(String(cell ?? ""), widths[ci] ?? 0);
1149
+ if (isHeader) s = sgr(STYLE.bold) + s + reset();
1150
+ return pad + s + pad;
1151
+ });
1152
+ return b.v + cells.join(b.v) + b.v;
1153
+ };
1154
+ const lines = [];
1155
+ lines.push(rowSep(b.tl, b.mt, b.tr, b.h));
1156
+ rows.forEach((row, ri) => {
1157
+ lines.push(renderRow(row, ri === 0 && header));
1158
+ if (ri === 0 && header && rows.length > 1) lines.push(rowSep(b.ml, b.cx, b.mr, b.h));
1159
+ });
1160
+ lines.push(rowSep(b.bl, b.mb, b.br, b.h));
1161
+ return lines.join("\n");
1162
+ };
1163
+ var badge = (label, value, opts = {}) => {
1164
+ const { labelBg = BG.blue, valueBg = BG.green, labelFg = FG.white, valueFg = FG.white } = opts;
1165
+ return sgr(labelBg, labelFg) + ` ${label} ` + reset() + sgr(valueBg, valueFg) + ` ${value} ` + reset();
1166
+ };
1167
+ var progressBar = (percent, opts = {}) => {
1168
+ const { width = 30, char = "\u2588", emptyChar = "\u2591", showPercentage = true, label = "", color: color2 = null } = opts;
1169
+ const clamped = Math.min(100, Math.max(0, percent));
1170
+ const filled = Math.round(clamped / 100 * width);
1171
+ const empty = width - filled;
1172
+ let filledStr = char.repeat(filled);
1173
+ const emptyStr = emptyChar.repeat(empty);
1174
+ if (color2 !== null) filledStr = sgr(color2) + filledStr + reset();
1175
+ const pct = showPercentage ? ` ${String(Math.round(clamped)).padStart(3)}%` : "";
1176
+ const lbl = label ? ` ${label}` : "";
1177
+ return `[${filledStr}${emptyStr}]${pct}${lbl}`;
1178
+ };
1179
+ var STATUS_MAP = {
1180
+ success: { icon: "\u2713", color: FG.green },
1181
+ error: { icon: "\u2717", color: FG.red },
1182
+ warn: { icon: "\u26A0", color: FG.yellow },
1183
+ info: { icon: "\u2139", color: FG.cyan },
1184
+ wait: { icon: "\u25CC", color: FG.brightBlack }
1185
+ };
1186
+ var status = (type, message) => {
1187
+ const { icon, color: color2 } = STATUS_MAP[type] ?? STATUS_MAP.info;
1188
+ return sgr(color2) + icon + reset() + " " + message;
1189
+ };
1190
+ var section = (title, opts = {}) => {
1191
+ const { char = "\u2500", width = null, color: colorCode = FG.cyan } = opts;
1192
+ const { cols } = termSize();
1193
+ const w = Math.max(width ?? cols, title.length + 2);
1194
+ const side = Math.floor((w - title.length - 2) / 2);
1195
+ const divider2 = sgr(colorCode) + char.repeat(side) + reset();
1196
+ const t = sgr(STYLE.bold, colorCode) + title + reset();
1197
+ const trail = sgr(colorCode) + char.repeat(Math.max(0, w - side - title.length - 2)) + reset();
1198
+ return divider2 + " " + t + " " + trail;
1199
+ };
1200
+ var columns = (items, opts = {}) => {
1201
+ const { cols: numCols = 2, gap = 2, width = null } = opts;
1202
+ if (numCols < 1) throw new Error("columns: cols must be >= 1");
1203
+ const { cols: termCols } = termSize();
1204
+ const totalW = width ?? termCols;
1205
+ const colW = Math.floor((totalW - gap * (numCols - 1)) / numCols);
1206
+ const rows = [];
1207
+ for (let i = 0; i < items.length; i += numCols) {
1208
+ const chunk = items.slice(i, i + numCols);
1209
+ rows.push(chunk.map((item) => padEnd(String(item), colW)).join(" ".repeat(gap)));
1210
+ }
1211
+ return rows.join("\n");
1212
+ };
1213
+ var timeline = (events, opts = {}) => {
1214
+ const {
1215
+ connector = "\u2502",
1216
+ node = "\u25CF",
1217
+ color: colorCode = FG.cyan,
1218
+ doneColor = FG.green,
1219
+ pendingColor = FG.brightBlack
1220
+ } = opts;
1221
+ const lines = [];
1222
+ events.forEach((ev, i) => {
1223
+ const isLast = i === events.length - 1;
1224
+ const clr = ev.done ? doneColor : i === 0 ? colorCode : pendingColor;
1225
+ const nodeStr = sgr(clr) + node + reset();
1226
+ const textStr = ev.done ? sgr(STYLE.bold) + ev.label + reset() : sgr(pendingColor) + ev.label + reset();
1227
+ lines.push(`${nodeStr} ${textStr}${ev.time ? sgr(FG.brightBlack) + " " + ev.time + reset() : ""}`);
1228
+ if (!isLast) lines.push(sgr(pendingColor) + connector + reset());
1229
+ });
1230
+ return lines.join("\n");
1231
+ };
1232
+ var MENU_CANCELLED = /* @__PURE__ */ Symbol("MENU_CANCELLED");
1233
+ var menu = (items, opts = {}) => {
1234
+ const {
1235
+ title = null,
1236
+ pointer = "\u25B6",
1237
+ multiSelect = false,
1238
+ color: colorCode = FG.cyan,
1239
+ input: inp = process.stdin,
1240
+ output: out = { write: (s) => process.stdout.write(s) }
1241
+ } = opts;
1242
+ if (!items.length) throw new Error("menu requires at least one item");
1243
+ if (!inp.isTTY) return Promise.resolve(multiSelect ? [] : 0);
1244
+ let cursorPos = 0;
1245
+ const selected = /* @__PURE__ */ new Set();
1246
+ const emit = (str) => {
1247
+ out.write(str);
1248
+ };
1249
+ const render = () => {
1250
+ if (title) emit(sgr(STYLE.bold) + title + reset() + "\n");
1251
+ items.forEach((item, i) => {
1252
+ const isActive = i === cursorPos;
1253
+ const isSelected = selected.has(i);
1254
+ const ptr = isActive ? sgr(colorCode) + pointer + reset() : " ";
1255
+ const sel = multiSelect ? isSelected ? sgr(colorCode) + "\u25CF" + reset() : "\u25CB" : "";
1256
+ const txt = isActive ? sgr(STYLE.bold, colorCode) + item + reset() : item;
1257
+ emit(`${ptr} ${sel}${multiSelect ? " " : ""}${txt}
1258
+ `);
1259
+ });
1260
+ };
1261
+ const clearLines2 = () => {
1262
+ const lines = items.length + (title ? 1 : 0);
1263
+ for (let i = 0; i < lines; i++) emit(cursor.up(1) + screen.clearLine());
1264
+ emit("\r");
1265
+ };
1266
+ const cleanup = (onKey) => {
1267
+ inp.removeListener("data", onKey);
1268
+ if (inp.setRawMode) inp.setRawMode(false);
1269
+ emit(cursor.show());
1270
+ };
1271
+ emit(cursor.hide());
1272
+ render();
1273
+ return new Promise((resolve) => {
1274
+ const onKey = (...args) => {
1275
+ const key = args[0];
1276
+ const k = key.toString();
1277
+ const KEY_UP = "\x1B[A";
1278
+ const KEY_DOWN = "\x1B[B";
1279
+ const KEY_ENTER = "\r";
1280
+ const KEY_SPACE = " ";
1281
+ const KEY_CTRL_C = "";
1282
+ if (k === KEY_CTRL_C) {
1283
+ clearLines2();
1284
+ cleanup(onKey);
1285
+ resolve(MENU_CANCELLED);
1286
+ return;
1287
+ }
1288
+ if (k === KEY_UP || k === "k" || k === "w") {
1289
+ cursorPos = (cursorPos - 1 + items.length) % items.length;
1290
+ } else if (k === KEY_DOWN || k === "j" || k === "s") {
1291
+ cursorPos = (cursorPos + 1) % items.length;
1292
+ } else if (k === KEY_SPACE && multiSelect) {
1293
+ if (selected.has(cursorPos)) selected.delete(cursorPos);
1294
+ else selected.add(cursorPos);
1295
+ } else if (k === KEY_ENTER) {
1296
+ clearLines2();
1297
+ cleanup(onKey);
1298
+ resolve(multiSelect ? selected.size ? [...selected] : [cursorPos] : cursorPos);
1299
+ return;
1300
+ }
1301
+ clearLines2();
1302
+ render();
1303
+ };
1304
+ if (inp.setRawMode) inp.setRawMode(true);
1305
+ inp.resume();
1306
+ inp.on("data", onKey);
1307
+ });
1308
+ };
1309
+ var components = { table, badge, progressBar, status, section, columns, timeline, menu };
1310
+
1311
+ // src/themes/index.ts
1312
+ var THEMES = {
1313
+ dracula: { name: "Dracula", primary: "#bd93f9", secondary: "#ff79c6", accent: "#50fa7b", warning: "#f1fa8c", error: "#ff5555", info: "#8be9fd", muted: "#6272a4", bg: "#282a36", surface: "#44475a", text: "#f8f8f2", gradient: ["#bd93f9", "#ff79c6"] },
1314
+ nord: { name: "Nord", primary: "#88c0d0", secondary: "#81a1c1", accent: "#a3be8c", warning: "#ebcb8b", error: "#bf616a", info: "#5e81ac", muted: "#4c566a", bg: "#2e3440", surface: "#3b4252", text: "#eceff4", gradient: ["#88c0d0", "#81a1c1"] },
1315
+ monokai: { name: "Monokai", primary: "#a6e22e", secondary: "#66d9e8", accent: "#f92672", warning: "#fd971f", error: "#f92672", info: "#66d9e8", muted: "#75715e", bg: "#272822", surface: "#3e3d32", text: "#f8f8f2", gradient: ["#a6e22e", "#66d9e8"] },
1316
+ cyberpunk: { name: "Cyberpunk", primary: "#ff2d78", secondary: "#00fff5", accent: "#ffe801", warning: "#ff8800", error: "#ff2d78", info: "#00fff5", muted: "#444466", bg: "#0d0d1a", surface: "#1a1a2e", text: "#e0e0ff", gradient: ["#ff2d78", "#00fff5", "#ffe801"] },
1317
+ pastel: { name: "Pastel", primary: "#a29bfe", secondary: "#fd79a8", accent: "#55efc4", warning: "#ffeaa7", error: "#e17055", info: "#74b9ff", muted: "#b2bec3", bg: "#f8f9fa", surface: "#ffffff", text: "#2d3436", gradient: ["#a29bfe", "#fd79a8", "#74b9ff"] },
1318
+ matrix: { name: "Matrix", primary: "#00ff41", secondary: "#008f11", accent: "#00ff41", warning: "#aaff00", error: "#ff0000", info: "#00cc33", muted: "#003b00", bg: "#0d0208", surface: "#001a00", text: "#00ff41", gradient: ["#00ff41", "#003b00"] },
1319
+ ocean: { name: "Ocean", primary: "#0099ff", secondary: "#00d2d3", accent: "#ffd32a", warning: "#ffa502", error: "#ff4757", info: "#70a1ff", muted: "#57606f", bg: "#0a1628", surface: "#0f2942", text: "#dfe6e9", gradient: ["#0099ff", "#00d2d3"] },
1320
+ sunset: { name: "Sunset", primary: "#fd7272", secondary: "#f9ca24", accent: "#6ab04c", warning: "#f0932b", error: "#eb4d4b", info: "#22a6b3", muted: "#95afc0", bg: "#1a1a2e", surface: "#16213e", text: "#f5f6fa", gradient: ["#fd7272", "#f9ca24", "#6ab04c"] }
1321
+ };
1322
+ var _active = THEMES["dracula"];
1323
+ var apply = (colorHex) => (text) => {
1324
+ const { r, g, b } = hexToRgb(colorHex);
1325
+ return fgRgb(r, g, b) + text + reset();
1326
+ };
1327
+ var themes = {
1328
+ list: () => Object.keys(THEMES),
1329
+ get: (name) => THEMES[name] ?? null,
1330
+ use(name) {
1331
+ const t = THEMES[name];
1332
+ if (!t) throw new Error(`Theme "${name}" not found. Available: ${Object.keys(THEMES).join(", ")}`);
1333
+ _active = t;
1334
+ return themes;
1335
+ },
1336
+ current: () => _active,
1337
+ primary: (text) => apply(_active.primary)(text),
1338
+ secondary: (text) => apply(_active.secondary)(text),
1339
+ accent: (text) => apply(_active.accent)(text),
1340
+ warning: (text) => apply(_active.warning)(text),
1341
+ error: (text) => apply(_active.error)(text),
1342
+ info: (text) => apply(_active.info)(text),
1343
+ muted: (text) => apply(_active.muted)(text),
1344
+ text: (text) => apply(_active.text)(text),
1345
+ bold: (text) => sgr(STYLE.bold) + text + reset(),
1346
+ gradient: (text) => gradient(text, _active.gradient),
1347
+ register: (name, def) => {
1348
+ THEMES[name] = def;
1349
+ },
1350
+ preview: () => {
1351
+ const orig = _active;
1352
+ Object.values(THEMES).forEach((t) => {
1353
+ _active = t;
1354
+ console.log(
1355
+ gradient(` ${t.name} `, t.gradient) + " " + themes.primary("primary") + " " + themes.secondary("secondary") + " " + themes.accent("accent") + " " + themes.error("error") + " " + themes.warning("warning")
1356
+ );
1357
+ });
1358
+ _active = orig;
1359
+ }
1360
+ };
1361
+
1362
+ // src/images/index.ts
1363
+ var FULL_BLOCK = "\u2588";
1364
+ var UPPER_HALF = "\u2580";
1365
+ var HEX_RE4 = /^#?([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
1366
+ var safeHex2 = (h) => {
1367
+ if (!HEX_RE4.test(h.trim())) return null;
1368
+ return hexToRgb(h);
1369
+ };
1370
+ var toRgb = (p) => p ?? { r: 0, g: 0, b: 0 };
1371
+ var renderPixelArt = (pixels, opts = {}) => {
1372
+ const { scale = 1, halfBlock = true } = opts;
1373
+ if (!pixels.length) return "";
1374
+ const lines = [];
1375
+ if (halfBlock) {
1376
+ for (let row = 0; row < pixels.length; row += 2) {
1377
+ let line = "";
1378
+ const topRow = pixels[row] ?? [];
1379
+ const botRow = pixels[row + 1] ?? [];
1380
+ for (let col = 0; col < topRow.length; col++) {
1381
+ const top = topRow[col] ?? null;
1382
+ const bot = botRow[col] ?? null;
1383
+ if (!top && !bot) {
1384
+ line += " ".repeat(scale);
1385
+ continue;
1386
+ }
1387
+ let cell = "";
1388
+ for (let s = 0; s < scale; s++) {
1389
+ if (top && bot) {
1390
+ const t = toRgb(top), b = toRgb(bot);
1391
+ cell += fgRgb(t.r, t.g, t.b) + bgRgb(b.r, b.g, b.b) + UPPER_HALF + reset();
1392
+ } else if (top) {
1393
+ const { r, g, b } = toRgb(top);
1394
+ cell += fgRgb(r, g, b) + FULL_BLOCK + reset();
1395
+ } else {
1396
+ const { r, g, b } = toRgb(bot);
1397
+ cell += fgRgb(r, g, b) + "\u2584" + reset();
1398
+ }
1399
+ }
1400
+ line += cell;
1401
+ }
1402
+ lines.push(line);
1403
+ }
1404
+ } else {
1405
+ for (const row of pixels) {
1406
+ let line = "";
1407
+ for (const pixel of row) {
1408
+ if (!pixel) line += " ".repeat(scale);
1409
+ else {
1410
+ const { r, g, b } = pixel;
1411
+ line += fgRgb(r, g, b) + FULL_BLOCK.repeat(scale) + reset();
1412
+ }
1413
+ }
1414
+ lines.push(line);
1415
+ }
1416
+ }
1417
+ return lines.join("\n");
1418
+ };
1419
+ var R = { r: 255, g: 0, b: 0 };
1420
+ var Y = { r: 255, g: 220, b: 0 };
1421
+ var G = { r: 255, g: 215, b: 0 };
1422
+ var K = { r: 0, g: 0, b: 0 };
1423
+ var N = null;
1424
+ var SPRITES = {
1425
+ heart: { pixels: [
1426
+ [N, R, N, R, N],
1427
+ [R, R, R, R, R],
1428
+ [R, R, R, R, R],
1429
+ [N, R, R, R, N],
1430
+ [N, N, R, N, N]
1431
+ ] },
1432
+ star: { pixels: [
1433
+ [N, G, N, G, N],
1434
+ [G, G, G, G, G],
1435
+ [N, G, G, G, N],
1436
+ [G, N, G, N, G],
1437
+ [N, N, G, N, N]
1438
+ ] },
1439
+ smiley: { pixels: [
1440
+ [N, Y, Y, Y, N],
1441
+ [Y, K, Y, K, Y],
1442
+ [Y, Y, Y, Y, Y],
1443
+ [Y, K, Y, K, Y],
1444
+ [N, Y, Y, Y, N]
1445
+ ] },
1446
+ pacman: { pixels: [
1447
+ [N, Y, Y, Y, N],
1448
+ [Y, Y, Y, N, N],
1449
+ [Y, Y, N, N, N],
1450
+ [Y, Y, Y, N, N],
1451
+ [N, Y, Y, Y, N]
1452
+ ] }
1453
+ };
1454
+ var flipHorizontal = (pixels) => pixels.map((row) => [...row].reverse());
1455
+ var flipVertical = (pixels) => [...pixels].reverse();
1456
+ var rotate90 = (pixels) => {
1457
+ if (!pixels.length || !pixels[0]?.length) return pixels;
1458
+ const rows = pixels.length;
1459
+ const cols = pixels[0].length;
1460
+ return Array.from(
1461
+ { length: cols },
1462
+ (_, c) => Array.from({ length: rows }, (__, r) => pixels[rows - 1 - r]?.[c] ?? null)
1463
+ );
1464
+ };
1465
+ var gradientRect = (opts = {}) => {
1466
+ const {
1467
+ width = 40,
1468
+ height = 10,
1469
+ colors = ["#ff0000", "#0000ff"],
1470
+ style = "horizontal"
1471
+ } = opts;
1472
+ const stops = colors.map(safeHex2).filter((c) => c !== null);
1473
+ if (stops.length < 2) throw new Error("gradientRect: at least 2 valid hex color stops required");
1474
+ const safeW = Math.max(2, width);
1475
+ const safeH = Math.max(2, height);
1476
+ const pixels = [];
1477
+ for (let row = 0; row < safeH; row++) {
1478
+ const line = [];
1479
+ for (let col = 0; col < safeW; col++) {
1480
+ let t;
1481
+ if (style === "horizontal") t = col / (safeW - 1);
1482
+ else if (style === "vertical") t = row / (safeH - 1);
1483
+ else if (style === "diagonal") t = (col + row) / (safeW + safeH - 2);
1484
+ else {
1485
+ const cx = safeW / 2, cy = safeH / 2;
1486
+ const dx = (col - cx) / cx;
1487
+ const dy = (row - cy) / cy;
1488
+ t = clamp(Math.sqrt(dx * dx + dy * dy) / Math.SQRT2, 0, 1);
1489
+ }
1490
+ const scaled = t * (stops.length - 1);
1491
+ const lo = Math.floor(scaled);
1492
+ const hi = Math.min(lo + 1, stops.length - 1);
1493
+ line.push(lerpColor(stops[lo], stops[hi], scaled - lo));
1494
+ }
1495
+ pixels.push(line);
1496
+ }
1497
+ return renderPixelArt(pixels, { scale: 1, halfBlock: true });
1498
+ };
1499
+ var createCanvas = (width, height, fillColor = null) => {
1500
+ const pixels = Array.from(
1501
+ { length: height },
1502
+ () => Array.from({ length: width }, () => fillColor ? { ...fillColor } : null)
1503
+ );
1504
+ return {
1505
+ set(x, y, color2) {
1506
+ if (y >= 0 && y < height && x >= 0 && x < width) pixels[y][x] = color2;
1507
+ },
1508
+ get(x, y) {
1509
+ return pixels[y]?.[x] ?? null;
1510
+ },
1511
+ fill(color2) {
1512
+ for (let y = 0; y < height; y++)
1513
+ for (let x = 0; x < width; x++)
1514
+ pixels[y][x] = color2 ? { ...color2 } : null;
1515
+ },
1516
+ drawRect(x, y, w, h, color2, fill = false) {
1517
+ for (let dy = y; dy < y + h; dy++)
1518
+ for (let dx = x; dx < x + w; dx++)
1519
+ if (fill || dy === y || dy === y + h - 1 || dx === x || dx === x + w - 1)
1520
+ this.set(dx, dy, color2);
1521
+ },
1522
+ drawCircle(cx, cy, radius, color2, fill = false) {
1523
+ const r2 = radius * radius;
1524
+ for (let y = 0; y < height; y++)
1525
+ for (let x = 0; x < width; x++) {
1526
+ const dx = x - cx, dy = y - cy;
1527
+ const d2 = dx * dx + dy * dy;
1528
+ if (fill ? d2 <= r2 : Math.abs(Math.sqrt(d2) - radius) <= 0.7)
1529
+ this.set(x, y, color2);
1530
+ }
1531
+ },
1532
+ render(opts = {}) {
1533
+ return renderPixelArt(pixels, opts);
1534
+ },
1535
+ // Use write() instead of console.log for consistency with the I/O layer
1536
+ print(opts = {}) {
1537
+ write(this.render(opts) + "\n");
1538
+ },
1539
+ width,
1540
+ height,
1541
+ pixels
1542
+ };
1543
+ };
1544
+ var images = {
1545
+ render: renderPixelArt,
1546
+ sprites: SPRITES,
1547
+ flipHorizontal,
1548
+ flipVertical,
1549
+ rotate90,
1550
+ sprite(name, opts = {}) {
1551
+ const s = SPRITES[name];
1552
+ if (!s) throw new Error(`Sprite "${name}" not found. Available: ${Object.keys(SPRITES).join(", ")}`);
1553
+ return renderPixelArt(s.pixels, opts);
1554
+ },
1555
+ gradientRect,
1556
+ createCanvas
1557
+ };
1558
+
1559
+ // src/configure.ts
1560
+ var _config = {
1561
+ colorMode: "truecolor",
1562
+ animationSpeed: "normal",
1563
+ asciiFont: "big",
1564
+ locale: "es",
1565
+ theme: "dracula"
1566
+ };
1567
+ var SPEED_MAP = {
1568
+ slow: 2,
1569
+ normal: 1,
1570
+ fast: 0.4
1571
+ };
1572
+ var configure = (opts = {}) => {
1573
+ Object.assign(_config, opts);
1574
+ };
1575
+ var getConfig = () => ({ ..._config });
1576
+ var getSpeedMultiplier = () => SPEED_MAP[_config.animationSpeed] ?? 1;
1577
+
1578
+ // src/index.ts
1579
+ var ansimax = { color, animate, ascii, loader, frames, components, themes, images, configure };
1580
+ var index_default = ansimax;
1581
+ export {
1582
+ SPINNERS,
1583
+ SPRITES,
1584
+ animate,
1585
+ ascii,
1586
+ bgRgb,
1587
+ center,
1588
+ clamp,
1589
+ color,
1590
+ presets as colorPresets,
1591
+ components,
1592
+ compose,
1593
+ configure,
1594
+ createCanvas,
1595
+ cursor,
1596
+ index_default as default,
1597
+ fgRgb,
1598
+ frames,
1599
+ getConfig,
1600
+ getSpeedMultiplier,
1601
+ gradient,
1602
+ gradientRect,
1603
+ hexToRgb,
1604
+ images,
1605
+ isHexColor,
1606
+ isNoColor,
1607
+ lerp,
1608
+ lerpColor,
1609
+ loader,
1610
+ padEnd,
1611
+ padStart,
1612
+ rainbow,
1613
+ renderPixelArt,
1614
+ repeatVisible,
1615
+ reset,
1616
+ resetNoColor,
1617
+ rgbTo256,
1618
+ rgbToHex,
1619
+ screen,
1620
+ setNoColor,
1621
+ sgr,
1622
+ sleep,
1623
+ stripAnsi,
1624
+ supportsColor,
1625
+ termSize,
1626
+ themes,
1627
+ truncateAnsi,
1628
+ visibleLen,
1629
+ wordWrap,
1630
+ write,
1631
+ writeln
1632
+ };