@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,278 @@
1
+ ---
2
+ name: kotlin-compose
3
+ description: >
4
+ Jetpack Compose avanzado: state hoisting, remember vs rememberSaveable,
5
+ derivedStateOf, Navigation Compose con type-safe routes, LazyColumn con keys,
6
+ side effects, animaciones y optimización de recomposición con @Stable.
7
+ Cargar cuando se implementen pantallas Compose, se optimice recomposición,
8
+ o se configure Navigation Compose en proyectos Android.
9
+ version: "1.0.0"
10
+ herramientasPermitidas: [Read, Glob, Grep]
11
+ exclusiones:
12
+ - "No cargar para lógica de negocio, ViewModels o coroutines fuera de Compose — para eso cargar `kotlin-experto`."
13
+ - "No cargar para escribir tests de UI con ComposeTestRule — para testing cargar `kotlin-testing`."
14
+ - "No cargar para errores de compilación Kotlin o Compose — para build errors cargar `build-errors-kotlin`."
15
+ - "No cargar para SwiftUI o React Native — Compose es específico de Android/Kotlin; para iOS cargar `swift-patrones`."
16
+ evolvable: true # default para skill estandar
17
+ ---
18
+ # Kotlin Compose — State, Navigation y Performance
19
+
20
+ ## Cuándo NO cargar
21
+
22
+ - La pregunta es sobre lógica de negocio, ViewModels, coroutines o Hilt fuera de Compose — para eso cargar `kotlin-experto`.
23
+ - La tarea es escribir tests de UI con `ComposeTestRule` — para testing cargar `kotlin-testing`.
24
+ - Los errores son de compilación Kotlin o Compose (generación de código de Hilt, errores de BOM) — cargar `build-errors-kotlin`.
25
+ - La UI es SwiftUI, React Native o Flutter — Compose es específico de Android/Kotlin.
26
+
27
+ ## State Hoisting — Regla fundamental
28
+
29
+ El estado debe vivir en el nivel más bajo que lo necesita, pero no más abajo.
30
+ Hoistear hacia arriba cuando más de un composable lo necesita.
31
+
32
+ ```kotlin
33
+ // MAL — estado interno, no testeable, no reutilizable
34
+ @Composable
35
+ fun BuscadorFacturas() {
36
+ var query by remember { mutableStateOf("") }
37
+ // query solo visible aquí
38
+ }
39
+
40
+ // BIEN — estado hoisted, el llamador controla
41
+ @Composable
42
+ fun BuscadorFacturas(
43
+ query: String,
44
+ onQueryChange: (String) -> Unit,
45
+ modifier: Modifier = Modifier
46
+ ) {
47
+ OutlinedTextField(
48
+ value = query,
49
+ onValueChange = onQueryChange,
50
+ modifier = modifier
51
+ )
52
+ }
53
+
54
+ // Llamador (o ViewModel) posee el estado
55
+ @Composable
56
+ fun FacturasScreen(viewModel: FacturasViewModel = hiltViewModel()) {
57
+ val uiState by viewModel.uiState.collectAsStateWithLifecycle()
58
+ BuscadorFacturas(
59
+ query = uiState.query,
60
+ onQueryChange = viewModel::onQueryChange
61
+ )
62
+ }
63
+ ```
64
+
65
+ ---
66
+
67
+ ## remember vs rememberSaveable
68
+
69
+ ```kotlin
70
+ // remember — sobrevive recomposición, NO sobrevive rotación de pantalla
71
+ var expandido by remember { mutableStateOf(false) }
72
+
73
+ // rememberSaveable — sobrevive recomposición Y rotación
74
+ // Usar para estado de UI efímero que el usuario espera que persista
75
+ var seleccionado by rememberSaveable { mutableStateOf("") }
76
+
77
+ // rememberSaveable con Saver personalizado para objetos complejos
78
+ var filtros by rememberSaveable(stateSaver = FiltrosSaver) {
79
+ mutableStateOf(FiltrosFactura())
80
+ }
81
+
82
+ val FiltrosSaver = Saver<FiltrosFactura, Bundle>(
83
+ save = { filtros ->
84
+ Bundle().apply {
85
+ putString("estatus", filtros.estatus)
86
+ putString("desde", filtros.desde?.toString())
87
+ }
88
+ },
89
+ restore = { bundle ->
90
+ FiltrosFactura(
91
+ estatus = bundle.getString("estatus"),
92
+ desde = bundle.getString("desde")?.let { LocalDate.parse(it) }
93
+ )
94
+ }
95
+ )
96
+ ```
97
+
98
+ ---
99
+
100
+ ## derivedStateOf — Computaciones derivadas
101
+
102
+ ```kotlin
103
+ // derivedStateOf solo recompone cuando el RESULTADO cambia,
104
+ // no cuando la fuente cambia. Ideal para filtros y búsquedas.
105
+ @Composable
106
+ fun FacturasList(facturas: List<Factura>, query: String) {
107
+ // Sin derivedStateOf: recompone en CADA keystroke aunque el resultado sea igual
108
+ // Con derivedStateOf: recompone solo cuando la lista filtrada cambia
109
+ val facturasFiltradas by remember(facturas) {
110
+ derivedStateOf {
111
+ if (query.isBlank()) facturas
112
+ else facturas.filter {
113
+ it.folio.contains(query, ignoreCase = true) ||
114
+ it.cliente.contains(query, ignoreCase = true)
115
+ }
116
+ }
117
+ }
118
+
119
+ LazyColumn {
120
+ items(facturasFiltradas, key = { it.id }) { factura ->
121
+ FacturaItem(factura)
122
+ }
123
+ }
124
+ }
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Navigation Compose — Type-safe Routes
130
+
131
+ ```kotlin
132
+ // Definir rutas como objetos serializables (Navigation 2.8+)
133
+ @Serializable object RutaFacturas
134
+ @Serializable data class RutaDetalleFactura(val id: String)
135
+ @Serializable object RutaCrearFactura
136
+
137
+ @Composable
138
+ fun AppNavGraph(navController: NavHostController = rememberNavController()) {
139
+ NavHost(navController, startDestination = RutaFacturas) {
140
+ composable<RutaFacturas> {
141
+ FacturasScreen(
142
+ onFacturaClick = { id ->
143
+ navController.navigate(RutaDetalleFactura(id))
144
+ },
145
+ onCrearClick = { navController.navigate(RutaCrearFactura) }
146
+ )
147
+ }
148
+ composable<RutaDetalleFactura> { backStackEntry ->
149
+ val ruta = backStackEntry.toRoute<RutaDetalleFactura>()
150
+ DetalleFacturaScreen(facturaId = ruta.id)
151
+ }
152
+ composable<RutaCrearFactura> {
153
+ CrearFacturaScreen(onGuardado = { navController.popBackStack() })
154
+ }
155
+ }
156
+ }
157
+ ```
158
+
159
+ ---
160
+
161
+ ## LazyColumn — Keys y Performance
162
+
163
+ ```kotlin
164
+ // SIEMPRE proveer key estable para evitar recomposición completa
165
+ LazyColumn(
166
+ contentPadding = PaddingValues(16.dp),
167
+ verticalArrangement = Arrangement.spacedBy(8.dp)
168
+ ) {
169
+ // key debe ser estable y único — usar el ID del dominio
170
+ items(facturas, key = { factura -> factura.id }) { factura ->
171
+ FacturaItem(
172
+ factura = factura,
173
+ modifier = Modifier.animateItem() // animación de inserción/eliminación
174
+ )
175
+ }
176
+
177
+ // Separador sin key — usar índice si no hay ID
178
+ itemsIndexed(secciones, key = { index, _ -> "seccion_$index" }) { _, seccion ->
179
+ SeccionHeader(seccion)
180
+ }
181
+ }
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Side Effects
187
+
188
+ ```kotlin
189
+ @Composable
190
+ fun FacturasScreen(viewModel: FacturasViewModel = hiltViewModel()) {
191
+ val contexto = LocalContext.current
192
+
193
+ // LaunchedEffect — efecto async ligado al ciclo de vida del composable
194
+ // Se re-ejecuta cuando cambia la key
195
+ LaunchedEffect(Unit) {
196
+ viewModel.events.collect { evento ->
197
+ when (evento) {
198
+ is FacturasEvent.FacturaCreada ->
199
+ Toast.makeText(contexto, "Factura creada", Toast.LENGTH_SHORT).show()
200
+ }
201
+ }
202
+ }
203
+
204
+ // DisposableEffect — para limpiar recursos (listeners, suscripciones)
205
+ val lifecycleOwner = LocalLifecycleOwner.current
206
+ DisposableEffect(lifecycleOwner) {
207
+ val observer = LifecycleEventObserver { _, event ->
208
+ if (event == Lifecycle.Event.ON_RESUME) viewModel.recargar()
209
+ }
210
+ lifecycleOwner.lifecycle.addObserver(observer)
211
+ onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
212
+ }
213
+
214
+ // SideEffect — sincronizar estado a código no-Compose
215
+ // Se ejecuta en CADA recomposición exitosa
216
+ SideEffect {
217
+ analytics.setPantallaActual("facturas")
218
+ }
219
+ }
220
+ ```
221
+
222
+ ---
223
+
224
+ Para animaciones (AnimatedVisibility, animateContentSize, updateTransition) y
225
+ optimización de performance con @Stable, ImmutableList y lambdas estables, ver
226
+ [recursos/animaciones-performance.md](recursos/animaciones-performance.md).
227
+
228
+ ---
229
+
230
+ ## Anti-patrones
231
+
232
+ ### Leer State en lambda sin capturar correctamente
233
+
234
+ ```kotlin
235
+ // MAL — captura el valor en el momento de creación del composable
236
+ val contador by remember { mutableStateOf(0) }
237
+ Button(onClick = { println(contador) }) // siempre imprime el valor inicial
238
+
239
+ // BIEN — leer el estado dentro de la lambda (se evalúa al click)
240
+ val contadorState = remember { mutableStateOf(0) }
241
+ Button(onClick = { println(contadorState.value) })
242
+ ```
243
+
244
+ ### Función en lugar de computed state
245
+
246
+ ```kotlin
247
+ // MAL — función recalcula y causa recomposición en cada frame
248
+ @Composable
249
+ fun Pantalla(facturas: List<Factura>) {
250
+ val total = facturas.sumOf { it.total } // recalcula siempre
251
+ Text("Total: $total")
252
+ }
253
+
254
+ // BIEN — derivedStateOf o remember con key
255
+ val total by remember(facturas) { derivedStateOf { facturas.sumOf { it.total } } }
256
+ ```
257
+
258
+ ---
259
+
260
+ ## Gotchas / Errores comunes no obvios
261
+
262
+ **`remember { derivedStateOf { ... } }` sin `remember` en la derivación no se recomputa**: `derivedStateOf { lista.filter { it.activo } }` sin envolver en `remember` crea un nuevo objeto `State` en cada recomposición, anulando la optimización. Fix: siempre combinar: `val filtrado by remember { derivedStateOf { lista.filter { it.activo } } }`.
263
+
264
+ **`LazyColumn` sin `key` causa que los composables se recreen en lugar de reordenarse**: al cambiar el orden de los items, Compose reutiliza los composables por posición, no por identidad — los estados internos de cada item (scroll position, animation state) se mezclan. Fix: siempre especificar `key = { item -> item.id }` en `items()` de `LazyColumn`/`LazyRow`.
265
+
266
+ **`SideEffect` se ejecuta en cada recomposición, no una sola vez**: `SideEffect { SystemUiController.setStatusBarColor(color) }` cambia el color en cada recomposición del composable, no solo al montar. Causa: `SideEffect` no tiene ciclo de vida — ejecuta en cada render exitoso. Fix: usar `LaunchedEffect(key)` con una clave estable si el efecto solo debe ejecutarse cuando cambia un valor específico.
267
+
268
+ **`@Stable` en una clase con campos `var` no previene recomposiciones**: marcar una clase como `@Stable` le dice a Compose que las comparaciones de igualdad son confiables, pero si la clase tiene `var` mutables que cambian sin notificar a Compose (no usando `mutableStateOf`), las recomposiciones no se disparan cuando deberían y la UI queda desactualizada. Fix: usar `@Stable` solo en clases verdaderamente inmutables o en clases que usan `State` de Compose para sus campos mutables.
269
+
270
+ ## Checklist Compose
271
+
272
+ - [ ] Estado hoisted al nivel mínimo necesario
273
+ - [ ] rememberSaveable para estado que debe sobrevivir rotación
274
+ - [ ] derivedStateOf para computaciones sobre listas o búsquedas
275
+ - [ ] LazyColumn siempre con key = { item.id }
276
+ - [ ] Lambdas en items de LazyColumn con remember para evitar recreación
277
+ - [ ] @Stable o ImmutableList para listas en parámetros de composable
278
+ - [ ] Navigation usa type-safe routes (objetos @Serializable)
@@ -0,0 +1,93 @@
1
+ # Compose — Animaciones y Performance
2
+
3
+ ## Animaciones
4
+
5
+ ```kotlin
6
+ // AnimatedVisibility — mostrar/ocultar con transición
7
+ AnimatedVisibility(
8
+ visible = mostrarFiltros,
9
+ enter = slideInVertically() + fadeIn(),
10
+ exit = slideOutVertically() + fadeOut()
11
+ ) {
12
+ PanelFiltros()
13
+ }
14
+
15
+ // animateContentSize — tamaño cambia suavemente
16
+ Card(
17
+ modifier = Modifier
18
+ .animateContentSize(
19
+ animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy)
20
+ )
21
+ ) {
22
+ Column {
23
+ FacturasHeader(expandido = expandido, onClick = { expandido = !expandido })
24
+ if (expandido) FacturasDetalle()
25
+ }
26
+ }
27
+
28
+ // updateTransition — múltiples propiedades animadas juntas
29
+ val transicion = updateTransition(targetState = estado, label = "estado")
30
+ val color by transicion.animateColor(label = "color") { s ->
31
+ when (s) {
32
+ Estado.Activo -> MaterialTheme.colorScheme.primary
33
+ Estado.Inactivo -> MaterialTheme.colorScheme.surfaceVariant
34
+ }
35
+ }
36
+
37
+ // Animate*AsState — animación de valor único
38
+ val opacidad by animateFloatAsState(
39
+ targetValue = if (visible) 1f else 0f,
40
+ animationSpec = tween(durationMillis = 300),
41
+ label = "opacidad"
42
+ )
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Performance — @Stable y Skippability
48
+
49
+ ### Reglas de estabilidad
50
+
51
+ Compose puede saltarse la recomposición de un composable solo si todos sus
52
+ parámetros son estables. Un tipo es estable cuando:
53
+ - Es primitivo (Int, Boolean, String, etc.)
54
+ - Es un data class donde todos los campos son estables
55
+ - Está anotado con `@Stable` o `@Immutable`
56
+
57
+ ```kotlin
58
+ // @Stable: el compilador confía en que equals() detecta cambios
59
+ @Stable
60
+ class FacturasState(
61
+ val facturas: List<Factura>,
62
+ val cargando: Boolean
63
+ ) {
64
+ override fun equals(other: Any?) = other is FacturasState &&
65
+ facturas == other.facturas && cargando == other.cargando
66
+ }
67
+
68
+ // ImmutableList de kotlinx.collections.immutable
69
+ // La List<T> estándar NO es @Stable — causa recomposición innecesaria
70
+ @Composable
71
+ fun FacturasList(facturas: ImmutableList<Factura>) {
72
+ LazyColumn {
73
+ items(facturas, key = { it.id }) { FacturaItem(it) }
74
+ }
75
+ }
76
+
77
+ // Lambdas estables en items de lista
78
+ // MAL — nueva lambda en cada recomposición del padre
79
+ items(facturas) { factura ->
80
+ FacturaItem(onClic = { viewModel.seleccionar(factura.id) })
81
+ }
82
+
83
+ // BIEN — lambda estable con remember
84
+ items(facturas) { factura ->
85
+ val onClic = remember(factura.id) { { viewModel.seleccionar(factura.id) } }
86
+ FacturaItem(onClic = onClic)
87
+ }
88
+ ```
89
+
90
+ ### Diagnóstico con Layout Inspector
91
+
92
+ Activar "Recomposition counts" en Layout Inspector de Android Studio para
93
+ identificar composables que recomponen más veces de lo esperado.
@@ -0,0 +1,318 @@
1
+ ---
2
+ name: kotlin-experto
3
+ description: >
4
+ Kotlin moderno: coroutines, Flow con stateIn/shareIn, ViewModel con
5
+ SavedStateHandle, Hilt DI, Room con Flow, Ktor server, kotlinx.serialization
6
+ y sealed classes para estados UI. Cargar cuando se implementen features
7
+ Android/Kotlin, ViewModels, repositorios Room, o servicios backend Ktor.
8
+ version: "1.0.0"
9
+ herramientasPermitidas: [Read, Grep]
10
+ exclusiones:
11
+ - "No cargar para implementar pantallas Jetpack Compose — para Compose cargar `kotlin-compose`."
12
+ - "No cargar para escribir tests Kotlin (MockK, Turbine, runTest) — para testing cargar `kotlin-testing`."
13
+ - "No cargar para errores de compilación Kotlin o Gradle — para build errors cargar `build-errors-kotlin`."
14
+ - "No cargar para servicios Java Spring Boot sin Kotlin — Java tiene su propio modelo de concurrencia; cargar `java-experto`."
15
+ evolvable: true # default para skill estandar
16
+ ---
17
+ # Kotlin Experto — Coroutines, Flow y Android
18
+
19
+ ## Cuándo NO cargar
20
+
21
+ - La tarea es implementar pantallas Jetpack Compose (composables, state hoisting, Navigation Compose) — cargar `kotlin-compose`.
22
+ - La tarea es escribir tests Kotlin con MockK, Turbine o runTest — cargar `kotlin-testing`.
23
+ - Los errores son de compilación Kotlin, Hilt o Gradle — cargar `build-errors-kotlin`.
24
+ - El proyecto es Java Spring Boot sin Kotlin — Java tiene su propio modelo de concurrencia y DI; cargar `java-experto`.
25
+
26
+ ## Coroutines — Scopes y Dispatchers
27
+
28
+ ```kotlin
29
+ // Regla: usar el dispatcher correcto según el trabajo
30
+ class FacturasViewModel(
31
+ private val repo: IFacturasRepository,
32
+ savedState: SavedStateHandle
33
+ ) : ViewModel() {
34
+
35
+ // SavedStateHandle sobrevive a process death
36
+ private val empresaId = savedState.get<String>("empresaId")
37
+ ?: throw IllegalArgumentException("empresaId requerido")
38
+
39
+ // StateFlow para UI state — nunca MutableStateFlow público
40
+ private val _uiState = MutableStateFlow<FacturasUiState>(FacturasUiState.Cargando)
41
+ val uiState: StateFlow<FacturasUiState> = _uiState.asStateFlow()
42
+
43
+ init {
44
+ cargarFacturas()
45
+ }
46
+
47
+ private fun cargarFacturas() {
48
+ viewModelScope.launch { // se cancela con el ViewModel
49
+ _uiState.value = FacturasUiState.Cargando
50
+ repo.observarFacturas(empresaId)
51
+ .catch { e ->
52
+ _uiState.value = FacturasUiState.Error(e.message ?: "Error desconocido")
53
+ }
54
+ .collect { facturas ->
55
+ _uiState.value = FacturasUiState.Exito(facturas)
56
+ }
57
+ }
58
+ }
59
+ }
60
+
61
+ // withContext para cambiar dispatcher
62
+ suspend fun cargarDesdeRed(): List<Factura> = withContext(Dispatchers.IO) {
63
+ api.obtenerFacturas() // IO: red, disco
64
+ }
65
+
66
+ // async/await para paralelismo
67
+ suspend fun cargarDashboard(): Dashboard = coroutineScope {
68
+ val facturasDeferred = async { api.obtenerFacturas() }
69
+ val clientesDeferred = async { api.obtenerClientes() }
70
+ Dashboard(facturas = facturasDeferred.await(), clientes = clientesDeferred.await())
71
+ }
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Flow — stateIn, shareIn, conflate
77
+
78
+ ```kotlin
79
+ class FacturasRepository(private val dao: FacturasDao) : IFacturasRepository {
80
+
81
+ // stateIn: convierte Flow frío en StateFlow caliente
82
+ // SharingStarted.WhileSubscribed(5000): mantiene 5s luego del último suscriptor
83
+ // (sobrevive rotación de pantalla)
84
+ override fun observarFacturas(empresaId: String): StateFlow<List<Factura>> =
85
+ dao.observarPorEmpresa(empresaId)
86
+ .map { entities -> entities.map { it.toDomain() } }
87
+ .stateIn(
88
+ scope = externalScope, // scope del Application, no del ViewModel
89
+ started = SharingStarted.WhileSubscribed(5_000),
90
+ initialValue = emptyList()
91
+ )
92
+
93
+ // conflate: descarta intermedios cuando el consumidor es lento
94
+ fun observarProgreso(): Flow<Int> = producirProgreso().conflate()
95
+ }
96
+
97
+ // Room DAO retorna Flow — se re-emite en cada cambio de BD
98
+ @Dao
99
+ interface FacturasDao {
100
+ @Query("SELECT * FROM facturas WHERE empresa_id = :empresaId ORDER BY fecha DESC")
101
+ fun observarPorEmpresa(empresaId: String): Flow<List<FacturaEntity>>
102
+
103
+ @Insert(onConflict = OnConflictStrategy.REPLACE)
104
+ suspend fun insertar(factura: FacturaEntity)
105
+ }
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Hilt — Módulos e Inyección
111
+
112
+ ```kotlin
113
+ // Módulo para dependencias externas / interfaces
114
+ @Module
115
+ @InstallIn(SingletonComponent::class)
116
+ object NetworkModule {
117
+
118
+ @Provides
119
+ @Singleton
120
+ fun provideHttpClient(): HttpClient = HttpClient(Android) {
121
+ install(ContentNegotiation) { json() }
122
+ install(HttpTimeout) { requestTimeoutMillis = 30_000 }
123
+ }
124
+
125
+ @Provides
126
+ @Singleton
127
+ fun provideFacturasApi(client: HttpClient): IFacturasApi =
128
+ FacturasApiImpl(client)
129
+ }
130
+
131
+ // Bind: implementación de interfaz en el mismo módulo
132
+ @Module
133
+ @InstallIn(SingletonComponent::class)
134
+ abstract class RepositoryModule {
135
+ @Binds
136
+ @Singleton
137
+ abstract fun bindFacturasRepo(
138
+ impl: FacturasRepositoryImpl
139
+ ): IFacturasRepository
140
+ }
141
+
142
+ // ViewModel con Hilt
143
+ @HiltViewModel
144
+ class FacturasViewModel @Inject constructor(
145
+ private val repo: IFacturasRepository,
146
+ savedState: SavedStateHandle
147
+ ) : ViewModel()
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Sealed Classes para Estados UI
153
+
154
+ ```kotlin
155
+ sealed interface FacturasUiState {
156
+ data object Cargando : FacturasUiState
157
+ data class Exito(val facturas: List<Factura>) : FacturasUiState
158
+ data class Error(val mensaje: String) : FacturasUiState
159
+ }
160
+
161
+ // Uso exhaustivo en Compose — el compilador fuerza todos los casos
162
+ @Composable
163
+ fun FacturasScreen(uiState: FacturasUiState) {
164
+ when (uiState) {
165
+ is FacturasUiState.Cargando -> CircularProgressIndicator()
166
+ is FacturasUiState.Error -> ErrorView(uiState.mensaje)
167
+ is FacturasUiState.Exito -> FacturasList(uiState.facturas)
168
+ }
169
+ }
170
+ ```
171
+
172
+ ---
173
+
174
+ ## Ktor — Routing y Plugins
175
+
176
+ ```kotlin
177
+ fun Application.configurarRouting() {
178
+ install(ContentNegotiation) { json() }
179
+ install(RequestValidation) {
180
+ validate<CrearFacturaRequest> { req ->
181
+ if (req.folio.isBlank()) ValidationResult.Invalid("folio requerido")
182
+ else ValidationResult.Valid
183
+ }
184
+ }
185
+ install(StatusPages) {
186
+ exception<Throwable> { call, cause ->
187
+ call.respond(HttpStatusCode.InternalServerError,
188
+ mapOf("error" to (cause.message ?: "Error interno")))
189
+ }
190
+ }
191
+
192
+ routing {
193
+ route("/api/v1") {
194
+ authenticate("jwt") {
195
+ facturaRoutes()
196
+ }
197
+ }
198
+ }
199
+ }
200
+
201
+ fun Route.facturaRoutes() {
202
+ route("/facturas") {
203
+ get {
204
+ val empresaId = call.principal<JWTPrincipal>()!!
205
+ .payload.getClaim("empresa_id").asString()
206
+ val facturas = facturasService.obtenerTodas(empresaId)
207
+ call.respond(facturas)
208
+ }
209
+ post {
210
+ val req = call.receive<CrearFacturaRequest>()
211
+ val factura = facturasService.crear(req)
212
+ call.respond(HttpStatusCode.Created, factura)
213
+ }
214
+ }
215
+ }
216
+ ```
217
+
218
+ ---
219
+
220
+ ## kotlinx.serialization
221
+
222
+ ```kotlin
223
+ @Serializable
224
+ data class FacturaDto(
225
+ val id: String,
226
+ val folio: String,
227
+ val total: Double,
228
+ @SerialName("fecha_emision") val fechaEmision: String,
229
+ val estatus: EstatusFactura = EstatusFactura.BORRADOR
230
+ )
231
+
232
+ @Serializable
233
+ enum class EstatusFactura { BORRADOR, EMITIDA, CANCELADA }
234
+
235
+ // Configuración global de JSON
236
+ val jsonConfig = Json {
237
+ ignoreUnknownKeys = true // tolerante a campos extras de API
238
+ isLenient = false
239
+ encodeDefaults = false // no serializar campos con valor default
240
+ prettyPrint = false
241
+ }
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Extension Functions útiles
247
+
248
+ ```kotlin
249
+ // Result como alternativa a excepciones
250
+ suspend fun <T> safeApiCall(block: suspend () -> T): Result<T> =
251
+ try { Result.success(block()) }
252
+ catch (e: CancellationException) { throw e } // NUNCA atrapar CancellationException
253
+ catch (e: Exception) { Result.failure(e) }
254
+
255
+ // Flow de paginación
256
+ fun <T> Flow<List<T>>.paginar(pagina: Int, tamanoPagina: Int): Flow<List<T>> =
257
+ map { it.drop(pagina * tamanoPagina).take(tamanoPagina) }
258
+ ```
259
+
260
+ ---
261
+
262
+ ## Anti-patrones
263
+
264
+ ### GlobalScope — NUNCA
265
+
266
+ ```kotlin
267
+ // MAL — no tiene lifecycle, las coroutines se filtran
268
+ GlobalScope.launch { api.obtenerFacturas() }
269
+
270
+ // BIEN — scope ligado al lifecycle
271
+ viewModelScope.launch { ... } // ViewModel
272
+ lifecycleScope.launch { ... } // Activity/Fragment
273
+ ```
274
+
275
+ ### Atrapar CancellationException — NUNCA
276
+
277
+ ```kotlin
278
+ // MAL — rompe la cooperación de coroutines
279
+ try { ... } catch (e: Exception) { /* atrapa CancellationException */ }
280
+
281
+ // BIEN — re-lanzar siempre
282
+ try { ... } catch (e: Exception) {
283
+ if (e is CancellationException) throw e
284
+ // manejar otros errores
285
+ }
286
+ ```
287
+
288
+ ### MutableStateFlow público — NUNCA
289
+
290
+ ```kotlin
291
+ // MAL — UI puede modificar el estado desde afuera
292
+ val uiState = MutableStateFlow<Estado>(Estado.Cargando)
293
+
294
+ // BIEN — privado con backing property
295
+ private val _uiState = MutableStateFlow<Estado>(Estado.Cargando)
296
+ val uiState: StateFlow<Estado> = _uiState.asStateFlow()
297
+ ```
298
+
299
+ ---
300
+
301
+ ## Gotchas / Errores comunes no obvios
302
+
303
+ **`CancellationException` atrapada en un `catch(e: Exception)` rompe la cooperación de coroutines**: un bloque `catch (e: Exception) { /* ignorar */ }` captura `CancellationException` porque es subclase de `Exception`, lo que impide que la coroutine cancele correctamente. La coroutine sigue ejecutando después de que su scope fue cancelado. Fix: siempre hacer `catch (e: CancellationException) { throw e }` o usar `catch (e: Exception) { if (e is CancellationException) throw e }`.
304
+
305
+ **`stateIn(scope, SharingStarted.Eagerly, ...)` inicia el Flow aunque no haya suscriptores y consume recursos en background**: usar `Eagerly` en un ViewModel que se crea pero no se observa inmediatamente mantiene el Flow activo y puede generar requests innecesarios a la BD. Fix: usar `SharingStarted.WhileSubscribed(5000)` para activar el Flow solo cuando hay colectores activos, con 5 segundos de gracia para rotaciones de pantalla.
306
+
307
+ **`viewModelScope.launch` sobrevive a la destrucción del ViewModel si usa `withContext(Dispatchers.IO)`**: el coroutine scope del ViewModel se cancela en `onCleared()`, pero si hay trabajo en `Dispatchers.IO` en progreso, ese trabajo puede seguir ejecutando hasta que termine porque `Dispatchers.IO` no respeta automáticamente la cancelación del scope si el código no verifica `isActive`. Fix: asegurar que el código I/O usa operaciones cancelables o verifica `coroutineContext.isActive` periódicamente en loops.
308
+
309
+ **`@HiltViewModel` con parámetros que no son `SavedStateHandle` rompe la inyección en runtime**: si se agrega un parámetro no provisto por Hilt al constructor del ViewModel (como un ID de entidad), Hilt no puede crear el ViewModel y lanza `RuntimeException` al navegar a la pantalla. Fix: pasar datos iniciales siempre a través de `SavedStateHandle` desde los argumentos de navegación, nunca como constructor directo del ViewModel.
310
+
311
+ ## Checklist
312
+
313
+ - [ ] No hay GlobalScope.launch en código de producción
314
+ - [ ] CancellationException siempre se re-lanza
315
+ - [ ] MutableStateFlow siempre privado con backing property
316
+ - [ ] Room DAO retorna Flow para observabilidad reactiva
317
+ - [ ] stateIn usa WhileSubscribed(5000) para sobrevivir rotaciones
318
+ - [ ] Hilt: repositorios en SingletonComponent, ViewModels con @HiltViewModel