@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,789 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Gestión de hooks en settings.json del runtime destino.
5
+ *
6
+ * Funciones para registrar, desregistrar y verificar hooks SWL
7
+ * en la configuración del runtime (Claude Code, Gemini CLI, etc.).
8
+ *
9
+ * Los hooks SWL se identifican por la presencia de "hooks/" + nombre
10
+ * del archivo en el campo `command`.
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ const RAIZ_PKG = path.resolve(__dirname, '..', '..');
17
+
18
+ /**
19
+ * Carga la configuración de hooks desde manifiestos/hooks-config.json
20
+ * @returns {object} Mapa de nombre_archivo → { event, matcher, description, blocking }
21
+ */
22
+ function cargarHooksConfig() {
23
+ const configPath = path.join(RAIZ_PKG, 'manifiestos', 'hooks-config.json');
24
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
25
+ return config.hooks;
26
+ }
27
+
28
+ /**
29
+ * Lee settings.json del runtime. Si no existe, retorna objeto base.
30
+ * @param {string} settingsPath - Ruta completa al archivo settings.json
31
+ * @returns {object}
32
+ */
33
+ function leerSettings(settingsPath) {
34
+ if (!fs.existsSync(settingsPath)) {
35
+ return {};
36
+ }
37
+ try {
38
+ return JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
39
+ } catch {
40
+ return {};
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Escribe settings.json preservando formato legible.
46
+ * @param {string} settingsPath
47
+ * @param {object} settings
48
+ */
49
+ function escribirSettings(settingsPath, settings) {
50
+ const dir = path.dirname(settingsPath);
51
+ if (!fs.existsSync(dir)) {
52
+ fs.mkdirSync(dir, { recursive: true });
53
+ }
54
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', 'utf-8');
55
+ }
56
+
57
+ /**
58
+ * Determina si un hook entry en settings.json pertenece a SWL.
59
+ * @param {object} entry - { matcher, hooks: [{ type, command }] }
60
+ * @returns {boolean}
61
+ */
62
+ function esHookSWL(entry) {
63
+ const hooksArr = entry.hooks || [];
64
+ return hooksArr.some(h => {
65
+ const cmd = h.command || '';
66
+ // Los hooks SWL usan el patrón: node hooks/nombre-hook.js
67
+ return /node\s+.*hooks\/[a-z-]+\.js/.test(cmd);
68
+ });
69
+ }
70
+
71
+ /**
72
+ * Calcula la ruta del settings.json para un runtime.
73
+ * @param {object} runtime - Configuración del runtime
74
+ * @param {string} base - Directorio base (.claude, ~/.claude, etc.)
75
+ * @returns {string} Ruta completa al settings.json
76
+ */
77
+ function rutaSettings(runtime, base) {
78
+ const configFile = runtime.hookConfig || 'settings.json';
79
+ return path.join(base, configFile);
80
+ }
81
+
82
+ /**
83
+ * En Windows (o cuando el entorno lo solicita vía SWL_HOOKS_PATH_PREFIX),
84
+ * agrega ubicaciones típicas de Node al PATH del comando para resolver
85
+ * `node: command not found` en git-bash/MinGW y similares.
86
+ *
87
+ * El prefix es inocuo en Linux/macOS: los paths no existen y se ignoran.
88
+ * El usuario puede desactivarlo con SWL_HOOKS_PATH_PREFIX=0.
89
+ */
90
+ function prefijoPathNode() {
91
+ if (process.env.SWL_HOOKS_PATH_PREFIX === '0') return '';
92
+ // En Windows siempre; en otros sistemas solo si se pide explícitamente.
93
+ const aplicar = process.platform === 'win32' || process.env.SWL_HOOKS_PATH_PREFIX === '1';
94
+ if (!aplicar) return '';
95
+ // Usamos rutas de estilo MSYS/Git-Bash: funcionan en git-bash y son
96
+ // ignoradas silenciosamente por `sh` en sistemas donde no existen.
97
+ return 'PATH="/c/Program Files/nodejs:/c/Program Files (x86)/nodejs:$PATH" ';
98
+ }
99
+
100
+ /**
101
+ * Decide si debe usarse el wrapper bash `hooks/_run-hook.sh` en lugar del
102
+ * inline `node -e`. El wrapper es más robusto contra formatters que
103
+ * reescriben settings.json, porque el command es corto y no contiene el
104
+ * prefix PATH que algunos formatters remueven.
105
+ *
106
+ * Activar con SWL_HOOKS_USAR_WRAPPER=1 (opt-in por ahora para no romper
107
+ * instalaciones existentes; se activará por default en v6.0.0).
108
+ */
109
+ function debeUsarWrapper(hooksDir) {
110
+ if (process.env.SWL_HOOKS_USAR_WRAPPER === '0') return false;
111
+ if (process.env.SWL_HOOKS_USAR_WRAPPER !== '1') return false;
112
+ try {
113
+ const fs = require('fs');
114
+ const wrapperPath = path.join(hooksDir, '_run-hook.sh');
115
+ return fs.existsSync(wrapperPath);
116
+ } catch {
117
+ return false;
118
+ }
119
+ }
120
+
121
+ /**
122
+ * Genera el comando para ejecutar un hook desde el directorio de trabajo.
123
+ * @param {string} hookFilename - Nombre del archivo de hook (ej: "escaneo-secretos.js")
124
+ * @param {string} hooksDir - Directorio donde se instalaron los hooks
125
+ * @param {boolean} esGlobal - Si es instalación global
126
+ * @returns {string} Comando ejecutable
127
+ */
128
+ function generarComando(hookFilename, hooksDir, esGlobal) {
129
+ // Modo wrapper (opt-in): más resiliente contra formatters
130
+ if (debeUsarWrapper(hooksDir)) {
131
+ if (esGlobal) {
132
+ const wrapper = path.join(hooksDir, '_run-hook.sh').replace(/\\/g, '/');
133
+ const hookAbs = path.join(hooksDir, hookFilename).replace(/\\/g, '/');
134
+ return `bash "${wrapper}" "${hookAbs}"`;
135
+ }
136
+ return `bash ./hooks/_run-hook.sh ${hookFilename}`;
137
+ }
138
+
139
+ // Modo inline (default, compatible con instalaciones previas)
140
+ const prefix = prefijoPathNode();
141
+ if (esGlobal) {
142
+ const rutaAbsoluta = path.join(hooksDir, hookFilename).replace(/\\/g, '/');
143
+ return `${prefix}node -e "try{require('${rutaAbsoluta}')}catch(e){if(e.code!=='MODULE_NOT_FOUND')throw e}"`;
144
+ }
145
+ return `${prefix}node -e "try{require('./hooks/${hookFilename}')}catch(e){if(e.code!=='MODULE_NOT_FOUND')throw e}"`;
146
+ }
147
+
148
+ /**
149
+ * Registra los hooks SWL en settings.json del runtime.
150
+ * Preserva hooks existentes no-SWL. Reemplaza hooks SWL previos.
151
+ *
152
+ * @param {object} opciones
153
+ * @param {string} opciones.settingsPath - Ruta al settings.json
154
+ * @param {string} opciones.hooksDir - Directorio donde están los hooks
155
+ * @param {boolean} opciones.esGlobal - Si es instalación global
156
+ * @param {string[]} opciones.hookFiles - Lista de archivos de hooks instalados
157
+ * @returns {{ registrados: number, preservados: number }}
158
+ */
159
+ function registrarHooks(opciones) {
160
+ const { settingsPath, hooksDir, esGlobal, hookFiles } = opciones;
161
+ const hooksConfig = cargarHooksConfig();
162
+ const settings = leerSettings(settingsPath);
163
+
164
+ // Inicializar sección hooks si no existe
165
+ if (!settings.hooks) {
166
+ settings.hooks = {};
167
+ }
168
+
169
+ let registrados = 0;
170
+ let preservados = 0;
171
+
172
+ // Agrupar hooks SWL por evento
173
+ const hooksPorEvento = {};
174
+ for (const filename of hookFiles) {
175
+ const config = hooksConfig[filename];
176
+ if (!config) continue;
177
+
178
+ const evento = config.event;
179
+ if (!hooksPorEvento[evento]) {
180
+ hooksPorEvento[evento] = [];
181
+ }
182
+
183
+ hooksPorEvento[evento].push({
184
+ matcher: config.matcher || '',
185
+ hooks: [{
186
+ type: 'command',
187
+ command: generarComando(filename, hooksDir, esGlobal),
188
+ }],
189
+ });
190
+ registrados++;
191
+ }
192
+
193
+ // Para cada tipo de evento, preservar hooks no-SWL y agregar los SWL
194
+ const todosEventos = new Set(['PreToolUse', 'PostToolUse']);
195
+ Object.keys(hooksPorEvento).forEach(e => todosEventos.add(e));
196
+ for (const evento of todosEventos) {
197
+ const existentes = settings.hooks[evento] || [];
198
+ const noSWL = existentes.filter(entry => !esHookSWL(entry));
199
+ preservados += noSWL.length;
200
+
201
+ const swlNuevos = hooksPorEvento[evento] || [];
202
+
203
+ // Limpiar entradas con matcher vacío (usar "" para match-all)
204
+ const swlLimpios = swlNuevos.map(h => {
205
+ const entry = { matcher: h.matcher || '' };
206
+ entry.hooks = h.hooks;
207
+ return entry;
208
+ });
209
+
210
+ const combinados = [...noSWL, ...swlLimpios];
211
+
212
+ if (combinados.length > 0) {
213
+ settings.hooks[evento] = combinados;
214
+ } else {
215
+ delete settings.hooks[evento];
216
+ }
217
+ }
218
+
219
+ // Limpiar sección hooks si quedó vacía
220
+ if (Object.keys(settings.hooks).length === 0) {
221
+ delete settings.hooks;
222
+ }
223
+
224
+ escribirSettings(settingsPath, settings);
225
+
226
+ return { registrados, preservados };
227
+ }
228
+
229
+ /**
230
+ * Desregistra todos los hooks SWL de settings.json.
231
+ * Preserva hooks no-SWL intactos.
232
+ *
233
+ * @param {string} settingsPath - Ruta al settings.json
234
+ * @returns {{ eliminados: number, preservados: number }}
235
+ */
236
+ function desregistrarHooks(settingsPath) {
237
+ const settings = leerSettings(settingsPath);
238
+
239
+ if (!settings.hooks) {
240
+ return { eliminados: 0, preservados: 0 };
241
+ }
242
+
243
+ let eliminados = 0;
244
+ let preservados = 0;
245
+
246
+ // Iterar TODOS los eventos presentes en settings.json (no solo PreToolUse/PostToolUse)
247
+ for (const evento of Object.keys(settings.hooks)) {
248
+ const existentes = settings.hooks[evento] || [];
249
+ if (!Array.isArray(existentes)) continue;
250
+ const noSWL = [];
251
+
252
+ for (const entry of existentes) {
253
+ if (esHookSWL(entry)) {
254
+ eliminados++;
255
+ } else {
256
+ noSWL.push(entry);
257
+ preservados++;
258
+ }
259
+ }
260
+
261
+ if (noSWL.length > 0) {
262
+ settings.hooks[evento] = noSWL;
263
+ } else {
264
+ delete settings.hooks[evento];
265
+ }
266
+ }
267
+
268
+ // Limpiar sección hooks si quedó vacía
269
+ if (Object.keys(settings.hooks).length === 0) {
270
+ delete settings.hooks;
271
+ }
272
+
273
+ escribirSettings(settingsPath, settings);
274
+
275
+ return { eliminados, preservados };
276
+ }
277
+
278
+ /**
279
+ * Verifica que los hooks SWL estén correctamente registrados en settings.json.
280
+ *
281
+ * @param {string} settingsPath - Ruta al settings.json
282
+ * @param {string[]} hookFiles - Lista de archivos de hooks que deberían estar registrados
283
+ * @returns {{ ok: boolean, registrados: string[], faltantes: string[], incorrectos: string[] }}
284
+ */
285
+ function verificarHooks(settingsPath, hookFiles) {
286
+ const hooksConfig = cargarHooksConfig();
287
+ const settings = leerSettings(settingsPath);
288
+
289
+ const registrados = [];
290
+ const faltantes = [];
291
+ const incorrectos = [];
292
+
293
+ for (const filename of hookFiles) {
294
+ const config = hooksConfig[filename];
295
+ if (!config) {
296
+ faltantes.push(filename);
297
+ continue;
298
+ }
299
+
300
+ const evento = config.event;
301
+ const entradas = (settings.hooks && settings.hooks[evento]) || [];
302
+
303
+ // Buscar si existe un hook SWL que referencie este archivo
304
+ const encontrado = entradas.find(entry => {
305
+ const hooksArr = entry.hooks || [];
306
+ return hooksArr.some(h => (h.command || '').includes(filename));
307
+ });
308
+
309
+ if (!encontrado) {
310
+ faltantes.push(filename);
311
+ continue;
312
+ }
313
+
314
+ // Verificar matcher correcto
315
+ const matcherEsperado = config.matcher || '';
316
+ const matcherActual = encontrado.matcher || '';
317
+
318
+ if (matcherEsperado !== matcherActual) {
319
+ incorrectos.push(`${filename}: matcher esperado="${matcherEsperado || '(ninguno)'}" actual="${matcherActual || '(ninguno)'}"`);
320
+ continue;
321
+ }
322
+
323
+ // Verificar que todos los hooks tienen type: "command"
324
+ const hooksSinType = (encontrado.hooks || []).filter(h => h.type !== 'command');
325
+ if (hooksSinType.length > 0) {
326
+ incorrectos.push(`${filename}: falta "type": "command" en hook entry (causa Settings Error en Claude Code)`);
327
+ continue;
328
+ }
329
+
330
+ registrados.push(filename);
331
+ }
332
+
333
+ return {
334
+ ok: faltantes.length === 0 && incorrectos.length === 0,
335
+ registrados,
336
+ faltantes,
337
+ incorrectos,
338
+ };
339
+ }
340
+
341
+ /**
342
+ * Repara hooks SWL en settings.json que no tienen el campo "type": "command".
343
+ * Claude Code requiere este campo; sin él, genera "Settings Error: type: Invalid input".
344
+ *
345
+ * @param {string} settingsPath - Ruta al settings.json
346
+ * @returns {{ reparados: number }}
347
+ */
348
+ function repararHooks(settingsPath) {
349
+ const settings = leerSettings(settingsPath);
350
+
351
+ if (!settings.hooks) {
352
+ return { reparados: 0 };
353
+ }
354
+
355
+ let reparados = 0;
356
+
357
+ // Iterar TODOS los eventos presentes (no solo PreToolUse/PostToolUse)
358
+ for (const evento of Object.keys(settings.hooks)) {
359
+ const entradas = settings.hooks[evento] || [];
360
+ if (!Array.isArray(entradas)) continue;
361
+
362
+ for (const entry of entradas) {
363
+ if (!esHookSWL(entry)) continue;
364
+
365
+ const hooksArr = entry.hooks || [];
366
+ for (const h of hooksArr) {
367
+ if (h.command && h.type !== 'command') {
368
+ h.type = 'command';
369
+ reparados++;
370
+ }
371
+ }
372
+ }
373
+ }
374
+
375
+ if (reparados > 0) {
376
+ escribirSettings(settingsPath, settings);
377
+ }
378
+
379
+ return { reparados };
380
+ }
381
+
382
+ /**
383
+ * Agrega hooks SWL al settings.json GLOBAL (~/.claude/settings.json) sin
384
+ * remover hooks no-SWL ni duplicar entries SWL que ya existan.
385
+ *
386
+ * EXCEPCIÓN DOCUMENTADA (ADR-0009): Esta función es la única excepción a la
387
+ * regla "SWL solo registra hooks a nivel proyecto". Solo debe invocarse bajo
388
+ * opt-in explícito del usuario (instalador interactivo o /swl:notificaciones init).
389
+ *
390
+ * @param {string} settingsPath - Ruta al settings.json global.
391
+ * @param {Array<{ evento: string, matcher: string, archivo: string, hooksDir?: string|null }>} hookEntries
392
+ * Lista de hooks a agregar. Cada entry describe el evento, matcher, archivo y
393
+ * directorio de hooks instalados para construir el comando.
394
+ * @returns {{ agregados: number, preservados: number, error?: string }}
395
+ */
396
+ function mergeHooksGlobales(settingsPath, hookEntries) {
397
+ // Validar que el archivo es JSON parseable antes de modificar
398
+ let settings;
399
+ try {
400
+ settings = leerSettings(settingsPath);
401
+ } catch (err) {
402
+ return { agregados: 0, preservados: 0, error: `No se puede leer settings.json: ${err.message}` };
403
+ }
404
+
405
+ // Verificar que el JSON existente (si existe el archivo) es válido
406
+ if (fs.existsSync(settingsPath)) {
407
+ try {
408
+ JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
409
+ } catch (err) {
410
+ return {
411
+ agregados: 0,
412
+ preservados: 0,
413
+ error: `settings.json tiene JSON inválido — abortando merge para proteger el archivo. Error: ${err.message}`,
414
+ };
415
+ }
416
+ }
417
+
418
+ // Crear backup antes de cualquier modificación
419
+ const ts = Date.now();
420
+ const backup = `${settingsPath}.swl-backup-${ts}`;
421
+ if (fs.existsSync(settingsPath)) {
422
+ try {
423
+ fs.copyFileSync(settingsPath, backup);
424
+ } catch (err) {
425
+ return { agregados: 0, preservados: 0, error: `No se pudo crear backup: ${err.message}` };
426
+ }
427
+ }
428
+
429
+ if (!settings.hooks) settings.hooks = {};
430
+
431
+ let agregados = 0;
432
+ let preservados = 0;
433
+ let migrados = 0;
434
+
435
+ /**
436
+ * REM-C helper: detecta si dos comandos corresponden al mismo hook
437
+ * (mismo nombre de archivo .js) independientemente de si la ruta es
438
+ * relativa o absoluta.
439
+ *
440
+ * Ejemplos que deben coincidir:
441
+ * "node hooks/notificacion-telegram.js"
442
+ * 'node "C:/Users/.../.claude/hooks/notificacion-telegram.js"'
443
+ * 'node "/home/user/.claude/hooks/notificacion-telegram.js"'
444
+ *
445
+ * @param {string} commandA
446
+ * @param {string} archivoRef - Nombre de archivo simple, ej: "notificacion-telegram.js"
447
+ * @returns {boolean}
448
+ */
449
+ function _mismoArchivo(commandA, archivoRef) {
450
+ // Extraer solo el nombre de archivo del comando (parte después del último /)
451
+ const match = commandA.match(/([a-z0-9-]+\.js)["']?\s*$/i);
452
+ if (!match) return false;
453
+ return match[1] === path.basename(archivoRef);
454
+ }
455
+
456
+ for (const entry of hookEntries) {
457
+ const { evento, matcher, archivo, hooksDir } = entry;
458
+
459
+ if (!settings.hooks[evento]) {
460
+ settings.hooks[evento] = [];
461
+ }
462
+
463
+ const existentes = settings.hooks[evento];
464
+
465
+ // Contar hooks no-SWL que se preservan
466
+ const noSWL = existentes.filter(e => !esHookSWL(e));
467
+ preservados += noSWL.length;
468
+
469
+ // REM-B: siempre usar ruta absoluta — si no hay hooksDir es error de configuración
470
+ // (quien llama debe siempre proporcionar hooksDir con HOOKS_GLOBAL_DIR)
471
+ const comandoNuevo = hooksDir
472
+ ? `node "${path.join(hooksDir, archivo).replace(/\\/g, '/')}"`
473
+ : `node hooks/${archivo}`; // fallback de emergencia — nunca debería usarse
474
+
475
+ // REM-C: buscar entry existente con mismo archivo (puede tener ruta relativa/incorrecta)
476
+ const idxExistente = existentes.findIndex(e =>
477
+ (e.hooks || []).some(h => h.command && _mismoArchivo(h.command, archivo))
478
+ );
479
+
480
+ if (idxExistente === -1) {
481
+ // No existe — agregar
482
+ settings.hooks[evento].push({
483
+ matcher: matcher || '',
484
+ hooks: [{ type: 'command', command: comandoNuevo }],
485
+ });
486
+ agregados++;
487
+ } else {
488
+ // Existe — verificar si necesita migración de ruta relativa → absoluta
489
+ const entryExistente = existentes[idxExistente];
490
+ const commandActual = (entryExistente.hooks || [])[0]?.command || '';
491
+ const esRelativo = /^node\s+hooks\//.test(commandActual.trim());
492
+ const esIncorrecto = commandActual !== comandoNuevo;
493
+
494
+ if (esRelativo || esIncorrecto) {
495
+ // REM-C: migrar en lugar de duplicar
496
+ existentes[idxExistente] = {
497
+ matcher: matcher || entryExistente.matcher || '',
498
+ hooks: [{ type: 'command', command: comandoNuevo }],
499
+ };
500
+ migrados++;
501
+ }
502
+ // Si ya tiene el comando correcto: no-op (idempotente)
503
+ }
504
+ }
505
+
506
+ // Serializar y validar antes de escribir
507
+ let contenidoNuevo;
508
+ try {
509
+ contenidoNuevo = JSON.stringify(settings, null, 2) + '\n';
510
+ JSON.parse(contenidoNuevo); // validación pre-escritura
511
+ } catch (err) {
512
+ return {
513
+ agregados: 0,
514
+ preservados: 0,
515
+ error: `JSON inválido al serializar settings — operación abortada: ${err.message}`,
516
+ };
517
+ }
518
+
519
+ // Escritura atómica
520
+ try {
521
+ const atomicWrite = require('../../hooks/lib/atomic-write');
522
+ atomicWrite.atomicWriteSync(settingsPath, contenidoNuevo);
523
+ } catch (err) {
524
+ // Intentar restaurar backup
525
+ try {
526
+ if (fs.existsSync(backup)) {
527
+ fs.copyFileSync(backup, settingsPath);
528
+ }
529
+ } catch (_) { /* no se pudo restaurar — dejar backup en su lugar */ }
530
+ return { agregados: 0, preservados: 0, error: `Error escribiendo settings.json: ${err.message}` };
531
+ }
532
+
533
+ // Validación post-escritura
534
+ try {
535
+ const escritoFinal = fs.readFileSync(settingsPath, 'utf8');
536
+ JSON.parse(escritoFinal);
537
+ } catch (err) {
538
+ // Rollback desde backup
539
+ try {
540
+ if (fs.existsSync(backup)) {
541
+ fs.copyFileSync(backup, settingsPath);
542
+ console.error(` [notificaciones] Rollback desde backup ${backup} (JSON inválido post-escritura).`);
543
+ }
544
+ } catch (_) { /* no se pudo restaurar */ }
545
+ return {
546
+ agregados: 0,
547
+ preservados: 0,
548
+ error: `Validación post-escritura falló — settings restaurado desde backup: ${err.message}`,
549
+ };
550
+ }
551
+
552
+ return { agregados, preservados, migrados };
553
+ }
554
+
555
+ /**
556
+ * Quita todas las entries SWL del settings.json GLOBAL preservando hooks ajenos.
557
+ *
558
+ * EXCEPCIÓN DOCUMENTADA (ADR-0009): Inversa de mergeHooksGlobales.
559
+ * Solo debe invocarse desde /swl:notificaciones disable.
560
+ *
561
+ * @param {string} settingsPath
562
+ * @returns {{ eliminados: number, preservados: number, error?: string }}
563
+ */
564
+ function desregistrarHooksGlobales(settingsPath) {
565
+ if (!fs.existsSync(settingsPath)) {
566
+ return { eliminados: 0, preservados: 0 };
567
+ }
568
+
569
+ let settings;
570
+ try {
571
+ settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
572
+ } catch (err) {
573
+ return { eliminados: 0, preservados: 0, error: `JSON inválido en settings.json: ${err.message}` };
574
+ }
575
+
576
+ if (!settings.hooks) {
577
+ return { eliminados: 0, preservados: 0 };
578
+ }
579
+
580
+ // Backup antes de modificar
581
+ const backup = `${settingsPath}.swl-backup-${Date.now()}`;
582
+ try {
583
+ fs.copyFileSync(settingsPath, backup);
584
+ } catch (err) {
585
+ return { eliminados: 0, preservados: 0, error: `No se pudo crear backup: ${err.message}` };
586
+ }
587
+
588
+ let eliminados = 0;
589
+ let preservados = 0;
590
+
591
+ for (const evento of Object.keys(settings.hooks)) {
592
+ const existentes = settings.hooks[evento] || [];
593
+ if (!Array.isArray(existentes)) continue;
594
+
595
+ const noSWL = [];
596
+ for (const entry of existentes) {
597
+ if (esHookSWL(entry)) {
598
+ eliminados++;
599
+ } else {
600
+ noSWL.push(entry);
601
+ preservados++;
602
+ }
603
+ }
604
+
605
+ if (noSWL.length > 0) {
606
+ settings.hooks[evento] = noSWL;
607
+ } else {
608
+ delete settings.hooks[evento];
609
+ }
610
+ }
611
+
612
+ if (Object.keys(settings.hooks).length === 0) {
613
+ delete settings.hooks;
614
+ }
615
+
616
+ // Escritura atómica + validación post-escritura
617
+ try {
618
+ const contenido = JSON.stringify(settings, null, 2) + '\n';
619
+ JSON.parse(contenido); // validación pre-escritura
620
+ const atomicWrite = require('../../hooks/lib/atomic-write');
621
+ atomicWrite.atomicWriteSync(settingsPath, contenido);
622
+ } catch (err) {
623
+ try {
624
+ if (fs.existsSync(backup)) fs.copyFileSync(backup, settingsPath);
625
+ } catch (_) { /* no se pudo restaurar */ }
626
+ return { eliminados: 0, preservados: 0, error: `Error al escribir settings.json: ${err.message}` };
627
+ }
628
+
629
+ return { eliminados, preservados };
630
+ }
631
+
632
+ /**
633
+ * Optimizaciones de settings.json recomendadas por SWL.
634
+ * Basadas en auditoría de 858 sesiones / 18,903 turnos.
635
+ *
636
+ * - ENABLE_TOOL_SEARCH: carga schemas de herramientas bajo demanda en vez de
637
+ * todos al inicio. Reduce ~20,000 tokens/turno de definiciones no usadas.
638
+ * - showThinkingSummaries: hace visible cuando Claude reduce profundidad de
639
+ * razonamiento, permitiendo detectar regresiones de calidad.
640
+ *
641
+ * Estas configuraciones se aplican solo a nivel de PROYECTO (.claude/settings.json),
642
+ * no a nivel global (~/.claude/settings.json), para no afectar otros proyectos.
643
+ */
644
+ const OPTIMIZACIONES_SWL = {
645
+ env: {
646
+ ENABLE_TOOL_SEARCH: 'true',
647
+ },
648
+ preferences: {
649
+ showThinkingSummaries: true,
650
+ },
651
+ };
652
+
653
+ /**
654
+ * Registra las optimizaciones SWL en settings.json del proyecto.
655
+ * No sobrescribe valores existentes del usuario — solo agrega los faltantes.
656
+ *
657
+ * @param {string} settingsPath - Ruta al settings.json
658
+ * @returns {{ aplicadas: number, yaExistentes: number }}
659
+ */
660
+ function registrarOptimizaciones(settingsPath) {
661
+ const settings = leerSettings(settingsPath);
662
+ let aplicadas = 0;
663
+ let yaExistentes = 0;
664
+
665
+ for (const [seccion, valores] of Object.entries(OPTIMIZACIONES_SWL)) {
666
+ if (!settings[seccion]) {
667
+ settings[seccion] = {};
668
+ }
669
+
670
+ for (const [clave, valor] of Object.entries(valores)) {
671
+ if (settings[seccion][clave] === undefined) {
672
+ settings[seccion][clave] = valor;
673
+ aplicadas++;
674
+ } else {
675
+ yaExistentes++;
676
+ }
677
+ }
678
+ }
679
+
680
+ if (aplicadas > 0) {
681
+ escribirSettings(settingsPath, settings);
682
+ }
683
+
684
+ return { aplicadas, yaExistentes };
685
+ }
686
+
687
+ /**
688
+ * Valida la estructura del settings.json: secciones esperadas, tipos correctos,
689
+ * hooks con formato válido. No valida contenido semántico, solo estructura.
690
+ *
691
+ * @param {string} settingsPath
692
+ * @returns {{ ok: boolean, problemas: string[] }}
693
+ */
694
+ function validarEstructuraSettings(settingsPath) {
695
+ const settings = leerSettings(settingsPath);
696
+ const problemas = [];
697
+
698
+ // Validar sección hooks
699
+ if (settings.hooks) {
700
+ const eventosValidos = new Set([
701
+ 'PreToolUse', 'PostToolUse', 'UserPromptSubmit', 'Stop',
702
+ 'SubagentStart', 'SubagentStop', 'PreCompact', 'PostCompact',
703
+ 'Notification', 'SessionStart', 'TaskCompleted',
704
+ ]);
705
+
706
+ for (const [evento, entradas] of Object.entries(settings.hooks)) {
707
+ if (!eventosValidos.has(evento)) {
708
+ problemas.push(`hooks.${evento}: evento no reconocido`);
709
+ }
710
+ if (!Array.isArray(entradas)) {
711
+ problemas.push(`hooks.${evento}: debe ser un array de matchers`);
712
+ continue;
713
+ }
714
+ for (let i = 0; i < entradas.length; i++) {
715
+ const entrada = entradas[i];
716
+ if (typeof entrada.matcher !== 'string' && entrada.matcher !== undefined) {
717
+ problemas.push(`hooks.${evento}[${i}].matcher: debe ser string`);
718
+ }
719
+ if (!Array.isArray(entrada.hooks)) {
720
+ problemas.push(`hooks.${evento}[${i}].hooks: debe ser array de hooks`);
721
+ continue;
722
+ }
723
+ for (let j = 0; j < entrada.hooks.length; j++) {
724
+ const hook = entrada.hooks[j];
725
+ const tiposValidos = ['command', 'prompt', 'agent', 'http'];
726
+ if (!tiposValidos.includes(hook.type)) {
727
+ problemas.push(`hooks.${evento}[${i}].hooks[${j}].type: "${hook.type}" no es válido (command|prompt|agent|http)`);
728
+ }
729
+ if (hook.type === 'command' && !hook.command) {
730
+ problemas.push(`hooks.${evento}[${i}].hooks[${j}]: hook tipo command sin campo command`);
731
+ }
732
+ }
733
+ }
734
+ }
735
+ }
736
+
737
+ // Validar sección env
738
+ if (settings.env && typeof settings.env !== 'object') {
739
+ problemas.push('env: debe ser un objeto { clave: valor }');
740
+ }
741
+
742
+ // Validar sección preferences
743
+ if (settings.preferences && typeof settings.preferences !== 'object') {
744
+ problemas.push('preferences: debe ser un objeto');
745
+ }
746
+
747
+ return { ok: problemas.length === 0, problemas };
748
+ }
749
+
750
+ /**
751
+ * Verifica que las optimizaciones SWL estén presentes en settings.json.
752
+ *
753
+ * @param {string} settingsPath
754
+ * @returns {{ ok: boolean, faltantes: string[] }}
755
+ */
756
+ function verificarOptimizaciones(settingsPath) {
757
+ const settings = leerSettings(settingsPath);
758
+ const faltantes = [];
759
+
760
+ for (const [seccion, valores] of Object.entries(OPTIMIZACIONES_SWL)) {
761
+ for (const [clave, valor] of Object.entries(valores)) {
762
+ if (!settings[seccion] || settings[seccion][clave] === undefined) {
763
+ faltantes.push(`${seccion}.${clave}`);
764
+ }
765
+ }
766
+ }
767
+
768
+ return { ok: faltantes.length === 0, faltantes };
769
+ }
770
+
771
+ module.exports = {
772
+ cargarHooksConfig,
773
+ leerSettings,
774
+ escribirSettings,
775
+ rutaSettings,
776
+ registrarHooks,
777
+ desregistrarHooks,
778
+ verificarHooks,
779
+ repararHooks,
780
+ esHookSWL,
781
+ registrarOptimizaciones,
782
+ verificarOptimizaciones,
783
+ validarEstructuraSettings,
784
+ generarComando,
785
+ OPTIMIZACIONES_SWL,
786
+ // ADR-0009: excepción opt-in para hooks globales de notificaciones Telegram
787
+ mergeHooksGlobales,
788
+ desregistrarHooksGlobales,
789
+ };