@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.
- package/CLAUDE.md +9 -9
- package/README.md +37 -37
- package/agentes/_intent-spec.md +73 -73
- package/agentes/_propose-step.md +90 -90
- package/agentes/accesibilidad-wcag-swl.md +690 -690
- package/agentes/arquitecto-swl.md +267 -267
- package/agentes/auto-evolucion-swl.md +932 -908
- package/agentes/backend-csharp-swl.md +420 -420
- package/agentes/backend-go-swl.md +390 -390
- package/agentes/backend-java-swl.md +281 -281
- package/agentes/backend-rust-swl.md +364 -364
- package/agentes/backend-workers-swl.md +482 -482
- package/agentes/cloud-infra-swl.md +509 -509
- package/agentes/consolidador-swl.md +541 -541
- package/agentes/depurador-swl.md +352 -352
- package/agentes/devops-ci-swl.md +400 -400
- package/agentes/disenador-ui-swl.md +569 -569
- package/agentes/documentador-swl.md +345 -345
- package/agentes/frontend-angular-swl.md +621 -621
- package/agentes/frontend-css-swl.md +716 -716
- package/agentes/frontend-react-swl.md +692 -692
- package/agentes/frontend-swl.md +496 -496
- package/agentes/frontend-tailwind-swl.md +826 -826
- package/agentes/investigador-swl.md +432 -432
- package/agentes/investigador-ux-swl.md +505 -505
- package/agentes/migrador-swl.md +442 -442
- package/agentes/mobile-android-swl.md +511 -511
- package/agentes/mobile-cross-swl.md +541 -541
- package/agentes/mobile-ios-swl.md +502 -502
- package/agentes/mobile-testing-swl.md +302 -302
- package/agentes/nemesis-auditor-swl.md +285 -285
- package/agentes/observabilidad-swl.md +438 -438
- package/agentes/pagos-swl.md +310 -310
- package/agentes/perfilador-usuario-swl.md +321 -321
- package/agentes/planificador-swl.md +399 -399
- package/agentes/producto-prd-swl.md +589 -589
- package/agentes/red-team-swl.md +218 -218
- package/agentes/release-manager-swl.md +590 -590
- package/agentes/rendimiento-swl.md +713 -713
- package/agentes/revisor-angular-swl.md +278 -278
- package/agentes/revisor-csharp-swl.md +264 -264
- package/agentes/revisor-go-swl.md +259 -259
- package/agentes/revisor-java-swl.md +257 -257
- package/agentes/revisor-kotlin-swl.md +273 -273
- package/agentes/revisor-nextjs-swl.md +281 -281
- package/agentes/revisor-php-swl.md +271 -271
- package/agentes/revisor-react-swl.md +278 -278
- package/agentes/revisor-rust-swl.md +346 -346
- package/agentes/revisor-seguridad-swl.md +399 -399
- package/agentes/revisor-swift-swl.md +268 -268
- package/agentes/revisor-typescript-swl.md +346 -346
- package/agentes/tdd-qa-swl.md +393 -393
- package/bin/swl-ses.js +32 -7
- package/comandos/swl/actualizar.md +3 -3
- package/comandos/swl/aprender.md +13 -0
- package/comandos/swl/deuda-codigo.md +97 -97
- package/comandos/swl/evaluar-skill.md +18 -3
- package/comandos/swl/evolucion-continua.md +73 -0
- package/comandos/swl/evolucionar.md +13 -0
- package/comandos/swl/instalar.md +4 -4
- package/comandos/swl/notificaciones.md +1 -1
- package/comandos/swl/status.md +2 -2
- package/gateway/cron/jobs.example.json +12 -0
- package/habilidades/auto-evolucion-protocolo/SKILL.md +19 -1
- package/habilidades/autoresearch/SKILL.md +3 -2
- package/habilidades/backend-async-postgres-testing/SKILL.md +2 -1
- package/habilidades/benchmark-memoria/SKILL.md +7 -7
- package/habilidades/changelog-generator/SKILL.md +1 -1
- package/habilidades/changelog-generator/scripts/parse-commits.js +2 -1
- package/habilidades/checkpoints-verificacion/SKILL.md +6 -0
- package/habilidades/compactacion-contexto/SKILL.md +2 -1
- package/habilidades/contenedores-docker/SKILL.md +4 -2
- package/habilidades/context-builder/SKILL.md +4 -0
- package/habilidades/doubt-driven-review/SKILL.md +17 -1
- package/habilidades/drift-detection/SKILL.md +6 -1
- package/habilidades/ejecutar-fase/SKILL.md +6 -6
- package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
- package/habilidades/eval-framework/SKILL.md +8 -3
- package/habilidades/extractor-de-aprendizajes/SKILL.md +8 -2
- package/habilidades/git-worktrees-paralelo/SKILL.md +19 -1
- package/habilidades/harness-claude-code/SKILL.md +7 -3
- package/habilidades/infra-github-actions/SKILL.md +4 -3
- package/habilidades/instalar-sistema/SKILL.md +5 -1
- package/habilidades/memoria-busqueda/SKILL.md +31 -39
- package/habilidades/planear-fase/SKILL.md +9 -1
- package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
- package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
- package/habilidades/proceso-ddia-fundamentos/SKILL.md +3 -2
- package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -147
- package/habilidades/release-semver/SKILL.md +2 -2
- package/habilidades/swl-claudemd/SKILL.md +6 -7
- package/habilidades/swl-dashboard/SKILL.md +11 -43
- package/habilidades/tdd-workflow/SKILL.md +12 -7
- package/habilidades/validacion-ci-sistema/SKILL.md +1 -1
- package/hooks/agente-lifecycle.js +2 -1
- package/hooks/aiisms-detector.js +13 -4
- package/hooks/audit-trail.js +2 -1
- package/hooks/auto-consolidacion.js +2 -1
- package/hooks/captura-acciones-post.js +2 -1
- package/hooks/captura-acciones-session.js +2 -1
- package/hooks/captura-feedback-usuario.js +3 -2
- package/hooks/claudemd-bloat-detector.js +12 -3
- package/hooks/claudemd-duplicacion-detector.js +13 -3
- package/hooks/contexto-iteracion.js +2 -1
- package/hooks/contexto-subagente.js +68 -68
- package/hooks/degradacion-instintos.js +2 -1
- package/hooks/extraccion-aprendizajes.js +109 -15
- package/hooks/grafo-contexto.js +2 -1
- package/hooks/guardrail-modelo.js +2 -1
- package/hooks/inbox-aviso.js +2 -1
- package/hooks/inyeccion-contexto.js +2 -1
- package/hooks/lib/agent-matcher.js +2 -1
- package/hooks/lib/agent-routing.js +2 -1
- package/hooks/lib/autonomia.js +5 -3
- package/hooks/lib/captura-acciones.js +2 -1
- package/hooks/lib/consolidation-lock.js +21 -10
- package/hooks/lib/etapa-auto-evolucion.js +10 -4
- package/hooks/lib/etapa-metricas.js +2 -1
- package/hooks/lib/etapa-perfil-usuario.js +20 -4
- package/hooks/lib/evolution-tracker.js +2 -1
- package/hooks/lib/gateway-notify.js +17 -3
- package/hooks/lib/loop-telemetry.js +5 -4
- package/hooks/lib/mcp-health.js +2 -1
- package/hooks/lib/memory-search.js +4 -0
- package/hooks/lib/merkle-audit.js +58 -6
- package/hooks/lib/notificacion-formato.js +58 -0
- package/hooks/lib/nudge-tracker.js +2 -1
- package/hooks/lib/otlp-exporter.js +2 -1
- package/hooks/lib/propose-step.js +3 -2
- package/hooks/lib/raiz-proyecto.js +127 -0
- package/hooks/lib/run-log.js +2 -1
- package/hooks/lib/singleton-guard.js +225 -27
- package/hooks/lib/telegram-cliente.js +28 -11
- package/hooks/notificacion-telegram.js +13 -3
- package/hooks/preservar-estado-pre-compact.js +2 -1
- package/hooks/proteccion-rutas.js +59 -3
- package/hooks/registro-turnos.js +2 -1
- package/hooks/resumen-sesion.js +2 -1
- package/hooks/risk-scoring.js +2 -1
- package/hooks/rotar-audit-auto.js +46 -20
- package/hooks/session-briefing.js +127 -1
- package/hooks/spec-gate.js +2 -1
- package/hooks/sugerir-contribuir.js +6 -3
- package/hooks/sugerir-regenerar-inventario.js +3 -2
- package/hooks/tdd-gate.js +2 -1
- package/hooks/telemetria-agentes.js +2 -1
- package/hooks/telemetria-skill-routing.js +2 -1
- package/hooks/tracking-costos.js +4 -3
- package/hooks/validar-formato-post-subagente.js +2 -1
- package/hooks/validar-intent-spec.js +2 -1
- package/hooks/validar-memoria-hook.js +13 -3
- package/hooks/validar-planning-paths.js +2 -1
- package/instintos/perfil-usuario.yaml +506 -3
- package/instintos/proyecto.yaml +78 -0
- package/llms.txt +29 -29
- package/manifiestos/canonical-hashes.json +5588 -4925
- package/manifiestos/hooks-config.json +469 -469
- package/manifiestos/invariantes-criticos.json +30 -30
- package/manifiestos/modulos.json +1429 -1423
- package/manifiestos/planning-paths.json +1 -0
- package/manifiestos/skills-lock.json +1275 -1275
- package/package.json +94 -95
- package/plugin.json +369 -369
- package/scripts/actualizar.js +3 -0
- package/scripts/auditar-clases-conocidas.js +134 -106
- package/scripts/benchmark-memoria.js +1 -0
- package/scripts/bootstrap-instintos.js +85 -14
- package/scripts/canario-hooks.js +166 -166
- package/scripts/cli/autonomia.js +23 -0
- package/scripts/cli/benchmark-memoria.js +37 -0
- package/scripts/cli/ciclo-autonomo.js +73 -0
- package/scripts/cli/ciclo-fase-b.js +102 -0
- package/scripts/cli/guardrail-metrics.js +39 -0
- package/scripts/cli/loop-telemetry.js +4 -2
- package/scripts/cli/memoria-search.js +69 -0
- package/scripts/cli/nudge-accionar.js +39 -0
- package/scripts/cli/run-eval.js +38 -0
- package/scripts/cli/run-skill-evals.js +13 -2
- package/scripts/derivar-feature-list.js +15 -14
- package/scripts/desinstalar.js +11 -0
- package/scripts/doctor.js +50 -13
- package/scripts/evidencia-valor.js +101 -101
- package/scripts/field-report.js +16 -16
- package/scripts/instalador.js +98 -7
- package/scripts/lib/activar-hooks-proyecto.js +116 -104
- package/scripts/lib/auditar-invocaciones-comandos.js +96 -6
- package/scripts/lib/ciclo-autonomo/candidatos.js +174 -0
- package/scripts/lib/ciclo-autonomo/config.js +165 -0
- package/scripts/lib/ciclo-autonomo/drenador-feedback.js +174 -0
- package/scripts/lib/ciclo-autonomo/fallback.js +77 -0
- package/scripts/lib/ciclo-autonomo/guard-convivencia.js +139 -0
- package/scripts/lib/ciclo-autonomo/higiene-nudges.js +112 -0
- package/scripts/lib/ciclo-autonomo/index.js +301 -0
- package/scripts/lib/ciclo-autonomo/lock.js +124 -0
- package/scripts/lib/ciclo-autonomo/presupuesto.js +122 -0
- package/scripts/lib/ciclo-autonomo/puente-degradacion.js +240 -0
- package/scripts/lib/ciclo-autonomo/runner-fase-b.js +248 -0
- package/scripts/lib/ciclo-autonomo/writer-instintos.js +190 -0
- package/scripts/lib/ciclo-autonomo/yaml-instintos.js +535 -0
- package/scripts/lib/estado.js +9 -0
- package/scripts/lib/evidencia-valor.js +228 -228
- package/scripts/lib/expandir-targets.js +71 -71
- package/scripts/lib/gitignore-manifest.js +8 -1
- package/scripts/lib/hooks-settings.js +45 -0
- package/scripts/lib/limpiar-basura-global.js +161 -0
- package/scripts/lib/toml-merge.js +204 -204
- package/scripts/mcp-server/auth.js +105 -105
- package/scripts/mcp-server/cache.js +106 -106
- package/scripts/rotar-audit-logs.js +48 -2
- package/scripts/run-eval.js +1 -0
- package/scripts/run-skill-evals.js +287 -8
- package/scripts/smoke-test.js +16 -8
- package/scripts/tui/pantallas/install-wizard.js +69 -13
- 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.
|
|
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
|
|
77
|
-
`hooks/lib/loop-telemetry.js`
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/hooks/aiisms-detector.js
CHANGED
|
@@ -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
|
-
//
|
|
96
|
-
const CWD = process.cwd();
|
|
97
|
-
|
|
98
|
-
|
|
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
|
|
package/hooks/audit-trail.js
CHANGED
|
@@ -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
|
-
|
|
97
|
-
const
|
|
98
|
-
|
|
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
|
-
|
|
106
|
-
const
|
|
107
|
-
|
|
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
|