@saulwade/swl-ses 1.0.0

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 (702) hide show
  1. package/CLAUDE.md +238 -0
  2. package/README.md +560 -0
  3. package/_userland/agentes/.gitkeep +0 -0
  4. package/_userland/habilidades/.gitkeep +0 -0
  5. package/agentes/.evolved.json +9 -0
  6. package/agentes/accesibilidad-wcag-swl.md +692 -0
  7. package/agentes/arquitecto-swl.md +238 -0
  8. package/agentes/auto-evolucion-swl.md +854 -0
  9. package/agentes/backend-api-swl.md +470 -0
  10. package/agentes/backend-csharp-swl.md +418 -0
  11. package/agentes/backend-go-swl.md +388 -0
  12. package/agentes/backend-java-swl.md +279 -0
  13. package/agentes/backend-node-swl.md +477 -0
  14. package/agentes/backend-python-swl.md +608 -0
  15. package/agentes/backend-rust-swl.md +362 -0
  16. package/agentes/backend-workers-swl.md +480 -0
  17. package/agentes/cloud-infra-swl.md +485 -0
  18. package/agentes/consolidador-swl.md +539 -0
  19. package/agentes/datos-swl.md +584 -0
  20. package/agentes/depurador-swl.md +349 -0
  21. package/agentes/devops-ci-swl.md +374 -0
  22. package/agentes/disenador-ui-swl.md +558 -0
  23. package/agentes/documentador-swl.md +343 -0
  24. package/agentes/evals/arquitecto-swl.evals.json +56 -0
  25. package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
  26. package/agentes/evals/implementador-swl.evals.json +56 -0
  27. package/agentes/evals/orquestador-swl.evals.json +60 -0
  28. package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
  29. package/agentes/evals/red-team-swl.evals.json +59 -0
  30. package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
  31. package/agentes/frontend-angular-swl.md +627 -0
  32. package/agentes/frontend-css-swl.md +720 -0
  33. package/agentes/frontend-react-swl.md +696 -0
  34. package/agentes/frontend-swl.md +500 -0
  35. package/agentes/frontend-tailwind-swl.md +830 -0
  36. package/agentes/implementador-swl.md +328 -0
  37. package/agentes/investigador-swl.md +430 -0
  38. package/agentes/investigador-ux-swl.md +500 -0
  39. package/agentes/llm-apps-swl.md +276 -0
  40. package/agentes/migrador-swl.md +417 -0
  41. package/agentes/mobile-android-swl.md +509 -0
  42. package/agentes/mobile-cross-swl.md +539 -0
  43. package/agentes/mobile-ios-swl.md +500 -0
  44. package/agentes/mobile-testing-swl.md +300 -0
  45. package/agentes/notificador-swl.md +916 -0
  46. package/agentes/observabilidad-swl.md +436 -0
  47. package/agentes/orquestador-swl.md +884 -0
  48. package/agentes/pagos-swl.md +283 -0
  49. package/agentes/perfilador-usuario-swl.md +306 -0
  50. package/agentes/planificador-swl.md +402 -0
  51. package/agentes/producto-prd-swl.md +587 -0
  52. package/agentes/red-team-swl.md +216 -0
  53. package/agentes/release-manager-swl.md +568 -0
  54. package/agentes/rendimiento-swl.md +714 -0
  55. package/agentes/resolutor-build-swl.md +243 -0
  56. package/agentes/revisor-angular-swl.md +276 -0
  57. package/agentes/revisor-codigo-swl.md +348 -0
  58. package/agentes/revisor-csharp-swl.md +262 -0
  59. package/agentes/revisor-go-swl.md +257 -0
  60. package/agentes/revisor-java-swl.md +255 -0
  61. package/agentes/revisor-kotlin-swl.md +271 -0
  62. package/agentes/revisor-nextjs-swl.md +279 -0
  63. package/agentes/revisor-php-swl.md +269 -0
  64. package/agentes/revisor-react-swl.md +276 -0
  65. package/agentes/revisor-rust-swl.md +344 -0
  66. package/agentes/revisor-seguridad-swl.md +390 -0
  67. package/agentes/revisor-swift-swl.md +266 -0
  68. package/agentes/revisor-typescript-swl.md +344 -0
  69. package/agentes/sre-swl.md +265 -0
  70. package/agentes/tdd-qa-swl.md +354 -0
  71. package/agentes/ux-disenador-swl.md +501 -0
  72. package/bin/lib/bot-comandos.js +1030 -0
  73. package/bin/lib/bot-discovery.js +182 -0
  74. package/bin/lib/bot-git.js +142 -0
  75. package/bin/swl-ses.js +325 -0
  76. package/bin/swl-telegram-bot.js +442 -0
  77. package/bin/swl-telegram-bot.plist +21 -0
  78. package/bin/swl-telegram-bot.service +14 -0
  79. package/comandos/swl/.evolved.json +23 -0
  80. package/comandos/swl/actualizar.md +174 -0
  81. package/comandos/swl/adoptar-proyecto.md +207 -0
  82. package/comandos/swl/aprender.md +701 -0
  83. package/comandos/swl/auditar-deps.md +134 -0
  84. package/comandos/swl/autoresearch.md +170 -0
  85. package/comandos/swl/ayuda.md +224 -0
  86. package/comandos/swl/brainstorm.md +50 -0
  87. package/comandos/swl/checkpoint.md +330 -0
  88. package/comandos/swl/compactar.md +283 -0
  89. package/comandos/swl/configurar-ci.md +227 -0
  90. package/comandos/swl/contexto.md +112 -0
  91. package/comandos/swl/contribuir.md +233 -0
  92. package/comandos/swl/crear-skill.md +292 -0
  93. package/comandos/swl/cron.md +196 -0
  94. package/comandos/swl/dashboard.md +146 -0
  95. package/comandos/swl/discutir-fase.md +230 -0
  96. package/comandos/swl/ejecutar-fase.md +135 -0
  97. package/comandos/swl/evaluar-skill.md +487 -0
  98. package/comandos/swl/evolucion-estado.md +142 -0
  99. package/comandos/swl/evolucionar.md +259 -0
  100. package/comandos/swl/exportar-vault.md +189 -0
  101. package/comandos/swl/gateway.md +158 -0
  102. package/comandos/swl/inbox.md +116 -0
  103. package/comandos/swl/instalar.md +220 -0
  104. package/comandos/swl/instintos.md +86 -0
  105. package/comandos/swl/mapear-codebase.md +312 -0
  106. package/comandos/swl/mcp-status.md +175 -0
  107. package/comandos/swl/metricas.md +270 -0
  108. package/comandos/swl/modelo.md +102 -0
  109. package/comandos/swl/notificaciones.md +396 -0
  110. package/comandos/swl/nuevo-proyecto.md +154 -0
  111. package/comandos/swl/planear-fase.md +221 -0
  112. package/comandos/swl/plugins.md +256 -0
  113. package/comandos/swl/reflect-skills.md +125 -0
  114. package/comandos/swl/release.md +217 -0
  115. package/comandos/swl/revisar-impacto.md +206 -0
  116. package/comandos/swl/revisar.md +330 -0
  117. package/comandos/swl/salud.md +363 -0
  118. package/comandos/swl/sesiones.md +200 -0
  119. package/comandos/swl/skill-search.md +113 -0
  120. package/comandos/swl/verificar.md +585 -0
  121. package/comandos/swl/wiki.md +620 -0
  122. package/contextos/dev.md +32 -0
  123. package/contextos/research.md +30 -0
  124. package/contextos/review.md +31 -0
  125. package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
  126. package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
  127. package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
  128. package/habilidades/agent-browser/SKILL.md +218 -0
  129. package/habilidades/agentes-como-servicio/SKILL.md +218 -0
  130. package/habilidades/ai-runtime-security/SKILL.md +273 -0
  131. package/habilidades/angular-avanzado/SKILL.md +164 -0
  132. package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
  133. package/habilidades/angular-moderno/SKILL.md +186 -0
  134. package/habilidades/angular-moderno/evals/evals.json +45 -0
  135. package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
  136. package/habilidades/api-rest-diseno/SKILL.md +191 -0
  137. package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
  138. package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
  139. package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
  140. package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
  141. package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
  142. package/habilidades/async-python/SKILL.md +149 -0
  143. package/habilidades/async-python/evals/evals.json +47 -0
  144. package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
  145. package/habilidades/auth-patrones/.evolved.json +9 -0
  146. package/habilidades/auth-patrones/SKILL.md +413 -0
  147. package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
  148. package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
  149. package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
  150. package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
  151. package/habilidades/autoresearch/SKILL.md +268 -0
  152. package/habilidades/autoresearch/evals/evals.json +41 -0
  153. package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
  154. package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
  155. package/habilidades/azure-cloud/SKILL.md +308 -0
  156. package/habilidades/azure-cloud/recursos/aks.md +327 -0
  157. package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
  158. package/habilidades/backend-production-resilience/SKILL.md +288 -0
  159. package/habilidades/brainstorming/SKILL.md +295 -0
  160. package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
  161. package/habilidades/build-errors-cpp/SKILL.md +270 -0
  162. package/habilidades/build-errors-csharp/SKILL.md +265 -0
  163. package/habilidades/build-errors-go/SKILL.md +306 -0
  164. package/habilidades/build-errors-java/SKILL.md +278 -0
  165. package/habilidades/build-errors-kotlin/SKILL.md +303 -0
  166. package/habilidades/build-errors-nextjs/SKILL.md +312 -0
  167. package/habilidades/build-errors-php/SKILL.md +270 -0
  168. package/habilidades/build-errors-python/SKILL.md +292 -0
  169. package/habilidades/build-errors-rust/SKILL.md +284 -0
  170. package/habilidades/build-errors-swift/SKILL.md +272 -0
  171. package/habilidades/build-errors-typescript/SKILL.md +369 -0
  172. package/habilidades/checklist-calidad/SKILL.md +271 -0
  173. package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
  174. package/habilidades/checklist-seguridad/SKILL.md +285 -0
  175. package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
  176. package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
  177. package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
  178. package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
  179. package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
  180. package/habilidades/cloud-aws/SKILL.md +142 -0
  181. package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
  182. package/habilidades/compactacion-contexto/SKILL.md +247 -0
  183. package/habilidades/contenedores-docker/SKILL.md +137 -0
  184. package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
  185. package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
  186. package/habilidades/context-builder/SKILL.md +170 -0
  187. package/habilidades/control-profundidad/SKILL.md +128 -0
  188. package/habilidades/csharp-experto/SKILL.md +322 -0
  189. package/habilidades/csharp-patrones/SKILL.md +316 -0
  190. package/habilidades/csharp-testing/SKILL.md +286 -0
  191. package/habilidades/css-moderno/SKILL.md +166 -0
  192. package/habilidades/css-moderno/evals/evals.json +43 -0
  193. package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
  194. package/habilidades/datos-etl/SKILL.md +129 -0
  195. package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
  196. package/habilidades/dbml-experto/SKILL.md +339 -0
  197. package/habilidades/dbml-experto/evals/evals.json +56 -0
  198. package/habilidades/dependencias-auditoria/SKILL.md +320 -0
  199. package/habilidades/deprecacion-migracion/SKILL.md +169 -0
  200. package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
  201. package/habilidades/design-tokens/SKILL.md +158 -0
  202. package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
  203. package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
  204. package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
  205. package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
  206. package/habilidades/discutir-fase/SKILL.md +188 -0
  207. package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
  208. package/habilidades/diseno-responsivo/SKILL.md +186 -0
  209. package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
  210. package/habilidades/django-experto/SKILL.md +205 -0
  211. package/habilidades/django-experto/recursos/async-django.md +390 -0
  212. package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
  213. package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
  214. package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
  215. package/habilidades/django-experto/recursos/testing-django.md +415 -0
  216. package/habilidades/doc-sync/SKILL.md +280 -0
  217. package/habilidades/drift-detection/SKILL.md +179 -0
  218. package/habilidades/ejecutar-fase/SKILL.md +468 -0
  219. package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
  220. package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
  221. package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
  222. package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
  223. package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
  224. package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
  225. package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
  226. package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
  227. package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
  228. package/habilidades/evaluacion-agentes/SKILL.md +314 -0
  229. package/habilidades/event-driven/SKILL.md +153 -0
  230. package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
  231. package/habilidades/extraccion-documentos/SKILL.md +221 -0
  232. package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
  233. package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
  234. package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
  235. package/habilidades/fastapi-experto/SKILL.md +221 -0
  236. package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
  237. package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
  238. package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
  239. package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
  240. package/habilidades/filament-admin/SKILL.md +290 -0
  241. package/habilidades/frontend-avanzado/SKILL.md +257 -0
  242. package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
  243. package/habilidades/gcp-cloud/SKILL.md +260 -0
  244. package/habilidades/gcp-cloud/recursos/gke.md +234 -0
  245. package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
  246. package/habilidades/generacion-mermaid/SKILL.md +229 -0
  247. package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
  248. package/habilidades/go-experto/SKILL.md +305 -0
  249. package/habilidades/go-patrones/SKILL.md +299 -0
  250. package/habilidades/go-testing/SKILL.md +291 -0
  251. package/habilidades/graphql-experto/SKILL.md +323 -0
  252. package/habilidades/guardrail-semantico/SKILL.md +282 -0
  253. package/habilidades/harness-claude-code/SKILL.md +299 -0
  254. package/habilidades/iam-secretos/SKILL.md +265 -0
  255. package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
  256. package/habilidades/infra-github-actions/SKILL.md +166 -0
  257. package/habilidades/instalar-sistema/.evolved.json +9 -0
  258. package/habilidades/instalar-sistema/SKILL.md +221 -0
  259. package/habilidades/java-experto/SKILL.md +290 -0
  260. package/habilidades/java-patrones/SKILL.md +275 -0
  261. package/habilidades/java-testing/SKILL.md +288 -0
  262. package/habilidades/kotlin-compose/SKILL.md +278 -0
  263. package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
  264. package/habilidades/kotlin-experto/SKILL.md +318 -0
  265. package/habilidades/kotlin-testing/SKILL.md +267 -0
  266. package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
  267. package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
  268. package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
  269. package/habilidades/langchain-langraph/SKILL.md +386 -0
  270. package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
  271. package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
  272. package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
  273. package/habilidades/legacy-code-rescue/SKILL.md +267 -0
  274. package/habilidades/likec4-experto/SKILL.md +412 -0
  275. package/habilidades/likec4-experto/evals/evals.json +69 -0
  276. package/habilidades/manejo-errores/.evolved.json +9 -0
  277. package/habilidades/manejo-errores/SKILL.md +407 -0
  278. package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
  279. package/habilidades/mapear-codebase/SKILL.md +275 -0
  280. package/habilidades/memoria-busqueda/SKILL.md +194 -0
  281. package/habilidades/memoria-busqueda/evals/evals.json +44 -0
  282. package/habilidades/meta-skills-estandar/SKILL.md +298 -0
  283. package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
  284. package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
  285. package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
  286. package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
  287. package/habilidades/microservicios/SKILL.md +155 -0
  288. package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
  289. package/habilidades/mobile-flutter/SKILL.md +199 -0
  290. package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
  291. package/habilidades/mobile-react-native/SKILL.md +176 -0
  292. package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
  293. package/habilidades/mongodb-experto/SKILL.md +302 -0
  294. package/habilidades/monitoring-alertas/SKILL.md +201 -0
  295. package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
  296. package/habilidades/nestjs-experto/SKILL.md +307 -0
  297. package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
  298. package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
  299. package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
  300. package/habilidades/nextjs-experto/SKILL.md +335 -0
  301. package/habilidades/nextjs-patrones/SKILL.md +303 -0
  302. package/habilidades/nextjs-testing/SKILL.md +331 -0
  303. package/habilidades/node-experto/.evolved.json +9 -0
  304. package/habilidades/node-experto/SKILL.md +266 -0
  305. package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
  306. package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
  307. package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
  308. package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
  309. package/habilidades/nuevo-proyecto/SKILL.md +204 -0
  310. package/habilidades/orquestacion-async/SKILL.md +303 -0
  311. package/habilidades/paid-media-tracking/SKILL.md +269 -0
  312. package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
  313. package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
  314. package/habilidades/patrones-python/SKILL.md +228 -0
  315. package/habilidades/patrones-python/evals/evals.json +56 -0
  316. package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
  317. package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
  318. package/habilidades/perfil-usuario/SKILL.md +200 -0
  319. package/habilidades/perfil-usuario/evals/evals.json +55 -0
  320. package/habilidades/performance-baseline/SKILL.md +297 -0
  321. package/habilidades/php-experto/SKILL.md +291 -0
  322. package/habilidades/php-patrones/SKILL.md +306 -0
  323. package/habilidades/php-testing/SKILL.md +280 -0
  324. package/habilidades/planear-fase/SKILL.md +269 -0
  325. package/habilidades/postgresql-experto/SKILL.md +151 -0
  326. package/habilidades/postgresql-experto/evals/evals.json +53 -0
  327. package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
  328. package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
  329. package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
  330. package/habilidades/privacy-memoria/SKILL.md +141 -0
  331. package/habilidades/privacy-memoria/evals/evals.json +43 -0
  332. package/habilidades/prompt-engineering/SKILL.md +518 -0
  333. package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
  334. package/habilidades/rag-arquitectura/SKILL.md +338 -0
  335. package/habilidades/rails-experto/SKILL.md +237 -0
  336. package/habilidades/rails-experto/recursos/active-record.md +260 -0
  337. package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
  338. package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
  339. package/habilidades/react-experto/SKILL.md +209 -0
  340. package/habilidades/react-experto/evals/evals.json +55 -0
  341. package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
  342. package/habilidades/react-optimizacion/SKILL.md +174 -0
  343. package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
  344. package/habilidades/redis-experto/SKILL.md +305 -0
  345. package/habilidades/release-semver/.evolved.json +9 -0
  346. package/habilidades/release-semver/SKILL.md +248 -0
  347. package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
  348. package/habilidades/rust-experto/SKILL.md +400 -0
  349. package/habilidades/rust-patrones/SKILL.md +296 -0
  350. package/habilidades/rust-testing/SKILL.md +311 -0
  351. package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
  352. package/habilidades/sql-optimizacion/SKILL.md +200 -0
  353. package/habilidades/sql-optimizacion/evals/evals.json +54 -0
  354. package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
  355. package/habilidades/sre-patrones/SKILL.md +333 -0
  356. package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
  357. package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
  358. package/habilidades/stripe-pagos/SKILL.md +550 -0
  359. package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
  360. package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
  361. package/habilidades/structured-outputs/SKILL.md +343 -0
  362. package/habilidades/swift-experto/SKILL.md +320 -0
  363. package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
  364. package/habilidades/swift-patrones/SKILL.md +313 -0
  365. package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
  366. package/habilidades/swift-testing/SKILL.md +254 -0
  367. package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
  368. package/habilidades/swl-dashboard/SKILL.md +370 -0
  369. package/habilidades/swl-markitdown/SKILL.md +285 -0
  370. package/habilidades/swl-markitdown/evals/evals.json +52 -0
  371. package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
  372. package/habilidades/tailwind-experto/SKILL.md +240 -0
  373. package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
  374. package/habilidades/tdd-workflow/SKILL.md +293 -0
  375. package/habilidades/terraform-experto/SKILL.md +321 -0
  376. package/habilidades/testing-python/SKILL.md +340 -0
  377. package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
  378. package/habilidades/threat-model-lite/SKILL.md +246 -0
  379. package/habilidades/tracing-processor/SKILL.md +212 -0
  380. package/habilidades/tracking-measurement/SKILL.md +239 -0
  381. package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
  382. package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
  383. package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
  384. package/habilidades/typescript-avanzado/SKILL.md +144 -0
  385. package/habilidades/typescript-avanzado/evals/evals.json +55 -0
  386. package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
  387. package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
  388. package/habilidades/ux-diseno/SKILL.md +116 -0
  389. package/habilidades/ux-diseno/evals/evals.json +43 -0
  390. package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
  391. package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
  392. package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
  393. package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
  394. package/habilidades/verificacion-evidencia/SKILL.md +160 -0
  395. package/habilidades/verificar-trabajo/SKILL.md +303 -0
  396. package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
  397. package/habilidades/wiki-conocimiento/SKILL.md +276 -0
  398. package/habilidades/wireframes-flujos/SKILL.md +212 -0
  399. package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
  400. package/habilidades/workflow-claude-code/SKILL.md +260 -0
  401. package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
  402. package/hooks/_run-hook.sh +57 -0
  403. package/hooks/actualizar-perfil-usuario.js +364 -0
  404. package/hooks/agente-lifecycle.js +71 -0
  405. package/hooks/aiisms-detector.js +173 -0
  406. package/hooks/audit-trail.js +204 -0
  407. package/hooks/auto-background.js +97 -0
  408. package/hooks/auto-consolidacion.js +178 -0
  409. package/hooks/auto-evolucion.js +666 -0
  410. package/hooks/auto-restaurar-settings.js +360 -0
  411. package/hooks/calidad-pre-commit.js +929 -0
  412. package/hooks/calidad-typescript.js +511 -0
  413. package/hooks/captura-feedback-usuario.js +148 -0
  414. package/hooks/check-update.js +211 -0
  415. package/hooks/clasificador-mensajes.js +271 -0
  416. package/hooks/degradacion-instintos.js +272 -0
  417. package/hooks/escaneo-secretos.js +389 -0
  418. package/hooks/extraccion-aprendizajes.js +763 -0
  419. package/hooks/grafo-contexto.js +129 -0
  420. package/hooks/graph-update.js +67 -0
  421. package/hooks/guardrail-modelo.js +247 -0
  422. package/hooks/inbox-aviso.js +75 -0
  423. package/hooks/inyeccion-contexto.js +246 -0
  424. package/hooks/lib/abort-registry.js +214 -0
  425. package/hooks/lib/agent-backend.js +210 -0
  426. package/hooks/lib/agent-comms.js +263 -0
  427. package/hooks/lib/agent-issue-codes.js +284 -0
  428. package/hooks/lib/agent-matcher.js +189 -0
  429. package/hooks/lib/async-hook-registry.js +252 -0
  430. package/hooks/lib/atomic-write.js +130 -0
  431. package/hooks/lib/auto-consolidator.js +335 -0
  432. package/hooks/lib/canary-skills.js +187 -0
  433. package/hooks/lib/consolidation-lock.js +291 -0
  434. package/hooks/lib/context-builder.js +430 -0
  435. package/hooks/lib/context-compressor.js +657 -0
  436. package/hooks/lib/convergence-detector.js +105 -0
  437. package/hooks/lib/delegation-tracker.js +198 -0
  438. package/hooks/lib/detectar-package-manager.js +423 -0
  439. package/hooks/lib/edit-accumulator.js +171 -0
  440. package/hooks/lib/error-classifier.js +308 -0
  441. package/hooks/lib/event-bus.js +112 -0
  442. package/hooks/lib/evolution-tracker.js +442 -0
  443. package/hooks/lib/execution-state.js +316 -0
  444. package/hooks/lib/fingerprint-id.js +135 -0
  445. package/hooks/lib/gateway-notify.js +116 -0
  446. package/hooks/lib/graph-security.js +75 -0
  447. package/hooks/lib/guardrail-metrics.js +202 -0
  448. package/hooks/lib/hook-circuit-breaker.js +206 -0
  449. package/hooks/lib/loop-detector.js +267 -0
  450. package/hooks/lib/mcp-health.js +184 -0
  451. package/hooks/lib/mcp-pool.js +436 -0
  452. package/hooks/lib/memory-search.js +506 -0
  453. package/hooks/lib/merkle-audit.js +96 -0
  454. package/hooks/lib/model-router.js +222 -0
  455. package/hooks/lib/normalize-error.js +324 -0
  456. package/hooks/lib/normalize-input.js +65 -0
  457. package/hooks/lib/nudge-tracker.js +306 -0
  458. package/hooks/lib/otlp-exporter.js +365 -0
  459. package/hooks/lib/performance-marks.js +239 -0
  460. package/hooks/lib/privacy-filter.js +128 -0
  461. package/hooks/lib/prompt-injection-scanner.js +209 -0
  462. package/hooks/lib/provenance-tracker.js +183 -0
  463. package/hooks/lib/rate-limit-tracker.js +253 -0
  464. package/hooks/lib/reflect-classifier.js +164 -0
  465. package/hooks/lib/resource-quota.js +122 -0
  466. package/hooks/lib/retry-jitter.js +165 -0
  467. package/hooks/lib/risk-engine.js +368 -0
  468. package/hooks/lib/run-log.js +408 -0
  469. package/hooks/lib/session-fts.js +379 -0
  470. package/hooks/lib/session-store.js +293 -0
  471. package/hooks/lib/singleton-guard.js +159 -0
  472. package/hooks/lib/skill-auditor.js +588 -0
  473. package/hooks/lib/sync-status.js +228 -0
  474. package/hooks/lib/taint-tracker.js +107 -0
  475. package/hooks/lib/task-service.js +295 -0
  476. package/hooks/lib/tech-skills-map.js +146 -0
  477. package/hooks/lib/telegram-cliente.js +159 -0
  478. package/hooks/lib/telegram-config.js +170 -0
  479. package/hooks/lib/token-budget.js +156 -0
  480. package/hooks/lib/token-estimator.js +420 -0
  481. package/hooks/lib/toon-compressor.js +245 -0
  482. package/hooks/lib/usage-model.js +183 -0
  483. package/hooks/lib/variable-resolver.js +230 -0
  484. package/hooks/linea-estado.js +324 -0
  485. package/hooks/metricas-evolucion.js +209 -0
  486. package/hooks/monitor-contexto.js +325 -0
  487. package/hooks/notificacion-sesion-stop.js +198 -0
  488. package/hooks/notificacion-telegram-notification.js +4 -0
  489. package/hooks/notificacion-telegram-subagent.js +4 -0
  490. package/hooks/notificacion-telegram.js +267 -0
  491. package/hooks/preservar-estado-pre-compact.js +150 -0
  492. package/hooks/proteccion-rutas.js +366 -0
  493. package/hooks/registro-turnos.js +209 -0
  494. package/hooks/resumen-sesion.js +249 -0
  495. package/hooks/risk-scoring.js +323 -0
  496. package/hooks/rotar-audit-auto.js +122 -0
  497. package/hooks/sugerir-regenerar-inventario.js +170 -0
  498. package/hooks/telemetria-agentes.js +167 -0
  499. package/hooks/tracking-costos.js +688 -0
  500. package/instintos/global.yaml +8 -0
  501. package/instintos/perfil-usuario.yaml +53 -0
  502. package/instintos/prompt-appendices.yaml +57 -0
  503. package/instintos/proyecto.yaml +372 -0
  504. package/manifiestos/gateway-config.json +77 -0
  505. package/manifiestos/handoff-context.json +223 -0
  506. package/manifiestos/hook-profiles.json +44 -0
  507. package/manifiestos/hooks-config.json +360 -0
  508. package/manifiestos/modulos.json +1173 -0
  509. package/manifiestos/perfiles.json +404 -0
  510. package/package.json +86 -0
  511. package/plantillas/ESTADO.md +109 -0
  512. package/plantillas/HOJA-RUTA.md +143 -0
  513. package/plantillas/PROYECTO.md +122 -0
  514. package/plantillas/REQUISITOS.md +132 -0
  515. package/plantillas/auditor-veto-template.md +105 -0
  516. package/plantillas/github-workflows/README.md +47 -0
  517. package/plantillas/github-workflows/release-please.yml +44 -0
  518. package/plantillas/github-workflows/swl-ci.yml +107 -0
  519. package/plantillas/github-workflows/swl-security.yml +51 -0
  520. package/plantillas/mcp-mineru.json +13 -0
  521. package/plantillas/research/ARQUITECTURA.md +220 -0
  522. package/plantillas/research/FUNCIONALIDADES.md +175 -0
  523. package/plantillas/research/RESUMEN.md +165 -0
  524. package/plantillas/research/STACK.md +233 -0
  525. package/plantillas/research/TRAMPAS.md +299 -0
  526. package/plantillas/skill-evals-template.json +44 -0
  527. package/plugin.json +343 -0
  528. package/reglas/accesibilidad.md +269 -0
  529. package/reglas/api-diseno.md +400 -0
  530. package/reglas/arquitectura.md +352 -0
  531. package/reglas/brevedad-output.md +124 -0
  532. package/reglas/cloud-infra.md +247 -0
  533. package/reglas/docs.md +245 -0
  534. package/reglas/estilo-codigo.md +201 -0
  535. package/reglas/git-workflow.md +245 -0
  536. package/reglas/gobernanza.md +271 -0
  537. package/reglas/harness-claude-code.md +213 -0
  538. package/reglas/hooks.md +186 -0
  539. package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
  540. package/reglas/lenguajes/csharp/hooks.md +281 -0
  541. package/reglas/lenguajes/csharp/patrones.md +226 -0
  542. package/reglas/lenguajes/csharp/seguridad.md +258 -0
  543. package/reglas/lenguajes/csharp/testing.md +176 -0
  544. package/reglas/lenguajes/go/estilo-codigo.md +195 -0
  545. package/reglas/lenguajes/go/hooks.md +249 -0
  546. package/reglas/lenguajes/go/patrones.md +249 -0
  547. package/reglas/lenguajes/go/seguridad.md +225 -0
  548. package/reglas/lenguajes/go/testing.md +272 -0
  549. package/reglas/lenguajes/java/estilo-codigo.md +217 -0
  550. package/reglas/lenguajes/java/hooks.md +251 -0
  551. package/reglas/lenguajes/java/patrones.md +226 -0
  552. package/reglas/lenguajes/java/seguridad.md +233 -0
  553. package/reglas/lenguajes/java/testing.md +238 -0
  554. package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
  555. package/reglas/lenguajes/kotlin/hooks.md +245 -0
  556. package/reglas/lenguajes/kotlin/patrones.md +201 -0
  557. package/reglas/lenguajes/kotlin/seguridad.md +202 -0
  558. package/reglas/lenguajes/kotlin/testing.md +236 -0
  559. package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
  560. package/reglas/lenguajes/nextjs/hooks.md +186 -0
  561. package/reglas/lenguajes/nextjs/patrones.md +225 -0
  562. package/reglas/lenguajes/nextjs/seguridad.md +216 -0
  563. package/reglas/lenguajes/nextjs/testing.md +193 -0
  564. package/reglas/lenguajes/php/estilo-codigo.md +228 -0
  565. package/reglas/lenguajes/php/hooks.md +165 -0
  566. package/reglas/lenguajes/php/patrones.md +233 -0
  567. package/reglas/lenguajes/php/seguridad.md +186 -0
  568. package/reglas/lenguajes/php/testing.md +205 -0
  569. package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
  570. package/reglas/lenguajes/rust/hooks.md +240 -0
  571. package/reglas/lenguajes/rust/patrones.md +250 -0
  572. package/reglas/lenguajes/rust/seguridad.md +221 -0
  573. package/reglas/lenguajes/rust/testing.md +194 -0
  574. package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
  575. package/reglas/lenguajes/swift/hooks.md +257 -0
  576. package/reglas/lenguajes/swift/patrones.md +235 -0
  577. package/reglas/lenguajes/swift/seguridad.md +248 -0
  578. package/reglas/lenguajes/swift/testing.md +242 -0
  579. package/reglas/markitdown.md +60 -0
  580. package/reglas/memoria-consolidada.md +209 -0
  581. package/reglas/patrones.md +225 -0
  582. package/reglas/performance.md +195 -0
  583. package/reglas/pruebas.md +159 -0
  584. package/reglas/seguridad-agentes.md +351 -0
  585. package/reglas/seguridad.md +151 -0
  586. package/reglas/skills-estandar.md +373 -0
  587. package/reglas/testing.md +193 -0
  588. package/schemas/agent-contract.json +176 -0
  589. package/schemas/agent-frontmatter.schema.json +149 -0
  590. package/schemas/agent-message.schema.json +53 -0
  591. package/schemas/agent-output-implementacion.schema.json +85 -0
  592. package/schemas/agent-output-planificacion.schema.json +113 -0
  593. package/schemas/agent-output-review.schema.json +78 -0
  594. package/schemas/diary-entry.schema.json +80 -0
  595. package/schemas/hook-profiles.schema.json +39 -0
  596. package/schemas/hooks-config.schema.json +74 -0
  597. package/schemas/instinct.schema.json +115 -0
  598. package/schemas/modulos.schema.json +29 -0
  599. package/schemas/perfiles.schema.json +28 -0
  600. package/schemas/plugin.schema.json +64 -0
  601. package/schemas/skill-evals.schema.json +95 -0
  602. package/schemas/skill-frontmatter.schema.json +170 -0
  603. package/scripts/actualizar.js +145 -0
  604. package/scripts/audit-skills.sh +78 -0
  605. package/scripts/auditar-agentes-gaps.js +149 -0
  606. package/scripts/auditar-cobertura-frameworks.js +241 -0
  607. package/scripts/auditar-skills-gaps.js +206 -0
  608. package/scripts/bootstrap-instintos.js +259 -0
  609. package/scripts/check-update.js +109 -0
  610. package/scripts/comandos/agents.js +105 -0
  611. package/scripts/comandos/info.js +108 -0
  612. package/scripts/comandos/install-asistido.js +186 -0
  613. package/scripts/comandos/skills.js +211 -0
  614. package/scripts/configurar-branch-protection.js +418 -0
  615. package/scripts/daemon-swl.py +388 -0
  616. package/scripts/desinstalar.js +130 -0
  617. package/scripts/doctor.js +559 -0
  618. package/scripts/field-report.js +199 -0
  619. package/scripts/generar-inventario.js +317 -0
  620. package/scripts/inbox-tmux-inject.js +161 -0
  621. package/scripts/inferir-herramientas-permitidas.js +586 -0
  622. package/scripts/inicializar.js +133 -0
  623. package/scripts/instalador.js +1031 -0
  624. package/scripts/instalar-git-hook.js +122 -0
  625. package/scripts/lib/agp-frontmatter.js +222 -0
  626. package/scripts/lib/append-con-marcadores.js +199 -0
  627. package/scripts/lib/artefactos-python.js +43 -0
  628. package/scripts/lib/audit-query.js +221 -0
  629. package/scripts/lib/autostart-linux.js +347 -0
  630. package/scripts/lib/autostart-macos.js +360 -0
  631. package/scripts/lib/autostart-windows.js +307 -0
  632. package/scripts/lib/budget-enforcer.js +252 -0
  633. package/scripts/lib/claude-sessions.js +285 -0
  634. package/scripts/lib/configurar-ci.js +380 -0
  635. package/scripts/lib/console-span-exporter.js +92 -0
  636. package/scripts/lib/contadores-inventario.js +217 -0
  637. package/scripts/lib/dashboard-widgets.js +290 -0
  638. package/scripts/lib/detectar-runtime.js +279 -0
  639. package/scripts/lib/detectar-stack.js +187 -0
  640. package/scripts/lib/diary-entry.js +234 -0
  641. package/scripts/lib/drift-detector.js +545 -0
  642. package/scripts/lib/estado.js +124 -0
  643. package/scripts/lib/gestor-componentes.js +243 -0
  644. package/scripts/lib/gitignore-manifest.js +305 -0
  645. package/scripts/lib/graph-analyze.py +556 -0
  646. package/scripts/lib/graph-builder.py +485 -0
  647. package/scripts/lib/graph-cluster.py +259 -0
  648. package/scripts/lib/health-row.js +168 -0
  649. package/scripts/lib/hooks-settings.js +789 -0
  650. package/scripts/lib/manifiestos.js +138 -0
  651. package/scripts/lib/mc-client.js +137 -0
  652. package/scripts/lib/notificaciones-telegram.js +1107 -0
  653. package/scripts/lib/npm-version.js +261 -0
  654. package/scripts/lib/paquetes-conocidos.js +50 -0
  655. package/scripts/lib/preservar-usuario.js +586 -0
  656. package/scripts/lib/prompt-builder.js +264 -0
  657. package/scripts/lib/resolver-externo.js +332 -0
  658. package/scripts/lib/schedule-parser.js +305 -0
  659. package/scripts/lib/scoring-instintos.js +240 -0
  660. package/scripts/lib/seguridad.js +160 -0
  661. package/scripts/lib/selector-interactivo.js +152 -0
  662. package/scripts/lib/semantic-search.js +242 -0
  663. package/scripts/lib/skill-discovery.js +234 -0
  664. package/scripts/lib/skill-metrics.js +246 -0
  665. package/scripts/lib/skill-normalizer.js +112 -0
  666. package/scripts/lib/skills-hub.js +340 -0
  667. package/scripts/lib/span-schema.js +134 -0
  668. package/scripts/lib/tool-cost-analyzer.js +255 -0
  669. package/scripts/lib/tracing-processor-interface.js +286 -0
  670. package/scripts/lib/transformadores/base.js +80 -0
  671. package/scripts/lib/transformadores/claude.js +124 -0
  672. package/scripts/lib/transformadores/codex.js +115 -0
  673. package/scripts/lib/transformadores/copilot.js +106 -0
  674. package/scripts/lib/transformadores/gemini.js +74 -0
  675. package/scripts/lib/transformadores/index.js +35 -0
  676. package/scripts/lib/transformadores/opencode.js +75 -0
  677. package/scripts/lib/ui.js +259 -0
  678. package/scripts/limpiar-artefactos-python.js +131 -0
  679. package/scripts/mcp-orchestrator.py +386 -0
  680. package/scripts/mcp-pool-manager.py +352 -0
  681. package/scripts/mcp-telemetry.py +378 -0
  682. package/scripts/poblar-evolvable.js +226 -0
  683. package/scripts/publicar.js +287 -0
  684. package/scripts/reflect-skills.js +403 -0
  685. package/scripts/rotar-audit-logs.js +185 -0
  686. package/scripts/run-skill-evals.js +242 -0
  687. package/scripts/smoke-test.js +374 -0
  688. package/scripts/token-analysis.py +471 -0
  689. package/scripts/validar-manifest.js +195 -0
  690. package/scripts/validar-memoria.js +321 -0
  691. package/scripts/validar-tests-aislamiento.js +184 -0
  692. package/scripts/validar-tokens-test.js +208 -0
  693. package/scripts/validar.js +147 -0
  694. package/scripts/validate-markdown.py +339 -0
  695. package/scripts/validate-skills.py +385 -0
  696. package/scripts/vendor/claude-usage/README.md +116 -0
  697. package/scripts/vendor/claude-usage/cli.py +334 -0
  698. package/scripts/vendor/claude-usage/dashboard.py +795 -0
  699. package/scripts/vendor/claude-usage/scanner.py +467 -0
  700. package/scripts/vendor/markitdown/cli.py +194 -0
  701. package/scripts/verificar-evolucion.js +289 -0
  702. package/scripts/verificar-release.js +494 -0
