@saulwade/swl-ses 2.4.2 → 2.5.1
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/CLAUDE.md +194 -241
- package/README.md +600 -597
- package/agentes/_intent-spec.md +73 -73
- package/agentes/_propose-step.md +90 -90
- package/agentes/abogado-diablo-swl.md +145 -0
- package/agentes/accesibilidad-wcag-swl.md +690 -690
- package/agentes/arquitecto-swl.md +267 -267
- package/agentes/auto-evolucion-swl.md +908 -908
- package/agentes/backend-api-swl.md +1 -1
- package/agentes/backend-csharp-swl.md +420 -420
- package/agentes/backend-go-swl.md +390 -390
- package/agentes/backend-java-swl.md +281 -281
- package/agentes/backend-node-swl.md +1 -1
- package/agentes/backend-python-swl.md +1 -1
- package/agentes/backend-rust-swl.md +364 -364
- package/agentes/backend-workers-swl.md +482 -482
- package/agentes/cloud-infra-swl.md +509 -509
- package/agentes/consolidador-swl.md +541 -541
- package/agentes/datos-swl.md +1 -1
- package/agentes/depurador-swl.md +352 -352
- package/agentes/devops-ci-swl.md +400 -400
- package/agentes/disenador-ui-swl.md +569 -569
- package/agentes/documentador-swl.md +345 -345
- package/agentes/frontend-angular-swl.md +621 -621
- package/agentes/frontend-css-swl.md +716 -716
- package/agentes/frontend-react-swl.md +692 -692
- package/agentes/frontend-swl.md +496 -496
- package/agentes/frontend-tailwind-swl.md +826 -826
- package/agentes/gh-fix-ci-swl.md +6 -1
- package/agentes/implementador-swl.md +1 -1
- package/agentes/investigador-swl.md +432 -432
- package/agentes/investigador-ux-swl.md +505 -505
- package/agentes/llm-apps-swl.md +1 -1
- package/agentes/migrador-swl.md +442 -442
- package/agentes/mobile-android-swl.md +511 -511
- package/agentes/mobile-cross-swl.md +541 -541
- package/agentes/mobile-ios-swl.md +502 -502
- package/agentes/mobile-testing-swl.md +302 -302
- package/agentes/nemesis-auditor-swl.md +285 -285
- package/agentes/notificador-swl.md +1 -1
- package/agentes/observabilidad-swl.md +438 -438
- package/agentes/pagos-swl.md +310 -310
- package/agentes/perfilador-usuario-swl.md +321 -321
- package/agentes/planificador-swl.md +399 -399
- package/agentes/producto-prd-swl.md +589 -589
- package/agentes/red-team-swl.md +218 -218
- package/agentes/release-manager-swl.md +590 -590
- package/agentes/rendimiento-swl.md +713 -713
- package/agentes/resolutor-build-swl.md +10 -1
- package/agentes/revisor-angular-swl.md +278 -278
- package/agentes/revisor-codigo-swl.md +1 -1
- package/agentes/revisor-csharp-swl.md +264 -264
- package/agentes/revisor-go-swl.md +259 -259
- package/agentes/revisor-java-swl.md +257 -257
- package/agentes/revisor-kotlin-swl.md +273 -273
- package/agentes/revisor-nextjs-swl.md +281 -281
- package/agentes/revisor-php-swl.md +271 -271
- package/agentes/revisor-react-swl.md +278 -278
- package/agentes/revisor-rust-swl.md +346 -346
- package/agentes/revisor-seguridad-swl.md +399 -399
- package/agentes/revisor-swift-swl.md +268 -268
- package/agentes/revisor-typescript-swl.md +346 -346
- package/agentes/sre-swl.md +1 -1
- package/agentes/tdd-qa-swl.md +393 -393
- package/bin/lib/bot-comandos.js +1 -1
- package/bin/swl-ses.js +6 -0
- package/comandos/swl/adoptar-proyecto.md +14 -2
- package/comandos/swl/configurar-ci.md +8 -1
- package/comandos/swl/deuda-codigo.md +97 -97
- package/comandos/swl/discutir-fase.md +22 -118
- package/comandos/swl/fix.md +118 -0
- package/comandos/swl/nuevo-proyecto.md +54 -3
- package/comandos/swl/predecir.md +32 -2
- package/comandos/swl/seguridad.md +189 -0
- package/comandos/swl/status.md +5 -3
- package/habilidades/aprendizaje-continuo/SKILL.md +3 -1
- package/habilidades/discutir-fase/SKILL.md +84 -81
- package/habilidades/discutir-fase/recursos/plantilla-contexto.md +136 -0
- package/habilidades/doc-sync/SKILL.md +3 -1
- package/habilidades/doubt-driven-review/SKILL.md +15 -1
- package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
- package/habilidades/estructura-proyecto-claude/SKILL.md +11 -2
- package/habilidades/harness-claude-code/SKILL.md +3 -1
- package/habilidades/instalar-sistema/SKILL.md +3 -1
- package/habilidades/meta-reglas-extendido/SKILL.md +92 -0
- package/habilidades/meta-reglas-extendido/recursos/analisis-previo-tareas-grandes.md +186 -0
- package/habilidades/meta-reglas-extendido/recursos/analizar-directorios-antes-de-escribir.md +235 -0
- package/habilidades/meta-reglas-extendido/recursos/api-diseno.md +413 -0
- package/habilidades/meta-reglas-extendido/recursos/arquitectura.md +491 -0
- package/habilidades/meta-reglas-extendido/recursos/arreglar-al-detectar.md +264 -0
- package/habilidades/meta-reglas-extendido/recursos/debatir-antes-de-aceptar.md +152 -0
- package/habilidades/meta-reglas-extendido/recursos/git-workflow.md +259 -0
- package/habilidades/meta-reglas-extendido/recursos/gobernanza.md +291 -0
- package/habilidades/meta-reglas-extendido/recursos/memoria-consolidada.md +263 -0
- package/habilidades/meta-reglas-extendido/recursos/seguridad-agentes.md +443 -0
- package/habilidades/meta-reglas-extendido/recursos/sesiones-paralelas.md +190 -0
- package/habilidades/meta-reglas-extendido/recursos/sin-duplicacion-reglas-globales.md +179 -0
- package/habilidades/meta-reglas-extendido/recursos/skills-estandar.md +394 -0
- package/habilidades/meta-reglas-extendido/recursos/usar-code-review-graph.md +156 -0
- package/habilidades/meta-reglas-extendido/recursos/usar-context7.md +236 -0
- package/habilidades/meta-reglas-extendido/recursos/usar-sistema-swl.md +253 -0
- package/habilidades/meta-reglas-extendido/recursos/verificar-citas-normativas.md +527 -0
- package/habilidades/meta-skills-estandar/SKILL.md +3 -1
- package/habilidades/nuevo-proyecto/SKILL.md +20 -3
- package/habilidades/php-experto/SKILL.md +10 -3
- package/habilidades/{filament-admin/SKILL.md → php-experto/recursos/filament-admin.md} +23 -39
- package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
- package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
- package/habilidades/proceso-debate-adversarial/recursos/personas.md +5 -4
- package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -0
- package/hooks/check-update.js +19 -10
- package/hooks/contexto-subagente.js +68 -68
- package/hooks/degradacion-instintos.js +1 -1
- package/hooks/extraccion-aprendizajes.js +2 -2
- package/hooks/lib/briefing.js +3 -3
- package/hooks/lib/nudge-tracker.js +1 -1
- package/hooks/lib/otlp-exporter.js +1 -1
- package/hooks/lib/webhook-dedup.js +1 -1
- package/hooks/session-briefing.js +1 -1
- package/llms.txt +6 -6
- package/manifiestos/canonical-hashes.json +989 -0
- package/manifiestos/hooks-config.json +469 -469
- package/manifiestos/invariantes-criticos.json +30 -30
- package/manifiestos/modulos.json +168 -135
- package/manifiestos/perfiles.json +0 -2
- package/manifiestos/skills-lock.json +52 -59
- package/package.json +7 -5
- package/plantillas/github-workflows/README.md +15 -1
- package/plantillas/github-workflows/swl-devsecops.yml +70 -0
- package/plugin.json +5 -5
- package/reglas/analisis-previo-tareas-grandes.md +30 -156
- package/reglas/analizar-directorios-antes-de-escribir.md +30 -211
- package/reglas/api-diseno.md +28 -398
- package/reglas/arquitectura.md +35 -456
- package/reglas/arreglar-al-detectar.md +30 -230
- package/reglas/debatir-antes-de-aceptar.md +30 -143
- package/reglas/docs.md +7 -0
- package/reglas/estilo-codigo.md +9 -0
- package/reglas/fragmentos-compartidos.md +6 -0
- package/reglas/git-workflow.md +44 -240
- package/reglas/gobernanza.md +23 -262
- package/reglas/memoria-consolidada.md +34 -228
- package/reglas/performance.md +8 -0
- package/reglas/pruebas.md +12 -0
- package/reglas/seguridad-agentes.md +37 -418
- package/reglas/seguridad.md +12 -0
- package/reglas/sesiones-paralelas.md +29 -162
- package/reglas/sin-duplicacion-reglas-globales.md +25 -166
- package/reglas/skills-estandar.md +23 -373
- package/reglas/usar-code-review-graph.md +31 -140
- package/reglas/usar-context7.md +30 -208
- package/reglas/usar-sistema-swl.md +47 -242
- package/reglas/verificar-citas-normativas.md +47 -537
- package/scripts/actualizar.js +253 -253
- package/scripts/audit-tools/auditar-relleno-inventario.js +145 -0
- package/scripts/auditar-clases-conocidas.js +106 -0
- package/scripts/bootstrap-instintos.js +2 -2
- package/scripts/canario-hooks.js +166 -0
- package/scripts/cli/configurar-ci.js +2 -1
- package/scripts/evidencia-valor.js +93 -0
- package/scripts/field-report.js +1 -1
- package/scripts/generar-comandos.js +143 -0
- package/scripts/generar-inventario.js +236 -23
- package/scripts/generar-matriz-lenguajes.js +1 -1
- package/scripts/instalador.js +15 -1
- package/scripts/lib/configurar-ci.js +10 -3
- package/scripts/lib/detectar-runtime.js +12 -3
- package/scripts/lib/diary-entry.js +3 -1
- package/scripts/lib/drift-detector.js +1 -1
- package/scripts/lib/evidencia-valor.js +189 -0
- package/scripts/lib/expandir-targets.js +71 -71
- package/scripts/lib/frontmatter-md.js +63 -0
- package/scripts/lib/parsear-opciones.js +2 -0
- package/scripts/lib/prune-componentes.js +180 -0
- package/scripts/lib/reglas-globales-conocidas.json +16 -2
- package/scripts/lib/scoring-instintos.js +2 -2
- package/scripts/lib/toml-merge.js +204 -204
- package/scripts/lib/transformadores/claude.js +1 -1
- package/scripts/lib/transformadores/codex.js +1 -1
- package/scripts/lib/transformadores/copilot.js +1 -1
- package/scripts/lib/transformadores/cursor.js +1 -1
- package/scripts/lib/transformadores/gemini.js +22 -2
- package/scripts/lib/transformadores/opencode.js +1 -1
- package/scripts/mcp-server/auth.js +105 -105
- package/scripts/mcp-server/cache.js +106 -106
- package/scripts/prune.js +102 -0
- package/scripts/publicar.js +18 -2
- package/scripts/tui/pantallas/inspect.js +175 -175
- package/scripts/tui/pantallas/uninstall-wizard.js +210 -210
- package/scripts/tui/pantallas/update-wizard.js +234 -234
- package/scripts/tui/pantallas/welcome.js +189 -189
- package/habilidades/paid-media-tracking/SKILL.md +0 -269
- package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +0 -220
- package/habilidades/paid-media-tracking/recursos/google-ads-api.md +0 -215
- package/habilidades/tracking-measurement/SKILL.md +0 -239
- package/habilidades/tracking-measurement/recursos/consent-mode.md +0 -231
- package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +0 -216
- package/habilidades/tracking-measurement/recursos/meta-capi.md +0 -262
|
@@ -1,175 +1,175 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Pantalla Inspect — navegador read-only de componentes instalados.
|
|
5
|
-
*
|
|
6
|
-
* Flujo:
|
|
7
|
-
* 1. Lista de instalaciones detectadas (runtime + scope + perfil + version)
|
|
8
|
-
* 2. Al seleccionar una, muestra detalles:
|
|
9
|
-
* - Componentes por categoría (con conteos)
|
|
10
|
-
* - Última actualización
|
|
11
|
-
* - Lista de hooks registrados
|
|
12
|
-
* - Lista de skills disponibles
|
|
13
|
-
*
|
|
14
|
-
* No modifica nada. Solo lee de los archivos de estado.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
const fs = require('fs');
|
|
18
|
-
const path = require('path');
|
|
19
|
-
|
|
20
|
-
const { selectorUnico } = require('../componentes/selector-unico');
|
|
21
|
-
const render = require('../lib/render');
|
|
22
|
-
const teclas = require('../lib/teclas');
|
|
23
|
-
const { colores, semantico, iconos } = require('../lib/colores');
|
|
24
|
-
|
|
25
|
-
function _cargarDatosInstalaciones() {
|
|
26
|
-
let detectarRuntimes, cargarEstado;
|
|
27
|
-
try {
|
|
28
|
-
({ detectarRuntimes, scopesReales } = require('../../lib/detectar-runtime'));
|
|
29
|
-
({ cargarEstado } = require('../../lib/estado'));
|
|
30
|
-
} catch (_) {
|
|
31
|
-
return [];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const runtimes = detectarRuntimes();
|
|
35
|
-
const filas = [];
|
|
36
|
-
for (const runtime of runtimes) {
|
|
37
|
-
// Dedup + guard anti-fantasma: desde HOME, el local relativo resuelve al
|
|
38
|
-
// global propio (duplicado) o al de OTRO runtime (p.ej. .claude de
|
|
39
|
-
// OpenClaude = global de Claude Code) — ver scopesReales().
|
|
40
|
-
const candidatos = scopesReales(runtime).map(({ dir, esGlobal }) => (
|
|
41
|
-
{ ruta: dir, scope: esGlobal ? 'global' : 'proyecto' }
|
|
42
|
-
));
|
|
43
|
-
for (const { ruta, scope } of candidatos) {
|
|
44
|
-
if (!fs.existsSync(ruta)) continue;
|
|
45
|
-
const estado = cargarEstado(ruta);
|
|
46
|
-
if (!estado) continue;
|
|
47
|
-
filas.push({
|
|
48
|
-
id: `${runtime.id}:${scope}`,
|
|
49
|
-
runtimeId: runtime.id,
|
|
50
|
-
runtimeNombre: runtime.nombre,
|
|
51
|
-
scope,
|
|
52
|
-
ruta,
|
|
53
|
-
version: estado.versionSistema || 'desconocida',
|
|
54
|
-
perfil: estado.perfil || '-',
|
|
55
|
-
instalado: estado.fechaInstalacion || estado.timestamp || '-',
|
|
56
|
-
componentes: estado.componentesInstalados || [],
|
|
57
|
-
archivos: estado.archivosInstalados || [],
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return filas;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
function _agruparPorCategoria(archivos) {
|
|
65
|
-
const grupos = {};
|
|
66
|
-
for (const a of archivos) {
|
|
67
|
-
const cat = a.tipo || a.categoria || 'otros';
|
|
68
|
-
grupos[cat] = (grupos[cat] || 0) + 1;
|
|
69
|
-
}
|
|
70
|
-
return grupos;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function _pantallaDetalle(fila) {
|
|
74
|
-
return new Promise((resolve) => {
|
|
75
|
-
if (!render.ES_TTY || !process.stdin.isTTY) {
|
|
76
|
-
resolve();
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
function _renderizar() {
|
|
81
|
-
render.limpiarPantalla();
|
|
82
|
-
const { cols, rows } = render.obtenerDimensiones();
|
|
83
|
-
|
|
84
|
-
render.escribirEn(2, 3, semantico.titulo(`${fila.runtimeNombre} — ${fila.scope}`));
|
|
85
|
-
render.escribirEn(3, 3, colores.dim(fila.ruta));
|
|
86
|
-
|
|
87
|
-
const datos = [
|
|
88
|
-
['Versión', colores.cyan('v' + fila.version)],
|
|
89
|
-
['Perfil', semantico.enfasis(fila.perfil)],
|
|
90
|
-
['Instalado', fila.instalado],
|
|
91
|
-
['Total componentes', String(fila.componentes.length)],
|
|
92
|
-
['Total archivos', String(fila.archivos.length)],
|
|
93
|
-
];
|
|
94
|
-
|
|
95
|
-
datos.forEach((d, i) => {
|
|
96
|
-
render.escribirEn(5 + i, 5,
|
|
97
|
-
render.rellenarDer(colores.dim(d[0] + ':'), 22) + d[1]);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
// Conteos por categoría
|
|
101
|
-
const grupos = _agruparPorCategoria(fila.archivos);
|
|
102
|
-
const categorias = Object.entries(grupos).sort(([a], [b]) => a.localeCompare(b));
|
|
103
|
-
|
|
104
|
-
const filaCat = 5 + datos.length + 2;
|
|
105
|
-
render.escribirEn(filaCat, 3, semantico.enfasis('Archivos por categoría:'));
|
|
106
|
-
categorias.forEach(([cat, n], i) => {
|
|
107
|
-
const fila = filaCat + 1 + i;
|
|
108
|
-
if (fila >= rows - 3) return;
|
|
109
|
-
render.escribirEn(fila, 5,
|
|
110
|
-
render.rellenarDer(`${iconos.punto} ${cat}`, 22) +
|
|
111
|
-
colores.cyan(String(n).padStart(4)));
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
render.dibujarPiePagina([
|
|
115
|
-
['Enter|Esc', 'volver al listado'],
|
|
116
|
-
]);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
render.iniciarModoTui();
|
|
120
|
-
_renderizar();
|
|
121
|
-
|
|
122
|
-
const onResize = () => _renderizar();
|
|
123
|
-
process.stdout.on('resize', onResize);
|
|
124
|
-
|
|
125
|
-
const teclado = teclas.crearTeclado();
|
|
126
|
-
function _finalizar() {
|
|
127
|
-
teclado.desactivar();
|
|
128
|
-
process.stdout.removeListener('resize', onResize);
|
|
129
|
-
render.salirModoTui();
|
|
130
|
-
resolve();
|
|
131
|
-
}
|
|
132
|
-
teclado.on('return', _finalizar);
|
|
133
|
-
teclado.on('escape', _finalizar);
|
|
134
|
-
teclado.activar();
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function ejecutarInspect() {
|
|
139
|
-
const instalaciones = _cargarDatosInstalaciones();
|
|
140
|
-
|
|
141
|
-
if (instalaciones.length === 0) {
|
|
142
|
-
return {
|
|
143
|
-
exito: false,
|
|
144
|
-
error: 'No se detectaron instalaciones SWL en este equipo.',
|
|
145
|
-
sugerencia: 'Ejecuta swl-ses install para crear una.',
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Loop: seleccionar una instalación → ver detalle → volver al listado.
|
|
150
|
-
// Esc en el listado sale del Inspect.
|
|
151
|
-
while (true) {
|
|
152
|
-
const items = instalaciones.map(i => ({
|
|
153
|
-
valor: i.id,
|
|
154
|
-
etiqueta: `${i.runtimeNombre} (${i.scope}) — v${i.version} · perfil ${i.perfil}`,
|
|
155
|
-
descripcion: `${i.componentes.length} componentes · ${i.archivos.length} archivos · ${i.ruta}`,
|
|
156
|
-
}));
|
|
157
|
-
|
|
158
|
-
const elegida = await selectorUnico({
|
|
159
|
-
titulo: 'Inspect — Elige una instalación para ver detalle:',
|
|
160
|
-
items,
|
|
161
|
-
});
|
|
162
|
-
if (!elegida) break;
|
|
163
|
-
|
|
164
|
-
const fila = instalaciones.find(i => i.id === elegida);
|
|
165
|
-
if (fila) await _pantallaDetalle(fila);
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
return { exito: true };
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
module.exports = {
|
|
172
|
-
ejecutarInspect,
|
|
173
|
-
_cargarDatosInstalaciones,
|
|
174
|
-
_agruparPorCategoria,
|
|
175
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Pantalla Inspect — navegador read-only de componentes instalados.
|
|
5
|
+
*
|
|
6
|
+
* Flujo:
|
|
7
|
+
* 1. Lista de instalaciones detectadas (runtime + scope + perfil + version)
|
|
8
|
+
* 2. Al seleccionar una, muestra detalles:
|
|
9
|
+
* - Componentes por categoría (con conteos)
|
|
10
|
+
* - Última actualización
|
|
11
|
+
* - Lista de hooks registrados
|
|
12
|
+
* - Lista de skills disponibles
|
|
13
|
+
*
|
|
14
|
+
* No modifica nada. Solo lee de los archivos de estado.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const path = require('path');
|
|
19
|
+
|
|
20
|
+
const { selectorUnico } = require('../componentes/selector-unico');
|
|
21
|
+
const render = require('../lib/render');
|
|
22
|
+
const teclas = require('../lib/teclas');
|
|
23
|
+
const { colores, semantico, iconos } = require('../lib/colores');
|
|
24
|
+
|
|
25
|
+
function _cargarDatosInstalaciones() {
|
|
26
|
+
let detectarRuntimes, cargarEstado;
|
|
27
|
+
try {
|
|
28
|
+
({ detectarRuntimes, scopesReales } = require('../../lib/detectar-runtime'));
|
|
29
|
+
({ cargarEstado } = require('../../lib/estado'));
|
|
30
|
+
} catch (_) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const runtimes = detectarRuntimes();
|
|
35
|
+
const filas = [];
|
|
36
|
+
for (const runtime of runtimes) {
|
|
37
|
+
// Dedup + guard anti-fantasma: desde HOME, el local relativo resuelve al
|
|
38
|
+
// global propio (duplicado) o al de OTRO runtime (p.ej. .claude de
|
|
39
|
+
// OpenClaude = global de Claude Code) — ver scopesReales().
|
|
40
|
+
const candidatos = scopesReales(runtime).map(({ dir, esGlobal }) => (
|
|
41
|
+
{ ruta: dir, scope: esGlobal ? 'global' : 'proyecto' }
|
|
42
|
+
));
|
|
43
|
+
for (const { ruta, scope } of candidatos) {
|
|
44
|
+
if (!fs.existsSync(ruta)) continue;
|
|
45
|
+
const estado = cargarEstado(ruta);
|
|
46
|
+
if (!estado) continue;
|
|
47
|
+
filas.push({
|
|
48
|
+
id: `${runtime.id}:${scope}`,
|
|
49
|
+
runtimeId: runtime.id,
|
|
50
|
+
runtimeNombre: runtime.nombre,
|
|
51
|
+
scope,
|
|
52
|
+
ruta,
|
|
53
|
+
version: estado.versionSistema || 'desconocida',
|
|
54
|
+
perfil: estado.perfil || '-',
|
|
55
|
+
instalado: estado.fechaInstalacion || estado.timestamp || '-',
|
|
56
|
+
componentes: estado.componentesInstalados || [],
|
|
57
|
+
archivos: estado.archivosInstalados || [],
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return filas;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function _agruparPorCategoria(archivos) {
|
|
65
|
+
const grupos = {};
|
|
66
|
+
for (const a of archivos) {
|
|
67
|
+
const cat = a.tipo || a.categoria || 'otros';
|
|
68
|
+
grupos[cat] = (grupos[cat] || 0) + 1;
|
|
69
|
+
}
|
|
70
|
+
return grupos;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function _pantallaDetalle(fila) {
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
if (!render.ES_TTY || !process.stdin.isTTY) {
|
|
76
|
+
resolve();
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function _renderizar() {
|
|
81
|
+
render.limpiarPantalla();
|
|
82
|
+
const { cols, rows } = render.obtenerDimensiones();
|
|
83
|
+
|
|
84
|
+
render.escribirEn(2, 3, semantico.titulo(`${fila.runtimeNombre} — ${fila.scope}`));
|
|
85
|
+
render.escribirEn(3, 3, colores.dim(fila.ruta));
|
|
86
|
+
|
|
87
|
+
const datos = [
|
|
88
|
+
['Versión', colores.cyan('v' + fila.version)],
|
|
89
|
+
['Perfil', semantico.enfasis(fila.perfil)],
|
|
90
|
+
['Instalado', fila.instalado],
|
|
91
|
+
['Total componentes', String(fila.componentes.length)],
|
|
92
|
+
['Total archivos', String(fila.archivos.length)],
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
datos.forEach((d, i) => {
|
|
96
|
+
render.escribirEn(5 + i, 5,
|
|
97
|
+
render.rellenarDer(colores.dim(d[0] + ':'), 22) + d[1]);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Conteos por categoría
|
|
101
|
+
const grupos = _agruparPorCategoria(fila.archivos);
|
|
102
|
+
const categorias = Object.entries(grupos).sort(([a], [b]) => a.localeCompare(b));
|
|
103
|
+
|
|
104
|
+
const filaCat = 5 + datos.length + 2;
|
|
105
|
+
render.escribirEn(filaCat, 3, semantico.enfasis('Archivos por categoría:'));
|
|
106
|
+
categorias.forEach(([cat, n], i) => {
|
|
107
|
+
const fila = filaCat + 1 + i;
|
|
108
|
+
if (fila >= rows - 3) return;
|
|
109
|
+
render.escribirEn(fila, 5,
|
|
110
|
+
render.rellenarDer(`${iconos.punto} ${cat}`, 22) +
|
|
111
|
+
colores.cyan(String(n).padStart(4)));
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
render.dibujarPiePagina([
|
|
115
|
+
['Enter|Esc', 'volver al listado'],
|
|
116
|
+
]);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
render.iniciarModoTui();
|
|
120
|
+
_renderizar();
|
|
121
|
+
|
|
122
|
+
const onResize = () => _renderizar();
|
|
123
|
+
process.stdout.on('resize', onResize);
|
|
124
|
+
|
|
125
|
+
const teclado = teclas.crearTeclado();
|
|
126
|
+
function _finalizar() {
|
|
127
|
+
teclado.desactivar();
|
|
128
|
+
process.stdout.removeListener('resize', onResize);
|
|
129
|
+
render.salirModoTui();
|
|
130
|
+
resolve();
|
|
131
|
+
}
|
|
132
|
+
teclado.on('return', _finalizar);
|
|
133
|
+
teclado.on('escape', _finalizar);
|
|
134
|
+
teclado.activar();
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
async function ejecutarInspect() {
|
|
139
|
+
const instalaciones = _cargarDatosInstalaciones();
|
|
140
|
+
|
|
141
|
+
if (instalaciones.length === 0) {
|
|
142
|
+
return {
|
|
143
|
+
exito: false,
|
|
144
|
+
error: 'No se detectaron instalaciones SWL en este equipo.',
|
|
145
|
+
sugerencia: 'Ejecuta swl-ses install para crear una.',
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Loop: seleccionar una instalación → ver detalle → volver al listado.
|
|
150
|
+
// Esc en el listado sale del Inspect.
|
|
151
|
+
while (true) {
|
|
152
|
+
const items = instalaciones.map(i => ({
|
|
153
|
+
valor: i.id,
|
|
154
|
+
etiqueta: `${i.runtimeNombre} (${i.scope}) — v${i.version} · perfil ${i.perfil}`,
|
|
155
|
+
descripcion: `${i.componentes.length} componentes · ${i.archivos.length} archivos · ${i.ruta}`,
|
|
156
|
+
}));
|
|
157
|
+
|
|
158
|
+
const elegida = await selectorUnico({
|
|
159
|
+
titulo: 'Inspect — Elige una instalación para ver detalle:',
|
|
160
|
+
items,
|
|
161
|
+
});
|
|
162
|
+
if (!elegida) break;
|
|
163
|
+
|
|
164
|
+
const fila = instalaciones.find(i => i.id === elegida);
|
|
165
|
+
if (fila) await _pantallaDetalle(fila);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return { exito: true };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
module.exports = {
|
|
172
|
+
ejecutarInspect,
|
|
173
|
+
_cargarDatosInstalaciones,
|
|
174
|
+
_agruparPorCategoria,
|
|
175
|
+
};
|