@saulwade/swl-ses 1.5.2 → 1.6.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.
Files changed (64) hide show
  1. package/CLAUDE.md +32 -61
  2. package/README.md +20 -3
  3. package/agentes/datos-swl.md +1 -1
  4. package/agentes/frontend-angular-swl.md +7 -7
  5. package/agentes/frontend-css-swl.md +4 -4
  6. package/agentes/frontend-react-swl.md +7 -7
  7. package/agentes/frontend-swl.md +9 -9
  8. package/agentes/frontend-tailwind-swl.md +4 -4
  9. package/agentes/rendimiento-swl.md +2 -2
  10. package/bin/swl-ses.js +49 -7
  11. package/comandos/swl/brainstorm.md +1 -0
  12. package/comandos/swl/compactar.md +1 -1
  13. package/comandos/swl/discutir-fase.md +15 -1
  14. package/comandos/swl/mapear-codebase.md +1 -1
  15. package/comandos/swl/nemesis.md +29 -0
  16. package/comandos/swl/planear-fase.md +2 -2
  17. package/comandos/swl/verificar.md +4 -4
  18. package/habilidades/aprendizaje-continuo/SKILL.md +7 -1
  19. package/habilidades/diseno-herramientas-agente/SKILL.md +1 -0
  20. package/habilidades/doc-sync/SKILL.md +441 -1
  21. package/habilidades/doubt-driven-review/SKILL.md +177 -171
  22. package/habilidades/feynman-auditor-swl/SKILL.md +129 -123
  23. package/habilidades/infra-github-actions/SKILL.md +172 -166
  24. package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -163
  25. package/habilidades/nemesis-evaluacion-json/SKILL.md +5 -0
  26. package/habilidades/nemesis-redistribuir/SKILL.md +5 -0
  27. package/habilidades/node-experto/SKILL.md +197 -3
  28. package/habilidades/prevencion-racionalizacion/SKILL.md +1 -0
  29. package/habilidades/privacy-memoria/SKILL.md +1 -0
  30. package/habilidades/sre-patrones/SKILL.md +1 -1
  31. package/habilidades/state-inconsistency-auditor-swl/SKILL.md +172 -166
  32. package/habilidades/tdd-workflow/SKILL.md +178 -3
  33. package/habilidades/verificacion-evidencia/SKILL.md +1 -0
  34. package/habilidades/web-fetcher-routing/SKILL.md +81 -75
  35. package/habilidades/workflow-claude-code/SKILL.md +2 -2
  36. package/hooks/extraccion-aprendizajes.js +11 -0
  37. package/manifiestos/modulos.json +2 -1
  38. package/manifiestos/skills-lock.json +1142 -1114
  39. package/package.json +7 -4
  40. package/plugin.json +4 -2
  41. package/reglas/auditorias-documentales-estructurales.md +205 -0
  42. package/schemas/agent-frontmatter.schema.json +1 -1
  43. package/scripts/desinstalar.js +105 -24
  44. package/scripts/generar-inventario.js +450 -420
  45. package/scripts/instalador.js +55 -4
  46. package/scripts/lib/parsear-opciones.js +3 -0
  47. package/scripts/lib/ui.js +148 -22
  48. package/scripts/tui/componentes/selector-multi.js +189 -0
  49. package/scripts/tui/componentes/selector-unico.js +158 -0
  50. package/scripts/tui/ejecutores.js +375 -0
  51. package/scripts/tui/index.js +162 -0
  52. package/scripts/tui/lib/colores.js +129 -0
  53. package/scripts/tui/lib/render.js +264 -0
  54. package/scripts/tui/lib/teclas.js +113 -0
  55. package/scripts/tui/pantallas/inspect.js +173 -0
  56. package/scripts/tui/pantallas/install-wizard.js +334 -0
  57. package/scripts/tui/pantallas/menu-principal.js +52 -0
  58. package/scripts/tui/pantallas/progreso.js +274 -0
  59. package/scripts/tui/pantallas/resumen.js +132 -0
  60. package/scripts/tui/pantallas/uninstall-wizard.js +208 -0
  61. package/scripts/tui/pantallas/update-wizard.js +232 -0
  62. package/scripts/tui/pantallas/welcome.js +187 -0
  63. package/scripts/verificar-docs-vs-codigo.js +654 -0
  64. package/scripts/verificar-evolucion.js +19 -3
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@saulwade/swl-ses",
3
- "version": "1.5.2",
4
- "description": "Sistema de ingenieria de software auto-evolutivo multi-runtime polyglot con 60 agentes, 162 habilidades, 44 comandos, 66 reglas y 41 hooks. Soporta 11 lenguajes y 7 runtimes: Claude Code, OpenClaude, OpenCode, Gemini CLI, Cursor, Codex CLI (soporte completo); GitHub Copilot (soporte parcial). 100% en espanol (Mexico). Multi-target install (--target CSV / --all-runtimes), autoconfig MCP en Cursor/Codex con --with-mcp, agentes Codex en TOML, hooks Cursor (17 eventos) y Codex (6 eventos). Gateway bidireccional con relay Telegram y auditoria profunda Nemesis con loop evaluator-optimizer opt-in (ADR-0021) y 8 tools ejecutables.",
3
+ "version": "1.6.1",
4
+ "description": "Sistema de ingenieria de software auto-evolutivo multi-runtime polyglot con 60 agentes, 162 habilidades, 44 comandos, 67 reglas y 41 hooks. Soporta 11 lenguajes y 7 runtimes: Claude Code, OpenClaude, OpenCode, Gemini CLI, Cursor, Codex CLI (soporte completo); GitHub Copilot (soporte parcial). 100% en espanol (Mexico). Multi-target install (--target CSV / --all-runtimes), autoconfig MCP en Cursor/Codex con --with-mcp, agentes Codex en TOML, hooks Cursor (17 eventos) y Codex (6 eventos). Gateway bidireccional con relay Telegram y auditoria profunda Nemesis con loop evaluator-optimizer opt-in (ADR-0021) y 8 tools ejecutables. v1.6.1 endurece el verificador docs-vs-codigo con gates de profundidad (Check #2 + #6 + #7 + #8 nuevos) y formaliza el protocolo proactivo de propagacion (doc-sync v1.3.0) — ADR-0023.",
5
5
  "bin": {
6
6
  "swl-ses": "bin/swl-ses.js",
7
7
  "swl-telegram-bot": "bin/swl-telegram-bot.js",
@@ -28,12 +28,13 @@
28
28
  ],
