doctor-beez 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/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # 🐝 DOCTOR BEEZ CLI v1.0
2
+ > **El Enjambre de CuraciΓ³n AutΓ³noma de CΓ³digo**
3
+ > *Powered by BEEZ DIGITAL*
4
+
5
+ ---
6
+
7
+ ## πŸ“Œ ΒΏQuΓ© es Doctor Beez?
8
+
9
+ **DOCTOR BEEZ** es un CLI de auditorΓ­a y curaciΓ³n automΓ‘tica en 5 niveles para aplicaciones React / TypeScript. Despliega un "enjambre" de motores de anΓ‘lisis estΓ‘tico y pruebas para detectar y corregir problemas de cΓ³digo en lotes pequeΓ±os con commits atΓ³micos de Git.
10
+
11
+ ```
12
+ .@@%
13
+ #::::*@*@@@@@@@@%
14
+ @
15
+ . @
16
+ -:::::@==++*#%@# =@ +*@ =
17
+ @ @- :%@. @ =
18
+ @@ @%%%%%%%@* # @ .@. @ %
19
+ @%::@%%%%%%%+-%% -@ @ @ ..
20
+ .%:.= %%@:..%%%%%%%%% %%:+ = = .@# % %#
21
+ @ :+- .%%%...@%%%%%%%% %%%:@ @ @ # :#@@# @
22
+ . * . ::#%%%..-%%%%%%%% %%:::@ - @@# +@#*% % % @
23
+ . *.# @@. # @%%*.:@%%%%%%%%%%:*@:@%%%%%@*+++++*%=+@ -@ .
24
+ .@. %-. @ %%%+..%%%%%%%%%%.%#:@%%%%%%%@@ @++# + @ #
25
+ % @%.. %%:..*%%%%%*- =*::@%%%%%%%%%%@ .@+@*-.@ @
26
+ .#+%-# @:.....:::.@ %::@%%%%%%%%@- #.*++++++%
27
+ @.*+@ :@. -..........::::@%%%%%%%%%%- @@@*+#@@@+
28
+ *#@+++@:@@****:...:%@@@@%%%%%%%%%%%%%%%- #@*+#*#@+*@
29
+ :.**+++++++++++*@@%%%%%%%%%%%%%%%%%%%%%@@.% . %+*=
30
+ . .%. . %++@%%%%%%%%%%%%%%%%%%%%%%@ @%+*#
31
+ @.. -*+*@+@%@%%%%%%%%%%%%%%%%%%%%. .**@
32
+ =@+*@@@ *@@%%%%%%%%%%%%%%%%%%%%%-@ @
33
+ .@+*++++*@. @@@%%%%%%%%%%%%%%%%%@%. .
34
+ @**@+ *++@.. @:@%%%%%%%%%%%%%%@ ..
35
+ @+*@%* . #@%%%@@%@%%%%%% :@
36
+ *+++*#@ @%@@:....:.@%%@###%%#-
37
+ @@ @:..........-#*#@@@#
38
+ @%@@@:......... @@@@.
39
+ .@%%%%%%%%:.......@@@*
40
+ @%%%%%%%%%%%:.....:@@
41
+ :.....@%%%%%%%@:::::@
42
+ =:........*#%%%%@+:::+
43
+ @%@@@*.......%%@@@@:%
44
+ @@%%%%%%%@:...::@@@@@
45
+ @@%%%%%%%@:::::@@@
46
+ @. .@@@@@@@@-:::@
47
+ .@ ..@@ @@@@@@@@@@
48
+ +#@%
49
+
50
+
51
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
52
+ β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ•β•β–ˆβ–ˆβ–ˆβ•”β•
53
+ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•”β•
54
+ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ–ˆβ•”β•
55
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
56
+ β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•
57
+
58
+ ========================================================================================
59
+ [ 🐝 KILLA SWARM CODE HEALING PROTOCOL · DOCTOR BEEZ v1.0 · POWERED BY BEEZ DIGITAL 🐝 ]
60
+ ========================================================================================
61
+ ```
62
+
63
+ ---
64
+
65
+ ## πŸ“Š Los 5 Niveles de AuditorΓ­a
66
+
67
+ 1. **TypeScript (`tsc --noEmit`):** VerificaciΓ³n estricta de compilaciΓ³n y tipado.
68
+ 2. **Suite de Pruebas (`vitest` / `jest` / `react-scripts`):** EjecuciΓ³n no interactiva con `CI=true`.
69
+ 3. **Knip (`knip`):** DetecciΓ³n de cΓ³digo muerto, archivos huΓ©rfanos y dependencias no utilizadas.
70
+ 4. **Semgrep (`semgrep`):** Escaneo de reglas de seguridad y buenas prΓ‘cticas.
71
+ 5. **DPDM (`dpdm`):** Mapeo y prevenciΓ³n de grafos de dependencias circulares.
72
+
73
+ ---
74
+
75
+ ## πŸš€ InstalaciΓ³n y Uso
76
+
77
+ ### 1. En este repositorio:
78
+ ```bash
79
+ npm install
80
+ npm run doctor-beez
81
+ ```
82
+
83
+ ### 2. Uso Global en tu sistema:
84
+ ```bash
85
+ npm link
86
+ # Ahora puedes ejecutar en cualquier carpeta:
87
+ doctor-beez
88
+ ```
89
+
90
+ ---
91
+
92
+ ## πŸ“„ Licencia
93
+
94
+ MIT Β© **BEEZ DIGITAL**
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from 'child_process';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ const rootDir = path.resolve(__dirname, '..');
9
+
10
+ const tsxBin = path.join(rootDir, 'node_modules', '.bin', 'tsx');
11
+ const indexPath = path.join(rootDir, 'src', 'index.ts');
12
+
13
+ const child = spawn(tsxBin, [indexPath], {
14
+ cwd: rootDir,
15
+ stdio: 'inherit',
16
+ env: process.env,
17
+ });
18
+
19
+ child.on('exit', (code) => {
20
+ process.exit(code || 0);
21
+ });
@@ -0,0 +1,32 @@
1
+ import { execa } from 'execa';
2
+ import * as p from '@clack/prompts';
3
+ export async function checkGitHubAuth() {
4
+ const spinner = p.spinner();
5
+ spinner.start('πŸ”‘ Verificando credenciales de GitHub (gh CLI)...');
6
+ try {
7
+ const { stdout } = await execa('gh', ['auth', 'status']);
8
+ spinner.stop('🟒 Autenticación de GitHub verificada.');
9
+ return true;
10
+ }
11
+ catch (error) {
12
+ spinner.stop('πŸ”΄ No estΓ‘s autenticado en GitHub CLI (gh).');
13
+ const shouldLogin = await p.confirm({
14
+ message: 'ΒΏDeseas iniciar sesiΓ³n en GitHub ahora usando `gh auth login`?',
15
+ initialValue: true,
16
+ });
17
+ if (p.isCancel(shouldLogin) || !shouldLogin) {
18
+ p.log.warn('Continuando sin autenticaciΓ³n de GitHub...');
19
+ return false;
20
+ }
21
+ p.log.info('Iniciando proceso de login de GitHub...');
22
+ try {
23
+ await execa('gh', ['auth', 'login'], { stdio: 'inherit' });
24
+ p.log.success('Β‘AutenticaciΓ³n completada con Γ©xito!');
25
+ return true;
26
+ }
27
+ catch (err) {
28
+ p.log.error('No se pudo completar la autenticaciΓ³n en GitHub.');
29
+ return false;
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,26 @@
1
+ import * as p from '@clack/prompts';
2
+ import chalk from 'chalk';
3
+ import { runDiagnosticScan } from '../scanner/doctor.js';
4
+ export async function startSwarmHealingLoop() {
5
+ p.log.info(chalk.bold.yellow('🐝 ENJAMBRE DESPLEGADO: Iniciando bucle de curación autónoma...'));
6
+ p.note(`1. Copia las reglas de curaciΓ³n en tu agente (OpenCode / Aider / Antigravity).
7
+ 2. El agente procesarΓ‘ lotes de 3 a 5 errores como mΓ‘ximo.
8
+ 3. Se verificarΓ‘ compilaciΓ³n tsc y tests tras cada iteraciΓ³n.
9
+ 4. Cada lote limpio generarΓ‘ un commit atΓ³mico en Git.`, 'πŸ“‹ Instrucciones para el Agente Curador');
10
+ const confirmStart = await p.confirm({
11
+ message: 'ΒΏIniciar primera iteraciΓ³n del enjambre de curaciΓ³n ahora?',
12
+ initialValue: true,
13
+ });
14
+ if (p.isCancel(confirmStart) || !confirmStart) {
15
+ p.log.warn('Bucle de curaciΓ³n en pausa. Puedes ejecutarlo cuando quieras.');
16
+ return;
17
+ }
18
+ p.log.success('🐝 ‘Enjambre trabajando! Re-auditando después del primer lote...');
19
+ const newResults = await runDiagnosticScan();
20
+ if (!newResults.hasErrors) {
21
+ p.outro(chalk.bold.green('πŸŽ‰ Β‘EL PANAL ESTÁ 100% LIMPIO Y SANO! 🐝✨'));
22
+ }
23
+ else {
24
+ p.log.info('AΓΊn quedan observaciones por pulir. ContinΓΊa con el siguiente lote.');
25
+ }
26
+ }
package/dist/index.js ADDED
@@ -0,0 +1,48 @@
1
+ import * as p from '@clack/prompts';
2
+ import chalk from 'chalk';
3
+ import { renderBanner } from './ui/banner.js';
4
+ import { checkGitHubAuth } from './auth/github.js';
5
+ import { runDiagnosticScan } from './scanner/doctor.js';
6
+ import { renderDashboard } from './ui/dashboard.js';
7
+ import { startSwarmHealingLoop } from './healer/swarm.js';
8
+ async function main() {
9
+ // 1. Mostrar Banner Killa Beez
10
+ renderBanner();
11
+ p.intro(chalk.bold.yellow('🐝 DOCTOR BEEZ CLI β€” SISTEMA AUTΓ“NOMO DE AUDITORÍA Y CURACIΓ“N'));
12
+ // 2. Verificar AutenticaciΓ³n GitHub
13
+ await checkGitHubAuth();
14
+ // 3. Escaneo Silencioso
15
+ const results = await runDiagnosticScan();
16
+ // 4. Renderizar "La Media Cagadita"
17
+ renderDashboard(results);
18
+ // 5. Pregunta Interactiva al Usuario
19
+ if (!results.hasErrors) {
20
+ p.outro(chalk.bold.green('✨ ‘Tu proyecto estÑ impecable! No hay errores críticos detectados.'));
21
+ return;
22
+ }
23
+ const action = await p.select({
24
+ message: 'ΒΏQuΓ© deseas hacer con las observaciones encontradas?',
25
+ options: [
26
+ {
27
+ value: 'heal',
28
+ label: 'πŸš€ Β‘DALE COLOR! (Desplegar Enjambre de CuraciΓ³n)',
29
+ hint: 'Inicia el bucle de reparaciΓ³n autΓ³nomo',
30
+ },
31
+ {
32
+ value: 'exit',
33
+ label: '❌ No hermano, me dio miedo (Cancelar por ahora)',
34
+ hint: 'Mantiene los reportes sin hacer cambios',
35
+ },
36
+ ],
37
+ });
38
+ if (p.isCancel(action) || action === 'exit') {
39
+ p.outro(chalk.yellow('🐝 Operación cancelada. El enjambre se mantiene en espera.'));
40
+ process.exit(0);
41
+ }
42
+ // 6. Desplegar Enjambre
43
+ await startSwarmHealingLoop();
44
+ }
45
+ main().catch((err) => {
46
+ console.error(chalk.red('Error inesperado en DOCTOR BEEZ:'), err);
47
+ process.exit(1);
48
+ });
@@ -0,0 +1,80 @@
1
+ import { execa } from 'execa';
2
+ import * as p from '@clack/prompts';
3
+ import fs from 'fs';
4
+ export async function runDiagnosticScan() {
5
+ const spinner = p.spinner();
6
+ spinner.start('🐝 Desplegando abejas exploradoras para la auditoría de código...');
7
+ try {
8
+ // Run doctor.sh
9
+ await execa('bash', ['doctor.sh']);
10
+ spinner.stop('🐝 Auditoría inicial completada. Analizando reportes...');
11
+ }
12
+ catch (error) {
13
+ spinner.stop('🐝 Auditoría finalizada con observaciones.');
14
+ }
15
+ // Parse report-1-types.log
16
+ let typeErrorsCount = 0;
17
+ if (fs.existsSync('report-1-types.log')) {
18
+ const content = fs.readFileSync('report-1-types.log', 'utf-8');
19
+ const matches = content.match(/error TS\d+/g);
20
+ if (matches) {
21
+ typeErrorsCount = matches.length;
22
+ }
23
+ }
24
+ // Parse report-2-tests.log
25
+ let testFailuresCount = 0;
26
+ if (fs.existsSync('report-2-tests.log')) {
27
+ const content = fs.readFileSync('report-2-tests.log', 'utf-8');
28
+ if (content.includes('FAIL') || content.includes('FAILED')) {
29
+ const matches = content.match(/FAIL/g);
30
+ testFailuresCount = matches ? matches.length : 1;
31
+ }
32
+ }
33
+ // Parse report-3-knip.json
34
+ let knipIssuesCount = 0;
35
+ if (fs.existsSync('report-3-knip.json')) {
36
+ try {
37
+ const raw = fs.readFileSync('report-3-knip.json', 'utf-8');
38
+ const data = JSON.parse(raw);
39
+ if (data && typeof data === 'object') {
40
+ const unused = data.unused || {};
41
+ knipIssuesCount = Object.keys(unused).reduce((acc, key) => acc + (Array.isArray(unused[key]) ? unused[key].length : 1), 0);
42
+ }
43
+ }
44
+ catch (e) {
45
+ knipIssuesCount = 0;
46
+ }
47
+ }
48
+ // Parse report-4-semgrep.json
49
+ let semgrepIssuesCount = 0;
50
+ if (fs.existsSync('report-4-semgrep.json')) {
51
+ try {
52
+ const raw = fs.readFileSync('report-4-semgrep.json', 'utf-8');
53
+ const data = JSON.parse(raw);
54
+ if (data && data.results && Array.isArray(data.results)) {
55
+ semgrepIssuesCount = data.results.length;
56
+ }
57
+ }
58
+ catch (e) {
59
+ semgrepIssuesCount = 0;
60
+ }
61
+ }
62
+ // Parse report-5-dpdm.log
63
+ let circularDepsCount = 0;
64
+ if (fs.existsSync('report-5-dpdm.log')) {
65
+ const content = fs.readFileSync('report-5-dpdm.log', 'utf-8');
66
+ const matches = content.match(/Circular/gi);
67
+ if (matches) {
68
+ circularDepsCount = matches.length;
69
+ }
70
+ }
71
+ const hasErrors = typeErrorsCount > 0 || testFailuresCount > 0 || knipIssuesCount > 0 || semgrepIssuesCount > 0 || circularDepsCount > 0;
72
+ return {
73
+ typeErrorsCount,
74
+ testFailuresCount,
75
+ knipIssuesCount,
76
+ semgrepIssuesCount,
77
+ circularDepsCount,
78
+ hasErrors,
79
+ };
80
+ }
@@ -0,0 +1,58 @@
1
+ import chalk from 'chalk';
2
+ import gradient from 'gradient-string';
3
+ const killaGradient = gradient(['#FFE600', '#FFB300', '#FF8C00']);
4
+ export const ASCII_BEE = `
5
+ .@@%
6
+ #::::*@*@@@@@@@@%
7
+ @
8
+ . @
9
+ -:::::@==++*#%@# =@ +*@ =
10
+ @ @- :%@. @ =
11
+ @@ @%%%%%%%@* # @ .@. @ %
12
+ @%::@%%%%%%%+-%% -@ @ @ ..
13
+ .%:.= %%@:..%%%%%%%%% %%:+ = = .@# % %#
14
+ @ :+- .%%%...@%%%%%%%% %%%:@ @ @ # :#@@# @
15
+ . * . ::#%%%..-%%%%%%%% %%:::@ - @@# +@#*% % % @
16
+ . *.# @@. # @%%*.:@%%%%%%%%%%:*@:@%%%%%@*+++++*%=+@ -@ .
17
+ .@. %-. @ %%%+..%%%%%%%%%%.%#:@%%%%%%%@@ @++# + @ #
18
+ % @%.. %%:..*%%%%%*- =*::@%%%%%%%%%%@ .@+@*-.@ @
19
+ .#+%-# @:.....:::.@ %::@%%%%%%%%@- #.*++++++%
20
+ @.*+@ :@. -..........::::@%%%%%%%%%%- @@@*+#@@@+
21
+ *#@+++@:@@****:...:%@@@@%%%%%%%%%%%%%%%- #@*+#*#@+*@
22
+ :.**+++++++++++*@@%%%%%%%%%%%%%%%%%%%%%@@.% . %+*=
23
+ . .%. . %++@%%%%%%%%%%%%%%%%%%%%%%@ @%+*#
24
+ @.. -*+*@+@%@%%%%%%%%%%%%%%%%%%%%. .**@
25
+ =@+*@@@ *@@%%%%%%%%%%%%%%%%%%%%%-@ @
26
+ .@+*++++*@. @@@%%%%%%%%%%%%%%%%%@%. .
27
+ @**@+ *++@.. @:@%%%%%%%%%%%%%%@ ..
28
+ @+*@%* . #@%%%@@%@%%%%%% :@
29
+ *+++*#@ @%@@:....:.@%%@###%%#-
30
+ @@ @:..........-#*#@@@#
31
+ @%@@@:......... @@@@.
32
+ .@%%%%%%%%:.......@@@*
33
+ @%%%%%%%%%%%:.....:@@
34
+ :.....@%%%%%%%@:::::@
35
+ =:........*#%%%%@+:::+
36
+ @%%%@*.......%%@@@@:%
37
+ @@%%%%%%%@:...::@@@@@
38
+ @@%%%%%%%@:::::@@@
39
+ @. .@@@@@@@@-:::@
40
+ .@ ..@@ @@@@@@@@@@
41
+ +#@%
42
+ `;
43
+ export const ASCII_TITLE = `
44
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
45
+ β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ•β•β–ˆβ–ˆβ–ˆβ•”β•
46
+ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•”β•
47
+ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ–ˆβ•”β•
48
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
49
+ β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•
50
+ `;
51
+ export function renderBanner() {
52
+ console.clear();
53
+ console.log(killaGradient(ASCII_BEE));
54
+ console.log(killaGradient(ASCII_TITLE));
55
+ console.log(chalk.bold.yellow(' ========================================================================================'));
56
+ console.log(chalk.bold.yellow(' [ 🐝 KILLA SWARM CODE HEALING PROTOCOL · DOCTOR BEEZ v1.0 · POWERED BY BEEZ DIGITAL 🐝 ]'));
57
+ console.log(chalk.bold.yellow(' ========================================================================================\n'));
58
+ }
@@ -0,0 +1,29 @@
1
+ import chalk from 'chalk';
2
+ export function renderDashboard(results) {
3
+ console.log(chalk.bold.yellow(' β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”'));
4
+ console.log(chalk.bold.yellow(' β”‚ πŸ“Š RESUMEN DE SALUD DEL PANAL ("LA MEDIA CAGADITA") β”‚'));
5
+ console.log(chalk.bold.yellow(' β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€'));
6
+ console.log(chalk.bold.yellow(' β”‚ Motor de AuditorΓ­a β”‚ Estado β”‚ Observaciones β”‚'));
7
+ console.log(chalk.bold.yellow(' β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€'));
8
+ const statusType = results.typeErrorsCount > 0
9
+ ? chalk.bold.red(` 🚨 ${results.typeErrorsCount} err `)
10
+ : chalk.bold.green(' 🟒 0 err ');
11
+ console.log(` β”‚ 1. TypeScript (CompilaciΓ³n) β”‚ ${statusType}β”‚ Errores de Tipado β”‚`);
12
+ const statusTests = results.testFailuresCount > 0
13
+ ? chalk.bold.red(` 🚨 ${results.testFailuresCount} fallos `)
14
+ : chalk.bold.green(' 🟒 0 fallos');
15
+ console.log(` β”‚ 2. Suite de Pruebas (Vitest/Jest) β”‚ ${statusTests}β”‚ Regresiones en Tests β”‚`);
16
+ const statusKnip = results.knipIssuesCount > 0
17
+ ? chalk.bold.yellow(` ⚠️ ${results.knipIssuesCount} obs `)
18
+ : chalk.bold.green(' 🟒 0 obs ');
19
+ console.log(` β”‚ 3. Knip (CΓ³digo Muerto y Deps) β”‚ ${statusKnip}β”‚ Variables/Exports β”‚`);
20
+ const statusSemgrep = results.semgrepIssuesCount > 0
21
+ ? chalk.bold.red(` πŸ›‘οΈ ${results.semgrepIssuesCount} warn `)
22
+ : chalk.bold.green(' 🟒 0 warn ');
23
+ console.log(` β”‚ 4. Semgrep (Seguridad) β”‚ ${statusSemgrep}β”‚ Reglas de Seguridad β”‚`);
24
+ const statusDpdm = results.circularDepsCount > 0
25
+ ? chalk.bold.yellow(` πŸ”„ ${results.circularDepsCount} circ `)
26
+ : chalk.bold.green(' 🟒 0 circ ');
27
+ console.log(` β”‚ 5. DPDM (Dependencias Circulares) β”‚ ${statusDpdm}β”‚ Grafos CΓ­clicos β”‚`);
28
+ console.log(chalk.bold.yellow(' β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n'));
29
+ }
package/doctor.sh ADDED
@@ -0,0 +1,103 @@
1
+ #!/bin/bash
2
+
3
+ # Color codes
4
+ RED='\033[0;31m'
5
+ GREEN='\033[0;32m'
6
+ NC='\033[0m'
7
+
8
+ echo "============================================="
9
+ echo " INICIANDO AUDITORÍA TOTAL DE EXCELENCIA "
10
+ echo "============================================="
11
+
12
+ # Clean old reports
13
+ rm -f report-1-types.log report-2-tests.log report-3-knip.json report-4-semgrep.json report-5-dpdm.log doctor-summary.txt
14
+
15
+ # Helper para ejecutar binarios locales ultra-rΓ‘pido sin overhead de npx
16
+ run_bin() {
17
+ if [ -f "./node_modules/.bin/$1" ]; then
18
+ "./node_modules/.bin/$@"
19
+ else
20
+ npx --no-install "$@"
21
+ fi
22
+ }
23
+
24
+ # ---------------------------------------------------------
25
+ # 1. VERIFICACIΓ“N DE TIPOS (TypeScript)
26
+ # ---------------------------------------------------------
27
+ echo -n "[1/5] Verificando compilaciΓ³n de tipos (tsc)... "
28
+ if run_bin tsc --noEmit > report-1-types.log 2>&1; then
29
+ echo -e "${GREEN}PASΓ“${NC}"
30
+ else
31
+ echo -e "${RED}FALLΓ“ (Revisar report-1-types.log)${NC}"
32
+ fi
33
+
34
+ # ---------------------------------------------------------
35
+ # 2. PRUEBAS UNITARIAS (DetecciΓ³n previa + EjecuciΓ³n)
36
+ # ---------------------------------------------------------
37
+ echo -n "[2/5] Ejecutando suite de pruebas... "
38
+
39
+ TEST_RUNNER=""
40
+ TEST_ARGS=""
41
+
42
+ if [ -f "./node_modules/.bin/vitest" ]; then
43
+ TEST_RUNNER="vitest"
44
+ TEST_ARGS="run --passWithNoTests"
45
+ elif [ -f "./node_modules/.bin/jest" ]; then
46
+ TEST_RUNNER="jest"
47
+ TEST_ARGS="--passWithNoTests"
48
+ elif [ -f "./node_modules/.bin/react-scripts" ]; then
49
+ TEST_RUNNER="react-scripts"
50
+ TEST_ARGS="test --watchAll=false"
51
+ fi
52
+
53
+ if [ -n "$TEST_RUNNER" ]; then
54
+ if CI=true run_bin $TEST_RUNNER $TEST_ARGS > report-2-tests.log 2>&1; then
55
+ echo -e "${GREEN}PASΓ“ ($TEST_RUNNER)${NC}"
56
+ else
57
+ echo -e "${RED}FALLΓ“ (Revisar report-2-tests.log)${NC}"
58
+ fi
59
+ else
60
+ echo "Omitido (No se encontrΓ³ Vitest, Jest ni react-scripts)"
61
+ fi
62
+
63
+ # ---------------------------------------------------------
64
+ # 3. CΓ“DIGO MUERTO Y DEPENDENCIAS (Knip)
65
+ # ---------------------------------------------------------
66
+ echo -n "[3/5] Analizando cΓ³digo muerto (Knip)... "
67
+ run_bin knip --no-exit-code --formatter json > report-3-knip.json 2>&1
68
+ echo -e "${GREEN}COMPLETADO${NC}"
69
+
70
+ # ---------------------------------------------------------
71
+ # 4. SEGURIDAD Y REGLAS DE LΓ“GICA (Semgrep)
72
+ # ---------------------------------------------------------
73
+ echo -n "[4/5] Auditando seguridad (Semgrep)... "
74
+ if command -v semgrep &> /dev/null; then
75
+ semgrep scan --config auto --json --output report-4-semgrep.json 2>/dev/null
76
+ else
77
+ run_bin semgrep scan --config auto --json --output report-4-semgrep.json 2>/dev/null
78
+ fi
79
+ echo -e "${GREEN}COMPLETADO${NC}"
80
+
81
+ # ---------------------------------------------------------
82
+ # 5. DEPENDENCIAS CIRCULARES (dpdm)
83
+ # ---------------------------------------------------------
84
+ ENTRY_POINT=""
85
+ for file in src/main.tsx src/main.ts src/index.tsx src/index.js src/app/layout.tsx app/layout.tsx; do
86
+ if [ -f "$file" ]; then
87
+ ENTRY_POINT="$file"
88
+ break
89
+ fi
90
+ done
91
+
92
+ if [ -n "$ENTRY_POINT" ]; then
93
+ echo -n "[5/5] Analizando grafos circulares en $ENTRY_POINT... "
94
+ run_bin dpdm "$ENTRY_POINT" --exit-code circular:0 > report-5-dpdm.log 2>&1
95
+ echo -e "${GREEN}COMPLETADO${NC}"
96
+ else
97
+ echo "Omitido (No se encontrΓ³ punto de entrada estΓ‘ndar en src/)"
98
+ fi
99
+
100
+ echo ""
101
+ echo "============================================="
102
+ echo " AUDITORÍA FINALIZADA. REVISA LOS LOGS. "
103
+ echo "============================================="
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "doctor-beez",
3
+ "version": "1.0.0",
4
+ "description": "El Enjambre de CuraciΓ³n AutΓ³noma de CΓ³digo - Powered by BEEZ DIGITAL",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "doctor-beez": "bin/doctor-beez.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "prepublishOnly": "npm run build",
12
+ "start": "tsx src/index.ts",
13
+ "doctor-beez": "tsx src/index.ts"
14
+ },
15
+ "files": [
16
+ "bin",
17
+ "src",
18
+ "dist",
19
+ "doctor.sh",
20
+ "README.md"
21
+ ],
22
+ "keywords": [
23
+ "cli",
24
+ "doctor",
25
+ "beez",
26
+ "refactor",
27
+ "linter",
28
+ "swapping"
29
+ ],
30
+ "author": "BEEZ DIGITAL",
31
+ "license": "MIT",
32
+ "dependencies": {
33
+ "@clack/prompts": "^0.8.2",
34
+ "chalk": "^5.3.0",
35
+ "execa": "^9.1.0",
36
+ "figlet": "^1.7.0",
37
+ "gradient-string": "^3.0.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/figlet": "^1.7.0",
41
+ "@types/node": "^20.11.0",
42
+ "tsx": "^4.7.0",
43
+ "typescript": "^5.3.3"
44
+ },
45
+ "type": "module"
46
+ }
@@ -0,0 +1,36 @@
1
+ import { execa } from 'execa';
2
+ import * as p from '@clack/prompts';
3
+ import chalk from 'chalk';
4
+
5
+ export async function checkGitHubAuth(): Promise<boolean> {
6
+ const spinner = p.spinner();
7
+ spinner.start('πŸ”‘ Verificando credenciales de GitHub (gh CLI)...');
8
+
9
+ try {
10
+ const { stdout } = await execa('gh', ['auth', 'status']);
11
+ spinner.stop('🟒 Autenticación de GitHub verificada.');
12
+ return true;
13
+ } catch (error) {
14
+ spinner.stop('πŸ”΄ No estΓ‘s autenticado en GitHub CLI (gh).');
15
+
16
+ const shouldLogin = await p.confirm({
17
+ message: 'ΒΏDeseas iniciar sesiΓ³n en GitHub ahora usando `gh auth login`?',
18
+ initialValue: true,
19
+ });
20
+
21
+ if (p.isCancel(shouldLogin) || !shouldLogin) {
22
+ p.log.warn('Continuando sin autenticaciΓ³n de GitHub...');
23
+ return false;
24
+ }
25
+
26
+ p.log.info('Iniciando proceso de login de GitHub...');
27
+ try {
28
+ await execa('gh', ['auth', 'login'], { stdio: 'inherit' });
29
+ p.log.success('Β‘AutenticaciΓ³n completada con Γ©xito!');
30
+ return true;
31
+ } catch (err) {
32
+ p.log.error('No se pudo completar la autenticaciΓ³n en GitHub.');
33
+ return false;
34
+ }
35
+ }
36
+ }
@@ -0,0 +1,34 @@
1
+ import * as p from '@clack/prompts';
2
+ import chalk from 'chalk';
3
+ import { runDiagnosticScan } from '../scanner/doctor.js';
4
+
5
+ export async function startSwarmHealingLoop(): Promise<void> {
6
+ p.log.info(chalk.bold.yellow('🐝 ENJAMBRE DESPLEGADO: Iniciando bucle de curación autónoma...'));
7
+
8
+ p.note(
9
+ `1. Copia las reglas de curaciΓ³n en tu agente (OpenCode / Aider / Antigravity).
10
+ 2. El agente procesarΓ‘ lotes de 3 a 5 errores como mΓ‘ximo.
11
+ 3. Se verificarΓ‘ compilaciΓ³n tsc y tests tras cada iteraciΓ³n.
12
+ 4. Cada lote limpio generarΓ‘ un commit atΓ³mico en Git.`,
13
+ 'πŸ“‹ Instrucciones para el Agente Curador'
14
+ );
15
+
16
+ const confirmStart = await p.confirm({
17
+ message: 'ΒΏIniciar primera iteraciΓ³n del enjambre de curaciΓ³n ahora?',
18
+ initialValue: true,
19
+ });
20
+
21
+ if (p.isCancel(confirmStart) || !confirmStart) {
22
+ p.log.warn('Bucle de curaciΓ³n en pausa. Puedes ejecutarlo cuando quieras.');
23
+ return;
24
+ }
25
+
26
+ p.log.success('🐝 ‘Enjambre trabajando! Re-auditando después del primer lote...');
27
+ const newResults = await runDiagnosticScan();
28
+
29
+ if (!newResults.hasErrors) {
30
+ p.outro(chalk.bold.green('πŸŽ‰ Β‘EL PANAL ESTÁ 100% LIMPIO Y SANO! 🐝✨'));
31
+ } else {
32
+ p.log.info('AΓΊn quedan observaciones por pulir. ContinΓΊa con el siguiente lote.');
33
+ }
34
+ }
package/src/index.ts ADDED
@@ -0,0 +1,58 @@
1
+ import * as p from '@clack/prompts';
2
+ import chalk from 'chalk';
3
+ import { renderBanner } from './ui/banner.js';
4
+ import { checkGitHubAuth } from './auth/github.js';
5
+ import { runDiagnosticScan } from './scanner/doctor.js';
6
+ import { renderDashboard } from './ui/dashboard.js';
7
+ import { startSwarmHealingLoop } from './healer/swarm.js';
8
+
9
+ async function main() {
10
+ // 1. Mostrar Banner Killa Beez
11
+ renderBanner();
12
+
13
+ p.intro(chalk.bold.yellow('🐝 DOCTOR BEEZ CLI β€” SISTEMA AUTΓ“NOMO DE AUDITORÍA Y CURACIΓ“N'));
14
+
15
+ // 2. Verificar AutenticaciΓ³n GitHub
16
+ await checkGitHubAuth();
17
+
18
+ // 3. Escaneo Silencioso
19
+ const results = await runDiagnosticScan();
20
+
21
+ // 4. Renderizar "La Media Cagadita"
22
+ renderDashboard(results);
23
+
24
+ // 5. Pregunta Interactiva al Usuario
25
+ if (!results.hasErrors) {
26
+ p.outro(chalk.bold.green('✨ ‘Tu proyecto estÑ impecable! No hay errores críticos detectados.'));
27
+ return;
28
+ }
29
+
30
+ const action = await p.select({
31
+ message: 'ΒΏQuΓ© deseas hacer con las observaciones encontradas?',
32
+ options: [
33
+ {
34
+ value: 'heal',
35
+ label: 'πŸš€ Β‘DALE COLOR! (Desplegar Enjambre de CuraciΓ³n)',
36
+ hint: 'Inicia el bucle de reparaciΓ³n autΓ³nomo',
37
+ },
38
+ {
39
+ value: 'exit',
40
+ label: '❌ No hermano, me dio miedo (Cancelar por ahora)',
41
+ hint: 'Mantiene los reportes sin hacer cambios',
42
+ },
43
+ ],
44
+ });
45
+
46
+ if (p.isCancel(action) || action === 'exit') {
47
+ p.outro(chalk.yellow('🐝 Operación cancelada. El enjambre se mantiene en espera.'));
48
+ process.exit(0);
49
+ }
50
+
51
+ // 6. Desplegar Enjambre
52
+ await startSwarmHealingLoop();
53
+ }
54
+
55
+ main().catch((err) => {
56
+ console.error(chalk.red('Error inesperado en DOCTOR BEEZ:'), err);
57
+ process.exit(1);
58
+ });
@@ -0,0 +1,96 @@
1
+ import { execa } from 'execa';
2
+ import * as p from '@clack/prompts';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+
6
+ export interface AuditResults {
7
+ typeErrorsCount: number;
8
+ testFailuresCount: number;
9
+ knipIssuesCount: number;
10
+ semgrepIssuesCount: number;
11
+ circularDepsCount: number;
12
+ hasErrors: boolean;
13
+ }
14
+
15
+ export async function runDiagnosticScan(): Promise<AuditResults> {
16
+ const spinner = p.spinner();
17
+ spinner.start('🐝 Desplegando abejas exploradoras para la auditoría de código...');
18
+
19
+ try {
20
+ // Run doctor.sh
21
+ await execa('bash', ['doctor.sh']);
22
+ spinner.stop('🐝 Auditoría inicial completada. Analizando reportes...');
23
+ } catch (error) {
24
+ spinner.stop('🐝 Auditoría finalizada con observaciones.');
25
+ }
26
+
27
+ // Parse report-1-types.log
28
+ let typeErrorsCount = 0;
29
+ if (fs.existsSync('report-1-types.log')) {
30
+ const content = fs.readFileSync('report-1-types.log', 'utf-8');
31
+ const matches = content.match(/error TS\d+/g);
32
+ if (matches) {
33
+ typeErrorsCount = matches.length;
34
+ }
35
+ }
36
+
37
+ // Parse report-2-tests.log
38
+ let testFailuresCount = 0;
39
+ if (fs.existsSync('report-2-tests.log')) {
40
+ const content = fs.readFileSync('report-2-tests.log', 'utf-8');
41
+ if (content.includes('FAIL') || content.includes('FAILED')) {
42
+ const matches = content.match(/FAIL/g);
43
+ testFailuresCount = matches ? matches.length : 1;
44
+ }
45
+ }
46
+
47
+ // Parse report-3-knip.json
48
+ let knipIssuesCount = 0;
49
+ if (fs.existsSync('report-3-knip.json')) {
50
+ try {
51
+ const raw = fs.readFileSync('report-3-knip.json', 'utf-8');
52
+ const data = JSON.parse(raw);
53
+ if (data && typeof data === 'object') {
54
+ const unused = data.unused || {};
55
+ knipIssuesCount = Object.keys(unused).reduce((acc, key) => acc + (Array.isArray(unused[key]) ? unused[key].length : 1), 0);
56
+ }
57
+ } catch (e) {
58
+ knipIssuesCount = 0;
59
+ }
60
+ }
61
+
62
+ // Parse report-4-semgrep.json
63
+ let semgrepIssuesCount = 0;
64
+ if (fs.existsSync('report-4-semgrep.json')) {
65
+ try {
66
+ const raw = fs.readFileSync('report-4-semgrep.json', 'utf-8');
67
+ const data = JSON.parse(raw);
68
+ if (data && data.results && Array.isArray(data.results)) {
69
+ semgrepIssuesCount = data.results.length;
70
+ }
71
+ } catch (e) {
72
+ semgrepIssuesCount = 0;
73
+ }
74
+ }
75
+
76
+ // Parse report-5-dpdm.log
77
+ let circularDepsCount = 0;
78
+ if (fs.existsSync('report-5-dpdm.log')) {
79
+ const content = fs.readFileSync('report-5-dpdm.log', 'utf-8');
80
+ const matches = content.match(/Circular/gi);
81
+ if (matches) {
82
+ circularDepsCount = matches.length;
83
+ }
84
+ }
85
+
86
+ const hasErrors = typeErrorsCount > 0 || testFailuresCount > 0 || knipIssuesCount > 0 || semgrepIssuesCount > 0 || circularDepsCount > 0;
87
+
88
+ return {
89
+ typeErrorsCount,
90
+ testFailuresCount,
91
+ knipIssuesCount,
92
+ semgrepIssuesCount,
93
+ circularDepsCount,
94
+ hasErrors,
95
+ };
96
+ }
@@ -0,0 +1,62 @@
1
+ import chalk from 'chalk';
2
+ import gradient from 'gradient-string';
3
+
4
+ const killaGradient = gradient(['#FFE600', '#FFB300', '#FF8C00']);
5
+
6
+ export const ASCII_BEE = `
7
+ .@@%
8
+ #::::*@*@@@@@@@@%
9
+ @
10
+ . @
11
+ -:::::@==++*#%@# =@ +*@ =
12
+ @ @- :%@. @ =
13
+ @@ @%%%%%%%@* # @ .@. @ %
14
+ @%::@%%%%%%%+-%% -@ @ @ ..
15
+ .%:.= %%@:..%%%%%%%%% %%:+ = = .@# % %#
16
+ @ :+- .%%%...@%%%%%%%% %%%:@ @ @ # :#@@# @
17
+ . * . ::#%%%..-%%%%%%%% %%:::@ - @@# +@#*% % % @
18
+ . *.# @@. # @%%*.:@%%%%%%%%%%:*@:@%%%%%@*+++++*%=+@ -@ .
19
+ .@. %-. @ %%%+..%%%%%%%%%%.%#:@%%%%%%%@@ @++# + @ #
20
+ % @%.. %%:..*%%%%%*- =*::@%%%%%%%%%%@ .@+@*-.@ @
21
+ .#+%-# @:.....:::.@ %::@%%%%%%%%@- #.*++++++%
22
+ @.*+@ :@. -..........::::@%%%%%%%%%%- @@@*+#@@@+
23
+ *#@+++@:@@****:...:%@@@@%%%%%%%%%%%%%%%- #@*+#*#@+*@
24
+ :.**+++++++++++*@@%%%%%%%%%%%%%%%%%%%%%@@.% . %+*=
25
+ . .%. . %++@%%%%%%%%%%%%%%%%%%%%%%@ @%+*#
26
+ @.. -*+*@+@%@%%%%%%%%%%%%%%%%%%%%. .**@
27
+ =@+*@@@ *@@%%%%%%%%%%%%%%%%%%%%%-@ @
28
+ .@+*++++*@. @@@%%%%%%%%%%%%%%%%%@%. .
29
+ @**@+ *++@.. @:@%%%%%%%%%%%%%%@ ..
30
+ @+*@%* . #@%%%@@%@%%%%%% :@
31
+ *+++*#@ @%@@:....:.@%%@###%%#-
32
+ @@ @:..........-#*#@@@#
33
+ @%@@@:......... @@@@.
34
+ .@%%%%%%%%:.......@@@*
35
+ @%%%%%%%%%%%:.....:@@
36
+ :.....@%%%%%%%@:::::@
37
+ =:........*#%%%%@+:::+
38
+ @%%%@*.......%%@@@@:%
39
+ @@%%%%%%%@:...::@@@@@
40
+ @@%%%%%%%@:::::@@@
41
+ @. .@@@@@@@@-:::@
42
+ .@ ..@@ @@@@@@@@@@
43
+ +#@%
44
+ `;
45
+
46
+ export const ASCII_TITLE = `
47
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
48
+ β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ•β•β–ˆβ–ˆβ•”β•β•β•β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β•β•β•β–ˆβ–ˆβ•”β•β•β•β•β•β•šβ•β•β–ˆβ–ˆβ–ˆβ•”β•
49
+ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β• β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ–ˆβ•”β•
50
+ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•— β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ•”β•β•β• β–ˆβ–ˆβ–ˆβ•”β•
51
+ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•— β–ˆβ–ˆβ•‘ β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ•‘ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—
52
+ β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β• β•šβ•β• β•šβ•β•β•β•β•β• β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•β•šβ•β•β•β•β•β•β•
53
+ `;
54
+
55
+ export function renderBanner(): void {
56
+ console.clear();
57
+ console.log(killaGradient(ASCII_BEE));
58
+ console.log(killaGradient(ASCII_TITLE));
59
+ console.log(chalk.bold.yellow(' ========================================================================================'));
60
+ console.log(chalk.bold.yellow(' [ 🐝 KILLA SWARM CODE HEALING PROTOCOL · DOCTOR BEEZ v1.0 · POWERED BY BEEZ DIGITAL 🐝 ]'));
61
+ console.log(chalk.bold.yellow(' ========================================================================================\n'));
62
+ }
@@ -0,0 +1,37 @@
1
+ import chalk from 'chalk';
2
+ import { AuditResults } from '../scanner/doctor.js';
3
+
4
+ export function renderDashboard(results: AuditResults): void {
5
+ console.log(chalk.bold.yellow(' β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”'));
6
+ console.log(chalk.bold.yellow(' β”‚ πŸ“Š RESUMEN DE SALUD DEL PANAL ("LA MEDIA CAGADITA") β”‚'));
7
+ console.log(chalk.bold.yellow(' β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€'));
8
+ console.log(chalk.bold.yellow(' β”‚ Motor de AuditorΓ­a β”‚ Estado β”‚ Observaciones β”‚'));
9
+ console.log(chalk.bold.yellow(' β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€'));
10
+
11
+ const statusType = results.typeErrorsCount > 0
12
+ ? chalk.bold.red(` 🚨 ${results.typeErrorsCount} err `)
13
+ : chalk.bold.green(' 🟒 0 err ');
14
+ console.log(` β”‚ 1. TypeScript (CompilaciΓ³n) β”‚ ${statusType}β”‚ Errores de Tipado β”‚`);
15
+
16
+ const statusTests = results.testFailuresCount > 0
17
+ ? chalk.bold.red(` 🚨 ${results.testFailuresCount} fallos `)
18
+ : chalk.bold.green(' 🟒 0 fallos');
19
+ console.log(` β”‚ 2. Suite de Pruebas (Vitest/Jest) β”‚ ${statusTests}β”‚ Regresiones en Tests β”‚`);
20
+
21
+ const statusKnip = results.knipIssuesCount > 0
22
+ ? chalk.bold.yellow(` ⚠️ ${results.knipIssuesCount} obs `)
23
+ : chalk.bold.green(' 🟒 0 obs ');
24
+ console.log(` β”‚ 3. Knip (CΓ³digo Muerto y Deps) β”‚ ${statusKnip}β”‚ Variables/Exports β”‚`);
25
+
26
+ const statusSemgrep = results.semgrepIssuesCount > 0
27
+ ? chalk.bold.red(` πŸ›‘οΈ ${results.semgrepIssuesCount} warn `)
28
+ : chalk.bold.green(' 🟒 0 warn ');
29
+ console.log(` β”‚ 4. Semgrep (Seguridad) β”‚ ${statusSemgrep}β”‚ Reglas de Seguridad β”‚`);
30
+
31
+ const statusDpdm = results.circularDepsCount > 0
32
+ ? chalk.bold.yellow(` πŸ”„ ${results.circularDepsCount} circ `)
33
+ : chalk.bold.green(' 🟒 0 circ ');
34
+ console.log(` β”‚ 5. DPDM (Dependencias Circulares) β”‚ ${statusDpdm}β”‚ Grafos CΓ­clicos β”‚`);
35
+
36
+ console.log(chalk.bold.yellow(' β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜\n'));
37
+ }