@saulwade/swl-ses 2.4.3 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +1043 -52
- 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 +49 -56
- 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 +101 -0
- package/scripts/field-report.js +18 -2
- 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/instalar-git-hook.js +8 -1
- package/scripts/lib/configurar-ci.js +10 -3
- package/scripts/lib/diary-entry.js +3 -1
- package/scripts/lib/drift-detector.js +1 -1
- package/scripts/lib/evidencia-valor.js +228 -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/index.js +10 -1
- package/scripts/tui/pantallas/inspect.js +175 -175
- package/scripts/tui/pantallas/install-wizard.js +21 -8
- package/scripts/tui/pantallas/uninstall-wizard.js +210 -210
- package/scripts/tui/pantallas/update-wizard.js +234 -234
- package/scripts/tui/pantallas/welcome.js +188 -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, scopesReales, 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
|
+
};
|
|
@@ -170,7 +170,7 @@ function pantallaPreview(opciones, perfiles) {
|
|
|
170
170
|
render.escribirEn(3, 3, colores.dim('Revisa antes de confirmar:'));
|
|
171
171
|
|
|
172
172
|
const filas = [
|
|
173
|
-
['Runtime',
|
|
173
|
+
['Runtime(s)', (opciones.targets || [opciones.target]).join(', ')],
|
|
174
174
|
['Perfil', opciones.profile],
|
|
175
175
|
['Scope', opciones.global ? 'global (~/.claude)' : 'proyecto (./.claude)'],
|
|
176
176
|
['With MCP', opciones.with_mcp ? 'sí' : 'no'],
|
|
@@ -243,13 +243,25 @@ async function ejecutarWizardInstall() {
|
|
|
243
243
|
return { exito: false, error: 'No se pudo cargar manifiestos/perfiles.json' };
|
|
244
244
|
}
|
|
245
245
|
|
|
246
|
-
// 1. Runtime
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
246
|
+
// 1. Runtime(s) — multiselección: instala en varios runtimes en una corrida
|
|
247
|
+
// (fix 2026-07-09: era selector único; el flujo multi-runtime obligaba a
|
|
248
|
+
// repetir el wizard completo por cada runtime).
|
|
249
|
+
let targets = null;
|
|
250
|
+
let tituloPaso1 = 'Paso 1/6 — ¿En qué runtime(s) instalas SWL? (espacio para marcar)';
|
|
251
|
+
for (;;) {
|
|
252
|
+
targets = await selectorMulti({ titulo: tituloPaso1, items: RUNTIMES });
|
|
253
|
+
if (targets === null) return { exito: false, cancelado: true };
|
|
254
|
+
if (targets.length > 0) break;
|
|
255
|
+
// no-TTY: selectorMulti resuelve [] al instante — re-preguntar sería un
|
|
256
|
+
// spin infinito en caliente (colgó la suite 2.7h el 2026-07-09). Default:
|
|
257
|
+
// primer runtime, igual que hacía el selector único.
|
|
258
|
+
if (!render.ES_TTY || !process.stdin.isTTY) {
|
|
259
|
+
targets = [RUNTIMES[0].valor];
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
tituloPaso1 = 'Paso 1/6 — Marca AL MENOS un runtime con espacio (Esc para cancelar)';
|
|
263
|
+
}
|
|
264
|
+
const target = targets[0]; // compat: preview/ejecutores leen .target
|
|
253
265
|
|
|
254
266
|
// 2. Perfil
|
|
255
267
|
const profile = await selectorUnico({
|
|
@@ -287,6 +299,7 @@ async function ejecutarWizardInstall() {
|
|
|
287
299
|
|
|
288
300
|
const opciones = {
|
|
289
301
|
target,
|
|
302
|
+
targets,
|
|
290
303
|
profile,
|
|
291
304
|
global: scope === 'global',
|
|
292
305
|
with_mcp: flagsSeleccionados.includes('with-mcp'),
|