29
29
  "scripts": {
30
30
  "postinstall": "echo '\n swl-software-engineering-system instalado.\n Ejecuta: npx swl-ses init\n'",
31
- "test": "node --test tests/lib/*.test.js tests/scripts/*.test.js tests/scripts/lib/*.test.js tests/hooks/*.test.js tests/gateway/*.test.js tests/bin/*.test.js tests/transformadores/*.test.js tests/mcp-server/*.test.js",
31
+ "test": "node --test tests/lib/*.test.js tests/scripts/*.test.js tests/scripts/lib/*.test.js tests/scripts/tui/*.test.js tests/hooks/*.test.js tests/gateway/*.test.js tests/bin/*.test.js tests/transformadores/*.test.js tests/mcp-server/*.test.js",
32
32
  "test:validate": "node scripts/validar.js",
33
33
  "test:manifest": "node scripts/validar-manifest.js",
34
+ "test:docs": "node scripts/verificar-docs-vs-codigo.js",
34
35
  "test:smoke": "node scripts/smoke-test.js",
35
36
  "test:aislamiento": "node scripts/validar-tests-aislamiento.js",
36
- "test:all": "npm test && node scripts/validar.js && node scripts/validar-manifest.js",
37
+ "test:all": "npm test && node scripts/validar.js && node scripts/validar-manifest.js && node scripts/verificar-docs-vs-codigo.js && node scripts/derivar-feature-list.js --check",
37
38
  "test:userland": "node scripts/validar-userland-vacio.js",
38
39
  "test:release": "npm run test:all && npm run test:userland && npm run test:smoke",
39
40
  "doctor": "node scripts/doctor.js",
@@ -46,6 +47,8 @@
46
47
  "generate:docs": "node scripts/generar-inventario.js",
47
48
  "gen-checklists": "node scripts/generar-checklists-consolidados.js",
48
49
  "gen-checklists:check": "node scripts/generar-checklists-consolidados.js --check",
50
+ "gen:feature-list": "node scripts/derivar-feature-list.js",
51
+ "gen:feature-list:check": "node scripts/derivar-feature-list.js --check",
49
52
  "field-report": "node scripts/field-report.js",
50
53
  "configure:branch-protection": "node scripts/configurar-branch-protection.js"
51
54
  },
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "swl-ses",
3
- "version": "1.5.2",
4
- "description": "Sistema de ingenieria de software auto-evolutivo multi-runtime polyglot. 60 agentes, 162 habilidades, 44 comandos, 66 reglas y 41 hooks. 62 librerias. 11 lenguajes. Soporta Claude Code, Copilot, OpenCode, Codex y Gemini CLI. Loop evaluator-optimizer en /swl:nemesis (ADR-0021).",
3
+ "version": "1.6.1",
4
+ "description": "Sistema de ingenieria de software auto-evolutivo multi-runtime polyglot. 60 agentes, 162 habilidades, 44 comandos, 67 reglas y 41 hooks. 62 librerias. 11 lenguajes. Soporta Claude Code, Copilot, OpenCode, Codex y Gemini CLI. Loop evaluator-optimizer en /swl:nemesis (ADR-0021). v1.6.1 endurece verificador docs-vs-codigo (gates de profundidad) y formaliza protocolo proactivo doc-sync v1.3.0 (ADR-0023).",
5
5
  "author": "Saul Wade Leon",
