@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,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: async-python
|
|
3
|
+
description: Patrones avanzados de async/await en Python. asyncio, aiohttp, SQLAlchemy async, concurrencia, semáforos, task groups, error handling en async, testing. Anti-patrones comunes de código asíncrono.
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
herramientasPermitidas: [Read]
|
|
6
|
+
exclusiones:
|
|
7
|
+
- "No cargar para paralelismo CPU-bound con múltiples núcleos — `asyncio` es monohilo y no aprovecha múltiples CPUs; para paralelismo CPU-bound usar `multiprocessing` o `concurrent.futures.ProcessPoolExecutor`."
|
|
8
|
+
- "No cargar para scripts Python de una sola ejecución sin I/O concurrente — si el script hace una sola operación I/O secuencial, `requests` síncrono es más simple y correcto que introducir asyncio."
|
|
9
|
+
- "No cargar cuando el framework ya maneja la concurrencia (FastAPI, Django Channels) y la pregunta es sobre la lógica de endpoints — en ese contexto cargar `fastapi-experto` o `django-experto` que cubren el uso de async en su framework específico."
|
|
10
|
+
- "No cargar para orquestación de agentes SWL en paralelo — ese patrón tiene semántica diferente (fire-and-forget, corrección mid-task, supervisión); cargar `orquestacion-async`."
|
|
11
|
+
evolvable: true # default para skill estandar
|
|
12
|
+
---
|
|
13
|
+
# Async Python — Patrones Avanzados
|
|
14
|
+
|
|
15
|
+
## Cuándo NO cargar
|
|
16
|
+
|
|
17
|
+
- La tarea es CPU-bound (cálculos numéricos, procesamiento de imágenes) — asyncio no paralela CPU; usar `multiprocessing`.
|
|
18
|
+
- El script hace una sola operación I/O sin concurrencia — `requests` síncrono es más simple y adecuado.
|
|
19
|
+
- La pregunta es sobre endpoints en FastAPI o Django — cargar el skill del framework que ya incorpora el contexto async correcto.
|
|
20
|
+
|
|
21
|
+
asyncio es el núcleo de I/O asíncrono en Python. Este skill cubre desde patrones básicos
|
|
22
|
+
hasta orquestación avanzada de tareas concurrentes para sistemas de producción.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Reglas Obligatorias
|
|
27
|
+
|
|
28
|
+
1. **NUNCA bloquear el event loop** con operaciones síncronas (`requests`, `time.sleep`, I/O de disco síncrono). Usar clientes async (`aiohttp`, `httpx`, `asyncio.sleep`).
|
|
29
|
+
2. **SIEMPRE usar `async with` para sesiones HTTP** — nunca dejar sesiones aiohttp sin cerrar (file descriptor leak).
|
|
30
|
+
3. **SIEMPRE usar `expire_on_commit=False`** en `async_sessionmaker` de SQLAlchemy — el default causa `MissingGreenlet` en async.
|
|
31
|
+
4. **SIEMPRE usar `selectinload`** para relaciones ORM accedidas fuera de la sesión activa.
|
|
32
|
+
5. **NUNCA llamar `asyncio.run()` dentro de una coroutine** — causa `RuntimeError: loop anidado`.
|
|
33
|
+
6. **SIEMPRE poner timeout en llamadas HTTP** — sin timeout puede colgar indefinidamente.
|
|
34
|
+
7. **Una sesión SQLAlchemy por request/task** — compartir sesiones entre tasks causa race conditions.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Fundamentos: Event Loop y Coroutines
|
|
39
|
+
|
|
40
|
+
```python
|
|
41
|
+
# MAL: bloquear el event loop con operaciones síncronas
|
|
42
|
+
async def descargar_archivo_mal(url: str) -> bytes:
|
|
43
|
+
import requests # ¡síncrono! bloquea el loop
|
|
44
|
+
return requests.get(url).content
|
|
45
|
+
|
|
46
|
+
# BIEN: usar clientes async
|
|
47
|
+
import aiohttp
|
|
48
|
+
|
|
49
|
+
async def descargar_archivo(url: str) -> bytes:
|
|
50
|
+
async with aiohttp.ClientSession() as session:
|
|
51
|
+
async with session.get(url) as response:
|
|
52
|
+
response.raise_for_status()
|
|
53
|
+
return await response.read()
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Semáforos — Control de concurrencia máxima
|
|
59
|
+
|
|
60
|
+
```python
|
|
61
|
+
# MAL: lanzar 1000 requests simultáneos sin límite
|
|
62
|
+
async def fetch_todo_mal(urls: list[str]) -> list[str]:
|
|
63
|
+
tasks = [fetch_url(url) for url in urls] # ¡sobrecarga el servidor!
|
|
64
|
+
return await asyncio.gather(*tasks)
|
|
65
|
+
|
|
66
|
+
# BIEN: limitar concurrencia con Semaphore
|
|
67
|
+
async def fetch_url_limitado(
|
|
68
|
+
session: aiohttp.ClientSession, url: str, sem: asyncio.Semaphore,
|
|
69
|
+
) -> str:
|
|
70
|
+
async with sem:
|
|
71
|
+
async with session.get(url) as resp:
|
|
72
|
+
return await resp.text()
|
|
73
|
+
|
|
74
|
+
async def fetch_todo_con_limite(urls: list[str], max_concurrente: int = 10) -> list[str]:
|
|
75
|
+
sem = asyncio.Semaphore(max_concurrente)
|
|
76
|
+
async with aiohttp.ClientSession() as session:
|
|
77
|
+
tasks = [fetch_url_limitado(session, url, sem) for url in urls]
|
|
78
|
+
return await asyncio.gather(*tasks, return_exceptions=True)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## SQLAlchemy Async — Reglas críticas
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine, async_sessionmaker
|
|
87
|
+
from sqlalchemy.orm import selectinload
|
|
88
|
+
from sqlalchemy import select
|
|
89
|
+
|
|
90
|
+
engine = create_async_engine(
|
|
91
|
+
"postgresql+asyncpg://user:pass@localhost/db",
|
|
92
|
+
pool_size=20, max_overflow=0, pool_pre_ping=True,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
AsyncSessionLocal = async_sessionmaker(
|
|
96
|
+
engine, expire_on_commit=False, class_=AsyncSession, # CRÍTICO
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
# REGLA: selectinload SIEMPRE para relaciones accedidas fuera de la sesión
|
|
100
|
+
async def obtener_usuario_con_roles(db: AsyncSession, usuario_id: str) -> Usuario:
|
|
101
|
+
stmt = (
|
|
102
|
+
select(Usuario).where(Usuario.id == usuario_id)
|
|
103
|
+
.options(selectinload(Usuario.roles), selectinload(Usuario.departamento))
|
|
104
|
+
)
|
|
105
|
+
result = await db.execute(stmt)
|
|
106
|
+
return result.scalar_one_or_none()
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Timeouts y Cancelación
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
# BIEN: timeout en múltiples niveles
|
|
115
|
+
async def llamar_api(url: str, timeout_seg: float = 5.0) -> dict:
|
|
116
|
+
try:
|
|
117
|
+
async with asyncio.timeout(timeout_seg):
|
|
118
|
+
async with aiohttp.ClientSession() as s:
|
|
119
|
+
async with s.get(url, timeout=aiohttp.ClientTimeout(total=timeout_seg)) as r:
|
|
120
|
+
r.raise_for_status()
|
|
121
|
+
return await r.json()
|
|
122
|
+
except asyncio.TimeoutError:
|
|
123
|
+
raise TimeoutError(f"La API no respondió en {timeout_seg}s: {url}")
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Anti-patrones Comunes
|
|
129
|
+
|
|
130
|
+
| Anti-patrón | Consecuencia | Corrección |
|
|
131
|
+
|-------------|-------------|------------|
|
|
132
|
+
| Llamar función síncrona bloqueante en coroutine | Bloquea event loop completo | `loop.run_in_executor(None, func)` |
|
|
133
|
+
| Crear engine SQLAlchemy dentro de coroutine | Conexiones huérfanas | Engine singleton a nivel de módulo |
|
|
134
|
+
| `await` dentro de list comprehension sin gather | Ejecución secuencial (lenta) | `asyncio.gather(*[coro(x) for x in xs])` |
|
|
135
|
+
| No cerrar sesiones aiohttp | File descriptor leak | Siempre `async with ClientSession()` |
|
|
136
|
+
| `asyncio.run()` dentro de coroutine | RuntimeError: loop anidado | Solo llamar en código síncrono top-level |
|
|
137
|
+
| Compartir objetos de sesión SQLAlchemy entre tasks | Race conditions | Una sesión por request/task |
|
|
138
|
+
| `expire_on_commit=True` (default) con async | Lazy-load fuera de sesión falla | `expire_on_commit=False` en async |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
Para ejemplos completos de gather, TaskGroup, queues async, context managers, error handling con reintento, testing async y service HTTP con pool de conexiones, ver [recursos/patrones-y-ejemplos-completos.md](recursos/patrones-y-ejemplos-completos.md).
|
|
143
|
+
|
|
144
|
+
## Gotchas / Errores comunes no obvios
|
|
145
|
+
|
|
146
|
+
- **`asyncio.gather()` con `return_exceptions=False` (default) cancela silenciosamente tareas exitosas cuando una falla**: si una de las coroutines lanza excepción, `gather` cancela el resto y la excepción se propaga, pero las tareas ya en progreso pueden dejar estado parcial. Causa: `return_exceptions=False` propaga la primera excepción inmediatamente y cancela el `gather`, pero no espera a que las tasks canceladas hagan cleanup. Solución: usar `return_exceptions=True` para obtener todos los resultados/excepciones, o `asyncio.TaskGroup` (Python 3.11+) que garantiza que todas las tasks se completan antes de propagar errores.
|
|
147
|
+
- **`loop.run_in_executor(None, func_sincrona)` bloquea el event loop cuando se llama con alta frecuencia**: el executor por defecto es un `ThreadPoolExecutor` con un número limitado de workers (CPU count × 5). Causa: si se hacen 1000 llamadas simultáneas a `run_in_executor`, las threads se agotan y las nuevas tasks quedan en cola, bloqueando el event loop. Solución: crear un executor explícito con el número de workers apropiado: `executor = ThreadPoolExecutor(max_workers=50)` y pasarlo como primer argumento a `run_in_executor`.
|
|
148
|
+
- **`async with aiohttp.ClientSession()` creado dentro de la coroutine crea y destruye la sesión en cada llamada, anulando los beneficios del pooling**: la sesión aiohttp mantiene un pool de conexiones TCP — si se crea una sesión nueva por cada request, no hay pooling. Causa: la sesión es liviana de crear pero destruye las conexiones keepalive al hacer `await session.close()`. Solución: crear la sesión como singleton a nivel de módulo o en el lifespan de la app (`async with aiohttp.ClientSession() as session:` en el contexto de arranque, no en cada handler).
|
|
149
|
+
- **`await asyncio.sleep(0)` en un bucle no es suficiente para que otras coroutines corran si el bucle hace I/O bloqueante entre los sleeps**: el `sleep(0)` cede el control al event loop pero si la siguiente operación es síncrona/bloqueante, el loop queda bloqueado de nuevo. Causa: `asyncio.sleep(0)` es un yield point que permite al event loop ejecutar callbacks pendientes, pero si la operación siguiente es síncrona, el bloqueo reaparece inmediatamente. Solución: identificar la operación I/O bloqueante con `asyncio.run()` + `--profile` o usar `asyncio.iscoroutinefunction()` para verificar que las funciones llamadas son realmente async.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schemas/skill-evals.schema.json",
|
|
3
|
+
"skill_name": "async-python",
|
|
4
|
+
"artifact_type": "skill",
|
|
5
|
+
"schema_version": 1,
|
|
6
|
+
"description": "Evals para async-python — asyncio, patrones correctos de concurrencia, SQLAlchemy async.",
|
|
7
|
+
"evals": [
|
|
8
|
+
{
|
|
9
|
+
"id": 0,
|
|
10
|
+
"prompt": "Ejecutar 3 requests HTTP concurrentemente con httpx async — snippet minimal.",
|
|
11
|
+
"files": [],
|
|
12
|
+
"expectations": [
|
|
13
|
+
"Usa `asyncio.gather(...)` (no secuencial).",
|
|
14
|
+
"Usa `async with httpx.AsyncClient()` (no sync Client).",
|
|
15
|
+
"NO mezcla `requests` con async."
|
|
16
|
+
],
|
|
17
|
+
"tags": ["primary-flow", "concurrency"],
|
|
18
|
+
"weight": 1.5
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "sqlalchemy-relationship",
|
|
22
|
+
"prompt": "En SQLAlchemy async, tengo `class User: orders = relationship('Order')`. ¿Qué necesito para serializar `user.orders` con Pydantic?",
|
|
23
|
+
"files": [],
|
|
24
|
+
"expectations": [
|
|
25
|
+
"La respuesta menciona `selectinload(User.orders)` en el query.",
|
|
26
|
+
"La respuesta menciona el error `MissingGreenlet` si no se carga eagerly.",
|
|
27
|
+
"La respuesta menciona `lazy='selectin'` como alternativa si es relación frecuente."
|
|
28
|
+
],
|
|
29
|
+
"grading_guidance": "Failure si no menciona selectinload o MissingGreenlet.",
|
|
30
|
+
"tags": ["sqlalchemy", "anti-pattern"],
|
|
31
|
+
"weight": 2.0
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "anti-pattern-sync-in-async",
|
|
35
|
+
"prompt": "¿Qué pasa si llamo `time.sleep(5)` dentro de un `async def`?",
|
|
36
|
+
"files": [],
|
|
37
|
+
"expectations": [
|
|
38
|
+
"La respuesta identifica que bloquea el event loop entero.",
|
|
39
|
+
"La respuesta da la solución: `await asyncio.sleep(5)`.",
|
|
40
|
+
"La respuesta menciona que cualquier llamada sync bloqueante tiene este problema (open, requests, time.sleep)."
|
|
41
|
+
],
|
|
42
|
+
"grading_guidance": "Failure si sugiere que `time.sleep` funciona en async.",
|
|
43
|
+
"tags": ["anti-pattern"],
|
|
44
|
+
"weight": 1.5
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# Async Python — Patrones y Ejemplos Completos
|
|
2
|
+
|
|
3
|
+
Referencia extendida de la skill `async-python`. Contiene ejemplos de código completos
|
|
4
|
+
y patrones avanzados que complementan las instrucciones principales en SKILL.md.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## asyncio.gather — Concurrencia de tareas independientes
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
import asyncio
|
|
12
|
+
import aiohttp
|
|
13
|
+
from typing import NamedTuple
|
|
14
|
+
|
|
15
|
+
class ResultadoAPI(NamedTuple):
|
|
16
|
+
url: str
|
|
17
|
+
datos: dict | None
|
|
18
|
+
error: str | None
|
|
19
|
+
|
|
20
|
+
async def fetch_json(session: aiohttp.ClientSession, url: str) -> dict:
|
|
21
|
+
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp:
|
|
22
|
+
resp.raise_for_status()
|
|
23
|
+
return await resp.json()
|
|
24
|
+
|
|
25
|
+
async def fetch_multiples(urls: list[str]) -> list[ResultadoAPI]:
|
|
26
|
+
"""Descarga múltiples URLs concurrentemente con manejo de errores individual."""
|
|
27
|
+
async with aiohttp.ClientSession() as session:
|
|
28
|
+
tasks = [fetch_json(session, url) for url in urls]
|
|
29
|
+
# return_exceptions=True evita que un error cancele todas las tareas
|
|
30
|
+
resultados = await asyncio.gather(*tasks, return_exceptions=True)
|
|
31
|
+
|
|
32
|
+
return [
|
|
33
|
+
ResultadoAPI(
|
|
34
|
+
url=url,
|
|
35
|
+
datos=r if not isinstance(r, Exception) else None,
|
|
36
|
+
error=str(r) if isinstance(r, Exception) else None,
|
|
37
|
+
)
|
|
38
|
+
for url, r in zip(urls, resultados)
|
|
39
|
+
]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## asyncio.TaskGroup — Python 3.11+
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import asyncio
|
|
48
|
+
from contextlib import asynccontextmanager
|
|
49
|
+
|
|
50
|
+
async def procesar_lote(ids: list[int]) -> list[dict]:
|
|
51
|
+
"""TaskGroup cancela TODAS las tareas si una falla — comportamiento más seguro."""
|
|
52
|
+
resultados: list[dict] = []
|
|
53
|
+
|
|
54
|
+
async with asyncio.TaskGroup() as tg:
|
|
55
|
+
tasks = [
|
|
56
|
+
tg.create_task(obtener_registro(id_), name=f"registro-{id_}")
|
|
57
|
+
for id_ in ids
|
|
58
|
+
]
|
|
59
|
+
return [t.result() for t in tasks]
|
|
60
|
+
|
|
61
|
+
async def obtener_registro(id_: int) -> dict:
|
|
62
|
+
await asyncio.sleep(0.1) # Simular I/O
|
|
63
|
+
return {"id": id_, "nombre": f"Registro {id_}"}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Context Managers Asíncronos
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from contextlib import asynccontextmanager
|
|
72
|
+
import asyncio
|
|
73
|
+
|
|
74
|
+
@asynccontextmanager
|
|
75
|
+
async def cronometro(nombre: str):
|
|
76
|
+
"""Context manager async para medir tiempos."""
|
|
77
|
+
inicio = asyncio.get_event_loop().time()
|
|
78
|
+
try:
|
|
79
|
+
yield
|
|
80
|
+
finally:
|
|
81
|
+
elapsed = asyncio.get_event_loop().time() - inicio
|
|
82
|
+
print(f"[{nombre}] tardó {elapsed:.3f}s")
|
|
83
|
+
|
|
84
|
+
# Uso
|
|
85
|
+
async def proceso_pesado():
|
|
86
|
+
async with cronometro("importación de nómina"):
|
|
87
|
+
await importar_nomina()
|
|
88
|
+
|
|
89
|
+
# Inicialización y cierre de recursos (FastAPI lifespan)
|
|
90
|
+
@asynccontextmanager
|
|
91
|
+
async def lifespan(app: FastAPI):
|
|
92
|
+
# Startup
|
|
93
|
+
await engine.connect()
|
|
94
|
+
await redis_client.ping()
|
|
95
|
+
yield
|
|
96
|
+
# Shutdown
|
|
97
|
+
await engine.dispose()
|
|
98
|
+
await redis_client.close()
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Queues Async — Productor/Consumidor
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
import asyncio
|
|
107
|
+
from dataclasses import dataclass
|
|
108
|
+
from typing import Callable, Awaitable
|
|
109
|
+
|
|
110
|
+
@dataclass
|
|
111
|
+
class Tarea:
|
|
112
|
+
id: int
|
|
113
|
+
payload: dict
|
|
114
|
+
|
|
115
|
+
async def productor(queue: asyncio.Queue, tareas: list[Tarea]) -> None:
|
|
116
|
+
for tarea in tareas:
|
|
117
|
+
await queue.put(tarea)
|
|
118
|
+
await queue.put(None)
|
|
119
|
+
|
|
120
|
+
async def consumidor(
|
|
121
|
+
queue: asyncio.Queue,
|
|
122
|
+
procesar: Callable[[Tarea], Awaitable[None]],
|
|
123
|
+
worker_id: int,
|
|
124
|
+
) -> None:
|
|
125
|
+
while True:
|
|
126
|
+
tarea = await queue.get()
|
|
127
|
+
if tarea is None:
|
|
128
|
+
queue.task_done()
|
|
129
|
+
break
|
|
130
|
+
try:
|
|
131
|
+
await procesar(tarea)
|
|
132
|
+
except Exception as e:
|
|
133
|
+
print(f"[Worker {worker_id}] Error en tarea {tarea.id}: {e}")
|
|
134
|
+
finally:
|
|
135
|
+
queue.task_done()
|
|
136
|
+
|
|
137
|
+
async def pipeline_tareas(
|
|
138
|
+
tareas: list[Tarea],
|
|
139
|
+
procesar: Callable[[Tarea], Awaitable[None]],
|
|
140
|
+
num_workers: int = 5,
|
|
141
|
+
max_queue: int = 100,
|
|
142
|
+
) -> None:
|
|
143
|
+
queue: asyncio.Queue = asyncio.Queue(maxsize=max_queue)
|
|
144
|
+
|
|
145
|
+
async with asyncio.TaskGroup() as tg:
|
|
146
|
+
tg.create_task(productor(queue, tareas))
|
|
147
|
+
for i in range(num_workers):
|
|
148
|
+
tg.create_task(consumidor(queue, procesar, worker_id=i))
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Error Handling — Reintento con backoff exponencial
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
import asyncio
|
|
157
|
+
import logging
|
|
158
|
+
from typing import TypeVar, Callable, Awaitable
|
|
159
|
+
|
|
160
|
+
logger = logging.getLogger(__name__)
|
|
161
|
+
T = TypeVar("T")
|
|
162
|
+
|
|
163
|
+
async def reintentar(
|
|
164
|
+
func: Callable[[], Awaitable[T]],
|
|
165
|
+
max_intentos: int = 3,
|
|
166
|
+
delay_base: float = 1.0,
|
|
167
|
+
errores_reintentables: tuple[type[Exception], ...] = (Exception,),
|
|
168
|
+
) -> T:
|
|
169
|
+
ultimo_error: Exception | None = None
|
|
170
|
+
for intento in range(1, max_intentos + 1):
|
|
171
|
+
try:
|
|
172
|
+
return await func()
|
|
173
|
+
except errores_reintentables as e:
|
|
174
|
+
ultimo_error = e
|
|
175
|
+
if intento < max_intentos:
|
|
176
|
+
delay = delay_base * (2 ** (intento - 1))
|
|
177
|
+
logger.warning(
|
|
178
|
+
"Intento %d/%d falló (%s). Reintentando en %.1fs",
|
|
179
|
+
intento, max_intentos, e, delay,
|
|
180
|
+
)
|
|
181
|
+
await asyncio.sleep(delay)
|
|
182
|
+
raise ultimo_error # type: ignore[misc]
|
|
183
|
+
|
|
184
|
+
# Uso
|
|
185
|
+
async def obtener_datos_con_reintento(id_: str) -> dict:
|
|
186
|
+
return await reintentar(
|
|
187
|
+
lambda: fetch_json(f"/api/datos/{id_}"),
|
|
188
|
+
max_intentos=3,
|
|
189
|
+
errores_reintentables=(aiohttp.ClientError, asyncio.TimeoutError),
|
|
190
|
+
)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## Testing de Código Async
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
import pytest
|
|
199
|
+
import asyncio
|
|
200
|
+
from unittest.mock import AsyncMock, patch
|
|
201
|
+
|
|
202
|
+
# pytest-asyncio — configuración en pyproject.toml
|
|
203
|
+
# [tool.pytest.ini_options]
|
|
204
|
+
# asyncio_mode = "auto"
|
|
205
|
+
|
|
206
|
+
@pytest.fixture
|
|
207
|
+
async def db_session():
|
|
208
|
+
"""Fixture async con rollback automático."""
|
|
209
|
+
async with TestingSessionLocal() as session:
|
|
210
|
+
async with session.begin():
|
|
211
|
+
yield session
|
|
212
|
+
await session.rollback() # Siempre limpiar
|
|
213
|
+
|
|
214
|
+
@pytest.mark.asyncio
|
|
215
|
+
async def test_obtener_usuario_con_roles(db_session):
|
|
216
|
+
# Arrange
|
|
217
|
+
usuario = await crear_usuario_fixture(db_session, roles=["ADMIN"])
|
|
218
|
+
|
|
219
|
+
# Act
|
|
220
|
+
resultado = await obtener_usuario_con_roles(db_session, usuario.id)
|
|
221
|
+
|
|
222
|
+
# Assert
|
|
223
|
+
assert resultado.id == usuario.id
|
|
224
|
+
assert len(resultado.roles) == 1
|
|
225
|
+
assert resultado.roles[0].nombre == "ADMIN"
|
|
226
|
+
|
|
227
|
+
# Mock de llamadas HTTP
|
|
228
|
+
@pytest.mark.asyncio
|
|
229
|
+
async def test_fetch_url_reintenta_en_error():
|
|
230
|
+
llamadas = 0
|
|
231
|
+
|
|
232
|
+
async def mock_get(*args, **kwargs):
|
|
233
|
+
nonlocal llamadas
|
|
234
|
+
llamadas += 1
|
|
235
|
+
if llamadas < 3:
|
|
236
|
+
raise aiohttp.ClientError("Fallo temporal")
|
|
237
|
+
return MockResponse(status=200, data={"ok": True})
|
|
238
|
+
|
|
239
|
+
with patch("aiohttp.ClientSession.get", side_effect=mock_get):
|
|
240
|
+
resultado = await obtener_datos_con_reintento("123")
|
|
241
|
+
|
|
242
|
+
assert resultado == {"ok": True}
|
|
243
|
+
assert llamadas == 3
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Receta: Service HTTP con Pool de Conexiones
|
|
249
|
+
|
|
250
|
+
```python
|
|
251
|
+
import asyncio
|
|
252
|
+
import aiohttp
|
|
253
|
+
from typing import Any
|
|
254
|
+
|
|
255
|
+
class ClienteHTTP:
|
|
256
|
+
"""Cliente HTTP reutilizable con pool de conexiones."""
|
|
257
|
+
|
|
258
|
+
def __init__(self, base_url: str, max_conexiones: int = 20):
|
|
259
|
+
self._base_url = base_url.rstrip("/")
|
|
260
|
+
self._connector = aiohttp.TCPConnector(limit=max_conexiones)
|
|
261
|
+
self._session: aiohttp.ClientSession | None = None
|
|
262
|
+
|
|
263
|
+
async def __aenter__(self) -> "ClienteHTTP":
|
|
264
|
+
self._session = aiohttp.ClientSession(
|
|
265
|
+
connector=self._connector,
|
|
266
|
+
timeout=aiohttp.ClientTimeout(total=30),
|
|
267
|
+
headers={"Content-Type": "application/json"},
|
|
268
|
+
)
|
|
269
|
+
return self
|
|
270
|
+
|
|
271
|
+
async def __aexit__(self, *args: Any) -> None:
|
|
272
|
+
if self._session:
|
|
273
|
+
await self._session.close()
|
|
274
|
+
await self._connector.close()
|
|
275
|
+
|
|
276
|
+
async def get(self, path: str, **kwargs: Any) -> dict:
|
|
277
|
+
assert self._session, "Usar dentro de 'async with ClienteHTTP()'"
|
|
278
|
+
url = f"{self._base_url}/{path.lstrip('/')}"
|
|
279
|
+
async with self._session.get(url, **kwargs) as resp:
|
|
280
|
+
resp.raise_for_status()
|
|
281
|
+
return await resp.json()
|
|
282
|
+
|
|
283
|
+
# Uso en FastAPI startup
|
|
284
|
+
cliente_sap: ClienteHTTP | None = None
|
|
285
|
+
|
|
286
|
+
@asynccontextmanager
|
|
287
|
+
async def lifespan(app: FastAPI):
|
|
288
|
+
global cliente_sap
|
|
289
|
+
async with ClienteHTTP("https://sap.empresa.com.mx/api") as client:
|
|
290
|
+
cliente_sap = client
|
|
291
|
+
yield
|
|
292
|
+
```
|