@saulwade/swl-ses 1.8.0 → 2.0.0

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 (135) hide show
  1. package/CLAUDE.md +8 -8
  2. package/README.md +13 -13
  3. package/agentes/accesibilidad-wcag-swl.md +3 -3
  4. package/agentes/auto-evolucion-swl.md +908 -908
  5. package/agentes/disenador-ui-swl.md +6 -5
  6. package/agentes/frontend-angular-swl.md +2 -2
  7. package/agentes/frontend-css-swl.md +2 -2
  8. package/agentes/frontend-react-swl.md +4 -4
  9. package/agentes/frontend-swl.md +6 -6
  10. package/agentes/investigador-ux-swl.md +5 -5
  11. package/agentes/orquestador-swl.md +96 -8
  12. package/agentes/perfilador-usuario-swl.md +308 -308
  13. package/agentes/producto-prd-swl.md +1 -1
  14. package/agentes/red-team-swl.md +218 -218
  15. package/agentes/revisor-codigo-swl.md +34 -10
  16. package/agentes/revisor-seguridad-swl.md +7 -0
  17. package/agentes/tdd-qa-swl.md +39 -2
  18. package/comandos/swl/actualizar.md +1 -1
  19. package/comandos/swl/aprender.md +2 -2
  20. package/comandos/swl/aprobar-plan.md +152 -0
  21. package/comandos/swl/autoresearch.md +102 -6
  22. package/comandos/swl/ayuda.md +3 -3
  23. package/comandos/swl/discutir-fase.md +20 -2
  24. package/comandos/swl/ejecutar-fase.md +53 -6
  25. package/comandos/swl/evolucionar.md +1 -1
  26. package/comandos/swl/inbox.md +1 -1
  27. package/comandos/swl/instalar.md +1 -1
  28. package/comandos/swl/nemesis.md +42 -1
  29. package/comandos/swl/planear-fase.md +25 -1
  30. package/comandos/swl/plugins.md +1 -1
  31. package/comandos/swl/predecir.md +139 -0
  32. package/comandos/swl/release.md +1 -1
  33. package/comandos/swl/status.md +279 -0
  34. package/comandos/swl/verificar.md +75 -7
  35. package/habilidades/ai-runtime-security/SKILL.md +1 -1
  36. package/habilidades/angular-moderno/SKILL.md +44 -1
  37. package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -276
  38. package/habilidades/autoresearch/SKILL.md +15 -1
  39. package/habilidades/benchmark-memoria/SKILL.md +1 -1
  40. package/habilidades/calidad-contract-testing/SKILL.md +165 -0
  41. package/habilidades/calidad-mutation-testing/SKILL.md +170 -0
  42. package/habilidades/changelog-generator/SKILL.md +9 -2
  43. package/habilidades/changelog-generator/scripts/parse-commits.js +12 -1
  44. package/habilidades/checklist-seguridad/SKILL.md +29 -1
  45. package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -0
  46. package/habilidades/css-moderno/SKILL.md +3 -1
  47. package/habilidades/diagrama-arquitectura/SKILL.md +1 -1
  48. package/habilidades/drift-detection/SKILL.md +179 -179
  49. package/habilidades/ejecutar-fase/SKILL.md +64 -14
  50. package/habilidades/estructura-proyecto-claude/SKILL.md +17 -14
  51. package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +34 -23
  52. package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +70 -53
  53. package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -77
  54. package/habilidades/extractor-de-aprendizajes/SKILL.md +9 -5
  55. package/habilidades/fastapi-experto/SKILL.md +56 -5
  56. package/habilidades/harness-claude-code/SKILL.md +10 -7
  57. package/{reglas/harness-claude-code.md → habilidades/harness-claude-code/recursos/disciplina-harness-regla.md} +2 -2
  58. package/habilidades/instalar-sistema/SKILL.md +3 -3
  59. package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +1 -1
  60. package/habilidades/patrones-python/SKILL.md +8 -5
  61. package/habilidades/perfil-usuario/SKILL.md +200 -200
  62. package/habilidades/planear-fase/SKILL.md +25 -4
  63. package/habilidades/proceso-ddia-fundamentos/SKILL.md +1 -1
  64. package/habilidades/proceso-ddia-streaming/SKILL.md +4 -4
  65. package/habilidades/proceso-debate-adversarial/SKILL.md +164 -0
  66. package/habilidades/proceso-debate-adversarial/recursos/personas.md +105 -0
  67. package/habilidades/proceso-dynamic-workflows/SKILL.md +138 -0
  68. package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -0
  69. package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -0
  70. package/habilidades/protocolo-revision-swl/SKILL.md +1 -1
  71. package/habilidades/seguridad-skills-ia/SKILL.md +1 -1
  72. package/habilidades/swl-claudemd/SKILL.md +50 -210
  73. package/habilidades/swl-claudemd/recursos/contrato-aprender.md +83 -0
  74. package/habilidades/swl-claudemd/recursos/duplicacion-reglas-globales.md +85 -0
  75. package/habilidades/swl-claudemd/recursos/plantillas-init.md +94 -0
  76. package/habilidades/swl-dashboard/SKILL.md +9 -9
  77. package/habilidades/swl-revisar-impacto/SKILL.md +1 -1
  78. package/habilidades/tdd-workflow/SKILL.md +58 -5
  79. package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -0
  80. package/habilidades/validacion-ci-sistema/SKILL.md +3 -3
  81. package/hooks/calidad-pre-commit.js +340 -3
  82. package/hooks/ciclo-evolucion-subagente.js +26 -0
  83. package/hooks/ciclo-evolucion.js +26 -0
  84. package/hooks/contexto-iteracion.js +144 -0
  85. package/hooks/extraccion-aprendizajes.js +13 -0
  86. package/hooks/lib/ciclo-evolucion.js +47 -0
  87. package/hooks/{auto-evolucion.js → lib/etapa-auto-evolucion.js} +701 -700
  88. package/hooks/{metricas-evolucion.js → lib/etapa-metricas.js} +388 -376
  89. package/hooks/{actualizar-perfil-usuario.js → lib/etapa-perfil-usuario.js} +376 -364
  90. package/hooks/lib/evolution-tracker.js +24 -3
  91. package/hooks/lib/loop-telemetry.js +321 -0
  92. package/hooks/notificacion-telegram.js +11 -3
  93. package/hooks/spec-gate.js +211 -0
  94. package/hooks/tdd-gate.js +241 -0
  95. package/hooks/validar-intent-spec.js +30 -10
  96. package/llms.txt +29 -0
  97. package/manifiestos/hooks-config.json +36 -18
  98. package/manifiestos/modulos.json +23 -14
  99. package/manifiestos/skills-lock.json +100 -72
  100. package/package.json +4 -3
  101. package/plugin.json +9 -10
  102. package/reglas/accesibilidad.md +10 -0
  103. package/reglas/api-diseno.md +9 -0
  104. package/reglas/arquitectura.evolved.json +7 -0
  105. package/reglas/arquitectura.md +65 -0
  106. package/reglas/auditorias-documentales-estructurales.md +7 -0
  107. package/reglas/cloud-infra.md +8 -0
  108. package/reglas/fragmentos-compartidos.md +5 -0
  109. package/reglas/gobernanza.md +4 -4
  110. package/reglas/hooks.md +6 -0
  111. package/reglas/intent-engineering.md +4 -0
  112. package/reglas/markitdown.md +8 -0
  113. package/reglas/memoria-consolidada.md +1 -1
  114. package/reglas/patrones.md +6 -0
  115. package/reglas/registro-componentes-nuevos.md +10 -1
  116. package/reglas/seguridad-agentes.md +1 -1
  117. package/reglas/seguridad.evolved.json +7 -0
  118. package/reglas/seguridad.md +144 -0
  119. package/reglas/skills-estandar.md +6 -0
  120. package/reglas/testing.md +7 -0
  121. package/reglas/tests-cleanup.md +4 -0
  122. package/reglas/usar-sistema-swl.md +1 -1
  123. package/scripts/generar-inventario.js +64 -1
  124. package/scripts/instalador.js +32 -2
  125. package/scripts/lib/gitignore-manifest.js +29 -1
  126. package/scripts/lib/plan-lock.js +275 -0
  127. package/scripts/migrar-fase-dominio.js +0 -1
  128. package/scripts/smoke-test.js +24 -2
  129. package/scripts/verificar-trazabilidad.js +292 -0
  130. package/agentes/ux-disenador-swl.md +0 -503
  131. package/comandos/swl/dashboard.md +0 -146
  132. package/comandos/swl/evolucion-estado.md +0 -191
  133. package/comandos/swl/metricas.md +0 -342
  134. package/comandos/swl/salud.md +0 -481
  135. package/reglas/verificar-citas-temporales.md +0 -139
