@saulwade/swl-ses 2.5.3 → 2.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 (214) hide show
  1. package/CLAUDE.md +9 -9
  2. package/README.md +37 -37
  3. package/agentes/_intent-spec.md +73 -73
  4. package/agentes/_propose-step.md +90 -90
  5. package/agentes/accesibilidad-wcag-swl.md +690 -690
  6. package/agentes/arquitecto-swl.md +267 -267
  7. package/agentes/auto-evolucion-swl.md +932 -908
  8. package/agentes/backend-csharp-swl.md +420 -420
  9. package/agentes/backend-go-swl.md +390 -390
  10. package/agentes/backend-java-swl.md +281 -281
  11. package/agentes/backend-rust-swl.md +364 -364
  12. package/agentes/backend-workers-swl.md +482 -482
  13. package/agentes/cloud-infra-swl.md +509 -509
  14. package/agentes/consolidador-swl.md +541 -541
  15. package/agentes/depurador-swl.md +352 -352
  16. package/agentes/devops-ci-swl.md +400 -400
  17. package/agentes/disenador-ui-swl.md +569 -569
  18. package/agentes/documentador-swl.md +345 -345
  19. package/agentes/frontend-angular-swl.md +621 -621
  20. package/agentes/frontend-css-swl.md +716 -716
  21. package/agentes/frontend-react-swl.md +692 -692
  22. package/agentes/frontend-swl.md +496 -496
  23. package/agentes/frontend-tailwind-swl.md +826 -826
  24. package/agentes/investigador-swl.md +432 -432
  25. package/agentes/investigador-ux-swl.md +505 -505
  26. package/agentes/migrador-swl.md +442 -442
  27. package/agentes/mobile-android-swl.md +511 -511
  28. package/agentes/mobile-cross-swl.md +541 -541
  29. package/agentes/mobile-ios-swl.md +502 -502
  30. package/agentes/mobile-testing-swl.md +302 -302
  31. package/agentes/nemesis-auditor-swl.md +285 -285
  32. package/agentes/observabilidad-swl.md +438 -438
  33. package/agentes/pagos-swl.md +310 -310
  34. package/agentes/perfilador-usuario-swl.md +321 -321
  35. package/agentes/planificador-swl.md +399 -399
  36. package/agentes/producto-prd-swl.md +589 -589
  37. package/agentes/red-team-swl.md +218 -218
  38. package/agentes/release-manager-swl.md +590 -590
  39. package/agentes/rendimiento-swl.md +713 -713
  40. package/agentes/revisor-angular-swl.md +278 -278
  41. package/agentes/revisor-csharp-swl.md +264 -264
  42. package/agentes/revisor-go-swl.md +259 -259
  43. package/agentes/revisor-java-swl.md +257 -257
  44. package/agentes/revisor-kotlin-swl.md +273 -273
  45. package/agentes/revisor-nextjs-swl.md +281 -281
  46. package/agentes/revisor-php-swl.md +271 -271
  47. package/agentes/revisor-react-swl.md +278 -278
  48. package/agentes/revisor-rust-swl.md +346 -346
  49. package/agentes/revisor-seguridad-swl.md +399 -399
  50. package/agentes/revisor-swift-swl.md +268 -268
  51. package/agentes/revisor-typescript-swl.md +346 -346
  52. package/agentes/tdd-qa-swl.md +393 -393
  53. package/bin/swl-ses.js +32 -7
  54. package/comandos/swl/actualizar.md +3 -3
  55. package/comandos/swl/aprender.md +13 -0
  56. package/comandos/swl/deuda-codigo.md +97 -97
  57. package/comandos/swl/evaluar-skill.md +18 -3
  58. package/comandos/swl/evolucion-continua.md +73 -0
  59. package/comandos/swl/evolucionar.md +13 -0
  60. package/comandos/swl/instalar.md +4 -4
  61. package/comandos/swl/notificaciones.md +1 -1
  62. package/comandos/swl/status.md +2 -2
  63. package/gateway/cron/jobs.example.json +12 -0
  64. package/habilidades/auto-evolucion-protocolo/SKILL.md +19 -1
  65. package/habilidades/autoresearch/SKILL.md +3 -2
  66. package/habilidades/backend-async-postgres-testing/SKILL.md +2 -1
  67. package/habilidades/benchmark-memoria/SKILL.md +7 -7
  68. package/habilidades/changelog-generator/SKILL.md +1 -1
  69. package/habilidades/changelog-generator/scripts/parse-commits.js +2 -1
  70. package/habilidades/checkpoints-verificacion/SKILL.md +6 -0
  71. package/habilidades/compactacion-contexto/SKILL.md +2 -1
  72. package/habilidades/contenedores-docker/SKILL.md +4 -2
  73. package/habilidades/context-builder/SKILL.md +4 -0
  74. package/habilidades/doubt-driven-review/SKILL.md +17 -1
  75. package/habilidades/drift-detection/SKILL.md +6 -1
  76. package/habilidades/ejecutar-fase/SKILL.md +6 -6
  77. package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
  78. package/habilidades/eval-framework/SKILL.md +8 -3
  79. package/habilidades/extractor-de-aprendizajes/SKILL.md +8 -2
  80. package/habilidades/git-worktrees-paralelo/SKILL.md +19 -1
  81. package/habilidades/harness-claude-code/SKILL.md +7 -3
  82. package/habilidades/infra-github-actions/SKILL.md +4 -3
  83. package/habilidades/instalar-sistema/SKILL.md +5 -1
  84. package/habilidades/memoria-busqueda/SKILL.md +31 -39
  85. package/habilidades/planear-fase/SKILL.md +9 -1
  86. package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
  87. package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
  88. package/habilidades/proceso-ddia-fundamentos/SKILL.md +3 -2
  89. package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -147
  90. package/habilidades/release-semver/SKILL.md +2 -2
  91. package/habilidades/swl-claudemd/SKILL.md +6 -7
  92. package/habilidades/swl-dashboard/SKILL.md +11 -43
  93. package/habilidades/tdd-workflow/SKILL.md +12 -7
  94. package/habilidades/validacion-ci-sistema/SKILL.md +1 -1
  95. package/hooks/agente-lifecycle.js +2 -1
  96. package/hooks/aiisms-detector.js +13 -4
  97. package/hooks/audit-trail.js +2 -1
  98. package/hooks/auto-consolidacion.js +2 -1
  99. package/hooks/captura-acciones-post.js +2 -1
  100. package/hooks/captura-acciones-session.js +2 -1
  101. package/hooks/captura-feedback-usuario.js +3 -2
  102. package/hooks/claudemd-bloat-detector.js +12 -3
  103. package/hooks/claudemd-duplicacion-detector.js +13 -3
  104. package/hooks/contexto-iteracion.js +2 -1
  105. package/hooks/contexto-subagente.js +68 -68
  106. package/hooks/degradacion-instintos.js +2 -1
  107. package/hooks/extraccion-aprendizajes.js +109 -15
  108. package/hooks/grafo-contexto.js +2 -1
  109. package/hooks/guardrail-modelo.js +2 -1
  110. package/hooks/inbox-aviso.js +2 -1
  111. package/hooks/inyeccion-contexto.js +2 -1
  112. package/hooks/lib/agent-matcher.js +2 -1
  113. package/hooks/lib/agent-routing.js +2 -1
  114. package/hooks/lib/autonomia.js +5 -3
  115. package/hooks/lib/captura-acciones.js +2 -1
  116. package/hooks/lib/consolidation-lock.js +21 -10
  117. package/hooks/lib/etapa-auto-evolucion.js +10 -4
  118. package/hooks/lib/etapa-metricas.js +2 -1
  119. package/hooks/lib/etapa-perfil-usuario.js +20 -4
  120. package/hooks/lib/evolution-tracker.js +2 -1
  121. package/hooks/lib/gateway-notify.js +17 -3
  122. package/hooks/lib/loop-telemetry.js +5 -4
  123. package/hooks/lib/mcp-health.js +2 -1
  124. package/hooks/lib/memory-search.js +4 -0
  125. package/hooks/lib/merkle-audit.js +58 -6
  126. package/hooks/lib/notificacion-formato.js +58 -0
  127. package/hooks/lib/nudge-tracker.js +2 -1
  128. package/hooks/lib/otlp-exporter.js +2 -1
  129. package/hooks/lib/propose-step.js +3 -2
  130. package/hooks/lib/raiz-proyecto.js +127 -0
  131. package/hooks/lib/run-log.js +2 -1
  132. package/hooks/lib/singleton-guard.js +225 -27
  133. package/hooks/lib/telegram-cliente.js +28 -11
  134. package/hooks/notificacion-telegram.js +13 -3
  135. package/hooks/preservar-estado-pre-compact.js +2 -1
  136. package/hooks/proteccion-rutas.js +59 -3
  137. package/hooks/registro-turnos.js +2 -1
  138. package/hooks/resumen-sesion.js +2 -1
  139. package/hooks/risk-scoring.js +2 -1
  140. package/hooks/rotar-audit-auto.js +46 -20
  141. package/hooks/session-briefing.js +127 -1
  142. package/hooks/spec-gate.js +2 -1
  143. package/hooks/sugerir-contribuir.js +6 -3
  144. package/hooks/sugerir-regenerar-inventario.js +3 -2
  145. package/hooks/tdd-gate.js +2 -1
  146. package/hooks/telemetria-agentes.js +2 -1
  147. package/hooks/telemetria-skill-routing.js +2 -1
  148. package/hooks/tracking-costos.js +4 -3
  149. package/hooks/validar-formato-post-subagente.js +2 -1
  150. package/hooks/validar-intent-spec.js +2 -1
  151. package/hooks/validar-memoria-hook.js +13 -3
  152. package/hooks/validar-planning-paths.js +2 -1
  153. package/instintos/perfil-usuario.yaml +506 -3
  154. package/instintos/proyecto.yaml +78 -0
  155. package/llms.txt +29 -29
  156. package/manifiestos/canonical-hashes.json +5588 -4925
  157. package/manifiestos/hooks-config.json +469 -469
  158. package/manifiestos/invariantes-criticos.json +30 -30
  159. package/manifiestos/modulos.json +1429 -1423
  160. package/manifiestos/planning-paths.json +1 -0
  161. package/manifiestos/skills-lock.json +1275 -1275
  162. package/package.json +94 -95
  163. package/plugin.json +369 -369
  164. package/scripts/actualizar.js +3 -0
  165. package/scripts/auditar-clases-conocidas.js +134 -106
  166. package/scripts/benchmark-memoria.js +1 -0
  167. package/scripts/bootstrap-instintos.js +85 -14
  168. package/scripts/canario-hooks.js +166 -166
  169. package/scripts/cli/autonomia.js +23 -0
  170. package/scripts/cli/benchmark-memoria.js +37 -0
  171. package/scripts/cli/ciclo-autonomo.js +73 -0
  172. package/scripts/cli/ciclo-fase-b.js +102 -0
  173. package/scripts/cli/guardrail-metrics.js +39 -0
  174. package/scripts/cli/loop-telemetry.js +4 -2
  175. package/scripts/cli/memoria-search.js +69 -0
  176. package/scripts/cli/nudge-accionar.js +39 -0
  177. package/scripts/cli/run-eval.js +38 -0
  178. package/scripts/cli/run-skill-evals.js +13 -2
  179. package/scripts/derivar-feature-list.js +15 -14
  180. package/scripts/desinstalar.js +11 -0
  181. package/scripts/doctor.js +50 -13
  182. package/scripts/evidencia-valor.js +101 -101
  183. package/scripts/field-report.js +16 -16
  184. package/scripts/instalador.js +98 -7
  185. package/scripts/lib/activar-hooks-proyecto.js +116 -104
  186. package/scripts/lib/auditar-invocaciones-comandos.js +96 -6
  187. package/scripts/lib/ciclo-autonomo/candidatos.js +174 -0
  188. package/scripts/lib/ciclo-autonomo/config.js +165 -0
  189. package/scripts/lib/ciclo-autonomo/drenador-feedback.js +174 -0
  190. package/scripts/lib/ciclo-autonomo/fallback.js +77 -0
  191. package/scripts/lib/ciclo-autonomo/guard-convivencia.js +139 -0
  192. package/scripts/lib/ciclo-autonomo/higiene-nudges.js +112 -0
  193. package/scripts/lib/ciclo-autonomo/index.js +301 -0
  194. package/scripts/lib/ciclo-autonomo/lock.js +124 -0
  195. package/scripts/lib/ciclo-autonomo/presupuesto.js +122 -0
  196. package/scripts/lib/ciclo-autonomo/puente-degradacion.js +240 -0
  197. package/scripts/lib/ciclo-autonomo/runner-fase-b.js +248 -0
  198. package/scripts/lib/ciclo-autonomo/writer-instintos.js +190 -0
  199. package/scripts/lib/ciclo-autonomo/yaml-instintos.js +535 -0
  200. package/scripts/lib/estado.js +9 -0
  201. package/scripts/lib/evidencia-valor.js +228 -228
  202. package/scripts/lib/expandir-targets.js +71 -71
  203. package/scripts/lib/gitignore-manifest.js +8 -1
  204. package/scripts/lib/hooks-settings.js +45 -0
  205. package/scripts/lib/limpiar-basura-global.js +161 -0
  206. package/scripts/lib/toml-merge.js +204 -204
  207. package/scripts/mcp-server/auth.js +105 -105
  208. package/scripts/mcp-server/cache.js +106 -106
  209. package/scripts/rotar-audit-logs.js +48 -2
  210. package/scripts/run-eval.js +1 -0
  211. package/scripts/run-skill-evals.js +287 -8
  212. package/scripts/smoke-test.js +16 -8
  213. package/scripts/tui/pantallas/install-wizard.js +69 -13
  214. package/scripts/validar.js +40 -1
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: tdd-workflow
3
3
  description: Flujo completo de Test-Driven Development. Ciclo RED (el test falla) → GREEN (implementación mínima) → REFACTOR (limpieza). Incluye cobertura mínima obligatoria, tests de frontera, factories, fixtures y estrategias para diferentes tipos de código (APIs, services, componentes Angular).
