@saulwade/swl-ses 2.6.0 → 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 +197 -197
- package/README.md +600 -600
- 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 -932
- 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/comandos/swl/actualizar.md +174 -174
- package/comandos/swl/adoptar-proyecto.md +265 -265
- package/comandos/swl/aprender.md +836 -836
- package/comandos/swl/aprobar-plan.md +146 -146
- package/comandos/swl/auditar-deps.md +134 -134
- package/comandos/swl/autoresearch.md +264 -264
- package/comandos/swl/ayuda.md +224 -224
- package/comandos/swl/brainstorm.md +51 -51
- package/comandos/swl/briefing.md +119 -119
- package/comandos/swl/checkpoint.md +325 -325
- package/comandos/swl/claudemd.md +234 -234
- package/comandos/swl/compactar.md +310 -310
- package/comandos/swl/configurar-ci.md +235 -235
- package/comandos/swl/contexto.md +110 -110
- package/comandos/swl/contribuir.md +233 -233
- package/comandos/swl/crear-skill.md +292 -292
- package/comandos/swl/cron.md +194 -194
- package/comandos/swl/discutir-fase.md +169 -169
- package/comandos/swl/ejecutar-fase.md +233 -233
- package/comandos/swl/evaluar-skill.md +520 -520
- package/comandos/swl/evolucion-continua.md +73 -73
- package/comandos/swl/evolucionar.md +267 -267
- package/comandos/swl/exportar-vault.md +583 -583
- package/comandos/swl/fix.md +118 -118
- package/comandos/swl/gateway.md +158 -158
- package/comandos/swl/inbox.md +116 -116
- package/comandos/swl/instalar.md +220 -220
- package/comandos/swl/instintos.md +86 -86
- package/comandos/swl/mapear-codebase.md +312 -312
- package/comandos/swl/mcp-status.md +175 -175
- package/comandos/swl/modelo.md +100 -100
- package/comandos/swl/nemesis.md +433 -433
- package/comandos/swl/notificaciones.md +299 -299
- package/comandos/swl/nuevo-proyecto.md +251 -251
- package/comandos/swl/planear-fase.md +263 -263
- package/comandos/swl/plugins.md +256 -256
- package/comandos/swl/predecir.md +169 -169
- package/comandos/swl/reflect-skills.md +125 -125
- package/comandos/swl/release.md +450 -450
- package/comandos/swl/revisar-impacto.md +201 -201
- package/comandos/swl/revisar.md +330 -330
- package/comandos/swl/seguridad.md +189 -189
- package/comandos/swl/sesiones.md +200 -200
- package/comandos/swl/skill-search.md +113 -113
- package/comandos/swl/status.md +345 -345
- package/comandos/swl/verificar.md +817 -817
- package/comandos/swl/wiki.md +620 -620
- package/gateway/cron/jobs.example.json +12 -12
- package/habilidades/auto-evolucion-protocolo/SKILL.md +294 -294
- package/habilidades/backend-async-postgres-testing/SKILL.md +2 -1
- package/habilidades/changelog-generator/SKILL.md +174 -174
- package/habilidades/compactacion-contexto/SKILL.md +2 -1
- package/habilidades/contenedores-docker/SKILL.md +4 -2
- package/habilidades/doubt-driven-review/SKILL.md +207 -207
- package/habilidades/drift-detection/SKILL.md +1 -1
- package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
- 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 +314 -314
- package/habilidades/instalar-sistema/SKILL.md +227 -227
- package/habilidades/planear-fase/SKILL.md +358 -358
- 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-ingenieria-requerimientos/SKILL.md +147 -147
- package/habilidades/release-semver/SKILL.md +2 -2
- package/habilidades/tdd-workflow/SKILL.md +749 -749
- package/hooks/agente-lifecycle.js +1 -1
- package/hooks/audit-trail.js +1 -1
- package/hooks/auto-consolidacion.js +1 -1
- package/hooks/captura-acciones-post.js +1 -1
- package/hooks/captura-acciones-session.js +1 -1
- package/hooks/captura-feedback-usuario.js +1 -1
- package/hooks/contexto-iteracion.js +1 -1
- package/hooks/contexto-subagente.js +68 -68
- package/hooks/degradacion-instintos.js +1 -1
- package/hooks/grafo-contexto.js +1 -1
- package/hooks/guardrail-modelo.js +1 -1
- package/hooks/inbox-aviso.js +1 -1
- package/hooks/inyeccion-contexto.js +1 -1
- package/hooks/lib/agent-matcher.js +1 -1
- package/hooks/lib/agent-routing.js +1 -1
- package/hooks/lib/captura-acciones.js +1 -1
- package/hooks/lib/etapa-metricas.js +1 -1
- package/hooks/lib/evolution-tracker.js +1 -1
- package/hooks/lib/gateway-notify.js +193 -193
- package/hooks/lib/mcp-health.js +1 -1
- package/hooks/lib/notificacion-formato.js +58 -0
- package/hooks/lib/nudge-tracker.js +1 -1
- package/hooks/lib/otlp-exporter.js +1 -1
- package/hooks/lib/propose-step.js +1 -1
- package/hooks/lib/raiz-proyecto.js +127 -102
- package/hooks/lib/run-log.js +1 -1
- package/hooks/lib/singleton-guard.js +20 -13
- package/hooks/lib/telegram-cliente.js +11 -3
- package/hooks/notificacion-telegram.js +13 -3
- package/hooks/preservar-estado-pre-compact.js +1 -1
- package/hooks/registro-turnos.js +1 -1
- package/hooks/resumen-sesion.js +1 -1
- package/hooks/risk-scoring.js +1 -1
- package/hooks/session-briefing.js +1 -1
- package/hooks/spec-gate.js +1 -1
- package/hooks/sugerir-regenerar-inventario.js +1 -1
- package/hooks/tdd-gate.js +1 -1
- package/hooks/telemetria-agentes.js +1 -1
- package/hooks/telemetria-skill-routing.js +1 -1
- package/hooks/tracking-costos.js +1 -1
- package/hooks/validar-formato-post-subagente.js +1 -1
- package/hooks/validar-intent-spec.js +1 -1
- package/hooks/validar-planning-paths.js +1 -1
- package/llms.txt +29 -29
- package/manifiestos/canonical-hashes.json +5588 -5257
- package/manifiestos/hooks-config.json +469 -469
- package/manifiestos/invariantes-criticos.json +30 -30
- package/manifiestos/modulos.json +1429 -1428
- package/manifiestos/skills-lock.json +1275 -1275
- package/package.json +94 -94
- package/plugin.json +369 -369
- package/scripts/auditar-clases-conocidas.js +134 -134
- package/scripts/bootstrap-instintos.js +85 -14
- package/scripts/canario-hooks.js +166 -166
- package/scripts/cli/autonomia.js +23 -23
- package/scripts/cli/benchmark-memoria.js +37 -37
- package/scripts/cli/ciclo-autonomo.js +73 -73
- package/scripts/cli/ciclo-fase-b.js +102 -102
- package/scripts/cli/guardrail-metrics.js +39 -39
- package/scripts/cli/memoria-search.js +69 -69
- package/scripts/cli/nudge-accionar.js +39 -39
- package/scripts/cli/run-eval.js +38 -38
- package/scripts/doctor.js +26 -3
- package/scripts/evidencia-valor.js +101 -101
- package/scripts/field-report.js +16 -16
- package/scripts/instalador.js +13 -0
- package/scripts/lib/activar-hooks-proyecto.js +116 -116
- package/scripts/lib/ciclo-autonomo/candidatos.js +174 -174
- package/scripts/lib/ciclo-autonomo/config.js +165 -165
- package/scripts/lib/ciclo-autonomo/drenador-feedback.js +174 -174
- package/scripts/lib/ciclo-autonomo/fallback.js +77 -77
- package/scripts/lib/ciclo-autonomo/guard-convivencia.js +139 -139
- package/scripts/lib/ciclo-autonomo/higiene-nudges.js +112 -112
- package/scripts/lib/ciclo-autonomo/index.js +301 -301
- package/scripts/lib/ciclo-autonomo/lock.js +124 -124
- package/scripts/lib/ciclo-autonomo/presupuesto.js +122 -122
- package/scripts/lib/ciclo-autonomo/puente-degradacion.js +240 -240
- package/scripts/lib/ciclo-autonomo/runner-fase-b.js +248 -248
- package/scripts/lib/ciclo-autonomo/writer-instintos.js +190 -190
- package/scripts/lib/ciclo-autonomo/yaml-instintos.js +535 -535
- package/scripts/lib/evidencia-valor.js +228 -228
- package/scripts/lib/expandir-targets.js +71 -71
- 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/tui/pantallas/install-wizard.js +403 -403
- package/instintos/.backups/perfil-usuario.yaml.2026-07-10-165128.bak +0 -53
- package/instintos/.backups/proyecto.yaml.2026-07-10-165128.bak +0 -372
|
@@ -1,102 +1,127 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* raiz-proyecto.js — Resolución de la raíz del proyecto para hooks que
|
|
5
|
-
* escriben telemetría/memoria en `.planning/`.
|
|
6
|
-
*
|
|
7
|
-
* El CWD de arranque de una sesión NO es la frontera del proyecto: en un
|
|
8
|
-
* monorepo con sesiones abiertas en subdirectorios (`backend/`, `frontend/`),
|
|
9
|
-
* anclar `.planning/` a `process.cwd()` fragmenta la memoria del proyecto en
|
|
10
|
-
* árboles huérfanos (DT-HOOKS-RAIZ-GIT; misma clase que el fix de
|
|
11
|
-
* proteccion-rutas). La frontera correcta es la raíz del repositorio git,
|
|
12
|
-
* con una excepción: un sub-proyecto anidado que ya tiene su propio
|
|
13
|
-
* `.planning/` REAL (con marcadores de proyecto) conserva su árbol local.
|
|
14
|
-
*
|
|
15
|
-
* Reglas de resolución (en orden):
|
|
16
|
-
* 1. Ascendiendo desde `desde`, el primer directorio cuyo `.planning/`
|
|
17
|
-
* contiene un marcador de proyecto (PROYECTO.md, HOJA-RUTA.md,
|
|
18
|
-
* ESTADO.md) gana — respeta sub-proyectos legítimos en monorepos.
|
|
19
|
-
* Un `.planning/` sin marcadores (solo telemetría huérfana de hooks)
|
|
20
|
-
* NO cuenta: eso es el síntoma del bug, no un proyecto.
|
|
21
|
-
* 2. Si ningún nivel tiene `.planning/` real, gana la raíz del repo git
|
|
22
|
-
* (`.git` como directorio o como archivo — worktrees).
|
|
23
|
-
* 3. Sin `.git` alcanzable: fallback al propio `desde`.
|
|
24
|
-
*
|
|
25
|
-
* La ascensión se detiene en el HOME del usuario (sin incluirlo) cuando se
|
|
26
|
-
* llega ahí subiendo: un dotfiles-repo en `~`
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* (
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* (
|
|
41
|
-
*
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* raiz-proyecto.js — Resolución de la raíz del proyecto para hooks que
|
|
5
|
+
* escriben telemetría/memoria en `.planning/`.
|
|
6
|
+
*
|
|
7
|
+
* El CWD de arranque de una sesión NO es la frontera del proyecto: en un
|
|
8
|
+
* monorepo con sesiones abiertas en subdirectorios (`backend/`, `frontend/`),
|
|
9
|
+
* anclar `.planning/` a `process.cwd()` fragmenta la memoria del proyecto en
|
|
10
|
+
* árboles huérfanos (DT-HOOKS-RAIZ-GIT; misma clase que el fix de
|
|
11
|
+
* proteccion-rutas). La frontera correcta es la raíz del repositorio git,
|
|
12
|
+
* con una excepción: un sub-proyecto anidado que ya tiene su propio
|
|
13
|
+
* `.planning/` REAL (con marcadores de proyecto) conserva su árbol local.
|
|
14
|
+
*
|
|
15
|
+
* Reglas de resolución (en orden):
|
|
16
|
+
* 1. Ascendiendo desde `desde`, el primer directorio cuyo `.planning/`
|
|
17
|
+
* contiene un marcador de proyecto (PROYECTO.md, HOJA-RUTA.md,
|
|
18
|
+
* ESTADO.md) gana — respeta sub-proyectos legítimos en monorepos.
|
|
19
|
+
* Un `.planning/` sin marcadores (solo telemetría huérfana de hooks)
|
|
20
|
+
* NO cuenta: eso es el síntoma del bug, no un proyecto.
|
|
21
|
+
* 2. Si ningún nivel tiene `.planning/` real, gana la raíz del repo git
|
|
22
|
+
* (`.git` como directorio o como archivo — worktrees).
|
|
23
|
+
* 3. Sin `.git` alcanzable: fallback al propio `desde`.
|
|
24
|
+
*
|
|
25
|
+
* La ascensión se detiene en el HOME del usuario (sin incluirlo) cuando se
|
|
26
|
+
* llega ahí subiendo: un dotfiles-repo en `~` — o un `~/.planning` sembrado
|
|
27
|
+
* por `swl-ses doctor` en una instalación global — no debe capturar la
|
|
28
|
+
* memoria de un proyecto sin git que viva debajo. La comparación con el HOME
|
|
29
|
+
* se hace en forma CANÓNICA (realpath): en Windows `os.tmpdir()` puede
|
|
30
|
+
* devolver el nombre corto 8.3 (`C:\Users\SAUL~1.WAD`) mientras `os.homedir()`
|
|
31
|
+
* devuelve el largo (`C:\Users\saul.wade`); sin canonicalizar, la frontera no
|
|
32
|
+
* dispararía y capturaría `~/.planning` o `~/.git` (rompía 38 tests locales
|
|
33
|
+
* en Windows, verde en CI Linux porque `/tmp` no cuelga de `$HOME`).
|
|
34
|
+
*
|
|
35
|
+
* Zero-deps (regla de hooks/lib/). Consumidor inicial:
|
|
36
|
+
* hooks/extraccion-aprendizajes.js; la flota completa migró el 2026-07-10
|
|
37
|
+
* (cierre de DT-HOOKS-RAIZ-GIT).
|
|
38
|
+
*
|
|
39
|
+
* LÍMITE DE USO (hallazgo revisor-seguridad 2026-07-10): esta ancla es SOLO
|
|
40
|
+
* para DATOS (.planning/, instintos/, lecturas de config del proyecto).
|
|
41
|
+
* NUNCA resolver con ella EJECUTABLES ni módulos a require()/spawn(): la
|
|
42
|
+
* raíz resuelta pertenece al árbol del proyecto, y un repositorio no
|
|
43
|
+
* confiable puede plantar el script (marcador .planning/PROYECTO.md +
|
|
44
|
+
* scripts/x.js hostil = ejecución de código al disparar el hook). Los
|
|
45
|
+
* ejecutables de la distribución SWL se resuelven desde __dirname
|
|
46
|
+
* (ubicación instalada del hook). Test guardián:
|
|
47
|
+
* tests/hooks/ejecutables-desde-instalacion.test.js.
|
|
48
|
+
*/
|
|
49
|
+
|
|
50
|
+
const fs = require('fs');
|
|
51
|
+
const path = require('path');
|
|
52
|
+
const os = require('os');
|
|
53
|
+
|
|
54
|
+
const MARCADORES_PROYECTO = ['PROYECTO.md', 'HOJA-RUTA.md', 'ESTADO.md'];
|
|
55
|
+
const MAX_NIVELES = 40;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* ¿El directorio tiene un `.planning/` de proyecto real (no huérfano)?
|
|
59
|
+
* @param {string} dir
|
|
60
|
+
* @returns {boolean}
|
|
61
|
+
*/
|
|
62
|
+
function tienePlanningReal(dir) {
|
|
63
|
+
try {
|
|
64
|
+
return MARCADORES_PROYECTO.some(m =>
|
|
65
|
+
fs.existsSync(path.join(dir, '.planning', m))
|
|
66
|
+
);
|
|
67
|
+
} catch (_) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Canonicaliza un path resolviendo enlaces simbólicos y el nombre corto 8.3
|
|
74
|
+
* de Windows (`C:\Users\SAUL~1.WAD` → `C:\Users\saul.wade`). Solo se usa para
|
|
75
|
+
* la comparación de la frontera del HOME: el valor de RETORNO de raizProyecto
|
|
76
|
+
* conserva la forma del argumento recibido, no la canónica. Si el path no
|
|
77
|
+
* existe (no se puede resolver), cae a `path.resolve`.
|
|
78
|
+
* @param {string} p
|
|
79
|
+
* @returns {string}
|
|
80
|
+
*/
|
|
81
|
+
function canonicalizar(p) {
|
|
82
|
+
try {
|
|
83
|
+
return fs.realpathSync.native(p);
|
|
84
|
+
} catch (_) {
|
|
85
|
+
return path.resolve(p);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Resuelve la raíz del proyecto a la que deben anclarse las escrituras
|
|
91
|
+
* de `.planning/`.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} [desde] - Directorio de partida (default: process.cwd()).
|
|
94
|
+
* @returns {string} Ruta absoluta de la raíz del proyecto.
|
|
95
|
+
*/
|
|
96
|
+
function raizProyecto(desde) {
|
|
97
|
+
const inicio = path.resolve(desde || process.cwd());
|
|
98
|
+
let actual = inicio;
|
|
99
|
+
let homedirCanon = null;
|
|
100
|
+
try {
|
|
101
|
+
homedirCanon = canonicalizar(path.resolve(os.homedir()));
|
|
102
|
+
} catch (_) { /* sin home resolvible — seguir sin el guard */ }
|
|
103
|
+
|
|
104
|
+
for (let i = 0; i < MAX_NIVELES; i++) {
|
|
105
|
+
// Frontera del HOME: si llegamos aquí ASCENDIENDO, no seguir — un
|
|
106
|
+
// dotfiles-repo (o un ~/.planning sembrado por doctor) en ~ no es la raíz
|
|
107
|
+
// de un proyecto que vive debajo. Comparación canónica: iguala el nombre
|
|
108
|
+
// corto 8.3 heredado de os.tmpdir() con el HOME largo de os.homedir().
|
|
109
|
+
if (homedirCanon && i > 0 && canonicalizar(actual) === homedirCanon) break;
|
|
110
|
+
|
|
111
|
+
if (tienePlanningReal(actual)) return actual;
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
if (fs.existsSync(path.join(actual, '.git'))) return actual;
|
|
115
|
+
} catch (_) {
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const padre = path.dirname(actual);
|
|
120
|
+
if (padre === actual) break; // raíz del filesystem
|
|
121
|
+
actual = padre;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return inicio;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
module.exports = { raizProyecto, tienePlanningReal, canonicalizar };
|
package/hooks/lib/run-log.js
CHANGED
|
@@ -32,6 +32,7 @@ const DIR_LOCKS = path.join(raizProyecto(process.cwd()), '.planning', 'locks');
|
|
|
32
32
|
const STALE_MS_DEFAULT = 5 * 60 * 1000; // 5 minutos
|
|
33
33
|
const locksAdquiridos = new Set();
|
|
34
34
|
let handlersRegistrados = false;
|
|
35
|
+
let seqTmp = 0; // secuencia para nombres de temp únicos por proceso
|
|
35
36
|
|
|
36
37
|
function rutaLock(nombre) {
|
|
37
38
|
return path.join(DIR_LOCKS, `${nombre}.lock`);
|
|
@@ -60,28 +61,34 @@ function pidVivo(pid) {
|
|
|
60
61
|
}
|
|
61
62
|
|
|
62
63
|
/**
|
|
63
|
-
* Escribe el lockfile con exclusión atómica
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
64
|
+
* Escribe el lockfile con exclusión atómica y SIN ventana de archivo vacío:
|
|
65
|
+
* escribe el contenido completo en un temp único y lo ENLAZA (link(2)) a `ruta`.
|
|
66
|
+
* link es atómico y falla con EEXIST si `ruta` ya existe — misma garantía de
|
|
67
|
+
* exclusión mutua que O_EXCL — pero, a diferencia de open('wx')+write, `ruta`
|
|
68
|
+
* NUNCA aparece vacío: el inodo enlazado ya trae el JSON completo.
|
|
69
|
+
*
|
|
70
|
+
* Por qué NO open('wx')+write (hallazgo 2026-07-15): esa forma crea el archivo
|
|
71
|
+
* vacío y ESCRIBE después. Un contendiente en el path de takeover que lo leyera
|
|
72
|
+
* en esa ventana obtenía '' → JSON.parse lanza → leerLock=null →
|
|
73
|
+
* contenidoTomable(null)=true → hacía takeover de un lock YA ganado → DOS
|
|
74
|
+
* holders. Reproducido a ~10% con 16 procesos simultáneos sobre el path stale;
|
|
75
|
+
* antes no se veía porque el test no forzaba simultaneidad real.
|
|
76
|
+
* (Precedente: fs.existsSync+writeFileSync tampoco sirve — nemesis iter-2.)
|
|
68
77
|
*
|
|
69
78
|
* @param {string} ruta
|
|
70
79
|
* @param {string} nombre
|
|
71
80
|
* @returns {boolean} true si este proceso creó el lock.
|
|
72
81
|
*/
|
|
73
82
|
function crearLockExclusivo(ruta, nombre) {
|
|
83
|
+
const tmp = `${ruta}.${process.pid}.${++seqTmp}.tmp`;
|
|
74
84
|
try {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
fs.writeFileSync(fd, JSON.stringify({ pid: process.pid, ts: new Date().toISOString(), nombre }));
|
|
78
|
-
} finally {
|
|
79
|
-
fs.closeSync(fd);
|
|
80
|
-
}
|
|
85
|
+
fs.writeFileSync(tmp, JSON.stringify({ pid: process.pid, ts: new Date().toISOString(), nombre }));
|
|
86
|
+
fs.linkSync(tmp, ruta); // atómico; lanza EEXIST si `ruta` ya existe
|
|
81
87
|
return true;
|
|
82
88
|
} catch (err) {
|
|
83
|
-
|
|
84
|
-
|
|
89
|
+
return false; // EEXIST (otro ganó) u otro error de I/O → no se adquirió
|
|
90
|
+
} finally {
|
|
91
|
+
try { fs.unlinkSync(tmp); } catch (_) { /* temp ya removido o nunca creado */ }
|
|
85
92
|
}
|
|
86
93
|
}
|
|
87
94
|
|
|
@@ -130,15 +130,23 @@ function _esperar(ms) {
|
|
|
130
130
|
*
|
|
131
131
|
* @param {string} token - Token del bot (`123:ABC...`).
|
|
132
132
|
* @param {string} chatId - ID numérico del chat destino.
|
|
133
|
-
* @param {string} texto - Texto del mensaje.
|
|
133
|
+
* @param {string} texto - Texto del mensaje. Por default se escapa (el llamador
|
|
134
|
+
* pasa texto PLANO). Si el llamador ya construyó HTML válido (tags + contenido
|
|
135
|
+
* escapado), pasar `opts.escaparContenido = false` para NO re-escapar — de lo
|
|
136
|
+
* contrario los `<b>` se convierten en `<b>` y Telegram los muestra
|
|
137
|
+
* literales (doble escape; bug 2026-07-15).
|
|
134
138
|
* @param {object} [opts] - Campos adicionales para el body de sendMessage.
|
|
139
|
+
* @param {boolean} [opts.escaparContenido=true] - Escapar HTML del texto (para
|
|
140
|
+
* llamadores que pasan texto plano). false si el texto YA es HTML listo.
|
|
135
141
|
* @returns {Promise<{ok: boolean, statusCode: number, error?: string}>}
|
|
136
142
|
*/
|
|
137
143
|
async function enviarMensaje(token, chatId, texto, opts = {}) {
|
|
138
|
-
const
|
|
144
|
+
const { escaparContenido = true, ...payloadOpts } = opts;
|
|
145
|
+
const base = escaparContenido ? escaparHtml(texto) : String(texto);
|
|
146
|
+
const textoPrepado = truncar(base, LIMITE_CHARS);
|
|
139
147
|
|
|
140
148
|
for (let intento = 0; intento < REINTENTOS_MAX; intento++) {
|
|
141
|
-
const resultado = await _intentarEnvio(token, chatId, textoPrepado,
|
|
149
|
+
const resultado = await _intentarEnvio(token, chatId, textoPrepado, payloadOpts);
|
|
142
150
|
|
|
143
151
|
if (resultado.ok) {
|
|
144
152
|
return { ok: true, statusCode: resultado.statusCode };
|
|
@@ -23,6 +23,7 @@ const path = require('node:path');
|
|
|
23
23
|
|
|
24
24
|
const { cargarConfig, estaMuted } = require('./lib/telegram-config');
|
|
25
25
|
const { enviarMensaje, escaparHtml } = require('./lib/telegram-cliente');
|
|
26
|
+
const { resumirParaNotificacion } = require('./lib/notificacion-formato');
|
|
26
27
|
|
|
27
28
|
// ----------------------------------------------------------------
|
|
28
29
|
// Utilidades de logging
|
|
@@ -121,7 +122,7 @@ function construirCampos(nombreEvento, nombreProyecto, transcriptPath, evt) {
|
|
|
121
122
|
if (nombreEvento === 'Stop' || nombreEvento === 'SubagentStop') {
|
|
122
123
|
tituloBase = nombreEvento === 'SubagentStop' ? 'Subagente terminó' : 'Claude terminó';
|
|
123
124
|
subtitulo = 'Turno completado';
|
|
124
|
-
cuerpo = leerUltimoMensajeAsistente(transcriptPath) || 'Claude terminó el turno.';
|
|
125
|
+
cuerpo = resumirParaNotificacion(leerUltimoMensajeAsistente(transcriptPath)) || 'Claude terminó el turno.';
|
|
125
126
|
|
|
126
127
|
} else if (nombreEvento === 'Notification') {
|
|
127
128
|
tituloBase = 'Claude espera respuesta';
|
|
@@ -262,14 +263,23 @@ async function run() {
|
|
|
262
263
|
`<b>Estado:</b> ${escaparHtml(subtitulo)}\n\n` +
|
|
263
264
|
`${escaparHtml(cuerpo)}`;
|
|
264
265
|
|
|
265
|
-
// Enviar notificación Telegram
|
|
266
|
+
// Enviar notificación Telegram. escaparContenido:false porque `texto` YA es
|
|
267
|
+
// HTML listo (tags <b> + contenido escapado arriba); re-escaparlo mostraría
|
|
268
|
+
// los tags literales en Telegram (doble escape, bug 2026-07-15).
|
|
266
269
|
const resultado = await enviarMensaje(
|
|
267
270
|
config.TELEGRAM_BOT_TOKEN,
|
|
268
271
|
config.TELEGRAM_CHAT_ID,
|
|
269
|
-
texto
|
|
272
|
+
texto,
|
|
273
|
+
{ escaparContenido: false }
|
|
270
274
|
);
|
|
271
275
|
|
|
272
276
|
log('telegram resultado', resultado.ok ? 'ok' : resultado.error);
|
|
273
277
|
}
|
|
274
278
|
|
|
279
|
+
// Sin gate de entrypoint: los hooks se invocan vía el wrapper
|
|
280
|
+
// `node -e "require('./hooks/notificacion-telegram.js')"` de settings.json (y
|
|
281
|
+
// desde los wrappers -notification/-subagent), donde require.main es undefined;
|
|
282
|
+
// un gate de entrypoint dejaría el hook muerto en producción (audit
|
|
283
|
+
// entrypoint-wrapper.test.js). Las funciones puras testeables viven en
|
|
284
|
+
// ./lib/notificacion-formato.js.
|
|
275
285
|
run().catch(e => log('run error', e && e.message));
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
const fs = require('fs');
|
|
23
|
-
const { raizProyecto } = require('./lib/raiz-proyecto');
|
|
23
|
+
const { raizProyecto } = require('./lib/raiz-proyecto');
|
|
24
24
|
const path = require('path');
|
|
25
25
|
|
|
26
26
|
// Atomic write para backups pre-compact (.planning/backups/). Si la
|
package/hooks/registro-turnos.js
CHANGED
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
*/
|
|
55
55
|
|
|
56
56
|
const fs = require('fs');
|
|
57
|
-
const { raizProyecto } = require('./lib/raiz-proyecto');
|
|
57
|
+
const { raizProyecto } = require('./lib/raiz-proyecto');
|
|
58
58
|
const path = require('path');
|
|
59
59
|
|
|
60
60
|
const LIMITE_TURNOS = parseInt(process.env.SWL_REGISTRO_TURNOS_LIMITE || '1000', 10);
|
package/hooks/resumen-sesion.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
const fs = require('fs');
|
|
21
|
-
const { raizProyecto } = require('./lib/raiz-proyecto');
|
|
21
|
+
const { raizProyecto } = require('./lib/raiz-proyecto');
|
|
22
22
|
const path = require('path');
|
|
23
23
|
const os = require('os');
|
|
24
24
|
const { execFile } = require('child_process');
|
package/hooks/risk-scoring.js
CHANGED
package/hooks/spec-gate.js
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
*/
|
|
28
28
|
|
|
29
29
|
const fs = require('fs');
|
|
30
|
-
const { raizProyecto } = require('./lib/raiz-proyecto');
|
|
30
|
+
const { raizProyecto } = require('./lib/raiz-proyecto');
|
|
31
31
|
const path = require('path');
|
|
32
32
|
|
|
33
33
|
// Carpetas cuyo cambio invalida los contadores de INVENTARIO.md
|
package/hooks/tdd-gate.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
const { registrar } = require('./lib/otlp-exporter');
|
|
20
|
-
const { raizProyecto } = require('./lib/raiz-proyecto');
|
|
20
|
+
const { raizProyecto } = require('./lib/raiz-proyecto');
|
|
21
21
|
|
|
22
22
|
// Importar esquema de spans con guard de robustez — el hook no debe fallar
|
|
23
23
|
// si el módulo aún no existe en instalaciones anteriores del sistema.
|
package/hooks/tracking-costos.js
CHANGED
package/llms.txt
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
# swl-ses (@saulwade/swl-ses)
|
|
2
|
-
|
|
3
|
-
> Sistema de ingeniería de software auto-evolutivo multi-runtime polyglot (SDLC completo), distribuido como paquete npm y plugin de Claude Code. 61 agentes, 181 habilidades, 48 comandos, 37 reglas base y 49 hooks. Soporta 11 lenguajes y 7 runtimes (Claude Code, OpenClaude, OpenCode, Gemini, Cursor, Codex, Copilot). Versión 2.6.
|
|
4
|
-
|
|
5
|
-
Archivo generado por `node scripts/generar-inventario.js` — no editar a mano. Las cifras se sincronizan con INVENTARIO.md en cada regeneración.
|
|
6
|
-
|
|
7
|
-
## Documentación
|
|
8
|
-
|
|
9
|
-
- [README](README.md): overview público y quickstart
|
|
10
|
-
- [Manual de uso](MANUAL_USO.md): manual operacional completo
|
|
11
|
-
- [Comandos](COMANDOS.md): referencia detallada de cada comando `/swl:*`
|
|
12
|
-
- [Agentes](AGENTS.md): catálogo de agentes con capacidades
|
|
13
|
-
- [Inventario](INVENTARIO.md): conteos oficiales de todos los componentes
|
|
14
|
-
- [Instalación](INSTALACION.md): instalación, perfiles y configuración
|
|
15
|
-
- [Instrucciones del proyecto](CLAUDE.md): convenciones, stack y reglas
|
|
16
|
-
|
|
17
|
-
## Componentes
|
|
18
|
-
|
|
19
|
-
- [61 agentes especializados](AGENTS.md): orquestación, implementación por stack, revisión, calidad, diseño — fuente en `agentes/`
|
|
20
|
-
- [181 habilidades cargables bajo demanda](INVENTARIO.md): conocimiento operacional con divulgación progresiva — fuente en `habilidades/`
|
|
21
|
-
- [48 comandos /swl:*](COMANDOS.md): ciclo GSD, calidad, release, diagnóstico — fuente en `comandos/swl/`
|
|
22
|
-
- [37 reglas base + 40 por lenguaje](INVENTARIO.md): políticas obligatorias por matcher — fuente en `reglas/`
|
|
23
|
-
- [49 hooks](INVENTARIO.md): telemetría, validación, seguridad; zero-deps, escrituras atómicas — fuente en `hooks/`
|
|
24
|
-
|
|
25
|
-
## Opcional
|
|
26
|
-
|
|
27
|
-
- [CHANGELOG](CHANGELOG.md): historial de versiones
|
|
28
|
-
- [Índice de ADRs](.planning/adrs/README.md): decisiones de arquitectura
|
|
29
|
-
- [Variables de entorno](docs/variables-entorno.md): configuración opt-in
|
|
1
|
+
# swl-ses (@saulwade/swl-ses)
|
|
2
|
+
|
|
3
|
+
> Sistema de ingeniería de software auto-evolutivo multi-runtime polyglot (SDLC completo), distribuido como paquete npm y plugin de Claude Code. 61 agentes, 181 habilidades, 48 comandos, 37 reglas base y 49 hooks. Soporta 11 lenguajes y 7 runtimes (Claude Code, OpenClaude, OpenCode, Gemini, Cursor, Codex, Copilot). Versión 2.6.1.
|
|
4
|
+
|
|
5
|
+
Archivo generado por `node scripts/generar-inventario.js` — no editar a mano. Las cifras se sincronizan con INVENTARIO.md en cada regeneración.
|
|
6
|
+
|
|
7
|
+
## Documentación
|
|
8
|
+
|
|
9
|
+
- [README](README.md): overview público y quickstart
|
|
10
|
+
- [Manual de uso](MANUAL_USO.md): manual operacional completo
|
|
11
|
+
- [Comandos](COMANDOS.md): referencia detallada de cada comando `/swl:*`
|
|
12
|
+
- [Agentes](AGENTS.md): catálogo de agentes con capacidades
|
|
13
|
+
- [Inventario](INVENTARIO.md): conteos oficiales de todos los componentes
|
|
14
|
+
- [Instalación](INSTALACION.md): instalación, perfiles y configuración
|
|
15
|
+
- [Instrucciones del proyecto](CLAUDE.md): convenciones, stack y reglas
|
|
16
|
+
|
|
17
|
+
## Componentes
|
|
18
|
+
|
|
19
|
+
- [61 agentes especializados](AGENTS.md): orquestación, implementación por stack, revisión, calidad, diseño — fuente en `agentes/`
|
|
20
|
+
- [181 habilidades cargables bajo demanda](INVENTARIO.md): conocimiento operacional con divulgación progresiva — fuente en `habilidades/`
|
|
21
|
+
- [48 comandos /swl:*](COMANDOS.md): ciclo GSD, calidad, release, diagnóstico — fuente en `comandos/swl/`
|
|
22
|
+
- [37 reglas base + 40 por lenguaje](INVENTARIO.md): políticas obligatorias por matcher — fuente en `reglas/`
|
|
23
|
+
- [49 hooks](INVENTARIO.md): telemetría, validación, seguridad; zero-deps, escrituras atómicas — fuente en `hooks/`
|
|
24
|
+
|
|
25
|
+
## Opcional
|
|
26
|
+
|
|
27
|
+
- [CHANGELOG](CHANGELOG.md): historial de versiones
|
|
28
|
+
- [Índice de ADRs](.planning/adrs/README.md): decisiones de arquitectura
|
|
29
|
+
- [Variables de entorno](docs/variables-entorno.md): configuración opt-in
|