@@ -160,7 +160,7 @@ const conFeedback = applyFeedback(instinto, 'helpful');
160
160
  ```
161
161
 
162
162
  **Cuándo recomputar**:
163
- - `/swl:salud` reporta instintos con `effective_confidence < 0.3` para revisión.
163
+ - `/swl:status salud` reporta instintos con `effective_confidence < 0.3` para revisión.
164
164
  - `hooks/degradacion-instintos.js` puede marcar `status_proposed: degraded`
165
165
  cuando `shouldAutoDeprecate(instinto)` devuelve `true`.
166
166
  - `bootstrap-instintos.js` emite los nuevos instintos con `decay_half_life_days: 90`,
@@ -1,3 +1,9 @@
1
+ ---
2
+ paths:
3
+ - "**/*.tsx"
4
+ - "**/*.jsx"
5
+ - "**/next.config.{js,mjs,ts}"
6
+ ---
1
7
  # Regla: Patrones de Arquitectura — Next.js (App Router)
2
8
 
3
9
  El App Router de Next.js cambia fundamentalmente dónde y cómo se cargan datos.
@@ -1,3 +1,12 @@
1
+ ---
2
+ paths:
3
+ - "**/manifiestos/**"
4
+ - "**/agentes/**"
5
+ - "**/habilidades/**"
6
+ - "**/comandos/**"
7
+ - "**/hooks/**"
8
+ - "**/plugin.json"
9
+ ---
1
10
  # Regla: Registro obligatorio de componentes nuevos en manifiestos
2
11
 
3
12
  Esta regla es OBLIGATORIA para el proyecto **@saulwade/swl-ses**. Aplica
@@ -26,7 +35,7 @@ propagación de cambios" del `CLAUDE.md` del proyecto.
26
35
 
27
36
  El costo de registrar es ~30 segundos por componente (3 archivos a editar
28
37
  + un comando de regeneración). El costo de no registrar es: instalador roto
29
- para usuarios del paquete público, `npm run test:all` falla, `/swl:salud`
38
+ para usuarios del paquete público, `npm run test:all` falla, `/swl:status salud`
30
39
  reporta degradación, deuda acumulada difícil de detectar tras varios commits.
31
40
 
32
41
  ---
@@ -335,7 +335,7 @@ Precedente: ADR-0002 (skills) y ADR-0004 (agentes). Agregar Exclusion a un agent
335
335
 
336
336
  ### Auditoría
337
337
 
338
- `scripts/auditar-agentes-gaps.js` reporta cobertura. Integración con `/swl:salud`
338
+ `scripts/auditar-agentes-gaps.js` reporta cobertura. Integración con `/swl:status salud`
339
339
  mediante `SWL_AUDIT_AGENTES=1` (paso 5d).
340
340
 
341
341
  ### Ejemplo de frontmatter
@@ -0,0 +1,7 @@
1
+ {
2
+ "evolved": true,
3
+ "evolved-from": "1.8.0",
4
+ "evolved-at": "2026-06-04",
5
+ "evolved-by": "evolucionar",
6
+ "evolved-note": "PE-003 (verificación de flags antes de asumir servicios externos LDAP/Redis/S3) + PE-004 (sanitización PII centralizada en handlers) + PE-007 (generación de passwords legibles sin chars ambiguos). Origen: OIC v1.5 2026-06-04, bug histórico manuel.monteagudo + Slice 2 v1.5 Observabilidad."
7
+ }
@@ -141,6 +141,147 @@ vulnerabilidad del OWASP Top 10. Las más frecuentes en este stack:
141
141
 
142
142
  ---
143
143
 
144
+ ## Verificación obligatoria de flags de configuración antes de asumir servicios externos
145
+
146
+ Toda rama de código que asuma un servicio externo opcional (LDAP, Redis, S3, SMTP,
147
+ OIDC, Auth0, etc.) DEBE verificar el flag de configuración del proyecto ANTES de
148
+ tomar la decisión. Sin esta verificación, una configuración no esperada deja a los
149
+ usuarios atrapados en flujos rotos sin error visible.
150
+
151
+ **Anti-patrón** (caso real OIC 2026-06-04, dos bugs históricos en el mismo flujo):
152
+
153
+ ```python
154
+ # MAL — asume LDAP siempre habilitado
155
+ if rol == "ADMIN":
156
+ hashed = hash_password(body.password)
157
+ else:
158
+ # "Para usuarios LDAP, no se almacena contraseña funcional local."
159
+ hashed = hash_password(uuid.uuid4().hex)
160
+ # ↑ Si AUTH_LDAP_ENABLED=false (caso real), el usuario queda con un hash
161
+ # UUID dummy que ninguna password real puede igualar → 401 perpetuo.
162
+ ```
163
+
164
+ ```python
165
+ # MAL — rechaza no-ADMIN sin verificar si LDAP existe siquiera
166
+ if rol != "ADMIN":
167
+ raise HTTPException(400, "Los usuarios no ADMIN gestionan su contraseña en LDAP")
168
+ # ↑ Sin LDAP habilitado los usuarios no tienen forma de cambiar password.
169
+ ```
170
+
171
+ **Patrón correcto**:
172
+
173
+ ```python
174
+ # BIEN — siempre verifica el flag antes de asumir el servicio
175
+ if rol == "ADMIN":
176
+ hashed = hash_password(body.password)
177
+ else:
178
+ if body.password:
179
+ hashed = hash_password(body.password)
180
+ elif not settings.AUTH_LDAP_ENABLED:
181
+ # Sin LDAP: generar password funcional para que el usuario pueda entrar
182
+ temp = _generar_temp_password()
183
+ hashed = hash_password(temp)
184
+ # devolver `temp` en la respuesta del POST UNA SOLA VEZ
185
+ else:
186
+ # LDAP habilitado: dummy OK porque el usuario se autentica fuera
187
+ hashed = hash_password(uuid.uuid4().hex)
188
+ ```
189
+
190
+ **Detección temprana en code review**: cualquier comentario `"para LDAP"`,
191
+ `"para Redis"`, `"para S3"` debe acompañarse del check del flag correspondiente.
192
+ Si el comentario está solo, es bug latente — el código asume un mundo que el
193
+ deployment puede no tener.
194
+
195
+ ---
196
+
197
+ ## Sanitización PII centralizada en handlers vs refactorear N sitios
198
+
199
+ Cuando un sistema persiste logs estructurados (audit trails, error logs,
200
+ telemetría) y existen N sitios donde el código emite `logger.error(..., extra={...})`
201
+ con potencial PII en los valores, **siempre preferir sanitización centralizada en
202
+ el handler** sobre refactorear cada sitio individualmente.
203
+
204
+ **Decisión arquitectónica** (caso OIC v1.5 Slice 2, 2026-06-04):
205
+
206
+ | Opción | Esfuerzo | Cobertura futura | Mantenimiento |
207
+ |---|---|---|---|
208
+ | Refactorear N sitios uno por uno | O(N) turnos | Solo lo refactorizado | Cada `logger.error` nuevo requiere auditoría |
209
+ | Sanitización centralizada en handler | O(1) turno | Todos los sitios + futuros automáticamente | Cero auditoría manual al agregar nuevos `logger.error` |
210
+
211
+ **Patrón portable**:
212
+
213
+ ```python
214
+ import re
215
+
216
+ _PATRON_SENSIBLE = re.compile(
217
+ r'(password|token|secret|jwt|authorization|cookie|api[_-]?key)([=:])([^&\s"\']+)',
218
+ re.IGNORECASE,
219
+ )
220
+
221
+ def sanitizar_url(url: str | None) -> str | None:
222
+ """Redacta query-params sensibles preservando key y separador."""
223
+ if not url:
224
+ return url
225
+ return _PATRON_SENSIBLE.sub(r"\1\2<redacted>", url)
226
+
227
+ def sanitizar_valor(valor: Any) -> Any:
228
+ """Sanitiza recursivamente strings dentro de dict/list/tuple."""
229
+ if isinstance(valor, str):
230
+ return _PATRON_SENSIBLE.sub(r"\1\2<redacted>", valor)
231
+ if isinstance(valor, dict):
232
+ return {k: sanitizar_valor(v) for k, v in valor.items()}
233
+ if isinstance(valor, (list, tuple)):
234
+ return [sanitizar_valor(item) for item in valor]
235
+ return valor
236
+ ```
237
+
238
+ **Regla del regex**:
239
+ - Grupo 1 (key) y grupo 2 (`=` o `:`) se preservan → mantiene legibilidad
240
+ (`password=<redacted>` en vez de `<redacted>`).
241
+ - Grupo 3 (valor) se reemplaza por `<redacted>`.
242
+ - Boundary del valor: `&`, whitespace, comilla, paréntesis.
243
+ - `api_key` y `api-key` ambos matchean con `api[_-]?key`.
244
+
245
+ **Aplicabilidad**: handlers de logging custom, middleware HTTP que redactan headers,
246
+ sanitización de cookies en logs, redactor de stack traces, error reporters
247
+ (Sentry-style). Defensa en profundidad sin tocar el código del caller.
248
+
249
+ **Limitación documentada**: el regex opera sobre strings; NO sanitiza claves cuyo
250
+ nombre no esté en la lista (no detecta `contraseña` en español, `pwd`, `mot_de_passe`).
251
+ Mantener el regex extensible vía configuración si el proyecto opera en múltiples idiomas.
252
+
253
+ ---
254
+
255
+ ## Generación de tokens y passwords legibles (sin caracteres ambiguos)
256
+
257
+ Para passwords temporales (reset por admin, primer login, recuperación) que el
258
+ usuario debe transcribir verbalmente o desde papel, usar alfabeto SIN caracteres
259
+ ambiguos: `0` (cero) vs `O` (o mayúscula), `1` (uno) vs `l` (L minúscula) vs `I`
260
+ (i mayúscula).
261
+
262
+ ```python
263
+ import secrets
264
+
265
+ # 54 chars del alfabeto seguro (sin 0, O, 1, l, I)
266
+ _ALFABETO_LEGIBLE = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"
267
+
268
+ def generar_password_temporal(longitud: int = 12) -> str:
269
+ """12 chars → ~71 bits de entropía. Suficiente para temporal que debe
270
+ cambiarse en primer login. NUNCA persistir en texto plano; el caller
271
+ la hashea con bcrypt y la devuelve UNA SOLA VEZ en la respuesta del POST."""
272
+ return "".join(secrets.choice(_ALFABETO_LEGIBLE) for _ in range(longitud))
273
+ ```
274
+
275
+ **NO usar** `secrets.token_urlsafe()` para passwords visibles al humano: incluye
276
+ `-` y `_` que pueden confundir al transcribir. Reservar `token_urlsafe()` para
277
+ tokens de sesión, CSRF, magic links — strings que no se leen ni transcriben.
278
+
279
+ **Para tokens de uso programático** (API keys, session IDs, refresh tokens):
280
+ `secrets.token_urlsafe(32)` (32 bytes → 256 bits) o `secrets.token_hex(32)`. Sin
281
+ restricción de alfabeto porque el usuario nunca los teclea manualmente.
282
+
283
+ ---
284
+
144
285
  ## Checklist antes de merge a main
145
286
 
146
287
  - [ ] No hay secrets hardcodeados (revisar con `git grep -i "password\|secret\|token\|key"`)
@@ -149,3 +290,6 @@ vulnerabilidad del OWASP Top 10. Las más frecuentes en este stack:
149
290
  - [ ] Sin uso de `eval`, `exec`, `shell=True`
150
291
  - [ ] Logs sin datos sensibles
151
292
  - [ ] Dependencias nuevas auditadas
293
+ - [ ] Cualquier rama que asuma servicio externo (LDAP/Redis/S3) verifica su flag de config
294
+ - [ ] Sanitización PII centralizada en handlers (no diseminada por N sitios)
295
+ - [ ] Passwords temporales generadas con alfabeto sin chars ambiguos
@@ -1,3 +1,9 @@
1
+ ---
2
+ paths:
3
+ - "**/habilidades/**"
4
+ - "**/skills/**"
5
+ - "**/_userland/**"
6
+ ---
1
7
  # Regla: Estándar Oficial de Claude Agent Skills para el Sistema SWL
2
8
 
3
9
  **Aplica a**: Toda skill nueva o modificada en `habilidades/` y `skills/`
package/reglas/testing.md CHANGED
@@ -1,3 +1,10 @@
1
+ ---
2
+ paths:
3
+ - "**/*.tsx"
4
+ - "**/*.jsx"
5
+ - "**/vitest.config.{js,ts,mjs}"
6
+ - "**/playwright.config.{js,ts}"
7
+ ---
1
8
  # Regla: Testing — Next.js
2
9
 
3
10
  Probar Next.js con App Router requiere estrategia porque existen tres tipos de
@@ -1,3 +1,7 @@
1
+ ---
2
+ paths:
3
+ - "**/tests/**"
4
+ ---
1
5
  # Regla: Cleanup obligatorio de directorios temporales en tests
2
6
 
3
7
  Esta regla es **OBLIGATORIA** y aplica a todo test Node.js del sistema SWL
@@ -78,7 +78,7 @@ de ejecutar.
78
78
  | Capturar aprendizaje recurrente | `/swl:aprender` → APRENDIZAJES.md → posible promoción a regla/skill |
79
79
  | Release con bump de versión | `/swl:release` (sincronización de ubicaciones de versión) |
80
80
  | Documentación viva post-feature | `documentador-swl` |
81
- | Diagnóstico del sistema | `/swl:salud` |
81
+ | Diagnóstico del sistema | `/swl:status salud` |
82
82
 
83
83
  ### Para tareas de búsqueda y contexto
84
84
 
@@ -33,7 +33,8 @@ const args = new Set(process.argv.slice(2));
33
33
  const DRY = args.has('--dry-run');
34
34
  const SOLO_INV = args.has('--inventario');
35
35
  const SOLO_SAL = args.has('--salud');
36
- const AMBOS = !SOLO_INV && !SOLO_SAL;
36
+ const SOLO_LLMS = args.has('--llms');
37
+ const AMBOS = !SOLO_INV && !SOLO_SAL && !SOLO_LLMS;
37
38
 
38
39
  // ── Helpers ────────────────────────────────────────────────────────────
39
40
 
@@ -427,6 +428,57 @@ function generarSalud() {
427
428
  return lines.join('\n');
428
429
  }
429
430
 
431
+ // ── llms.txt (convención llmstxt.org) ─────────────────────────────────
432
+ // Índice raíz LLM-legible para descubrimiento externo por herramientas/agentes
433
+ // que esperan el estándar. Cifras sincronizadas con INVENTARIO (mismo cómputo)
434
+ // para que el gate de release no detecte drift. Adoptado de obsidian-second-brain
435
+ // (análisis temp/ 2026-06-05); el resto de ese repo era redundante con swl-ses.
436
+ function generarLlmsTxt() {
437
+ const pkg = JSON.parse(fs.readFileSync(path.join(RAIZ, 'package.json'), 'utf8'));
438
+ const agentes = recolectarAgentes().length;
439
+ const skills = recolectarSkills().length;
440
+ const hooks = recolectarHooks().length;
441
+ const comandos = contarArchivos(path.join(RAIZ, 'comandos', 'swl'), '.md');
442
+ const reglasBase = contarArchivos(path.join(RAIZ, 'reglas'), '.md');
443
+ const reglasLang = fs.readdirSync(path.join(RAIZ, 'reglas', 'lenguajes'))
444
+ .filter(d => fs.statSync(path.join(RAIZ, 'reglas', 'lenguajes', d)).isDirectory())
445
+ .reduce((acc, d) => acc + contarArchivos(path.join(RAIZ, 'reglas', 'lenguajes', d), '.md'), 0);
446
+
447
+ const L = [];
448
+ L.push('# swl-ses (@saulwade/swl-ses)');
449
+ L.push('');
450
+ L.push(`> Sistema de ingeniería de software auto-evolutivo multi-runtime polyglot (SDLC completo), distribuido como paquete npm y plugin de Claude Code. ${agentes} agentes, ${skills} habilidades, ${comandos} comandos, ${reglasBase} reglas base y ${hooks} hooks. Soporta 11 lenguajes y 7 runtimes (Claude Code, OpenClaude, OpenCode, Gemini, Cursor, Codex, Copilot). Versión ${pkg.version}.`);
451
+ L.push('');
452
+ L.push('Archivo generado por `node scripts/generar-inventario.js` — no editar a mano. Las cifras se sincronizan con INVENTARIO.md en cada regeneración.');
453
+ L.push('');
454
+ L.push('## Documentación');
455
+ L.push('');
456
+ L.push('- [README](README.md): overview público y quickstart');
457
+ L.push('- [Manual de uso](MANUAL_USO.md): manual operacional completo');
458
+ L.push('- [Comandos](COMANDOS.md): referencia detallada de cada comando `/swl:*`');
459
+ L.push('- [Agentes](AGENTS.md): catálogo de agentes con capacidades');
460
+ L.push('- [Inventario](INVENTARIO.md): conteos oficiales de todos los componentes');
461
+ L.push('- [Instalación](INSTALACION.md): instalación, perfiles y configuración');
462
+ L.push('- [Instrucciones del proyecto](CLAUDE.md): convenciones, stack y reglas');
463
+ L.push('');
464
+ L.push('## Componentes');
465
+ L.push('');
466
+ L.push(`- ${agentes} agentes especializados en \`agentes/\` (orquestación, implementación por stack, revisión, calidad, diseño)`);
467
+ L.push(`- ${skills} habilidades cargables bajo demanda en \`habilidades/\` (conocimiento operacional con divulgación progresiva)`);
468
+ L.push(`- ${comandos} comandos \`/swl:*\` en \`comandos/swl/\` (ciclo GSD, calidad, release, diagnóstico)`);
469
+ L.push(`- ${reglasBase} reglas base + ${reglasLang} reglas por lenguaje en \`reglas/\` (políticas obligatorias por matcher)`);
470
+ L.push(`- ${hooks} hooks en \`hooks/\` (telemetría, validación, seguridad; zero-deps, escrituras atómicas)`);
471
+ L.push('');
472
+ L.push('## Opcional');
473
+ L.push('');
474
+ L.push('- [CHANGELOG](CHANGELOG.md): historial de versiones');
475
+ L.push('- [Índice de ADRs](.planning/adrs/README.md): decisiones de arquitectura');
476
+ L.push('- [Variables de entorno](docs/variables-entorno.md): configuración opt-in');
477
+ L.push('');
478
+
479
+ return L.join('\n');
480
+ }
481
+
430
482
  // ── Ejecutar ──────────────────────────────────────────────────────────
