@saulwade/swl-ses 2.3.0 → 2.3.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 +47 -6
- package/README.md +1 -1
- 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 +472 -472
- 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 +479 -479
- package/agentes/backend-python-swl.md +605 -605
- 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 +605 -605
- 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 +2 -2
- package/agentes/implementador-swl.md +328 -328
- package/agentes/investigador-swl.md +432 -432
- package/agentes/investigador-ux-swl.md +505 -505
- package/agentes/llm-apps-swl.md +278 -278
- 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 +918 -918
- package/agentes/observabilidad-swl.md +438 -438
- package/agentes/orquestador-swl.md +1026 -1026
- 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 +1 -1
- package/agentes/release-manager-swl.md +590 -590
- package/agentes/rendimiento-swl.md +713 -713
- package/agentes/resolutor-build-swl.md +245 -245
- package/agentes/revisor-angular-swl.md +278 -278
- package/agentes/revisor-codigo-swl.md +505 -505
- 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 +291 -291
- package/agentes/tdd-qa-swl.md +393 -393
- package/comandos/swl/briefing.md +119 -119
- package/comandos/swl/contribuir.md +233 -233
- package/comandos/swl/predecir.md +139 -139
- package/comandos/swl/sesiones.md +1 -1
- package/gateway/agent-executor.js +1 -1
- package/gateway/lib/event-channel.js +191 -191
- package/habilidades/agent-deep-links/SKILL.md +148 -148
- package/habilidades/agentes-como-servicio/SKILL.md +2 -2
- package/habilidades/angular-moderno/SKILL.md +20 -1
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -276
- package/habilidades/backend-async-postgres-testing/SKILL.md +215 -215
- package/habilidades/backend-error-design/SKILL.md +221 -221
- package/habilidades/backend-production-resilience/SKILL.md +288 -288
- package/habilidades/benchmark-memoria/SKILL.md +186 -186
- package/habilidades/calidad-anti-patrones-universales/SKILL.md +368 -368
- package/habilidades/calidad-contract-testing/SKILL.md +165 -165
- package/habilidades/calidad-mutation-testing/SKILL.md +170 -170
- package/habilidades/changelog-generator/scripts/parse-commits.js +367 -367
- package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -60
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/drift-detection/SKILL.md +179 -179
- package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +1 -1
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -57
- package/habilidades/eval-framework/SKILL.md +212 -212
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
- package/habilidades/harness-claude-code/recursos/disciplina-harness-regla.md +252 -252
- package/habilidades/legacy-code-rescue/SKILL.md +267 -267
- package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
- package/habilidades/perfil-usuario/SKILL.md +200 -200
- package/habilidades/prevencion-sobreingenieria/recursos/EXAMPLES.md +580 -580
- package/habilidades/proceso-ddia-fundamentos/SKILL.md +255 -255
- package/habilidades/proceso-ddia-streaming/SKILL.md +231 -231
- package/habilidades/proceso-debate-adversarial/recursos/personas.md +105 -105
- package/habilidades/proceso-discovery-machote/SKILL.md +157 -157
- package/habilidades/proceso-dynamic-workflows/SKILL.md +138 -138
- package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -65
- package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -65
- package/habilidades/proceso-intent-engineering/SKILL.md +269 -269
- package/habilidades/proceso-modular-split/SKILL.md +256 -256
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +2 -2
- package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
- package/habilidades/structured-outputs/SKILL.md +2 -2
- package/habilidades/swl-claudemd/recursos/contrato-aprender.md +83 -83
- package/habilidades/swl-claudemd/recursos/duplicacion-reglas-globales.md +85 -85
- package/habilidades/swl-claudemd/recursos/plantillas-init.md +94 -94
- package/habilidades/swl-dashboard/SKILL.md +2 -2
- package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -111
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +1 -1
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +1 -1
- package/hooks/ciclo-evolucion-subagente.js +26 -26
- package/hooks/ciclo-evolucion.js +26 -26
- package/hooks/claudemd-bloat-detector.js +161 -161
- package/hooks/claudemd-duplicacion-detector.js +170 -170
- package/hooks/contexto-iteracion.js +144 -144
- package/hooks/guardrail-modelo.js +1 -1
- package/hooks/lib/agent-routing.js +107 -107
- package/hooks/lib/auto-consolidator.js +335 -335
- package/hooks/lib/autonomia.js +208 -208
- package/hooks/lib/ciclo-evolucion.js +47 -47
- package/hooks/lib/deep-links.js +185 -185
- package/hooks/lib/error-classifier.js +308 -308
- package/hooks/lib/etapa-auto-evolucion.js +701 -701
- package/hooks/lib/etapa-metricas.js +388 -388
- package/hooks/lib/etapa-perfil-usuario.js +376 -376
- package/hooks/lib/loop-telemetry.js +321 -321
- package/hooks/lib/merkle-audit.js +96 -96
- package/hooks/lib/model-router.js +2 -2
- package/hooks/lib/propose-step.js +358 -358
- package/hooks/lib/provenance-tracker.js +191 -191
- package/hooks/lib/rate-limit-tracker.js +253 -253
- package/hooks/lib/resource-quota.js +122 -122
- package/hooks/lib/retry-jitter.js +165 -165
- package/hooks/lib/security-net.js +201 -201
- package/hooks/lib/skill-auditor.js +588 -588
- package/hooks/lib/sync-status.js +228 -228
- package/hooks/lib/taint-tracker.js +107 -107
- package/hooks/lib/text-similarity.js +241 -241
- package/hooks/lib/token-estimator.js +1 -0
- package/hooks/lib/toon-compressor.js +245 -245
- package/hooks/lib/usage-model.js +1 -1
- package/hooks/linea-estado.js +2 -0
- package/hooks/registro-turnos.js +209 -209
- package/hooks/session-briefing.js +98 -98
- package/hooks/spec-gate.js +211 -211
- package/hooks/sugerir-regenerar-inventario.js +170 -170
- package/hooks/tdd-gate.js +241 -241
- package/hooks/telemetria-skill-routing.js +100 -100
- package/hooks/validar-formato-post-subagente.js +140 -140
- package/hooks/validar-intent-spec.js +242 -242
- package/hooks/validar-memoria-hook.js +218 -218
- package/hooks/validar-planning-paths.js +134 -134
- package/instintos/autonomia.yaml +27 -27
- package/instintos/prompt-appendices.yaml +57 -57
- package/llms.txt +29 -29
- package/manifiestos/agent-output-schemas.json +57 -57
- package/manifiestos/canonical-hashes.json +2291 -1964
- package/manifiestos/planning-paths.json +44 -44
- package/manifiestos/skills-lock.json +1282 -1282
- package/package.json +1 -1
- package/plantillas/auditor-veto-template.md +105 -105
- package/plantillas/github-workflows/README.md +47 -47
- package/plantillas/github-workflows/release-please.yml +44 -44
- package/plantillas/github-workflows/swl-ci.yml +107 -107
- package/plantillas/github-workflows/swl-security.yml +51 -51
- package/plugin.json +1 -1
- package/reglas/accesibilidad.md +10 -10
- package/reglas/analisis-previo-tareas-grandes.md +172 -172
- package/reglas/api-diseno.md +9 -9
- package/reglas/arreglar-al-detectar.md +240 -240
- package/reglas/auditorias-documentales-estructurales.md +7 -7
- package/reglas/cloud-infra.md +8 -8
- package/reglas/consultar-vault-primero.md +195 -195
- package/reglas/debatir-antes-de-aceptar.md +158 -158
- package/reglas/fragmentos-compartidos.md +183 -183
- package/reglas/hooks.md +6 -6
- package/reglas/intent-engineering.md +218 -218
- package/reglas/markitdown.md +8 -8
- package/reglas/monitor-ci.md +309 -309
- package/reglas/patrones.md +6 -6
- package/reglas/sesiones-paralelas.md +180 -180
- package/reglas/sin-duplicacion-reglas-globales.md +182 -182
- package/reglas/skills-estandar.md +6 -6
- package/reglas/testing.md +7 -7
- package/reglas/tests-cleanup.md +224 -224
- package/reglas/usar-code-review-graph.md +155 -155
- package/reglas/usar-context7.md +226 -226
- package/reglas/verificar-citas-normativas.md +548 -548
- package/schemas/agent-frontmatter.schema.json +3 -3
- package/schemas/agent-message.schema.json +73 -73
- package/schemas/agent-output-implementacion.schema.json +114 -114
- package/schemas/agent-output-planificacion.schema.json +150 -150
- package/schemas/agent-output-review.schema.json +98 -98
- package/schemas/diary-entry.schema.json +112 -112
- package/schemas/hook-profiles.schema.json +54 -54
- package/schemas/hooks-config.schema.json +89 -89
- package/schemas/modulos.schema.json +38 -38
- package/schemas/perfiles.schema.json +36 -36
- package/schemas/plugin.schema.json +77 -77
- package/schemas/skill-evals.schema.json +119 -119
- package/schemas/skill-frontmatter.schema.json +245 -245
- package/scripts/audit-tools/audit-history.js +330 -330
- package/scripts/audit-tools/bundle-tracker.js +290 -290
- package/scripts/audit-tools/canary-monitor.js +352 -352
- package/scripts/audit-tools/code-profiler.js +605 -605
- package/scripts/audit-tools/dep-doctor.js +320 -320
- package/scripts/audit-tools/env-validator.js +206 -206
- package/scripts/audit-tools/lib/fs-walk.js +48 -48
- package/scripts/audit-tools/lib/output.js +23 -23
- package/scripts/audit-tools/migration-checker.js +392 -392
- package/scripts/audit-tools/pentest-scanner.js +1436 -1436
- package/scripts/benchmark-memoria.js +167 -167
- package/scripts/cli/aprobar-plan.js +73 -73
- package/scripts/cli/briefing.js +23 -23
- package/scripts/cli/ciclo-evolucion.js +26 -26
- package/scripts/cli/configurar-ci.js +40 -40
- package/scripts/cli/derivar-feature-list.js +25 -25
- package/scripts/cli/detectar-host.js +27 -27
- package/scripts/cli/diary-entry.js +69 -69
- package/scripts/cli/execution-state.js +18 -18
- package/scripts/cli/gateway-notify.js +41 -41
- package/scripts/cli/liberar-fase.js +42 -42
- package/scripts/cli/loop-telemetry.js +125 -125
- package/scripts/cli/mark-evolved.js +56 -56
- package/scripts/cli/metricas-dora.js +26 -26
- package/scripts/cli/near-duplicate.js +55 -55
- package/scripts/cli/notificaciones.js +123 -123
- package/scripts/cli/propose-step.js +29 -29
- package/scripts/cli/schedule-parse.js +19 -19
- package/scripts/cli/sugerir-modelo.js +20 -20
- package/scripts/cli/verificar-plan.js +36 -36
- package/scripts/cli/verificar-trazabilidad.js +35 -35
- package/scripts/configurar-branch-protection.js +418 -418
- package/scripts/detectar-aprendizajes-duplicados.js +151 -151
- package/scripts/field-report.js +199 -199
- package/scripts/generar-checklists-consolidados.js +273 -273
- package/scripts/generar-matriz-lenguajes.js +271 -271
- package/scripts/lib/artefactos-python.js +43 -43
- package/scripts/lib/auditar-invocaciones-comandos.js +104 -104
- package/scripts/lib/benchmark-metrics.js +160 -160
- package/scripts/lib/budget-enforcer.js +252 -252
- package/scripts/lib/ci-reader.js +193 -193
- package/scripts/lib/claude-sessions.js +1 -0
- package/scripts/lib/configurar-ci.js +380 -380
- package/scripts/lib/contadores-inventario.js +217 -217
- package/scripts/lib/detectar-host-swl.js +175 -175
- package/scripts/lib/detectar-stack-detallado.js +307 -307
- package/scripts/lib/detector-autoduplicacion-intra-archivo.js +234 -234
- package/scripts/lib/detector-reglas-duplicadas.js +220 -220
- package/scripts/lib/diary-entry.js +234 -234
- package/scripts/lib/eval-metrics-store.js +218 -218
- package/scripts/lib/eval-quality.js +171 -171
- package/scripts/lib/eval-schemas.js +144 -144
- package/scripts/lib/eval-self-correct.js +106 -106
- package/scripts/lib/eval-validator.js +185 -185
- package/scripts/lib/evidencia-release.js +322 -322
- package/scripts/lib/expandir-targets.js +71 -71
- package/scripts/lib/gate-hooks-requires.js +249 -249
- package/scripts/lib/gate-licencias.js +212 -212
- package/scripts/lib/git-metricas.js +257 -257
- package/scripts/lib/jaccard-similarity.js +98 -98
- package/scripts/lib/longmemeval-runner.js +125 -125
- package/scripts/lib/metricas-dora.js +204 -204
- package/scripts/lib/npm-version.js +261 -261
- package/scripts/lib/paquetes-conocidos.js +50 -50
- package/scripts/lib/plan-lock.js +275 -275
- package/scripts/lib/pr-analyzer.js +399 -399
- package/scripts/lib/prompt-builder.js +264 -264
- package/scripts/lib/reglas-globales-conocidas.json +180 -180
- package/scripts/lib/resolver-plan-fase.js +37 -37
- package/scripts/lib/rrf-fusion.js +175 -175
- package/scripts/lib/schema-version.js +164 -164
- package/scripts/lib/scoring-instintos.js +277 -277
- package/scripts/lib/semantic-search.js +252 -252
- package/scripts/lib/toml-merge.js +204 -204
- package/scripts/lib/tool-cost-analyzer.js +1 -0
- package/scripts/limpiar-artefactos-python.js +131 -131
- package/scripts/mcp-server/auth.js +105 -105
- package/scripts/mcp-server/cache.js +106 -106
- package/scripts/migrar-csv-a-array.js +168 -168
- package/scripts/migrar-fase-dominio.js +200 -200
- package/scripts/publicar.js +497 -497
- package/scripts/run-eval.js +141 -141
- package/scripts/tui/componentes/selector-multi.js +189 -189
- package/scripts/tui/componentes/selector-unico.js +158 -158
- package/scripts/tui/ejecutores.js +375 -375
- package/scripts/tui/index.js +162 -162
- package/scripts/tui/lib/colores.js +129 -129
- package/scripts/tui/lib/render.js +264 -264
- package/scripts/tui/lib/teclas.js +113 -113
- package/scripts/tui/pantallas/inspect.js +173 -173
- package/scripts/tui/pantallas/install-wizard.js +334 -334
- package/scripts/tui/pantallas/menu-principal.js +52 -52
- package/scripts/tui/pantallas/progreso.js +274 -274
- package/scripts/tui/pantallas/resumen.js +132 -132
- package/scripts/tui/pantallas/uninstall-wizard.js +208 -208
- package/scripts/tui/pantallas/update-wizard.js +232 -232
- package/scripts/tui/pantallas/welcome.js +187 -187
- package/scripts/validar-userland-vacio.js +110 -110
|
@@ -1,113 +1,113 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Handler unificado de keypress para la TUI de swl-ses.
|
|
5
|
-
* Zero-deps. Usa readline.emitKeypressEvents para parsear secuencias ANSI.
|
|
6
|
-
*
|
|
7
|
-
* Modelo de uso:
|
|
8
|
-
*
|
|
9
|
-
* const teclado = crearTeclado();
|
|
10
|
-
* teclado.on('up', () => cursor--);
|
|
11
|
-
* teclado.on('down', () => cursor++);
|
|
12
|
-
* teclado.on('return', () => resolver());
|
|
13
|
-
* teclado.on('escape', () => cancelar());
|
|
14
|
-
* teclado.activar();
|
|
15
|
-
* // ... eventualmente
|
|
16
|
-
* teclado.desactivar();
|
|
17
|
-
*
|
|
18
|
-
* Maneja:
|
|
19
|
-
* - Flechas (up/down/left/right)
|
|
20
|
-
* - vim-keys (h/j/k/l) opcional
|
|
21
|
-
* - Espacio, return, escape, tab
|
|
22
|
-
* - Ctrl+C (re-emite como 'escape' por default; se puede sobrescribir)
|
|
23
|
-
* - Teclas alfanuméricas como caracteres (con `keypress` evento)
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
const readline = require('readline');
|
|
27
|
-
|
|
28
|
-
function crearTeclado(opciones = {}) {
|
|
29
|
-
const aliasVim = opciones.vim !== false; // por default soporta h/j/k/l
|
|
30
|
-
const handlers = new Map();
|
|
31
|
-
let activo = false;
|
|
32
|
-
let modoAnterior = null;
|
|
33
|
-
|
|
34
|
-
function _resolverNombre(key, str) {
|
|
35
|
-
if (!key) return null;
|
|
36
|
-
if (key.ctrl && key.name === 'c') return 'escape'; // Ctrl+C → escape
|
|
37
|
-
if (key.name) return key.name;
|
|
38
|
-
return null;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function onKeypress(str, key) {
|
|
42
|
-
if (!activo) return;
|
|
43
|
-
|
|
44
|
-
const nombre = _resolverNombre(key, str);
|
|
45
|
-
if (!nombre) return;
|
|
46
|
-
|
|
47
|
-
// Alias vim
|
|
48
|
-
let normalizado = nombre;
|
|
49
|
-
if (aliasVim) {
|
|
50
|
-
if (nombre === 'k') normalizado = 'up';
|
|
51
|
-
else if (nombre === 'j') normalizado = 'down';
|
|
52
|
-
else if (nombre === 'h') normalizado = 'left';
|
|
53
|
-
else if (nombre === 'l') normalizado = 'right';
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Disparar handlers exactos
|
|
57
|
-
if (handlers.has(normalizado)) {
|
|
58
|
-
handlers.get(normalizado).forEach(fn => fn(key, str));
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Handler genérico para cualquier tecla
|
|
62
|
-
if (handlers.has('*')) {
|
|
63
|
-
handlers.get('*').forEach(fn => fn(nombre, str, key));
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function activar() {
|
|
68
|
-
if (activo) return;
|
|
69
|
-
if (!process.stdin.isTTY) {
|
|
70
|
-
// No-TTY: no podemos leer teclas. El llamador debe manejar este caso.
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
activo = true;
|
|
74
|
-
readline.emitKeypressEvents(process.stdin);
|
|
75
|
-
modoAnterior = process.stdin.isRaw;
|
|
76
|
-
process.stdin.setRawMode(true);
|
|
77
|
-
process.stdin.resume();
|
|
78
|
-
process.stdin.on('keypress', onKeypress);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function desactivar() {
|
|
82
|
-
if (!activo) return;
|
|
83
|
-
activo = false;
|
|
84
|
-
if (process.stdin.isTTY) {
|
|
85
|
-
process.stdin.removeListener('keypress', onKeypress);
|
|
86
|
-
process.stdin.setRawMode(modoAnterior || false);
|
|
87
|
-
process.stdin.pause();
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function on(tecla, handler) {
|
|
92
|
-
if (!handlers.has(tecla)) handlers.set(tecla, []);
|
|
93
|
-
handlers.get(tecla).push(handler);
|
|
94
|
-
return api;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function off(tecla, handler) {
|
|
98
|
-
if (!handlers.has(tecla)) return api;
|
|
99
|
-
if (!handler) {
|
|
100
|
-
handlers.delete(tecla);
|
|
101
|
-
return api;
|
|
102
|
-
}
|
|
103
|
-
const arr = handlers.get(tecla).filter(h => h !== handler);
|
|
104
|
-
if (arr.length === 0) handlers.delete(tecla);
|
|
105
|
-
else handlers.set(tecla, arr);
|
|
106
|
-
return api;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
const api = { activar, desactivar, on, off, estaActivo: () => activo };
|
|
110
|
-
return api;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
module.exports = { crearTeclado };
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handler unificado de keypress para la TUI de swl-ses.
|
|
5
|
+
* Zero-deps. Usa readline.emitKeypressEvents para parsear secuencias ANSI.
|
|
6
|
+
*
|
|
7
|
+
* Modelo de uso:
|
|
8
|
+
*
|
|
9
|
+
* const teclado = crearTeclado();
|
|
10
|
+
* teclado.on('up', () => cursor--);
|
|
11
|
+
* teclado.on('down', () => cursor++);
|
|
12
|
+
* teclado.on('return', () => resolver());
|
|
13
|
+
* teclado.on('escape', () => cancelar());
|
|
14
|
+
* teclado.activar();
|
|
15
|
+
* // ... eventualmente
|
|
16
|
+
* teclado.desactivar();
|
|
17
|
+
*
|
|
18
|
+
* Maneja:
|
|
19
|
+
* - Flechas (up/down/left/right)
|
|
20
|
+
* - vim-keys (h/j/k/l) opcional
|
|
21
|
+
* - Espacio, return, escape, tab
|
|
22
|
+
* - Ctrl+C (re-emite como 'escape' por default; se puede sobrescribir)
|
|
23
|
+
* - Teclas alfanuméricas como caracteres (con `keypress` evento)
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const readline = require('readline');
|
|
27
|
+
|
|
28
|
+
function crearTeclado(opciones = {}) {
|
|
29
|
+
const aliasVim = opciones.vim !== false; // por default soporta h/j/k/l
|
|
30
|
+
const handlers = new Map();
|
|
31
|
+
let activo = false;
|
|
32
|
+
let modoAnterior = null;
|
|
33
|
+
|
|
34
|
+
function _resolverNombre(key, str) {
|
|
35
|
+
if (!key) return null;
|
|
36
|
+
if (key.ctrl && key.name === 'c') return 'escape'; // Ctrl+C → escape
|
|
37
|
+
if (key.name) return key.name;
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function onKeypress(str, key) {
|
|
42
|
+
if (!activo) return;
|
|
43
|
+
|
|
44
|
+
const nombre = _resolverNombre(key, str);
|
|
45
|
+
if (!nombre) return;
|
|
46
|
+
|
|
47
|
+
// Alias vim
|
|
48
|
+
let normalizado = nombre;
|
|
49
|
+
if (aliasVim) {
|
|
50
|
+
if (nombre === 'k') normalizado = 'up';
|
|
51
|
+
else if (nombre === 'j') normalizado = 'down';
|
|
52
|
+
else if (nombre === 'h') normalizado = 'left';
|
|
53
|
+
else if (nombre === 'l') normalizado = 'right';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Disparar handlers exactos
|
|
57
|
+
if (handlers.has(normalizado)) {
|
|
58
|
+
handlers.get(normalizado).forEach(fn => fn(key, str));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Handler genérico para cualquier tecla
|
|
62
|
+
if (handlers.has('*')) {
|
|
63
|
+
handlers.get('*').forEach(fn => fn(nombre, str, key));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function activar() {
|
|
68
|
+
if (activo) return;
|
|
69
|
+
if (!process.stdin.isTTY) {
|
|
70
|
+
// No-TTY: no podemos leer teclas. El llamador debe manejar este caso.
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
activo = true;
|
|
74
|
+
readline.emitKeypressEvents(process.stdin);
|
|
75
|
+
modoAnterior = process.stdin.isRaw;
|
|
76
|
+
process.stdin.setRawMode(true);
|
|
77
|
+
process.stdin.resume();
|
|
78
|
+
process.stdin.on('keypress', onKeypress);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function desactivar() {
|
|
82
|
+
if (!activo) return;
|
|
83
|
+
activo = false;
|
|
84
|
+
if (process.stdin.isTTY) {
|
|
85
|
+
process.stdin.removeListener('keypress', onKeypress);
|
|
86
|
+
process.stdin.setRawMode(modoAnterior || false);
|
|
87
|
+
process.stdin.pause();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function on(tecla, handler) {
|
|
92
|
+
if (!handlers.has(tecla)) handlers.set(tecla, []);
|
|
93
|
+
handlers.get(tecla).push(handler);
|
|
94
|
+
return api;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function off(tecla, handler) {
|
|
98
|
+
if (!handlers.has(tecla)) return api;
|
|
99
|
+
if (!handler) {
|
|
100
|
+
handlers.delete(tecla);
|
|
101
|
+
return api;
|
|
102
|
+
}
|
|
103
|
+
const arr = handlers.get(tecla).filter(h => h !== handler);
|
|
104
|
+
if (arr.length === 0) handlers.delete(tecla);
|
|
105
|
+
else handlers.set(tecla, arr);
|
|
106
|
+
return api;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const api = { activar, desactivar, on, off, estaActivo: () => activo };
|
|
110
|
+
return api;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = { crearTeclado };
|
|
@@ -1,173 +1,173 @@
|
|
|
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 } = 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
|
-
const candidatos = [
|
|
38
|
-
{ ruta: runtime.global, scope: 'global' },
|
|
39
|
-
{ ruta: path.resolve(runtime.local), scope: 'proyecto' },
|
|
40
|
-
];
|
|
41
|
-
for (const { ruta, scope } of candidatos) {
|
|
42
|
-
if (!fs.existsSync(ruta)) continue;
|
|
43
|
-
const estado = cargarEstado(ruta);
|
|
44
|
-
if (!estado) continue;
|
|
45
|
-
filas.push({
|
|
46
|
-
id: `${runtime.id}:${scope}`,
|
|
47
|
-
runtimeId: runtime.id,
|
|
48
|
-
runtimeNombre: runtime.nombre,
|
|
49
|
-
scope,
|
|
50
|
-
ruta,
|
|
51
|
-
version: estado.versionSistema || 'desconocida',
|
|
52
|
-
perfil: estado.perfil || '-',
|
|
53
|
-
instalado: estado.fechaInstalacion || estado.timestamp || '-',
|
|
54
|
-
componentes: estado.componentesInstalados || [],
|
|
55
|
-
archivos: estado.archivosInstalados || [],
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return filas;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function _agruparPorCategoria(archivos) {
|
|
63
|
-
const grupos = {};
|
|
64
|
-
for (const a of archivos) {
|
|
65
|
-
const cat = a.tipo || a.categoria || 'otros';
|
|
66
|
-
grupos[cat] = (grupos[cat] || 0) + 1;
|
|
67
|
-
}
|
|
68
|
-
return grupos;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function _pantallaDetalle(fila) {
|
|
72
|
-
return new Promise((resolve) => {
|
|
73
|
-
if (!render.ES_TTY || !process.stdin.isTTY) {
|
|
74
|
-
resolve();
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function _renderizar() {
|
|
79
|
-
render.limpiarPantalla();
|
|
80
|
-
const { cols, rows } = render.obtenerDimensiones();
|
|
81
|
-
|
|
82
|
-
render.escribirEn(2, 3, semantico.titulo(`${fila.runtimeNombre} — ${fila.scope}`));
|
|
83
|
-
render.escribirEn(3, 3, colores.dim(fila.ruta));
|
|
84
|
-
|
|
85
|
-
const datos = [
|
|
86
|
-
['Versión', colores.cyan('v' + fila.version)],
|
|
87
|
-
['Perfil', semantico.enfasis(fila.perfil)],
|
|
88
|
-
['Instalado', fila.instalado],
|
|
89
|
-
['Total componentes', String(fila.componentes.length)],
|
|
90
|
-
['Total archivos', String(fila.archivos.length)],
|
|
91
|
-
];
|
|
92
|
-
|
|
93
|
-
datos.forEach((d, i) => {
|
|
94
|
-
render.escribirEn(5 + i, 5,
|
|
95
|
-
render.rellenarDer(colores.dim(d[0] + ':'), 22) + d[1]);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// Conteos por categoría
|
|
99
|
-
const grupos = _agruparPorCategoria(fila.archivos);
|
|
100
|
-
const categorias = Object.entries(grupos).sort(([a], [b]) => a.localeCompare(b));
|
|
101
|
-
|
|
102
|
-
const filaCat = 5 + datos.length + 2;
|
|
103
|
-
render.escribirEn(filaCat, 3, semantico.enfasis('Archivos por categoría:'));
|
|
104
|
-
categorias.forEach(([cat, n], i) => {
|
|
105
|
-
const fila = filaCat + 1 + i;
|
|
106
|
-
if (fila >= rows - 3) return;
|
|
107
|
-
render.escribirEn(fila, 5,
|
|
108
|
-
render.rellenarDer(`${iconos.punto} ${cat}`, 22) +
|
|
109
|
-
colores.cyan(String(n).padStart(4)));
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
render.dibujarPiePagina([
|
|
113
|
-
['Enter|Esc', 'volver al listado'],
|
|
114
|
-
]);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
render.iniciarModoTui();
|
|
118
|
-
_renderizar();
|
|
119
|
-
|
|
120
|
-
const onResize = () => _renderizar();
|
|
121
|
-
process.stdout.on('resize', onResize);
|
|
122
|
-
|
|
123
|
-
const teclado = teclas.crearTeclado();
|
|
124
|
-
function _finalizar() {
|
|
125
|
-
teclado.desactivar();
|
|
126
|
-
process.stdout.removeListener('resize', onResize);
|
|
127
|
-
render.salirModoTui();
|
|
128
|
-
resolve();
|
|
129
|
-
}
|
|
130
|
-
teclado.on('return', _finalizar);
|
|
131
|
-
teclado.on('escape', _finalizar);
|
|
132
|
-
teclado.activar();
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async function ejecutarInspect() {
|
|
137
|
-
const instalaciones = _cargarDatosInstalaciones();
|
|
138
|
-
|
|
139
|
-
if (instalaciones.length === 0) {
|
|
140
|
-
return {
|
|
141
|
-
exito: false,
|
|
142
|
-
error: 'No se detectaron instalaciones SWL en este equipo.',
|
|
143
|
-
sugerencia: 'Ejecuta swl-ses install para crear una.',
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Loop: seleccionar una instalación → ver detalle → volver al listado.
|
|
148
|
-
// Esc en el listado sale del Inspect.
|
|
149
|
-
while (true) {
|
|
150
|
-
const items = instalaciones.map(i => ({
|
|
151
|
-
valor: i.id,
|
|
152
|
-
etiqueta: `${i.runtimeNombre} (${i.scope}) — v${i.version} · perfil ${i.perfil}`,
|
|
153
|
-
descripcion: `${i.componentes.length} componentes · ${i.archivos.length} archivos · ${i.ruta}`,
|
|
154
|
-
}));
|
|
155
|
-
|
|
156
|
-
const elegida = await selectorUnico({
|
|
157
|
-
titulo: 'Inspect — Elige una instalación para ver detalle:',
|
|
158
|
-
items,
|
|
159
|
-
});
|
|
160
|
-
if (!elegida) break;
|
|
161
|
-
|
|
162
|
-
const fila = instalaciones.find(i => i.id === elegida);
|
|
163
|
-
if (fila) await _pantallaDetalle(fila);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
return { exito: true };
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
module.exports = {
|
|
170
|
-
ejecutarInspect,
|
|
171
|
-
_cargarDatosInstalaciones,
|
|
172
|
-
_agruparPorCategoria,
|
|
173
|
-
};
|
|
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 } = 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
|
+
const candidatos = [
|
|
38
|
+
{ ruta: runtime.global, scope: 'global' },
|
|
39
|
+
{ ruta: path.resolve(runtime.local), scope: 'proyecto' },
|
|
40
|
+
];
|
|
41
|
+
for (const { ruta, scope } of candidatos) {
|
|
42
|
+
if (!fs.existsSync(ruta)) continue;
|
|
43
|
+
const estado = cargarEstado(ruta);
|
|
44
|
+
if (!estado) continue;
|
|
45
|
+
filas.push({
|
|
46
|
+
id: `${runtime.id}:${scope}`,
|
|
47
|
+
runtimeId: runtime.id,
|
|
48
|
+
runtimeNombre: runtime.nombre,
|
|
49
|
+
scope,
|
|
50
|
+
ruta,
|
|
51
|
+
version: estado.versionSistema || 'desconocida',
|
|
52
|
+
perfil: estado.perfil || '-',
|
|
53
|
+
instalado: estado.fechaInstalacion || estado.timestamp || '-',
|
|
54
|
+
componentes: estado.componentesInstalados || [],
|
|
55
|
+
archivos: estado.archivosInstalados || [],
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return filas;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function _agruparPorCategoria(archivos) {
|
|
63
|
+
const grupos = {};
|
|
64
|
+
for (const a of archivos) {
|
|
65
|
+
const cat = a.tipo || a.categoria || 'otros';
|
|
66
|
+
grupos[cat] = (grupos[cat] || 0) + 1;
|
|
67
|
+
}
|
|
68
|
+
return grupos;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function _pantallaDetalle(fila) {
|
|
72
|
+
return new Promise((resolve) => {
|
|
73
|
+
if (!render.ES_TTY || !process.stdin.isTTY) {
|
|
74
|
+
resolve();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function _renderizar() {
|
|
79
|
+
render.limpiarPantalla();
|
|
80
|
+
const { cols, rows } = render.obtenerDimensiones();
|
|
81
|
+
|
|
82
|
+
render.escribirEn(2, 3, semantico.titulo(`${fila.runtimeNombre} — ${fila.scope}`));
|
|
83
|
+
render.escribirEn(3, 3, colores.dim(fila.ruta));
|
|
84
|
+
|
|
85
|
+
const datos = [
|
|
86
|
+
['Versión', colores.cyan('v' + fila.version)],
|
|
87
|
+
['Perfil', semantico.enfasis(fila.perfil)],
|
|
88
|
+
['Instalado', fila.instalado],
|
|
89
|
+
['Total componentes', String(fila.componentes.length)],
|
|
90
|
+
['Total archivos', String(fila.archivos.length)],
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
datos.forEach((d, i) => {
|
|
94
|
+
render.escribirEn(5 + i, 5,
|
|
95
|
+
render.rellenarDer(colores.dim(d[0] + ':'), 22) + d[1]);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Conteos por categoría
|
|
99
|
+
const grupos = _agruparPorCategoria(fila.archivos);
|
|
100
|
+
const categorias = Object.entries(grupos).sort(([a], [b]) => a.localeCompare(b));
|
|
101
|
+
|
|
102
|
+
const filaCat = 5 + datos.length + 2;
|
|
103
|
+
render.escribirEn(filaCat, 3, semantico.enfasis('Archivos por categoría:'));
|
|
104
|
+
categorias.forEach(([cat, n], i) => {
|
|
105
|
+
const fila = filaCat + 1 + i;
|
|
106
|
+
if (fila >= rows - 3) return;
|
|
107
|
+
render.escribirEn(fila, 5,
|
|
108
|
+
render.rellenarDer(`${iconos.punto} ${cat}`, 22) +
|
|
109
|
+
colores.cyan(String(n).padStart(4)));
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
render.dibujarPiePagina([
|
|
113
|
+
['Enter|Esc', 'volver al listado'],
|
|
114
|
+
]);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
render.iniciarModoTui();
|
|
118
|
+
_renderizar();
|
|
119
|
+
|
|
120
|
+
const onResize = () => _renderizar();
|
|
121
|
+
process.stdout.on('resize', onResize);
|
|
122
|
+
|
|
123
|
+
const teclado = teclas.crearTeclado();
|
|
124
|
+
function _finalizar() {
|
|
125
|
+
teclado.desactivar();
|
|
126
|
+
process.stdout.removeListener('resize', onResize);
|
|
127
|
+
render.salirModoTui();
|
|
128
|
+
resolve();
|
|
129
|
+
}
|
|
130
|
+
teclado.on('return', _finalizar);
|
|
131
|
+
teclado.on('escape', _finalizar);
|
|
132
|
+
teclado.activar();
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
async function ejecutarInspect() {
|
|
137
|
+
const instalaciones = _cargarDatosInstalaciones();
|
|
138
|
+
|
|
139
|
+
if (instalaciones.length === 0) {
|
|
140
|
+
return {
|
|
141
|
+
exito: false,
|
|
142
|
+
error: 'No se detectaron instalaciones SWL en este equipo.',
|
|
143
|
+
sugerencia: 'Ejecuta swl-ses install para crear una.',
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Loop: seleccionar una instalación → ver detalle → volver al listado.
|
|
148
|
+
// Esc en el listado sale del Inspect.
|
|
149
|
+
while (true) {
|
|
150
|
+
const items = instalaciones.map(i => ({
|
|
151
|
+
valor: i.id,
|
|
152
|
+
etiqueta: `${i.runtimeNombre} (${i.scope}) — v${i.version} · perfil ${i.perfil}`,
|
|
153
|
+
descripcion: `${i.componentes.length} componentes · ${i.archivos.length} archivos · ${i.ruta}`,
|
|
154
|
+
}));
|
|
155
|
+
|
|
156
|
+
const elegida = await selectorUnico({
|
|
157
|
+
titulo: 'Inspect — Elige una instalación para ver detalle:',
|
|
158
|
+
items,
|
|
159
|
+
});
|
|
160
|
+
if (!elegida) break;
|
|
161
|
+
|
|
162
|
+
const fila = instalaciones.find(i => i.id === elegida);
|
|
163
|
+
if (fila) await _pantallaDetalle(fila);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return { exito: true };
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
module.exports = {
|
|
170
|
+
ejecutarInspect,
|
|
171
|
+
_cargarDatosInstalaciones,
|
|
172
|
+
_agruparPorCategoria,
|
|
173
|
+
};
|