6
6
  "license": "MIT",
7
7
  "repository": "https://github.com/saul-wade/swl-ses",
@@ -62,6 +62,7 @@
62
62
  "habilidades/doubt-driven-review",
63
63
  "habilidades/drift-detection",
64
64
  "habilidades/ejecutar-fase",
65
+ "habilidades/ejecutar-task-iterativo",
65
66
  "habilidades/estilo-sin-ai-isms",
66
67
  "habilidades/estructura-proyecto-claude",
67
68
  "habilidades/eval-framework",
@@ -127,6 +128,7 @@
127
128
  "habilidades/prevencion-sobreingenieria",
128
129
  "habilidades/privacy-memoria",
129
130
  "habilidades/prompt-engineering",
131
+ "habilidades/protocolo-revision-swl",
130
132
  "habilidades/rag-arquitectura",
131
133
  "habilidades/rails-experto",
132
134
  "habilidades/react-experto",
@@ -0,0 +1,205 @@
1
+ # Regla: Auditorías documentales estructurales en SWL
2
+
3
+ Esta regla es **OBLIGATORIA** y aplica a todo agente o agente humano que
4
+ ejecute, reporte o consuma resultados de:
5
+
6
+ - `node scripts/verificar-docs-vs-codigo.js` (verificador docs↔código)
7
+ - `node scripts/verificar-release.js` (gate pre-publish)
8
+ - `npm run test:manifest` (coherencia modulos/hooks)
9
+ - `/swl:claudemd audit` (auditoría de CLAUDE.md)
10
+ - Cualquier comando o script que reporte un veredicto agregado tipo
11
+ "N/N checks OK" como prueba de calidad documental.
12
+
13
+ Es la **versión específica al sistema SWL** de la regla global
14
+ `~/.claude/rules/arreglar-al-detectar.md § Aplicación a auditorías`.
15
+
16
+ ---
17
+
18
+ ## Principio
19
+
20
+ > Una auditoría documental no se declara "limpia" hasta que se ha medido
21
+ > **profundidad**, no solo **presencia**. El verificador automático puede
22
+ > dar verde con docs vacías o infra-documentadas si su métrica es laxa.
23
+ > El agente que reporta resultados al usuario es responsable de distinguir
24
+ > entre **gate formal pasado** y **dominio realmente sano**.
25
+
26
+ ---
27
+
28
+ ## Por qué existe esta regla
29
+
30
+ Sesión 2026-05-16, post-release v1.6.0: el agente ejecutó dos auditorías
31
+ documentales consecutivas (Opción C release v1.6.0 + auditoría tras
32
+ `/swl:exportar-vault`) y reportó "verde" en ambas. El usuario detectó que:
33
+
34
+ - `agent-browser` estaba en el sistema desde ADR-0018 (skill + manifest +
35
+ integración con `investigador-swl` y `web-fetcher-routing`) pero **ausente
36
+ en `MANUAL_USO.md`**.
37
+ - `ADR-0022` (TUI custom zero-deps, propio del release v1.6.0) **no estaba
38
+ referenciado** en `MANUAL_USO.md`.
39
+ - 22 de 58 variables `SWL_*` que existen en `hooks/` y `scripts/` **no
40
+ estaban documentadas** ni en `docs/variables-entorno.md` ni en
41
+ `MANUAL_USO.md`.
42
+ - El verificador `scripts/verificar-docs-vs-codigo.js` reportaba "9 checks
43
+ OK" porque sus checks de comandos contaban menciones (presencia), no
44
+ profundidad. WARN consolidado de comandos infra-documentados se reportaba
45
+ como "OK".
46
+
47
+ Las dos auditorías fueron **cosméticas**, no estructurales. El gate verde
48
+ ocultaba 22 variables huérfanas y 19 ADRs no referenciados.
49
+
50
+ ---
51
+
52
+ ## Gates de profundidad obligatorios
53
+
54
+ ### Para comandos `/swl:*`
55
+
56
+ Un comando se considera **infra-documentado** si en `MANUAL_USO.md`:
57
+
58
+ - Tiene **menos de 4 menciones** Y
59
+ - Es un comando "no trivial" (excluir `ayuda`, `salud`, `modelo`,
60
+ `contexto`, `dashboard` que son operacionales simples).
61
+
62
+ Un comando infra-documentado debe tener al menos:
63
+
64
+ 1. Una sección dedicada con encabezado `### \`/swl:<nombre>\``.
65
+ 2. Subsección "**Uso**" con el patrón completo de flags.
66
+ 3. Subsección "**¿Qué hace?**" con descripción funcional.
67
+ 4. Subsección "**Cuándo usarlo**" con casos de uso.
68
+ 5. Al menos un **ejemplo concreto** de invocación con output esperado.
69
+ 6. Subsección "**Gotchas**" o "**Troubleshooting**" si el comando tiene
70
+ dependencias externas (MCP, herramientas opt-in, paths críticos).
71
+
72
+ ### Para variables de entorno `SWL_*`
73
+
74
+ Cobertura **completa, no muestral**:
75
+
76
+ - Toda variable `SWL_*` que aparezca en `hooks/` o `scripts/` DEBE estar
77
+ documentada en `docs/variables-entorno.md` con: nombre, default, qué
78
+ activa, archivo que la consume.
79
+ - La verificación es objetiva: `grep -rohE 'SWL_[A-Z_]+' hooks/ scripts/ |
80
+ sort -u` debe ser un **subconjunto** del set de variables documentadas.
81
+ - **Sin excepciones**: variables internas de debug también se documentan
82
+ (ej. `SWL_DEBUG`, `SWL_SESSION_ID`).
83
+
84
+ ### Para ADRs
85
+
86
+ - Todo ADR nuevo `.planning/adrs/NNNN-*.md` que cambia comportamiento
87
+ observable del sistema debe ser **referenciado** en al menos:
88
+ - `MANUAL_USO.md` en la sección del feature que materializa, Y
89
+ - `CHANGELOG.md` en la versión que lo introduce.
90
+ - ADRs de proceso interno (deprecaciones, splits internos, refactors
91
+ ocultos) pueden documentarse solo en `.planning/adrs/README.md`.
92
+ - El criterio de "cambia comportamiento observable" se evalúa: ¿un usuario
93
+ del sistema percibirá la diferencia? Si sí, debe ir a `MANUAL_USO.md`.
94
+
95
+ ### Para integraciones opt-in (dependencias externas)
96
+
97
+ Toda dependencia externa opt-in (markitdown, code-review-graph,
98
+ agent-browser, @dbml/core, likec4, etc.) debe documentarse en
99
+ `MANUAL_USO.md § Dependencias externas` con la **estructura mínima**:
100
+
101
+ 1. Marcador obligatorio "**NO es dependencia técnica de swl-ses**"
102
+ (regla CLAUDE.md sobre dependencias educativas opt-in).
103
+ 2. **Qué es** y **por qué existe la integración** (no solo
104
+ instalación — eso es lo cosmético).
105
+ 3. **Beneficio cuantificado** vs alternativas (tokens, espacio,
106
+ tiempo, etc. — números, no adjetivos).
107
+ 4. **Cuándo vale la pena** vs **cuándo NO instalarlo**.
108
+ 5. **Cómo lo usa el sistema** internamente (qué agente, qué skill,
109
+ qué comando lo invoca).
110
+ 6. **Comportamiento si NO está instalado** (debe degradar
111
+ funcionalmente sin fallar — regla `arreglar-al-detectar`).
112
+ 7. **Limitaciones conocidas**.
113
+ 8. **Origen** (ADR, sesión, paper, repo).
114
+
115
+ ---
116
+
117
+ ## Procedimiento al ejecutar una auditoría documental
118
+
119
+ ### Antes de reportar "verde"
120
+
121
+ 1. **Listar qué mide cada check del verificador** y nombrar
122
+ explícitamente qué **NO** mide.
123
+ 2. **Hacer sondeo manual estructural** sobre 2-3 ítems aleatorios del
124
+ dominio auditado:
125
+ - Para comandos: tomar 2-3 al azar, contar menciones en MANUAL_USO,
126
+ verificar que tengan las 6 subsecciones obligatorias.
127
+ - Para variables: comparar lista de código (`grep -rohE`) contra
128
+ lista de docs.
129
+ - Para ADRs: cruzar `ls .planning/adrs/*.md` contra
130
+ `grep -oE "ADR-[0-9]+" MANUAL_USO.md`.
131
+ 3. **Reportar al usuario el desglose** entre:
132
+ - Gate formal pasado: "N/N checks OK" (cita textual del verificador).
133
+ - Drift estructural detectado en sondeo: "X gaps reales encontrados
134
+ fuera del scope del verificador".
135
+
136
+ ### Patrón de reporte correcto
137
+
138
+ ```
139
+ Verificador docs-vs-código: 9/9 OK formal.
140
+ Sondeo estructural manual:
141
+ - Comandos infra-documentados (<4 menciones): 3 detectados
142
+ → /swl:exportar-vault, /swl:nemesis (en COMANDOS.md), /swl:wiki
143
+ - Variables SWL_* huérfanas: 22 de 58
144
+ - ADRs nuevos no referenciados en MANUAL_USO: 19 de 22
145
+
146
+ Conclusión: gate formal pasado, drift estructural REAL detectado.
147
+ Recomendación: cerrar gaps antes de declarar docs sanas.
148
+ ```
149
+
150
+ ### Patrón de reporte INCORRECTO (a evitar)
151
+
152
+ ```
153
+ Verificador docs-vs-código: 9/9 OK.
154
+ Docs alineadas con código. ✓
155
+ ```
156
+
157
+ Esta segunda forma es la que el usuario detectó y corrigió en
158
+ sesión 2026-05-16. **No reincidir**.
159
+
160
+ ---
161
+
162
+ ## Anti-patrones específicos del sistema SWL
163
+
164
+ - **Aceptar "WARN no falla el verificador"**: el check #2 actual
165
+ reporta WARN sin bloquear cuando comandos no están documentados.
166
+ Eso es deuda preexistente legítima, pero **NUNCA** se reporta como
167
+ "OK" al usuario sin enumerar los WARN.
168
+ - **Confiar en el conteo agregado** (`44 comandos /swl:* documentados`)
169
+ sin verificar la profundidad de cada uno.
170
+ - **No cruzar el universo real**: el verificador chequea `comandos/swl/*.md`
171
+ contra `MANUAL_USO.md`. Pero NO chequea `MANUAL_USO.md` contra ADRs
172
+ ni contra variables del código. Esos universos quedan invisibles.
173
+ - **Whitelist hardcodeada en check #3**: solo 7 flags críticas. El
174
+ parser BOOLEANAS tiene más. Las flags no listadas en la whitelist
175
+ son drift invisible.
176
+ - **Reportar "✓ skip" como "✓ pass"**: si el TUI no está instalado
177
+ (pre-v1.6.0), el check #5 reporta éxito. Eso es correcto técnicamente
178
+ pero el agente NO debe sumarlo al conteo "N/N OK" sin matizar.
179
+
180
+ ---
181
+
182
+ ## Relación con otras reglas
183
+
184
+ - `~/.claude/rules/arreglar-al-detectar.md § Aplicación a auditorías` —
185
+ principio general; esta regla lo concreta para SWL.
186
+ - `~/.claude/rules/registro-componentes-nuevos.md` — define el registro
187
+ obligatorio de componentes en manifiestos. Esta regla extiende:
188
+ no basta con registrar, hay que documentarlo con profundidad.
189
+ - `~/.claude/rules/verificar-citas-normativas.md § Familia 2` —
190
+ verificar afirmaciones factuales del verificador antes de aceptar
191
+ el "verde" como hecho.
192
+ - `habilidades/doc-sync/SKILL.md` — implementación operativa del
193
+ verificador. Esta regla define qué debe medir.
194
+
195
+ ---
196
+
197
+ ## Origen de esta regla
198
+
199
+ Sesión 2026-05-16, post-release v1.6.0. Documentado en
200
+ `.planning/adrs/0023-auditorias-documentales-estructurales.md`.
201
+ Promovida tras feedback explícito del usuario:
202
+ *"en esta misma sesión se pidieron dos auditorías que has minimizado o
203
+ ignorado"*. Cierra el gap conceptual donde el agente aplicaba
204
+ `arreglar-al-detectar.md` a bugs durante implementación pero NO a
205
+ verificadores de docs que devuelven verde cosmético.
@@ -60,7 +60,7 @@
60
60
  "skillsInvocables": {
61
61
  "type": "array",
62
62
  "items": { "type": "string" },
63
- "description": "Skills que este agente puede invocar"
63
+ "description": "Skills que este agente puede invocar. Valor especial 'todos' = wildcard (sin restriccion de skill); usar solo en agentes generalistas (investigador-swl, planificador-swl) cuando listar 162 skills es impractico. Para todos los demas agentes, listar skills especificos siguiendo privilegio minimo (regla seguridad-agentes.md)."
64
64
  },