431
483
 
432
484
  if (AMBOS || SOLO_INV) {
@@ -450,3 +502,14 @@ if (AMBOS || SOLO_SAL) {
450
502
  console.log('SALUD.md generado correctamente.');
451
503
  }
452
504
  }
505
+
506
+ if (AMBOS || SOLO_LLMS) {
507
+ const llms = generarLlmsTxt();
508
+ if (DRY) {
509
+ console.log('\n=== llms.txt (dry-run) ===\n');
510
+ console.log(llms);
511
+ } else {
512
+ atomicWriteSync(path.join(RAIZ, 'llms.txt'), llms, 'utf8');
513
+ console.log('llms.txt generado correctamente.');
514
+ }
515
+ }
@@ -210,10 +210,30 @@ async function install(opciones) {
210
210
  // 2b. Filtrar reglas de lenguaje por stack detectado
211
211
  // El stack se detecta siempre que: hay reglas de lenguaje en el perfil, O
212
212
  // se ejecuta con --force (actualización) para poder limpiar las ya instaladas.
213
+ // FIX (thrashing de contexto en subagentes): en scope GLOBAL las reglas
214
+ // por-lenguaje NO se instalan en ~/.claude/rules/. Global no tiene un proyecto
215
+ // que detectar, así que se instalarían los 8 lenguajes (~69K tokens) y
216
+ // saturarían la ventana de todo subagente que herede ~/.claude/rules/. Las
217
+ // reglas por-lenguaje viven project-scoped, donde el stack-filter sí aplica.
218
+ if (esGlobal) {
219
+ const antesGlobal = resolucion.archivos.length;
220
+ resolucion.archivos = resolucion.archivos.filter(
221
+ a => !(a.rutaRelativa && a.rutaRelativa.startsWith('reglas/lenguajes/'))
222
+ );
223
+ const excluidasGlobal = antesGlobal - resolucion.archivos.length;
224
+ if (excluidasGlobal > 0) {
225
+ console.log(
226
+ `\n[stack] Scope global: ${excluidasGlobal} regla(s) por-lenguaje excluidas ` +
227
+ '(se instalan project-scoped, filtradas por stack; no en ~/.claude/rules/ ' +
228
+ 'para no saturar el contexto de subagentes).'
229
+ );
230
+ }
231
+ }
232
+
213
233
  const tieneReglasLenguaje = resolucion.archivos.some(
214
234
  a => a.rutaRelativa && a.rutaRelativa.startsWith('reglas/lenguajes/')
215
235
  );
216
- const necesitaStack = (tieneReglasLenguaje || force) && !allLangs;
236
+ const necesitaStack = (tieneReglasLenguaje || force) && !allLangs && !esGlobal;
217
237
 
218
238
  let stackDetectado = null;
219
239
 
@@ -224,7 +244,7 @@ async function install(opciones) {
224
244
  // FIX v1.6.6: si el usuario pasa --all-langs pero el perfil actual no incluye
225
245
  // reglas/lenguajes/, el flag se ignora silenciosamente. Antes la única pista
226
246
  // era el conteo final de archivos. Ahora emitimos warning explícito.
227
- if (allLangs && !tieneReglasLenguaje) {
247
+ if (allLangs && !tieneReglasLenguaje && !esGlobal) {
228
248
  console.log(
229
249
  '\n[stack] Aviso: --all-langs ignorado — el perfil actual (' +
230
250
  (resolucion.perfil || 'core') +
@@ -269,6 +289,16 @@ async function install(opciones) {
269
289
  }
270
290
  }
271
291
 
292
+ // Scope global: purgar TODAS las reglas por-lenguaje preexistentes de
293
+ // ~/.claude/rules/ (instalaciones previas dejaban los 8 lenguajes always-loaded,
294
+ // saturando el contexto de subagentes). Corre en cada install global, no solo --force.
295
+ if (esGlobal && rutas.reglas) {
296
+ const purgaGlobal = limpiarReglasSinStack(rutas.reglas, new Set());
297
+ if (purgaGlobal.eliminados > 0) {
298
+ console.log(`\n[stack] Scope global: ${purgaGlobal.eliminados} subdir(s) de reglas por-lenguaje purgadas de ~/.claude/rules/ (${purgaGlobal.lenguajes.join(', ')}) — viven project-scoped.`);
299
+ }
300
+ }
301
+
272
302
  // 4. Detectar _userland/
273
303
  const userlandAgentes = path.join(process.cwd(), '_userland', 'agentes');
274
304
  const userlandHabilidades = path.join(process.cwd(), '_userland', 'habilidades');
@@ -79,7 +79,13 @@ const ENTRADAS_BASE = [
79
79
  // artefactos del proyecto usuario.
80
80
  ".planning/evolution/",
81
81
  ".planning/auto-evolution/",
82
- ".planning/locks/",
82
+ // locks/: contenido runtime ignorado (singleton-guard {pid,ts},
83
+ // fase-activa.json) EXCEPTO los plan-locks de G1 (*PLAN.md.lock), que son
84
+ // evidencia de aprobación versionable (audit trail SDD — aprobar-plan.md).
85
+ // Patrón `dir/*` + negación: git no re-incluye archivos si el DIRECTORIO
86
+ // está ignorado, por eso se ignora el contenido y no el dir.
87
+ ".planning/locks/*",
88
+ "!.planning/locks/*PLAN.md.lock",
83
89
  ".planning/user-profile/",
84
90
 
85
91
  // Instintos modificados automáticamente por hooks (degradacion-instintos.js)
@@ -87,6 +93,28 @@ const ENTRADAS_BASE = [
87
93
 
88
94
  // Base de datos de uso
89
95
  "usage.db",
96
+
97
+ // ── Runtime adicional: derivados regenerables, caches y telemetría ──
98
+ // Cobertura completada en Fase 09 tras auditar qué genera SWL en proyectos
99
+ // destino vs lo que ENTRADAS_BASE propagaba. Todo esto es output de runtime,
100
+ // regenerable, no editado por el equipo → no se commitea.
101
+ ".planning/feature-list.json", // derivar-feature-list.js (derivado de HOJA-RUTA.md)
102
+ ".planning/loops/", // loop-telemetry.js (/swl:verificar, /swl:status loops)
103
+ ".planning/archive/", // rotar-audit-auto.js (audit/logs rotados y comprimidos)
104
+ ".planning/analysis/", // outputs de análisis
105
+ ".planning/graph.json", // code-review-graph (cache del grafo)
106
+ ".planning/graph-cache.json", // code-review-graph (cache incremental)
107
+ ".planning/mcp-snapshot.json", // /swl:status (smoke test MCP) / mcp-status
108
+ ".planning/skill-index.json", // /swl:skill-search (índice FTS de skills)
109
+ ".planning/inventario-aviso-state.json", // throttle del aviso de inventario
110
+ ".planning/*.lock", // locks sueltos (ej. STATE.md.lock; el dir locks/ ya está arriba)
111
+
112
+ // Estado runtime de /swl:verificar --until-converge. Vive DENTRO de
113
+ // .planning/fases/, que SÍ contiene plantillas commiteadas
114
+ // (0N-CONTEXTO/PLAN/RESUMEN/VERIFICACION.md). Glob específico para ignorar
115
+ // SOLO el estado de convergencia, nunca esas plantillas.
116
+ ".planning/fases/*-converge-state.json",
117
+ ".planning/fases/*-converge-run-*.json",
90
118
  ];
91
119
 
92
120
  // Entradas adicionales por runtime (se agregan cuando install usa ese target)