@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,134 +1,134 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* auditar-clases-conocidas.js — Gate de clases de bug ya documentadas.
|
|
6
|
-
*
|
|
7
|
-
* "El conocimiento documentado no previene — solo los gates previenen."
|
|
8
|
-
* Cada clase de este gate mordió al proyecto en producción pese a estar
|
|
9
|
-
* escrita como regla/aprendizaje. El gate la vuelve imposible de reintroducir:
|
|
10
|
-
*
|
|
11
|
-
* C1 — Fecha UTC truncada: toISOString + slice(0,10) fecha artefactos
|
|
12
|
-
* "mañana" desde México (23 instancias corregidas 2026-07-08/09).
|
|
13
|
-
* Correcto: `toLocaleDateString('sv')`. Escape: `// fecha-utc-ok`.
|
|
14
|
-
* (El patrón no se escribe literal aquí: el gate escanea este archivo
|
|
15
|
-
* también — se auto-detectó en el publish v2.5.1.)
|
|
16
|
-
* C2 — Comparación byte a byte en modos --check: comparar texto leído de
|
|
17
|
-
* disco sin normalizar EOL revienta con CRLF tras checkout/reset de
|
|
18
|
-
* git (tumbó el publish v2.5.0). Un script con modo --check que lee
|
|
19
|
-
* texto debe normalizar `\r\n` o comparar estructuras (JSON.parse).
|
|
20
|
-
* Escape: `// eol-ok: <razón>`.
|
|
21
|
-
* C3 — Bloqueo ciego en hooks: exit(2) sin console.error deja al modelo
|
|
22
|
-
* sin la razón del bloqueo (el canal de exit 2 es stderr).
|
|
23
|
-
* C4 — Ancla .planning/instintos al CWD crudo en hooks: en monorepos con
|
|
24
|
-
* sesión abierta en un subdirectorio fragmenta la memoria del proyecto
|
|
25
|
-
* en árboles huérfanos (DT-HOOKS-RAIZ-GIT, reportes de campo oic+sigm
|
|
26
|
-
* 2026-07-10; flota completa migrada el mismo día). Correcto:
|
|
27
|
-
* `raizProyecto(process.cwd())` de hooks/lib/raiz-proyecto.js.
|
|
28
|
-
* Escape: `// raiz-ok: <razón>`. Solo hooks/** — los scripts CLI se
|
|
29
|
-
* invocan desde la raíz del proyecto por contrato, y el instalador
|
|
30
|
-
* ancla al cwd DELIBERADAMENTE (instala hacia ese proyecto; saltar a
|
|
31
|
-
* un repo padre sería un bug).
|
|
32
|
-
*
|
|
33
|
-
* Alcance: archivos .js versionados en scripts/, hooks/, bin/, gateway/ y
|
|
34
|
-
* los scripts ejecutables de skills (habilidades/<skill>/scripts/) —
|
|
35
|
-
* parse-commits.js escapó al gate C1 hasta 2026-07-10 por no estar en el alcance.
|
|
36
|
-
* (tests/ excluido: los tests DEBEN poder citar el patrón para validarlo.)
|
|
37
|
-
* Exit: 0 limpio · 1 con hallazgos.
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
const { execFileSync } = require('child_process');
|
|
41
|
-
const fs = require('fs');
|
|
42
|
-
const path = require('path');
|
|
43
|
-
|
|
44
|
-
const RAIZ = path.resolve(__dirname, '..');
|
|
45
|
-
|
|
46
|
-
const RX_UTC = /toISOString\(\)\s*\.\s*(?:slice|substring)\s*\(\s*0\s*,\s*10\s*\)/;
|
|
47
|
-
const RX_ESCAPE_UTC = /fecha-utc-ok/;
|
|
48
|
-
const RX_ESCAPE_EOL = /eol-ok:/;
|
|
49
|
-
// C4: join directo del cwd crudo con .planning o instintos. El patrón se
|
|
50
|
-
// construye por concatenación para que el gate no se detecte a sí mismo.
|
|
51
|
-
const RX_CWD_PLANNING = new RegExp(
|
|
52
|
-
'join\\(\\s*process\\.cwd\\(\\)\\s*,\\s*[\'"]' + '(?:\\.plan' + 'ning|instin' + 'tos)'
|
|
53
|
-
);
|
|
54
|
-
const RX_ESCAPE_RAIZ = /raiz-ok:/;
|
|
55
|
-
|
|
56
|
-
function archivosObjetivo() {
|
|
57
|
-
const salida = execFileSync('git', [
|
|
58
|
-
'ls-files', '--',
|
|
59
|
-
'scripts/*.js', 'scripts/**/*.js',
|
|
60
|
-
'hooks/*.js', 'hooks/**/*.js',
|
|
61
|
-
'bin/*.js',
|
|
62
|
-
'gateway/*.js', 'gateway/**/*.js',
|
|
63
|
-
'habilidades/*/scripts/*.js', 'habilidades/*/scripts/**/*.js',
|
|
64
|
-
], { cwd: RAIZ, encoding: 'utf8' });
|
|
65
|
-
return salida.split(/\r?\n/).filter(f => f && !f.includes('vendor/'));
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function auditarUtc(ruta, lineas, hallazgos) {
|
|
69
|
-
lineas.forEach((linea, i) => {
|
|
70
|
-
if (RX_UTC.test(linea) && !RX_ESCAPE_UTC.test(linea)) {
|
|
71
|
-
hallazgos.push(`[C1 fecha-UTC] ${ruta}:${i + 1} — toISOString().slice(0,10) fecha "mañana" desde UTC-6; usar toLocaleDateString('sv') o marcar \`// fecha-utc-ok\` si la semántica UTC es deliberada`);
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function auditarEolCheck(ruta, contenido, hallazgos) {
|
|
77
|
-
// Aplica solo a GENERADORES con modo --check (escriben el artefacto y en
|
|
78
|
-
// check comparan lo regenerado contra disco). Un --check selector de
|
|
79
|
-
// sub-checks (verificar-docs) no compara texto por igualdad — no aplica.
|
|
80
|
-
if (!contenido.includes("'--check'") && !contenido.includes('"--check"')) return;
|
|
81
|
-
if (!/atomicWrite|writeFileSync/.test(contenido)) return;
|
|
82
|
-
if (!/readFileSync\([^)]*utf-?8/i.test(contenido)) return;
|
|
83
|
-
const normaliza = contenido.includes('\\r\\n') || contenido.includes('\\r?\\n');
|
|
84
|
-
const comparaEstructura = contenido.includes('JSON.parse');
|
|
85
|
-
const escape = RX_ESCAPE_EOL.test(contenido);
|
|
86
|
-
if (!normaliza && !comparaEstructura && !escape) {
|
|
87
|
-
hallazgos.push(`[C2 EOL] ${ruta} — modo --check que lee texto sin normalizar \\r\\n ni comparar estructuras: reventará con CRLF tras checkout/reset de git (caso publish v2.5.0). Normalizar EOL antes de comparar o marcar \`// eol-ok: <razón>\``);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function auditarBloqueoCiego(ruta, contenido, hallazgos) {
|
|
92
|
-
if (!ruta.startsWith('hooks/') || ruta.startsWith('hooks/lib/')) return;
|
|
93
|
-
const usaExit2 = /exit\(2\)|exitCode\s*=\s*2/.test(contenido);
|
|
94
|
-
const escribeStderr = contenido.includes('console.error') || contenido.includes('process.stderr.write');
|
|
95
|
-
if (usaExit2 && !escribeStderr) {
|
|
96
|
-
hallazgos.push(`[C3 bloqueo-ciego] ${ruta} — usa exit 2 sin escribir a stderr (console.error/process.stderr.write): el modelo recibe el bloqueo sin la razón`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function auditarCwdPlanning(ruta, lineas, hallazgos) {
|
|
101
|
-
if (!ruta.startsWith('hooks/')) return;
|
|
102
|
-
lineas.forEach((linea, i) => {
|
|
103
|
-
if (RX_CWD_PLANNING.test(linea) && !RX_ESCAPE_RAIZ.test(linea)) {
|
|
104
|
-
hallazgos.push(`[C4 raiz-proyecto] ${ruta}:${i + 1} — ancla .planning/instintos a process.cwd() crudo: fragmenta la memoria en monorepos (DT-HOOKS-RAIZ-GIT); usar raizProyecto(process.cwd()) de hooks/lib/raiz-proyecto.js o marcar \`// raiz-ok: <razón>\``);
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function main() {
|
|
110
|
-
const hallazgos = [];
|
|
111
|
-
const archivos = archivosObjetivo();
|
|
112
|
-
for (const ruta of archivos) {
|
|
113
|
-
let contenido;
|
|
114
|
-
try {
|
|
115
|
-
contenido = fs.readFileSync(path.join(RAIZ, ruta), 'utf8');
|
|
116
|
-
} catch { continue; }
|
|
117
|
-
const lineas = contenido.split(/\r?\n/);
|
|
118
|
-
auditarUtc(ruta, lineas, hallazgos);
|
|
119
|
-
auditarEolCheck(ruta, contenido, hallazgos);
|
|
120
|
-
auditarBloqueoCiego(ruta, contenido, hallazgos);
|
|
121
|
-
auditarCwdPlanning(ruta, lineas, hallazgos);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (hallazgos.length === 0) {
|
|
125
|
-
console.log(`[clases-conocidas] OK — ${archivos.length} archivos, 0 reincidencias de clases documentadas (C1 UTC, C2 EOL, C3 bloqueo ciego, C4 ancla cwd)`);
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
console.error(`[clases-conocidas] ${hallazgos.length} reincidencia(s) de clases de bug documentadas:`);
|
|
129
|
-
for (const h of hallazgos) console.error(' ' + h);
|
|
130
|
-
process.exitCode = 1;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
module.exports = { auditarUtc, auditarEolCheck, auditarBloqueoCiego, auditarCwdPlanning };
|
|
134
|
-
if (require.main === module) main();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* auditar-clases-conocidas.js — Gate de clases de bug ya documentadas.
|
|
6
|
+
*
|
|
7
|
+
* "El conocimiento documentado no previene — solo los gates previenen."
|
|
8
|
+
* Cada clase de este gate mordió al proyecto en producción pese a estar
|
|
9
|
+
* escrita como regla/aprendizaje. El gate la vuelve imposible de reintroducir:
|
|
10
|
+
*
|
|
11
|
+
* C1 — Fecha UTC truncada: toISOString + slice(0,10) fecha artefactos
|
|
12
|
+
* "mañana" desde México (23 instancias corregidas 2026-07-08/09).
|
|
13
|
+
* Correcto: `toLocaleDateString('sv')`. Escape: `// fecha-utc-ok`.
|
|
14
|
+
* (El patrón no se escribe literal aquí: el gate escanea este archivo
|
|
15
|
+
* también — se auto-detectó en el publish v2.5.1.)
|
|
16
|
+
* C2 — Comparación byte a byte en modos --check: comparar texto leído de
|
|
17
|
+
* disco sin normalizar EOL revienta con CRLF tras checkout/reset de
|
|
18
|
+
* git (tumbó el publish v2.5.0). Un script con modo --check que lee
|
|
19
|
+
* texto debe normalizar `\r\n` o comparar estructuras (JSON.parse).
|
|
20
|
+
* Escape: `// eol-ok: <razón>`.
|
|
21
|
+
* C3 — Bloqueo ciego en hooks: exit(2) sin console.error deja al modelo
|
|
22
|
+
* sin la razón del bloqueo (el canal de exit 2 es stderr).
|
|
23
|
+
* C4 — Ancla .planning/instintos al CWD crudo en hooks: en monorepos con
|
|
24
|
+
* sesión abierta en un subdirectorio fragmenta la memoria del proyecto
|
|
25
|
+
* en árboles huérfanos (DT-HOOKS-RAIZ-GIT, reportes de campo oic+sigm
|
|
26
|
+
* 2026-07-10; flota completa migrada el mismo día). Correcto:
|
|
27
|
+
* `raizProyecto(process.cwd())` de hooks/lib/raiz-proyecto.js.
|
|
28
|
+
* Escape: `// raiz-ok: <razón>`. Solo hooks/** — los scripts CLI se
|
|
29
|
+
* invocan desde la raíz del proyecto por contrato, y el instalador
|
|
30
|
+
* ancla al cwd DELIBERADAMENTE (instala hacia ese proyecto; saltar a
|
|
31
|
+
* un repo padre sería un bug).
|
|
32
|
+
*
|
|
33
|
+
* Alcance: archivos .js versionados en scripts/, hooks/, bin/, gateway/ y
|
|
34
|
+
* los scripts ejecutables de skills (habilidades/<skill>/scripts/) —
|
|
35
|
+
* parse-commits.js escapó al gate C1 hasta 2026-07-10 por no estar en el alcance.
|
|
36
|
+
* (tests/ excluido: los tests DEBEN poder citar el patrón para validarlo.)
|
|
37
|
+
* Exit: 0 limpio · 1 con hallazgos.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
const { execFileSync } = require('child_process');
|
|
41
|
+
const fs = require('fs');
|
|
42
|
+
const path = require('path');
|
|
43
|
+
|
|
44
|
+
const RAIZ = path.resolve(__dirname, '..');
|
|
45
|
+
|
|
46
|
+
const RX_UTC = /toISOString\(\)\s*\.\s*(?:slice|substring)\s*\(\s*0\s*,\s*10\s*\)/;
|
|
47
|
+
const RX_ESCAPE_UTC = /fecha-utc-ok/;
|
|
48
|
+
const RX_ESCAPE_EOL = /eol-ok:/;
|
|
49
|
+
// C4: join directo del cwd crudo con .planning o instintos. El patrón se
|
|
50
|
+
// construye por concatenación para que el gate no se detecte a sí mismo.
|
|
51
|
+
const RX_CWD_PLANNING = new RegExp(
|
|
52
|
+
'join\\(\\s*process\\.cwd\\(\\)\\s*,\\s*[\'"]' + '(?:\\.plan' + 'ning|instin' + 'tos)'
|
|
53
|
+
);
|
|
54
|
+
const RX_ESCAPE_RAIZ = /raiz-ok:/;
|
|
55
|
+
|
|
56
|
+
function archivosObjetivo() {
|
|
57
|
+
const salida = execFileSync('git', [
|
|
58
|
+
'ls-files', '--',
|
|
59
|
+
'scripts/*.js', 'scripts/**/*.js',
|
|
60
|
+
'hooks/*.js', 'hooks/**/*.js',
|
|
61
|
+
'bin/*.js',
|
|
62
|
+
'gateway/*.js', 'gateway/**/*.js',
|
|
63
|
+
'habilidades/*/scripts/*.js', 'habilidades/*/scripts/**/*.js',
|
|
64
|
+
], { cwd: RAIZ, encoding: 'utf8' });
|
|
65
|
+
return salida.split(/\r?\n/).filter(f => f && !f.includes('vendor/'));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function auditarUtc(ruta, lineas, hallazgos) {
|
|
69
|
+
lineas.forEach((linea, i) => {
|
|
70
|
+
if (RX_UTC.test(linea) && !RX_ESCAPE_UTC.test(linea)) {
|
|
71
|
+
hallazgos.push(`[C1 fecha-UTC] ${ruta}:${i + 1} — toISOString().slice(0,10) fecha "mañana" desde UTC-6; usar toLocaleDateString('sv') o marcar \`// fecha-utc-ok\` si la semántica UTC es deliberada`);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function auditarEolCheck(ruta, contenido, hallazgos) {
|
|
77
|
+
// Aplica solo a GENERADORES con modo --check (escriben el artefacto y en
|
|
78
|
+
// check comparan lo regenerado contra disco). Un --check selector de
|
|
79
|
+
// sub-checks (verificar-docs) no compara texto por igualdad — no aplica.
|
|
80
|
+
if (!contenido.includes("'--check'") && !contenido.includes('"--check"')) return;
|
|
81
|
+
if (!/atomicWrite|writeFileSync/.test(contenido)) return;
|
|
82
|
+
if (!/readFileSync\([^)]*utf-?8/i.test(contenido)) return;
|
|
83
|
+
const normaliza = contenido.includes('\\r\\n') || contenido.includes('\\r?\\n');
|
|
84
|
+
const comparaEstructura = contenido.includes('JSON.parse');
|
|
85
|
+
const escape = RX_ESCAPE_EOL.test(contenido);
|
|
86
|
+
if (!normaliza && !comparaEstructura && !escape) {
|
|
87
|
+
hallazgos.push(`[C2 EOL] ${ruta} — modo --check que lee texto sin normalizar \\r\\n ni comparar estructuras: reventará con CRLF tras checkout/reset de git (caso publish v2.5.0). Normalizar EOL antes de comparar o marcar \`// eol-ok: <razón>\``);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function auditarBloqueoCiego(ruta, contenido, hallazgos) {
|
|
92
|
+
if (!ruta.startsWith('hooks/') || ruta.startsWith('hooks/lib/')) return;
|
|
93
|
+
const usaExit2 = /exit\(2\)|exitCode\s*=\s*2/.test(contenido);
|
|
94
|
+
const escribeStderr = contenido.includes('console.error') || contenido.includes('process.stderr.write');
|
|
95
|
+
if (usaExit2 && !escribeStderr) {
|
|
96
|
+
hallazgos.push(`[C3 bloqueo-ciego] ${ruta} — usa exit 2 sin escribir a stderr (console.error/process.stderr.write): el modelo recibe el bloqueo sin la razón`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function auditarCwdPlanning(ruta, lineas, hallazgos) {
|
|
101
|
+
if (!ruta.startsWith('hooks/')) return;
|
|
102
|
+
lineas.forEach((linea, i) => {
|
|
103
|
+
if (RX_CWD_PLANNING.test(linea) && !RX_ESCAPE_RAIZ.test(linea)) {
|
|
104
|
+
hallazgos.push(`[C4 raiz-proyecto] ${ruta}:${i + 1} — ancla .planning/instintos a process.cwd() crudo: fragmenta la memoria en monorepos (DT-HOOKS-RAIZ-GIT); usar raizProyecto(process.cwd()) de hooks/lib/raiz-proyecto.js o marcar \`// raiz-ok: <razón>\``);
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function main() {
|
|
110
|
+
const hallazgos = [];
|
|
111
|
+
const archivos = archivosObjetivo();
|
|
112
|
+
for (const ruta of archivos) {
|
|
113
|
+
let contenido;
|
|
114
|
+
try {
|
|
115
|
+
contenido = fs.readFileSync(path.join(RAIZ, ruta), 'utf8');
|
|
116
|
+
} catch { continue; }
|
|
117
|
+
const lineas = contenido.split(/\r?\n/);
|
|
118
|
+
auditarUtc(ruta, lineas, hallazgos);
|
|
119
|
+
auditarEolCheck(ruta, contenido, hallazgos);
|
|
120
|
+
auditarBloqueoCiego(ruta, contenido, hallazgos);
|
|
121
|
+
auditarCwdPlanning(ruta, lineas, hallazgos);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (hallazgos.length === 0) {
|
|
125
|
+
console.log(`[clases-conocidas] OK — ${archivos.length} archivos, 0 reincidencias de clases documentadas (C1 UTC, C2 EOL, C3 bloqueo ciego, C4 ancla cwd)`);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
console.error(`[clases-conocidas] ${hallazgos.length} reincidencia(s) de clases de bug documentadas:`);
|
|
129
|
+
for (const h of hallazgos) console.error(' ' + h);
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
module.exports = { auditarUtc, auditarEolCheck, auditarBloqueoCiego, auditarCwdPlanning };
|
|
134
|
+
if (require.main === module) main();
|
|
@@ -5,9 +5,23 @@
|
|
|
5
5
|
* bootstrap-instintos.js
|
|
6
6
|
*
|
|
7
7
|
* Pobla instintos/proyecto.yaml inicial a partir de las entradas de
|
|
8
|
-
* .planning/APRENDIZAJES.md.
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* .planning/APRENDIZAJES.md. Reconoce dos formatos de entrada:
|
|
9
|
+
*
|
|
10
|
+
* ### [YYYY-MM-DD] Título (formato histórico)
|
|
11
|
+
* ### L-NNN: Título (RATING, Tipo X → destino) (formato /swl:aprender actual)
|
|
12
|
+
*
|
|
13
|
+
* Para el formato L-NNN, la fecha se toma de una línea `**valid_at**: YYYY-MM-DD`
|
|
14
|
+
* dentro del cuerpo de la entrada (o de la fecha del encabezado `## [YYYY-MM-DD] ...`
|
|
15
|
+
* que la contiene, si la trae); si ninguna aparece, se usa la fecha de generación.
|
|
16
|
+
* El rating (HIGH/MEDIUM/LOW) y el Tipo (A/B/C/D) del título, cuando existen,
|
|
17
|
+
* tienen prioridad sobre la confidence/tags inferidas de la sección — son más
|
|
18
|
+
* específicos a la entrada individual que el título de la sección que la contiene.
|
|
19
|
+
*
|
|
20
|
+
* Gap conocido, no cubierto: entradas registradas como ítem de lista numerada
|
|
21
|
+
* dentro de un bloque de sesión (`4. **[L-285]** ...`) sin encabezado `###`
|
|
22
|
+
* propio — requieren un parser de listas dedicado, fuera del alcance de este fix.
|
|
23
|
+
*
|
|
24
|
+
* Cada instinto recibe confidence inicial según la sección que lo contiene:
|
|
11
25
|
*
|
|
12
26
|
* ## Anti-patrones detectados → confidence 0.7, tags: [anti-patron]
|
|
13
27
|
* ## Patrones exitosos → confidence 0.6, tags: [patron]
|
|
@@ -81,21 +95,54 @@ function detectarConfidence(seccion) {
|
|
|
81
95
|
return { confidence: 0.5, tags: [] };
|
|
82
96
|
}
|
|
83
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Detecta un rating (HIGH/MEDIUM/LOW) en el título de una entrada `### L-NNN: ...`.
|
|
100
|
+
* Más específico que la confidence por sección — prioridad cuando existe.
|
|
101
|
+
* @param {string} titulo
|
|
102
|
+
* @returns {number|null}
|
|
103
|
+
*/
|
|
104
|
+
function detectarConfidenceDeTitulo(titulo) {
|
|
105
|
+
const t = titulo || '';
|
|
106
|
+
if (/\bHIGH\b/i.test(t)) return 0.8;
|
|
107
|
+
if (/\bMEDIUM\b/i.test(t)) return 0.6;
|
|
108
|
+
if (/\bLOW\b/i.test(t)) return 0.4;
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Detecta el Tipo (A/B/C/D, taxonomía de /swl:aprender § Paso 4) en el título
|
|
114
|
+
* de una entrada `### L-NNN: ...` y lo mapea a un tag. Más específico que los
|
|
115
|
+
* tags por sección — prioridad cuando existe al menos un match.
|
|
116
|
+
* @param {string} titulo
|
|
117
|
+
* @returns {string[]}
|
|
118
|
+
*/
|
|
119
|
+
function detectarTagsDeTitulo(titulo) {
|
|
120
|
+
const t = titulo || '';
|
|
121
|
+
const tags = [];
|
|
122
|
+
if (/\bTipo\s*A\b/.test(t)) tags.push('regla-proyecto');
|
|
123
|
+
if (/\bTipo\s*B\b/.test(t)) tags.push('anti-patron');
|
|
124
|
+
if (/\bTipo\s*C\b/.test(t)) tags.push('nueva-habilidad');
|
|
125
|
+
if (/\bTipo\s*D\b/.test(t)) tags.push('metodologia');
|
|
126
|
+
return tags;
|
|
127
|
+
}
|
|
128
|
+
|
|
84
129
|
// ---------------------------------------------------------------------------
|
|
85
130
|
// Parser de APRENDIZAJES.md
|
|
86
131
|
// ---------------------------------------------------------------------------
|
|
87
132
|
|
|
88
133
|
/**
|
|
89
134
|
* Parsea el markdown en objetos de instinto.
|
|
90
|
-
*
|
|
135
|
+
* Formatos reconocidos por entrada:
|
|
91
136
|
* ## Sección
|
|
92
|
-
* ### [YYYY-MM-DD] Título
|
|
93
|
-
*
|
|
137
|
+
* ### [YYYY-MM-DD] Título — histórico
|
|
138
|
+
* ### L-NNN: Título (RATING, Tipo X → destino) — actual (/swl:aprender)
|
|
139
|
+
* Párrafo de descripción (puede ser multi-línea hasta el siguiente ### o ##).
|
|
94
140
|
*/
|
|
95
141
|
function parsearAprendizajes(texto) {
|
|
96
142
|
const lineas = texto.split(/\r?\n/);
|
|
97
143
|
const entradas = [];
|
|
98
144
|
let seccionActual = '';
|
|
145
|
+
let fechaSeccionActual = null;
|
|
99
146
|
let actual = null;
|
|
100
147
|
|
|
101
148
|
const flushActual = () => {
|
|
@@ -110,15 +157,17 @@ function parsearAprendizajes(texto) {
|
|
|
110
157
|
for (const raw of lineas) {
|
|
111
158
|
const linea = raw.replace(/\s+$/, '');
|
|
112
159
|
|
|
113
|
-
// Sección (##)
|
|
160
|
+
// Sección (## sin ser ###) — puede traer su propia fecha "## [YYYY-MM-DD] ..."
|
|
114
161
|
const mSec = linea.match(/^##\s+(.+)$/);
|
|
115
162
|
if (mSec && !linea.startsWith('###')) {
|
|
116
163
|
flushActual();
|
|
117
164
|
seccionActual = mSec[1].trim();
|
|
165
|
+
const mFechaSec = seccionActual.match(/^\[(\d{4}-\d{2}-\d{2})\]/);
|
|
166
|
+
fechaSeccionActual = mFechaSec ? mFechaSec[1] : null;
|
|
118
167
|
continue;
|
|
119
168
|
}
|
|
120
169
|
|
|
121
|
-
// Entrada
|
|
170
|
+
// Entrada formato histórico: ### [YYYY-MM-DD] Título
|
|
122
171
|
const mEntry = linea.match(/^###\s+\[(\d{4}-\d{2}-\d{2})\]\s+(.+)$/);
|
|
123
172
|
if (mEntry) {
|
|
124
173
|
flushActual();
|
|
@@ -131,9 +180,26 @@ function parsearAprendizajes(texto) {
|
|
|
131
180
|
continue;
|
|
132
181
|
}
|
|
133
182
|
|
|
134
|
-
//
|
|
183
|
+
// Entrada formato actual: ### L-NNN: Título (RATING, Tipo X → destino)
|
|
184
|
+
const mEntryL = linea.match(/^###\s+L-\d+:\s*(.+)$/);
|
|
185
|
+
if (mEntryL) {
|
|
186
|
+
flushActual();
|
|
187
|
+
actual = {
|
|
188
|
+
fecha: fechaSeccionActual, // se corrige abajo con **valid_at** si aparece
|
|
189
|
+
titulo: mEntryL[1].trim(),
|
|
190
|
+
seccion: seccionActual,
|
|
191
|
+
_descParts: [],
|
|
192
|
+
};
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Acumular descripción / capturar valid_at si tenemos entrada activa
|
|
135
197
|
if (actual) {
|
|
136
198
|
const t = linea.trim();
|
|
199
|
+
if (t) {
|
|
200
|
+
const mValidAt = t.match(/\*\*valid_at\*\*:\s*(\d{4}-\d{2}-\d{2})/);
|
|
201
|
+
if (mValidAt) actual.fecha = mValidAt[1];
|
|
202
|
+
}
|
|
137
203
|
if (t && !t.startsWith('#') && !t.startsWith('---')) {
|
|
138
204
|
actual._descParts.push(t);
|
|
139
205
|
}
|
|
@@ -161,9 +227,14 @@ function truncate(s, n) {
|
|
|
161
227
|
function generarInstintos(entradas) {
|
|
162
228
|
const hoy = new Date().toLocaleDateString('sv');
|
|
163
229
|
return entradas.map((e, idx) => {
|
|
164
|
-
const
|
|
230
|
+
const base = detectarConfidence(e.seccion);
|
|
231
|
+
const confidenceTitulo = detectarConfidenceDeTitulo(e.titulo);
|
|
232
|
+
const tagsTitulo = detectarTagsDeTitulo(e.titulo);
|
|
233
|
+
const confidence = confidenceTitulo != null ? confidenceTitulo : base.confidence;
|
|
234
|
+
const tags = tagsTitulo.length > 0 ? tagsTitulo : base.tags;
|
|
165
235
|
const pattern = truncate(e.titulo, 200);
|
|
166
236
|
const description = truncate(e.description || e.titulo, 500);
|
|
237
|
+
const fecha = e.fecha || hoy;
|
|
167
238
|
return {
|
|
168
239
|
id: `inst-${String(idx + 1).padStart(3, '0')}`,
|
|
169
240
|
pattern,
|
|
@@ -172,8 +243,8 @@ function generarInstintos(entradas) {
|
|
|
172
243
|
scope: 'project',
|
|
173
244
|
source: 'APRENDIZAJES.md',
|
|
174
245
|
evidence_count: 1,
|
|
175
|
-
last_validated:
|
|
176
|
-
last_validated_at:
|
|
246
|
+
last_validated: fecha,
|
|
247
|
+
last_validated_at: fecha,
|
|
177
248
|
contradictions: 0,
|
|
178
249
|
status: 'active',
|
|
179
250
|
tags,
|
|
@@ -242,7 +313,7 @@ function main() {
|
|
|
242
313
|
const entradas = parsearAprendizajes(texto);
|
|
243
314
|
|
|
244
315
|
if (entradas.length === 0) {
|
|
245
|
-
console.log('No se detectaron entradas en APRENDIZAJES.md (
|
|
316
|
+
console.log('No se detectaron entradas en APRENDIZAJES.md (patrones "### [YYYY-MM-DD] Título" o "### L-NNN: Título").');
|
|
246
317
|
return;
|
|
247
318
|
}
|
|
248
319
|
|
|
@@ -284,4 +355,4 @@ function main() {
|
|
|
284
355
|
|
|
285
356
|
if (require.main === module) main();
|
|
286
357
|
|
|
287
|
-
module.exports = { parsearAprendizajes, generarInstintos, detectarConfidence, inferirTipoMemoria, main };
|
|
358
|
+
module.exports = { parsearAprendizajes, generarInstintos, detectarConfidence, detectarConfidenceDeTitulo, detectarTagsDeTitulo, inferirTipoMemoria, main };
|