@mks2508/better-logger 0.18.2-alpha.1 → 0.18.2-alpha.2
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/README.md +38 -336
- package/dist/Logger.d.ts +243 -154
- package/dist/Logger.d.ts.map +1 -1
- package/dist/ScopedLogger.d.ts +511 -8
- package/dist/ScopedLogger.d.ts.map +1 -1
- package/dist/chunks/HookBridge-C-AvXmPD.cjs +504 -0
- package/dist/chunks/HookBridge-C-AvXmPD.cjs.map +1 -0
- package/dist/chunks/HookBridge-CI2PH79S.js +487 -0
- package/dist/chunks/HookBridge-CI2PH79S.js.map +1 -0
- package/dist/chunks/{LogContext-L7HzynFw.cjs → LogContext-BaMXleWj.cjs} +19 -4
- package/dist/chunks/LogContext-BaMXleWj.cjs.map +1 -0
- package/dist/chunks/{LogContext-Cwn-1Zzb.js → LogContext-DjlITOzZ.js} +19 -4
- package/dist/chunks/LogContext-DjlITOzZ.js.map +1 -0
- package/dist/chunks/SerializerBridge-Ba43Mk7j.js +393 -0
- package/dist/chunks/SerializerBridge-Ba43Mk7j.js.map +1 -0
- package/dist/chunks/SerializerBridge-C4a9Z37F.cjs +410 -0
- package/dist/chunks/SerializerBridge-C4a9Z37F.cjs.map +1 -0
- package/dist/chunks/{StyleManager-CIpd6wbO.cjs → StyleManager-DQ6UNRB-.cjs} +37 -11
- package/dist/chunks/StyleManager-DQ6UNRB-.cjs.map +1 -0
- package/dist/chunks/StyleManager-DjwAYbxE.js +113 -0
- package/dist/chunks/StyleManager-DjwAYbxE.js.map +1 -0
- package/dist/chunks/{core-PoT7RrTK.js → core-Blfi2klP.js} +1 -4
- package/dist/chunks/core-Blfi2klP.js.map +1 -0
- package/dist/chunks/{core-Dzz7agGa.cjs → core-CqS_UBzJ.cjs} +1 -4
- package/dist/chunks/core-CqS_UBzJ.cjs.map +1 -0
- package/dist/chunks/{environment-detector-CI3TrWK_.js → environment-detector-7NvnYUfr.js} +11 -11
- package/dist/chunks/environment-detector-7NvnYUfr.js.map +1 -0
- package/dist/chunks/{environment-detector-Cnn6wr6O.cjs → environment-detector-D-tHkKWA.cjs} +11 -11
- package/dist/chunks/environment-detector-D-tHkKWA.cjs.map +1 -0
- package/dist/chunks/server-fallback-CaCPjWby.cjs +119 -0
- package/dist/chunks/server-fallback-CaCPjWby.cjs.map +1 -0
- package/dist/chunks/server-fallback-jj0T6XaK.js +114 -0
- package/dist/chunks/server-fallback-jj0T6XaK.js.map +1 -0
- package/dist/chunks/{spinner-DNvxbM9a.cjs → spinner-BHyYEXsM.cjs} +319 -37
- package/dist/chunks/spinner-BHyYEXsM.cjs.map +1 -0
- package/dist/chunks/{spinner-D3FsF78o.js → spinner-BtkwpzYv.js} +319 -37
- package/dist/chunks/spinner-BtkwpzYv.js.map +1 -0
- package/dist/chunks/styling-CRw3KQW4.js +1592 -0
- package/dist/chunks/styling-CRw3KQW4.js.map +1 -0
- package/dist/chunks/styling-Cel2wPRy.cjs +1645 -0
- package/dist/chunks/styling-Cel2wPRy.cjs.map +1 -0
- package/dist/chunks/transports-BGfwwakw.js +1237 -0
- package/dist/chunks/transports-BGfwwakw.js.map +1 -0
- package/dist/chunks/transports-yK6CL0Ml.cjs +1278 -0
- package/dist/chunks/transports-yK6CL0Ml.cjs.map +1 -0
- package/dist/chunks/{utils-BqlFYocD.cjs → utils-W_cxqriN.cjs} +44 -37
- package/dist/chunks/utils-W_cxqriN.cjs.map +1 -0
- package/dist/chunks/{utils-VETbVpkR.js → utils-tKfBAWUM.js} +44 -37
- package/dist/chunks/utils-tKfBAWUM.js.map +1 -0
- package/dist/cli/CommandProcessor.d.ts +166 -19
- package/dist/cli/CommandProcessor.d.ts.map +1 -1
- package/dist/cli/commands/ConfigCommand.d.ts +36 -1
- package/dist/cli/commands/ConfigCommand.d.ts.map +1 -1
- package/dist/cli/commands/ExportCommand.d.ts +49 -3
- package/dist/cli/commands/ExportCommand.d.ts.map +1 -1
- package/dist/cli/commands/ThemeCommand.d.ts +62 -3
- package/dist/cli/commands/ThemeCommand.d.ts.map +1 -1
- package/dist/cli/help.d.ts +30 -2
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/index.d.ts +29 -2
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli.cjs +2 -2
- package/dist/cli.js +2 -2
- package/dist/context/LogContext.d.ts +165 -66
- package/dist/context/LogContext.d.ts.map +1 -1
- package/dist/context.cjs +1 -1
- package/dist/context.js +1 -1
- package/dist/core.cjs +52 -29
- package/dist/core.cjs.map +1 -1
- package/dist/core.d.ts +50 -27
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js +52 -29
- package/dist/core.js.map +1 -1
- package/dist/hooks/HookBridge.d.ts +15 -9
- package/dist/hooks/HookBridge.d.ts.map +1 -1
- package/dist/hooks/HookManager.d.ts +295 -2
- package/dist/hooks/HookManager.d.ts.map +1 -1
- package/dist/hooks.cjs +1 -1
- package/dist/hooks.js +1 -1
- package/dist/index.cjs +1092 -212
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1092 -212
- package/dist/index.js.map +1 -1
- package/dist/playground/TerminalBridge.d.ts +23 -16
- package/dist/playground/TerminalBridge.d.ts.map +1 -1
- package/dist/playground/box.d.ts +36 -5
- package/dist/playground/box.d.ts.map +1 -1
- package/dist/playground/cli-table.d.ts +41 -5
- package/dist/playground/cli-table.d.ts.map +1 -1
- package/dist/playground/divider.d.ts +22 -3
- package/dist/playground/divider.d.ts.map +1 -1
- package/dist/playground/header.d.ts +21 -4
- package/dist/playground/header.d.ts.map +1 -1
- package/dist/playground/server-fallback.d.ts +96 -9
- package/dist/playground/server-fallback.d.ts.map +1 -1
- package/dist/playground/spinner.d.ts +159 -10
- package/dist/playground/spinner.d.ts.map +1 -1
- package/dist/playground/step.d.ts +25 -6
- package/dist/playground/step.d.ts.map +1 -1
- package/dist/playground.cjs +1 -1
- package/dist/playground.js +1 -1
- package/dist/serializers/SerializerBridge.d.ts +13 -6
- package/dist/serializers/SerializerBridge.d.ts.map +1 -1
- package/dist/serializers/SerializerRegistry.d.ts +236 -0
- package/dist/serializers/SerializerRegistry.d.ts.map +1 -1
- package/dist/serializers.cjs +1 -1
- package/dist/serializers.js +1 -1
- package/dist/styles/StyleManager.d.ts +138 -31
- package/dist/styles/StyleManager.d.ts.map +1 -1
- package/dist/styles.cjs +2 -2
- package/dist/styles.js +2 -2
- package/dist/styling/SmartPresets.d.ts +100 -6
- package/dist/styling/SmartPresets.d.ts.map +1 -1
- package/dist/styling/StyleBuilder.d.ts +453 -32
- package/dist/styling/StyleBuilder.d.ts.map +1 -1
- package/dist/styling/banners.d.ts +83 -7
- package/dist/styling/banners.d.ts.map +1 -1
- package/dist/styling/themes.d.ts +41 -2
- package/dist/styling/themes.d.ts.map +1 -1
- package/dist/transports/ConsoleTransport.d.ts +95 -0
- package/dist/transports/ConsoleTransport.d.ts.map +1 -1
- package/dist/transports/FileTransport.d.ts +99 -18
- package/dist/transports/FileTransport.d.ts.map +1 -1
- package/dist/transports/HttpTransport.d.ts +135 -22
- package/dist/transports/HttpTransport.d.ts.map +1 -1
- package/dist/transports/OtlpTransport.d.ts +53 -36
- package/dist/transports/OtlpTransport.d.ts.map +1 -1
- package/dist/transports/TransportBridge.d.ts +19 -13
- package/dist/transports/TransportBridge.d.ts.map +1 -1
- package/dist/transports/TransportManager.d.ts +223 -8
- package/dist/transports/TransportManager.d.ts.map +1 -1
- package/dist/transports.cjs +1 -1
- package/dist/transports.js +1 -1
- package/dist/types/core.d.ts +155 -59
- package/dist/types/core.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +92 -14
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/serializers.d.ts +72 -0
- package/dist/types/serializers.d.ts.map +1 -1
- package/dist/types/transports.d.ts +42 -37
- package/dist/types/transports.d.ts.map +1 -1
- package/dist/utils/ansi-colors.d.ts +15 -15
- package/dist/utils/environment-detector.d.ts +11 -11
- package/dist/utils/formatting.d.ts +8 -8
- package/dist/utils/output.d.ts +9 -9
- package/dist/utils/output.d.ts.map +1 -1
- package/dist/utils/stackTrace.d.ts +2 -2
- package/package.json +24 -25
- package/dist/chunks/HookBridge-CiRfR67f.cjs +0 -190
- package/dist/chunks/HookBridge-CiRfR67f.cjs.map +0 -1
- package/dist/chunks/HookBridge-SgMmbXZB.js +0 -173
- package/dist/chunks/HookBridge-SgMmbXZB.js.map +0 -1
- package/dist/chunks/LogContext-Cwn-1Zzb.js.map +0 -1
- package/dist/chunks/LogContext-L7HzynFw.cjs.map +0 -1
- package/dist/chunks/SerializerBridge-BaOQOb8q.cjs +0 -166
- package/dist/chunks/SerializerBridge-BaOQOb8q.cjs.map +0 -1
- package/dist/chunks/SerializerBridge-BkpQu5c9.js +0 -149
- package/dist/chunks/SerializerBridge-BkpQu5c9.js.map +0 -1
- package/dist/chunks/StyleManager-CIpd6wbO.cjs.map +0 -1
- package/dist/chunks/StyleManager-LCvVlVdx.js +0 -87
- package/dist/chunks/StyleManager-LCvVlVdx.js.map +0 -1
- package/dist/chunks/core-Dzz7agGa.cjs.map +0 -1
- package/dist/chunks/core-PoT7RrTK.js.map +0 -1
- package/dist/chunks/environment-detector-CI3TrWK_.js.map +0 -1
- package/dist/chunks/environment-detector-Cnn6wr6O.cjs.map +0 -1
- package/dist/chunks/server-fallback-BUKjdLS7.cjs +0 -42
- package/dist/chunks/server-fallback-BUKjdLS7.cjs.map +0 -1
- package/dist/chunks/server-fallback-BsuWH1Dk.js +0 -37
- package/dist/chunks/server-fallback-BsuWH1Dk.js.map +0 -1
- package/dist/chunks/spinner-D3FsF78o.js.map +0 -1
- package/dist/chunks/spinner-DNvxbM9a.cjs.map +0 -1
- package/dist/chunks/styling-84N8T97t.js +0 -941
- package/dist/chunks/styling-84N8T97t.js.map +0 -1
- package/dist/chunks/styling-Cg5saQ46.cjs +0 -994
- package/dist/chunks/styling-Cg5saQ46.cjs.map +0 -1
- package/dist/chunks/transports-BiDk345e.js +0 -715
- package/dist/chunks/transports-BiDk345e.js.map +0 -1
- package/dist/chunks/transports-COPWmlF1.cjs +0 -756
- package/dist/chunks/transports-COPWmlF1.cjs.map +0 -1
- package/dist/chunks/utils-BqlFYocD.cjs.map +0 -1
- package/dist/chunks/utils-VETbVpkR.js.map +0 -1
- package/dist/example.d.ts +0 -18
- package/dist/example.d.ts.map +0 -1
- package/dist/main.d.ts +0 -2
- package/dist/main.d.ts.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as getTerminalWidth } from "./environment-detector-
|
|
1
|
+
import { a as getTerminalWidth } from "./environment-detector-7NvnYUfr.js";
|
|
2
2
|
//#region src/terminal/color-converter.ts
|
|
3
3
|
const ANSI_16_COLORS = {
|
|
4
4
|
black: {
|
|
@@ -427,12 +427,31 @@ function formatBadge(badge, style = "brackets", colorCapability = "full", color)
|
|
|
427
427
|
* @fileoverview Step progress renderer for CLI primitives
|
|
428
428
|
*/
|
|
429
429
|
/**
|
|
430
|
-
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
433
|
-
*
|
|
434
|
-
*
|
|
435
|
-
*
|
|
430
|
+
* Renderiza un indicador de progreso de step con el formato ` [n/total] msg`,
|
|
431
|
+
* donde el `[n/total]` se emite en cian bold (respetando `colorCap`) para
|
|
432
|
+
* destacarlo del mensaje descriptivo. Pensado para output secuencial de CLI
|
|
433
|
+
* tipo "steps de un build", "fases de un deploy" o "tareas de un script".
|
|
434
|
+
*
|
|
435
|
+
* No hace ningún chequeo de rango sobre `current`/`total` — el caller es
|
|
436
|
+
* responsable de pasar valores coherentes (se renderizan tal cual).
|
|
437
|
+
*
|
|
438
|
+
* @param current - Número de step actual (típicamente 1-based).
|
|
439
|
+
* @param total - Total de steps del proceso.
|
|
440
|
+
* @param msg - Descripción corta del step en curso.
|
|
441
|
+
* @param colorCap - Capacidad de color del terminal destino. Si es `'none'`,
|
|
442
|
+
* el label `[n/total]` se emite sin color.
|
|
443
|
+
* @returns String de una sola línea con formato ` [n/total] msg`.
|
|
444
|
+
*
|
|
445
|
+
* @example
|
|
446
|
+
* ```ts
|
|
447
|
+
* const steps = ['Resolving deps', 'Bundling', 'Writing dist'];
|
|
448
|
+
* steps.forEach((step, i) => {
|
|
449
|
+
* process.stdout.write(renderStep(i + 1, steps.length, step, 'full') + '\n');
|
|
450
|
+
* });
|
|
451
|
+
* // [1/3] Resolving deps
|
|
452
|
+
* // [2/3] Bundling
|
|
453
|
+
* // [3/3] Writing dist
|
|
454
|
+
* ```
|
|
436
455
|
*/
|
|
437
456
|
function renderStep(current, total, msg, colorCap) {
|
|
438
457
|
const label = `[${current}/${total}]`;
|
|
@@ -444,10 +463,27 @@ function renderStep(current, total, msg, colorCap) {
|
|
|
444
463
|
* @fileoverview Header renderer for CLI primitives
|
|
445
464
|
*/
|
|
446
465
|
/**
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
*
|
|
466
|
+
* Renderiza un header de sección: `title` en bold seguido opcionalmente de
|
|
467
|
+
* `subtitle` en dim (ANSI `2`), ideal para marcar bloques en output de CLI.
|
|
468
|
+
* No usa colores de foreground — sólo atributos de texto, así que el renderer
|
|
469
|
+
* es seguro para cualquier terminal sin importar la paleta del theme activo.
|
|
470
|
+
*
|
|
471
|
+
* @param title - Texto principal del header (siempre en bold).
|
|
472
|
+
* @param subtitle - Texto secundario a la derecha del título; se renderiza
|
|
473
|
+
* dimmed y separado por un espacio. Omitir si no aplica.
|
|
474
|
+
* @returns String de una línea con formato ` <bold>title</bold> <dim>subtitle</dim>`.
|
|
475
|
+
*
|
|
476
|
+
* @example
|
|
477
|
+
* ```ts
|
|
478
|
+
* process.stdout.write(renderHeader('Deploy', 'production · us-east-1') + '\n');
|
|
479
|
+
* // **Deploy** production · us-east-1 (con atributos ANSI aplicados)
|
|
480
|
+
* ```
|
|
481
|
+
*
|
|
482
|
+
* @example
|
|
483
|
+
* ```ts
|
|
484
|
+
* // Header sin subtítulo
|
|
485
|
+
* process.stdout.write(renderHeader('Build summary') + '\n');
|
|
486
|
+
* ```
|
|
451
487
|
*/
|
|
452
488
|
function renderHeader(title, subtitle) {
|
|
453
489
|
return ` ${ANSI.bold + title + ANSI.reset}${subtitle ? ANSI.dim + ` ${subtitle}` + ANSI.reset : ""}`;
|
|
@@ -458,9 +494,28 @@ function renderHeader(title, subtitle) {
|
|
|
458
494
|
* @fileoverview Divider renderer for CLI primitives
|
|
459
495
|
*/
|
|
460
496
|
/**
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
497
|
+
* Renderiza una línea divisoria horizontal dimmed (ANSI `2`) usando el
|
|
498
|
+
* caracter `─`. Por defecto el ancho es `min(terminalWidth - 4, 60)` para
|
|
499
|
+
* no ocupar todo el ancho de ventana y quedar visualmente alineado con otros
|
|
500
|
+
* primitives (box, header, table) que dejan 2 espacios de indentación.
|
|
501
|
+
*
|
|
502
|
+
* @param width - Ancho explícito en columnas visibles. Si se omite, se calcula
|
|
503
|
+
* automáticamente a partir del ancho del terminal (capped a 60).
|
|
504
|
+
* @returns String de una línea con `width` caracteres `─` envueltos en ANSI dim.
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* ```ts
|
|
508
|
+
* // Divider automático (respeta el ancho del terminal)
|
|
509
|
+
* process.stdout.write(renderDivider() + '\n');
|
|
510
|
+
* ```
|
|
511
|
+
*
|
|
512
|
+
* @example
|
|
513
|
+
* ```ts
|
|
514
|
+
* // Divider de ancho fijo para alinear con otra salida
|
|
515
|
+
* process.stdout.write(renderDivider(40) + '\n');
|
|
516
|
+
* ```
|
|
517
|
+
*
|
|
518
|
+
* @see {@link getTerminalWidth} para la detección de ancho cuando `width` se omite.
|
|
464
519
|
*/
|
|
465
520
|
function renderDivider(width) {
|
|
466
521
|
const w = width ?? Math.min(getTerminalWidth() - 4, 60);
|
|
@@ -469,7 +524,16 @@ function renderDivider(width) {
|
|
|
469
524
|
//#endregion
|
|
470
525
|
//#region src/playground/box.ts
|
|
471
526
|
/**
|
|
472
|
-
*
|
|
527
|
+
* Mapa de juegos de caracteres Unicode para los 4 estilos de borde soportados
|
|
528
|
+
* por {@link renderBox}. Cada entrada expone las 4 esquinas (`tl`, `tr`, `bl`,
|
|
529
|
+
* `br`), el caracter horizontal (`h`) y el vertical (`v`) que componen el marco.
|
|
530
|
+
*
|
|
531
|
+
* - `single`: l\u00edneas finas (U+2500 / U+2502).
|
|
532
|
+
* - `rounded`: igual que `single` con esquinas redondeadas.
|
|
533
|
+
* - `double`: l\u00edneas dobles (U+2550 / U+2551), alto contraste visual.
|
|
534
|
+
* - `bold`: l\u00edneas gruesas (U+2501 / U+2503), para destacar bloques cr\u00edticos.
|
|
535
|
+
*
|
|
536
|
+
* @internal Lookup interno del renderer; no es API p\u00fablica.
|
|
473
537
|
*/
|
|
474
538
|
const BORDER_CHARS = {
|
|
475
539
|
single: {
|
|
@@ -506,11 +570,42 @@ const BORDER_CHARS = {
|
|
|
506
570
|
}
|
|
507
571
|
};
|
|
508
572
|
/**
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
* @
|
|
512
|
-
*
|
|
513
|
-
*
|
|
573
|
+
* Renderiza `content` envuelto en un box con borde Unicode, respetando el
|
|
574
|
+
* ancho del terminal. El ancho interno se calcula a partir de la l\u00ednea m\u00e1s
|
|
575
|
+
* larga (o del {@link IBoxOptions.title} si es m\u00e1s ancho) y se acota a
|
|
576
|
+
* `min(terminalWidth - 4, 80)` columnas para no romper layouts estrechos.
|
|
577
|
+
*
|
|
578
|
+
* El padding se aplica como l\u00edneas vac\u00edas sim\u00e9tricas arriba/abajo del
|
|
579
|
+
* contenido. Si `borderColor` se omite o `colorCap` es `'none'`, el borde se
|
|
580
|
+
* emite sin secuencias ANSI (output plain-text seguro para logs y pipes).
|
|
581
|
+
*
|
|
582
|
+
* @param content - Texto a envolver; puede contener m\u00faltiples l\u00edneas (`\n`) y
|
|
583
|
+
* secuencias ANSI embebidas \u2014 el c\u00e1lculo de ancho usa el largo visible.
|
|
584
|
+
* @param options - Configuraci\u00f3n del box (title, borderColor, borderStyle,
|
|
585
|
+
* padding). Ver {@link IBoxOptions}.
|
|
586
|
+
* @param colorCap - Capacidad de color del terminal destino. Si es `'none'`,
|
|
587
|
+
* se omite cualquier secuencia ANSI.
|
|
588
|
+
* @returns String multilinea con el box ya construido (sin trailing newline).
|
|
589
|
+
*
|
|
590
|
+
* @example
|
|
591
|
+
* ```ts
|
|
592
|
+
* // Box b\u00e1sico con borde redondeado (default)
|
|
593
|
+
* process.stdout.write(renderBox('Deploy completado') + '\n');
|
|
594
|
+
* ```
|
|
595
|
+
*
|
|
596
|
+
* @example
|
|
597
|
+
* ```ts
|
|
598
|
+
* // Box con t\u00edtulo embebido en el borde superior y color custom
|
|
599
|
+
* process.stdout.write(renderBox('Service: auth-svc\nStatus: healthy', {
|
|
600
|
+
* title: 'Health Check',
|
|
601
|
+
* borderColor: '#00bcd4',
|
|
602
|
+
* borderStyle: 'double',
|
|
603
|
+
* padding: 1
|
|
604
|
+
* }) + '\n');
|
|
605
|
+
* ```
|
|
606
|
+
*
|
|
607
|
+
* @see {@link IBoxOptions} para el detalle de cada opci\u00f3n.
|
|
608
|
+
* @see {@link getTerminalWidth} para la detecci\u00f3n de ancho.
|
|
514
609
|
*/
|
|
515
610
|
function renderBox(content, options = {}, colorCap = "full") {
|
|
516
611
|
const { title, borderColor, borderStyle = "rounded", padding = 0 } = options;
|
|
@@ -549,11 +644,47 @@ function renderBox(content, options = {}, colorCap = "full") {
|
|
|
549
644
|
//#endregion
|
|
550
645
|
//#region src/playground/cli-table.ts
|
|
551
646
|
/**
|
|
552
|
-
*
|
|
553
|
-
*
|
|
554
|
-
*
|
|
555
|
-
*
|
|
556
|
-
*
|
|
647
|
+
* Renderiza un array de objetos como tabla ASCII alineada, con headers en
|
|
648
|
+
* cian bold y separador (`─`) bajo la cabecera. Las columnas se autodetectan
|
|
649
|
+
* a partir de las keys del primer row salvo que `options.columns` las imponga,
|
|
650
|
+
* y los labels se toman de `options.head` (default: nombres de columna).
|
|
651
|
+
*
|
|
652
|
+
* El ancho de cada columna se calcula como `max(header, valor más largo) + 2`
|
|
653
|
+
* para garantizar padding horizontal consistente. Si `colorCap` es `'none'`,
|
|
654
|
+
* se omiten todas las secuencias ANSI (útil para logs plain-text o CI).
|
|
655
|
+
*
|
|
656
|
+
* @param rows - Array de row objects. Un array vacío devuelve string vacío.
|
|
657
|
+
* @param options - Ver {@link ITableOptions} para `columns` y `head`.
|
|
658
|
+
* @param colorCap - Capacidad de color del terminal destino.
|
|
659
|
+
* @returns String multilinea con la tabla (header + separator + data rows),
|
|
660
|
+
* o `''` si `rows` está vacío.
|
|
661
|
+
*
|
|
662
|
+
* @example
|
|
663
|
+
* ```ts
|
|
664
|
+
* // Auto-detect columnas desde las keys del primer row
|
|
665
|
+
* const rows = [
|
|
666
|
+
* { service: 'auth', status: 'healthy', latency: 12 },
|
|
667
|
+
* { service: 'api', status: 'degraded', latency: 245 }
|
|
668
|
+
* ];
|
|
669
|
+
* process.stdout.write(renderTable(rows) + '\n');
|
|
670
|
+
* // ┌─────────┬──────────┬─────────┐
|
|
671
|
+
* // │ service │ status │ latency │
|
|
672
|
+
* // ─────────────────────────────────
|
|
673
|
+
* // │ auth │ healthy │ 12 │
|
|
674
|
+
* // │ api │ degraded │ 245 │
|
|
675
|
+
* ```
|
|
676
|
+
*
|
|
677
|
+
* @example
|
|
678
|
+
* ```ts
|
|
679
|
+
* // Forzar columnas y renombrar headers
|
|
680
|
+
* process.stdout.write(renderTable(rows, {
|
|
681
|
+
* columns: ['service', 'latency'],
|
|
682
|
+
* head: ['Service', 'Latency (ms)']
|
|
683
|
+
* }, 'none') + '\n');
|
|
684
|
+
* ```
|
|
685
|
+
*
|
|
686
|
+
* @see {@link ITableOptions} para las opciones disponibles.
|
|
687
|
+
* @see {@link getVisibleLength} y {@link padToWidth} para el cálculo de ancho.
|
|
557
688
|
*/
|
|
558
689
|
function renderTable(rows, options = {}, colorCap = "full") {
|
|
559
690
|
if (rows.length === 0) return "";
|
|
@@ -585,7 +716,12 @@ function renderTable(rows, options = {}, colorCap = "full") {
|
|
|
585
716
|
}
|
|
586
717
|
//#endregion
|
|
587
718
|
//#region src/playground/spinner.ts
|
|
588
|
-
/**
|
|
719
|
+
/**
|
|
720
|
+
* Frames braille usados por la animaci\u00f3n del spinner. Cada frame es un
|
|
721
|
+
* car\u00e1cter del bloque Unicode Braille Patterns (U+2800\u2013U+28FF) que da la
|
|
722
|
+
* ilusi\u00f3n de rotaci\u00f3n al ciclarlos a ~12 FPS. Elegidos sobre caracteres
|
|
723
|
+
* ASCII (`|/-\`) porque renderizan m\u00e1s suaves en terminales modernas.
|
|
724
|
+
*/
|
|
589
725
|
const SPINNER_FRAMES = [
|
|
590
726
|
"⠋",
|
|
591
727
|
"⠙",
|
|
@@ -598,24 +734,68 @@ const SPINNER_FRAMES = [
|
|
|
598
734
|
"⠇",
|
|
599
735
|
"⠏"
|
|
600
736
|
];
|
|
601
|
-
/**
|
|
737
|
+
/**
|
|
738
|
+
* Intervalo entre frames del spinner en milisegundos. 80 ms \u2248 12.5 FPS:
|
|
739
|
+
* suficientemente r\u00e1pido para sentirse responsivo sin consumir CPU
|
|
740
|
+
* perceptiblemente en runs largos.
|
|
741
|
+
*/
|
|
602
742
|
const FRAME_INTERVAL = 80;
|
|
603
743
|
/**
|
|
604
|
-
*
|
|
605
|
-
*
|
|
744
|
+
* Spinner interactivo para TTY: cicla frames braille reescribiendo la l\u00ednea
|
|
745
|
+
* actual en su sitio (no emite l\u00edneas nuevas hasta el stop).
|
|
746
|
+
*
|
|
747
|
+
* Para no poluir stdout piped ni entrelazarse con el output normal del
|
|
748
|
+
* {@link Logger}, hace dos cosas no obvias:
|
|
749
|
+
* 1. Escribe SIEMPRE a `process.stderr` (carriage return + `\x1b[K` para
|
|
750
|
+
* limpiar la l\u00ednea antes de cada render).
|
|
751
|
+
* 2. Con `start()` mutea el logger (`outputMode: 'silent'`) y lo restaura a
|
|
752
|
+
* `'console'` en cualquier m\u00e9todo de finalizaci\u00f3n (`stop`/`succeed`/`fail`).
|
|
753
|
+
* Sin esto, los logs del usuario se imprimir\u00edan encima del frame animado.
|
|
754
|
+
*
|
|
755
|
+
* No gestiona TTY detection \u2014 quien lo instancia (`TerminalBridge`) ya valid\u00f3
|
|
756
|
+
* que hay TTY. Para non-TTY ver {@link NoopSpinner}.
|
|
606
757
|
*
|
|
607
758
|
* @implements {ISpinnerHandle}
|
|
759
|
+
*
|
|
760
|
+
* @example
|
|
761
|
+
* ```ts
|
|
762
|
+
* const spinner = new SpinnerManager('Compilando...', logger.config, logger);
|
|
763
|
+
* spinner.start();
|
|
764
|
+
* // ...trabajo as\u00edncrono...
|
|
765
|
+
* spinner.succeed('Build OK');
|
|
766
|
+
* // stderr: " \u2713 Build OK"
|
|
767
|
+
* ```
|
|
768
|
+
*
|
|
769
|
+
* @see {@link NoopSpinner} para el path non-TTY.
|
|
770
|
+
* @see {@link ISpinnerHandle} para el contrato de la API p\u00fablica.
|
|
608
771
|
*/
|
|
609
772
|
var SpinnerManager = class {
|
|
610
773
|
message;
|
|
611
774
|
frameIndex = 0;
|
|
612
775
|
interval = null;
|
|
613
776
|
_logger;
|
|
777
|
+
/**
|
|
778
|
+
* @param {string} message - Texto a mostrar al lado del frame animado.
|
|
779
|
+
* Mutables luego v\u00eda {@link SpinnerManager.text}.
|
|
780
|
+
* @param {LoggerConfig} _config - Reservado para configuraci\u00f3n futura;
|
|
781
|
+
* actualmente no se lee dentro de la clase (lo conserva solo el caller).
|
|
782
|
+
* @param {Logger} logger - Instancia del logger due\u00f1a del spinner. Se
|
|
783
|
+
* mutea/restaura con `updateConfig({ outputMode })` en start/stop.
|
|
784
|
+
*/
|
|
614
785
|
constructor(message, _config, logger) {
|
|
615
786
|
this.message = message;
|
|
616
787
|
this._logger = logger;
|
|
617
788
|
}
|
|
618
|
-
/**
|
|
789
|
+
/**
|
|
790
|
+
* Arranca la animaci\u00f3n. Idempotente: si ya est\u00e1 corriendo, no hace nada.
|
|
791
|
+
*
|
|
792
|
+
* Como efecto lateral mutea el logger pasado al constructor cambiando su
|
|
793
|
+
* `outputMode` a `'silent'` \u2014 cualquier log durante la animaci\u00f3n quedar\u00eda
|
|
794
|
+
* bufferizado y se descarta al restaurar el modo. Llama siempre a
|
|
795
|
+
* {@link stop}, {@link succeed} o {@link fail} para restaurar el output.
|
|
796
|
+
*
|
|
797
|
+
* @returns {void}
|
|
798
|
+
*/
|
|
619
799
|
start() {
|
|
620
800
|
if (this.interval) return;
|
|
621
801
|
this._logger.updateConfig({ outputMode: "silent" });
|
|
@@ -626,13 +806,36 @@ var SpinnerManager = class {
|
|
|
626
806
|
this.render();
|
|
627
807
|
}, FRAME_INTERVAL);
|
|
628
808
|
}
|
|
629
|
-
/**
|
|
809
|
+
/**
|
|
810
|
+
* Detiene la animaci\u00f3n y limpia la l\u00ednea, sin emitir mensaje de estado.
|
|
811
|
+
* Restaura el `outputMode` del logger a `'console'`.
|
|
812
|
+
*
|
|
813
|
+
* \u00datil cuando el caller ya emiti\u00f3 su propio output final y solo necesita
|
|
814
|
+
* desmontar el spinner. Para terminaci\u00f3n con tick/cross usa
|
|
815
|
+
* {@link succeed} / {@link fail}.
|
|
816
|
+
*
|
|
817
|
+
* @returns {void}
|
|
818
|
+
*/
|
|
630
819
|
stop() {
|
|
631
820
|
this.clearInterval();
|
|
632
821
|
this.clearLine();
|
|
633
822
|
this._logger.updateConfig({ outputMode: "console" });
|
|
634
823
|
}
|
|
635
|
-
/**
|
|
824
|
+
/**
|
|
825
|
+
* Detiene la animaci\u00f3n y emite el mensaje con un check verde (`\u2713`).
|
|
826
|
+
* Restaura el `outputMode` del logger a `'console'`.
|
|
827
|
+
*
|
|
828
|
+
* @param {string} [msg] - Texto final a mostrar. Si se omite, reutiliza
|
|
829
|
+
* el `message` con el que se construy\u00f3 el spinner (o el \u00faltimo seteado
|
|
830
|
+
* v\u00eda {@link text}).
|
|
831
|
+
* @returns {void}
|
|
832
|
+
*
|
|
833
|
+
* @example
|
|
834
|
+
* ```ts
|
|
835
|
+
* spinner.succeed(); // \u2192 " \u2713 <message inicial>"
|
|
836
|
+
* spinner.succeed('Hecho'); // \u2192 " \u2713 Hecho"
|
|
837
|
+
* ```
|
|
838
|
+
*/
|
|
636
839
|
succeed(msg) {
|
|
637
840
|
this.clearInterval();
|
|
638
841
|
this.clearLine();
|
|
@@ -640,7 +843,25 @@ var SpinnerManager = class {
|
|
|
640
843
|
process.stderr.write(` ${ANSI.fg.green}\u2713${ANSI.reset} ${text}\n`);
|
|
641
844
|
this._logger.updateConfig({ outputMode: "console" });
|
|
642
845
|
}
|
|
643
|
-
/**
|
|
846
|
+
/**
|
|
847
|
+
* Detiene la animaci\u00f3n y emite el mensaje con una cruz roja (`\u2717`).
|
|
848
|
+
* Restaura el `outputMode` del logger a `'console'`.
|
|
849
|
+
*
|
|
850
|
+
* @param {string} [msg] - Texto final a mostrar. Si se omite, reutiliza
|
|
851
|
+
* el `message` con el que se construy\u00f3 el spinner (o el \u00faltimo seteado
|
|
852
|
+
* v\u00eda {@link text}).
|
|
853
|
+
* @returns {void}
|
|
854
|
+
*
|
|
855
|
+
* @example
|
|
856
|
+
* ```ts
|
|
857
|
+
* try {
|
|
858
|
+
* await build();
|
|
859
|
+
* spinner.succeed('Build OK');
|
|
860
|
+
* } catch (e) {
|
|
861
|
+
* spinner.fail(`Build fallido: ${e.message}`);
|
|
862
|
+
* }
|
|
863
|
+
* ```
|
|
864
|
+
*/
|
|
644
865
|
fail(msg) {
|
|
645
866
|
this.clearInterval();
|
|
646
867
|
this.clearLine();
|
|
@@ -648,7 +869,14 @@ var SpinnerManager = class {
|
|
|
648
869
|
process.stderr.write(` ${ANSI.fg.red}\u2717${ANSI.reset} ${text}\n`);
|
|
649
870
|
this._logger.updateConfig({ outputMode: "console" });
|
|
650
871
|
}
|
|
651
|
-
/**
|
|
872
|
+
/**
|
|
873
|
+
* Reemplaza el texto mostrado al lado del frame sin reiniciar la animaci\u00f3n
|
|
874
|
+
* ni perder el frame actual. Pensado para actualizar progreso in-place
|
|
875
|
+
* (p.ej. contador de items procesados).
|
|
876
|
+
*
|
|
877
|
+
* @param {string} msg - Nuevo texto a mostrar.
|
|
878
|
+
* @returns {void}
|
|
879
|
+
*/
|
|
652
880
|
text(msg) {
|
|
653
881
|
this.message = msg;
|
|
654
882
|
}
|
|
@@ -668,28 +896,82 @@ var SpinnerManager = class {
|
|
|
668
896
|
}
|
|
669
897
|
};
|
|
670
898
|
/**
|
|
671
|
-
*
|
|
672
|
-
*
|
|
899
|
+
* Spinner degenerate para non-TTY (CI logs, pipes, `outputMode: 'silent'`).
|
|
900
|
+
*
|
|
901
|
+
* No anima nada: traduce los eventos del ciclo de vida del spinner a llamadas
|
|
902
|
+
* normales del logger (`info` en start, `success`/`error` en finish). Así el
|
|
903
|
+
* consumidor mantiene la misma API {@link ISpinnerHandle} sin saber si está
|
|
904
|
+
* corriendo en terminal interactiva o en un job de CI.
|
|
905
|
+
*
|
|
906
|
+
* A diferencia de {@link SpinnerManager}, **no** toca el `outputMode` del
|
|
907
|
+
* logger — no hay nada que mutear porque no hay frame animado que proteger.
|
|
673
908
|
*
|
|
674
909
|
* @implements {ISpinnerHandle}
|
|
910
|
+
*
|
|
911
|
+
* @example
|
|
912
|
+
* ```ts
|
|
913
|
+
* // En CI (sin TTY) el TerminalBridge entrega un NoopSpinner automáticamente:
|
|
914
|
+
* const s = logger.spinner('Running tests...');
|
|
915
|
+
* s.start(); // logger.info('Running tests...')
|
|
916
|
+
* s.succeed('All green'); // logger.success('All green')
|
|
917
|
+
* ```
|
|
918
|
+
*
|
|
919
|
+
* @see {@link SpinnerManager} para el path interactivo con animación.
|
|
675
920
|
*/
|
|
676
921
|
var NoopSpinner = class {
|
|
677
922
|
message;
|
|
678
923
|
_logger;
|
|
924
|
+
/**
|
|
925
|
+
* @param {string} message - Texto base; se reutiliza como mensaje final
|
|
926
|
+
* si {@link succeed} / {@link fail} se llaman sin argumento.
|
|
927
|
+
* @param {Logger} logger - Logger sobre el que se emiten los eventos.
|
|
928
|
+
*/
|
|
679
929
|
constructor(message, logger) {
|
|
680
930
|
this.message = message;
|
|
681
931
|
this._logger = logger;
|
|
682
932
|
}
|
|
933
|
+
/**
|
|
934
|
+
* Emite el mensaje inicial como `logger.info(...)`. No arranca ningún
|
|
935
|
+
* timer — en non-TTY no hay nada que animar.
|
|
936
|
+
*
|
|
937
|
+
* @returns {void}
|
|
938
|
+
*/
|
|
683
939
|
start() {
|
|
684
940
|
this._logger.info(this.message);
|
|
685
941
|
}
|
|
942
|
+
/**
|
|
943
|
+
* No-op — no hay animación que detener ni output que restaurar.
|
|
944
|
+
*
|
|
945
|
+
* @returns {void}
|
|
946
|
+
*/
|
|
686
947
|
stop() {}
|
|
948
|
+
/**
|
|
949
|
+
* Emite el mensaje final como `logger.success(...)`.
|
|
950
|
+
*
|
|
951
|
+
* @param {string} [msg] - Texto final; si se omite usa el `message`
|
|
952
|
+
* inicial o el último seteado vía {@link text}.
|
|
953
|
+
* @returns {void}
|
|
954
|
+
*/
|
|
687
955
|
succeed(msg) {
|
|
688
956
|
this._logger.success(msg ?? this.message);
|
|
689
957
|
}
|
|
958
|
+
/**
|
|
959
|
+
* Emite el mensaje final como `logger.error(...)`.
|
|
960
|
+
*
|
|
961
|
+
* @param {string} [msg] - Texto final; si se omite usa el `message`
|
|
962
|
+
* inicial o el último seteado vía {@link text}.
|
|
963
|
+
* @returns {void}
|
|
964
|
+
*/
|
|
690
965
|
fail(msg) {
|
|
691
966
|
this._logger.error(msg ?? this.message);
|
|
692
967
|
}
|
|
968
|
+
/**
|
|
969
|
+
* Actualiza el mensaje interno (sin output). Solo afecta al texto que
|
|
970
|
+
* emitirán {@link succeed} / {@link fail} cuando se invoquen sin argumento.
|
|
971
|
+
*
|
|
972
|
+
* @param {string} msg - Nuevo texto base.
|
|
973
|
+
* @returns {void}
|
|
974
|
+
*/
|
|
693
975
|
text(msg) {
|
|
694
976
|
this.message = msg;
|
|
695
977
|
}
|
|
@@ -697,4 +979,4 @@ var NoopSpinner = class {
|
|
|
697
979
|
//#endregion
|
|
698
980
|
export { renderDivider as a, formatBadge as c, renderBox as i, SpinnerManager as n, renderHeader as o, renderTable as r, renderStep as s, NoopSpinner as t };
|
|
699
981
|
|
|
700
|
-
//# sourceMappingURL=spinner-
|
|
982
|
+
//# sourceMappingURL=spinner-BtkwpzYv.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spinner-BtkwpzYv.js","names":[],"sources":["../../src/terminal/color-converter.ts","../../src/terminal/formatter.ts","../../src/playground/step.ts","../../src/playground/header.ts","../../src/playground/divider.ts","../../src/playground/box.ts","../../src/playground/cli-table.ts","../../src/playground/spinner.ts"],"sourcesContent":["/**\n * Color Converter - CSS colors to ANSI extended color codes\n * Supports 256-color and truecolor (24-bit) terminals\n */\n\nexport type ColorCapability = 'full' | 'basic' | 'none';\n\nexport interface RGB {\n r: number;\n g: number;\n b: number;\n}\n\nconst ANSI_16_COLORS: Record<string, { fg: string; bg: string; bright: { fg: string; bg: string } }> = {\n black: { fg: '30', bg: '40', bright: { fg: '90', bg: '100' } },\n red: { fg: '31', bg: '41', bright: { fg: '91', bg: '101' } },\n green: { fg: '32', bg: '42', bright: { fg: '92', bg: '102' } },\n yellow: { fg: '33', bg: '43', bright: { fg: '93', bg: '103' } },\n blue: { fg: '34', bg: '44', bright: { fg: '94', bg: '104' } },\n magenta: { fg: '35', bg: '45', bright: { fg: '95', bg: '105' } },\n cyan: { fg: '36', bg: '46', bright: { fg: '96', bg: '106' } },\n white: { fg: '37', bg: '47', bright: { fg: '97', bg: '107' } },\n gray: { fg: '90', bg: '100', bright: { fg: '37', bg: '47' } },\n grey: { fg: '90', bg: '100', bright: { fg: '37', bg: '47' } },\n};\n\nconst CSS_NAMED_COLORS: Record<string, string> = {\n aliceblue: '#f0f8ff', antiquewhite: '#faebd7', aqua: '#00ffff',\n aquamarine: '#7fffd4', azure: '#f0ffff', beige: '#f5f5dc',\n bisque: '#ffe4c4', black: '#000000', blanchedalmond: '#ffebcd',\n blue: '#0000ff', blueviolet: '#8a2be2', brown: '#a52a2a',\n burlywood: '#deb887', cadetblue: '#5f9ea0', chartreuse: '#7fff00',\n chocolate: '#d2691e', coral: '#ff7f50', cornflowerblue: '#6495ed',\n cornsilk: '#fff8dc', crimson: '#dc143c', cyan: '#00ffff',\n darkblue: '#00008b', darkcyan: '#008b8b', darkgoldenrod: '#b8860b',\n darkgray: '#a9a9a9', darkgreen: '#006400', darkkhaki: '#bdb76b',\n darkmagenta: '#8b008b', darkolivegreen: '#556b2f', darkorange: '#ff8c00',\n darkorchid: '#9932cc', darkred: '#8b0000', darksalmon: '#e9967a',\n darkseagreen: '#8fbc8f', darkslateblue: '#483d8b', darkslategray: '#2f4f4f',\n darkturquoise: '#00ced1', darkviolet: '#9400d3', deeppink: '#ff1493',\n deepskyblue: '#00bfff', dimgray: '#696969', dodgerblue: '#1e90ff',\n firebrick: '#b22222', floralwhite: '#fffaf0', forestgreen: '#228b22',\n fuchsia: '#ff00ff', gainsboro: '#dcdcdc', ghostwhite: '#f8f8ff',\n gold: '#ffd700', goldenrod: '#daa520', gray: '#808080',\n green: '#008000', greenyellow: '#adff2f', honeydew: '#f0fff0',\n hotpink: '#ff69b4', indianred: '#cd5c5c', indigo: '#4b0082',\n ivory: '#fffff0', khaki: '#f0e68c', lavender: '#e6e6fa',\n lavenderblush: '#fff0f5', lawngreen: '#7cfc00', lemonchiffon: '#fffacd',\n lightblue: '#add8e6', lightcoral: '#f08080', lightcyan: '#e0ffff',\n lightgoldenrodyellow: '#fafad2', lightgray: '#d3d3d3', lightgreen: '#90ee90',\n lightpink: '#ffb6c1', lightsalmon: '#ffa07a', lightseagreen: '#20b2aa',\n lightskyblue: '#87cefa', lightslategray: '#778899', lightsteelblue: '#b0c4de',\n lightyellow: '#ffffe0', lime: '#00ff00', limegreen: '#32cd32',\n linen: '#faf0e6', magenta: '#ff00ff', maroon: '#800000',\n mediumaquamarine: '#66cdaa', mediumblue: '#0000cd', mediumorchid: '#ba55d3',\n mediumpurple: '#9370db', mediumseagreen: '#3cb371', mediumslateblue: '#7b68ee',\n mediumspringgreen: '#00fa9a', mediumturquoise: '#48d1cc', mediumvioletred: '#c71585',\n midnightblue: '#191970', mintcream: '#f5fffa', mistyrose: '#ffe4e1',\n moccasin: '#ffe4b5', navajowhite: '#ffdead', navy: '#000080',\n oldlace: '#fdf5e6', olive: '#808000', olivedrab: '#6b8e23',\n orange: '#ffa500', orangered: '#ff4500', orchid: '#da70d6',\n palegoldenrod: '#eee8aa', palegreen: '#98fb98', paleturquoise: '#afeeee',\n palevioletred: '#db7093', papayawhip: '#ffefd5', peachpuff: '#ffdab9',\n peru: '#cd853f', pink: '#ffc0cb', plum: '#dda0dd',\n powderblue: '#b0e0e6', purple: '#800080', rebeccapurple: '#663399',\n red: '#ff0000', rosybrown: '#bc8f8f', royalblue: '#4169e1',\n saddlebrown: '#8b4513', salmon: '#fa8072', sandybrown: '#f4a460',\n seagreen: '#2e8b57', seashell: '#fff5ee', sienna: '#a0522d',\n silver: '#c0c0c0', skyblue: '#87ceeb', slateblue: '#6a5acd',\n slategray: '#708090', snow: '#fffafa', springgreen: '#00ff7f',\n steelblue: '#4682b4', tan: '#d2b48c', teal: '#008080',\n thistle: '#d8bfd8', tomato: '#ff6347', turquoise: '#40e0d0',\n violet: '#ee82ee', wheat: '#f5deb3', white: '#ffffff',\n whitesmoke: '#f5f5f5', yellow: '#ffff00', yellowgreen: '#9acd32',\n};\n\nexport function hexToRgb(hex: string): RGB {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (!result || !result[1] || !result[2] || !result[3]) {\n return { r: 255, g: 255, b: 255 };\n }\n return {\n r: parseInt(result[1], 16),\n g: parseInt(result[2], 16),\n b: parseInt(result[3], 16),\n };\n}\n\nexport function rgbToHex(r: number, g: number, b: number): string {\n return '#' + [r, g, b].map(x => x.toString(16).padStart(2, '0')).join('');\n}\n\nexport function hexTo256(hex: string): number {\n const { r, g, b } = hexToRgb(hex);\n\n if (r === g && g === b) {\n if (r < 8) return 16;\n if (r > 248) return 231;\n return Math.round(((r - 8) / 247) * 24) + 232;\n }\n\n const ri = Math.round(r / 255 * 5);\n const gi = Math.round(g / 255 * 5);\n const bi = Math.round(b / 255 * 5);\n\n return 16 + (36 * ri) + (6 * gi) + bi;\n}\n\nexport function colorToHex(color: string): string {\n if (color.startsWith('#')) {\n return color;\n }\n\n const named = CSS_NAMED_COLORS[color.toLowerCase()];\n if (named) {\n return named;\n }\n\n const rgbMatch = color.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (rgbMatch && rgbMatch[1] && rgbMatch[2] && rgbMatch[3]) {\n return rgbToHex(\n parseInt(rgbMatch[1]),\n parseInt(rgbMatch[2]),\n parseInt(rgbMatch[3])\n );\n }\n\n return '#ffffff';\n}\n\nexport function getANSIForeground(color: string, capability: ColorCapability): string {\n if (capability === 'none') return '';\n\n const lowerColor = color.toLowerCase();\n\n if (capability === 'basic' && ANSI_16_COLORS[lowerColor]) {\n return `\\x1b[${ANSI_16_COLORS[lowerColor].fg}m`;\n }\n\n if (capability === 'basic') {\n const hex = colorToHex(color);\n const nearestBasic = findNearestBasicColor(hex);\n const basicColor = ANSI_16_COLORS[nearestBasic];\n return basicColor ? `\\x1b[${basicColor.fg}m` : '\\x1b[37m';\n }\n\n const hex = colorToHex(color);\n const { r, g, b } = hexToRgb(hex);\n return `\\x1b[38;2;${r};${g};${b}m`;\n}\n\nexport function getANSIBackground(color: string, capability: ColorCapability): string {\n if (capability === 'none') return '';\n\n const lowerColor = color.toLowerCase();\n\n if (capability === 'basic' && ANSI_16_COLORS[lowerColor]) {\n return `\\x1b[${ANSI_16_COLORS[lowerColor].bg}m`;\n }\n\n if (capability === 'basic') {\n const hex = colorToHex(color);\n const nearestBasic = findNearestBasicColor(hex);\n const basicColor = ANSI_16_COLORS[nearestBasic];\n return basicColor ? `\\x1b[${basicColor.bg}m` : '\\x1b[47m';\n }\n\n const hex = colorToHex(color);\n const { r, g, b } = hexToRgb(hex);\n return `\\x1b[48;2;${r};${g};${b}m`;\n}\n\nexport function getANSI256Foreground(colorIndex: number): string {\n return `\\x1b[38;5;${colorIndex}m`;\n}\n\nexport function getANSI256Background(colorIndex: number): string {\n return `\\x1b[48;5;${colorIndex}m`;\n}\n\nfunction findNearestBasicColor(hex: string): string {\n const { r, g, b } = hexToRgb(hex);\n const basicColors: Record<string, RGB> = {\n black: { r: 0, g: 0, b: 0 },\n red: { r: 205, g: 0, b: 0 },\n green: { r: 0, g: 205, b: 0 },\n yellow: { r: 205, g: 205, b: 0 },\n blue: { r: 0, g: 0, b: 238 },\n magenta: { r: 205, g: 0, b: 205 },\n cyan: { r: 0, g: 205, b: 205 },\n white: { r: 229, g: 229, b: 229 },\n };\n\n let nearest = 'white';\n let minDistance = Infinity;\n\n for (const [name, rgb] of Object.entries(basicColors)) {\n const distance = Math.sqrt(\n Math.pow(r - rgb.r, 2) +\n Math.pow(g - rgb.g, 2) +\n Math.pow(b - rgb.b, 2)\n );\n if (distance < minDistance) {\n minDistance = distance;\n nearest = name;\n }\n }\n\n return nearest;\n}\n\nexport function extractGradientColors(gradient: string): string[] {\n const hexMatches = gradient.match(/#[a-fA-F0-9]{6}/g) || [];\n const rgbMatches = gradient.match(/rgba?\\([^)]+\\)/g) || [];\n const namedMatches = gradient.match(/,\\s*([a-z]+)(?:\\s|,|\\))/gi) || [];\n\n const colors: string[] = [\n ...hexMatches,\n ...rgbMatches.map(colorToHex),\n ...namedMatches.map(m => {\n const name = m.replace(/[,\\s)]/g, '').toLowerCase();\n return CSS_NAMED_COLORS[name] || null;\n }).filter((c): c is string => c !== null)\n ];\n\n return colors.length > 0 ? colors : ['#ffffff'];\n}\n\nexport function gradientToSingleColor(gradient: string): string {\n const colors = extractGradientColors(gradient);\n if (colors.length === 0) return '#ffffff';\n if (colors.length === 1) return colors[0] ?? '#ffffff';\n\n const rgbs = colors.map(c => hexToRgb(colorToHex(c)));\n const avgR = Math.round(rgbs.reduce((sum, rgb) => sum + rgb.r, 0) / rgbs.length);\n const avgG = Math.round(rgbs.reduce((sum, rgb) => sum + rgb.g, 0) / rgbs.length);\n const avgB = Math.round(rgbs.reduce((sum, rgb) => sum + rgb.b, 0) / rgbs.length);\n\n return rgbToHex(avgR, avgG, avgB);\n}\n\nexport function cssColorToANSI(\n cssColor: string,\n capability: ColorCapability,\n isBackground: boolean = false\n): string {\n if (capability === 'none') return '';\n\n let resolvedColor: string;\n\n if (cssColor.includes('gradient')) {\n resolvedColor = gradientToSingleColor(cssColor);\n } else {\n resolvedColor = colorToHex(cssColor);\n }\n\n return isBackground\n ? getANSIBackground(resolvedColor, capability)\n : getANSIForeground(resolvedColor, capability);\n}\n\nexport const ANSI = {\n reset: '\\x1b[0m',\n bold: '\\x1b[1m',\n dim: '\\x1b[2m',\n italic: '\\x1b[3m',\n underline: '\\x1b[4m',\n blink: '\\x1b[5m',\n inverse: '\\x1b[7m',\n hidden: '\\x1b[8m',\n strikethrough: '\\x1b[9m',\n\n fg: {\n black: '\\x1b[30m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n magenta: '\\x1b[35m',\n cyan: '\\x1b[36m',\n white: '\\x1b[37m',\n gray: '\\x1b[90m',\n brightRed: '\\x1b[91m',\n brightGreen: '\\x1b[92m',\n brightYellow: '\\x1b[93m',\n brightBlue: '\\x1b[94m',\n brightMagenta: '\\x1b[95m',\n brightCyan: '\\x1b[96m',\n brightWhite: '\\x1b[97m',\n },\n\n bg: {\n black: '\\x1b[40m',\n red: '\\x1b[41m',\n green: '\\x1b[42m',\n yellow: '\\x1b[43m',\n blue: '\\x1b[44m',\n magenta: '\\x1b[45m',\n cyan: '\\x1b[46m',\n white: '\\x1b[47m',\n gray: '\\x1b[100m',\n brightRed: '\\x1b[101m',\n brightGreen: '\\x1b[102m',\n brightYellow: '\\x1b[103m',\n brightBlue: '\\x1b[104m',\n brightMagenta: '\\x1b[105m',\n brightCyan: '\\x1b[106m',\n brightWhite: '\\x1b[107m',\n },\n\n rgb: (r: number, g: number, b: number) => `\\x1b[38;2;${r};${g};${b}m`,\n bgRgb: (r: number, g: number, b: number) => `\\x1b[48;2;${r};${g};${b}m`,\n color256: (n: number) => `\\x1b[38;5;${n}m`,\n bgColor256: (n: number) => `\\x1b[48;5;${n}m`,\n};\n","/**\n * Terminal Formatter - Alignment, key-value, and advanced terminal formatting\n */\n\nimport { getTerminalWidth } from '../utils/environment-detector.js';\nimport { getANSIForeground, getANSIBackground, ANSI, type ColorCapability } from './color-converter.js';\nimport type { ColumnConfig, ColumnAlign, BadgeStyle, TimestampFormat, LogOptions } from '../types/index.js';\n\nexport function stripAnsi(str: string): string {\n return str.replace(/\\x1b\\[[0-9;]*m/g, '');\n}\n\nexport function getVisibleLength(str: string): number {\n return stripAnsi(str).length;\n}\n\nexport function padToWidth(str: string, width: number, align: ColumnAlign = 'left'): string {\n const visibleLen = getVisibleLength(str);\n if (visibleLen >= width) return str;\n\n const padding = width - visibleLen;\n\n switch (align) {\n case 'right':\n return ' '.repeat(padding) + str;\n case 'center':\n const leftPad = Math.floor(padding / 2);\n const rightPad = padding - leftPad;\n return ' '.repeat(leftPad) + str + ' '.repeat(rightPad);\n case 'left':\n default:\n return str + ' '.repeat(padding);\n }\n}\n\nexport function formatWithRightAlign(\n leftContent: string,\n rightContent: string,\n maxWidth?: number\n): string {\n const width = maxWidth ?? getTerminalWidth();\n const leftLen = getVisibleLength(leftContent);\n const rightLen = getVisibleLength(rightContent);\n\n const gap = width - leftLen - rightLen;\n if (gap <= 1) {\n return `${leftContent} ${rightContent}`;\n }\n\n return `${leftContent}${' '.repeat(gap)}${rightContent}`;\n}\n\nexport function formatColumns(\n columns: ColumnConfig[],\n maxWidth?: number,\n colorCapability: ColorCapability = 'full'\n): string {\n const width = maxWidth ?? getTerminalWidth();\n const totalColumns = columns.length;\n\n const columnsWithWidths = columns.map((col, idx) => {\n if (col.width) return { ...col, calculatedWidth: col.width };\n\n const remainingWidth = width - columns\n .filter((c, i) => i !== idx && c.width)\n .reduce((sum, c) => sum + (c.width ?? 0), 0);\n\n const autoColumns = columns.filter(c => !c.width).length;\n const calculatedWidth = Math.floor(remainingWidth / autoColumns);\n\n return { ...col, calculatedWidth };\n });\n\n return columnsWithWidths.map(col => {\n let content = col.content;\n\n if (col.color && colorCapability !== 'none') {\n const colorCode = getANSIForeground(col.color, colorCapability);\n content = `${colorCode}${content}${ANSI.reset}`;\n }\n\n return padToWidth(content, col.calculatedWidth, col.align);\n }).join('');\n}\n\nexport function formatKeyValue(\n obj: Record<string, unknown>,\n colorCapability: ColorCapability = 'full',\n options: { separator?: string; keyColor?: string; valueColor?: string } = {}\n): string {\n const {\n separator = ' ',\n keyColor = '#888888',\n valueColor = '#00ffff'\n } = options;\n\n const entries = Object.entries(obj);\n if (entries.length === 0) return '';\n\n const keyColorCode = colorCapability !== 'none'\n ? getANSIForeground(keyColor, colorCapability)\n : '';\n const valueColorCode = colorCapability !== 'none'\n ? getANSIForeground(valueColor, colorCapability)\n : '';\n const reset = colorCapability !== 'none' ? ANSI.reset : '';\n\n return entries\n .map(([key, value]) => {\n const valueStr = typeof value === 'object'\n ? JSON.stringify(value)\n : String(value);\n return `${keyColorCode}${key}:${reset} ${valueColorCode}${valueStr}${reset}`;\n })\n .join(separator);\n}\n\nexport function isKeyValueObject(obj: unknown): obj is Record<string, unknown> {\n if (typeof obj !== 'object' || obj === null) return false;\n if (Array.isArray(obj)) return false;\n\n const proto = Object.getPrototypeOf(obj);\n if (proto !== Object.prototype && proto !== null) return false;\n\n const values = Object.values(obj);\n return values.every(v =>\n typeof v === 'string' ||\n typeof v === 'number' ||\n typeof v === 'boolean' ||\n v === null\n );\n}\n\nexport function formatBadge(\n badge: string,\n style: BadgeStyle = 'brackets',\n colorCapability: ColorCapability = 'full',\n color?: string\n): string {\n const reset = colorCapability !== 'none' ? ANSI.reset : '';\n\n const text = badge.toUpperCase();\n\n switch (style) {\n case 'rounded':\n const colorCode1 = color && colorCapability !== 'none' ? getANSIForeground(color, colorCapability) : '';\n const bgBlack1 = colorCapability !== 'none' ? ANSI.bg.black : '';\n return `${bgBlack1}${colorCode1}⟨${text}⟩${reset}`;\n case 'plain':\n const colorCode2 = color && colorCapability !== 'none' ? getANSIForeground(color, colorCapability) : '';\n return `${colorCode2}${text}${reset}`;\n case 'unicode':\n const colorCode3 = color && colorCapability !== 'none' ? getANSIForeground(color, colorCapability) : '';\n const bgBlack3 = colorCapability !== 'none' ? ANSI.bg.black : '';\n return `${bgBlack3}${colorCode3}╭${text}╮${reset}`;\n case 'pill':\n // Badge con background de color y texto blanco/negro\n const bgColor = color && colorCapability !== 'none' ? getANSIBackground(color, colorCapability) : '';\n const fgColor = colorCapability !== 'none' ? getANSIForeground('#000000', colorCapability) : '';\n return `${bgColor}${fgColor}[${text}]${reset}`;\n case 'brackets':\n default:\n const colorCode5 = color && colorCapability !== 'none' ? getANSIForeground(color, colorCapability) : '';\n const bgBlack5 = colorCapability !== 'none' ? ANSI.bg.black : '';\n return `${bgBlack5}${colorCode5}[${text}]${reset}`;\n }\n}\n\nexport function formatTimestamp(\n date: Date = new Date(),\n format: TimestampFormat = 'time'\n): string {\n switch (format) {\n case 'iso':\n return date.toISOString();\n case 'date':\n return date.toISOString().split('T')[0] ?? '';\n case 'time':\n return date.toTimeString().slice(0, 8);\n case 'timeMs':\n return date.toTimeString().slice(0, 8) + '.' +\n String(date.getMilliseconds()).padStart(3, '0');\n case 'relative':\n return formatRelativeTime(date);\n case 'elapsed':\n return formatElapsedTime(date);\n case 'custom':\n default:\n return date.toLocaleTimeString();\n }\n}\n\nlet startTime: number | null = null;\n\nexport function formatRelativeTime(date: Date): string {\n if (startTime === null) {\n startTime = Date.now();\n }\n\n const diff = date.getTime() - startTime;\n\n if (diff < 1000) {\n return `+${diff}ms`;\n } else if (diff < 60000) {\n return `+${(diff / 1000).toFixed(1)}s`;\n } else {\n const mins = Math.floor(diff / 60000);\n const secs = Math.floor((diff % 60000) / 1000);\n return `+${mins}m${secs}s`;\n }\n}\n\nexport function formatElapsedTime(date: Date): string {\n if (startTime === null) {\n startTime = Date.now();\n }\n\n const diff = date.getTime() - startTime;\n const hours = Math.floor(diff / 3600000);\n const mins = Math.floor((diff % 3600000) / 60000);\n const secs = Math.floor((diff % 60000) / 1000);\n\n return `${String(hours).padStart(2, '0')}:${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`;\n}\n\nexport function resetStartTime(): void {\n startTime = Date.now();\n}\n\nexport function applyLogOptions(\n message: string,\n options: LogOptions,\n colorCapability: ColorCapability = 'full'\n): string {\n let result = message;\n\n if (options.rightAlign) {\n result = formatWithRightAlign(message, options.rightAlign);\n }\n\n return result;\n}\n","/**\n * @fileoverview Step progress renderer for CLI primitives\n */\n\nimport { getANSIForeground, ANSI, type ColorCapability } from '../terminal/color-converter.js';\n\n/**\n * Renderiza un indicador de progreso de step con el formato ` [n/total] msg`,\n * donde el `[n/total]` se emite en cian bold (respetando `colorCap`) para\n * destacarlo del mensaje descriptivo. Pensado para output secuencial de CLI\n * tipo \"steps de un build\", \"fases de un deploy\" o \"tareas de un script\".\n *\n * No hace ningún chequeo de rango sobre `current`/`total` — el caller es\n * responsable de pasar valores coherentes (se renderizan tal cual).\n *\n * @param current - Número de step actual (típicamente 1-based).\n * @param total - Total de steps del proceso.\n * @param msg - Descripción corta del step en curso.\n * @param colorCap - Capacidad de color del terminal destino. Si es `'none'`,\n * el label `[n/total]` se emite sin color.\n * @returns String de una sola línea con formato ` [n/total] msg`.\n *\n * @example\n * ```ts\n * const steps = ['Resolving deps', 'Bundling', 'Writing dist'];\n * steps.forEach((step, i) => {\n * process.stdout.write(renderStep(i + 1, steps.length, step, 'full') + '\\n');\n * });\n * // [1/3] Resolving deps\n * // [2/3] Bundling\n * // [3/3] Writing dist\n * ```\n */\nexport function renderStep(current: number, total: number, msg: string, colorCap: ColorCapability): string {\n const label = `[${current}/${total}]`;\n const colored = colorCap !== 'none'\n ? getANSIForeground('#00bcd4', colorCap) + ANSI.bold + label + ANSI.reset\n : label;\n return ` ${colored} ${msg}`;\n}\n","/**\n * @fileoverview Header renderer for CLI primitives\n */\n\nimport { ANSI } from '../terminal/color-converter.js';\n\n/**\n * Renderiza un header de sección: `title` en bold seguido opcionalmente de\n * `subtitle` en dim (ANSI `2`), ideal para marcar bloques en output de CLI.\n * No usa colores de foreground — sólo atributos de texto, así que el renderer\n * es seguro para cualquier terminal sin importar la paleta del theme activo.\n *\n * @param title - Texto principal del header (siempre en bold).\n * @param subtitle - Texto secundario a la derecha del título; se renderiza\n * dimmed y separado por un espacio. Omitir si no aplica.\n * @returns String de una línea con formato ` <bold>title</bold> <dim>subtitle</dim>`.\n *\n * @example\n * ```ts\n * process.stdout.write(renderHeader('Deploy', 'production · us-east-1') + '\\n');\n * // **Deploy** production · us-east-1 (con atributos ANSI aplicados)\n * ```\n *\n * @example\n * ```ts\n * // Header sin subtítulo\n * process.stdout.write(renderHeader('Build summary') + '\\n');\n * ```\n */\nexport function renderHeader(title: string, subtitle?: string): string {\n const t = ANSI.bold + title + ANSI.reset;\n const s = subtitle ? ANSI.dim + ` ${subtitle}` + ANSI.reset : '';\n return ` ${t}${s}`;\n}\n","/**\n * @fileoverview Divider renderer for CLI primitives\n */\n\nimport { ANSI } from '../terminal/color-converter.js';\nimport { getTerminalWidth } from '../utils/environment-detector.js';\n\n/**\n * Renderiza una línea divisoria horizontal dimmed (ANSI `2`) usando el\n * caracter `─`. Por defecto el ancho es `min(terminalWidth - 4, 60)` para\n * no ocupar todo el ancho de ventana y quedar visualmente alineado con otros\n * primitives (box, header, table) que dejan 2 espacios de indentación.\n *\n * @param width - Ancho explícito en columnas visibles. Si se omite, se calcula\n * automáticamente a partir del ancho del terminal (capped a 60).\n * @returns String de una línea con `width` caracteres `─` envueltos en ANSI dim.\n *\n * @example\n * ```ts\n * // Divider automático (respeta el ancho del terminal)\n * process.stdout.write(renderDivider() + '\\n');\n * ```\n *\n * @example\n * ```ts\n * // Divider de ancho fijo para alinear con otra salida\n * process.stdout.write(renderDivider(40) + '\\n');\n * ```\n *\n * @see {@link getTerminalWidth} para la detección de ancho cuando `width` se omite.\n */\nexport function renderDivider(width?: number): string {\n const w = width ?? Math.min(getTerminalWidth() - 4, 60);\n return ANSI.dim + ' ' + '\\u2500'.repeat(w) + ANSI.reset;\n}\n","/**\n * @fileoverview Box renderer for CLI primitives\n */\n\nimport type { IBoxOptions } from '../types/core.js';\nimport type { ColorCapability } from '../terminal/color-converter.js';\nimport { getANSIForeground, ANSI } from '../terminal/color-converter.js';\nimport { getTerminalWidth } from '../utils/environment-detector.js';\nimport { stripAnsi, getVisibleLength } from '../terminal/formatter.js';\n\n/**\n * Mapa de juegos de caracteres Unicode para los 4 estilos de borde soportados\n * por {@link renderBox}. Cada entrada expone las 4 esquinas (`tl`, `tr`, `bl`,\n * `br`), el caracter horizontal (`h`) y el vertical (`v`) que componen el marco.\n *\n * - `single`: l\\u00edneas finas (U+2500 / U+2502).\n * - `rounded`: igual que `single` con esquinas redondeadas.\n * - `double`: l\\u00edneas dobles (U+2550 / U+2551), alto contraste visual.\n * - `bold`: l\\u00edneas gruesas (U+2501 / U+2503), para destacar bloques cr\\u00edticos.\n *\n * @internal Lookup interno del renderer; no es API p\\u00fablica.\n */\nconst BORDER_CHARS = {\n single: { tl: '\\u250c', tr: '\\u2510', bl: '\\u2514', br: '\\u2518', h: '\\u2500', v: '\\u2502' },\n rounded: { tl: '\\u256d', tr: '\\u256e', bl: '\\u2570', br: '\\u256f', h: '\\u2500', v: '\\u2502' },\n double: { tl: '\\u2554', tr: '\\u2557', bl: '\\u255a', br: '\\u255d', h: '\\u2550', v: '\\u2551' },\n bold: { tl: '\\u250f', tr: '\\u2513', bl: '\\u2517', br: '\\u251b', h: '\\u2501', v: '\\u2503' },\n} as const;\n\n/**\n * Renderiza `content` envuelto en un box con borde Unicode, respetando el\n * ancho del terminal. El ancho interno se calcula a partir de la l\\u00ednea m\\u00e1s\n * larga (o del {@link IBoxOptions.title} si es m\\u00e1s ancho) y se acota a\n * `min(terminalWidth - 4, 80)` columnas para no romper layouts estrechos.\n *\n * El padding se aplica como l\\u00edneas vac\\u00edas sim\\u00e9tricas arriba/abajo del\n * contenido. Si `borderColor` se omite o `colorCap` es `'none'`, el borde se\n * emite sin secuencias ANSI (output plain-text seguro para logs y pipes).\n *\n * @param content - Texto a envolver; puede contener m\\u00faltiples l\\u00edneas (`\\n`) y\n * secuencias ANSI embebidas \\u2014 el c\\u00e1lculo de ancho usa el largo visible.\n * @param options - Configuraci\\u00f3n del box (title, borderColor, borderStyle,\n * padding). Ver {@link IBoxOptions}.\n * @param colorCap - Capacidad de color del terminal destino. Si es `'none'`,\n * se omite cualquier secuencia ANSI.\n * @returns String multilinea con el box ya construido (sin trailing newline).\n *\n * @example\n * ```ts\n * // Box b\\u00e1sico con borde redondeado (default)\n * process.stdout.write(renderBox('Deploy completado') + '\\n');\n * ```\n *\n * @example\n * ```ts\n * // Box con t\\u00edtulo embebido en el borde superior y color custom\n * process.stdout.write(renderBox('Service: auth-svc\\nStatus: healthy', {\n * title: 'Health Check',\n * borderColor: '#00bcd4',\n * borderStyle: 'double',\n * padding: 1\n * }) + '\\n');\n * ```\n *\n * @see {@link IBoxOptions} para el detalle de cada opci\\u00f3n.\n * @see {@link getTerminalWidth} para la detecci\\u00f3n de ancho.\n */\nexport function renderBox(content: string, options: IBoxOptions = {}, colorCap: ColorCapability = 'full'): string {\n const {\n title,\n borderColor,\n borderStyle = 'rounded',\n padding = 0,\n } = options;\n\n const chars = BORDER_CHARS[borderStyle] ?? BORDER_CHARS.rounded;\n const lines = content.split('\\n');\n const maxTermWidth = Math.min(getTerminalWidth() - 4, 80);\n\n // Calculate content width from visible text\n const contentWidths = lines.map(l => getVisibleLength(l));\n const titleWidth = title ? stripAnsi(title).length + 2 : 0; // +2 for spaces around title\n const maxContentWidth = Math.max(...contentWidths, titleWidth);\n const innerWidth = Math.min(maxContentWidth + 2, maxTermWidth); // +2 for horizontal padding\n\n // Color wrapper for border chars\n const bc = borderColor && colorCap !== 'none'\n ? getANSIForeground(borderColor, colorCap)\n : '';\n const reset = bc ? ANSI.reset : '';\n\n const wrap = (char: string) => `${bc}${char}${reset}`;\n\n // Build top border (with optional title)\n let topBorder: string;\n if (title) {\n const titleStr = ` ${title} `;\n const afterTitle = innerWidth - stripAnsi(titleStr).length;\n topBorder = ` ${wrap(chars.tl)}${wrap(chars.h)}${wrap(titleStr)}${wrap(chars.h.repeat(Math.max(0, afterTitle - 1)))}${wrap(chars.tr)}`;\n } else {\n topBorder = ` ${wrap(chars.tl)}${wrap(chars.h.repeat(innerWidth))}${wrap(chars.tr)}`;\n }\n\n // Build bottom border\n const bottomBorder = ` ${wrap(chars.bl)}${wrap(chars.h.repeat(innerWidth))}${wrap(chars.br)}`;\n\n // Build padding lines\n const emptyLine = ` ${wrap(chars.v)}${' '.repeat(innerWidth)}${wrap(chars.v)}`;\n const paddingLines = padding > 0 ? Array(padding).fill(emptyLine) : [];\n\n // Build content lines\n const contentLines = lines.map(line => {\n const visible = getVisibleLength(line);\n const pad = innerWidth - visible - 1; // -1 for left space\n return ` ${wrap(chars.v)} ${line}${' '.repeat(Math.max(0, pad))}${wrap(chars.v)}`;\n });\n\n return [\n topBorder,\n ...paddingLines,\n ...contentLines,\n ...paddingLines,\n bottomBorder,\n ].join('\\n');\n}\n","/**\n * @fileoverview CLI table renderer for CLI primitives\n */\n\nimport type { ITableOptions } from '../types/core.js';\nimport type { ColorCapability } from '../terminal/color-converter.js';\nimport { getANSIForeground, ANSI } from '../terminal/color-converter.js';\nimport { getVisibleLength, padToWidth } from '../terminal/formatter.js';\n\n/**\n * Renderiza un array de objetos como tabla ASCII alineada, con headers en\n * cian bold y separador (`─`) bajo la cabecera. Las columnas se autodetectan\n * a partir de las keys del primer row salvo que `options.columns` las imponga,\n * y los labels se toman de `options.head` (default: nombres de columna).\n *\n * El ancho de cada columna se calcula como `max(header, valor más largo) + 2`\n * para garantizar padding horizontal consistente. Si `colorCap` es `'none'`,\n * se omiten todas las secuencias ANSI (útil para logs plain-text o CI).\n *\n * @param rows - Array de row objects. Un array vacío devuelve string vacío.\n * @param options - Ver {@link ITableOptions} para `columns` y `head`.\n * @param colorCap - Capacidad de color del terminal destino.\n * @returns String multilinea con la tabla (header + separator + data rows),\n * o `''` si `rows` está vacío.\n *\n * @example\n * ```ts\n * // Auto-detect columnas desde las keys del primer row\n * const rows = [\n * { service: 'auth', status: 'healthy', latency: 12 },\n * { service: 'api', status: 'degraded', latency: 245 }\n * ];\n * process.stdout.write(renderTable(rows) + '\\n');\n * // ┌─────────┬──────────┬─────────┐\n * // │ service │ status │ latency │\n * // ─────────────────────────────────\n * // │ auth │ healthy │ 12 │\n * // │ api │ degraded │ 245 │\n * ```\n *\n * @example\n * ```ts\n * // Forzar columnas y renombrar headers\n * process.stdout.write(renderTable(rows, {\n * columns: ['service', 'latency'],\n * head: ['Service', 'Latency (ms)']\n * }, 'none') + '\\n');\n * ```\n *\n * @see {@link ITableOptions} para las opciones disponibles.\n * @see {@link getVisibleLength} y {@link padToWidth} para el cálculo de ancho.\n */\nexport function renderTable(\n rows: Record<string, unknown>[],\n options: ITableOptions = {},\n colorCap: ColorCapability = 'full'\n): string {\n if (rows.length === 0) return '';\n\n // Determine columns from options or first row's keys\n const columns = options.columns ?? Object.keys(rows[0]!);\n const headers = options.head ?? columns;\n\n // Calculate column widths (max of header and all values)\n const colWidths = columns.map((col, i) => {\n const headerLen = getVisibleLength(headers[i] ?? col);\n const maxValueLen = rows.reduce((max, row) => {\n const val = String(row[col] ?? '');\n return Math.max(max, getVisibleLength(val));\n }, 0);\n return Math.max(headerLen, maxValueLen) + 2; // +2 for padding\n });\n\n // Color helpers\n const cyan = colorCap !== 'none' ? getANSIForeground('#00bcd4', colorCap) : '';\n const dim = colorCap !== 'none' ? ANSI.dim : '';\n const reset = colorCap !== 'none' ? ANSI.reset : '';\n\n // Build header row\n const headerRow = ' ' + columns.map((col, i) => {\n const label = headers[i] ?? col;\n return cyan + ANSI.bold + padToWidth(` ${label}`, colWidths[i]!) + reset;\n }).join('');\n\n // Build separator\n const separator = ' ' + dim + colWidths.map(w => '\\u2500'.repeat(w)).join('\\u2500') + reset;\n\n // Build data rows\n const dataRows = rows.map(row => {\n return ' ' + columns.map((col, i) => {\n const val = String(row[col] ?? '');\n return padToWidth(` ${val}`, colWidths[i]!);\n }).join('');\n });\n\n return [headerRow, separator, ...dataRows].join('\\n');\n}\n","/**\n * @fileoverview Built-in spinner implementation for CLI primitives.\n *\n * Expone dos implementaciones de {@link ISpinnerHandle}:\n * - {@link SpinnerManager}: spinner braille animado para TTY interactiva.\n * - {@link NoopSpinner}: fallback sin animaci\\u00f3n para non-TTY / silent mode.\n *\n * La factor\\u00eda que decide cu\\u00e1l instanciar vive en `TerminalBridge.spinner()`;\n * los consumers rara vez construyen estas clases directamente.\n */\n\nimport type { ISpinnerHandle, LoggerConfig } from '../types/core.js';\nimport type { Logger } from '../Logger.js';\nimport { ANSI } from '../terminal/color-converter.js';\n\n/**\n * Frames braille usados por la animaci\\u00f3n del spinner. Cada frame es un\n * car\\u00e1cter del bloque Unicode Braille Patterns (U+2800\\u2013U+28FF) que da la\n * ilusi\\u00f3n de rotaci\\u00f3n al ciclarlos a ~12 FPS. Elegidos sobre caracteres\n * ASCII (`|/-\\`) porque renderizan m\\u00e1s suaves en terminales modernas.\n */\nconst SPINNER_FRAMES = ['\\u280b', '\\u2819', '\\u2839', '\\u2838', '\\u283c', '\\u2834', '\\u2826', '\\u2827', '\\u2807', '\\u280f'];\n\n/**\n * Intervalo entre frames del spinner en milisegundos. 80 ms \\u2248 12.5 FPS:\n * suficientemente r\\u00e1pido para sentirse responsivo sin consumir CPU\n * perceptiblemente en runs largos.\n */\nconst FRAME_INTERVAL = 80;\n\n/**\n * Spinner interactivo para TTY: cicla frames braille reescribiendo la l\\u00ednea\n * actual en su sitio (no emite l\\u00edneas nuevas hasta el stop).\n *\n * Para no poluir stdout piped ni entrelazarse con el output normal del\n * {@link Logger}, hace dos cosas no obvias:\n * 1. Escribe SIEMPRE a `process.stderr` (carriage return + `\\x1b[K` para\n * limpiar la l\\u00ednea antes de cada render).\n * 2. Con `start()` mutea el logger (`outputMode: 'silent'`) y lo restaura a\n * `'console'` en cualquier m\\u00e9todo de finalizaci\\u00f3n (`stop`/`succeed`/`fail`).\n * Sin esto, los logs del usuario se imprimir\\u00edan encima del frame animado.\n *\n * No gestiona TTY detection \\u2014 quien lo instancia (`TerminalBridge`) ya valid\\u00f3\n * que hay TTY. Para non-TTY ver {@link NoopSpinner}.\n *\n * @implements {ISpinnerHandle}\n *\n * @example\n * ```ts\n * const spinner = new SpinnerManager('Compilando...', logger.config, logger);\n * spinner.start();\n * // ...trabajo as\\u00edncrono...\n * spinner.succeed('Build OK');\n * // stderr: \" \\u2713 Build OK\"\n * ```\n *\n * @see {@link NoopSpinner} para el path non-TTY.\n * @see {@link ISpinnerHandle} para el contrato de la API p\\u00fablica.\n */\nexport class SpinnerManager implements ISpinnerHandle {\n private message: string;\n private frameIndex = 0;\n private interval: ReturnType<typeof setInterval> | null = null;\n private _logger: Logger;\n\n /**\n * @param {string} message - Texto a mostrar al lado del frame animado.\n * Mutables luego v\\u00eda {@link SpinnerManager.text}.\n * @param {LoggerConfig} _config - Reservado para configuraci\\u00f3n futura;\n * actualmente no se lee dentro de la clase (lo conserva solo el caller).\n * @param {Logger} logger - Instancia del logger due\\u00f1a del spinner. Se\n * mutea/restaura con `updateConfig({ outputMode })` en start/stop.\n */\n constructor(message: string, _config: LoggerConfig, logger: Logger) {\n this.message = message;\n this._logger = logger;\n }\n\n /**\n * Arranca la animaci\\u00f3n. Idempotente: si ya est\\u00e1 corriendo, no hace nada.\n *\n * Como efecto lateral mutea el logger pasado al constructor cambiando su\n * `outputMode` a `'silent'` \\u2014 cualquier log durante la animaci\\u00f3n quedar\\u00eda\n * bufferizado y se descarta al restaurar el modo. Llama siempre a\n * {@link stop}, {@link succeed} o {@link fail} para restaurar el output.\n *\n * @returns {void}\n */\n start(): void {\n if (this.interval) return; // Already running\n\n // Switch logger to buffer mode to prevent garbled output\n this._logger.updateConfig({ outputMode: 'silent' });\n\n this.frameIndex = 0;\n this.render();\n this.interval = setInterval(() => {\n this.frameIndex = (this.frameIndex + 1) % SPINNER_FRAMES.length;\n this.render();\n }, FRAME_INTERVAL);\n }\n\n /**\n * Detiene la animaci\\u00f3n y limpia la l\\u00ednea, sin emitir mensaje de estado.\n * Restaura el `outputMode` del logger a `'console'`.\n *\n * \\u00datil cuando el caller ya emiti\\u00f3 su propio output final y solo necesita\n * desmontar el spinner. Para terminaci\\u00f3n con tick/cross usa\n * {@link succeed} / {@link fail}.\n *\n * @returns {void}\n */\n stop(): void {\n this.clearInterval();\n this.clearLine();\n // Restore logger output\n this._logger.updateConfig({ outputMode: 'console' });\n }\n\n /**\n * Detiene la animaci\\u00f3n y emite el mensaje con un check verde (`\\u2713`).\n * Restaura el `outputMode` del logger a `'console'`.\n *\n * @param {string} [msg] - Texto final a mostrar. Si se omite, reutiliza\n * el `message` con el que se construy\\u00f3 el spinner (o el \\u00faltimo seteado\n * v\\u00eda {@link text}).\n * @returns {void}\n *\n * @example\n * ```ts\n * spinner.succeed(); // \\u2192 \" \\u2713 <message inicial>\"\n * spinner.succeed('Hecho'); // \\u2192 \" \\u2713 Hecho\"\n * ```\n */\n succeed(msg?: string): void {\n this.clearInterval();\n this.clearLine();\n const text = msg ?? this.message;\n process.stderr.write(` ${ANSI.fg.green}\\u2713${ANSI.reset} ${text}\\n`);\n this._logger.updateConfig({ outputMode: 'console' });\n }\n\n /**\n * Detiene la animaci\\u00f3n y emite el mensaje con una cruz roja (`\\u2717`).\n * Restaura el `outputMode` del logger a `'console'`.\n *\n * @param {string} [msg] - Texto final a mostrar. Si se omite, reutiliza\n * el `message` con el que se construy\\u00f3 el spinner (o el \\u00faltimo seteado\n * v\\u00eda {@link text}).\n * @returns {void}\n *\n * @example\n * ```ts\n * try {\n * await build();\n * spinner.succeed('Build OK');\n * } catch (e) {\n * spinner.fail(`Build fallido: ${e.message}`);\n * }\n * ```\n */\n fail(msg?: string): void {\n this.clearInterval();\n this.clearLine();\n const text = msg ?? this.message;\n process.stderr.write(` ${ANSI.fg.red}\\u2717${ANSI.reset} ${text}\\n`);\n this._logger.updateConfig({ outputMode: 'console' });\n }\n\n /**\n * Reemplaza el texto mostrado al lado del frame sin reiniciar la animaci\\u00f3n\n * ni perder el frame actual. Pensado para actualizar progreso in-place\n * (p.ej. contador de items procesados).\n *\n * @param {string} msg - Nuevo texto a mostrar.\n * @returns {void}\n */\n text(msg: string): void {\n this.message = msg;\n }\n\n private render(): void {\n const frame = SPINNER_FRAMES[this.frameIndex] ?? SPINNER_FRAMES[0];\n const line = ` ${ANSI.fg.cyan}${frame}${ANSI.reset} ${this.message}`;\n process.stderr.write(`\\r\\x1b[K${line}`);\n }\n\n private clearLine(): void {\n process.stderr.write('\\r\\x1b[K');\n }\n\n private clearInterval(): void {\n if (this.interval) {\n clearInterval(this.interval);\n this.interval = null;\n }\n }\n}\n\n/**\n * Spinner degenerate para non-TTY (CI logs, pipes, `outputMode: 'silent'`).\n *\n * No anima nada: traduce los eventos del ciclo de vida del spinner a llamadas\n * normales del logger (`info` en start, `success`/`error` en finish). Así el\n * consumidor mantiene la misma API {@link ISpinnerHandle} sin saber si está\n * corriendo en terminal interactiva o en un job de CI.\n *\n * A diferencia de {@link SpinnerManager}, **no** toca el `outputMode` del\n * logger — no hay nada que mutear porque no hay frame animado que proteger.\n *\n * @implements {ISpinnerHandle}\n *\n * @example\n * ```ts\n * // En CI (sin TTY) el TerminalBridge entrega un NoopSpinner automáticamente:\n * const s = logger.spinner('Running tests...');\n * s.start(); // logger.info('Running tests...')\n * s.succeed('All green'); // logger.success('All green')\n * ```\n *\n * @see {@link SpinnerManager} para el path interactivo con animación.\n */\nexport class NoopSpinner implements ISpinnerHandle {\n private message: string;\n private _logger: Logger;\n\n /**\n * @param {string} message - Texto base; se reutiliza como mensaje final\n * si {@link succeed} / {@link fail} se llaman sin argumento.\n * @param {Logger} logger - Logger sobre el que se emiten los eventos.\n */\n constructor(message: string, logger: Logger) {\n this.message = message;\n this._logger = logger;\n }\n\n /**\n * Emite el mensaje inicial como `logger.info(...)`. No arranca ningún\n * timer — en non-TTY no hay nada que animar.\n *\n * @returns {void}\n */\n start(): void {\n this._logger.info(this.message);\n }\n\n /**\n * No-op — no hay animación que detener ni output que restaurar.\n *\n * @returns {void}\n */\n stop(): void {\n // No-op\n }\n\n /**\n * Emite el mensaje final como `logger.success(...)`.\n *\n * @param {string} [msg] - Texto final; si se omite usa el `message`\n * inicial o el último seteado vía {@link text}.\n * @returns {void}\n */\n succeed(msg?: string): void {\n this._logger.success(msg ?? this.message);\n }\n\n /**\n * Emite el mensaje final como `logger.error(...)`.\n *\n * @param {string} [msg] - Texto final; si se omite usa el `message`\n * inicial o el último seteado vía {@link text}.\n * @returns {void}\n */\n fail(msg?: string): void {\n this._logger.error(msg ?? this.message);\n }\n\n /**\n * Actualiza el mensaje interno (sin output). Solo afecta al texto que\n * emitirán {@link succeed} / {@link fail} cuando se invoquen sin argumento.\n *\n * @param {string} msg - Nuevo texto base.\n * @returns {void}\n */\n text(msg: string): void {\n this.message = msg;\n }\n}\n"],"mappings":";;AAaA,MAAM,iBAAiG;CACnG,OAAS;EAAE,IAAI;EAAM,IAAI;EAAM,QAAQ;GAAE,IAAI;GAAM,IAAI;EAAM;CAAE;CAC/D,KAAS;EAAE,IAAI;EAAM,IAAI;EAAM,QAAQ;GAAE,IAAI;GAAM,IAAI;EAAM;CAAE;CAC/D,OAAS;EAAE,IAAI;EAAM,IAAI;EAAM,QAAQ;GAAE,IAAI;GAAM,IAAI;EAAM;CAAE;CAC/D,QAAS;EAAE,IAAI;EAAM,IAAI;EAAM,QAAQ;GAAE,IAAI;GAAM,IAAI;EAAM;CAAE;CAC/D,MAAS;EAAE,IAAI;EAAM,IAAI;EAAM,QAAQ;GAAE,IAAI;GAAM,IAAI;EAAM;CAAE;CAC/D,SAAS;EAAE,IAAI;EAAM,IAAI;EAAM,QAAQ;GAAE,IAAI;GAAM,IAAI;EAAM;CAAE;CAC/D,MAAS;EAAE,IAAI;EAAM,IAAI;EAAM,QAAQ;GAAE,IAAI;GAAM,IAAI;EAAM;CAAE;CAC/D,OAAS;EAAE,IAAI;EAAM,IAAI;EAAM,QAAQ;GAAE,IAAI;GAAM,IAAI;EAAM;CAAE;CAC/D,MAAS;EAAE,IAAI;EAAM,IAAI;EAAO,QAAQ;GAAE,IAAI;GAAM,IAAI;EAAK;CAAE;CAC/D,MAAS;EAAE,IAAI;EAAM,IAAI;EAAO,QAAQ;GAAE,IAAI;GAAM,IAAI;EAAK;CAAE;AACnE;AAEA,MAAM,mBAA2C;CAC7C,WAAW;CAAW,cAAc;CAAW,MAAM;CACrD,YAAY;CAAW,OAAO;CAAW,OAAO;CAChD,QAAQ;CAAW,OAAO;CAAW,gBAAgB;CACrD,MAAM;CAAW,YAAY;CAAW,OAAO;CAC/C,WAAW;CAAW,WAAW;CAAW,YAAY;CACxD,WAAW;CAAW,OAAO;CAAW,gBAAgB;CACxD,UAAU;CAAW,SAAS;CAAW,MAAM;CAC/C,UAAU;CAAW,UAAU;CAAW,eAAe;CACzD,UAAU;CAAW,WAAW;CAAW,WAAW;CACtD,aAAa;CAAW,gBAAgB;CAAW,YAAY;CAC/D,YAAY;CAAW,SAAS;CAAW,YAAY;CACvD,cAAc;CAAW,eAAe;CAAW,eAAe;CAClE,eAAe;CAAW,YAAY;CAAW,UAAU;CAC3D,aAAa;CAAW,SAAS;CAAW,YAAY;CACxD,WAAW;CAAW,aAAa;CAAW,aAAa;CAC3D,SAAS;CAAW,WAAW;CAAW,YAAY;CACtD,MAAM;CAAW,WAAW;CAAW,MAAM;CAC7C,OAAO;CAAW,aAAa;CAAW,UAAU;CACpD,SAAS;CAAW,WAAW;CAAW,QAAQ;CAClD,OAAO;CAAW,OAAO;CAAW,UAAU;CAC9C,eAAe;CAAW,WAAW;CAAW,cAAc;CAC9D,WAAW;CAAW,YAAY;CAAW,WAAW;CACxD,sBAAsB;CAAW,WAAW;CAAW,YAAY;CACnE,WAAW;CAAW,aAAa;CAAW,eAAe;CAC7D,cAAc;CAAW,gBAAgB;CAAW,gBAAgB;CACpE,aAAa;CAAW,MAAM;CAAW,WAAW;CACpD,OAAO;CAAW,SAAS;CAAW,QAAQ;CAC9C,kBAAkB;CAAW,YAAY;CAAW,cAAc;CAClE,cAAc;CAAW,gBAAgB;CAAW,iBAAiB;CACrE,mBAAmB;CAAW,iBAAiB;CAAW,iBAAiB;CAC3E,cAAc;CAAW,WAAW;CAAW,WAAW;CAC1D,UAAU;CAAW,aAAa;CAAW,MAAM;CACnD,SAAS;CAAW,OAAO;CAAW,WAAW;CACjD,QAAQ;CAAW,WAAW;CAAW,QAAQ;CACjD,eAAe;CAAW,WAAW;CAAW,eAAe;CAC/D,eAAe;CAAW,YAAY;CAAW,WAAW;CAC5D,MAAM;CAAW,MAAM;CAAW,MAAM;CACxC,YAAY;CAAW,QAAQ;CAAW,eAAe;CACzD,KAAK;CAAW,WAAW;CAAW,WAAW;CACjD,aAAa;CAAW,QAAQ;CAAW,YAAY;CACvD,UAAU;CAAW,UAAU;CAAW,QAAQ;CAClD,QAAQ;CAAW,SAAS;CAAW,WAAW;CAClD,WAAW;CAAW,MAAM;CAAW,aAAa;CACpD,WAAW;CAAW,KAAK;CAAW,MAAM;CAC5C,SAAS;CAAW,QAAQ;CAAW,WAAW;CAClD,QAAQ;CAAW,OAAO;CAAW,OAAO;CAC5C,YAAY;CAAW,QAAQ;CAAW,aAAa;AAC3D;AAEA,SAAgB,SAAS,KAAkB;CACvC,MAAM,SAAS,4CAA4C,KAAK,GAAG;CACnE,IAAI,CAAC,UAAU,CAAC,OAAO,MAAM,CAAC,OAAO,MAAM,CAAC,OAAO,IAC/C,OAAO;EAAE,GAAG;EAAK,GAAG;EAAK,GAAG;CAAI;CAEpC,OAAO;EACH,GAAG,SAAS,OAAO,IAAI,EAAE;EACzB,GAAG,SAAS,OAAO,IAAI,EAAE;EACzB,GAAG,SAAS,OAAO,IAAI,EAAE;CAC7B;AACJ;AAEA,SAAgB,SAAS,GAAW,GAAW,GAAmB;CAC9D,OAAO,MAAM;EAAC;EAAG;EAAG;CAAC,CAAC,CAAC,KAAI,MAAK,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE;AAC5E;AAkBA,SAAgB,WAAW,OAAuB;CAC9C,IAAI,MAAM,WAAW,GAAG,GACpB,OAAO;CAGX,MAAM,QAAQ,iBAAiB,MAAM,YAAY;CACjD,IAAI,OACA,OAAO;CAGX,MAAM,WAAW,MAAM,MAAM,gCAAgC;CAC7D,IAAI,YAAY,SAAS,MAAM,SAAS,MAAM,SAAS,IACnD,OAAO,SACH,SAAS,SAAS,EAAE,GACpB,SAAS,SAAS,EAAE,GACpB,SAAS,SAAS,EAAE,CACxB;CAGJ,OAAO;AACX;AAEA,SAAgB,kBAAkB,OAAe,YAAqC;CAClF,IAAI,eAAe,QAAQ,OAAO;CAElC,MAAM,aAAa,MAAM,YAAY;CAErC,IAAI,eAAe,WAAW,eAAe,aACzC,OAAO,QAAQ,eAAe,WAAW,CAAC,GAAG;CAGjD,IAAI,eAAe,SAAS;EAExB,MAAM,eAAe,sBADT,WAAW,KACsB,CAAC;EAC9C,MAAM,aAAa,eAAe;EAClC,OAAO,aAAa,QAAQ,WAAW,GAAG,KAAK;CACnD;CAGA,MAAM,EAAE,GAAG,GAAG,MAAM,SADR,WAAW,KACQ,CAAC;CAChC,OAAO,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE;AACpC;AAEA,SAAgB,kBAAkB,OAAe,YAAqC;CAClF,IAAI,eAAe,QAAQ,OAAO;CAElC,MAAM,aAAa,MAAM,YAAY;CAErC,IAAI,eAAe,WAAW,eAAe,aACzC,OAAO,QAAQ,eAAe,WAAW,CAAC,GAAG;CAGjD,IAAI,eAAe,SAAS;EAExB,MAAM,eAAe,sBADT,WAAW,KACsB,CAAC;EAC9C,MAAM,aAAa,eAAe;EAClC,OAAO,aAAa,QAAQ,WAAW,GAAG,KAAK;CACnD;CAGA,MAAM,EAAE,GAAG,GAAG,MAAM,SADR,WAAW,KACQ,CAAC;CAChC,OAAO,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE;AACpC;AAUA,SAAS,sBAAsB,KAAqB;CAChD,MAAM,EAAE,GAAG,GAAG,MAAM,SAAS,GAAG;CAChC,MAAM,cAAmC;EACrC,OAAS;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAE;EAC5B,KAAS;GAAE,GAAG;GAAK,GAAG;GAAG,GAAG;EAAE;EAC9B,OAAS;GAAE,GAAG;GAAG,GAAG;GAAK,GAAG;EAAE;EAC9B,QAAS;GAAE,GAAG;GAAK,GAAG;GAAK,GAAG;EAAE;EAChC,MAAS;GAAE,GAAG;GAAG,GAAG;GAAG,GAAG;EAAI;EAC9B,SAAS;GAAE,GAAG;GAAK,GAAG;GAAG,GAAG;EAAI;EAChC,MAAS;GAAE,GAAG;GAAG,GAAG;GAAK,GAAG;EAAI;EAChC,OAAS;GAAE,GAAG;GAAK,GAAG;GAAK,GAAG;EAAI;CACtC;CAEA,IAAI,UAAU;CACd,IAAI,cAAc;CAElB,KAAK,MAAM,CAAC,MAAM,QAAQ,OAAO,QAAQ,WAAW,GAAG;EACnD,MAAM,WAAW,KAAK,KAClB,KAAK,IAAI,IAAI,IAAI,GAAG,CAAC,IACrB,KAAK,IAAI,IAAI,IAAI,GAAG,CAAC,IACrB,KAAK,IAAI,IAAI,IAAI,GAAG,CAAC,CACzB;EACA,IAAI,WAAW,aAAa;GACxB,cAAc;GACd,UAAU;EACd;CACJ;CAEA,OAAO;AACX;AAoDA,MAAa,OAAO;CAChB,OAAO;CACP,MAAM;CACN,KAAK;CACL,QAAQ;CACR,WAAW;CACX,OAAO;CACP,SAAS;CACT,QAAQ;CACR,eAAe;CAEf,IAAI;EACA,OAAO;EACP,KAAK;EACL,OAAO;EACP,QAAQ;EACR,MAAM;EACN,SAAS;EACT,MAAM;EACN,OAAO;EACP,MAAM;EACN,WAAW;EACX,aAAa;EACb,cAAc;EACd,YAAY;EACZ,eAAe;EACf,YAAY;EACZ,aAAa;CACjB;CAEA,IAAI;EACA,OAAO;EACP,KAAK;EACL,OAAO;EACP,QAAQ;EACR,MAAM;EACN,SAAS;EACT,MAAM;EACN,OAAO;EACP,MAAM;EACN,WAAW;EACX,aAAa;EACb,cAAc;EACd,YAAY;EACZ,eAAe;EACf,YAAY;EACZ,aAAa;CACjB;CAEA,MAAM,GAAW,GAAW,MAAc,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE;CACnE,QAAQ,GAAW,GAAW,MAAc,aAAa,EAAE,GAAG,EAAE,GAAG,EAAE;CACrE,WAAW,MAAc,aAAa,EAAE;CACxC,aAAa,MAAc,aAAa,EAAE;AAC9C;;;AClTA,SAAgB,UAAU,KAAqB;CAC3C,OAAO,IAAI,QAAQ,mBAAmB,EAAE;AAC5C;AAEA,SAAgB,iBAAiB,KAAqB;CAClD,OAAO,UAAU,GAAG,CAAC,CAAC;AAC1B;AAEA,SAAgB,WAAW,KAAa,OAAe,QAAqB,QAAgB;CACxF,MAAM,aAAa,iBAAiB,GAAG;CACvC,IAAI,cAAc,OAAO,OAAO;CAEhC,MAAM,UAAU,QAAQ;CAExB,QAAQ,OAAR;EACI,KAAK,SACD,OAAO,IAAI,OAAO,OAAO,IAAI;EACjC,KAAK;GACD,MAAM,UAAU,KAAK,MAAM,UAAU,CAAC;GACtC,MAAM,WAAW,UAAU;GAC3B,OAAO,IAAI,OAAO,OAAO,IAAI,MAAM,IAAI,OAAO,QAAQ;EAE1D,SACI,OAAO,MAAM,IAAI,OAAO,OAAO;CACvC;AACJ;AAoGA,SAAgB,YACZ,OACA,QAAoB,YACpB,kBAAmC,QACnC,OACM;CACN,MAAM,QAAQ,oBAAoB,SAAS,KAAK,QAAQ;CAExD,MAAM,OAAO,MAAM,YAAY;CAE/B,QAAQ,OAAR;EACI,KAAK;GACD,MAAM,aAAa,SAAS,oBAAoB,SAAS,kBAAkB,OAAO,eAAe,IAAI;GAErG,OAAO,GADU,oBAAoB,SAAS,KAAK,GAAG,QAAQ,KACzC,WAAW,GAAG,KAAK,GAAG;EAC/C,KAAK,SAED,OAAO,GADY,SAAS,oBAAoB,SAAS,kBAAkB,OAAO,eAAe,IAAI,KAC9E,OAAO;EAClC,KAAK;GACD,MAAM,aAAa,SAAS,oBAAoB,SAAS,kBAAkB,OAAO,eAAe,IAAI;GAErG,OAAO,GADU,oBAAoB,SAAS,KAAK,GAAG,QAAQ,KACzC,WAAW,GAAG,KAAK,GAAG;EAC/C,KAAK,QAID,OAAO,GAFS,SAAS,oBAAoB,SAAS,kBAAkB,OAAO,eAAe,IAAI,KAClF,oBAAoB,SAAS,kBAAkB,WAAW,eAAe,IAAI,GACjE,GAAG,KAAK,GAAG;EAE3C;GACI,MAAM,aAAa,SAAS,oBAAoB,SAAS,kBAAkB,OAAO,eAAe,IAAI;GAErG,OAAO,GADU,oBAAoB,SAAS,KAAK,GAAG,QAAQ,KACzC,WAAW,GAAG,KAAK,GAAG;CACnD;AACJ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrIA,SAAgB,WAAW,SAAiB,OAAe,KAAa,UAAmC;CACvG,MAAM,QAAQ,IAAI,QAAQ,GAAG,MAAM;CAInC,OAAO,KAHS,aAAa,SACvB,kBAAkB,WAAW,QAAQ,IAAI,KAAK,OAAO,QAAQ,KAAK,QAClE,MACc,GAAG;AAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACVA,SAAgB,aAAa,OAAe,UAA2B;CAGnE,OAAO,KAFG,KAAK,OAAO,QAAQ,KAAK,QACzB,WAAW,KAAK,MAAM,IAAI,aAAa,KAAK,QAAQ;AAElE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACFA,SAAgB,cAAc,OAAwB;CAClD,MAAM,IAAI,SAAS,KAAK,IAAI,iBAAiB,IAAI,GAAG,EAAE;CACtD,OAAO,KAAK,MAAM,OAAO,IAAS,OAAO,CAAC,IAAI,KAAK;AACvD;;;;;;;;;;;;;;;ACZA,MAAM,eAAe;CACjB,QAAS;EAAE,IAAI;EAAU,IAAI;EAAU,IAAI;EAAU,IAAI;EAAU,GAAG;EAAU,GAAG;CAAS;CAC5F,SAAS;EAAE,IAAI;EAAU,IAAI;EAAU,IAAI;EAAU,IAAI;EAAU,GAAG;EAAU,GAAG;CAAS;CAC5F,QAAS;EAAE,IAAI;EAAU,IAAI;EAAU,IAAI;EAAU,IAAI;EAAU,GAAG;EAAU,GAAG;CAAS;CAC5F,MAAS;EAAE,IAAI;EAAU,IAAI;EAAU,IAAI;EAAU,IAAI;EAAU,GAAG;EAAU,GAAG;CAAS;AAChG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,SAAgB,UAAU,SAAiB,UAAuB,CAAC,GAAG,WAA4B,QAAgB;CAC9G,MAAM,EACF,OACA,aACA,cAAc,WACd,UAAU,MACV;CAEJ,MAAM,QAAQ,aAAa,gBAAgB,aAAa;CACxD,MAAM,QAAQ,QAAQ,MAAM,IAAI;CAChC,MAAM,eAAe,KAAK,IAAI,iBAAiB,IAAI,GAAG,EAAE;CAGxD,MAAM,gBAAgB,MAAM,KAAI,MAAK,iBAAiB,CAAC,CAAC;CACxD,MAAM,aAAa,QAAQ,UAAU,KAAK,CAAC,CAAC,SAAS,IAAI;CACzD,MAAM,kBAAkB,KAAK,IAAI,GAAG,eAAe,UAAU;CAC7D,MAAM,aAAa,KAAK,IAAI,kBAAkB,GAAG,YAAY;CAG7D,MAAM,KAAK,eAAe,aAAa,SACjC,kBAAkB,aAAa,QAAQ,IACvC;CACN,MAAM,QAAQ,KAAK,KAAK,QAAQ;CAEhC,MAAM,QAAQ,SAAiB,GAAG,KAAK,OAAO;CAG9C,IAAI;CACJ,IAAI,OAAO;EACP,MAAM,WAAW,IAAI,MAAM;EAC3B,MAAM,aAAa,aAAa,UAAU,QAAQ,CAAC,CAAC;EACpD,YAAY,KAAK,KAAK,MAAM,EAAE,IAAI,KAAK,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,MAAM,EAAE,OAAO,KAAK,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE;CACxI,OACI,YAAY,KAAK,KAAK,MAAM,EAAE,IAAI,KAAK,MAAM,EAAE,OAAO,UAAU,CAAC,IAAI,KAAK,MAAM,EAAE;CAItF,MAAM,eAAe,KAAK,KAAK,MAAM,EAAE,IAAI,KAAK,MAAM,EAAE,OAAO,UAAU,CAAC,IAAI,KAAK,MAAM,EAAE;CAG3F,MAAM,YAAY,KAAK,KAAK,MAAM,CAAC,IAAI,IAAI,OAAO,UAAU,IAAI,KAAK,MAAM,CAAC;CAC5E,MAAM,eAAe,UAAU,IAAI,MAAM,OAAO,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC;CAGrE,MAAM,eAAe,MAAM,KAAI,SAAQ;EACnC,MAAM,UAAU,iBAAiB,IAAI;EACrC,MAAM,MAAM,aAAa,UAAU;EACnC,OAAO,KAAK,KAAK,MAAM,CAAC,EAAE,GAAG,OAAO,IAAI,OAAO,KAAK,IAAI,GAAG,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC;CACnF,CAAC;CAED,OAAO;EACH;EACA,GAAG;EACH,GAAG;EACH,GAAG;EACH;CACJ,CAAC,CAAC,KAAK,IAAI;AACf;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxEA,SAAgB,YACZ,MACA,UAAyB,CAAC,GAC1B,WAA4B,QACtB;CACN,IAAI,KAAK,WAAW,GAAG,OAAO;CAG9B,MAAM,UAAU,QAAQ,WAAW,OAAO,KAAK,KAAK,EAAG;CACvD,MAAM,UAAU,QAAQ,QAAQ;CAGhC,MAAM,YAAY,QAAQ,KAAK,KAAK,MAAM;EACtC,MAAM,YAAY,iBAAiB,QAAQ,MAAM,GAAG;EACpD,MAAM,cAAc,KAAK,QAAQ,KAAK,QAAQ;GAC1C,MAAM,MAAM,OAAO,IAAI,QAAQ,EAAE;GACjC,OAAO,KAAK,IAAI,KAAK,iBAAiB,GAAG,CAAC;EAC9C,GAAG,CAAC;EACJ,OAAO,KAAK,IAAI,WAAW,WAAW,IAAI;CAC9C,CAAC;CAGD,MAAM,OAAO,aAAa,SAAS,kBAAkB,WAAW,QAAQ,IAAI;CAC5E,MAAM,MAAM,aAAa,SAAS,KAAK,MAAM;CAC7C,MAAM,QAAQ,aAAa,SAAS,KAAK,QAAQ;CAmBjD,OAAO;EAhBW,OAAO,QAAQ,KAAK,KAAK,MAAM;GAC7C,MAAM,QAAQ,QAAQ,MAAM;GAC5B,OAAO,OAAO,KAAK,OAAO,WAAW,IAAI,SAAS,UAAU,EAAG,IAAI;EACvE,CAAC,CAAC,CAAC,KAAK,EAAE;EAGQ,OAAO,MAAM,UAAU,KAAI,MAAK,IAAS,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,GAAQ,IAAI;EAUzD,GAPb,KAAK,KAAI,QAAO;GAC7B,OAAO,OAAO,QAAQ,KAAK,KAAK,MAAM;IAElC,OAAO,WAAW,IADN,OAAO,IAAI,QAAQ,EACP,KAAK,UAAU,EAAG;GAC9C,CAAC,CAAC,CAAC,KAAK,EAAE;EACd,CAEwC;CAAC,CAAC,CAAC,KAAK,IAAI;AACxD;;;;;;;;;AC3EA,MAAM,iBAAiB;CAAC;CAAU;CAAU;CAAU;CAAU;CAAU;CAAU;CAAU;CAAU;CAAU;AAAQ;;;;;;AAO1H,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BvB,IAAa,iBAAb,MAAsD;CAClD;CACA,aAAqB;CACrB,WAA0D;CAC1D;;;;;;;;;CAUA,YAAY,SAAiB,SAAuB,QAAgB;EAChE,KAAK,UAAU;EACf,KAAK,UAAU;CACnB;;;;;;;;;;;CAYA,QAAc;EACV,IAAI,KAAK,UAAU;EAGnB,KAAK,QAAQ,aAAa,EAAE,YAAY,SAAS,CAAC;EAElD,KAAK,aAAa;EAClB,KAAK,OAAO;EACZ,KAAK,WAAW,kBAAkB;GAC9B,KAAK,cAAc,KAAK,aAAa,KAAK,eAAe;GACzD,KAAK,OAAO;EAChB,GAAG,cAAc;CACrB;;;;;;;;;;;CAYA,OAAa;EACT,KAAK,cAAc;EACnB,KAAK,UAAU;EAEf,KAAK,QAAQ,aAAa,EAAE,YAAY,UAAU,CAAC;CACvD;;;;;;;;;;;;;;;;CAiBA,QAAQ,KAAoB;EACxB,KAAK,cAAc;EACnB,KAAK,UAAU;EACf,MAAM,OAAO,OAAO,KAAK;EACzB,QAAQ,OAAO,MAAM,KAAK,KAAK,GAAG,MAAM,QAAQ,KAAK,MAAM,GAAG,KAAK,GAAG;EACtE,KAAK,QAAQ,aAAa,EAAE,YAAY,UAAU,CAAC;CACvD;;;;;;;;;;;;;;;;;;;;CAqBA,KAAK,KAAoB;EACrB,KAAK,cAAc;EACnB,KAAK,UAAU;EACf,MAAM,OAAO,OAAO,KAAK;EACzB,QAAQ,OAAO,MAAM,KAAK,KAAK,GAAG,IAAI,QAAQ,KAAK,MAAM,GAAG,KAAK,GAAG;EACpE,KAAK,QAAQ,aAAa,EAAE,YAAY,UAAU,CAAC;CACvD;;;;;;;;;CAUA,KAAK,KAAmB;EACpB,KAAK,UAAU;CACnB;CAEA,SAAuB;EACnB,MAAM,QAAQ,eAAe,KAAK,eAAe,eAAe;EAChE,MAAM,OAAO,KAAK,KAAK,GAAG,OAAO,QAAQ,KAAK,MAAM,GAAG,KAAK;EAC5D,QAAQ,OAAO,MAAM,WAAW,MAAM;CAC1C;CAEA,YAA0B;EACtB,QAAQ,OAAO,MAAM,UAAU;CACnC;CAEA,gBAA8B;EAC1B,IAAI,KAAK,UAAU;GACf,cAAc,KAAK,QAAQ;GAC3B,KAAK,WAAW;EACpB;CACJ;AACJ;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,IAAa,cAAb,MAAmD;CAC/C;CACA;;;;;;CAOA,YAAY,SAAiB,QAAgB;EACzC,KAAK,UAAU;EACf,KAAK,UAAU;CACnB;;;;;;;CAQA,QAAc;EACV,KAAK,QAAQ,KAAK,KAAK,OAAO;CAClC;;;;;;CAOA,OAAa,CAEb;;;;;;;;CASA,QAAQ,KAAoB;EACxB,KAAK,QAAQ,QAAQ,OAAO,KAAK,OAAO;CAC5C;;;;;;;;CASA,KAAK,KAAoB;EACrB,KAAK,QAAQ,MAAM,OAAO,KAAK,OAAO;CAC1C;;;;;;;;CASA,KAAK,KAAmB;EACpB,KAAK,UAAU;CACnB;AACJ"}
|