@@ -0,0 +1,545 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * drift-detector.js
5
+ *
6
+ * Detector de drift para el ciclo AGP de swl-ses.
7
+ *
8
+ * Algoritmo de ventana deslizante (7 días recientes) vs baseline (4 semanas
9
+ * previas) que identifica degradación de skills y agentes antes de que el
10
+ * health score lo refleje.
11
+ *
12
+ * Adaptado de `runDriftCheck` y `getDriftTimeline` en:
13
+ * temp/mission-control-main/src/lib/agent-evals.ts (líneas 188-345)
14
+ * Licencia: MIT — Builderz Labs
15
+ *
16
+ * Diferencias respecto al original:
17
+ * - Fuente de datos: JSONL en disco, no SQLite
18
+ * - Sin dependencias externas (solo Node stdlib: fs, path)
19
+ * - Métricas configurables via parámetro, no hardcodeadas
20
+ * - Emite nudge a .planning/evolucion/nudges.jsonl en drift crítico
21
+ *
22
+ * @module scripts/lib/drift-detector
23
+ */
24
+
25
+ const fs = require('fs');
26
+ const path = require('path');
27
+
28
+ // ── constantes ────────────────────────────────────────────────────────────────
29
+
30
+ const UMBRAL_DEFAULT_PCT = 10; // warn si drift > 10%
31
+ const VENTANA_DIAS_DEFAULT = 7;
32
+ const BASELINE_SEMANAS_DEFAULT = 4;
33
+ const DIAS_LINEA_DEFAULT = 30;
34
+
35
+ /**
36
+ * Umbral de repair-loop: tras N nudges sucesivos del mismo (metrica, agente)
37
+ * sin accionar, banear el par para no saturar nudges.jsonl.
38
+ * Patrón adaptado de evolver GEP (temp/evolver-main/src/config.js:74-88).
39
+ */
40
+ const REPAIR_LOOP_THRESHOLD = parseInt(process.env.SWL_REPAIR_LOOP_THRESHOLD || '3', 10);
41
+
42
+ /** Ventana para contar repeticiones sin accionar (ms). */
43
+ const REPAIR_LOOP_WINDOW_MS = 14 * 24 * 3600 * 1000;
44
+
45
+ const METRICAS_DEFAULT = [
46
+ 'tokens_promedio_por_sesion',
47
+ 'tasa_exito_tool',
48
+ 'tasa_finalizacion_tarea',
49
+ ];
50
+
51
+ // Ruta raíz del proyecto (dos niveles arriba de scripts/lib/)
52
+ const RAIZ_PROYECTO = path.resolve(__dirname, '..', '..');
53
+ const RUTA_NUDGES = path.join(RAIZ_PROYECTO, '.planning', 'evolucion', 'nudges.jsonl');
54
+
55
+ // ── helpers internos ──────────────────────────────────────────────────────────
56
+
57
+ /**
58
+ * Lee y parsea un archivo JSONL. Filtra líneas vacías y JSON inválido.
59
+ *
60
+ * @param {string} ruta - Ruta absoluta al archivo JSONL.
61
+ * @returns {object[]} Array de objetos parseados.
62
+ * @throws {Error} Si el archivo no existe o no es legible.
63
+ */
64
+ function leerJsonl(ruta) {
65
+ if (!fs.existsSync(ruta)) {
66
+ throw new Error(`JSONL no encontrado: ${ruta}`);
67
+ }
68
+ const contenido = fs.readFileSync(ruta, 'utf8');
69
+ return contenido
70
+ .split('\n')
71
+ .filter(l => l.trim().length > 0)
72
+ .reduce((acc, linea) => {
73
+ try {
74
+ acc.push(JSON.parse(linea));
75
+ } catch (_) {
76
+ // línea malformada — ignorar silenciosamente
77
+ }
78
+ return acc;
79
+ }, []);
80
+ }
81
+
82
+ /**
83
+ * Convierte un timestamp ISO o epoch-segundos a epoch-milisegundos.
84
+ *
85
+ * @param {string|number} ts
86
+ * @returns {number} timestamp en ms, o NaN si inválido.
87
+ */
88
+ function aMs(ts) {
89
+ if (!ts) return NaN;
90
+ if (typeof ts === 'number') {
91
+ // Si viene en segundos (< año 3000 en segundos), convertir a ms
92
+ return ts < 32503680000 ? ts * 1000 : ts;
93
+ }
94
+ return new Date(ts).getTime();
95
+ }
96
+
97
+ /**
98
+ * Calcula métricas agregadas de un conjunto de eventos.
99
+ *
100
+ * @param {object[]} eventos
101
+ * @param {string[]} metricas - Lista de nombres de métrica a calcular.
102
+ * @returns {object} Mapa metrica → valor calculado (0 si sin datos).
103
+ */
104
+ function calcularMetricas(eventos, metricas) {
105
+ const resultado = {};
106
+
107
+ if (metricas.includes('tokens_promedio_por_sesion')) {
108
+ const coTokens = eventos.filter(e => {
109
+ const t = e.atributos?.tokens_totales ?? e.tokens ?? e.total_tokens;
110
+ return typeof t === 'number';
111
+ });
112
+ resultado.tokens_promedio_por_sesion = coTokens.length > 0
113
+ ? coTokens.reduce((s, e) => {
114
+ const t = e.atributos?.tokens_totales ?? e.tokens ?? e.total_tokens ?? 0;
115
+ return s + t;
116
+ }, 0) / coTokens.length
117
+ : 0;
118
+ }
119
+
120
+ if (metricas.includes('tasa_exito_tool')) {
121
+ const conExito = eventos.filter(e => {
122
+ const s = e.success ?? e.exito ?? e.atributos?.success;
123
+ return s !== undefined && s !== null;
124
+ });
125
+ if (conExito.length > 0) {
126
+ const exitosos = conExito.filter(e => {
127
+ const s = e.success ?? e.exito ?? e.atributos?.success;
128
+ return s === true || s === 1 || s === 'true';
129
+ }).length;
130
+ resultado.tasa_exito_tool = exitosos / conExito.length;
131
+ } else {
132
+ resultado.tasa_exito_tool = 1.0; // sin datos → asumir 100%
133
+ }
134
+ }
135
+
136
+ if (metricas.includes('tasa_finalizacion_tarea')) {
137
+ const conEstado = eventos.filter(e => {
138
+ const st = e.estado ?? e.status ?? e.atributos?.estado;
139
+ return st !== undefined && st !== null;
140
+ });
141
+ if (conEstado.length > 0) {
142
+ const terminadas = conEstado.filter(e => {
143
+ const st = String(e.estado ?? e.status ?? e.atributos?.estado ?? '').toLowerCase();
144
+ return st === 'ok' || st === 'done' || st === 'completado' || st === 'complete';
145
+ }).length;
146
+ resultado.tasa_finalizacion_tarea = terminadas / conEstado.length;
147
+ } else {
148
+ resultado.tasa_finalizacion_tarea = 1.0;
149
+ }
150
+ }
151
+
152
+ return resultado;
153
+ }
154
+
155
+ /**
156
+ * Determina el estado de drift para un porcentaje dado.
157
+ *
158
+ * @param {number} driftPct
159
+ * @param {number} umbralPct
160
+ * @returns {'ok'|'warn'|'critico'}
161
+ */
162
+ function estadoDrift(driftPct, umbralPct) {
163
+ const abs = Math.abs(driftPct);
164
+ if (abs > umbralPct * 2) return 'critico';
165
+ if (abs > umbralPct) return 'warn';
166
+ return 'ok';
167
+ }
168
+
169
+ /**
170
+ * Cuenta nudges previos tipo 'drift-detectado' del mismo (metrica, agente)
171
+ * no accionados dentro de la ventana. Zero-deps, lectura lineal.
172
+ *
173
+ * @param {string} metrica
174
+ * @param {string} agente
175
+ * @returns {number} cantidad de nudges no accionados en la ventana
176
+ */
177
+ function contarNudgesPrevios(metrica, agente) {
178
+ if (!fs.existsSync(RUTA_NUDGES)) return 0;
179
+ let contenido;
180
+ try {
181
+ contenido = fs.readFileSync(RUTA_NUDGES, 'utf8');
182
+ } catch {
183
+ return 0;
184
+ }
185
+ const limiteMs = Date.now() - REPAIR_LOOP_WINDOW_MS;
186
+ let conteo = 0;
187
+ for (const linea of contenido.split(/\r?\n/)) {
188
+ if (!linea.trim()) continue;
189
+ let ev;
190
+ try { ev = JSON.parse(linea); } catch { continue; }
191
+ const esDrift = ev.tipo === 'drift-detectado' || ev.kind === 'drift-detectado';
192
+ if (!esDrift) continue;
193
+ const mismaMetrica = ev.metrica === metrica;
194
+ const mismoAgente = (ev.agente_o_skill === agente) || (ev.target === agente);
195
+ if (!mismaMetrica || !mismoAgente) continue;
196
+ if (ev.accionado === true) continue;
197
+ const t = Date.parse(ev.timestamp || ev.ts || '');
198
+ if (!Number.isFinite(t) || t < limiteMs) continue;
199
+ conteo++;
200
+ }
201
+ return conteo;
202
+ }
203
+
204
+ /**
205
+ * Emite un nudge a .planning/evolucion/nudges.jsonl cuando se detecta
206
+ * drift crítico. Usa fs.appendFileSync (JSONL, no sobreescribe).
207
+ *
208
+ * Aplica repair-loop detection: si el mismo (metrica, agente) ya fue
209
+ * emitido ≥ REPAIR_LOOP_THRESHOLD veces sin accionar en la ventana,
210
+ * el nudge se marca como `banned: true` para inspección diagnóstica
211
+ * pero no se emite a stderr. Esto evita saturar el log ante drift
212
+ * persistente ignorado.
213
+ *
214
+ * @param {string} metrica
215
+ * @param {number} driftPct
216
+ * @param {string} [agente]
217
+ * @returns {{emitido: boolean, banned: boolean, previos: number}}
218
+ */
219
+ function emitirNudgeDrift(metrica, driftPct, agente) {
220
+ const agenteNormalizado = agente || 'desconocido';
221
+ const previos = contarNudgesPrevios(metrica, agenteNormalizado);
222
+ const banned = previos >= REPAIR_LOOP_THRESHOLD;
223
+
224
+ const nudge = {
225
+ timestamp: new Date().toISOString(),
226
+ tipo: 'drift-detectado',
227
+ agente_o_skill: agenteNormalizado,
228
+ metrica,
229
+ drift_pct: Math.round(driftPct * 100) / 100,
230
+ estado: 'critico',
231
+ previos_ventana: previos,
232
+ };
233
+ if (banned) nudge.banned = true;
234
+
235
+ try {
236
+ fs.appendFileSync(RUTA_NUDGES, JSON.stringify(nudge) + '\n', 'utf8');
237
+ } catch (_) {
238
+ // No crashear si la carpeta no existe
239
+ }
240
+ return { emitido: !banned, banned, previos };
241
+ }
242
+
243
+ // ── exports públicos ──────────────────────────────────────────────────────────
244
+
245
+ /**
246
+ * Detecta drift comparando una ventana reciente contra un baseline histórico.
247
+ *
248
+ * Lee el JSONL indicado, divide los eventos en dos ventanas temporales y
249
+ * calcula el porcentaje de variación por métrica. Emite nudge automático
250
+ * si algún drift es crítico.
251
+ *
252
+ * @param {object} opts
253
+ * @param {string} opts.rutaJsonl - Ruta absoluta al archivo JSONL de eventos.
254
+ * @param {number} [opts.ventanaDias=7] - Tamaño de la ventana reciente en días.
255
+ * @param {number} [opts.baselineSemanasBase=4] - Semanas de baseline previas a la ventana.
256
+ * @param {number} [opts.umbralPct=10] - Umbral de alerta (warn si drift > umbralPct%).
257
+ * @param {string[]} [opts.metricas] - Métricas a calcular (ver METRICAS_DEFAULT).
258
+ * @param {string} [opts.agente] - Nombre del agente/skill (para nudges).
259
+ * @returns {{
260
+ * drifts: Array<{metrica:string, baseline:number, reciente:number, driftPct:number, estado:string}>,
261
+ * timestamp: string,
262
+ * estado_global: 'ok'|'warn'|'critico'
263
+ * }}
264
+ */
265
+ function detectarDrift({
266
+ rutaJsonl,
267
+ ventanaDias = VENTANA_DIAS_DEFAULT,
268
+ baselineSemanasBase = BASELINE_SEMANAS_DEFAULT,
269
+ umbralPct = UMBRAL_DEFAULT_PCT,
270
+ metricas = METRICAS_DEFAULT,
271
+ agente,
272
+ } = {}) {
273
+ let eventos;
274
+ try {
275
+ eventos = leerJsonl(rutaJsonl);
276
+ } catch (err) {
277
+ return {
278
+ drifts: [],
279
+ timestamp: new Date().toISOString(),
280
+ estado_global: 'ok',
281
+ error: err.message,
282
+ };
283
+ }
284
+
285
+ const ahora = Date.now();
286
+ const msVentana = ventanaDias * 24 * 3600 * 1000;
287
+ const msBaseline = baselineSemanasBase * 7 * 24 * 3600 * 1000;
288
+
289
+ const inicioVentana = ahora - msVentana;
290
+ const inicioBaseline = ahora - msBaseline - msVentana;
291
+ const finBaseline = inicioVentana;
292
+
293
+ const eventosRecientes = eventos.filter(e => {
294
+ const ms = aMs(e.timestamp ?? e.ts ?? e.inicio ?? e.created_at);
295
+ return !isNaN(ms) && ms >= inicioVentana && ms <= ahora;
296
+ });
297
+
298
+ const eventosBaseline = eventos.filter(e => {
299
+ const ms = aMs(e.timestamp ?? e.ts ?? e.inicio ?? e.created_at);
300
+ return !isNaN(ms) && ms >= inicioBaseline && ms < finBaseline;
301
+ });
302
+
303
+ const metricasRecientes = calcularMetricas(eventosRecientes, metricas);
304
+ const metricasBaseline = calcularMetricas(eventosBaseline, metricas);
305
+
306
+ const drifts = metricas.map(m => {
307
+ const base = metricasBaseline[m] ?? 0;
308
+ const actual = metricasRecientes[m] ?? 0;
309
+
310
+ let driftPct;
311
+ if (base !== 0) {
312
+ driftPct = (actual - base) / Math.abs(base) * 100;
313
+ } else {
314
+ driftPct = actual !== 0 ? 100 : 0;
315
+ }
316
+ driftPct = Math.round(driftPct * 100) / 100;
317
+
318
+ const estado = estadoDrift(driftPct, umbralPct);
319
+ return { metrica: m, baseline: base, reciente: actual, driftPct, estado };
320
+ });
321
+
322
+ // Emitir nudge por cada métrica crítica
323
+ for (const d of drifts) {
324
+ if (d.estado === 'critico') {
325
+ emitirNudgeDrift(d.metrica, d.driftPct, agente);
326
+ }
327
+ }
328
+
329
+ const estado_global = drifts.some(d => d.estado === 'critico') ? 'critico'
330
+ : drifts.some(d => d.estado === 'warn') ? 'warn'
331
+ : 'ok';
332
+
333
+ return {
334
+ drifts,
335
+ timestamp: new Date().toISOString(),
336
+ estado_global,
337
+ };
338
+ }
339
+
340
+ /**
341
+ * Genera una línea temporal diaria de métricas agregadas para visualización.
342
+ *
343
+ * Para cada uno de los últimos `dias` días calcula tokens, éxitos y fallos
344
+ * acumulados en ese día.
345
+ *
346
+ * @param {object} opts
347
+ * @param {string} opts.rutaJsonl - Ruta absoluta al archivo JSONL de eventos.
348
+ * @param {number} [opts.ventanaDias=7] - No usado en este export; reservado para consistencia API.
349
+ * @param {number} [opts.dias=30] - Cantidad de días en el historial.
350
+ * @returns {Array<{fecha:string, tokens:number, exitos:number, fallos:number}>}
351
+ */
352
+ function generarLineaTemporal({
353
+ rutaJsonl,
354
+ ventanaDias = VENTANA_DIAS_DEFAULT, // eslint-disable-line no-unused-vars
355
+ dias = DIAS_LINEA_DEFAULT,
356
+ } = {}) {
357
+ let eventos;
358
+ try {
359
+ eventos = leerJsonl(rutaJsonl);
360
+ } catch (_) {
361
+ eventos = [];
362
+ }
363
+
364
+ const ahora = Date.now();
365
+ const linea = [];
366
+
367
+ for (let i = dias - 1; i >= 0; i--) {
368
+ const inicioDia = ahora - (i + 1) * 24 * 3600 * 1000;
369
+ const finDia = ahora - i * 24 * 3600 * 1000;
370
+ const fecha = new Date(inicioDia).toISOString().slice(0, 10);
371
+
372
+ const del_dia = eventos.filter(e => {
373
+ const ms = aMs(e.timestamp ?? e.ts ?? e.inicio ?? e.created_at);
374
+ return !isNaN(ms) && ms >= inicioDia && ms < finDia;
375
+ });
376
+
377
+ const tokens = del_dia.reduce((s, e) => {
378
+ return s + (e.atributos?.tokens_totales ?? e.tokens ?? e.total_tokens ?? 0);
379
+ }, 0);
380
+
381
+ const exitos = del_dia.filter(e => {
382
+ const s = e.success ?? e.exito ?? e.atributos?.success;
383
+ return s === true || s === 1 || s === 'true';
384
+ }).length;
385
+
386
+ const fallos = del_dia.filter(e => {
387
+ const s = e.success ?? e.exito ?? e.atributos?.success;
388
+ return s === false || s === 0 || s === 'false';
389
+ }).length;
390
+
391
+ linea.push({ fecha, tokens, exitos, fallos });
392
+ }
393
+
394
+ return linea;
395
+ }
396
+
397
+ // ── Drift Score formalizado (Bhardwaj 2026, §3.12) ──────────────────────────
398
+ //
399
+ // Métrica continua D(t) ∈ [0, 1] que combina:
400
+ // - Componente compliance (lagging): 1 − C_soft(t), proporción de
401
+ // restricciones soft violadas en la ventana reciente.
402
+ // - Componente distribucional (leading): √JSD(P_obs ∥ P_ref), Jensen-
403
+ // Shannon divergence entre la distribución observada de acciones y la
404
+ // distribución de referencia. La √ comprime el rango y da más peso
405
+ // a desviaciones pequeñas detectables temprano.
406
+ //
407
+ // D(t) = w_c · (1 − C_soft) + w_d · √JSD
408
+ //
409
+ // Pesos por defecto w_c=0.7, w_d=0.3 reflejan que las violaciones son
410
+ // señal más fuerte que la deriva distribucional. Configurables.
411
+ //
412
+ // Referencia: Bhardwaj V.P., "Agent Behavioral Contracts: Formal
413
+ // Specification and Runtime Enforcement", arXiv:2602.22302v1, §3.12.
414
+ //
415
+ // Adaptación SWL: implementación zero-deps Node stdlib. Las distribuciones
416
+ // son objetos plain {accion: probabilidad}.
417
+
418
+ /**
419
+ * Calcula la divergencia Kullback-Leibler de p respecto a q sobre el soporte
420
+ * de p. Usa logaritmo natural. Convención: 0 · log(0/q) = 0.
421
+ *
422
+ * @param {object} p - Distribución como {clave: probabilidad}
423
+ * @param {object} q - Distribución como {clave: probabilidad}
424
+ * @returns {number} KL(p || q) en nats
425
+ */
426
+ function divergenciaKL(p, q) {
427
+ let suma = 0;
428
+ for (const k of Object.keys(p)) {
429
+ const pi = p[k];
430
+ if (!pi || pi <= 0) continue;
431
+ const qi = q[k];
432
+ if (!qi || qi <= 0) {
433
+ // KL infinita si q asigna 0 a un evento que p considera posible.
434
+ // Convención práctica: usar smoothing mínimo en lugar de Infinity.
435
+ return Infinity;
436
+ }
437
+ suma += pi * Math.log(pi / qi);
438
+ }
439
+ return suma;
440
+ }
441
+
442
+ /**
443
+ * Jensen-Shannon divergence entre dos distribuciones discretas.
444
+ * Simétrica, acotada en [0, log(2)] con logaritmo natural.
445
+ * Aplicamos smoothing aditivo (Laplace) para evitar KL infinita cuando
446
+ * el soporte difiere.
447
+ *
448
+ * @param {object} pObs - Distribución observada (frecuencias o probs)
449
+ * @param {object} pRef - Distribución de referencia
450
+ * @returns {number} JSD normalizada en [0, 1]
451
+ */
452
+ function divergenciaJS(pObs, pRef) {
453
+ const claves = new Set([...Object.keys(pObs || {}), ...Object.keys(pRef || {})]);
454
+ if (claves.size === 0) return 0;
455
+
456
+ // Normalizar a probabilidades + Laplace smoothing
457
+ const epsilon = 1e-9;
458
+ const p = {}, q = {};
459
+ let sumP = 0, sumQ = 0;
460
+ for (const k of claves) {
461
+ p[k] = (pObs?.[k] || 0) + epsilon;
462
+ q[k] = (pRef?.[k] || 0) + epsilon;
463
+ sumP += p[k];
464
+ sumQ += q[k];
465
+ }
466
+ for (const k of claves) {
467
+ p[k] /= sumP;
468
+ q[k] /= sumQ;
469
+ }
470
+
471
+ const m = {};
472
+ for (const k of claves) {
473
+ m[k] = 0.5 * (p[k] + q[k]);
474
+ }
475
+ const jsd = 0.5 * divergenciaKL(p, m) + 0.5 * divergenciaKL(q, m);
476
+ // Normalizar a [0,1] dividiendo por log(2)
477
+ return jsd / Math.log(2);
478
+ }
479
+
480
+ /**
481
+ * Calcula el Drift Score D(t) según Bhardwaj 2026, §3.12, adaptado a SWL.
482
+ *
483
+ * @param {object} opts
484
+ * @param {number} opts.compliance - C_soft(t) ∈ [0, 1]; 1 = sin violaciones
485
+ * @param {object} [opts.accionesObservadas] - {tool: count} en ventana reciente
486
+ * @param {object} [opts.accionesReferencia] - {tool: count} en baseline
487
+ * @param {number} [opts.pesoCompliance=0.7] - w_c
488
+ * @param {number} [opts.pesoDistribucion=0.3] - w_d
489
+ * @returns {{
490
+ * driftScore: number,
491
+ * compliance_term: number,
492
+ * distribucion_term: number,
493
+ * jsd: number,
494
+ * estado: 'ok' | 'warn' | 'critico'
495
+ * }}
496
+ */
497
+ function calcularDriftScore({
498
+ compliance,
499
+ accionesObservadas,
500
+ accionesReferencia,
501
+ pesoCompliance = 0.7,
502
+ pesoDistribucion = 0.3,
503
+ } = {}) {
504
+ const cClamp = typeof compliance === 'number'
505
+ ? Math.max(0, Math.min(1, compliance))
506
+ : 1;
507
+
508
+ const complianceTerm = 1 - cClamp;
509
+ const jsd = (accionesObservadas && accionesReferencia)
510
+ ? divergenciaJS(accionesObservadas, accionesReferencia)
511
+ : 0;
512
+ const distribucionTerm = Math.sqrt(Math.max(0, jsd));
513
+
514
+ const score = pesoCompliance * complianceTerm + pesoDistribucion * distribucionTerm;
515
+ const driftScore = Math.max(0, Math.min(1, score));
516
+
517
+ let estado = 'ok';
518
+ if (driftScore > 0.6) estado = 'critico';
519
+ else if (driftScore > 0.35) estado = 'warn';
520
+
521
+ return {
522
+ driftScore: Math.round(driftScore * 1000) / 1000,
523
+ compliance_term: Math.round(complianceTerm * 1000) / 1000,
524
+ distribucion_term: Math.round(distribucionTerm * 1000) / 1000,
525
+ jsd: Math.round(jsd * 1000) / 1000,
526
+ estado,
527
+ };
528
+ }
529
+
530
+ module.exports = {
531
+ detectarDrift,
532
+ generarLineaTemporal,
533
+ // Drift Score formalizado (Bhardwaj 2026 §3.12)
534
+ calcularDriftScore,
535
+ divergenciaJS,
536
+ // Exponer para tests
537
+ _leerJsonl: leerJsonl,
538
+ _calcularMetricas: calcularMetricas,
539
+ _estadoDrift: estadoDrift,
540
+ _contarNudgesPrevios: contarNudgesPrevios,
541
+ _emitirNudgeDrift: emitirNudgeDrift,
542
+ _divergenciaKL: divergenciaKL,
543
+ METRICAS_DEFAULT,
544
+ REPAIR_LOOP_THRESHOLD,
545
+ };
@@ -0,0 +1,124 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Gestión de estado de instalación SWL.
5
+ * Persiste qué se instaló, dónde y cuándo para soporte de doctor/repair/uninstall.
6
+ */
7
+
8
+ const fs = require('fs');
9
+ const path = require('path');
10
+
11
+ const NOMBRE_ESTADO = '.swl-install-state.json';
12
+
13
+ /**
14
+ * Crea un nuevo registro de estado de instalación
15
+ */
16
+ function crearEstado(opciones) {
17
+ return {
18
+ version: 3,
19
+ sistema: 'swl-software-engineering-system',
20
+ versionSistema: opciones.versionSistema || '1.0.0',
21
+ target: opciones.target,
22
+ perfil: opciones.perfil,
23
+ rutaBase: opciones.rutaBase,
24
+ global: opciones.global || false,
25
+ componentesInstalados: [],
26
+ archivosInstalados: [],
27
+ componentesExternos: [],
28
+ hooksRegistrados: 0,
29
+ settingsModificado: false,
30
+ instaladoEn: new Date().toISOString(),
31
+ actualizadoEn: new Date().toISOString(),
32
+ };
33
+ }
34
+
35
+ /**
36
+ * Registra un archivo instalado en el estado
37
+ */
38
+ function registrarArchivo(estado, archivo) {
39
+ estado.archivosInstalados.push({
40
+ origen: archivo.origen,
41
+ destino: archivo.destino,
42
+ tipo: archivo.tipo, // agente, habilidad, comando, regla, hook
43
+ checksum: archivo.checksum || null,
44
+ instaladoEn: new Date().toISOString(),
45
+ });
46
+ estado.actualizadoEn = new Date().toISOString();
47
+ }
48
+
49
+ /**
50
+ * Registra un componente instalado
51
+ */
52
+ function registrarComponente(estado, componente) {
53
+ if (!estado.componentesInstalados.includes(componente)) {
54
+ estado.componentesInstalados.push(componente);
55
+ estado.actualizadoEn = new Date().toISOString();
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Guarda el estado en disco
61
+ */
62
+ function guardarEstado(estado, directorio) {
63
+ const rutaEstado = path.join(directorio, NOMBRE_ESTADO);
64
+ fs.writeFileSync(rutaEstado, JSON.stringify(estado, null, 2), 'utf-8');
65
+ return rutaEstado;
66
+ }
67
+
68
+ /**
69
+ * Carga el estado desde disco.
70
+ * Si detecta formato v2, migra automáticamente a v3.
71
+ */
72
+ function cargarEstado(directorio) {
73
+ const rutaEstado = path.join(directorio, NOMBRE_ESTADO);
74
+ if (!fs.existsSync(rutaEstado)) {
75
+ return null;
76
+ }
77
+ try {
78
+ const estado = JSON.parse(fs.readFileSync(rutaEstado, 'utf-8'));
79
+ // Migración v2 → v3
80
+ if (estado.version === 2 || !estado.version) {
81
+ estado.version = 3;
82
+ if (!estado.componentesExternos) {
83
+ estado.componentesExternos = [];
84
+ }
85
+ // Persistir la migración
86
+ fs.writeFileSync(rutaEstado, JSON.stringify(estado, null, 2), 'utf-8');
87
+ }
88
+ return estado;
89
+ } catch {
90
+ return null;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Verifica integridad del estado contra archivos en disco
96
+ */
97
+ function verificarIntegridad(estado) {
98
+ const problemas = [];
99
+
100
+ for (const archivo of estado.archivosInstalados) {
101
+ if (!fs.existsSync(archivo.destino)) {
102
+ problemas.push({
103
+ tipo: 'faltante',
104
+ archivo: archivo.destino,
105
+ mensaje: `Archivo instalado no encontrado: ${archivo.destino}`,
106
+ });
107
+ }
108
+ }
109
+
110
+ return {
111
+ integro: problemas.length === 0,
112
+ problemas,
113
+ };
114
+ }
115
+
116
+ module.exports = {
117
+ NOMBRE_ESTADO,
118
+ crearEstado,
119
+ registrarArchivo,
120
+ registrarComponente,
121
+ guardarEstado,
122
+ cargarEstado,
123
+ verificarIntegridad,
124
+ };