4
- version: "1.2.3"
4
+ version: "1.2.4"
5
5
  herramientasPermitidas: [Read, Bash]
6
6
  evolvable: true # default para skill estandar
7
7
  exclusiones:
@@ -73,18 +73,19 @@ def test_descuento_cliente_premium_es_15_porciento():
73
73
  #### Evidencia RED en telemetría (gate G2 — proyectos con SWL)
74
74
 
75
75
  El RED debe dejar rastro verificable (cierra F-TDD-6: "TDD declarativo sin
76
- evidencia"). En proyectos con `.planning/`, registrar la corrida en
77
- `hooks/lib/loop-telemetry.js` ANTES de pasar a GREEN:
76
+ evidencia"). En proyectos con `.planning/`, registrar la corrida con el CLI
77
+ (resuelve cross-scope; en el repo madre equivale a `hooks/lib/loop-telemetry.js`)
78
+ ANTES de pasar a GREEN:
78
79
 
79
80
  ```bash
80
- # Una vez por fase/tarea — abre la corrida
81
- node -e "const lt=require('./hooks/lib/loop-telemetry');const r=lt.iniciarCorrida({tipo:'tdd',direccion:'lower_is_better',config:{fase:'0N',tarea:'T-NN'}});console.log(r.dir)"
81
+ # Una vez por fase/tarea — abre la corrida (imprime el dir)
82
+ swl-ses loop-telemetry iniciar --tipo=tdd --direccion=lower_is_better --config='{"fase":"0N","tarea":"T-NN"}'
82
83
 
83
84
  # Al confirmar el RED — métrica = número de tests fallando, descripción = fallo exacto
84
- node -e "const lt=require('./hooks/lib/loop-telemetry');lt.registrarIteracion('<dir>',{iteracion:0,metrica:N,delta:0,estado:'baseline',descripcion:'RED T-NN: <error textual del runner>'})"
85
+ swl-ses loop-telemetry registrar --dir=<dir> --iteracion=0 --metrica=<N> --delta=0 --estado=baseline --descripcion="RED T-NN: <error textual del runner>"
85
86
 
86
87
  # Al llegar a GREEN
87
- node -e "const lt=require('./hooks/lib/loop-telemetry');lt.registrarIteracion('<dir>',{iteracion:1,metrica:0,delta:-N,estado:'keep',descripcion:'GREEN T-NN: suite verde'})"
88
+ swl-ses loop-telemetry registrar --dir=<dir> --iteracion=1 --metrica=0 --delta=-<N> --estado=keep --descripcion="GREEN T-NN: suite verde"
88
89
  ```
89
90
 
90
91
  `hooks/tdd-gate.js` (warn-only, ADR-0035) busca la fila RED en
@@ -339,6 +340,10 @@ pytest --cov=src/services --cov-fail-under=90
339
340
 
340
341
  ## Gotchas / Errores comunes no obvios
341
342
 
343
+ **Fixtures que apuntan a archivos que el sistema muta en runtime se rompen solos — congelar el fixture, nunca el archivo vivo** [caso real swl-ses 2026-07-10]: los tests del ciclo autónomo copiaban `instintos/proyecto.yaml` y `perfil-usuario.yaml` REALES del repo como fixtures; horas después el bootstrap del motor los pobló (72 señales, campos nuevos) y 2 tests verdes reventaron sin que nadie tocara código de test. Causa: el fixture era un puntero al estado vivo, no una instantánea. Con cualquier sistema que auto-muta archivos (telemetría, motores de aprendizaje, caches regenerables), TODO archivo del repo es potencialmente mutable en runtime. Fix: congelar la instantánea de fábrica en `tests/**/fixtures/` (p. ej. `git show HEAD:ruta > tests/x/fixtures/archivo`) y apuntar los tests ahí; documentar en el path del fixture POR QUÉ está congelado. Señal de detección temprana: un test que falla sin diff en el código de test ni en el SUT.
344
+
345
+ **`node:test` hereda `process.exitCode`: un caso que lo deja en 1 marca el ARCHIVO entero como fallido aunque todos los tests pasen** [caso real swl-ses 2026-07-10]: un test de CLI que ejercita la rama de error (`wrapper que setea process.exitCode = 1` y retorna null) deja el exit code sucio; node:test reporta `pass N / fail 0` por caso pero el archivo cierra con "test failed" y exit 1. Fix: el test que ejercita ramas de error de CLIs restaura `process.exitCode = 0` tras el assert. Patrón: `assert.equal(process.exitCode, 1); process.exitCode = 0;` — verifica el contrato Y limpia.
346
+
342
347
  **Tests que dependen de que N llamadas caigan en el MISMO segundo (IDs con timestamp, sufijos de colisión) son flaky por frontera de segundo — congelar el reloj**: si el SUT genera identificadores tipo `tipo-YYMMDD-HHMMSS` y el test llama 3 veces esperando sufijos de colisión `-2`/`-3`, cruzar el límite de segundo entre llamadas hace que la 3ª obtenga timestamp nuevo sin colisión — falla intermitente que puede tumbar un `npm publish` (caso real swl-ses 2026-07-03: `loop-telemetry`). Causa: el SUT toma el reloj de pared internamente; el test no controla el tiempo. Fix (Node): `t.mock.timers.enable({ apis: ['Date'], now: new Date('2026-01-01T12:00:00Z') })` de `node:test` — el equivalente a freezegun; se restaura solo al terminar el test. En Python: `freezegun.freeze_time`. NUNCA "reintentar el test" ni ampliar ventanas: congelar el reloj hace la colisión determinista por construcción.
343
348
 
344
349
  **El ciclo TDD se rompe cuando el test en fase RED pasa sin implementación porque la función ya existe con otro nombre en el módulo y Python la importa silenciosamente desde un namespace diferente**: escribir `from app.services import calcular_descuento` en el test cuando `calcular_descuento` ya existe en `app.utils` (importada en `__init__.py`) hace que el test pase en RED sin error, invalidando el ciclo. Causa: los imports con `from app.services import *` en `__init__.py` pueden re-exportar funciones de submódulos, haciendo que el test encuentre una implementación inesperada. Fix: verificar con `python -c "from app.services import calcular_descuento; print(calcular_descuento.__module__)"` que el símbolo viene del módulo correcto. Usar imports explícitos en los tests (`from app.services.descuentos import calcular_descuento`) en lugar de imports de paquete.
@@ -30,7 +30,7 @@ validar y un score de componentes sería engañoso. El gate determinista vive en
30
30
  `/swl:status salud` (Paso 0):
31
31
 
32
32
  ```bash
33
- node scripts/lib/detectar-host-swl.js --json
33
+ swl-ses detectar-host --json
34
34
  ```
35
35
 
36
36
  Si `esHost: false`, NO ejecutar este skill: reportar que `salud` no aplica y
@@ -21,9 +21,10 @@
21
21
  */
22
22
 
23
23
  const { desdePayloadHook, emitirCompletado } = require('./lib/agent-backend');
24
+ const { raizProyecto } = require('./lib/raiz-proyecto');
24
25
  const es = require('./lib/execution-state');
25
26
 
26
- const CWD = process.cwd();
27
+ const CWD = raizProyecto(process.cwd());
27
28
 
28
29
  // ---------------------------------------------------------------------------
29
30
  // Entrypoint
@@ -34,6 +34,7 @@
34
34
  */
35
35
 
36
36
  const fs = require('fs');
37
+ const { raizProyecto } = require('./lib/raiz-proyecto');
37
38
  const path = require('path');
38
39
  const { spawnSync, randomUUID } = require('child_process');
39
40
  const crypto = require('crypto');
@@ -92,10 +93,18 @@ if (!fs.existsSync(filePath)) {
92
93
  process.exit(0);
93
94
  }
94
95
 
95
- // Ruta del detector (zero-deps, stdlib Python)
96
- const CWD = process.cwd();
97
- const detector = path.join(CWD, 'habilidades', 'estilo-sin-ai-isms', 'scripts', 'detectar_aiisms.py');
98
- if (!fs.existsSync(detector)) {
96
+ // Ancla de DATOS (nudges, rutas relativas): raíz del proyecto.
97
+ const CWD = raizProyecto(process.cwd());
98
+ // El detector es EJECUTABLE de la distribución SWL: se resuelve SOLO desde
99
+ // la ubicación instalada del hook (__dirname), NUNCA desde el árbol del
100
+ // proyecto — un repo no confiable podría plantar el script (hallazgo
101
+ // revisor-seguridad 2026-07-10, clase spawn/require-desde-raíz).
102
+ const detector = [
103
+ path.join(__dirname, '..', 'habilidades', 'estilo-sin-ai-isms', 'scripts', 'detectar_aiisms.py'), // repo madre
104
+ path.join(__dirname, '..', 'skills', 'estilo-sin-ai-isms', 'scripts', 'detectar_aiisms.py'), // destino global (~/.claude/hooks ~ skills hermanos)
105
+ path.join(__dirname, '..', '.claude', 'skills', 'estilo-sin-ai-isms', 'scripts', 'detectar_aiisms.py'), // destino local (<proyecto>/hooks + <proyecto>/.claude/skills)
106
+ ].find(p => { try { return fs.existsSync(p); } catch (_) { return false; } });
107
+ if (!detector) {
99
108
  process.exit(0);
100
109
  }
101
110
 
@@ -19,13 +19,14 @@
19
19
  */
20
20
 
21
21
  const fs = require('fs');
22
+ const { raizProyecto } = require('./lib/raiz-proyecto');
22
23
  const path = require('path');
23
24
  const http = require('http');
24
25
  const https = require('https');
25
26
 
26
27
  const { appendAudit: merkleAppend } = require(path.join(__dirname, 'lib', 'merkle-audit'));
27
28
 
28
- const CWD = process.cwd();
29
+ const CWD = raizProyecto(process.cwd());
29
30
  const AUDIT_FILE = path.join(CWD, '.planning', 'audit.jsonl');
30
31
  const MERKLE_FILE = path.join(CWD, '.planning', 'audit-merkle.jsonl');
31
32
 
@@ -29,6 +29,7 @@
29
29
  */
30
30
 
31
31
  const path = require('path');
32
+ const { raizProyecto } = require('./lib/raiz-proyecto');
32
33
  const fs = require('fs');
33
34
  const os = require('os');
34
35
 
@@ -97,7 +98,7 @@ process.stdin.on('end', () => {
97
98
  // Anti-spam: solo ejecutar 1 vez por sesión
98
99
  if (alreadyRan()) return;
99
100
 
100
- const baseDir = process.cwd();
101
+ const baseDir = raizProyecto(process.cwd());
101
102
 
102
103
  // Verificar las 3 gates
103
104
  const gates = checkAllGates(baseDir, {
@@ -19,6 +19,7 @@
19
19
  */
20
20
 
21
21
  const fs = require('fs');
22
+ const { raizProyecto } = require('./lib/raiz-proyecto');
22
23
  const path = require('path');
23
24
  const { execFileSync } = require('child_process');
24
25
 
@@ -142,7 +143,7 @@ if (!require.main || require.main === module) {
142
143
  process.stdin.on('end', () => {
143
144
  try {
144
145
  const data = JSON.parse(inputRaw);
145
- procesarTurno(data, process.cwd());
146
+ procesarTurno(data, raizProyecto(process.cwd()));
146
147
  } catch (_) {
147
148
  /* silencioso */
148
149
  }
@@ -20,6 +20,7 @@
20
20
  */
21
21
 
22
22
  const fs = require('fs');
23
+ const { raizProyecto } = require('./lib/raiz-proyecto');
23
24
  const path = require('path');
24
25
  const { execFileSync } = require('child_process');
25
26
 
@@ -145,7 +146,7 @@ if (!require.main || require.main === module) {
145
146
  process.stdin.on('data', (c) => { inputRaw += c; });
146
147
  process.stdin.on('end', () => {
147
148
  try {
148
- inspeccionar(process.cwd());
149
+ inspeccionar(raizProyecto(process.cwd()));
149
150
  } catch (_) {
150
151
  /* silencioso: el hook nunca bloquea la sesión */
151
152
  }
@@ -25,6 +25,7 @@
25
25
  */
26
26
 
27
27
  const fs = require('fs');
28
+ const { raizProyecto } = require('./lib/raiz-proyecto');
28
29
  const path = require('path');
29
30
 
30
31
  // ---------------------------------------------------------------------------
@@ -104,7 +105,7 @@ function detectarFeedback(prompt) {
104
105
  */
105
106
  function encolar(hallazgo, meta) {
106
107
  try {
107
- const dir = path.join(process.cwd(), '.planning', 'evolution');
108
+ const dir = path.join(raizProyecto(process.cwd()), '.planning', 'evolution');
108
109
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
109
110
 
110
111
  const entrada = {
@@ -140,7 +141,7 @@ process.stdin.on('end', () => {
140
141
  if (hallazgos.length === 0) return;
141
142
 
142
143
  for (const h of hallazgos) {
143
- encolar(h, { sessionId, cwd: process.cwd() });
144
+ encolar(h, { sessionId, cwd: raizProyecto(process.cwd()) });
144
145
  }
145
146
  } catch (_) { /* silencioso */ }
146
147
  });
@@ -36,6 +36,7 @@
36
36
  */
37
37
 
38
38
  const fs = require('fs');
39
+ const { raizProyecto } = require('./lib/raiz-proyecto');
39
40
  const path = require('path');
40
41
  const crypto = require('crypto');
41
42
 
@@ -93,9 +94,17 @@ if (!fs.existsSync(filePath)) {
93
94
  }
94
95
 
95
96
  // ─── Ejecutar auditor (módulo, no subproceso) ─────────────────────────────
96
- const CWD = process.cwd();
97
- const auditorPath = path.join(CWD, 'scripts', 'auditar-claudemd.js');
98
- if (!fs.existsSync(auditorPath)) {
97
+ // Ancla de DATOS (nudges, rutas relativas): raíz del proyecto.
98
+ const CWD = raizProyecto(process.cwd());
99
+ // El auditor es MÓDULO de la distribución SWL: se resuelve SOLO desde la
100
+ // ubicación instalada del hook (__dirname), NUNCA desde el árbol del
101
+ // proyecto — un require() de un path plantado por un repo no confiable es
102
+ // ejecución de código (hallazgo revisor-seguridad 2026-07-10).
103
+ const auditorPath = [
104
+ path.join(__dirname, '..', 'scripts', 'auditar-claudemd.js'), // repo madre
105
+ path.join(__dirname, 'auditar-claudemd.js'), // destino aplanado
106
+ ].find(p => { try { return fs.existsSync(p); } catch (_) { return false; } });
107
+ if (!auditorPath) {
99
108
  // No hay auditor instalado en este destino; salir silenciosamente
100
109
  process.exit(0);
101
110
  }
@@ -39,6 +39,7 @@
39
39
  */
40
40
 
41
41
  const fs = require('fs');
42
+ const { raizProyecto } = require('./lib/raiz-proyecto');
42
43
  const path = require('path');
43
44
  const os = require('os');
44
45
  const crypto = require('crypto');
@@ -102,9 +103,18 @@ if (!fs.existsSync(filePath)) {
102
103
  }
103
104
 
104
105
  // ─── Cargar detector ──────────────────────────────────────────────────────
105
- const CWD = process.cwd();
106
- const detectorPath = path.join(CWD, 'scripts', 'lib', 'detector-reglas-duplicadas.js');
107
- if (!fs.existsSync(detectorPath)) {
106
+ // Ancla de DATOS (nudges, rutas relativas): raíz del proyecto.
107
+ const CWD = raizProyecto(process.cwd());
108
+ // El detector es MÓDULO de la distribución SWL: se resuelve SOLO desde la
109
+ // ubicación instalada del hook (__dirname), NUNCA desde el árbol del
110
+ // proyecto — un require() de un path plantado por un repo no confiable es
111
+ // ejecución de código (hallazgo revisor-seguridad 2026-07-10).
112
+ const detectorPath = [
113
+ path.join(__dirname, '..', 'scripts', 'lib', 'detector-reglas-duplicadas.js'), // repo madre
114
+ path.join(__dirname, 'lib', 'detector-reglas-duplicadas.js'), // destino (scripts/lib → hooks/lib)
115
+ path.join(__dirname, 'detector-reglas-duplicadas.js'), // destino legado aplanado
116
+ ].find(p => { try { return fs.existsSync(p); } catch (_) { return false; } });
117
+ if (!detectorPath) {
108
118
  // No hay detector instalado en este destino; salir silenciosamente
109
119
  process.exit(0);
110
120
  }
@@ -28,6 +28,7 @@
28
28
  */
29
29
 
30
30
  const fs = require('fs');
31
+ const { raizProyecto } = require('./lib/raiz-proyecto');
31
32
  const path = require('path');
32
33
 
33
34
  const { atomicWriteJSON } = require('./lib/atomic-write');
@@ -112,7 +113,7 @@ function main() {
112
113
  try {
113
114
  if (process.env.SWL_CONTEXTO_ITERACION === '0') return;
114
115
 
115
- const activa = corridaActiva(process.cwd(), { maxEdadMin: 30 });
116
+ const activa = corridaActiva(raizProyecto(process.cwd()), { maxEdadMin: 30 });
116
117
  if (!activa) return;
117
118
  if (!debeInyectar(activa.dir)) return;
118
119
 
@@ -1,68 +1,68 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- /**
5
- * Hook: contexto-subagente.js
6
- * Tipo: SubagentStart (aplica a todos los subagentes Task/Agent)
7
- *
8
- * El contexto emitido por hooks de SessionStart es solo del hilo padre y
9
- * NUNCA llega a los subagentes: cada agente spawneado vía Task/Agent corre
10
- * sin las disciplinas activas de la sesión (patrón documentado en ponytail
11
- * issue #252 — mismo gap verificado en swl-ses el 2026-07-03: 0 usos de
12
- * SubagentStart hasta este hook).
13
- *
14
- * Re-inyecta a cada subagente un bloque compacto (~120 tokens) con las
15
- * disciplinas transversales no negociables: idioma es-MX, escalera de código
16
- * mínimo con guardas intocables, y la convención de marcador `simplificado:`.
17
- * Deliberadamente mínimo — el costo se paga en CADA spawn de subagente.
18
- *
19
- * Opt-out: SWL_CONTEXTO_SUBAGENTE=0 desactiva la inyección.
20
- * Formato de salida: SubagentStart requiere la forma JSON hookSpecificOutput
21
- * (stdout crudo se descarta en este evento — a diferencia de SessionStart).
22
- */
23
-
24
- /**
25
- * Construye el bloque de disciplinas que se inyecta al subagente.
26
- *
27
- * @returns {string} Contexto compacto en es-MX.
28
- */
29
- function construirContexto() {
30
- return [
31
- 'DISCIPLINAS SWL ACTIVAS (heredadas de la sesión padre):',
32
- '- Idioma: español de México en todo output (código, comentarios, commits, reportes).',
33
- '- Código mínimo — escalera antes de escribir: ¿necesita existir (YAGNI)? →',
34
- ' ¿ya existe en este codebase? → ¿stdlib? → ¿feature nativa de la plataforma? →',
35
- ' ¿dependencia ya instalada? → ¿una línea? → solo entonces, el mínimo que funciona.',
36
- '- Guardas intocables (nunca simplificar): validación en trust boundaries,',
37
- ' manejo de errores que previene pérdida de datos, seguridad, accesibilidad.',
38
- '- Simplificación deliberada se marca: `simplificado: <techo>, <trigger de upgrade>`.',
39
- '- Bug fix = causa raíz: grep de todos los callers antes de parchar uno.',
40
- 'Detalle completo: Skill("prevencion-sobreingenieria").',
41
- ].join('\n');
42
- }
43
-
44
- /**
45
- * Emite el contexto en el formato JSON que SubagentStart exige.
46
- * Nunca falla hacia afuera: un stdout roto no debe reportarse como hook error.
47
- */
48
- function main() {
49
- if (process.env.SWL_CONTEXTO_SUBAGENTE === '0') return;
50
- try {
51
- process.stdout.write(JSON.stringify({
52
- hookSpecificOutput: {
53
- hookEventName: 'SubagentStart',
54
- additionalContext: construirContexto(),
55
- },
56
- }));
57
- } catch (_) {
58
- // Silencioso — no interrumpir el spawn del subagente.
59
- }
60
- }
61
-
62
- // Entrypoint directo o wrapper `node -e "require(...)"` (require.main undefined).
63
- // No consume stdin: emite y termina — sin listeners, el proceso sale solo.
64
- if (!require.main || require.main === module) {
65
- main();
66
- }
67
-
68
- module.exports = { construirContexto };
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * Hook: contexto-subagente.js
6
+ * Tipo: SubagentStart (aplica a todos los subagentes Task/Agent)
7
+ *
8
+ * El contexto emitido por hooks de SessionStart es solo del hilo padre y
9
+ * NUNCA llega a los subagentes: cada agente spawneado vía Task/Agent corre
10
+ * sin las disciplinas activas de la sesión (patrón documentado en ponytail
11
+ * issue #252 — mismo gap verificado en swl-ses el 2026-07-03: 0 usos de
12
+ * SubagentStart hasta este hook).
13
+ *
14
+ * Re-inyecta a cada subagente un bloque compacto (~120 tokens) con las
15
+ * disciplinas transversales no negociables: idioma es-MX, escalera de código
16
+ * mínimo con guardas intocables, y la convención de marcador `simplificado:`.
17
+ * Deliberadamente mínimo — el costo se paga en CADA spawn de subagente.
18
+ *
19
+ * Opt-out: SWL_CONTEXTO_SUBAGENTE=0 desactiva la inyección.
20
+ * Formato de salida: SubagentStart requiere la forma JSON hookSpecificOutput
21
+ * (stdout crudo se descarta en este evento — a diferencia de SessionStart).
22
+ */
23
+
24
+ /**
25
+ * Construye el bloque de disciplinas que se inyecta al subagente.
26
+ *
27
+ * @returns {string} Contexto compacto en es-MX.
28
+ */
29
+ function construirContexto() {
30
+ return [
31
+ 'DISCIPLINAS SWL ACTIVAS (heredadas de la sesión padre):',
32
+ '- Idioma: español de México en todo output (código, comentarios, commits, reportes).',
33
+ '- Código mínimo — escalera antes de escribir: ¿necesita existir (YAGNI)? →',
34
+ ' ¿ya existe en este codebase? → ¿stdlib? → ¿feature nativa de la plataforma? →',
35
+ ' ¿dependencia ya instalada? → ¿una línea? → solo entonces, el mínimo que funciona.',
36
+ '- Guardas intocables (nunca simplificar): validación en trust boundaries,',
37
+ ' manejo de errores que previene pérdida de datos, seguridad, accesibilidad.',
38
+ '- Simplificación deliberada se marca: `simplificado: <techo>, <trigger de upgrade>`.',
39
+ '- Bug fix = causa raíz: grep de todos los callers antes de parchar uno.',
40
+ 'Detalle completo: Skill("prevencion-sobreingenieria").',
41
+ ].join('\n');
42
+ }
43
+
44
+ /**
45
+ * Emite el contexto en el formato JSON que SubagentStart exige.
46
+ * Nunca falla hacia afuera: un stdout roto no debe reportarse como hook error.
47
+ */
48
+ function main() {
49
+ if (process.env.SWL_CONTEXTO_SUBAGENTE === '0') return;
50
+ try {
51
+ process.stdout.write(JSON.stringify({
52
+ hookSpecificOutput: {
53
+ hookEventName: 'SubagentStart',
54
+ additionalContext: construirContexto(),
55
+ },
56
+ }));
57
+ } catch (_) {
58
+ // Silencioso — no interrumpir el spawn del subagente.
59
+ }
60
+ }
61
+
62
+ // Entrypoint directo o wrapper `node -e "require(...)"` (require.main undefined).
63
+ // No consume stdin: emite y termina — sin listeners, el proceso sale solo.
64
+ if (!require.main || require.main === module) {
65
+ main();
66
+ }
67
+
68
+ module.exports = { construirContexto };
@@ -20,6 +20,7 @@
20
20
  */
21
21
 
22
22
  const fs = require('fs');
23
+ const { raizProyecto } = require('./lib/raiz-proyecto');
23
24
  const path = require('path');
24
25
 
25
26
  const { atomicWriteSync } = require('./lib/atomic-write');
@@ -28,7 +29,7 @@ const { atomicWriteSync } = require('./lib/atomic-write');
28
29
  // Constantes
29
30
  // ---------------------------------------------------------------------------
30
31
 
31
- const RUTA_APRENDIZAJES = path.join(process.cwd(), '.planning', 'APRENDIZAJES.md');
32
+ const RUTA_APRENDIZAJES = path.join(raizProyecto(process.cwd()), '.planning', 'APRENDIZAJES.md');
32
33
  const MAX_CONTRADICCIONES = 3;
33
34
 
34
35
  // Palabras clave que indican exito en el output del agente