@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,238 @@
|
|
|
1
|
+
# Regla: Testing Java
|
|
2
|
+
|
|
3
|
+
Los tests no son opcionales. Un método sin test es un método que no se puede
|
|
4
|
+
modificar con confianza. Esta regla aplica a todo código Java nuevo o modificado.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## JUnit 5 como framework principal
|
|
9
|
+
|
|
10
|
+
JUnit 5 (Jupiter) es el único framework de testing aceptado. JUnit 4 está prohibido
|
|
11
|
+
en código nuevo. No mezclar anotaciones de ambas versiones en el mismo proyecto.
|
|
12
|
+
|
|
13
|
+
```java
|
|
14
|
+
// MAL — JUnit 4 en código nuevo
|
|
15
|
+
import org.junit.Test;
|
|
16
|
+
import org.junit.Before;
|
|
17
|
+
|
|
18
|
+
// BIEN — JUnit 5
|
|
19
|
+
import org.junit.jupiter.api.Test;
|
|
20
|
+
import org.junit.jupiter.api.BeforeEach;
|
|
21
|
+
import org.junit.jupiter.api.DisplayName;
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## @DisplayName descriptivos en español
|
|
27
|
+
|
|
28
|
+
Los nombres de los métodos de test son para máquinas. `@DisplayName` es para humanos.
|
|
29
|
+
Todo test DEBE tener `@DisplayName` con el escenario completo en español.
|
|
30
|
+
|
|
31
|
+
```java
|
|
32
|
+
// MAL — nombre técnico sin contexto
|
|
33
|
+
@Test
|
|
34
|
+
void test1() { ... }
|
|
35
|
+
|
|
36
|
+
@Test
|
|
37
|
+
void calcularIvaTest() { ... }
|
|
38
|
+
|
|
39
|
+
// BIEN — describe el escenario y el resultado esperado
|
|
40
|
+
@Test
|
|
41
|
+
@DisplayName("Calcula IVA de 16% para productos gravados con tasa estándar")
|
|
42
|
+
void calcularIva_productoGravadoTasaEstandar_retornaIva16Porciento() {
|
|
43
|
+
// ...
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@Test
|
|
47
|
+
@DisplayName("Lanza excepción cuando el subtotal es negativo")
|
|
48
|
+
void calcularIva_subtotalNegativo_lanzaIllegalArgumentException() {
|
|
49
|
+
// ...
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Patrón Arrange-Act-Assert (AAA)
|
|
56
|
+
|
|
57
|
+
Todos los tests siguen AAA. Los tres bloques separados con comentario o línea en blanco.
|
|
58
|
+
|
|
59
|
+
```java
|
|
60
|
+
@Test
|
|
61
|
+
@DisplayName("Crea factura con total correcto para múltiples líneas con IVA")
|
|
62
|
+
void crearFactura_variasLineas_calculaTotalConIva() {
|
|
63
|
+
// Arrange
|
|
64
|
+
var cliente = ClienteFactory.clienteActivo();
|
|
65
|
+
var lineas = List.of(
|
|
66
|
+
LineaFactura.de(Producto.con(precio("100.00")), cantidad(2)),
|
|
67
|
+
LineaFactura.de(Producto.con(precio("50.00")), cantidad(1))
|
|
68
|
+
);
|
|
69
|
+
var servicio = new FacturaService(repositorioMock, calculadorIva);
|
|
70
|
+
|
|
71
|
+
// Act
|
|
72
|
+
var factura = servicio.crear(cliente, lineas);
|
|
73
|
+
|
|
74
|
+
// Assert
|
|
75
|
+
assertThat(factura.getSubtotal()).isEqualByComparingTo("250.00");
|
|
76
|
+
assertThat(factura.getIva()).isEqualByComparingTo("40.00");
|
|
77
|
+
assertThat(factura.getTotal()).isEqualByComparingTo("290.00");
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Mockito para mocks — no PowerMock
|
|
84
|
+
|
|
85
|
+
PowerMock no se usa. Si el código requiere PowerMock (mockear static, final,
|
|
86
|
+
constructores), el código tiene un problema de diseño que debe corregirse primero.
|
|
87
|
+
|
|
88
|
+
```java
|
|
89
|
+
// Configuración estándar
|
|
90
|
+
@ExtendWith(MockitoExtension.class)
|
|
91
|
+
class FacturaServiceTest {
|
|
92
|
+
@Mock
|
|
93
|
+
private FacturaRepository repositorio;
|
|
94
|
+
|
|
95
|
+
@Mock
|
|
96
|
+
private EventoPublicador publicador;
|
|
97
|
+
|
|
98
|
+
@InjectMocks
|
|
99
|
+
private FacturaService servicio;
|
|
100
|
+
|
|
101
|
+
@Test
|
|
102
|
+
@DisplayName("Publica evento cuando la factura se crea exitosamente")
|
|
103
|
+
void crear_facturaValida_publicaEventoCreado() {
|
|
104
|
+
// Arrange
|
|
105
|
+
var factura = FacturaFactory.borradora();
|
|
106
|
+
when(repositorio.guardar(any())).thenReturn(factura);
|
|
107
|
+
|
|
108
|
+
// Act
|
|
109
|
+
servicio.crear(factura.getCliente(), factura.getLineas());
|
|
110
|
+
|
|
111
|
+
// Assert
|
|
112
|
+
verify(publicador).publicar(argThat(evento ->
|
|
113
|
+
evento instanceof FacturaCreada fc && fc.facturaId().equals(factura.getId())
|
|
114
|
+
));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## AssertJ para assertions fluidas
|
|
122
|
+
|
|
123
|
+
AssertJ provee mensajes de error descriptivos y una API fluida.
|
|
124
|
+
Usar siempre sobre `assertEquals`, `assertTrue` y similares de JUnit.
|
|
125
|
+
|
|
126
|
+
```java
|
|
127
|
+
// MAL — assertions básicas con mensajes de error pobres
|
|
128
|
+
assertEquals("ACTIVA", factura.getEstatus());
|
|
129
|
+
assertTrue(factura.getLineas().size() > 0);
|
|
130
|
+
assertNotNull(factura.getId());
|
|
131
|
+
|
|
132
|
+
// BIEN — AssertJ: legible y con mensajes de error útiles al fallar
|
|
133
|
+
assertThat(factura.getEstatus()).isEqualTo(EstatusFactura.ACTIVA);
|
|
134
|
+
assertThat(factura.getLineas()).isNotEmpty().hasSize(3);
|
|
135
|
+
assertThat(factura.getId()).isNotNull();
|
|
136
|
+
assertThat(factura.getTotal()).isGreaterThan(BigDecimal.ZERO);
|
|
137
|
+
|
|
138
|
+
// Para excepciones
|
|
139
|
+
assertThatThrownBy(() -> servicio.crear(clienteInactivo, lineas))
|
|
140
|
+
.isInstanceOf(ClienteInactivoException.class)
|
|
141
|
+
.hasMessageContaining("inactivo");
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## TestContainers para tests de integración con BD
|
|
147
|
+
|
|
148
|
+
Las pruebas de integración usan TestContainers. No hay bases de datos H2 en
|
|
149
|
+
tests — H2 tiene comportamiento diferente a PostgreSQL/MySQL en producción.
|
|
150
|
+
|
|
151
|
+
```java
|
|
152
|
+
@SpringBootTest
|
|
153
|
+
@Testcontainers
|
|
154
|
+
class FacturaRepositoryIntegrationTest {
|
|
155
|
+
|
|
156
|
+
@Container
|
|
157
|
+
static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16")
|
|
158
|
+
.withDatabaseName("test_db")
|
|
159
|
+
.withUsername("test")
|
|
160
|
+
.withPassword("test");
|
|
161
|
+
|
|
162
|
+
@DynamicPropertySource
|
|
163
|
+
static void configurarPropiedades(DynamicPropertyRegistry registry) {
|
|
164
|
+
registry.add("spring.datasource.url", postgres::getJdbcUrl);
|
|
165
|
+
registry.add("spring.datasource.username", postgres::getUsername);
|
|
166
|
+
registry.add("spring.datasource.password", postgres::getPassword);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
@Test
|
|
170
|
+
@DisplayName("Persiste y recupera factura con todas sus líneas")
|
|
171
|
+
void guardar_facturaConLineas_persisteCorrectamente() { ... }
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Tests parametrizados con @ParameterizedTest
|
|
178
|
+
|
|
179
|
+
Para múltiples casos del mismo escenario, usar `@ParameterizedTest` en lugar
|
|
180
|
+
de duplicar métodos de test.
|
|
181
|
+
|
|
182
|
+
```java
|
|
183
|
+
@ParameterizedTest(name = "Tasa {0}% sobre ${1} resulta en ${2} de IVA")
|
|
184
|
+
@CsvSource({
|
|
185
|
+
"0.16, 100.00, 16.00",
|
|
186
|
+
"0.08, 100.00, 8.00",
|
|
187
|
+
"0.00, 100.00, 0.00",
|
|
188
|
+
"0.16, 0.00, 0.00"
|
|
189
|
+
})
|
|
190
|
+
@DisplayName("Calcula IVA correctamente para diferentes tasas y subtotales")
|
|
191
|
+
void calcularIva_variasConfiguraciones_resultadoCorrecto(
|
|
192
|
+
double tasa, String subtotal, String ivaEsperado) {
|
|
193
|
+
var resultado = calculador.calcular(new BigDecimal(subtotal), tasa);
|
|
194
|
+
assertThat(resultado).isEqualByComparingTo(ivaEsperado);
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Cobertura mínima 80% con JaCoCo
|
|
201
|
+
|
|
202
|
+
JaCoCo en CI con umbral de fallo. Sin excepciones para módulos de lógica de negocio.
|
|
203
|
+
|
|
204
|
+
```xml
|
|
205
|
+
<!-- pom.xml -->
|
|
206
|
+
<plugin>
|
|
207
|
+
<groupId>org.jacoco</groupId>
|
|
208
|
+
<artifactId>jacoco-maven-plugin</artifactId>
|
|
209
|
+
<configuration>
|
|
210
|
+
<rules>
|
|
211
|
+
<rule>
|
|
212
|
+
<element>BUNDLE</element>
|
|
213
|
+
<limits>
|
|
214
|
+
<limit>
|
|
215
|
+
<counter>LINE</counter>
|
|
216
|
+
<value>COVEREDRATIO</value>
|
|
217
|
+
<minimum>0.80</minimum>
|
|
218
|
+
</limit>
|
|
219
|
+
</limits>
|
|
220
|
+
</rule>
|
|
221
|
+
</rules>
|
|
222
|
+
</configuration>
|
|
223
|
+
</plugin>
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Checklist de testing Java antes de abrir PR
|
|
229
|
+
|
|
230
|
+
- [ ] Todo método público nuevo tiene al menos un test
|
|
231
|
+
- [ ] Tests usan @DisplayName descriptivo en español
|
|
232
|
+
- [ ] Patrón AAA aplicado con separación visual clara
|
|
233
|
+
- [ ] Mocks con Mockito — sin PowerMock
|
|
234
|
+
- [ ] Assertions con AssertJ — sin assertEquals de JUnit
|
|
235
|
+
- [ ] Tests de integración con TestContainers (no H2)
|
|
236
|
+
- [ ] Casos parametrizados usan @ParameterizedTest
|
|
237
|
+
- [ ] Cobertura del módulo >= 80% en reporte JaCoCo
|
|
238
|
+
- [ ] Sin Thread.sleep() en tests
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Regla: Estilo de Código Kotlin
|
|
2
|
+
|
|
3
|
+
Esta regla es OBLIGATORIA para todo código Kotlin nuevo o modificado.
|
|
4
|
+
Kotlin ofrece construcciones que eliminan verbosidad y reducen bugs por diseño.
|
|
5
|
+
Usarlas no es opcional: `val` sobre `var`, null safety real, y coroutines sobre callbacks.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Linters obligatorios: ktlint y Detekt
|
|
10
|
+
|
|
11
|
+
- **ktlint** verifica formato y convenciones del lenguaje. Corre en CI como verificación bloqueante.
|
|
12
|
+
- **Detekt** analiza complejidad, code smells y anti-patrones. Falla con severidad `error`.
|
|
13
|
+
- Configurar el IDE para aplicar ktlint al guardar. No formatear manualmente.
|
|
14
|
+
|
|
15
|
+
```kotlin
|
|
16
|
+
// build.gradle.kts
|
|
17
|
+
plugins {
|
|
18
|
+
id("org.jlleitschuh.gradle.ktlint") version "12.1.0"
|
|
19
|
+
id("io.gitlab.arturbosch.detekt") version "1.23.6"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
detekt {
|
|
23
|
+
config.setFrom("$rootDir/config/detekt.yml")
|
|
24
|
+
buildUponDefaultConfig = true
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## val sobre var: inmutabilidad por defecto
|
|
31
|
+
|
|
32
|
+
Declarar `val` siempre que el valor no cambie después de la asignación.
|
|
33
|
+
`var` solo cuando la mutabilidad es estrictamente necesaria y documentada.
|
|
34
|
+
|
|
35
|
+
```kotlin
|
|
36
|
+
// MAL — var donde el valor nunca se reasigna
|
|
37
|
+
var nombre = "Juan"
|
|
38
|
+
var total = calcularTotal(items)
|
|
39
|
+
|
|
40
|
+
// BIEN — val comunica que no cambia
|
|
41
|
+
val nombre = "Juan"
|
|
42
|
+
val total = calcularTotal(items)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## data class para DTOs, sealed class para estados
|
|
48
|
+
|
|
49
|
+
```kotlin
|
|
50
|
+
// BIEN — data class para transportar datos (equals, hashCode, copy gratis)
|
|
51
|
+
data class UsuarioDto(
|
|
52
|
+
val id: UUID,
|
|
53
|
+
val nombre: String,
|
|
54
|
+
val email: String,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
// BIEN — sealed class para estados cerrados con when exhaustivo
|
|
58
|
+
sealed class EstadoPedido {
|
|
59
|
+
data class Procesando(val progreso: Int) : EstadoPedido()
|
|
60
|
+
data class Completado(val transaccionId: String) : EstadoPedido()
|
|
61
|
+
data class Error(val mensaje: String) : EstadoPedido()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// MAL — String o constantes enteras para estados
|
|
65
|
+
const val ESTADO_PROCESANDO = 1
|
|
66
|
+
const val ESTADO_COMPLETADO = 2
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Null safety: nunca !! en producción
|
|
72
|
+
|
|
73
|
+
El operador `!!` es una bomba de tiempo. Lanza `NullPointerException` en runtime.
|
|
74
|
+
Usar `?.`, `?:`, `let`, o `requireNotNull` con mensaje descriptivo.
|
|
75
|
+
|
|
76
|
+
```kotlin
|
|
77
|
+
// MAL — !! puede lanzar NPE en producción
|
|
78
|
+
val nombre = usuario!!.perfil!!.nombre
|
|
79
|
+
|
|
80
|
+
// BIEN — manejo explícito del nulo
|
|
81
|
+
val nombre = usuario?.perfil?.nombre ?: "Anónimo"
|
|
82
|
+
|
|
83
|
+
// BIEN — fallo temprano con mensaje claro cuando el nulo es inesperado
|
|
84
|
+
val usuario = repositorio.buscarPorId(id)
|
|
85
|
+
?: throw IllegalStateException("Usuario $id no encontrado")
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Detekt con la regla `ForbiddenCode` o `NullableToStringCall` debe detectar `!!` en `src/`.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## when exhaustivo para sealed classes
|
|
93
|
+
|
|
94
|
+
El compilador verifica que todos los casos están cubiertos cuando `when` es expresión.
|
|
95
|
+
|
|
96
|
+
```kotlin
|
|
97
|
+
// MAL — when como sentencia pierde exhaustividad del compilador
|
|
98
|
+
when (estado) {
|
|
99
|
+
is EstadoPedido.Procesando -> mostrarProgreso(estado.progreso)
|
|
100
|
+
is EstadoPedido.Completado -> mostrarExito()
|
|
101
|
+
// Error olvidado — el compilador no avisa
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// BIEN — when como expresion fuerza exhaustividad
|
|
105
|
+
val mensaje: String = when (estado) {
|
|
106
|
+
is EstadoPedido.Procesando -> "Procesando ${estado.progreso}%"
|
|
107
|
+
is EstadoPedido.Completado -> "Completado: ${estado.transaccionId}"
|
|
108
|
+
is EstadoPedido.Error -> "Error: ${estado.mensaje}"
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Extension functions para enriquecer tipos sin herencia
|
|
115
|
+
|
|
116
|
+
```kotlin
|
|
117
|
+
// MAL — función utilitaria con receptor como parámetro
|
|
118
|
+
fun formatearFecha(fecha: LocalDate): String = ...
|
|
119
|
+
|
|
120
|
+
// BIEN — extension function: legible como llamada a método
|
|
121
|
+
fun LocalDate.formatearParaFactura(): String =
|
|
122
|
+
DateTimeFormatter.ofPattern("dd/MM/yyyy").format(this)
|
|
123
|
+
|
|
124
|
+
// Uso natural
|
|
125
|
+
val texto = fechaEmision.formatearParaFactura()
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Scope functions con criterio
|
|
131
|
+
|
|
132
|
+
| Función | Uso correcto |
|
|
133
|
+
|---------|-------------|
|
|
134
|
+
| `let` | Transformar un valor nullable o encadenar operaciones |
|
|
135
|
+
| `run` | Ejecutar bloque en contexto del objeto, retornar resultado |
|
|
136
|
+
| `with` | Operar sobre objeto sin repetir su nombre (no nullable) |
|
|
137
|
+
| `apply` | Configurar objeto y retornarlo (builders) |
|
|
138
|
+
| `also` | Efecto secundario (logging, validación) sin alterar el flujo |
|
|
139
|
+
|
|
140
|
+
```kotlin
|
|
141
|
+
// BIEN — apply para configurar
|
|
142
|
+
val intent = Intent(context, MainActivity::class.java).apply {
|
|
143
|
+
putExtra("userId", usuario.id)
|
|
144
|
+
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// MAL — anidamiento de scope functions (ilegible)
|
|
148
|
+
usuario?.let { u ->
|
|
149
|
+
u.perfil?.run {
|
|
150
|
+
with(this) { /* confusión total sobre 'this' */ }
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Máximo dos scope functions anidadas. Si se necesitan más, extraer funciones con nombre.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Coroutines: suspend funciones, no callbacks
|
|
160
|
+
|
|
161
|
+
```kotlin
|
|
162
|
+
// MAL — callback hell
|
|
163
|
+
fun obtenerUsuario(id: String, callback: (Usuario?, Error?) -> Unit) {
|
|
164
|
+
api.buscar(id) { resultado, error ->
|
|
165
|
+
if (error != null) callback(null, error)
|
|
166
|
+
else callback(resultado, null)
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// BIEN — suspend function: lineal, testeable, componible
|
|
171
|
+
suspend fun obtenerUsuario(id: String): Usuario =
|
|
172
|
+
api.buscar(id)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Nombres y límites de tamaño
|
|
178
|
+
|
|
179
|
+
- Clases e interfaces: `PascalCase`
|
|
180
|
+
- Funciones, variables y propiedades: `camelCase`
|
|
181
|
+
- Constantes (`val` en companion object o top-level): `SCREAMING_CASE`
|
|
182
|
+
- Máximo **40 líneas** por función (sin contar líneas en blanco y comentarios)
|
|
183
|
+
- Máximo **4 parámetros** por función. Si se necesitan más: data class de parámetros
|
|
184
|
+
- Single expression functions cuando el cuerpo es una sola expresión legible
|
|
185
|
+
|
|
186
|
+
```kotlin
|
|
187
|
+
// BIEN — single expression function
|
|
188
|
+
fun esAdmin(usuario: Usuario): Boolean = usuario.rol == Rol.ADMIN
|
|
189
|
+
|
|
190
|
+
// MAL — cuerpo innecesariamente expandido
|
|
191
|
+
fun esAdmin(usuario: Usuario): Boolean {
|
|
192
|
+
return usuario.rol == Rol.ADMIN
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Checklist de estilo Kotlin antes de abrir PR
|
|
199
|
+
|
|
200
|
+
- [ ] ktlint aplicado sin errores
|
|
201
|
+
- [ ] Detekt pasa con configuración del proyecto
|
|
202
|
+
- [ ] Sin `!!` en código de `src/` (solo en tests con justificación)
|
|
203
|
+
- [ ] `val` usado por defecto; `var` solo donde hay mutacion real
|
|
204
|
+
- [ ] `data class` para DTOs, `sealed class` para estados cerrados
|
|
205
|
+
- [ ] `when` sobre sealed classes es expresion (no sentencia)
|
|
206
|
+
- [ ] Funciones <= 40 líneas
|
|
207
|
+
- [ ] Sin callbacks: usar `suspend` functions y coroutines
|
|
208
|
+
- [ ] Sin scope functions anidadas más de dos niveles
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Regla: Hooks de Calidad para Kotlin
|
|
2
|
+
|
|
3
|
+
Esta regla define las verificaciones automáticas obligatorias que corren en cada
|
|
4
|
+
commit y merge para código Kotlin. Los hooks detectan errores en segundos —
|
|
5
|
+
mucho antes de que lleguen a code review o a producción.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ktlint --format antes de commit (pre-commit hook)
|
|
10
|
+
|
|
11
|
+
ktlint verifica y corrige formato automáticamente. El hook debe correr en modo
|
|
12
|
+
`--format` para aplicar correcciones, y fallar si quedan errores no autocorregibles.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
#!/bin/sh
|
|
16
|
+
# .git/hooks/pre-commit o via lefthook/husky
|
|
17
|
+
|
|
18
|
+
echo "Ejecutando ktlint..."
|
|
19
|
+
./gradlew ktlintFormat
|
|
20
|
+
|
|
21
|
+
# Verificar si ktlint introdujo cambios (reformateo)
|
|
22
|
+
if ! git diff --quiet; then
|
|
23
|
+
echo "ktlint reformateó archivos. Revisa los cambios y vuelve a hacer commit."
|
|
24
|
+
exit 1
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
./gradlew ktlintCheck
|
|
28
|
+
if [ $? -ne 0 ]; then
|
|
29
|
+
echo "ktlint encontró errores de formato no corregibles automáticamente."
|
|
30
|
+
exit 1
|
|
31
|
+
fi
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Configuración recomendada vía **Lefthook** (más rápido que husky para JVM):
|
|
35
|
+
|
|
36
|
+
```yaml
|
|
37
|
+
# lefthook.yml
|
|
38
|
+
pre-commit:
|
|
39
|
+
parallel: false
|
|
40
|
+
commands:
|
|
41
|
+
ktlint:
|
|
42
|
+
glob: "*.{kt,kts}"
|
|
43
|
+
run: ./gradlew ktlintFormat && ./gradlew ktlintCheck
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Detekt con configuración del proyecto
|
|
49
|
+
|
|
50
|
+
Detekt analiza complejidad ciclomática, código duplicado, funciones largas y
|
|
51
|
+
anti-patrones. La configuración base del proyecto define la severidad de cada regla.
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
# config/detekt.yml — reglas críticas en error
|
|
55
|
+
complexity:
|
|
56
|
+
LongMethod:
|
|
57
|
+
active: true
|
|
58
|
+
threshold: 40
|
|
59
|
+
ComplexMethod:
|
|
60
|
+
active: true
|
|
61
|
+
threshold: 10
|
|
62
|
+
|
|
63
|
+
style:
|
|
64
|
+
ForbiddenComment:
|
|
65
|
+
active: true
|
|
66
|
+
values: ['TODO:', 'FIXME:', 'HACK:']
|
|
67
|
+
|
|
68
|
+
potential-bugs:
|
|
69
|
+
UnsafeCallOnNullableType:
|
|
70
|
+
active: true # detecta !!
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
# En el hook pre-merge (no pre-commit — Detekt es más lento)
|
|
75
|
+
./gradlew detekt
|
|
76
|
+
if [ $? -ne 0 ]; then
|
|
77
|
+
echo "Detekt encontró problemas. Revisa el reporte en build/reports/detekt/"
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Gradle build antes de merge (CI obligatorio)
|
|
85
|
+
|
|
86
|
+
El build completo con tests corre en CI antes de aprobar el merge.
|
|
87
|
+
Localmente, correr al menos una vez antes de abrir el PR.
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# Pre-push hook — más lento pero evita PRs rotos
|
|
91
|
+
./gradlew build
|
|
92
|
+
if [ $? -ne 0 ]; then
|
|
93
|
+
echo "Build fallido. No se puede hacer push."
|
|
94
|
+
exit 1
|
|
95
|
+
fi
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
En CI (GitHub Actions):
|
|
99
|
+
```yaml
|
|
100
|
+
- name: Build y test
|
|
101
|
+
run: ./gradlew build koverXmlReport
|
|
102
|
+
|
|
103
|
+
- name: Verificar cobertura
|
|
104
|
+
run: ./gradlew koverVerify
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## Detección de println en código no-test
|
|
110
|
+
|
|
111
|
+
`println()` en producción contamina los logs del sistema y puede exponer datos sensibles.
|
|
112
|
+
Solo se permite en archivos bajo `src/test/`.
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
# Script de detección — corre en pre-commit
|
|
116
|
+
KOTLIN_SRC=$(git diff --cached --name-only | grep -E "^src/main.*\.kt$")
|
|
117
|
+
|
|
118
|
+
if [ -n "$KOTLIN_SRC" ]; then
|
|
119
|
+
MATCHES=$(echo "$KOTLIN_SRC" | xargs grep -l "println(" 2>/dev/null)
|
|
120
|
+
if [ -n "$MATCHES" ]; then
|
|
121
|
+
echo "ERROR: println() encontrado en código de producción:"
|
|
122
|
+
echo "$MATCHES"
|
|
123
|
+
echo "Usar Timber.d() o el logger del proyecto."
|
|
124
|
+
exit 1
|
|
125
|
+
fi
|
|
126
|
+
fi
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Alternativa vía regla Detekt personalizada o `ForbiddenMethodCall`:
|
|
130
|
+
```yaml
|
|
131
|
+
style:
|
|
132
|
+
ForbiddenMethodCall:
|
|
133
|
+
active: true
|
|
134
|
+
methods:
|
|
135
|
+
- reason: "Usar Timber o logger del proyecto"
|
|
136
|
+
value: "kotlin.io.println"
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Detección de !! (force unwrap) en src/
|
|
142
|
+
|
|
143
|
+
El operador `!!` en producción es una bomba de tiempo. Detectarlo en pre-commit
|
|
144
|
+
evita que llegue al repositorio principal.
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Detección de !! en archivos Kotlin de producción
|
|
148
|
+
KOTLIN_MAIN=$(git diff --cached --name-only | grep -E "^src/main.*\.kt$")
|
|
149
|
+
|
|
150
|
+
if [ -n "$KOTLIN_MAIN" ]; then
|
|
151
|
+
# Excluir !! dentro de comentarios y strings
|
|
152
|
+
MATCHES=$(echo "$KOTLIN_MAIN" | xargs grep -En "[^!'\"]\!\![^=]" 2>/dev/null | grep -v "//.*!!")
|
|
153
|
+
if [ -n "$MATCHES" ]; then
|
|
154
|
+
echo "ERROR: Operador !! encontrado en src/main:"
|
|
155
|
+
echo "$MATCHES"
|
|
156
|
+
echo "Usar ?., ?: o requireNotNull() con mensaje descriptivo."
|
|
157
|
+
exit 1
|
|
158
|
+
fi
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## Android Lint con severidad error
|
|
166
|
+
|
|
167
|
+
Android Lint detecta problemas específicos de Android: uso de APIs deprecadas,
|
|
168
|
+
faltantes de permisos, problemas de rendimiento en Compose, etc.
|
|
169
|
+
|
|
170
|
+
```kotlin
|
|
171
|
+
// build.gradle.kts
|
|
172
|
+
android {
|
|
173
|
+
lint {
|
|
174
|
+
abortOnError = true
|
|
175
|
+
warningsAsErrors = false // solo errors bloquean el build
|
|
176
|
+
checkDependencies = true
|
|
177
|
+
htmlReport = true
|
|
178
|
+
xmlReport = true
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Reglas de lint que DEBEN estar en severidad `error` en el proyecto:
|
|
184
|
+
- `HardcodedText` — textos sin localizar
|
|
185
|
+
- `UnusedResources` — recursos no referenciados
|
|
186
|
+
- `MissingPermission` — llamadas a APIs que requieren permisos no declarados
|
|
187
|
+
- `NewApi` — uso de API no disponible en el minSdk del proyecto
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
# En pre-merge (CI)
|
|
191
|
+
./gradlew lint
|
|
192
|
+
if [ $? -ne 0 ]; then
|
|
193
|
+
echo "Android Lint encontró errores. Ver app/build/reports/lint-results.html"
|
|
194
|
+
exit 1
|
|
195
|
+
fi
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## Configuración de Lefthook (recomendado)
|
|
201
|
+
|
|
202
|
+
Lefthook es más rápido que husky y nativo en JVM. Configuración completa:
|
|
203
|
+
|
|
204
|
+
```yaml
|
|
205
|
+
# lefthook.yml en la raíz del proyecto
|
|
206
|
+
pre-commit:
|
|
207
|
+
parallel: true
|
|
208
|
+
commands:
|
|
209
|
+
ktlint:
|
|
210
|
+
glob: "src/main/**/*.{kt,kts}"
|
|
211
|
+
run: ./gradlew ktlintFormat ktlintCheck
|
|
212
|
+
detectar-println:
|
|
213
|
+
glob: "src/main/**/*.kt"
|
|
214
|
+
run: |
|
|
215
|
+
if grep -rn "println(" {staged_files} 2>/dev/null; then
|
|
216
|
+
echo "ERROR: println() en producción. Usar el logger del proyecto."
|
|
217
|
+
exit 1
|
|
218
|
+
fi
|
|
219
|
+
detectar-force-unwrap:
|
|
220
|
+
glob: "src/main/**/*.kt"
|
|
221
|
+
run: |
|
|
222
|
+
if grep -En "[^!'\"]\!\![^=]" {staged_files} 2>/dev/null | grep -v "//"; then
|
|
223
|
+
echo "ERROR: Operador !! en producción."
|
|
224
|
+
exit 1
|
|
225
|
+
fi
|
|
226
|
+
|
|
227
|
+
pre-push:
|
|
228
|
+
commands:
|
|
229
|
+
detekt:
|
|
230
|
+
run: ./gradlew detekt
|
|
231
|
+
lint:
|
|
232
|
+
run: ./gradlew lint
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Checklist de hooks Kotlin
|
|
238
|
+
|
|
239
|
+
- [ ] ktlint configurado y corriendo en pre-commit
|
|
240
|
+
- [ ] Detekt configurado con `config/detekt.yml` del proyecto
|
|
241
|
+
- [ ] Gradle build corre en CI antes de aprobar merge
|
|
242
|
+
- [ ] Detección de `println()` activa para `src/main/`
|
|
243
|
+
- [ ] Detección de `!!` activa para `src/main/`
|
|
244
|
+
- [ ] Android Lint con `abortOnError = true`
|
|
245
|
+
- [ ] Lefthook o husky instalado y versionado en el repositorio
|