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 +94 -0
- package/bin/doctor-beez.js +21 -0
- package/dist/auth/github.js +32 -0
- package/dist/healer/swarm.js +26 -0
- package/dist/index.js +48 -0
- package/dist/scanner/doctor.js +80 -0
- package/dist/ui/banner.js +58 -0
- package/dist/ui/dashboard.js +29 -0
- package/doctor.sh +103 -0
- package/package.json +46 -0
- package/src/auth/github.ts +36 -0
- package/src/healer/swarm.ts +34 -0
- package/src/index.ts +58 -0
- package/src/scanner/doctor.ts +96 -0
- package/src/ui/banner.ts +62 -0
- package/src/ui/dashboard.ts +37 -0
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
|
+
}
|
package/src/ui/banner.ts
ADDED
|
@@ -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
|
+
}
|