@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.
Files changed (207) hide show
  1. package/CLAUDE.md +197 -197
  2. package/README.md +600 -600
  3. package/agentes/_intent-spec.md +73 -73
  4. package/agentes/_propose-step.md +90 -90
  5. package/agentes/accesibilidad-wcag-swl.md +690 -690
  6. package/agentes/arquitecto-swl.md +267 -267
  7. package/agentes/auto-evolucion-swl.md +932 -932
  8. package/agentes/backend-csharp-swl.md +420 -420
  9. package/agentes/backend-go-swl.md +390 -390
  10. package/agentes/backend-java-swl.md +281 -281
  11. package/agentes/backend-rust-swl.md +364 -364
  12. package/agentes/backend-workers-swl.md +482 -482
  13. package/agentes/cloud-infra-swl.md +509 -509
  14. package/agentes/consolidador-swl.md +541 -541
  15. package/agentes/depurador-swl.md +352 -352
  16. package/agentes/devops-ci-swl.md +400 -400
  17. package/agentes/disenador-ui-swl.md +569 -569
  18. package/agentes/documentador-swl.md +345 -345
  19. package/agentes/frontend-angular-swl.md +621 -621
  20. package/agentes/frontend-css-swl.md +716 -716
  21. package/agentes/frontend-react-swl.md +692 -692
  22. package/agentes/frontend-swl.md +496 -496
  23. package/agentes/frontend-tailwind-swl.md +826 -826
  24. package/agentes/investigador-swl.md +432 -432
  25. package/agentes/investigador-ux-swl.md +505 -505
  26. package/agentes/migrador-swl.md +442 -442
  27. package/agentes/mobile-android-swl.md +511 -511
  28. package/agentes/mobile-cross-swl.md +541 -541
  29. package/agentes/mobile-ios-swl.md +502 -502
  30. package/agentes/mobile-testing-swl.md +302 -302
  31. package/agentes/nemesis-auditor-swl.md +285 -285
  32. package/agentes/observabilidad-swl.md +438 -438
  33. package/agentes/pagos-swl.md +310 -310
  34. package/agentes/perfilador-usuario-swl.md +321 -321
  35. package/agentes/planificador-swl.md +399 -399
  36. package/agentes/producto-prd-swl.md +589 -589
  37. package/agentes/red-team-swl.md +218 -218
  38. package/agentes/release-manager-swl.md +590 -590
  39. package/agentes/rendimiento-swl.md +713 -713
  40. package/agentes/revisor-angular-swl.md +278 -278
  41. package/agentes/revisor-csharp-swl.md +264 -264
  42. package/agentes/revisor-go-swl.md +259 -259
  43. package/agentes/revisor-java-swl.md +257 -257
  44. package/agentes/revisor-kotlin-swl.md +273 -273
  45. package/agentes/revisor-nextjs-swl.md +281 -281
  46. package/agentes/revisor-php-swl.md +271 -271
  47. package/agentes/revisor-react-swl.md +278 -278
  48. package/agentes/revisor-rust-swl.md +346 -346
  49. package/agentes/revisor-seguridad-swl.md +399 -399
  50. package/agentes/revisor-swift-swl.md +268 -268
  51. package/agentes/revisor-typescript-swl.md +346 -346
  52. package/agentes/tdd-qa-swl.md +393 -393
  53. package/comandos/swl/actualizar.md +174 -174
  54. package/comandos/swl/adoptar-proyecto.md +265 -265
  55. package/comandos/swl/aprender.md +836 -836
  56. package/comandos/swl/aprobar-plan.md +146 -146
  57. package/comandos/swl/auditar-deps.md +134 -134
  58. package/comandos/swl/autoresearch.md +264 -264
  59. package/comandos/swl/ayuda.md +224 -224
  60. package/comandos/swl/brainstorm.md +51 -51
  61. package/comandos/swl/briefing.md +119 -119
  62. package/comandos/swl/checkpoint.md +325 -325
  63. package/comandos/swl/claudemd.md +234 -234
  64. package/comandos/swl/compactar.md +310 -310
  65. package/comandos/swl/configurar-ci.md +235 -235
  66. package/comandos/swl/contexto.md +110 -110
  67. package/comandos/swl/contribuir.md +233 -233
  68. package/comandos/swl/crear-skill.md +292 -292
  69. package/comandos/swl/cron.md +194 -194
  70. package/comandos/swl/discutir-fase.md +169 -169
  71. package/comandos/swl/ejecutar-fase.md +233 -233
  72. package/comandos/swl/evaluar-skill.md +520 -520
  73. package/comandos/swl/evolucion-continua.md +73 -73
  74. package/comandos/swl/evolucionar.md +267 -267
  75. package/comandos/swl/exportar-vault.md +583 -583
  76. package/comandos/swl/fix.md +118 -118
  77. package/comandos/swl/gateway.md +158 -158
  78. package/comandos/swl/inbox.md +116 -116
  79. package/comandos/swl/instalar.md +220 -220
  80. package/comandos/swl/instintos.md +86 -86
  81. package/comandos/swl/mapear-codebase.md +312 -312
  82. package/comandos/swl/mcp-status.md +175 -175
  83. package/comandos/swl/modelo.md +100 -100
  84. package/comandos/swl/nemesis.md +433 -433
  85. package/comandos/swl/notificaciones.md +299 -299
  86. package/comandos/swl/nuevo-proyecto.md +251 -251
  87. package/comandos/swl/planear-fase.md +263 -263
  88. package/comandos/swl/plugins.md +256 -256
  89. package/comandos/swl/predecir.md +169 -169
  90. package/comandos/swl/reflect-skills.md +125 -125
  91. package/comandos/swl/release.md +450 -450
  92. package/comandos/swl/revisar-impacto.md +201 -201
  93. package/comandos/swl/revisar.md +330 -330
  94. package/comandos/swl/seguridad.md +189 -189
  95. package/comandos/swl/sesiones.md +200 -200
  96. package/comandos/swl/skill-search.md +113 -113
  97. package/comandos/swl/status.md +345 -345
  98. package/comandos/swl/verificar.md +817 -817
  99. package/comandos/swl/wiki.md +620 -620
  100. package/gateway/cron/jobs.example.json +12 -12
  101. package/habilidades/auto-evolucion-protocolo/SKILL.md +294 -294
  102. package/habilidades/backend-async-postgres-testing/SKILL.md +2 -1
  103. package/habilidades/changelog-generator/SKILL.md +174 -174
  104. package/habilidades/compactacion-contexto/SKILL.md +2 -1
  105. package/habilidades/contenedores-docker/SKILL.md +4 -2
  106. package/habilidades/doubt-driven-review/SKILL.md +207 -207
  107. package/habilidades/drift-detection/SKILL.md +1 -1
  108. package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
  109. package/habilidades/extractor-de-aprendizajes/SKILL.md +8 -2
  110. package/habilidades/git-worktrees-paralelo/SKILL.md +19 -1
  111. package/habilidades/harness-claude-code/SKILL.md +314 -314
  112. package/habilidades/instalar-sistema/SKILL.md +227 -227
  113. package/habilidades/planear-fase/SKILL.md +358 -358
  114. package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
  115. package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
  116. package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -147
  117. package/habilidades/release-semver/SKILL.md +2 -2
  118. package/habilidades/tdd-workflow/SKILL.md +749 -749
  119. package/hooks/agente-lifecycle.js +1 -1
  120. package/hooks/audit-trail.js +1 -1
  121. package/hooks/auto-consolidacion.js +1 -1
  122. package/hooks/captura-acciones-post.js +1 -1
  123. package/hooks/captura-acciones-session.js +1 -1
  124. package/hooks/captura-feedback-usuario.js +1 -1
  125. package/hooks/contexto-iteracion.js +1 -1
  126. package/hooks/contexto-subagente.js +68 -68
  127. package/hooks/degradacion-instintos.js +1 -1
  128. package/hooks/grafo-contexto.js +1 -1
  129. package/hooks/guardrail-modelo.js +1 -1
  130. package/hooks/inbox-aviso.js +1 -1
  131. package/hooks/inyeccion-contexto.js +1 -1
  132. package/hooks/lib/agent-matcher.js +1 -1
  133. package/hooks/lib/agent-routing.js +1 -1
  134. package/hooks/lib/captura-acciones.js +1 -1
  135. package/hooks/lib/etapa-metricas.js +1 -1
  136. package/hooks/lib/evolution-tracker.js +1 -1
  137. package/hooks/lib/gateway-notify.js +193 -193
  138. package/hooks/lib/mcp-health.js +1 -1
  139. package/hooks/lib/notificacion-formato.js +58 -0
  140. package/hooks/lib/nudge-tracker.js +1 -1
  141. package/hooks/lib/otlp-exporter.js +1 -1
  142. package/hooks/lib/propose-step.js +1 -1
  143. package/hooks/lib/raiz-proyecto.js +127 -102
  144. package/hooks/lib/run-log.js +1 -1
  145. package/hooks/lib/singleton-guard.js +20 -13
  146. package/hooks/lib/telegram-cliente.js +11 -3
  147. package/hooks/notificacion-telegram.js +13 -3
  148. package/hooks/preservar-estado-pre-compact.js +1 -1
  149. package/hooks/registro-turnos.js +1 -1
  150. package/hooks/resumen-sesion.js +1 -1
  151. package/hooks/risk-scoring.js +1 -1
  152. package/hooks/session-briefing.js +1 -1
  153. package/hooks/spec-gate.js +1 -1
  154. package/hooks/sugerir-regenerar-inventario.js +1 -1
  155. package/hooks/tdd-gate.js +1 -1
  156. package/hooks/telemetria-agentes.js +1 -1
  157. package/hooks/telemetria-skill-routing.js +1 -1
  158. package/hooks/tracking-costos.js +1 -1
  159. package/hooks/validar-formato-post-subagente.js +1 -1
  160. package/hooks/validar-intent-spec.js +1 -1
  161. package/hooks/validar-planning-paths.js +1 -1
  162. package/llms.txt +29 -29
  163. package/manifiestos/canonical-hashes.json +5588 -5257
  164. package/manifiestos/hooks-config.json +469 -469
  165. package/manifiestos/invariantes-criticos.json +30 -30
  166. package/manifiestos/modulos.json +1429 -1428
  167. package/manifiestos/skills-lock.json +1275 -1275
  168. package/package.json +94 -94
  169. package/plugin.json +369 -369
  170. package/scripts/auditar-clases-conocidas.js +134 -134
  171. package/scripts/bootstrap-instintos.js +85 -14
  172. package/scripts/canario-hooks.js +166 -166
  173. package/scripts/cli/autonomia.js +23 -23
  174. package/scripts/cli/benchmark-memoria.js +37 -37
  175. package/scripts/cli/ciclo-autonomo.js +73 -73
  176. package/scripts/cli/ciclo-fase-b.js +102 -102
  177. package/scripts/cli/guardrail-metrics.js +39 -39
  178. package/scripts/cli/memoria-search.js +69 -69
  179. package/scripts/cli/nudge-accionar.js +39 -39
  180. package/scripts/cli/run-eval.js +38 -38
  181. package/scripts/doctor.js +26 -3
  182. package/scripts/evidencia-valor.js +101 -101
  183. package/scripts/field-report.js +16 -16
  184. package/scripts/instalador.js +13 -0
  185. package/scripts/lib/activar-hooks-proyecto.js +116 -116
  186. package/scripts/lib/ciclo-autonomo/candidatos.js +174 -174
  187. package/scripts/lib/ciclo-autonomo/config.js +165 -165
  188. package/scripts/lib/ciclo-autonomo/drenador-feedback.js +174 -174
  189. package/scripts/lib/ciclo-autonomo/fallback.js +77 -77
  190. package/scripts/lib/ciclo-autonomo/guard-convivencia.js +139 -139
  191. package/scripts/lib/ciclo-autonomo/higiene-nudges.js +112 -112
  192. package/scripts/lib/ciclo-autonomo/index.js +301 -301
  193. package/scripts/lib/ciclo-autonomo/lock.js +124 -124
  194. package/scripts/lib/ciclo-autonomo/presupuesto.js +122 -122
  195. package/scripts/lib/ciclo-autonomo/puente-degradacion.js +240 -240
  196. package/scripts/lib/ciclo-autonomo/runner-fase-b.js +248 -248
  197. package/scripts/lib/ciclo-autonomo/writer-instintos.js +190 -190
  198. package/scripts/lib/ciclo-autonomo/yaml-instintos.js +535 -535
  199. package/scripts/lib/evidencia-valor.js +228 -228
  200. package/scripts/lib/expandir-targets.js +71 -71
  201. package/scripts/lib/limpiar-basura-global.js +161 -0
  202. package/scripts/lib/toml-merge.js +204 -204
  203. package/scripts/mcp-server/auth.js +105 -105
  204. package/scripts/mcp-server/cache.js +106 -106
  205. package/scripts/tui/pantallas/install-wizard.js +403 -403
  206. package/instintos/.backups/perfil-usuario.yaml.2026-07-10-165128.bak +0 -53
  207. 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. Cada entrada `### [YYYY-MM-DD] título` se
9
- * convierte en un instinto con confidence inicial según la sección que lo
10
- * contiene:
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
- * Formato esperado por entrada:
135
+ * Formatos reconocidos por entrada:
91
136
  * ## Sección
92
- * ### [YYYY-MM-DD] Título
93
- * Párrafo de descripción (puede ser multi-línea hasta el siguiente ###)
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 (### [YYYY-MM-DD] Título)
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
- // Acumular descripción si tenemos entrada activa
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 { confidence, tags } = detectarConfidence(e.seccion);
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: e.fecha,
176
- last_validated_at: e.fecha,
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 (patrón "### [YYYY-MM-DD] Título").');
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 };