@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.
Files changed (198) hide show
  1. package/CLAUDE.md +194 -241
  2. package/README.md +600 -597
  3. package/agentes/_intent-spec.md +73 -73
  4. package/agentes/_propose-step.md +90 -90
  5. package/agentes/abogado-diablo-swl.md +145 -0
  6. package/agentes/accesibilidad-wcag-swl.md +690 -690
  7. package/agentes/arquitecto-swl.md +267 -267
  8. package/agentes/auto-evolucion-swl.md +908 -908
  9. package/agentes/backend-api-swl.md +1 -1
  10. package/agentes/backend-csharp-swl.md +420 -420
  11. package/agentes/backend-go-swl.md +390 -390
  12. package/agentes/backend-java-swl.md +281 -281
  13. package/agentes/backend-node-swl.md +1 -1
  14. package/agentes/backend-python-swl.md +1 -1
  15. package/agentes/backend-rust-swl.md +364 -364
  16. package/agentes/backend-workers-swl.md +482 -482
  17. package/agentes/cloud-infra-swl.md +509 -509
  18. package/agentes/consolidador-swl.md +541 -541
  19. package/agentes/datos-swl.md +1 -1
  20. package/agentes/depurador-swl.md +352 -352
  21. package/agentes/devops-ci-swl.md +400 -400
  22. package/agentes/disenador-ui-swl.md +569 -569
  23. package/agentes/documentador-swl.md +345 -345
  24. package/agentes/frontend-angular-swl.md +621 -621
  25. package/agentes/frontend-css-swl.md +716 -716
  26. package/agentes/frontend-react-swl.md +692 -692
  27. package/agentes/frontend-swl.md +496 -496
  28. package/agentes/frontend-tailwind-swl.md +826 -826
  29. package/agentes/gh-fix-ci-swl.md +6 -1
  30. package/agentes/implementador-swl.md +1 -1
  31. package/agentes/investigador-swl.md +432 -432
  32. package/agentes/investigador-ux-swl.md +505 -505
  33. package/agentes/llm-apps-swl.md +1 -1
  34. package/agentes/migrador-swl.md +442 -442
  35. package/agentes/mobile-android-swl.md +511 -511
  36. package/agentes/mobile-cross-swl.md +541 -541
  37. package/agentes/mobile-ios-swl.md +502 -502
  38. package/agentes/mobile-testing-swl.md +302 -302
  39. package/agentes/nemesis-auditor-swl.md +285 -285
  40. package/agentes/notificador-swl.md +1 -1
  41. package/agentes/observabilidad-swl.md +438 -438
  42. package/agentes/pagos-swl.md +310 -310
  43. package/agentes/perfilador-usuario-swl.md +321 -321
  44. package/agentes/planificador-swl.md +399 -399
  45. package/agentes/producto-prd-swl.md +589 -589
  46. package/agentes/red-team-swl.md +218 -218
  47. package/agentes/release-manager-swl.md +590 -590
  48. package/agentes/rendimiento-swl.md +713 -713
  49. package/agentes/resolutor-build-swl.md +10 -1
  50. package/agentes/revisor-angular-swl.md +278 -278
  51. package/agentes/revisor-codigo-swl.md +1 -1
  52. package/agentes/revisor-csharp-swl.md +264 -264
  53. package/agentes/revisor-go-swl.md +259 -259
  54. package/agentes/revisor-java-swl.md +257 -257
  55. package/agentes/revisor-kotlin-swl.md +273 -273
  56. package/agentes/revisor-nextjs-swl.md +281 -281
  57. package/agentes/revisor-php-swl.md +271 -271
  58. package/agentes/revisor-react-swl.md +278 -278
  59. package/agentes/revisor-rust-swl.md +346 -346
  60. package/agentes/revisor-seguridad-swl.md +399 -399
  61. package/agentes/revisor-swift-swl.md +268 -268
  62. package/agentes/revisor-typescript-swl.md +346 -346
  63. package/agentes/sre-swl.md +1 -1
  64. package/agentes/tdd-qa-swl.md +393 -393
  65. package/bin/lib/bot-comandos.js +1 -1
  66. package/bin/swl-ses.js +6 -0
  67. package/comandos/swl/adoptar-proyecto.md +14 -2
  68. package/comandos/swl/configurar-ci.md +8 -1
  69. package/comandos/swl/deuda-codigo.md +97 -97
  70. package/comandos/swl/discutir-fase.md +22 -118
  71. package/comandos/swl/fix.md +118 -0
  72. package/comandos/swl/nuevo-proyecto.md +54 -3
  73. package/comandos/swl/predecir.md +32 -2
  74. package/comandos/swl/seguridad.md +189 -0
  75. package/comandos/swl/status.md +5 -3
  76. package/habilidades/aprendizaje-continuo/SKILL.md +3 -1
  77. package/habilidades/discutir-fase/SKILL.md +84 -81
  78. package/habilidades/discutir-fase/recursos/plantilla-contexto.md +136 -0
  79. package/habilidades/doc-sync/SKILL.md +3 -1
  80. package/habilidades/doubt-driven-review/SKILL.md +15 -1
  81. package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
  82. package/habilidades/estructura-proyecto-claude/SKILL.md +11 -2
  83. package/habilidades/harness-claude-code/SKILL.md +3 -1
  84. package/habilidades/instalar-sistema/SKILL.md +3 -1
  85. package/habilidades/meta-reglas-extendido/SKILL.md +92 -0
  86. package/habilidades/meta-reglas-extendido/recursos/analisis-previo-tareas-grandes.md +186 -0
  87. package/habilidades/meta-reglas-extendido/recursos/analizar-directorios-antes-de-escribir.md +235 -0
  88. package/habilidades/meta-reglas-extendido/recursos/api-diseno.md +413 -0
  89. package/habilidades/meta-reglas-extendido/recursos/arquitectura.md +491 -0
  90. package/habilidades/meta-reglas-extendido/recursos/arreglar-al-detectar.md +264 -0
  91. package/habilidades/meta-reglas-extendido/recursos/debatir-antes-de-aceptar.md +152 -0
  92. package/habilidades/meta-reglas-extendido/recursos/git-workflow.md +259 -0
  93. package/habilidades/meta-reglas-extendido/recursos/gobernanza.md +291 -0
  94. package/habilidades/meta-reglas-extendido/recursos/memoria-consolidada.md +263 -0
  95. package/habilidades/meta-reglas-extendido/recursos/seguridad-agentes.md +443 -0
  96. package/habilidades/meta-reglas-extendido/recursos/sesiones-paralelas.md +190 -0
  97. package/habilidades/meta-reglas-extendido/recursos/sin-duplicacion-reglas-globales.md +179 -0
  98. package/habilidades/meta-reglas-extendido/recursos/skills-estandar.md +394 -0
  99. package/habilidades/meta-reglas-extendido/recursos/usar-code-review-graph.md +156 -0
  100. package/habilidades/meta-reglas-extendido/recursos/usar-context7.md +236 -0
  101. package/habilidades/meta-reglas-extendido/recursos/usar-sistema-swl.md +253 -0
  102. package/habilidades/meta-reglas-extendido/recursos/verificar-citas-normativas.md +527 -0
  103. package/habilidades/meta-skills-estandar/SKILL.md +3 -1
  104. package/habilidades/nuevo-proyecto/SKILL.md +20 -3
  105. package/habilidades/php-experto/SKILL.md +10 -3
  106. package/habilidades/{filament-admin/SKILL.md → php-experto/recursos/filament-admin.md} +23 -39
  107. package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
  108. package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
  109. package/habilidades/proceso-debate-adversarial/recursos/personas.md +5 -4
  110. package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -0
  111. package/hooks/check-update.js +19 -10
  112. package/hooks/contexto-subagente.js +68 -68
  113. package/hooks/degradacion-instintos.js +1 -1
  114. package/hooks/extraccion-aprendizajes.js +2 -2
  115. package/hooks/lib/briefing.js +3 -3
  116. package/hooks/lib/nudge-tracker.js +1 -1
  117. package/hooks/lib/otlp-exporter.js +1 -1
  118. package/hooks/lib/webhook-dedup.js +1 -1
  119. package/hooks/session-briefing.js +1 -1
  120. package/llms.txt +6 -6
  121. package/manifiestos/canonical-hashes.json +989 -0
  122. package/manifiestos/hooks-config.json +469 -469
  123. package/manifiestos/invariantes-criticos.json +30 -30
  124. package/manifiestos/modulos.json +168 -135
  125. package/manifiestos/perfiles.json +0 -2
  126. package/manifiestos/skills-lock.json +52 -59
  127. package/package.json +7 -5
  128. package/plantillas/github-workflows/README.md +15 -1
  129. package/plantillas/github-workflows/swl-devsecops.yml +70 -0
  130. package/plugin.json +5 -5
  131. package/reglas/analisis-previo-tareas-grandes.md +30 -156
  132. package/reglas/analizar-directorios-antes-de-escribir.md +30 -211
  133. package/reglas/api-diseno.md +28 -398
  134. package/reglas/arquitectura.md +35 -456
  135. package/reglas/arreglar-al-detectar.md +30 -230
  136. package/reglas/debatir-antes-de-aceptar.md +30 -143
  137. package/reglas/docs.md +7 -0
  138. package/reglas/estilo-codigo.md +9 -0
  139. package/reglas/fragmentos-compartidos.md +6 -0
  140. package/reglas/git-workflow.md +44 -240
  141. package/reglas/gobernanza.md +23 -262
  142. package/reglas/memoria-consolidada.md +34 -228
  143. package/reglas/performance.md +8 -0
  144. package/reglas/pruebas.md +12 -0
  145. package/reglas/seguridad-agentes.md +37 -418
  146. package/reglas/seguridad.md +12 -0
  147. package/reglas/sesiones-paralelas.md +29 -162
  148. package/reglas/sin-duplicacion-reglas-globales.md +25 -166
  149. package/reglas/skills-estandar.md +23 -373
  150. package/reglas/usar-code-review-graph.md +31 -140
  151. package/reglas/usar-context7.md +30 -208
  152. package/reglas/usar-sistema-swl.md +47 -242
  153. package/reglas/verificar-citas-normativas.md +47 -537
  154. package/scripts/actualizar.js +253 -253
  155. package/scripts/audit-tools/auditar-relleno-inventario.js +145 -0
  156. package/scripts/auditar-clases-conocidas.js +106 -0
  157. package/scripts/bootstrap-instintos.js +2 -2
  158. package/scripts/canario-hooks.js +166 -0
  159. package/scripts/cli/configurar-ci.js +2 -1
  160. package/scripts/evidencia-valor.js +93 -0
  161. package/scripts/field-report.js +1 -1
  162. package/scripts/generar-comandos.js +143 -0
  163. package/scripts/generar-inventario.js +236 -23
  164. package/scripts/generar-matriz-lenguajes.js +1 -1
  165. package/scripts/instalador.js +15 -1
  166. package/scripts/lib/configurar-ci.js +10 -3
  167. package/scripts/lib/detectar-runtime.js +12 -3
  168. package/scripts/lib/diary-entry.js +3 -1
  169. package/scripts/lib/drift-detector.js +1 -1
  170. package/scripts/lib/evidencia-valor.js +189 -0
  171. package/scripts/lib/expandir-targets.js +71 -71
  172. package/scripts/lib/frontmatter-md.js +63 -0
  173. package/scripts/lib/parsear-opciones.js +2 -0
  174. package/scripts/lib/prune-componentes.js +180 -0
  175. package/scripts/lib/reglas-globales-conocidas.json +16 -2
  176. package/scripts/lib/scoring-instintos.js +2 -2
  177. package/scripts/lib/toml-merge.js +204 -204
  178. package/scripts/lib/transformadores/claude.js +1 -1
  179. package/scripts/lib/transformadores/codex.js +1 -1
  180. package/scripts/lib/transformadores/copilot.js +1 -1
  181. package/scripts/lib/transformadores/cursor.js +1 -1
  182. package/scripts/lib/transformadores/gemini.js +22 -2
  183. package/scripts/lib/transformadores/opencode.js +1 -1
  184. package/scripts/mcp-server/auth.js +105 -105
  185. package/scripts/mcp-server/cache.js +106 -106
  186. package/scripts/prune.js +102 -0
  187. package/scripts/publicar.js +18 -2
  188. package/scripts/tui/pantallas/inspect.js +175 -175
  189. package/scripts/tui/pantallas/uninstall-wizard.js +210 -210
  190. package/scripts/tui/pantallas/update-wizard.js +234 -234
  191. package/scripts/tui/pantallas/welcome.js +189 -189
  192. package/habilidades/paid-media-tracking/SKILL.md +0 -269
  193. package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +0 -220
  194. package/habilidades/paid-media-tracking/recursos/google-ads-api.md +0 -215
  195. package/habilidades/tracking-measurement/SKILL.md +0 -239
  196. package/habilidades/tracking-measurement/recursos/consent-mode.md +0 -231
  197. package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +0 -216
  198. package/habilidades/tracking-measurement/recursos/meta-capi.md +0 -262