65
65
  "skillsRestringidos": {
66
66
  "type": "array",
@@ -3,6 +3,22 @@
3
3
  /**
4
4
  * swl-ses uninstall
5
5
  * Desinstala componentes SWL del runtime especificado.
6
+ *
7
+ * Contrato adicional: opciones.onProgress(evento)
8
+ *
9
+ * Si se pasa una función onProgress, el desinstalador emite eventos
10
+ * estructurados en vez de imprimir cada archivo a stdout:
11
+ * { tipo: 'archivo-eliminado', componente, archivo, destino }
12
+ * { tipo: 'bloque-eliminado', archivo, etiqueta }
13
+ * { tipo: 'archivo-no-encontrado', archivo }
14
+ * { tipo: 'error', archivo, mensaje }
15
+ * { tipo: 'log', linea }
16
+ *
17
+ * Backward compat: si onProgress no se pasa, los console.log son idénticos
18
+ * a antes. El CLI clásico (uninstall sin TUI) no cambia.
19
+ *
20
+ * Devuelve { eliminados, noEncontrados, bloquesEliminados } para que el
21
+ * caller (TUI) pueda mostrar resumen sin re-parsear stdout.
6
22
  */
7
23
 
8
24
  const fs = require('fs');
@@ -15,23 +31,40 @@ const { eliminarBloque } = require('./lib/append-con-marcadores');
15
31
  function uninstall(opciones) {
16
32
  const target = opciones.target || 'claude';
17
33
  const esGlobal = opciones.global || false;
34
+ const onProgress = typeof opciones.onProgress === 'function' ? opciones.onProgress : null;
18
35
 
19
- console.log('swl-ses uninstall');
20
- console.log('='.repeat(40));
36
+ function _emitir(evento, mensajeFallback) {
37
+ if (onProgress) {
38
+ onProgress(evento);
39
+ } else if (mensajeFallback) {
40
+ console.log(mensajeFallback);
41
+ }
42
+ }
43
+
44
+ if (!onProgress) {
45
+ console.log('swl-ses uninstall');
46
+ console.log('='.repeat(40));
47
+ }
21
48
 
22
49
  const runtime = obtenerRuntime(target);
23
50
  const rutas = calcularRutas(target, { global: esGlobal });
24
51
 
25
52
  const estado = cargarEstado(rutas.base);
26
53
  if (!estado) {
54
+ if (onProgress) {
55
+ onProgress({ tipo: 'log', linea: `No se encontró instalación SWL en ${rutas.base}` });
56
+ return { eliminados: 0, noEncontrados: 0, bloquesEliminados: 0, error: 'instalacion-no-encontrada' };
57
+ }
27
58
  console.log(`No se encontró instalación SWL en ${rutas.base}`);
28
59
  process.exit(1);
29
60
  }
30
61
 
31
- console.log(`Target: ${target} (${runtime.nombre})`);
32
- console.log(`Ubicación: ${rutas.base}`);
33
- console.log(`Archivos a eliminar: ${estado.archivosInstalados.length}`);
34
- console.log('');
62
+ if (!onProgress) {
63
+ console.log(`Target: ${target} (${runtime.nombre})`);
64
+ console.log(`Ubicación: ${rutas.base}`);
65
+ console.log(`Archivos a eliminar: ${estado.archivosInstalados.length}`);
66
+ console.log('');
67
+ }
35
68
 
36
69
  let eliminados = 0;
37
70
  let noEncontrados = 0;
@@ -56,10 +89,17 @@ function uninstall(opciones) {
56
89
  if (accionInstall === 'creado') {
57
90
  try {
58
91
  fs.unlinkSync(archivo.destino);
59
- console.log(` - ${archivo.destino} (creado por swl-ses, eliminación completa)`);
92
+ _emitir(
93
+ { tipo: 'archivo-eliminado', componente: archivo.tipo, archivo: archivo.destino, motivo: 'creado-por-swl' },
94
+ ` - ${archivo.destino} (creado por swl-ses, eliminación completa)`
95
+ );
60
96
  eliminados++;
61
97
  } catch (err) {
62
- console.error(` ! Error eliminando ${archivo.destino}: ${err.message}`);
98
+ _emitir(
99
+ { tipo: 'error', archivo: archivo.destino, mensaje: err.message },
100
+ null
101
+ );
102
+ if (!onProgress) console.error(` ! Error eliminando ${archivo.destino}: ${err.message}`);
63
103
  }
64
104
  } else {
65
105
  try {
@@ -70,12 +110,19 @@ function uninstall(opciones) {
70
110
  'sin-cambios': 'sin bloque SWL presente (ya limpio)',
71
111
  'error': `error: ${r.detalle || 'desconocido'}`,
72
112
  }[r.accion] || r.accion;
73
- console.log(` ~ ${archivo.destino} (${etiqueta})`);
113
+ _emitir(
114
+ { tipo: 'bloque-eliminado', archivo: archivo.destino, etiqueta, accion: r.accion },
115
+ ` ~ ${archivo.destino} (${etiqueta})`
116
+ );
74
117
  if (r.accion === 'bloque-eliminado' || r.accion === 'archivo-eliminado') {
75
118
  bloquesEliminados++;
76
119
  }
77
120
  } catch (err) {
78
- console.error(` ! Error limpiando bloque en ${archivo.destino}: ${err.message}`);
121
+ _emitir(
122
+ { tipo: 'error', archivo: archivo.destino, mensaje: err.message },
123
+ null
124
+ );
125
+ if (!onProgress) console.error(` ! Error limpiando bloque en ${archivo.destino}: ${err.message}`);
79
126
  }
80
127
  }
81
128
  continue;
@@ -88,26 +135,47 @@ function uninstall(opciones) {
88
135
  } else {
89
136
  fs.unlinkSync(archivo.destino);
90
137
  }
91
- console.log(` - ${archivo.destino}`);
138
+ _emitir(
139
+ { tipo: 'archivo-eliminado', componente: archivo.tipo, archivo: archivo.destino },
140
+ ` - ${archivo.destino}`
141
+ );
92
142
  eliminados++;
93
143
  } catch (err) {
94
- console.error(` ! Error eliminando ${archivo.destino}: ${err.message}`);
144
+ _emitir(
145
+ { tipo: 'error', archivo: archivo.destino, mensaje: err.message },
146
+ null
147
+ );
148
+ if (!onProgress) console.error(` ! Error eliminando ${archivo.destino}: ${err.message}`);
95
149
  }
96
150
  }
97
151
 
98
152
  // Desregistrar hooks de settings.json
153
+ let hooksDesregistrados = 0;
154
+ let hooksPreservados = 0;
99
155
  if (runtime.soportaHooks) {
100
156
  const settingsPath = rutaSettings(runtime, rutas.base);
101
157
  try {
102
158
  const resultado = desregistrarHooks(settingsPath);
103
- if (resultado.eliminados > 0) {
104
- console.log(` - Hooks desregistrados de settings.json: ${resultado.eliminados}`);
159
+ hooksDesregistrados = resultado.eliminados || 0;
160
+ hooksPreservados = resultado.preservados || 0;
161
+ if (hooksDesregistrados > 0) {
162
+ _emitir(
163
+ { tipo: 'hooks-desregistrados', cuenta: hooksDesregistrados },
164
+ ` - Hooks desregistrados de settings.json: ${hooksDesregistrados}`
165
+ );
105
166
  }
106
- if (resultado.preservados > 0) {
107
- console.log(` (${resultado.preservados} hooks externos preservados)`);
167
+ if (hooksPreservados > 0) {
168
+ _emitir(
169
+ { tipo: 'hooks-preservados', cuenta: hooksPreservados },
170
+ ` (${hooksPreservados} hooks externos preservados)`
171
+ );
108
172
  }
109
173
  } catch (err) {
110
- console.error(` ! Error desregistrando hooks: ${err.message}`);
174
+ _emitir(
175
+ { tipo: 'error', mensaje: `Error desregistrando hooks: ${err.message}` },
176
+ null
177
+ );
178
+ if (!onProgress) console.error(` ! Error desregistrando hooks: ${err.message}`);
111
179
  }
112
180
  }
113
181
 
@@ -117,14 +185,27 @@ function uninstall(opciones) {
117
185
  fs.unlinkSync(estadoPath);
118
186
  }
119
187
 
120
- console.log('');
121
- console.log(`Eliminados: ${eliminados}`);
122
- if (bloquesEliminados > 0) {
123
- console.log(`Bloques SWL quitados (contenido de usuario preservado): ${bloquesEliminados}`);
188
+ if (!onProgress) {
189
+ console.log('');
190
+ console.log(`Eliminados: ${eliminados}`);
191
+ if (bloquesEliminados > 0) {
192
+ console.log(`Bloques SWL quitados (contenido de usuario preservado): ${bloquesEliminados}`);
193
+ }
194
+ console.log(`No encontrados: ${noEncontrados}`);
195
+ console.log('');
196
+ console.log('Nota: .planning/ y _userland/ no se eliminan (contienen datos del proyecto).');
124
197
  }
125
- console.log(`No encontrados: ${noEncontrados}`);
126
- console.log('');
127
- console.log('Nota: .planning/ y _userland/ no se eliminan (contienen datos del proyecto).');
198
+
199
+ return {
200
+ eliminados,
201
+ noEncontrados,
202
+ bloquesEliminados,
203
+ hooksDesregistrados,
204
+ hooksPreservados,
205
+ target,
206
+ scope: esGlobal ? 'global' : 'proyecto',
207
+ ubicacion: rutas.base,
208
+ };
128
209
  }
129
210
 
130
211
  module.exports = uninstall;