@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,362 @@
|
|
|
1
|
+
# Testing con RSpec en Rails
|
|
2
|
+
|
|
3
|
+
Referencia de configuración y patrones de testing con RSpec, FactoryBot,
|
|
4
|
+
Capybara y SimpleCov para Rails 7+.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Configuración base
|
|
9
|
+
|
|
10
|
+
```ruby
|
|
11
|
+
# spec/rails_helper.rb
|
|
12
|
+
require 'spec_helper'
|
|
13
|
+
ENV['RAILS_ENV'] ||= 'test'
|
|
14
|
+
require_relative '../config/environment'
|
|
15
|
+
abort("Entorno no es test") if Rails.env.production?
|
|
16
|
+
|
|
17
|
+
require 'rspec/rails'
|
|
18
|
+
require 'capybara/rspec'
|
|
19
|
+
require 'factory_bot_rails'
|
|
20
|
+
|
|
21
|
+
RSpec.configure do |config|
|
|
22
|
+
config.fixture_path = Rails.root.join('spec/fixtures')
|
|
23
|
+
config.use_transactional_fixtures = true
|
|
24
|
+
config.infer_spec_type_from_file_location!
|
|
25
|
+
config.filter_rails_from_backtrace!
|
|
26
|
+
|
|
27
|
+
config.include FactoryBot::Syntax::Methods
|
|
28
|
+
config.include Devise::Test::IntegrationHelpers, type: :request
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# spec/spec_helper.rb
|
|
32
|
+
require 'simplecov'
|
|
33
|
+
SimpleCov.start 'rails' do
|
|
34
|
+
add_filter '/spec/'
|
|
35
|
+
enable_coverage :branch # coverage de ramas, no solo líneas
|
|
36
|
+
minimum_coverage 90
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
RSpec.configure do |config|
|
|
40
|
+
config.expect_with(:rspec) { |c| c.syntax = :expect }
|
|
41
|
+
config.order = :random
|
|
42
|
+
config.warnings = true
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## FactoryBot — factories, traits y sequences
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
# spec/factories/users.rb
|
|
52
|
+
FactoryBot.define do
|
|
53
|
+
factory :user do
|
|
54
|
+
sequence(:email) { |n| "usuario#{n}@ejemplo.com" }
|
|
55
|
+
nombre { "Usuario de Prueba" }
|
|
56
|
+
password { "contraseña_segura_123" }
|
|
57
|
+
|
|
58
|
+
trait :admin do
|
|
59
|
+
role { :admin }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
trait :con_posts do
|
|
63
|
+
after(:create) { |user| create_list(:post, 3, author: user) }
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# spec/factories/posts.rb
|
|
69
|
+
FactoryBot.define do
|
|
70
|
+
factory :post do
|
|
71
|
+
sequence(:titulo) { |n| "Post de prueba #{n}" }
|
|
72
|
+
cuerpo { "Contenido del post de prueba" }
|
|
73
|
+
status { :publicado }
|
|
74
|
+
association :author, factory: :user
|
|
75
|
+
|
|
76
|
+
trait :borrador do
|
|
77
|
+
status { :borrador }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
trait :con_comentarios do
|
|
81
|
+
after(:create) { |post| create_list(:comment, 2, post: post) }
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
**Regla**: preferir `build` sobre `create` cuando el test no requiere persistencia
|
|
88
|
+
— es significativamente más rápido.
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
build(:post) # objeto en memoria, sin BD
|
|
92
|
+
create(:post) # persiste en BD
|
|
93
|
+
build_stubbed(:post) # objeto stub, más rápido que build para asociaciones
|
|
94
|
+
create(:post, :borrador, :con_comentarios) # traits combinados
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Tests de modelo
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
# spec/models/post_spec.rb
|
|
103
|
+
RSpec.describe Post, type: :model do
|
|
104
|
+
subject(:post) { build(:post) }
|
|
105
|
+
|
|
106
|
+
describe 'validaciones' do
|
|
107
|
+
it { is_expected.to validate_presence_of(:titulo) }
|
|
108
|
+
it { is_expected.to validate_length_of(:titulo).is_at_most(200) }
|
|
109
|
+
it { is_expected.to validate_presence_of(:cuerpo) }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe 'asociaciones' do
|
|
113
|
+
it { is_expected.to belong_to(:author).class_name('User') }
|
|
114
|
+
it { is_expected.to have_many(:comments).dependent(:destroy) }
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe 'scopes' do
|
|
118
|
+
describe '.publicados' do
|
|
119
|
+
let!(:publicado) { create(:post, status: :publicado) }
|
|
120
|
+
let!(:borrador) { create(:post, status: :borrador) }
|
|
121
|
+
|
|
122
|
+
it 'incluye solo posts publicados' do
|
|
123
|
+
expect(Post.publicados).to include(publicado)
|
|
124
|
+
expect(Post.publicados).not_to include(borrador)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Request specs para APIs (mejor que controller specs)
|
|
134
|
+
|
|
135
|
+
Los request specs prueban el stack completo de la request (middleware incluido).
|
|
136
|
+
Son la opción recomendada para APIs REST.
|
|
137
|
+
|
|
138
|
+
```ruby
|
|
139
|
+
# spec/requests/posts_spec.rb
|
|
140
|
+
RSpec.describe "Posts", type: :request do
|
|
141
|
+
let(:user) { create(:user) }
|
|
142
|
+
|
|
143
|
+
before { sign_in user }
|
|
144
|
+
|
|
145
|
+
describe "GET /posts" do
|
|
146
|
+
let!(:posts) { create_list(:post, 3, author: user) }
|
|
147
|
+
|
|
148
|
+
it "devuelve lista de posts con HTTP 200" do
|
|
149
|
+
get posts_path
|
|
150
|
+
expect(response).to have_http_status(:ok)
|
|
151
|
+
expect(response.body).to include(posts.first.titulo)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
describe "POST /posts" do
|
|
156
|
+
context "con parámetros válidos" do
|
|
157
|
+
let(:params) { { post: attributes_for(:post) } }
|
|
158
|
+
|
|
159
|
+
it "crea el post y redirige" do
|
|
160
|
+
expect { post posts_path, params: params }
|
|
161
|
+
.to change(Post, :count).by(1)
|
|
162
|
+
expect(response).to redirect_to(Post.last)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
context "con parámetros inválidos" do
|
|
167
|
+
let(:params) { { post: { titulo: "" } } }
|
|
168
|
+
|
|
169
|
+
it "no crea el post y responde 422" do
|
|
170
|
+
expect { post posts_path, params: params }
|
|
171
|
+
.not_to change(Post, :count)
|
|
172
|
+
expect(response).to have_http_status(:unprocessable_entity)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## System specs con Capybara + Selenium
|
|
182
|
+
|
|
183
|
+
Para probar flujos con JavaScript (Turbo, Stimulus).
|
|
184
|
+
|
|
185
|
+
```ruby
|
|
186
|
+
# spec/system/crear_post_spec.rb
|
|
187
|
+
RSpec.describe "Crear post", type: :system do
|
|
188
|
+
let(:user) { create(:user) }
|
|
189
|
+
|
|
190
|
+
before do
|
|
191
|
+
driven_by :selenium, using: :headless_chrome
|
|
192
|
+
sign_in user
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
it "el usuario puede crear un post y verlo en la lista" do
|
|
196
|
+
visit new_post_path
|
|
197
|
+
|
|
198
|
+
fill_in "Título", with: "Mi nuevo post"
|
|
199
|
+
fill_in "Cuerpo", with: "Contenido detallado del post"
|
|
200
|
+
click_button "Publicar"
|
|
201
|
+
|
|
202
|
+
expect(page).to have_text("Publicación creada")
|
|
203
|
+
expect(page).to have_text("Mi nuevo post")
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
it "muestra errores con parámetros inválidos" do
|
|
207
|
+
visit new_post_path
|
|
208
|
+
click_button "Publicar"
|
|
209
|
+
|
|
210
|
+
expect(page).to have_text("Título no puede estar en blanco")
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Shared examples y shared contexts
|
|
218
|
+
|
|
219
|
+
```ruby
|
|
220
|
+
# spec/support/shared_examples/authenticatable.rb
|
|
221
|
+
RSpec.shared_examples "requiere autenticación" do
|
|
222
|
+
context "sin sesión iniciada" do
|
|
223
|
+
before { sign_out :user }
|
|
224
|
+
|
|
225
|
+
it "redirige al login" do
|
|
226
|
+
subject
|
|
227
|
+
expect(response).to redirect_to(new_user_session_path)
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Uso en spec
|
|
233
|
+
RSpec.describe "Posts", type: :request do
|
|
234
|
+
describe "GET /posts/new" do
|
|
235
|
+
subject { get new_post_path }
|
|
236
|
+
it_behaves_like "requiere autenticación"
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Shared context para setup reutilizable
|
|
241
|
+
RSpec.shared_context "usuario autenticado" do
|
|
242
|
+
let(:user) { create(:user) }
|
|
243
|
+
before { sign_in user }
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
RSpec.describe "Posts", type: :request do
|
|
247
|
+
include_context "usuario autenticado"
|
|
248
|
+
end
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Mocking con instance_double y class_double
|
|
254
|
+
|
|
255
|
+
```ruby
|
|
256
|
+
# instance_double verifica que los métodos existen en la clase real
|
|
257
|
+
RSpec.describe Posts::CrearService do
|
|
258
|
+
let(:mailer) { instance_double(NotificacionMailer) }
|
|
259
|
+
|
|
260
|
+
before do
|
|
261
|
+
allow(NotificacionMailer).to receive(:nueva_publicacion).and_return(mailer)
|
|
262
|
+
allow(mailer).to receive(:deliver_later)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
it "encola notificación al crear post exitosamente" do
|
|
266
|
+
result = described_class.call(autor: create(:user), parametros: attributes_for(:post))
|
|
267
|
+
|
|
268
|
+
expect(result.exitoso?).to be true
|
|
269
|
+
expect(NotificacionMailer).to have_received(:nueva_publicacion)
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# class_double para stubs de métodos de clase
|
|
274
|
+
let(:job) { class_double(NotificarSeguidoresJob).as_stubbed_const }
|
|
275
|
+
before { allow(job).to receive(:perform_later) }
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## DatabaseCleaner
|
|
281
|
+
|
|
282
|
+
Necesario cuando se mezclan specs con `js: true` (que usan transacciones separadas).
|
|
283
|
+
|
|
284
|
+
```ruby
|
|
285
|
+
# spec/support/database_cleaner.rb
|
|
286
|
+
RSpec.configure do |config|
|
|
287
|
+
config.before(:suite) do
|
|
288
|
+
DatabaseCleaner.clean_with(:truncation)
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
config.before(:each) do
|
|
292
|
+
DatabaseCleaner.strategy = :transaction
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
config.before(:each, js: true) do
|
|
296
|
+
DatabaseCleaner.strategy = :truncation
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
config.before(:each) { DatabaseCleaner.start }
|
|
300
|
+
config.after(:each) { DatabaseCleaner.clean }
|
|
301
|
+
end
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## SimpleCov con branch coverage
|
|
307
|
+
|
|
308
|
+
```ruby
|
|
309
|
+
# spec/spec_helper.rb (ya mostrado arriba, recordatorio)
|
|
310
|
+
SimpleCov.start 'rails' do
|
|
311
|
+
add_filter '/spec/'
|
|
312
|
+
add_filter '/config/'
|
|
313
|
+
add_group 'Controllers', 'app/controllers'
|
|
314
|
+
add_group 'Models', 'app/models'
|
|
315
|
+
add_group 'Services', 'app/services'
|
|
316
|
+
add_group 'Jobs', 'app/jobs'
|
|
317
|
+
enable_coverage :branch
|
|
318
|
+
minimum_coverage 90
|
|
319
|
+
end
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Ejecutar y ver reporte:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
bundle exec rspec
|
|
326
|
+
open coverage/index.html
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## Convenciones Rubocop-RSpec
|
|
332
|
+
|
|
333
|
+
```ruby
|
|
334
|
+
# .rubocop.yml — sección RSpec
|
|
335
|
+
RSpec:
|
|
336
|
+
Max: 250 # líneas por archivo spec
|
|
337
|
+
|
|
338
|
+
RSpec/ExampleLength:
|
|
339
|
+
Max: 10 # líneas por ejemplo
|
|
340
|
+
|
|
341
|
+
RSpec/MultipleExpectations:
|
|
342
|
+
Max: 3 # expects por ejemplo
|
|
343
|
+
|
|
344
|
+
RSpec/NestedGroups:
|
|
345
|
+
Max: 4 # niveles de anidamiento describe/context
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
**Reglas de convención:**
|
|
349
|
+
- Un `describe` por clase pública, un `context` por escenario
|
|
350
|
+
- Nombrar contexts: `"cuando [condición]"`, `"con [estado]"`, `"sin [algo]"`
|
|
351
|
+
- Nombrar examples: `"[sujeto] [verbo] [resultado esperado]"`
|
|
352
|
+
- Preferir `let!` sobre `before { @var = ... }` para legibilidad
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
## Referencias externas
|
|
357
|
+
|
|
358
|
+
- [RSpec Rails — documentación](https://relishapp.com/rspec/rspec-rails/docs)
|
|
359
|
+
- [FactoryBot — guía](https://github.com/thoughtbot/factory_bot/blob/main/GETTING_STARTED.md)
|
|
360
|
+
- [Capybara — DSL](https://github.com/teamcapybara/capybara#the-dsl)
|
|
361
|
+
- [SimpleCov](https://github.com/simplecov-ruby/simplecov)
|
|
362
|
+
- [Rubocop-RSpec](https://docs.rubocop.org/rubocop-rspec/)
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react-experto
|
|
3
|
+
description: React + Next.js mejores prácticas modernas. Cubre Server Components vs Client Components, data fetching patterns (RSC, React Query, SWR, Server Actions), state management (useState, Zustand, Jotai), performance (memo, lazy, Suspense, streaming) y Next.js App Router patterns.
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
herramientasPermitidas: [Read]
|
|
6
|
+
exclusiones:
|
|
7
|
+
- "No cargar para optimización de rendimiento React (memo, useMemo, useCallback, virtualización, code splitting) — para rendimiento cargar `react-optimizacion`."
|
|
8
|
+
- "No cargar para patrones y configuraciones específicas de Next.js (App Router avanzado, middleware, ISR, layouts anidados) — para Next.js cargar `nextjs-experto`."
|
|
9
|
+
- "No cargar para Angular, Vue o Svelte — Server Components y el modelo de composición son específicos de React."
|
|
10
|
+
- "No cargar para testing React (Testing Library, Vitest, MSW) — para testing cargar `nextjs-testing`."
|
|
11
|
+
evolvable: true # default para skill estandar
|
|
12
|
+
---
|
|
13
|
+
# React Experto — React 19 + Next.js 15
|
|
14
|
+
|
|
15
|
+
## Cuándo NO cargar
|
|
16
|
+
|
|
17
|
+
- La tarea es específicamente optimización de rendimiento React: memo, useMemo, useCallback, virtualización o code splitting — cargar `react-optimizacion`.
|
|
18
|
+
- La pregunta es sobre Next.js avanzado: middleware, ISR, layouts anidados, route handlers — cargar `nextjs-experto`.
|
|
19
|
+
- El framework es Angular, Vue o Svelte — Server Components y el modelo de composición RSC son específicos de React/Next.js.
|
|
20
|
+
- La tarea es escribir tests React con Testing Library, Vitest o MSW — cargar `nextjs-testing`.
|
|
21
|
+
|
|
22
|
+
## Principio Fundamental
|
|
23
|
+
|
|
24
|
+
React moderno separa responsabilidades en dos mundos:
|
|
25
|
+
- **Server Components (RSC)**: renderizan en el servidor, acceden a datos directamente, NO tienen estado ni efectos
|
|
26
|
+
- **Client Components**: se ejecutan en el navegador, tienen estado, efectos e interactividad
|
|
27
|
+
|
|
28
|
+
La regla de oro: **por defecto todo es Server Component**. Solo se agrega `"use client"` cuando se necesita interactividad.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Reglas Obligatorias
|
|
33
|
+
|
|
34
|
+
1. **Server Component por defecto** — solo agregar `"use client"` cuando se necesita interactividad (onClick, useState, useEffect, browser APIs).
|
|
35
|
+
2. **NUNCA importar Server Component desde Client Component** — el flujo es Server -> Client (via props/children).
|
|
36
|
+
3. **NUNCA fetch en useEffect cuando RSC esta disponible** — usar Server Component con fetch directo.
|
|
37
|
+
4. **NUNCA useEffect para transformar datos** — usar `useMemo` para valores derivados.
|
|
38
|
+
5. **NUNCA key con index en listas mutables** — usar ID estable.
|
|
39
|
+
6. **Validar con Zod en Server Actions** — SIEMPRE validar server-side.
|
|
40
|
+
7. **Selectores especificos en stores** — evitar re-renders suscribiendose solo al slice necesario.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Server Components vs Client Components
|
|
45
|
+
|
|
46
|
+
### Server Component (default)
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
// app/usuarios/page.tsx — NO lleva "use client"
|
|
50
|
+
import { db } from '@/lib/db';
|
|
51
|
+
|
|
52
|
+
export default async function UsuariosPage() {
|
|
53
|
+
const usuarios = await db.usuario.findMany({ where: { activo: true } });
|
|
54
|
+
return (
|
|
55
|
+
<ul>
|
|
56
|
+
{usuarios.map(u => <li key={u.id}>{u.nombre}</li>)}
|
|
57
|
+
</ul>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Client Component
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
"use client";
|
|
66
|
+
import { useState } from 'react';
|
|
67
|
+
|
|
68
|
+
export function ContadorInteractivo() {
|
|
69
|
+
const [count, setCount] = useState(0);
|
|
70
|
+
return (
|
|
71
|
+
<button onClick={() => setCount(c => c + 1)}>Clicks: {count}</button>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Composicion correcta: RSC envuelve Client
|
|
77
|
+
|
|
78
|
+
```tsx
|
|
79
|
+
// app/dashboard/page.tsx (Server Component)
|
|
80
|
+
import { BotonFiltro } from '@/components/BotonFiltro'; // Client Component
|
|
81
|
+
import { db } from '@/lib/db';
|
|
82
|
+
|
|
83
|
+
export default async function DashboardPage() {
|
|
84
|
+
const datos = await db.reporte.findMany();
|
|
85
|
+
return <BotonFiltro datosIniciales={datos} />;
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Data Fetching — RSC Fetch (preferido)
|
|
92
|
+
|
|
93
|
+
```tsx
|
|
94
|
+
async function getDatos() {
|
|
95
|
+
const res = await fetch('https://api.ejemplo.com/datos', {
|
|
96
|
+
next: { revalidate: 60 }, // ISR: revalidar cada 60 segundos
|
|
97
|
+
});
|
|
98
|
+
if (!res.ok) throw new Error('Error al obtener datos');
|
|
99
|
+
return res.json();
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## State Management — Cuando usar que
|
|
106
|
+
|
|
107
|
+
| Herramienta | Cuando |
|
|
108
|
+
|-------------|--------|
|
|
109
|
+
| `useState` | Estado local de UI simple |
|
|
110
|
+
| `useMemo` | Valores derivados/computados |
|
|
111
|
+
| **Zustand** | Estado global ligero compartido entre componentes |
|
|
112
|
+
| **Jotai** | Estado atomico con dependencias complejas |
|
|
113
|
+
| **React Query** | Cache de datos del servidor en Client Components |
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## Performance
|
|
118
|
+
|
|
119
|
+
### React.memo — evitar re-renders innecesarios
|
|
120
|
+
|
|
121
|
+
```tsx
|
|
122
|
+
const TarjetaUsuario = React.memo(function TarjetaUsuario({ usuario }: Props) {
|
|
123
|
+
return <div>{usuario.nombre}</div>;
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### React.lazy + Suspense — code splitting
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
const EditorRich = lazy(() => import('@/components/EditorRich'));
|
|
131
|
+
|
|
132
|
+
function Pagina() {
|
|
133
|
+
return (
|
|
134
|
+
<Suspense fallback={<div>Cargando editor...</div>}>
|
|
135
|
+
<EditorRich />
|
|
136
|
+
</Suspense>
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Anti-patrones Criticos
|
|
144
|
+
|
|
145
|
+
```tsx
|
|
146
|
+
// MAL: useEffect para transformar datos
|
|
147
|
+
const [filtrados, setFiltrados] = useState([]);
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
setFiltrados(usuarios.filter(u => u.activo));
|
|
150
|
+
}, [usuarios]);
|
|
151
|
+
|
|
152
|
+
// BIEN: useMemo
|
|
153
|
+
const filtrados = useMemo(() => usuarios.filter(u => u.activo), [usuarios]);
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
```tsx
|
|
157
|
+
// MAL: fetch en Client Component cuando podria ser RSC
|
|
158
|
+
useEffect(() => {
|
|
159
|
+
fetch('/api/datos').then(r => r.json()).then(setDatos);
|
|
160
|
+
}, []);
|
|
161
|
+
|
|
162
|
+
// BIEN: Server Component con fetch directo
|
|
163
|
+
const datos = await db.datos.findMany();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
// MAL: key con index en lista mutable
|
|
168
|
+
{items.map((item, index) => <Item key={index} {...item} />)}
|
|
169
|
+
|
|
170
|
+
// BIEN: key con ID estable
|
|
171
|
+
{items.map(item => <Item key={item.id} {...item} />)}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
// MAL: componente importa librería de terceros directamente
|
|
176
|
+
import { loadStripe } from '@stripe/stripe-js';
|
|
177
|
+
import { Elements } from '@stripe/react-stripe-js';
|
|
178
|
+
|
|
179
|
+
export function Checkout() {
|
|
180
|
+
const stripe = loadStripe(process.env.NEXT_PUBLIC_STRIPE_KEY!);
|
|
181
|
+
return <Elements stripe={stripe}>...</Elements>;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// BIEN: adapter hook con interfaz estable — el componente no conoce Stripe
|
|
185
|
+
import { usePagos } from '@/hooks/usePagos';
|
|
186
|
+
|
|
187
|
+
export function Checkout() {
|
|
188
|
+
const { iniciarSesion, estado } = usePagos();
|
|
189
|
+
return <FormularioPago onSubmit={iniciarSesion} estado={estado} />;
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Toda API de terceros (Stripe, MapBox, analytics, browser APIs complejas) debe
|
|
194
|
+
envolverse en un hook adapter con interfaz estable. El componente NUNCA importa
|
|
195
|
+
la librería directamente — esto permite cambiar el proveedor sin tocar la UI.
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
Para ejemplos completos de React Query (mutations + invalidacion), Server Actions con Zod, Zustand con immer, Jotai atomico, Next.js App Router (estructura, route handlers, metadata, streaming con Suspense), ver [recursos/patrones-y-ejemplos-completos.md](recursos/patrones-y-ejemplos-completos.md).
|
|
200
|
+
|
|
201
|
+
## Gotchas / Errores comunes no obvios
|
|
202
|
+
|
|
203
|
+
**Un Client Component que importa un Server Component lo convierte en Client Component silenciosamente**: si `CartaUsuario.tsx` tiene `"use client"` e importa `FotoAvatar.tsx` (Server Component), Next.js convierte `FotoAvatar` a Client Component sin advertencia. Causa: el boundary `"use client"` se propaga hacia abajo en el árbol de importaciones. Fix: para pasar Server Components a Client Components, usar el patrón `children` o `slot` — el Client Component recibe el Server Component como prop `children`, no lo importa directamente.
|
|
204
|
+
|
|
205
|
+
**`useEffect` con array de dependencias vacío ejecuta dos veces en React 18 en modo desarrollo (StrictMode)**: React 18 con StrictMode monta, desmonta y vuelve a montar cada componente en desarrollo para detectar efectos no idempotentes. Una petición en `useEffect(fn, [])` puede dispararse dos veces. Causa: comportamiento intencional de StrictMode para detectar limpieza de efectos incorrecta. Fix: asegurarse de que el effect tiene función de cleanup correcta (ej: `return () => controller.abort()`); en producción solo se ejecuta una vez.
|
|
206
|
+
|
|
207
|
+
**Server Action que actualiza datos sin `revalidatePath` o `revalidateTag` muestra datos obsoletos**: después de un Server Action exitoso (crear/actualizar/eliminar), el cliente sigue viendo el caché anterior del RSC. Causa: Next.js cachea agresivamente los datos del servidor; los Server Actions no invalidan el caché automáticamente. Fix: llamar `revalidatePath('/ruta/afectada')` o `revalidateTag('tag-del-dato')` al final del Server Action antes de `redirect()` o `return`.
|
|
208
|
+
|
|
209
|
+
**`useState` con objeto como valor inicial no se actualiza con shallow comparison en re-renders del padre**: `useState({ nombre: '', email: '' })` inicializa el estado una sola vez — si el componente padre pasa nuevos valores como prop para reinicializar el formulario, el estado no se actualiza. Causa: `useState` solo usa el valor inicial en el primer render. Fix: usar `key` en el componente para forzar remonte cuando cambien los datos base, o usar `useEffect` con las props como dependencias para sincronizar explícitamente.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schemas/skill-evals.schema.json",
|
|
3
|
+
"skill_name": "react-experto",
|
|
4
|
+
"artifact_type": "skill",
|
|
5
|
+
"schema_version": 1,
|
|
6
|
+
"description": "Evals para react-experto — hooks, estado, patrones modernos, anti-patrones comunes.",
|
|
7
|
+
"evals": [
|
|
8
|
+
{
|
|
9
|
+
"id": 0,
|
|
10
|
+
"prompt": "Contador con botón — componente React mínimo y moderno.",
|
|
11
|
+
"files": [],
|
|
12
|
+
"expectations": [
|
|
13
|
+
"Usa `useState` hook.",
|
|
14
|
+
"Función component, no class component.",
|
|
15
|
+
"TypeScript con tipo explícito (o comentado si no aplica)."
|
|
16
|
+
],
|
|
17
|
+
"tags": ["primary-flow"]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "useeffect-deps",
|
|
21
|
+
"prompt": "Tengo `useEffect(() => { fetchData(userId); }, [])`. ¿Qué está mal?",
|
|
22
|
+
"files": [],
|
|
23
|
+
"expectations": [
|
|
24
|
+
"Falta `userId` en el array de dependencias.",
|
|
25
|
+
"La respuesta explica: stale closure — `userId` queda congelado al valor inicial.",
|
|
26
|
+
"Solución: `[userId]` como dependencia, o reconsiderar si realmente debe correr solo una vez."
|
|
27
|
+
],
|
|
28
|
+
"grading_guidance": "Failure si no identifica el problema de dependencias.",
|
|
29
|
+
"tags": ["anti-pattern"],
|
|
30
|
+
"weight": 1.5
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"id": "key-prop",
|
|
34
|
+
"prompt": "Renderizar lista con `items.map((item, i) => <Row key={i} ... />)` ¿Está bien?",
|
|
35
|
+
"files": [],
|
|
36
|
+
"expectations": [
|
|
37
|
+
"NO usar índice como key si la lista puede reordenar/filtrar.",
|
|
38
|
+
"Usar ID estable del item (`item.id`).",
|
|
39
|
+
"La respuesta explica por qué: React asocia estado al key; con índice se reasigna incorrectamente."
|
|
40
|
+
],
|
|
41
|
+
"tags": ["anti-pattern"]
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"id": "state-derivation",
|
|
45
|
+
"prompt": "Tengo `useState` para `items` y otro `useState` para `total` que es sum de items. ¿Está bien?",
|
|
46
|
+
"files": [],
|
|
47
|
+
"expectations": [
|
|
48
|
+
"NO — estado derivable no debe ser estado.",
|
|
49
|
+
"Solución: calcular `total` directamente en el render, o `useMemo` si el cálculo es costoso.",
|
|
50
|
+
"Razón: evita bugs de sincronización."
|
|
51
|
+
],
|
|
52
|
+
"tags": ["anti-pattern"]
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
}
|