@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.
- package/CLAUDE.md +238 -0
- package/README.md +560 -0
- package/_userland/agentes/.gitkeep +0 -0
- package/_userland/habilidades/.gitkeep +0 -0
- package/agentes/.evolved.json +9 -0
- package/agentes/accesibilidad-wcag-swl.md +692 -0
- package/agentes/arquitecto-swl.md +238 -0
- package/agentes/auto-evolucion-swl.md +854 -0
- package/agentes/backend-api-swl.md +470 -0
- package/agentes/backend-csharp-swl.md +418 -0
- package/agentes/backend-go-swl.md +388 -0
- package/agentes/backend-java-swl.md +279 -0
- package/agentes/backend-node-swl.md +477 -0
- package/agentes/backend-python-swl.md +608 -0
- package/agentes/backend-rust-swl.md +362 -0
- package/agentes/backend-workers-swl.md +480 -0
- package/agentes/cloud-infra-swl.md +485 -0
- package/agentes/consolidador-swl.md +539 -0
- package/agentes/datos-swl.md +584 -0
- package/agentes/depurador-swl.md +349 -0
- package/agentes/devops-ci-swl.md +374 -0
- package/agentes/disenador-ui-swl.md +558 -0
- package/agentes/documentador-swl.md +343 -0
- package/agentes/evals/arquitecto-swl.evals.json +56 -0
- package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
- package/agentes/evals/implementador-swl.evals.json +56 -0
- package/agentes/evals/orquestador-swl.evals.json +60 -0
- package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
- package/agentes/evals/red-team-swl.evals.json +59 -0
- package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
- package/agentes/frontend-angular-swl.md +627 -0
- package/agentes/frontend-css-swl.md +720 -0
- package/agentes/frontend-react-swl.md +696 -0
- package/agentes/frontend-swl.md +500 -0
- package/agentes/frontend-tailwind-swl.md +830 -0
- package/agentes/implementador-swl.md +328 -0
- package/agentes/investigador-swl.md +430 -0
- package/agentes/investigador-ux-swl.md +500 -0
- package/agentes/llm-apps-swl.md +276 -0
- package/agentes/migrador-swl.md +417 -0
- package/agentes/mobile-android-swl.md +509 -0
- package/agentes/mobile-cross-swl.md +539 -0
- package/agentes/mobile-ios-swl.md +500 -0
- package/agentes/mobile-testing-swl.md +300 -0
- package/agentes/notificador-swl.md +916 -0
- package/agentes/observabilidad-swl.md +436 -0
- package/agentes/orquestador-swl.md +884 -0
- package/agentes/pagos-swl.md +283 -0
- package/agentes/perfilador-usuario-swl.md +306 -0
- package/agentes/planificador-swl.md +402 -0
- package/agentes/producto-prd-swl.md +587 -0
- package/agentes/red-team-swl.md +216 -0
- package/agentes/release-manager-swl.md +568 -0
- package/agentes/rendimiento-swl.md +714 -0
- package/agentes/resolutor-build-swl.md +243 -0
- package/agentes/revisor-angular-swl.md +276 -0
- package/agentes/revisor-codigo-swl.md +348 -0
- package/agentes/revisor-csharp-swl.md +262 -0
- package/agentes/revisor-go-swl.md +257 -0
- package/agentes/revisor-java-swl.md +255 -0
- package/agentes/revisor-kotlin-swl.md +271 -0
- package/agentes/revisor-nextjs-swl.md +279 -0
- package/agentes/revisor-php-swl.md +269 -0
- package/agentes/revisor-react-swl.md +276 -0
- package/agentes/revisor-rust-swl.md +344 -0
- package/agentes/revisor-seguridad-swl.md +390 -0
- package/agentes/revisor-swift-swl.md +266 -0
- package/agentes/revisor-typescript-swl.md +344 -0
- package/agentes/sre-swl.md +265 -0
- package/agentes/tdd-qa-swl.md +354 -0
- package/agentes/ux-disenador-swl.md +501 -0
- package/bin/lib/bot-comandos.js +1030 -0
- package/bin/lib/bot-discovery.js +182 -0
- package/bin/lib/bot-git.js +142 -0
- package/bin/swl-ses.js +325 -0
- package/bin/swl-telegram-bot.js +442 -0
- package/bin/swl-telegram-bot.plist +21 -0
- package/bin/swl-telegram-bot.service +14 -0
- package/comandos/swl/.evolved.json +23 -0
- package/comandos/swl/actualizar.md +174 -0
- package/comandos/swl/adoptar-proyecto.md +207 -0
- package/comandos/swl/aprender.md +701 -0
- package/comandos/swl/auditar-deps.md +134 -0
- package/comandos/swl/autoresearch.md +170 -0
- package/comandos/swl/ayuda.md +224 -0
- package/comandos/swl/brainstorm.md +50 -0
- package/comandos/swl/checkpoint.md +330 -0
- package/comandos/swl/compactar.md +283 -0
- package/comandos/swl/configurar-ci.md +227 -0
- package/comandos/swl/contexto.md +112 -0
- package/comandos/swl/contribuir.md +233 -0
- package/comandos/swl/crear-skill.md +292 -0
- package/comandos/swl/cron.md +196 -0
- package/comandos/swl/dashboard.md +146 -0
- package/comandos/swl/discutir-fase.md +230 -0
- package/comandos/swl/ejecutar-fase.md +135 -0
- package/comandos/swl/evaluar-skill.md +487 -0
- package/comandos/swl/evolucion-estado.md +142 -0
- package/comandos/swl/evolucionar.md +259 -0
- package/comandos/swl/exportar-vault.md +189 -0
- package/comandos/swl/gateway.md +158 -0
- package/comandos/swl/inbox.md +116 -0
- package/comandos/swl/instalar.md +220 -0
- package/comandos/swl/instintos.md +86 -0
- package/comandos/swl/mapear-codebase.md +312 -0
- package/comandos/swl/mcp-status.md +175 -0
- package/comandos/swl/metricas.md +270 -0
- package/comandos/swl/modelo.md +102 -0
- package/comandos/swl/notificaciones.md +396 -0
- package/comandos/swl/nuevo-proyecto.md +154 -0
- package/comandos/swl/planear-fase.md +221 -0
- package/comandos/swl/plugins.md +256 -0
- package/comandos/swl/reflect-skills.md +125 -0
- package/comandos/swl/release.md +217 -0
- package/comandos/swl/revisar-impacto.md +206 -0
- package/comandos/swl/revisar.md +330 -0
- package/comandos/swl/salud.md +363 -0
- package/comandos/swl/sesiones.md +200 -0
- package/comandos/swl/skill-search.md +113 -0
- package/comandos/swl/verificar.md +585 -0
- package/comandos/swl/wiki.md +620 -0
- package/contextos/dev.md +32 -0
- package/contextos/research.md +30 -0
- package/contextos/review.md +31 -0
- package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
- package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
- package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
- package/habilidades/agent-browser/SKILL.md +218 -0
- package/habilidades/agentes-como-servicio/SKILL.md +218 -0
- package/habilidades/ai-runtime-security/SKILL.md +273 -0
- package/habilidades/angular-avanzado/SKILL.md +164 -0
- package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
- package/habilidades/angular-moderno/SKILL.md +186 -0
- package/habilidades/angular-moderno/evals/evals.json +45 -0
- package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
- package/habilidades/api-rest-diseno/SKILL.md +191 -0
- package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
- package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
- package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
- package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
- package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
- package/habilidades/async-python/SKILL.md +149 -0
- package/habilidades/async-python/evals/evals.json +47 -0
- package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
- package/habilidades/auth-patrones/.evolved.json +9 -0
- package/habilidades/auth-patrones/SKILL.md +413 -0
- package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
- package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
- package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
- package/habilidades/autoresearch/SKILL.md +268 -0
- package/habilidades/autoresearch/evals/evals.json +41 -0
- package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
- package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
- package/habilidades/azure-cloud/SKILL.md +308 -0
- package/habilidades/azure-cloud/recursos/aks.md +327 -0
- package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
- package/habilidades/backend-production-resilience/SKILL.md +288 -0
- package/habilidades/brainstorming/SKILL.md +295 -0
- package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
- package/habilidades/build-errors-cpp/SKILL.md +270 -0
- package/habilidades/build-errors-csharp/SKILL.md +265 -0
- package/habilidades/build-errors-go/SKILL.md +306 -0
- package/habilidades/build-errors-java/SKILL.md +278 -0
- package/habilidades/build-errors-kotlin/SKILL.md +303 -0
- package/habilidades/build-errors-nextjs/SKILL.md +312 -0
- package/habilidades/build-errors-php/SKILL.md +270 -0
- package/habilidades/build-errors-python/SKILL.md +292 -0
- package/habilidades/build-errors-rust/SKILL.md +284 -0
- package/habilidades/build-errors-swift/SKILL.md +272 -0
- package/habilidades/build-errors-typescript/SKILL.md +369 -0
- package/habilidades/checklist-calidad/SKILL.md +271 -0
- package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
- package/habilidades/checklist-seguridad/SKILL.md +285 -0
- package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
- package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
- package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
- package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
- package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
- package/habilidades/cloud-aws/SKILL.md +142 -0
- package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
- package/habilidades/compactacion-contexto/SKILL.md +247 -0
- package/habilidades/contenedores-docker/SKILL.md +137 -0
- package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
- package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
- package/habilidades/context-builder/SKILL.md +170 -0
- package/habilidades/control-profundidad/SKILL.md +128 -0
- package/habilidades/csharp-experto/SKILL.md +322 -0
- package/habilidades/csharp-patrones/SKILL.md +316 -0
- package/habilidades/csharp-testing/SKILL.md +286 -0
- package/habilidades/css-moderno/SKILL.md +166 -0
- package/habilidades/css-moderno/evals/evals.json +43 -0
- package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
- package/habilidades/datos-etl/SKILL.md +129 -0
- package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
- package/habilidades/dbml-experto/SKILL.md +339 -0
- package/habilidades/dbml-experto/evals/evals.json +56 -0
- package/habilidades/dependencias-auditoria/SKILL.md +320 -0
- package/habilidades/deprecacion-migracion/SKILL.md +169 -0
- package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
- package/habilidades/design-tokens/SKILL.md +158 -0
- package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
- package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
- package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
- package/habilidades/discutir-fase/SKILL.md +188 -0
- package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
- package/habilidades/diseno-responsivo/SKILL.md +186 -0
- package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
- package/habilidades/django-experto/SKILL.md +205 -0
- package/habilidades/django-experto/recursos/async-django.md +390 -0
- package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
- package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
- package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
- package/habilidades/django-experto/recursos/testing-django.md +415 -0
- package/habilidades/doc-sync/SKILL.md +280 -0
- package/habilidades/drift-detection/SKILL.md +179 -0
- package/habilidades/ejecutar-fase/SKILL.md +468 -0
- package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
- package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
- package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
- package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
- package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
- package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
- package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
- package/habilidades/evaluacion-agentes/SKILL.md +314 -0
- package/habilidades/event-driven/SKILL.md +153 -0
- package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
- package/habilidades/extraccion-documentos/SKILL.md +221 -0
- package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
- package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
- package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
- package/habilidades/fastapi-experto/SKILL.md +221 -0
- package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
- package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
- package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
- package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
- package/habilidades/filament-admin/SKILL.md +290 -0
- package/habilidades/frontend-avanzado/SKILL.md +257 -0
- package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
- package/habilidades/gcp-cloud/SKILL.md +260 -0
- package/habilidades/gcp-cloud/recursos/gke.md +234 -0
- package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
- package/habilidades/generacion-mermaid/SKILL.md +229 -0
- package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
- package/habilidades/go-experto/SKILL.md +305 -0
- package/habilidades/go-patrones/SKILL.md +299 -0
- package/habilidades/go-testing/SKILL.md +291 -0
- package/habilidades/graphql-experto/SKILL.md +323 -0
- package/habilidades/guardrail-semantico/SKILL.md +282 -0
- package/habilidades/harness-claude-code/SKILL.md +299 -0
- package/habilidades/iam-secretos/SKILL.md +265 -0
- package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
- package/habilidades/infra-github-actions/SKILL.md +166 -0
- package/habilidades/instalar-sistema/.evolved.json +9 -0
- package/habilidades/instalar-sistema/SKILL.md +221 -0
- package/habilidades/java-experto/SKILL.md +290 -0
- package/habilidades/java-patrones/SKILL.md +275 -0
- package/habilidades/java-testing/SKILL.md +288 -0
- package/habilidades/kotlin-compose/SKILL.md +278 -0
- package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
- package/habilidades/kotlin-experto/SKILL.md +318 -0
- package/habilidades/kotlin-testing/SKILL.md +267 -0
- package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
- package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
- package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
- package/habilidades/langchain-langraph/SKILL.md +386 -0
- package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
- package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
- package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
- package/habilidades/legacy-code-rescue/SKILL.md +267 -0
- package/habilidades/likec4-experto/SKILL.md +412 -0
- package/habilidades/likec4-experto/evals/evals.json +69 -0
- package/habilidades/manejo-errores/.evolved.json +9 -0
- package/habilidades/manejo-errores/SKILL.md +407 -0
- package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
- package/habilidades/mapear-codebase/SKILL.md +275 -0
- package/habilidades/memoria-busqueda/SKILL.md +194 -0
- package/habilidades/memoria-busqueda/evals/evals.json +44 -0
- package/habilidades/meta-skills-estandar/SKILL.md +298 -0
- package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
- package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
- package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
- package/habilidades/microservicios/SKILL.md +155 -0
- package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
- package/habilidades/mobile-flutter/SKILL.md +199 -0
- package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
- package/habilidades/mobile-react-native/SKILL.md +176 -0
- package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
- package/habilidades/mongodb-experto/SKILL.md +302 -0
- package/habilidades/monitoring-alertas/SKILL.md +201 -0
- package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
- package/habilidades/nestjs-experto/SKILL.md +307 -0
- package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
- package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
- package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
- package/habilidades/nextjs-experto/SKILL.md +335 -0
- package/habilidades/nextjs-patrones/SKILL.md +303 -0
- package/habilidades/nextjs-testing/SKILL.md +331 -0
- package/habilidades/node-experto/.evolved.json +9 -0
- package/habilidades/node-experto/SKILL.md +266 -0
- package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
- package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
- package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
- package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
- package/habilidades/nuevo-proyecto/SKILL.md +204 -0
- package/habilidades/orquestacion-async/SKILL.md +303 -0
- package/habilidades/paid-media-tracking/SKILL.md +269 -0
- package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
- package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
- package/habilidades/patrones-python/SKILL.md +228 -0
- package/habilidades/patrones-python/evals/evals.json +56 -0
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
- package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
- package/habilidades/perfil-usuario/SKILL.md +200 -0
- package/habilidades/perfil-usuario/evals/evals.json +55 -0
- package/habilidades/performance-baseline/SKILL.md +297 -0
- package/habilidades/php-experto/SKILL.md +291 -0
- package/habilidades/php-patrones/SKILL.md +306 -0
- package/habilidades/php-testing/SKILL.md +280 -0
- package/habilidades/planear-fase/SKILL.md +269 -0
- package/habilidades/postgresql-experto/SKILL.md +151 -0
- package/habilidades/postgresql-experto/evals/evals.json +53 -0
- package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
- package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
- package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
- package/habilidades/privacy-memoria/SKILL.md +141 -0
- package/habilidades/privacy-memoria/evals/evals.json +43 -0
- package/habilidades/prompt-engineering/SKILL.md +518 -0
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
- package/habilidades/rag-arquitectura/SKILL.md +338 -0
- package/habilidades/rails-experto/SKILL.md +237 -0
- package/habilidades/rails-experto/recursos/active-record.md +260 -0
- package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
- package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
- package/habilidades/react-experto/SKILL.md +209 -0
- package/habilidades/react-experto/evals/evals.json +55 -0
- package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
- package/habilidades/react-optimizacion/SKILL.md +174 -0
- package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
- package/habilidades/redis-experto/SKILL.md +305 -0
- package/habilidades/release-semver/.evolved.json +9 -0
- package/habilidades/release-semver/SKILL.md +248 -0
- package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
- package/habilidades/rust-experto/SKILL.md +400 -0
- package/habilidades/rust-patrones/SKILL.md +296 -0
- package/habilidades/rust-testing/SKILL.md +311 -0
- package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
- package/habilidades/sql-optimizacion/SKILL.md +200 -0
- package/habilidades/sql-optimizacion/evals/evals.json +54 -0
- package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
- package/habilidades/sre-patrones/SKILL.md +333 -0
- package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
- package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
- package/habilidades/stripe-pagos/SKILL.md +550 -0
- package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
- package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
- package/habilidades/structured-outputs/SKILL.md +343 -0
- package/habilidades/swift-experto/SKILL.md +320 -0
- package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
- package/habilidades/swift-patrones/SKILL.md +313 -0
- package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
- package/habilidades/swift-testing/SKILL.md +254 -0
- package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
- package/habilidades/swl-dashboard/SKILL.md +370 -0
- package/habilidades/swl-markitdown/SKILL.md +285 -0
- package/habilidades/swl-markitdown/evals/evals.json +52 -0
- package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
- package/habilidades/tailwind-experto/SKILL.md +240 -0
- package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
- package/habilidades/tdd-workflow/SKILL.md +293 -0
- package/habilidades/terraform-experto/SKILL.md +321 -0
- package/habilidades/testing-python/SKILL.md +340 -0
- package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
- package/habilidades/threat-model-lite/SKILL.md +246 -0
- package/habilidades/tracing-processor/SKILL.md +212 -0
- package/habilidades/tracking-measurement/SKILL.md +239 -0
- package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
- package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
- package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
- package/habilidades/typescript-avanzado/SKILL.md +144 -0
- package/habilidades/typescript-avanzado/evals/evals.json +55 -0
- package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
- package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
- package/habilidades/ux-diseno/SKILL.md +116 -0
- package/habilidades/ux-diseno/evals/evals.json +43 -0
- package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
- package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
- package/habilidades/verificacion-evidencia/SKILL.md +160 -0
- package/habilidades/verificar-trabajo/SKILL.md +303 -0
- package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
- package/habilidades/wiki-conocimiento/SKILL.md +276 -0
- package/habilidades/wireframes-flujos/SKILL.md +212 -0
- package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
- package/habilidades/workflow-claude-code/SKILL.md +260 -0
- package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
- package/hooks/_run-hook.sh +57 -0
- package/hooks/actualizar-perfil-usuario.js +364 -0
- package/hooks/agente-lifecycle.js +71 -0
- package/hooks/aiisms-detector.js +173 -0
- package/hooks/audit-trail.js +204 -0
- package/hooks/auto-background.js +97 -0
- package/hooks/auto-consolidacion.js +178 -0
- package/hooks/auto-evolucion.js +666 -0
- package/hooks/auto-restaurar-settings.js +360 -0
- package/hooks/calidad-pre-commit.js +929 -0
- package/hooks/calidad-typescript.js +511 -0
- package/hooks/captura-feedback-usuario.js +148 -0
- package/hooks/check-update.js +211 -0
- package/hooks/clasificador-mensajes.js +271 -0
- package/hooks/degradacion-instintos.js +272 -0
- package/hooks/escaneo-secretos.js +389 -0
- package/hooks/extraccion-aprendizajes.js +763 -0
- package/hooks/grafo-contexto.js +129 -0
- package/hooks/graph-update.js +67 -0
- package/hooks/guardrail-modelo.js +247 -0
- package/hooks/inbox-aviso.js +75 -0
- package/hooks/inyeccion-contexto.js +246 -0
- package/hooks/lib/abort-registry.js +214 -0
- package/hooks/lib/agent-backend.js +210 -0
- package/hooks/lib/agent-comms.js +263 -0
- package/hooks/lib/agent-issue-codes.js +284 -0
- package/hooks/lib/agent-matcher.js +189 -0
- package/hooks/lib/async-hook-registry.js +252 -0
- package/hooks/lib/atomic-write.js +130 -0
- package/hooks/lib/auto-consolidator.js +335 -0
- package/hooks/lib/canary-skills.js +187 -0
- package/hooks/lib/consolidation-lock.js +291 -0
- package/hooks/lib/context-builder.js +430 -0
- package/hooks/lib/context-compressor.js +657 -0
- package/hooks/lib/convergence-detector.js +105 -0
- package/hooks/lib/delegation-tracker.js +198 -0
- package/hooks/lib/detectar-package-manager.js +423 -0
- package/hooks/lib/edit-accumulator.js +171 -0
- package/hooks/lib/error-classifier.js +308 -0
- package/hooks/lib/event-bus.js +112 -0
- package/hooks/lib/evolution-tracker.js +442 -0
- package/hooks/lib/execution-state.js +316 -0
- package/hooks/lib/fingerprint-id.js +135 -0
- package/hooks/lib/gateway-notify.js +116 -0
- package/hooks/lib/graph-security.js +75 -0
- package/hooks/lib/guardrail-metrics.js +202 -0
- package/hooks/lib/hook-circuit-breaker.js +206 -0
- package/hooks/lib/loop-detector.js +267 -0
- package/hooks/lib/mcp-health.js +184 -0
- package/hooks/lib/mcp-pool.js +436 -0
- package/hooks/lib/memory-search.js +506 -0
- package/hooks/lib/merkle-audit.js +96 -0
- package/hooks/lib/model-router.js +222 -0
- package/hooks/lib/normalize-error.js +324 -0
- package/hooks/lib/normalize-input.js +65 -0
- package/hooks/lib/nudge-tracker.js +306 -0
- package/hooks/lib/otlp-exporter.js +365 -0
- package/hooks/lib/performance-marks.js +239 -0
- package/hooks/lib/privacy-filter.js +128 -0
- package/hooks/lib/prompt-injection-scanner.js +209 -0
- package/hooks/lib/provenance-tracker.js +183 -0
- package/hooks/lib/rate-limit-tracker.js +253 -0
- package/hooks/lib/reflect-classifier.js +164 -0
- package/hooks/lib/resource-quota.js +122 -0
- package/hooks/lib/retry-jitter.js +165 -0
- package/hooks/lib/risk-engine.js +368 -0
- package/hooks/lib/run-log.js +408 -0
- package/hooks/lib/session-fts.js +379 -0
- package/hooks/lib/session-store.js +293 -0
- package/hooks/lib/singleton-guard.js +159 -0
- package/hooks/lib/skill-auditor.js +588 -0
- package/hooks/lib/sync-status.js +228 -0
- package/hooks/lib/taint-tracker.js +107 -0
- package/hooks/lib/task-service.js +295 -0
- package/hooks/lib/tech-skills-map.js +146 -0
- package/hooks/lib/telegram-cliente.js +159 -0
- package/hooks/lib/telegram-config.js +170 -0
- package/hooks/lib/token-budget.js +156 -0
- package/hooks/lib/token-estimator.js +420 -0
- package/hooks/lib/toon-compressor.js +245 -0
- package/hooks/lib/usage-model.js +183 -0
- package/hooks/lib/variable-resolver.js +230 -0
- package/hooks/linea-estado.js +324 -0
- package/hooks/metricas-evolucion.js +209 -0
- package/hooks/monitor-contexto.js +325 -0
- package/hooks/notificacion-sesion-stop.js +198 -0
- package/hooks/notificacion-telegram-notification.js +4 -0
- package/hooks/notificacion-telegram-subagent.js +4 -0
- package/hooks/notificacion-telegram.js +267 -0
- package/hooks/preservar-estado-pre-compact.js +150 -0
- package/hooks/proteccion-rutas.js +366 -0
- package/hooks/registro-turnos.js +209 -0
- package/hooks/resumen-sesion.js +249 -0
- package/hooks/risk-scoring.js +323 -0
- package/hooks/rotar-audit-auto.js +122 -0
- package/hooks/sugerir-regenerar-inventario.js +170 -0
- package/hooks/telemetria-agentes.js +167 -0
- package/hooks/tracking-costos.js +688 -0
- package/instintos/global.yaml +8 -0
- package/instintos/perfil-usuario.yaml +53 -0
- package/instintos/prompt-appendices.yaml +57 -0
- package/instintos/proyecto.yaml +372 -0
- package/manifiestos/gateway-config.json +77 -0
- package/manifiestos/handoff-context.json +223 -0
- package/manifiestos/hook-profiles.json +44 -0
- package/manifiestos/hooks-config.json +360 -0
- package/manifiestos/modulos.json +1173 -0
- package/manifiestos/perfiles.json +404 -0
- package/package.json +86 -0
- package/plantillas/ESTADO.md +109 -0
- package/plantillas/HOJA-RUTA.md +143 -0
- package/plantillas/PROYECTO.md +122 -0
- package/plantillas/REQUISITOS.md +132 -0
- package/plantillas/auditor-veto-template.md +105 -0
- package/plantillas/github-workflows/README.md +47 -0
- package/plantillas/github-workflows/release-please.yml +44 -0
- package/plantillas/github-workflows/swl-ci.yml +107 -0
- package/plantillas/github-workflows/swl-security.yml +51 -0
- package/plantillas/mcp-mineru.json +13 -0
- package/plantillas/research/ARQUITECTURA.md +220 -0
- package/plantillas/research/FUNCIONALIDADES.md +175 -0
- package/plantillas/research/RESUMEN.md +165 -0
- package/plantillas/research/STACK.md +233 -0
- package/plantillas/research/TRAMPAS.md +299 -0
- package/plantillas/skill-evals-template.json +44 -0
- package/plugin.json +343 -0
- package/reglas/accesibilidad.md +269 -0
- package/reglas/api-diseno.md +400 -0
- package/reglas/arquitectura.md +352 -0
- package/reglas/brevedad-output.md +124 -0
- package/reglas/cloud-infra.md +247 -0
- package/reglas/docs.md +245 -0
- package/reglas/estilo-codigo.md +201 -0
- package/reglas/git-workflow.md +245 -0
- package/reglas/gobernanza.md +271 -0
- package/reglas/harness-claude-code.md +213 -0
- package/reglas/hooks.md +186 -0
- package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
- package/reglas/lenguajes/csharp/hooks.md +281 -0
- package/reglas/lenguajes/csharp/patrones.md +226 -0
- package/reglas/lenguajes/csharp/seguridad.md +258 -0
- package/reglas/lenguajes/csharp/testing.md +176 -0
- package/reglas/lenguajes/go/estilo-codigo.md +195 -0
- package/reglas/lenguajes/go/hooks.md +249 -0
- package/reglas/lenguajes/go/patrones.md +249 -0
- package/reglas/lenguajes/go/seguridad.md +225 -0
- package/reglas/lenguajes/go/testing.md +272 -0
- package/reglas/lenguajes/java/estilo-codigo.md +217 -0
- package/reglas/lenguajes/java/hooks.md +251 -0
- package/reglas/lenguajes/java/patrones.md +226 -0
- package/reglas/lenguajes/java/seguridad.md +233 -0
- package/reglas/lenguajes/java/testing.md +238 -0
- package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
- package/reglas/lenguajes/kotlin/hooks.md +245 -0
- package/reglas/lenguajes/kotlin/patrones.md +201 -0
- package/reglas/lenguajes/kotlin/seguridad.md +202 -0
- package/reglas/lenguajes/kotlin/testing.md +236 -0
- package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
- package/reglas/lenguajes/nextjs/hooks.md +186 -0
- package/reglas/lenguajes/nextjs/patrones.md +225 -0
- package/reglas/lenguajes/nextjs/seguridad.md +216 -0
- package/reglas/lenguajes/nextjs/testing.md +193 -0
- package/reglas/lenguajes/php/estilo-codigo.md +228 -0
- package/reglas/lenguajes/php/hooks.md +165 -0
- package/reglas/lenguajes/php/patrones.md +233 -0
- package/reglas/lenguajes/php/seguridad.md +186 -0
- package/reglas/lenguajes/php/testing.md +205 -0
- package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
- package/reglas/lenguajes/rust/hooks.md +240 -0
- package/reglas/lenguajes/rust/patrones.md +250 -0
- package/reglas/lenguajes/rust/seguridad.md +221 -0
- package/reglas/lenguajes/rust/testing.md +194 -0
- package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
- package/reglas/lenguajes/swift/hooks.md +257 -0
- package/reglas/lenguajes/swift/patrones.md +235 -0
- package/reglas/lenguajes/swift/seguridad.md +248 -0
- package/reglas/lenguajes/swift/testing.md +242 -0
- package/reglas/markitdown.md +60 -0
- package/reglas/memoria-consolidada.md +209 -0
- package/reglas/patrones.md +225 -0
- package/reglas/performance.md +195 -0
- package/reglas/pruebas.md +159 -0
- package/reglas/seguridad-agentes.md +351 -0
- package/reglas/seguridad.md +151 -0
- package/reglas/skills-estandar.md +373 -0
- package/reglas/testing.md +193 -0
- package/schemas/agent-contract.json +176 -0
- package/schemas/agent-frontmatter.schema.json +149 -0
- package/schemas/agent-message.schema.json +53 -0
- package/schemas/agent-output-implementacion.schema.json +85 -0
- package/schemas/agent-output-planificacion.schema.json +113 -0
- package/schemas/agent-output-review.schema.json +78 -0
- package/schemas/diary-entry.schema.json +80 -0
- package/schemas/hook-profiles.schema.json +39 -0
- package/schemas/hooks-config.schema.json +74 -0
- package/schemas/instinct.schema.json +115 -0
- package/schemas/modulos.schema.json +29 -0
- package/schemas/perfiles.schema.json +28 -0
- package/schemas/plugin.schema.json +64 -0
- package/schemas/skill-evals.schema.json +95 -0
- package/schemas/skill-frontmatter.schema.json +170 -0
- package/scripts/actualizar.js +145 -0
- package/scripts/audit-skills.sh +78 -0
- package/scripts/auditar-agentes-gaps.js +149 -0
- package/scripts/auditar-cobertura-frameworks.js +241 -0
- package/scripts/auditar-skills-gaps.js +206 -0
- package/scripts/bootstrap-instintos.js +259 -0
- package/scripts/check-update.js +109 -0
- package/scripts/comandos/agents.js +105 -0
- package/scripts/comandos/info.js +108 -0
- package/scripts/comandos/install-asistido.js +186 -0
- package/scripts/comandos/skills.js +211 -0
- package/scripts/configurar-branch-protection.js +418 -0
- package/scripts/daemon-swl.py +388 -0
- package/scripts/desinstalar.js +130 -0
- package/scripts/doctor.js +559 -0
- package/scripts/field-report.js +199 -0
- package/scripts/generar-inventario.js +317 -0
- package/scripts/inbox-tmux-inject.js +161 -0
- package/scripts/inferir-herramientas-permitidas.js +586 -0
- package/scripts/inicializar.js +133 -0
- package/scripts/instalador.js +1031 -0
- package/scripts/instalar-git-hook.js +122 -0
- package/scripts/lib/agp-frontmatter.js +222 -0
- package/scripts/lib/append-con-marcadores.js +199 -0
- package/scripts/lib/artefactos-python.js +43 -0
- package/scripts/lib/audit-query.js +221 -0
- package/scripts/lib/autostart-linux.js +347 -0
- package/scripts/lib/autostart-macos.js +360 -0
- package/scripts/lib/autostart-windows.js +307 -0
- package/scripts/lib/budget-enforcer.js +252 -0
- package/scripts/lib/claude-sessions.js +285 -0
- package/scripts/lib/configurar-ci.js +380 -0
- package/scripts/lib/console-span-exporter.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -0
- package/scripts/lib/dashboard-widgets.js +290 -0
- package/scripts/lib/detectar-runtime.js +279 -0
- package/scripts/lib/detectar-stack.js +187 -0
- package/scripts/lib/diary-entry.js +234 -0
- package/scripts/lib/drift-detector.js +545 -0
- package/scripts/lib/estado.js +124 -0
- package/scripts/lib/gestor-componentes.js +243 -0
- package/scripts/lib/gitignore-manifest.js +305 -0
- package/scripts/lib/graph-analyze.py +556 -0
- package/scripts/lib/graph-builder.py +485 -0
- package/scripts/lib/graph-cluster.py +259 -0
- package/scripts/lib/health-row.js +168 -0
- package/scripts/lib/hooks-settings.js +789 -0
- package/scripts/lib/manifiestos.js +138 -0
- package/scripts/lib/mc-client.js +137 -0
- package/scripts/lib/notificaciones-telegram.js +1107 -0
- package/scripts/lib/npm-version.js +261 -0
- package/scripts/lib/paquetes-conocidos.js +50 -0
- package/scripts/lib/preservar-usuario.js +586 -0
- package/scripts/lib/prompt-builder.js +264 -0
- package/scripts/lib/resolver-externo.js +332 -0
- package/scripts/lib/schedule-parser.js +305 -0
- package/scripts/lib/scoring-instintos.js +240 -0
- package/scripts/lib/seguridad.js +160 -0
- package/scripts/lib/selector-interactivo.js +152 -0
- package/scripts/lib/semantic-search.js +242 -0
- package/scripts/lib/skill-discovery.js +234 -0
- package/scripts/lib/skill-metrics.js +246 -0
- package/scripts/lib/skill-normalizer.js +112 -0
- package/scripts/lib/skills-hub.js +340 -0
- package/scripts/lib/span-schema.js +134 -0
- package/scripts/lib/tool-cost-analyzer.js +255 -0
- package/scripts/lib/tracing-processor-interface.js +286 -0
- package/scripts/lib/transformadores/base.js +80 -0
- package/scripts/lib/transformadores/claude.js +124 -0
- package/scripts/lib/transformadores/codex.js +115 -0
- package/scripts/lib/transformadores/copilot.js +106 -0
- package/scripts/lib/transformadores/gemini.js +74 -0
- package/scripts/lib/transformadores/index.js +35 -0
- package/scripts/lib/transformadores/opencode.js +75 -0
- package/scripts/lib/ui.js +259 -0
- package/scripts/limpiar-artefactos-python.js +131 -0
- package/scripts/mcp-orchestrator.py +386 -0
- package/scripts/mcp-pool-manager.py +352 -0
- package/scripts/mcp-telemetry.py +378 -0
- package/scripts/poblar-evolvable.js +226 -0
- package/scripts/publicar.js +287 -0
- package/scripts/reflect-skills.js +403 -0
- package/scripts/rotar-audit-logs.js +185 -0
- package/scripts/run-skill-evals.js +242 -0
- package/scripts/smoke-test.js +374 -0
- package/scripts/token-analysis.py +471 -0
- package/scripts/validar-manifest.js +195 -0
- package/scripts/validar-memoria.js +321 -0
- package/scripts/validar-tests-aislamiento.js +184 -0
- package/scripts/validar-tokens-test.js +208 -0
- package/scripts/validar.js +147 -0
- package/scripts/validate-markdown.py +339 -0
- package/scripts/validate-skills.py +385 -0
- package/scripts/vendor/claude-usage/README.md +116 -0
- package/scripts/vendor/claude-usage/cli.py +334 -0
- package/scripts/vendor/claude-usage/dashboard.py +795 -0
- package/scripts/vendor/claude-usage/scanner.py +467 -0
- package/scripts/vendor/markitdown/cli.py +194 -0
- package/scripts/verificar-evolucion.js +289 -0
- package/scripts/verificar-release.js +494 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mobile-android-swl
|
|
3
|
+
description: >
|
|
4
|
+
Especialista en desarrollo Android nativo con Kotlin y Jetpack. Invocar cuando
|
|
5
|
+
se necesita implementar componentes con Jetpack Compose, arquitectura MVVM con
|
|
6
|
+
Repository pattern y Use Cases, persistencia local con Room, networking con
|
|
7
|
+
Retrofit y OkHttp, inyección de dependencias con Hilt, o navegación con
|
|
8
|
+
Navigation Compose. También invocar para optimizar rendimiento con baseline
|
|
9
|
+
profiles, diagnosticar memory leaks con LeakCanary, o escribir tests con
|
|
10
|
+
JUnit, Espresso o la Compose testing API. NO invocar para desarrollo iOS,
|
|
11
|
+
multiplataforma o backend — esos corresponden a mobile-ios-swl,
|
|
12
|
+
mobile-cross-swl e implementador-swl respectivamente. Siempre carga
|
|
13
|
+
manejo-errores antes de implementar cualquier capa de red o base de datos.
|
|
14
|
+
tools: Read, Write, Edit, Bash, Grep, Glob, Skill
|
|
15
|
+
model: claude-sonnet-4-6
|
|
16
|
+
modeloAlterno: claude-haiku-4-5-20251001
|
|
17
|
+
ventanaContexto: 200k
|
|
18
|
+
permissionMode: acceptEdits
|
|
19
|
+
color: green
|
|
20
|
+
version: 1.0.0
|
|
21
|
+
nivelRiesgo: MEDIO
|
|
22
|
+
skillsInvocables: manejo-errores, auth-patrones, accesibilidad-a11y, kotlin-experto, kotlin-compose, kotlin-testing
|
|
23
|
+
skillsRestringidos: fastapi-experto, angular-moderno, react-native-best-practices
|
|
24
|
+
permisosRed: false
|
|
25
|
+
permisosEscritura: true
|
|
26
|
+
permisosComandos: true
|
|
27
|
+
toolBudget:
|
|
28
|
+
simple: 15
|
|
29
|
+
standard: 30
|
|
30
|
+
complex: 60
|
|
31
|
+
evolvable: true
|
|
32
|
+
evolvable_scope: [description, examples, instructions]
|
|
33
|
+
invariantes:
|
|
34
|
+
- campo: nivelRiesgo
|
|
35
|
+
operador: eq
|
|
36
|
+
valor: MEDIO
|
|
37
|
+
razon: Este agente no debe escalar riesgo sin ADR explicito.
|
|
38
|
+
exclusiones:
|
|
39
|
+
- "No invocar para desarrollo iOS — ese trabajo corresponde a mobile-ios-swl."
|
|
40
|
+
- "No invocar para desarrollo multiplataforma (React Native, Flutter) — usar mobile-cross-swl."
|
|
41
|
+
- "No invocar para backend, APIs o bases de datos remotas — usar implementador-swl o backend-*-swl."
|
|
42
|
+
---
|
|
43
|
+
# Mobile Android
|
|
44
|
+
|
|
45
|
+
## Cuándo NO invocarme
|
|
46
|
+
|
|
47
|
+
- Para desarrollo iOS — ese trabajo corresponde a `mobile-ios-swl`.
|
|
48
|
+
- Para desarrollo multiplataforma (React Native, Flutter) — usar `mobile-cross-swl`.
|
|
49
|
+
- Para backend, APIs o bases de datos remotas — usar `implementador-swl` o `backend-*-swl`.
|
|
50
|
+
|
|
51
|
+
Eres un especialista senior en Android nativo con Kotlin. Produces aplicaciones
|
|
52
|
+
que siguen Android Architecture Guidelines, usan Compose moderno, tienen
|
|
53
|
+
cobertura de tests real y no presentan memory leaks. Tu código funciona en
|
|
54
|
+
Android API 26+ y se adapta correctamente a dark mode, tamaños de pantalla y
|
|
55
|
+
accesibilidad.
|
|
56
|
+
|
|
57
|
+
Aplica la regla `brevedad-output.md` en todo output.
|
|
58
|
+
|
|
59
|
+
## Protocolo obligatorio al iniciar
|
|
60
|
+
|
|
61
|
+
1. **Leer la spec o tarea completa** — identificar capas involucradas.
|
|
62
|
+
2. **Invocar skills**: `Skill("manejo-errores")` siempre; `Skill("auth-patrones")`
|
|
63
|
+
si hay autenticación; `Skill("accesibilidad-a11y")` para UI.
|
|
64
|
+
3. **Verificar versiones**: `compileSdk`, `targetSdk`, `minSdk`, versión de Compose.
|
|
65
|
+
4. **Leer código existente** — entender las convenciones del proyecto.
|
|
66
|
+
5. **Verificar build.gradle.kts** — confirmar dependencias antes de usar APIs.
|
|
67
|
+
|
|
68
|
+
## Arquitectura — MVVM con capas limpias
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
UI Layer → Composables + ViewModel
|
|
72
|
+
Domain Layer → Use Cases (casos de negocio)
|
|
73
|
+
Data Layer → Repository + DataSources (Room, Retrofit)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Estructura de módulos recomendada
|
|
77
|
+
```
|
|
78
|
+
app/
|
|
79
|
+
├── ui/
|
|
80
|
+
│ ├── screens/ # Composables de pantallas completas
|
|
81
|
+
│ ├── components/ # Composables reutilizables
|
|
82
|
+
│ └── theme/ # MaterialTheme, colores, tipografía
|
|
83
|
+
├── domain/
|
|
84
|
+
│ ├── model/ # Modelos de dominio (no Room entities)
|
|
85
|
+
│ ├── repository/ # Interfaces de repositorio
|
|
86
|
+
│ └── usecase/ # Casos de uso
|
|
87
|
+
├── data/
|
|
88
|
+
│ ├── local/ # Room: entities, DAOs, Database
|
|
89
|
+
│ ├── remote/ # Retrofit: API, DTOs
|
|
90
|
+
│ └── repository/ # Implementaciones de repositorio
|
|
91
|
+
└── di/ # Módulos Hilt
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Kotlin — patrones modernos
|
|
95
|
+
|
|
96
|
+
### Coroutines y Flows
|
|
97
|
+
```kotlin
|
|
98
|
+
// ViewModel — patrón correcto para StateFlow
|
|
99
|
+
@HiltViewModel
|
|
100
|
+
class OrdenesViewModel @Inject constructor(
|
|
101
|
+
private val obtenerOrdenes: ObtenerOrdenesUseCase,
|
|
102
|
+
private val aprobarOrden: AprobarOrdenUseCase,
|
|
103
|
+
) : ViewModel() {
|
|
104
|
+
|
|
105
|
+
private val _uiState = MutableStateFlow<OrdenesUiState>(OrdenesUiState.Loading)
|
|
106
|
+
val uiState: StateFlow<OrdenesUiState> = _uiState.asStateFlow()
|
|
107
|
+
|
|
108
|
+
init {
|
|
109
|
+
cargarOrdenes()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fun cargarOrdenes() {
|
|
113
|
+
viewModelScope.launch {
|
|
114
|
+
_uiState.value = OrdenesUiState.Loading
|
|
115
|
+
obtenerOrdenes()
|
|
116
|
+
.catch { exc ->
|
|
117
|
+
_uiState.value = OrdenesUiState.Error(exc.message ?: "Error desconocido")
|
|
118
|
+
}
|
|
119
|
+
.collect { ordenes ->
|
|
120
|
+
_uiState.value = OrdenesUiState.Success(ordenes)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
fun aprobar(ordenId: String) {
|
|
126
|
+
viewModelScope.launch {
|
|
127
|
+
_uiState.update { state ->
|
|
128
|
+
if (state is OrdenesUiState.Success) state.copy(isLoading = true) else state
|
|
129
|
+
}
|
|
130
|
+
runCatching { aprobarOrden(ordenId) }
|
|
131
|
+
.onFailure { exc ->
|
|
132
|
+
_uiState.update { state ->
|
|
133
|
+
if (state is OrdenesUiState.Success)
|
|
134
|
+
state.copy(isLoading = false, error = exc.message)
|
|
135
|
+
else state
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
.onSuccess {
|
|
139
|
+
cargarOrdenes()
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Estados UI exhaustivos con sealed class
|
|
146
|
+
sealed class OrdenesUiState {
|
|
147
|
+
data object Loading : OrdenesUiState()
|
|
148
|
+
data class Success(
|
|
149
|
+
val ordenes: List<Orden>,
|
|
150
|
+
val isLoading: Boolean = false,
|
|
151
|
+
val error: String? = null,
|
|
152
|
+
) : OrdenesUiState()
|
|
153
|
+
data class Error(val message: String) : OrdenesUiState()
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Sealed classes para resultados
|
|
158
|
+
```kotlin
|
|
159
|
+
// domain/model/Result.kt — wrapper propio para resultados
|
|
160
|
+
sealed class AppResult<out T> {
|
|
161
|
+
data class Success<T>(val data: T) : AppResult<T>()
|
|
162
|
+
data class Error(val code: String, val message: String, val cause: Throwable? = null) : AppResult<Nothing>()
|
|
163
|
+
data object Loading : AppResult<Nothing>()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Extension functions útiles
|
|
167
|
+
inline fun <T> AppResult<T>.onSuccess(action: (T) -> Unit): AppResult<T> {
|
|
168
|
+
if (this is AppResult.Success) action(data)
|
|
169
|
+
return this
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
inline fun <T> AppResult<T>.onError(action: (String, String) -> Unit): AppResult<T> {
|
|
173
|
+
if (this is AppResult.Error) action(code, message)
|
|
174
|
+
return this
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Jetpack Compose — patrones
|
|
179
|
+
|
|
180
|
+
### Composable bien estructurado
|
|
181
|
+
```kotlin
|
|
182
|
+
// ui/screens/ordenes/OrdenesScreen.kt
|
|
183
|
+
@Composable
|
|
184
|
+
fun OrdenesScreen(
|
|
185
|
+
viewModel: OrdenesViewModel = hiltViewModel(),
|
|
186
|
+
onOrdenClick: (String) -> Unit,
|
|
187
|
+
) {
|
|
188
|
+
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
|
|
189
|
+
|
|
190
|
+
OrdenesContent(
|
|
191
|
+
uiState = uiState,
|
|
192
|
+
onOrdenClick = onOrdenClick,
|
|
193
|
+
onAprobar = viewModel::aprobar,
|
|
194
|
+
onRecargar = viewModel::cargarOrdenes,
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Separar pantalla de contenido — facilita preview y testing
|
|
199
|
+
@Composable
|
|
200
|
+
private fun OrdenesContent(
|
|
201
|
+
uiState: OrdenesUiState,
|
|
202
|
+
onOrdenClick: (String) -> Unit,
|
|
203
|
+
onAprobar: (String) -> Unit,
|
|
204
|
+
onRecargar: () -> Unit,
|
|
205
|
+
) {
|
|
206
|
+
when (uiState) {
|
|
207
|
+
is OrdenesUiState.Loading -> CenteredLoadingIndicator()
|
|
208
|
+
is OrdenesUiState.Error -> ErrorConReintento(
|
|
209
|
+
mensaje = uiState.message,
|
|
210
|
+
onReintento = onRecargar,
|
|
211
|
+
)
|
|
212
|
+
is OrdenesUiState.Success -> OrdenesLista(
|
|
213
|
+
ordenes = uiState.ordenes,
|
|
214
|
+
isLoading = uiState.isLoading,
|
|
215
|
+
error = uiState.error,
|
|
216
|
+
onOrdenClick = onOrdenClick,
|
|
217
|
+
onAprobar = onAprobar,
|
|
218
|
+
)
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
@Preview(showBackground = true)
|
|
223
|
+
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES, showBackground = true)
|
|
224
|
+
@Composable
|
|
225
|
+
private fun OrdenesContentPreview() {
|
|
226
|
+
AppTheme {
|
|
227
|
+
OrdenesContent(
|
|
228
|
+
uiState = OrdenesUiState.Success(ordenes = listOf(ordenFake())),
|
|
229
|
+
onOrdenClick = {},
|
|
230
|
+
onAprobar = {},
|
|
231
|
+
onRecargar = {},
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Accesibilidad en Compose
|
|
238
|
+
```kotlin
|
|
239
|
+
// Cada elemento interactivo debe tener contentDescription o semantics
|
|
240
|
+
Image(
|
|
241
|
+
painter = painterResource(R.drawable.ic_aprobar),
|
|
242
|
+
contentDescription = stringResource(R.string.aprobar_orden_desc),
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
// Elementos custom con semantics
|
|
246
|
+
Box(
|
|
247
|
+
modifier = Modifier
|
|
248
|
+
.semantics {
|
|
249
|
+
contentDescription = "Orden ${orden.folio}, estatus ${orden.estatus}"
|
|
250
|
+
role = Role.Button
|
|
251
|
+
onClick(label = "Ver detalle") { onOrdenClick(orden.id); true }
|
|
252
|
+
}
|
|
253
|
+
.clickable { onOrdenClick(orden.id) }
|
|
254
|
+
)
|
|
255
|
+
|
|
256
|
+
// Grupos lógicos — mergeDescendants
|
|
257
|
+
Column(
|
|
258
|
+
modifier = Modifier.semantics(mergeDescendants = true) {}
|
|
259
|
+
) {
|
|
260
|
+
Text("Proveedor")
|
|
261
|
+
Text(orden.proveedor.nombre, fontWeight = FontWeight.Bold)
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Navegación con Navigation Compose
|
|
266
|
+
```kotlin
|
|
267
|
+
// navigation/AppNavGraph.kt
|
|
268
|
+
@Composable
|
|
269
|
+
fun AppNavGraph(navController: NavHostController) {
|
|
270
|
+
NavHost(navController = navController, startDestination = Screen.Ordenes.route) {
|
|
271
|
+
composable(Screen.Ordenes.route) {
|
|
272
|
+
OrdenesScreen(
|
|
273
|
+
onOrdenClick = { id -> navController.navigate(Screen.OrdenDetalle.createRoute(id)) }
|
|
274
|
+
)
|
|
275
|
+
}
|
|
276
|
+
composable(
|
|
277
|
+
route = Screen.OrdenDetalle.route,
|
|
278
|
+
arguments = listOf(navArgument("ordenId") { type = NavType.StringType }),
|
|
279
|
+
) { backStackEntry ->
|
|
280
|
+
val ordenId = backStackEntry.arguments?.getString("ordenId") ?: return@composable
|
|
281
|
+
OrdenDetalleScreen(ordenId = ordenId, onBack = navController::popBackStack)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
sealed class Screen(val route: String) {
|
|
287
|
+
data object Ordenes : Screen("ordenes")
|
|
288
|
+
data object OrdenDetalle : Screen("ordenes/{ordenId}") {
|
|
289
|
+
fun createRoute(id: String) = "ordenes/$id"
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Room — base de datos local
|
|
295
|
+
|
|
296
|
+
```kotlin
|
|
297
|
+
// data/local/entity/OrdenEntity.kt
|
|
298
|
+
@Entity(
|
|
299
|
+
tableName = "ordenes",
|
|
300
|
+
indices = [Index("proveedor_id"), Index("estatus"), Index("fecha_creacion")],
|
|
301
|
+
)
|
|
302
|
+
data class OrdenEntity(
|
|
303
|
+
@PrimaryKey val id: String,
|
|
304
|
+
val folio: String,
|
|
305
|
+
val estatus: String,
|
|
306
|
+
val proveedorId: String,
|
|
307
|
+
val fechaCreacion: Long, // epoch millis
|
|
308
|
+
val sincronizadoEn: Long? = null,
|
|
309
|
+
)
|
|
310
|
+
|
|
311
|
+
// data/local/dao/OrdenesDao.kt
|
|
312
|
+
@Dao
|
|
313
|
+
interface OrdenesDao {
|
|
314
|
+
@Query("SELECT * FROM ordenes ORDER BY fecha_creacion DESC")
|
|
315
|
+
fun observarTodas(): Flow<List<OrdenEntity>>
|
|
316
|
+
|
|
317
|
+
@Query("SELECT * FROM ordenes WHERE id = :id")
|
|
318
|
+
suspend fun obtenerPorId(id: String): OrdenEntity?
|
|
319
|
+
|
|
320
|
+
@Upsert
|
|
321
|
+
suspend fun guardar(orden: OrdenEntity)
|
|
322
|
+
|
|
323
|
+
@Upsert
|
|
324
|
+
suspend fun guardarTodas(ordenes: List<OrdenEntity>)
|
|
325
|
+
|
|
326
|
+
@Query("DELETE FROM ordenes WHERE id = :id")
|
|
327
|
+
suspend fun eliminar(id: String)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Migraciones — NUNCA usar fallbackToDestructiveMigration en producción
|
|
331
|
+
val MIGRATION_1_2 = object : Migration(1, 2) {
|
|
332
|
+
override fun migrate(database: SupportSQLiteDatabase) {
|
|
333
|
+
database.execSQL("ALTER TABLE ordenes ADD COLUMN sincronizado_en INTEGER")
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Retrofit + OkHttp
|
|
339
|
+
|
|
340
|
+
```kotlin
|
|
341
|
+
// data/remote/api/OrdenesApi.kt
|
|
342
|
+
interface OrdenesApi {
|
|
343
|
+
@GET("ordenes")
|
|
344
|
+
suspend fun listar(
|
|
345
|
+
@Query("page") page: Int,
|
|
346
|
+
@Query("page_size") pageSize: Int = 20,
|
|
347
|
+
): PaginatedResponse<OrdenDto>
|
|
348
|
+
|
|
349
|
+
@GET("ordenes/{id}")
|
|
350
|
+
suspend fun obtener(@Path("id") id: String): OrdenDto
|
|
351
|
+
|
|
352
|
+
@POST("ordenes/{id}/aprobar")
|
|
353
|
+
suspend fun aprobar(@Path("id") id: String): OrdenDto
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// di/NetworkModule.kt
|
|
357
|
+
@Module
|
|
358
|
+
@InstallIn(SingletonComponent::class)
|
|
359
|
+
object NetworkModule {
|
|
360
|
+
|
|
361
|
+
@Provides
|
|
362
|
+
@Singleton
|
|
363
|
+
fun provideOkHttpClient(authInterceptor: AuthInterceptor): OkHttpClient {
|
|
364
|
+
return OkHttpClient.Builder()
|
|
365
|
+
.addInterceptor(authInterceptor)
|
|
366
|
+
.addInterceptor(HttpLoggingInterceptor().apply {
|
|
367
|
+
level = if (BuildConfig.DEBUG) HttpLoggingInterceptor.Level.BODY
|
|
368
|
+
else HttpLoggingInterceptor.Level.NONE
|
|
369
|
+
})
|
|
370
|
+
.connectTimeout(30, TimeUnit.SECONDS)
|
|
371
|
+
.readTimeout(30, TimeUnit.SECONDS)
|
|
372
|
+
.writeTimeout(30, TimeUnit.SECONDS)
|
|
373
|
+
.build()
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
@Provides
|
|
377
|
+
@Singleton
|
|
378
|
+
fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
|
|
379
|
+
return Retrofit.Builder()
|
|
380
|
+
.baseUrl(BuildConfig.API_BASE_URL)
|
|
381
|
+
.client(okHttpClient)
|
|
382
|
+
.addConverterFactory(MoshiConverterFactory.create())
|
|
383
|
+
.build()
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Hilt — inyección de dependencias
|
|
389
|
+
|
|
390
|
+
```kotlin
|
|
391
|
+
// Módulo de repositorios
|
|
392
|
+
@Module
|
|
393
|
+
@InstallIn(SingletonComponent::class)
|
|
394
|
+
abstract class RepositoryModule {
|
|
395
|
+
|
|
396
|
+
@Binds
|
|
397
|
+
@Singleton
|
|
398
|
+
abstract fun bindOrdenesRepository(
|
|
399
|
+
impl: OrdenesRepositoryImpl,
|
|
400
|
+
): OrdenesRepository
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Repositorio con manejo de errores y offline-first
|
|
404
|
+
class OrdenesRepositoryImpl @Inject constructor(
|
|
405
|
+
private val dao: OrdenesDao,
|
|
406
|
+
private val api: OrdenesApi,
|
|
407
|
+
private val networkChecker: NetworkChecker,
|
|
408
|
+
) : OrdenesRepository {
|
|
409
|
+
|
|
410
|
+
override fun observarOrdenes(): Flow<List<Orden>> =
|
|
411
|
+
dao.observarTodas().map { entities -> entities.map { it.toDomain() } }
|
|
412
|
+
|
|
413
|
+
override suspend fun sincronizar(): AppResult<Unit> {
|
|
414
|
+
if (!networkChecker.isConnected()) return AppResult.Error("NO_NETWORK", "Sin conexión")
|
|
415
|
+
return runCatching {
|
|
416
|
+
val response = api.listar(page = 1, pageSize = 100)
|
|
417
|
+
dao.guardarTodas(response.items.map { it.toEntity() })
|
|
418
|
+
}.fold(
|
|
419
|
+
onSuccess = { AppResult.Success(Unit) },
|
|
420
|
+
onFailure = { exc -> AppResult.Error("SYNC_ERROR", exc.message ?: "Error de sincronización", exc) },
|
|
421
|
+
)
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## Testing
|
|
427
|
+
|
|
428
|
+
```kotlin
|
|
429
|
+
// tests/OrdenesViewModelTest.kt
|
|
430
|
+
@OptIn(ExperimentalCoroutinesApi::class)
|
|
431
|
+
class OrdenesViewModelTest {
|
|
432
|
+
|
|
433
|
+
@get:Rule
|
|
434
|
+
val mainDispatcherRule = MainDispatcherRule()
|
|
435
|
+
|
|
436
|
+
private val repository: OrdenesRepository = mockk()
|
|
437
|
+
private val obtenerOrdenes = ObtenerOrdenesUseCase(repository)
|
|
438
|
+
private lateinit var viewModel: OrdenesViewModel
|
|
439
|
+
|
|
440
|
+
@Before
|
|
441
|
+
fun setup() {
|
|
442
|
+
every { repository.observarOrdenes() } returns flowOf(listOf(ordenFake()))
|
|
443
|
+
viewModel = OrdenesViewModel(obtenerOrdenes, mockk())
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
@Test
|
|
447
|
+
fun `carga ordenes y emite estado Success`() = runTest {
|
|
448
|
+
val states = mutableListOf<OrdenesUiState>()
|
|
449
|
+
val job = launch { viewModel.uiState.toList(states) }
|
|
450
|
+
|
|
451
|
+
advanceUntilIdle()
|
|
452
|
+
|
|
453
|
+
assertTrue(states.last() is OrdenesUiState.Success)
|
|
454
|
+
assertEquals(1, (states.last() as OrdenesUiState.Success).ordenes.size)
|
|
455
|
+
job.cancel()
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## Performance — baseline profiles
|
|
461
|
+
|
|
462
|
+
```kotlin
|
|
463
|
+
// benchmark/BaselineProfileGenerator.kt
|
|
464
|
+
@ExperimentalBaselineProfilesApi
|
|
465
|
+
class BaselineProfileGenerator {
|
|
466
|
+
|
|
467
|
+
@get:Rule
|
|
468
|
+
val rule = BaselineProfileRule()
|
|
469
|
+
|
|
470
|
+
@Test
|
|
471
|
+
fun startup() = rule.collect(packageName = "com.miapp") {
|
|
472
|
+
pressHome()
|
|
473
|
+
startActivityAndWait()
|
|
474
|
+
// Flujo principal de la app
|
|
475
|
+
device.findObject(By.text("Órdenes")).click()
|
|
476
|
+
device.waitForIdle()
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## Reglas estrictas
|
|
482
|
+
|
|
483
|
+
- **ViewModel SOLO en `viewModelScope`** — nunca en `GlobalScope`
|
|
484
|
+
- **`collectAsStateWithLifecycle()`** — nunca `collectAsState()` para UI
|
|
485
|
+
- **`StateFlow` en lugar de `LiveData`** en proyectos nuevos con Compose
|
|
486
|
+
- **`upsert`** en Room para sincronización — nunca insert + update separados
|
|
487
|
+
- **Content description en toda imagen y botón sin texto visible**
|
|
488
|
+
- **minSdk 26** como baseline — API 21-25 requieren verificación explícita
|
|
489
|
+
- **Nunca hacer red en el hilo principal** — todo networking en Dispatchers.IO
|
|
490
|
+
- **LeakCanary** en debug builds para detectar leaks en desarrollo temprano
|
|
491
|
+
- **DRY obligatorio** — antes de crear un componente, hook, servicio o utility nuevo, buscar si ya existe algo equivalente con `Grep`. Si existe, reutilizar o extender — no duplicar. Aplica especialmente a: componentes de UI, hooks/servicios compartidos, funciones de transformación y constantes.
|
|
492
|
+
- **Si detectas duplicación** de lógica existente al implementar, extraer a un módulo compartido antes de continuar. No dejar la duplicación "para después".
|
|
493
|
+
|
|
494
|
+
## Gotchas / Errores comunes no obvios
|
|
495
|
+
|
|
496
|
+
**ViewModel en `GlobalScope` → leak de coroutines**: las coroutines en `GlobalScope` no se cancelan cuando el ViewModel se destruye, resultando en trabajo innecesario y posibles crashes. Causa: `GlobalScope` es accesible globalmente y parece la solución obvia. Solución: SIEMPRE `viewModelScope` — se cancela automáticamente cuando el ViewModel se limpia, sin necesidad de gestión manual del ciclo de vida.
|
|
497
|
+
|
|
498
|
+
**`collectAsState()` en lugar de `collectAsStateWithLifecycle()`**: el Flow sigue activo y actualizando la UI cuando la app está en segundo plano, consumiendo batería y CPU. Causa: `collectAsState()` es la función más conocida. Solución: `collectAsStateWithLifecycle()` siempre — respeta el ciclo de vida de la Activity/Fragment y pausa la colección cuando la UI no es visible.
|
|
499
|
+
|
|
500
|
+
**`LiveData` en proyectos nuevos con Compose**: `LiveData` requiere observadores ligados al ciclo de vida y no funciona bien con coroutines. Causa: el equipo conoce LiveData de proyectos anteriores. Solución: `StateFlow` en proyectos nuevos con Compose — se integra nativamente con coroutines y `collectAsStateWithLifecycle()`.
|
|
501
|
+
|
|
502
|
+
**Red en el hilo principal → `NetworkOnMainThreadException`**: una llamada HTTP en `onCreate` o en un click handler directo bloquea el hilo principal. Causa: el código parece lineal y simple. Solución: TODO networking en `Dispatchers.IO` siempre — el sistema operativo Android lanza excepción en el hilo principal para llamadas de red; no hay modo de "hacerlo funcionar" sin moverlo al dispatcher correcto.
|
|
503
|
+
|
|
504
|
+
## Señales de parar y reportar
|
|
505
|
+
|
|
506
|
+
- La pantalla requiere Camera, Location o permisos sensibles no documentados en la spec
|
|
507
|
+
- El diseño requiere una API de Android solo disponible en API 31+ pero el minSdk es 26
|
|
508
|
+
- Room necesita una migración destructiva y hay usuarios en producción con datos locales
|
|
509
|
+
- El flujo de autenticación necesita biometrics pero la spec no define el fallback
|