@@ -1,253 +1,253 @@
1
- 'use strict';
2
-
3
- /**
4
- * swl-ses update
5
- * Actualiza componentes instalados preservando _userland/.
6
- * Interactivo: muestra versiones, pide confirmación, muestra progreso.
7
- * No-interactivo con --force o sin TTY.
8
- *
9
- * Modo --check (read-only):
10
- * Solo muestra el estado actual de versiones (local vs npm vs runtimes instalados).
11
- * No pide confirmación. No actualiza nada. Util para el autor o usuarios que
12
- * quieren verificar si están al dia sin esperar al hook automatico.
13
- */
14
-
15
- const fs = require('fs');
16
- const os = require('os');
17
- const path = require('path');
18
- const { detectarRuntimes, scopesReales } = require('./lib/detectar-runtime');
19
- const { cargarEstado } = require('./lib/estado');
20
- const {
21
- color, icono, encabezado, formatearPaso, formatearAdvertencia,
22
- spinner, preguntarSiNo, lineaSeparadora, ES_TTY,
23
- } = require('./lib/ui');
24
- const { versionRemotaParalela, compararSemver } = require('./lib/npm-version');
25
-
26
- const VERSION_LOCAL = require('../package.json').version;
27
-
28
- /**
29
- * Consulta la versión más reciente publicada en npm. Si la consulta falla
30
- * (sin red, timeout), retorna la versión local como fallback razonable.
31
- */
32
- async function obtenerVersionRemota() {
33
- const r = await versionRemotaParalela({ timeoutMs: 10000 });
34
- return r.version || VERSION_LOCAL;
35
- }
36
-
37
- /**
38
- * Modo --check: muestra el estado actual sin actualizar. Read-only.
39
- *
40
- * Salida:
41
- * - Version del paquete que esta ejecutando este CLI (VERSION_LOCAL).
42
- * - Version mas reciente publicada en npm.
43
- * - Comparacion semver: al dia / adelantado / atras.
44
- * - Estado del hook check-update.js: ultima verificacion automatica.
45
- * - Tabla por runtime instalado (si los detecta) con su versionSistema.
46
- */
47
- async function checkStatus() {
48
- console.log(encabezado('swl-ses update --check', VERSION_LOCAL));
49
-
50
- // Resolver version remota con timeout corto
51
- const remota = await obtenerVersionRemota();
52
- const cmp = compararSemver(VERSION_LOCAL, remota);
53
-
54
- let estadoVersion;
55
- if (cmp === null) {
56
- estadoVersion = color.amarillo('Comparacion no disponible (formato inesperado)');
57
- } else if (cmp === 0) {
58
- estadoVersion = color.verde('Al dia');
59
- } else if (cmp < 0) {
60
- estadoVersion = color.amarillo(`Nueva version disponible (${remota})`);
61
- } else {
62
- estadoVersion = color.dim(`Local mas reciente que npm (${VERSION_LOCAL} > ${remota}, publicacion pendiente)`);
63
- }
64
-
65
- console.log(` Paquete ejecutado: ${color.negrita('v' + VERSION_LOCAL)}`);
66
- console.log(` Version en npm: ${color.negrita('v' + remota)}`);
67
- console.log(` Estado: ${estadoVersion}`);
68
- console.log('');
69
-
70
- // Estado del hook automatico (check-update.js).
71
- // SWL_UPDATE_FLAG_PATH override solo para tests (evita race con flag único).
72
- const flagPath = process.env.SWL_UPDATE_FLAG_PATH || path.join(os.tmpdir(), 'swl-ses-update-check.json');
73
- try {
74
- const flag = JSON.parse(fs.readFileSync(flagPath, 'utf8'));
75
- const horas = ((Date.now() - flag.timestamp) / 3600000).toFixed(1);
76
- console.log(` ${color.negrita('Hook automatico (check-update.js):')}`);
77
- console.log(` Ultima verificacion: hace ${horas}h`);
78
- console.log(` Local registrada: ${flag.local}`);
79
- console.log(` Remota registrada: ${flag.remota || color.dim('(no resuelta)')}`);
80
- console.log(` hayNueva: ${flag.hayNueva ? color.amarillo('si') : color.verde('no')}`);
81
- console.log(` Flag: ${flagPath}`);
82
- } catch {
83
- console.log(` ${color.negrita('Hook automatico (check-update.js):')}`);
84
- console.log(` ${color.dim('Sin flag de throttle — el hook nunca se ha ejecutado en este equipo,')}`);
85
- console.log(` ${color.dim('o el archivo temp/swl-ses-update-check.json fue removido.')}`);
86
- }
87
- console.log('');
88
-
89
- // Estado por runtime instalado
90
- const runtimes = detectarRuntimes();
91
- if (runtimes.length === 0) {
92
- console.log(formatearAdvertencia('Runtimes', 'No se detectaron runtimes con instalacion SWL'));
93
- console.log('');
94
- return;
95
- }
96
-
97
- console.log(` ${color.negrita('Runtimes detectados:')}`);
98
- let totalRuntimes = 0;
99
- for (const runtime of runtimes) {
100
- // Dedup + guard anti-fantasma (ver scopesReales): desde HOME el local
101
- // colapsa con el global propio o con el de otro runtime.
102
- for (const { dir, esGlobal } of scopesReales(runtime)) {
103
- if (!fs.existsSync(dir)) continue;
104
- const estado = cargarEstado(dir);
105
- if (!estado) continue;
106
-
107
- const ubicacion = esGlobal ? 'global' : 'proyecto';
108
- const v = estado.versionSistema || 'desconocida';
109
-
110
- const cmpRuntime = compararSemver(v, remota);
111
- let etiqueta;
112
- if (cmpRuntime === null) {
113
- etiqueta = color.dim('(version no reconocida)');
114
- } else if (cmpRuntime === 0) {
115
- etiqueta = color.verde('al dia');
116
- } else if (cmpRuntime < 0) {
117
- etiqueta = color.amarillo(`atrasada (npm: ${remota})`);
118
- } else {
119
- etiqueta = color.dim('adelantada');
120
- }
121
-
122
- console.log(` ${runtime.nombre} (${ubicacion}): v${v} ${etiqueta}`);
123
- totalRuntimes++;
124
- }
125
- }
126
- if (totalRuntimes === 0) {
127
- console.log(` ${color.dim('(ninguno con .swl-install-state.json valido)')}`);
128
- }
129
- console.log('');
130
- console.log(` ${color.dim('Modo --check es read-only. Para actualizar:')} npx -y @saulwade/swl-ses@latest update`);
131
- console.log('');
132
- }
133
-
134
- async function update(opciones) {
135
- // Modo read-only: solo reportar estado, no tocar nada
136
- if (opciones.check) {
137
- await checkStatus();
138
- return;
139
- }
140
-
141
- const force = opciones.force || !ES_TTY;
142
-
143
- // Obtener la versión más reciente del registro npm
144
- const VERSION = await obtenerVersionRemota();
145
-
146
- console.log(encabezado('swl-ses update', VERSION_LOCAL));
147
-
148
- // 1. Detectar runtimes
149
- const runtimes = detectarRuntimes();
150
-
151
- if (runtimes.length === 0) {
152
- console.log(formatearAdvertencia('Runtimes', 'No se detectaron runtimes con instalación SWL'));
153
- console.log(`\n Ejecuta primero: npx @saulwade/swl-ses@latest install --target claude`);
154
- process.exit(1);
155
- }
156
-
157
- let actualizados = 0;
158
- let omitidos = 0;
159
-
160
- // 2. Iterar runtimes
161
- for (const runtime of runtimes) {
162
- // Dedup + guard anti-fantasma (ver scopesReales).
163
- for (const { dir, esGlobal } of scopesReales(runtime)) {
164
- if (!fs.existsSync(dir)) continue;
165
-
166
- const estado = cargarEstado(dir);
167
- if (!estado) continue;
168
-
169
- const versionInstalada = estado.versionSistema || 'desconocida';
170
- const ubicacion = esGlobal ? 'global' : 'proyecto';
171
-
172
- const necesitaActualizar = versionInstalada !== VERSION;
173
- const paqueteDesactualizado = VERSION_LOCAL !== VERSION;
174
-
175
- console.log(` ${color.negrita(`Runtime: ${runtime.nombre}`)} ${color.dim(`(${ubicacion})`)}`);
176
- console.log(` Versión instalada: ${necesitaActualizar ? color.amarillo(versionInstalada) : color.verde(versionInstalada)}`);
177
- console.log(` Versión disponible: ${color.verde(VERSION)}${paqueteDesactualizado ? color.dim(` (ejecutando con v${VERSION_LOCAL})`) : ''}`);
178
- console.log(` Perfil: ${estado.perfil}`);
179
- console.log(` Componentes: ${estado.componentesInstalados.length}`);
180
- console.log(` Archivos: ${estado.archivosInstalados.length}`);
181
- console.log('');
182
-
183
- // Si la versión disponible es más reciente pero el paquete ejecutándose es viejo,
184
- // indicar al usuario que use @latest
185
- if (paqueteDesactualizado && necesitaActualizar) {
186
- console.log(formatearAdvertencia(runtime.nombre,
187
- `Este paquete es v${VERSION_LOCAL} pero la v${VERSION} está disponible.\n` +
188
- ` Para actualizar, ejecuta: npx @saulwade/swl-ses@latest update --force`));
189
- console.log('');
190
- omitidos++;
191
- continue;
192
- }
193
-
194
- // Verificar si ya está actualizado
195
- if (!necesitaActualizar && !force) {
196
- console.log(formatearPaso(runtime.nombre, 'Ya está en la versión más reciente'));
197
- console.log('');
198
- omitidos++;
199
- continue;
200
- }
201
-
202
- // Confirmar
203
- if (!force) {
204
- const confirmar = await preguntarSiNo(
205
- !necesitaActualizar
206
- ? `¿Re-instalar ${runtime.nombre} v${VERSION}?`
207
- : `¿Actualizar ${runtime.nombre} de ${versionInstalada} a ${VERSION}?`
208
- );
209
- console.log('');
210
-
211
- if (!confirmar) {
212
- console.log(formatearAdvertencia(runtime.nombre, 'Actualización cancelada por el usuario'));
213
- console.log('');
214
- omitidos++;
215
- continue;
216
- }
217
- }
218
-
219
- // Ejecutar actualización con spinner
220
- const sp = spinner(`Actualizando ${runtime.nombre}...`);
221
-
222
- try {
223
- const instalador = require('./instalador');
224
- await instalador({
225
- target: runtime.id,
226
- profile: estado.perfil,
227
- global: estado.global,
228
- force: true,
229
- });
230
-
231
- sp.exito(`${runtime.nombre} actualizado a v${VERSION} (${estado.archivosInstalados.length} archivos)`);
232
- actualizados++;
233
- } catch (err) {
234
- sp.fallo(`Error actualizando ${runtime.nombre}: ${err.message}`);
235
- }
236
-
237
- console.log('');
238
- }
239
- }
240
-
241
- // 3. Reporte final
242
- console.log(` ${lineaSeparadora()}`);
243
- if (actualizados > 0) {
244
- console.log(formatearPaso('Resultado', `${actualizados} runtime(s) actualizado(s)${omitidos > 0 ? `, ${omitidos} omitido(s)` : ''}`));
245
- } else if (omitidos > 0) {
246
- console.log(formatearPaso('Resultado', 'Todo está actualizado'));
247
- } else {
248
- console.log(formatearAdvertencia('Resultado', 'Ningún runtime fue actualizado'));
249
- }
250
- console.log('');
251
- }
252
-
253
- module.exports = update;
1
+ 'use strict';
2
+
3
+ /**
4
+ * swl-ses update
5
+ * Actualiza componentes instalados preservando _userland/.
6
+ * Interactivo: muestra versiones, pide confirmación, muestra progreso.
7
+ * No-interactivo con --force o sin TTY.
8
+ *
9
+ * Modo --check (read-only):
10
+ * Solo muestra el estado actual de versiones (local vs npm vs runtimes instalados).
11
+ * No pide confirmación. No actualiza nada. Util para el autor o usuarios que
12
+ * quieren verificar si están al dia sin esperar al hook automatico.
13
+ */
14
+
15
+ const fs = require('fs');
16
+ const os = require('os');
17
+ const path = require('path');
18
+ const { detectarRuntimes, scopesReales } = require('./lib/detectar-runtime');
19
+ const { cargarEstado } = require('./lib/estado');
20
+ const {
21
+ color, icono, encabezado, formatearPaso, formatearAdvertencia,
22
+ spinner, preguntarSiNo, lineaSeparadora, ES_TTY,
23
+ } = require('./lib/ui');
24
+ const { versionRemotaParalela, compararSemver } = require('./lib/npm-version');
25
+
26
+ const VERSION_LOCAL = require('../package.json').version;
27
+
28
+ /**
29
+ * Consulta la versión más reciente publicada en npm. Si la consulta falla
30
+ * (sin red, timeout), retorna la versión local como fallback razonable.
31
+ */
32
+ async function obtenerVersionRemota() {
33
+ const r = await versionRemotaParalela({ timeoutMs: 10000 });
34
+ return r.version || VERSION_LOCAL;
35
+ }
36
+
37
+ /**
38
+ * Modo --check: muestra el estado actual sin actualizar. Read-only.
39
+ *
40
+ * Salida:
41
+ * - Version del paquete que esta ejecutando este CLI (VERSION_LOCAL).
42
+ * - Version mas reciente publicada en npm.
43
+ * - Comparacion semver: al dia / adelantado / atras.
44
+ * - Estado del hook check-update.js: ultima verificacion automatica.
45
+ * - Tabla por runtime instalado (si los detecta) con su versionSistema.
46
+ */
47
+ async function checkStatus() {
48
+ console.log(encabezado('swl-ses update --check', VERSION_LOCAL));
49
+
50
+ // Resolver version remota con timeout corto
51
+ const remota = await obtenerVersionRemota();
52
+ const cmp = compararSemver(VERSION_LOCAL, remota);
53
+
54
+ let estadoVersion;
55
+ if (cmp === null) {
56
+ estadoVersion = color.amarillo('Comparacion no disponible (formato inesperado)');
57
+ } else if (cmp === 0) {
58
+ estadoVersion = color.verde('Al dia');
59
+ } else if (cmp < 0) {
60
+ estadoVersion = color.amarillo(`Nueva version disponible (${remota})`);
61
+ } else {
62
+ estadoVersion = color.dim(`Local mas reciente que npm (${VERSION_LOCAL} > ${remota}, publicacion pendiente)`);
63
+ }
64
+
65
+ console.log(` Paquete ejecutado: ${color.negrita('v' + VERSION_LOCAL)}`);
66
+ console.log(` Version en npm: ${color.negrita('v' + remota)}`);
67
+ console.log(` Estado: ${estadoVersion}`);
68
+ console.log('');
69
+
70
+ // Estado del hook automatico (check-update.js).
71
+ // SWL_UPDATE_FLAG_PATH override solo para tests (evita race con flag único).
72
+ const flagPath = process.env.SWL_UPDATE_FLAG_PATH || path.join(os.tmpdir(), 'swl-ses-update-check.json');
73
+ try {
74
+ const flag = JSON.parse(fs.readFileSync(flagPath, 'utf8'));
75
+ const horas = ((Date.now() - flag.timestamp) / 3600000).toFixed(1);
76
+ console.log(` ${color.negrita('Hook automatico (check-update.js):')}`);
77
+ console.log(` Ultima verificacion: hace ${horas}h`);
78
+ console.log(` Local registrada: ${flag.local}`);
79
+ console.log(` Remota registrada: ${flag.remota || color.dim('(no resuelta)')}`);
80
+ console.log(` hayNueva: ${flag.hayNueva ? color.amarillo('si') : color.verde('no')}`);
81
+ console.log(` Flag: ${flagPath}`);
82
+ } catch {
83
+ console.log(` ${color.negrita('Hook automatico (check-update.js):')}`);
84
+ console.log(` ${color.dim('Sin flag de throttle — el hook nunca se ha ejecutado en este equipo,')}`);
85
+ console.log(` ${color.dim('o el archivo temp/swl-ses-update-check.json fue removido.')}`);
86
+ }
87
+ console.log('');
88
+
89
+ // Estado por runtime instalado
90
+ const runtimes = detectarRuntimes();
91
+ if (runtimes.length === 0) {
92
+ console.log(formatearAdvertencia('Runtimes', 'No se detectaron runtimes con instalacion SWL'));
93
+ console.log('');
94
+ return;
95
+ }
96
+
97
+ console.log(` ${color.negrita('Runtimes detectados:')}`);
98
+ let totalRuntimes = 0;
99
+ for (const runtime of runtimes) {
100
+ // Dedup + guard anti-fantasma (ver scopesReales): desde HOME el local
101
+ // colapsa con el global propio o con el de otro runtime.
102
+ for (const { dir, esGlobal } of scopesReales(runtime)) {
103
+ if (!fs.existsSync(dir)) continue;
104
+ const estado = cargarEstado(dir);
105
+ if (!estado) continue;
106
+
107
+ const ubicacion = esGlobal ? 'global' : 'proyecto';
108
+ const v = estado.versionSistema || 'desconocida';
109
+
110
+ const cmpRuntime = compararSemver(v, remota);
111
+ let etiqueta;
112
+ if (cmpRuntime === null) {
113
+ etiqueta = color.dim('(version no reconocida)');
114
+ } else if (cmpRuntime === 0) {
115
+ etiqueta = color.verde('al dia');
116
+ } else if (cmpRuntime < 0) {
117
+ etiqueta = color.amarillo(`atrasada (npm: ${remota})`);
118
+ } else {
119
+ etiqueta = color.dim('adelantada');
120
+ }
121
+
122
+ console.log(` ${runtime.nombre} (${ubicacion}): v${v} ${etiqueta}`);
123
+ totalRuntimes++;
124
+ }
125
+ }
126
+ if (totalRuntimes === 0) {
127
+ console.log(` ${color.dim('(ninguno con .swl-install-state.json valido)')}`);
128
+ }
129
+ console.log('');
130
+ console.log(` ${color.dim('Modo --check es read-only. Para actualizar:')} npx -y @saulwade/swl-ses@latest update`);
131
+ console.log('');
132
+ }
133
+
134
+ async function update(opciones) {
135
+ // Modo read-only: solo reportar estado, no tocar nada
136
+ if (opciones.check) {
137
+ await checkStatus();
138
+ return;
139
+ }
140
+
141
+ const force = opciones.force || !ES_TTY;
142
+
143
+ // Obtener la versión más reciente del registro npm
144
+ const VERSION = await obtenerVersionRemota();
145
+
146
+ console.log(encabezado('swl-ses update', VERSION_LOCAL));
147
+
148
+ // 1. Detectar runtimes
149
+ const runtimes = detectarRuntimes();
150
+
151
+ if (runtimes.length === 0) {
152
+ console.log(formatearAdvertencia('Runtimes', 'No se detectaron runtimes con instalación SWL'));
153
+ console.log(`\n Ejecuta primero: npx @saulwade/swl-ses@latest install --target claude`);
154
+ process.exit(1);
155
+ }
156
+
157
+ let actualizados = 0;
158
+ let omitidos = 0;
159
+
160
+ // 2. Iterar runtimes
161
+ for (const runtime of runtimes) {
162
+ // Dedup + guard anti-fantasma (ver scopesReales).
163
+ for (const { dir, esGlobal } of scopesReales(runtime)) {
164
+ if (!fs.existsSync(dir)) continue;
165
+
166
+ const estado = cargarEstado(dir);
167
+ if (!estado) continue;
168
+
169
+ const versionInstalada = estado.versionSistema || 'desconocida';
170
+ const ubicacion = esGlobal ? 'global' : 'proyecto';
171
+
172
+ const necesitaActualizar = versionInstalada !== VERSION;
173
+ const paqueteDesactualizado = VERSION_LOCAL !== VERSION;
174
+
175
+ console.log(` ${color.negrita(`Runtime: ${runtime.nombre}`)} ${color.dim(`(${ubicacion})`)}`);
176
+ console.log(` Versión instalada: ${necesitaActualizar ? color.amarillo(versionInstalada) : color.verde(versionInstalada)}`);
177
+ console.log(` Versión disponible: ${color.verde(VERSION)}${paqueteDesactualizado ? color.dim(` (ejecutando con v${VERSION_LOCAL})`) : ''}`);
178
+ console.log(` Perfil: ${estado.perfil}`);
179
+ console.log(` Componentes: ${estado.componentesInstalados.length}`);
180
+ console.log(` Archivos: ${estado.archivosInstalados.length}`);
181
+ console.log('');
182
+
183
+ // Si la versión disponible es más reciente pero el paquete ejecutándose es viejo,
184
+ // indicar al usuario que use @latest
185
+ if (paqueteDesactualizado && necesitaActualizar) {
186
+ console.log(formatearAdvertencia(runtime.nombre,
187
+ `Este paquete es v${VERSION_LOCAL} pero la v${VERSION} está disponible.\n` +
188
+ ` Para actualizar, ejecuta: npx @saulwade/swl-ses@latest update --force`));
189
+ console.log('');
190
+ omitidos++;
191
+ continue;
192
+ }
193
+
194
+ // Verificar si ya está actualizado
195
+ if (!necesitaActualizar && !force) {
196
+ console.log(formatearPaso(runtime.nombre, 'Ya está en la versión más reciente'));
197
+ console.log('');
198
+ omitidos++;
199
+ continue;
200
+ }
201
+
202
+ // Confirmar
203
+ if (!force) {
204
+ const confirmar = await preguntarSiNo(
205
+ !necesitaActualizar
206
+ ? `¿Re-instalar ${runtime.nombre} v${VERSION}?`
207
+ : `¿Actualizar ${runtime.nombre} de ${versionInstalada} a ${VERSION}?`
208
+ );
209
+ console.log('');
210
+
211
+ if (!confirmar) {
212
+ console.log(formatearAdvertencia(runtime.nombre, 'Actualización cancelada por el usuario'));
213
+ console.log('');
214
+ omitidos++;
215
+ continue;
216
+ }
217
+ }
218
+
219
+ // Ejecutar actualización con spinner
220
+ const sp = spinner(`Actualizando ${runtime.nombre}...`);
221
+
222
+ try {
223
+ const instalador = require('./instalador');
224
+ await instalador({
225
+ target: runtime.id,
226
+ profile: estado.perfil,
227
+ global: estado.global,
228
+ force: true,
229
+ });
230
+
231
+ sp.exito(`${runtime.nombre} actualizado a v${VERSION} (${estado.archivosInstalados.length} archivos)`);
232
+ actualizados++;
233
+ } catch (err) {
234
+ sp.fallo(`Error actualizando ${runtime.nombre}: ${err.message}`);
235
+ }
236
+
237
+ console.log('');
238
+ }
239
+ }
240
+
241
+ // 3. Reporte final
242
+ console.log(` ${lineaSeparadora()}`);
243
+ if (actualizados > 0) {
244
+ console.log(formatearPaso('Resultado', `${actualizados} runtime(s) actualizado(s)${omitidos > 0 ? `, ${omitidos} omitido(s)` : ''}`));
245
+ } else if (omitidos > 0) {
246
+ console.log(formatearPaso('Resultado', 'Todo está actualizado'));
247
+ } else {
248
+ console.log(formatearAdvertencia('Resultado', 'Ningún runtime fue actualizado'));
249
+ }
250
+ console.log('');
251
+ }
252
+
253
+ module.exports = update;
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env node
2
+ // Auditoría de relleno: cross-referencias de componentes SWL.
3
+ // Para cada skill/agente/comando cuenta las referencias de "cableado" desde
4
+ // otros componentes (agentes, comandos, reglas, hooks, scripts, contextos,
5
+ // otros skills). 0 referencias = huérfano operacional (candidato a relleno
6
+ // o a cablear). Una skill sin cableado sigue siendo invocable por descripción,
7
+ // así que el resultado es señal, no veredicto.
8
+ //
9
+ // Uso: node scripts/audit-tools/auditar-relleno-inventario.js [--json <ruta>]
10
+ // Output JSON por defecto: .planning/audit/relleno-crossref.json
11
+ 'use strict';
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ const REPO = path.resolve(__dirname, '..', '..');
16
+ const DIRS_EXCLUIDOS = ['node_modules', '.git', 'temp', 'respositorios-git', '_logs'];
17
+
18
+ function listarArchivos(dir, exts, out = []) {
19
+ if (!fs.existsSync(dir)) return out;
20
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
21
+ const p = path.join(dir, e.name);
22
+ if (e.isDirectory()) {
23
+ if (DIRS_EXCLUIDOS.includes(e.name)) continue;
24
+ listarArchivos(p, exts, out);
25
+ } else if (exts.some((x) => e.name.endsWith(x))) {
26
+ out.push(p);
27
+ }
28
+ }
29
+ return out;
30
+ }
31
+
32
+ // --- Inventario de componentes ---
33
+ const skills = fs.readdirSync(path.join(REPO, 'habilidades'), { withFileTypes: true })
34
+ .filter((e) => e.isDirectory() && fs.existsSync(path.join(REPO, 'habilidades', e.name, 'SKILL.md')))
35
+ .map((e) => e.name);
36
+
37
+ const agentes = fs.readdirSync(path.join(REPO, 'agentes'))
38
+ .filter((f) => f.endsWith('.md') && !f.startsWith('_'))
39
+ .map((f) => f.replace(/\.md$/, ''));
40
+
41
+ const comandos = fs.readdirSync(path.join(REPO, 'comandos', 'swl'))
42
+ .filter((f) => f.endsWith('.md'))
43
+ .map((f) => f.replace(/\.md$/, ''));
44
+
45
+ // --- Corpus de cableado (fuentes que "usan" componentes) ---
46
+ const archivosCableado = [
47
+ ...listarArchivos(path.join(REPO, 'agentes'), ['.md']),
48
+ ...listarArchivos(path.join(REPO, 'comandos'), ['.md']),
49
+ ...listarArchivos(path.join(REPO, 'reglas'), ['.md']),
50
+ ...listarArchivos(path.join(REPO, 'hooks'), ['.js']),
51
+ ...listarArchivos(path.join(REPO, 'scripts'), ['.js']),
52
+ ...listarArchivos(path.join(REPO, 'contextos'), ['.md']),
53
+ ...listarArchivos(path.join(REPO, 'habilidades'), ['.md']),
54
+ ];
55
+
56
+ const corpus = archivosCableado.map((f) => ({
57
+ file: f.replace(/\\/g, '/'),
58
+ text: fs.readFileSync(f, 'utf8'),
59
+ }));
60
+ const repoNorm = REPO.replace(/\\/g, '/') + '/';
61
+
62
+ function contarReferencias(nombre, fragmentosPropios) {
63
+ const re = new RegExp(`(?<![\\w/-])${nombre.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}(?![\\w-])`, 'g');
64
+ let refs = 0;
65
+ const referrers = new Set();
66
+ for (const { file, text } of corpus) {
67
+ if (fragmentosPropios.some((frag) => file.includes(frag))) continue;
68
+ const m = text.match(re);
69
+ if (m) {
70
+ refs += m.length;
71
+ referrers.add(file.replace(repoNorm, ''));
72
+ }
73
+ }
74
+ return { refs, referrers: [...referrers] };
75
+ }
76
+
77
+ // --- modulos.json: pertenencia a módulos ---
78
+ let componenteAModulo = {};
79
+ try {
80
+ const modulosRaw = JSON.parse(fs.readFileSync(path.join(REPO, 'manifiestos', 'modulos.json'), 'utf8'));
81
+ const modulosDef = modulosRaw.modulos || modulosRaw;
82
+ for (const [modName, mod] of Object.entries(modulosDef)) {
83
+ const comps = mod.componentes || mod.archivos || [];
84
+ for (const c of (Array.isArray(comps) ? comps : [])) {
85
+ const base = String(c).split('/').pop().replace(/\.md$/, '');
86
+ componenteAModulo[base] = modName;
87
+ const parts = String(c).split('/');
88
+ if (parts[0] === 'habilidades' && parts[1]) componenteAModulo[parts[1]] = modName;
89
+ }
90
+ }
91
+ } catch (err) {
92
+ console.warn(`[auditar-relleno] No se pudo leer manifiestos/modulos.json: ${err.message}`);
93
+ }
94
+
95
+ // Uso REAL (telemetría del hook telemetria-skill-routing.js → skill-metrics).
96
+ // El cableado estático dice quién PODRÍA invocar una skill; esta señal dice
97
+ // quién la invocó de verdad. Sin datos (proyecto sin sesiones), usos = null.
98
+ let usosPorSkill = null;
99
+ try {
100
+ const { obtenerMetricas } = require(path.join(REPO, 'scripts', 'lib', 'skill-metrics.js'));
101
+ const lista = obtenerMetricas(REPO); // [{skill, total, ok, error, ...}]
102
+ if (Array.isArray(lista) && lista.length > 0) {
103
+ usosPorSkill = Object.fromEntries(lista.map(m => [m.skill, m]));
104
+ }
105
+ } catch (err) {
106
+ console.warn(`[auditar-relleno] telemetría de uso no disponible: ${err.message}`);
107
+ }
108
+
109
+ const reporte = { generado: null, conUsoReal: Boolean(usosPorSkill), skills: [], agentes: [], comandos: [] };
110
+
111
+ for (const s of skills) {
112
+ const { refs, referrers } = contarReferencias(s, [`habilidades/${s}/`]);
113
+ const uso = usosPorSkill ? (usosPorSkill[s] ? usosPorSkill[s].total : 0) : null;
114
+ reporte.skills.push({ name: s, refs, usos: uso, modulo: componenteAModulo[s] || '?', referrers: referrers.slice(0, 8) });
115
+ }
116
+ for (const a of agentes) {
117
+ const { refs, referrers } = contarReferencias(a, [`agentes/${a}.md`]);
118
+ reporte.agentes.push({ name: a, refs, modulo: componenteAModulo[a] || '?', referrers: referrers.slice(0, 8) });
119
+ }
120
+ for (const c of comandos) {
121
+ const { refs, referrers } = contarReferencias(`swl:${c}`, [`comandos/swl/${c}.md`]);
122
+ reporte.comandos.push({ name: c, refs, modulo: componenteAModulo[c] || '?', referrers: referrers.slice(0, 8) });
123
+ }
124
+
125
+ for (const key of ['skills', 'agentes', 'comandos']) reporte[key].sort((x, y) => x.refs - y.refs);
126
+
127
+ const idxJson = process.argv.indexOf('--json');
128
+ const outPath = idxJson > -1 && process.argv[idxJson + 1]
129
+ ? path.resolve(process.argv[idxJson + 1])
130
+ : path.join(REPO, '.planning', 'audit', 'relleno-crossref.json');
131
+ fs.writeFileSync(outPath, JSON.stringify(reporte, null, 2));
132
+
133
+ console.log(`Skills: ${skills.length} | Agentes: ${agentes.length} | Comandos: ${comandos.length}`);
134
+ console.log(usosPorSkill
135
+ ? `Telemetría de uso real: ${Object.keys(usosPorSkill).length} skills con invocaciones registradas (columna usos=)`
136
+ : 'Telemetría de uso real: sin datos (.planning/skill-metrics.json vacío — el hook telemetria-skill-routing la alimenta con el uso)');
137
+ const huerfanas = reporte.skills.filter((s) => s.refs === 0);
138
+ console.log(`\n=== SKILLS con 0 referencias de cableado (${huerfanas.length}) ===`);
139
+ for (const s of huerfanas) console.log(` ${s.name} [${s.modulo}]`);
140
+ const bajas = reporte.skills.filter((s) => s.refs >= 1 && s.refs <= 2);
141
+ console.log(`\n=== SKILLS con 1-2 referencias (${bajas.length}) ===`);
142
+ for (const s of bajas) console.log(` ${s.name} [${s.modulo}] refs=${s.refs} <- ${s.referrers.join(', ')}`);
143
+ console.log('\n=== AGENTES con 0-2 referencias ===');
144
+ for (const a of reporte.agentes.filter((x) => x.refs <= 2)) console.log(` ${a.name} refs=${a.refs} <- ${a.referrers.join(', ')}`);
145
+ console.log(`\nJSON completo: ${outPath}`);