@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,341 @@
|
|
|
1
|
+
# Frontend Avanzado — Ejemplos Completos de APIs Nativas
|
|
2
|
+
|
|
3
|
+
Implementaciones completas de Web Workers, Service Workers, WebSockets, SSE, IndexedDB,
|
|
4
|
+
Container Queries, CSS Layers y View Transitions.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Web Workers — Comunicación Tipada Completa
|
|
9
|
+
|
|
10
|
+
```typescript
|
|
11
|
+
// estadisticas.worker.ts
|
|
12
|
+
/// <reference lib="webworker" />
|
|
13
|
+
|
|
14
|
+
interface MensajeEntrada {
|
|
15
|
+
tipo: "CALCULAR";
|
|
16
|
+
datos: number[];
|
|
17
|
+
id: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface MensajeSalida {
|
|
21
|
+
tipo: "RESULTADO" | "ERROR" | "PROGRESO";
|
|
22
|
+
id: string;
|
|
23
|
+
payload: EstadisticasResultado | string | number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
self.addEventListener("message", (event: MessageEvent<MensajeEntrada>) => {
|
|
27
|
+
const { tipo, datos, id } = event.data;
|
|
28
|
+
|
|
29
|
+
if (tipo === "CALCULAR") {
|
|
30
|
+
try {
|
|
31
|
+
const total = datos.length;
|
|
32
|
+
const correlaciones: number[] = [];
|
|
33
|
+
|
|
34
|
+
for (let i = 0; i < total; i++) {
|
|
35
|
+
for (let j = i + 1; j < total; j++) {
|
|
36
|
+
correlaciones.push(calcularCorrelacion(datos[i], datos[j]));
|
|
37
|
+
}
|
|
38
|
+
if (i % Math.floor(total / 10) === 0) {
|
|
39
|
+
self.postMessage({
|
|
40
|
+
tipo: "PROGRESO", id,
|
|
41
|
+
payload: Math.round((i / total) * 100),
|
|
42
|
+
} satisfies MensajeSalida);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
self.postMessage({
|
|
47
|
+
tipo: "RESULTADO", id,
|
|
48
|
+
payload: { correlaciones, promedio: datos.reduce((s, n) => s + n, 0) / total },
|
|
49
|
+
} satisfies MensajeSalida);
|
|
50
|
+
} catch (e) {
|
|
51
|
+
self.postMessage({ tipo: "ERROR", id, payload: String(e) } satisfies MensajeSalida);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// servicio-worker.service.ts (Angular)
|
|
57
|
+
@Injectable({ providedIn: "root" })
|
|
58
|
+
export class ServicioEstadisticas {
|
|
59
|
+
private worker = new Worker(
|
|
60
|
+
new URL("../workers/estadisticas.worker", import.meta.url),
|
|
61
|
+
{ type: "module" }
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
calcular(datos: number[]): Observable<EstadisticasResultado> {
|
|
65
|
+
const id = crypto.randomUUID();
|
|
66
|
+
|
|
67
|
+
return new Observable(observer => {
|
|
68
|
+
const manejador = (event: MessageEvent<MensajeSalida>) => {
|
|
69
|
+
if (event.data.id !== id) return;
|
|
70
|
+
switch (event.data.tipo) {
|
|
71
|
+
case "PROGRESO": break;
|
|
72
|
+
case "RESULTADO":
|
|
73
|
+
observer.next(event.data.payload as EstadisticasResultado);
|
|
74
|
+
observer.complete();
|
|
75
|
+
this.worker.removeEventListener("message", manejador);
|
|
76
|
+
break;
|
|
77
|
+
case "ERROR":
|
|
78
|
+
observer.error(new Error(event.data.payload as string));
|
|
79
|
+
this.worker.removeEventListener("message", manejador);
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
this.worker.addEventListener("message", manejador);
|
|
84
|
+
this.worker.postMessage({ tipo: "CALCULAR", datos, id });
|
|
85
|
+
return () => this.worker.removeEventListener("message", manejador);
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Service Workers — Estrategias de Cache
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
// service-worker.ts
|
|
97
|
+
const CACHE_VERSION = "v3";
|
|
98
|
+
const CACHE_ESTATICO = `estatico-${CACHE_VERSION}`;
|
|
99
|
+
const CACHE_DINAMICO = `dinamico-${CACHE_VERSION}`;
|
|
100
|
+
|
|
101
|
+
const RECURSOS_PRECACHEADOS = ["/", "/manifest.json", "/offline.html"];
|
|
102
|
+
|
|
103
|
+
self.addEventListener("install", (event: ExtendableEvent) => {
|
|
104
|
+
event.waitUntil(
|
|
105
|
+
caches.open(CACHE_ESTATICO).then(cache => cache.addAll(RECURSOS_PRECACHEADOS))
|
|
106
|
+
);
|
|
107
|
+
(self as ServiceWorkerGlobalScope).skipWaiting();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
self.addEventListener("activate", (event: ExtendableEvent) => {
|
|
111
|
+
event.waitUntil(
|
|
112
|
+
caches.keys().then(claves =>
|
|
113
|
+
Promise.all(
|
|
114
|
+
claves
|
|
115
|
+
.filter(c => c !== CACHE_ESTATICO && c !== CACHE_DINAMICO)
|
|
116
|
+
.map(c => caches.delete(c))
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
(self as ServiceWorkerGlobalScope).clients.claim();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
self.addEventListener("fetch", (event: FetchEvent) => {
|
|
124
|
+
const { request } = event;
|
|
125
|
+
const url = new URL(request.url);
|
|
126
|
+
|
|
127
|
+
if (url.pathname.startsWith("/api/")) {
|
|
128
|
+
event.respondWith(networkFirst(request));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (request.destination === "image" || url.pathname.endsWith(".js")) {
|
|
132
|
+
event.respondWith(cacheFirst(request));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
event.respondWith(staleWhileRevalidate(request));
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
async function networkFirst(request: Request): Promise<Response> {
|
|
139
|
+
try {
|
|
140
|
+
const respuesta = await fetch(request.clone());
|
|
141
|
+
const cache = await caches.open(CACHE_DINAMICO);
|
|
142
|
+
cache.put(request, respuesta.clone());
|
|
143
|
+
return respuesta;
|
|
144
|
+
} catch {
|
|
145
|
+
const cached = await caches.match(request);
|
|
146
|
+
return cached ?? caches.match("/offline.html") as Promise<Response>;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function cacheFirst(request: Request): Promise<Response> {
|
|
151
|
+
const cached = await caches.match(request);
|
|
152
|
+
if (cached) return cached;
|
|
153
|
+
const respuesta = await fetch(request);
|
|
154
|
+
const cache = await caches.open(CACHE_DINAMICO);
|
|
155
|
+
cache.put(request, respuesta.clone());
|
|
156
|
+
return respuesta;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function staleWhileRevalidate(request: Request): Promise<Response> {
|
|
160
|
+
const cache = await caches.open(CACHE_DINAMICO);
|
|
161
|
+
const cached = await caches.match(request);
|
|
162
|
+
const fetchPromise = fetch(request).then(respuesta => {
|
|
163
|
+
cache.put(request, respuesta.clone());
|
|
164
|
+
return respuesta;
|
|
165
|
+
});
|
|
166
|
+
return cached ?? fetchPromise;
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## WebSockets — Conexión Robusta con Reconexión
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
@Injectable({ providedIn: "root" })
|
|
176
|
+
export class WebSocketService {
|
|
177
|
+
private socket: WebSocket | null = null;
|
|
178
|
+
private reintentos = 0;
|
|
179
|
+
private readonly MAX_REINTENTOS = 5;
|
|
180
|
+
private readonly DELAY_BASE_MS = 1000;
|
|
181
|
+
private readonly _mensajes$ = new Subject<MensajeWS>();
|
|
182
|
+
private readonly _estado$ = new BehaviorSubject<"conectando" | "conectado" | "desconectado">("desconectado");
|
|
183
|
+
readonly mensajes$ = this._mensajes$.asObservable();
|
|
184
|
+
readonly estado$ = this._estado$.asObservable();
|
|
185
|
+
|
|
186
|
+
conectar(url: string): void {
|
|
187
|
+
this._estado$.next("conectando");
|
|
188
|
+
this.socket = new WebSocket(url);
|
|
189
|
+
this.socket.onopen = () => {
|
|
190
|
+
this.reintentos = 0;
|
|
191
|
+
this._estado$.next("conectado");
|
|
192
|
+
};
|
|
193
|
+
this.socket.onmessage = (event: MessageEvent) => {
|
|
194
|
+
try {
|
|
195
|
+
this._mensajes$.next(JSON.parse(event.data) as MensajeWS);
|
|
196
|
+
} catch { console.warn("Mensaje WS no parseado:", event.data); }
|
|
197
|
+
};
|
|
198
|
+
this.socket.onclose = (event: CloseEvent) => {
|
|
199
|
+
this._estado$.next("desconectado");
|
|
200
|
+
if (event.wasClean || this.reintentos >= this.MAX_REINTENTOS) return;
|
|
201
|
+
const delay = this.DELAY_BASE_MS * 2 ** this.reintentos;
|
|
202
|
+
this.reintentos++;
|
|
203
|
+
setTimeout(() => this.conectar(url), delay);
|
|
204
|
+
};
|
|
205
|
+
this.socket.onerror = () => {};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
enviar<T>(tipo: string, payload: T): void {
|
|
209
|
+
if (this.socket?.readyState !== WebSocket.OPEN) throw new Error("WebSocket no conectado");
|
|
210
|
+
this.socket.send(JSON.stringify({ tipo, payload, timestamp: Date.now() }));
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
desconectar(): void {
|
|
214
|
+
this.reintentos = this.MAX_REINTENTOS;
|
|
215
|
+
this.socket?.close(1000, "Cierre normal");
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## SSE — Server-Sent Events
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
@Injectable({ providedIn: "root" })
|
|
226
|
+
export class SSEService {
|
|
227
|
+
escuchar<T>(url: string): Observable<T> {
|
|
228
|
+
return new Observable<T>(observer => {
|
|
229
|
+
const fuente = new EventSource(url, { withCredentials: true });
|
|
230
|
+
fuente.onmessage = (event: MessageEvent) => {
|
|
231
|
+
try { observer.next(JSON.parse(event.data) as T); }
|
|
232
|
+
catch { observer.error(new Error(`SSE: JSON inválido: ${event.data}`)); }
|
|
233
|
+
};
|
|
234
|
+
fuente.onerror = () => observer.error(new Error("Conexión SSE perdida"));
|
|
235
|
+
return () => fuente.close();
|
|
236
|
+
}).pipe(
|
|
237
|
+
retryWhen(errores =>
|
|
238
|
+
errores.pipe(
|
|
239
|
+
delayWhen((_, intento) => timer(Math.min(1000 * 2 ** intento, 30000)))
|
|
240
|
+
)
|
|
241
|
+
)
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## IndexedDB — Almacenamiento Estructurado
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
import { openDB, DBSchema, IDBPDatabase } from "idb";
|
|
253
|
+
|
|
254
|
+
interface EsquemaBD extends DBSchema {
|
|
255
|
+
pedidos: {
|
|
256
|
+
key: string;
|
|
257
|
+
value: { id: string; datos: object; sincronizado: boolean; timestamp: number };
|
|
258
|
+
indexes: { "por-sincronizado": boolean };
|
|
259
|
+
};
|
|
260
|
+
cache_respuestas: {
|
|
261
|
+
key: string;
|
|
262
|
+
value: { url: string; datos: unknown; expira: number };
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
@Injectable({ providedIn: "root" })
|
|
267
|
+
export class AlmacenamientoLocalService {
|
|
268
|
+
private db!: IDBPDatabase<EsquemaBD>;
|
|
269
|
+
|
|
270
|
+
async inicializar(): Promise<void> {
|
|
271
|
+
this.db = await openDB<EsquemaBD>("mi-app-db", 2, {
|
|
272
|
+
upgrade(db, versionAnterior) {
|
|
273
|
+
if (versionAnterior < 1) {
|
|
274
|
+
const storePedidos = db.createObjectStore("pedidos", { keyPath: "id" });
|
|
275
|
+
storePedidos.createIndex("por-sincronizado", "sincronizado");
|
|
276
|
+
db.createObjectStore("cache_respuestas", { keyPath: "url" });
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async guardarPedidoOffline(pedido: object & { id: string }): Promise<void> {
|
|
283
|
+
await this.db.put("pedidos", {
|
|
284
|
+
id: pedido.id, datos: pedido, sincronizado: false, timestamp: Date.now(),
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async sincronizarPendientes(): Promise<void> {
|
|
289
|
+
const pendientes = await this.db.getAllFromIndex("pedidos", "por-sincronizado", false);
|
|
290
|
+
for (const pendiente of pendientes) {
|
|
291
|
+
try {
|
|
292
|
+
await fetch("/api/pedidos", {
|
|
293
|
+
method: "POST", body: JSON.stringify(pendiente.datos),
|
|
294
|
+
headers: { "Content-Type": "application/json" },
|
|
295
|
+
});
|
|
296
|
+
await this.db.put("pedidos", { ...pendiente, sincronizado: true });
|
|
297
|
+
} catch { /* Sin red — reintentará */ }
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## View Transitions API
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
@Injectable({ providedIn: "root" })
|
|
309
|
+
export class TransicionesService {
|
|
310
|
+
private router = inject(Router);
|
|
311
|
+
|
|
312
|
+
inicializarTransiciones(): void {
|
|
313
|
+
if (!("startViewTransition" in document)) return;
|
|
314
|
+
this.router.events
|
|
315
|
+
.pipe(filter(e => e instanceof NavigationStart))
|
|
316
|
+
.subscribe(() => {
|
|
317
|
+
(document as any).startViewTransition(() =>
|
|
318
|
+
new Promise<void>(resolve => {
|
|
319
|
+
const sub = this.router.events
|
|
320
|
+
.pipe(filter(e => e instanceof NavigationEnd), take(1))
|
|
321
|
+
.subscribe(() => { sub.unsubscribe(); resolve(); });
|
|
322
|
+
})
|
|
323
|
+
);
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
```css
|
|
330
|
+
::view-transition-old(root) {
|
|
331
|
+
animation: desvanece-sale 0.3s ease-out;
|
|
332
|
+
}
|
|
333
|
+
::view-transition-new(root) {
|
|
334
|
+
animation: desvanece-entra 0.3s ease-in;
|
|
335
|
+
}
|
|
336
|
+
.tarjeta-detalle {
|
|
337
|
+
view-transition-name: tarjeta-activa;
|
|
338
|
+
}
|
|
339
|
+
@keyframes desvanece-sale { to { opacity: 0; transform: translateX(-20px); } }
|
|
340
|
+
@keyframes desvanece-entra { from { opacity: 0; transform: translateX( 20px); } }
|
|
341
|
+
```
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gcp-cloud
|
|
3
|
+
description: >
|
|
4
|
+
Google Cloud Platform: Cloud Run para contenedores serverless, GKE para
|
|
5
|
+
Kubernetes, Cloud SQL con proxy, BigQuery para analytics, Pub/Sub para
|
|
6
|
+
mensajería async e IAM con mínimo privilegio. Cargar cuando se despliegue en
|
|
7
|
+
GCP, se configure infraestructura GCP con Terraform, se diseñen pipelines con
|
|
8
|
+
BigQuery o Dataflow, o se configure observabilidad con Cloud Monitoring.
|
|
9
|
+
version: "1.0.0"
|
|
10
|
+
herramientasPermitidas: [Read, Bash]
|
|
11
|
+
evolvable: true # default para skill estandar
|
|
12
|
+
exclusiones:
|
|
13
|
+
- "No cargar para despliegues en AWS o Azure — para AWS cargar `cloud-aws`, para Azure cargar `azure-cloud`."
|
|
14
|
+
- "No cargar para configurar pipelines de ML con Vertex AI, AutoML o Vertex Pipelines — para ML en GCP usar la documentación de Vertex AI directamente."
|
|
15
|
+
- "No cargar para análisis de costos GCP detallado o compromisos de uso (committed use discounts) — para optimización de costos usar GCP Billing directamente."
|
|
16
|
+
- "No cargar para configurar Firebase (Firestore, Auth, Hosting para apps móviles) — Firebase tiene su propio modelo de deployment; para Firebase cargar el skill correspondiente o usar su documentación."
|
|
17
|
+
---
|
|
18
|
+
# GCP Cloud — Google Cloud Platform
|
|
19
|
+
|
|
20
|
+
Skill para desplegar y operar sistemas en Google Cloud Platform. Cubre Cloud Run,
|
|
21
|
+
GKE, Cloud SQL, BigQuery, Pub/Sub, Cloud Functions e IAM. Para patrones AWS ver
|
|
22
|
+
`Skill("cloud-aws")`.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## Cuándo NO cargar
|
|
27
|
+
|
|
28
|
+
- La tarea es desplegar en AWS: cargar `cloud-aws`.
|
|
29
|
+
- La tarea es desplegar en Azure: cargar `azure-cloud`.
|
|
30
|
+
- La tarea es configurar Vertex AI o pipelines de ML: usar la documentación de Vertex AI directamente.
|
|
31
|
+
- La tarea es Firebase (Firestore, Auth, Hosting): usar la documentación de Firebase directamente.
|
|
32
|
+
|
|
33
|
+
## Cuándo cargar este skill
|
|
34
|
+
|
|
35
|
+
- Al desplegar servicios en Cloud Run o configurar GKE
|
|
36
|
+
- Al conectar a Cloud SQL desde código Python o Node
|
|
37
|
+
- Al diseñar pipelines de datos con BigQuery o Dataflow
|
|
38
|
+
- Al configurar Pub/Sub para comunicación async entre servicios
|
|
39
|
+
- Al definir IAM roles, service accounts o Workload Identity
|
|
40
|
+
- Al escribir Terraform para infraestructura GCP
|
|
41
|
+
- Al configurar observabilidad con Cloud Monitoring y Cloud Logging
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## 1. Cloud Run — despliegue de APIs serverless
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
# service.yaml para Cloud Run
|
|
49
|
+
apiVersion: serving.knative.dev/v1
|
|
50
|
+
kind: Service
|
|
51
|
+
metadata:
|
|
52
|
+
name: mi-api
|
|
53
|
+
annotations:
|
|
54
|
+
run.googleapis.com/ingress: internal-and-cloud-load-balancing
|
|
55
|
+
spec:
|
|
56
|
+
template:
|
|
57
|
+
metadata:
|
|
58
|
+
annotations:
|
|
59
|
+
autoscaling.knative.dev/minScale: "1"
|
|
60
|
+
autoscaling.knative.dev/maxScale: "10"
|
|
61
|
+
run.googleapis.com/cloudsql-instances: proyecto:region:instancia
|
|
62
|
+
spec:
|
|
63
|
+
serviceAccountName: mi-api-sa@proyecto.iam.gserviceaccount.com
|
|
64
|
+
containers:
|
|
65
|
+
- image: gcr.io/proyecto/mi-api:latest
|
|
66
|
+
resources:
|
|
67
|
+
limits:
|
|
68
|
+
cpu: "1"
|
|
69
|
+
memory: 512Mi
|
|
70
|
+
env:
|
|
71
|
+
- name: DATABASE_URL
|
|
72
|
+
valueFrom:
|
|
73
|
+
secretKeyRef:
|
|
74
|
+
name: database-url
|
|
75
|
+
key: latest
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Puntos clave de Cloud Run:**
|
|
79
|
+
- `minScale: "1"` para APIs que no toleran cold starts (pago mínimo constante)
|
|
80
|
+
- `minScale: "0"` solo para workloads con latencia tolerable en arranque en frío
|
|
81
|
+
- Los secretos SIEMPRE vienen de Secret Manager vía `secretKeyRef`, nunca hardcodeados
|
|
82
|
+
- `run.googleapis.com/cloudsql-instances` activa el Cloud SQL Auth Proxy automático
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## 2. Cloud SQL — conexión con Python Connector
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
# SQLAlchemy con Cloud SQL Python Connector (sin abrir puertos a internet)
|
|
90
|
+
from google.cloud.sql.connector import Connector
|
|
91
|
+
import sqlalchemy
|
|
92
|
+
|
|
93
|
+
connector = Connector()
|
|
94
|
+
|
|
95
|
+
def getconn():
|
|
96
|
+
return connector.connect(
|
|
97
|
+
"proyecto:region:instancia", # Instance connection name
|
|
98
|
+
"pg8000",
|
|
99
|
+
user="mi_usuario",
|
|
100
|
+
password="mi_contraseña",
|
|
101
|
+
db="mi_base",
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
engine = sqlalchemy.create_engine(
|
|
105
|
+
"postgresql+pg8000://",
|
|
106
|
+
creator=getconn,
|
|
107
|
+
pool_size=5,
|
|
108
|
+
max_overflow=2,
|
|
109
|
+
pool_timeout=30,
|
|
110
|
+
)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**Regla**: NUNCA exponer Cloud SQL con IP pública sin autorización de red. Usar
|
|
114
|
+
siempre Cloud SQL Auth Proxy (automático en Cloud Run) o el Python Connector.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
## 3. BigQuery — queries parametrizadas para analytics
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
from google.cloud import bigquery
|
|
122
|
+
|
|
123
|
+
client = bigquery.Client()
|
|
124
|
+
|
|
125
|
+
# BIEN: parámetros explícitos (previene inyección)
|
|
126
|
+
query = """
|
|
127
|
+
SELECT usuario_id, SUM(monto) AS total_ventas
|
|
128
|
+
FROM `proyecto.dataset.ventas`
|
|
129
|
+
WHERE fecha >= @fecha_inicio
|
|
130
|
+
AND region = @region
|
|
131
|
+
GROUP BY usuario_id
|
|
132
|
+
ORDER BY total_ventas DESC
|
|
133
|
+
LIMIT 100
|
|
134
|
+
"""
|
|
135
|
+
job_config = bigquery.QueryJobConfig(
|
|
136
|
+
query_parameters=[
|
|
137
|
+
bigquery.ScalarQueryParameter("fecha_inicio", "DATE", "2026-01-01"),
|
|
138
|
+
bigquery.ScalarQueryParameter("region", "STRING", "MX"),
|
|
139
|
+
]
|
|
140
|
+
)
|
|
141
|
+
resultados = client.query(query, job_config=job_config).result()
|
|
142
|
+
|
|
143
|
+
for fila in resultados:
|
|
144
|
+
print(f"Usuario {fila.usuario_id}: ${fila.total_ventas:,.2f}")
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Anti-patrón**: NUNCA usar f-strings con inputs de usuario en queries BigQuery.
|
|
148
|
+
Siempre usar `QueryJobConfig` con `query_parameters`.
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## 4. Pub/Sub — mensajería async entre servicios
|
|
153
|
+
|
|
154
|
+
```python
|
|
155
|
+
from google.cloud import pubsub_v1
|
|
156
|
+
import json
|
|
157
|
+
|
|
158
|
+
# Publicar evento
|
|
159
|
+
publisher = pubsub_v1.PublisherClient()
|
|
160
|
+
topic_path = publisher.topic_path("proyecto", "mi-topico")
|
|
161
|
+
|
|
162
|
+
future = publisher.publish(
|
|
163
|
+
topic_path,
|
|
164
|
+
json.dumps({"evento": "pago_completado", "orden_id": "123"}).encode("utf-8"),
|
|
165
|
+
origen="api-pagos", # atributos de mensaje para filtrado
|
|
166
|
+
version="1",
|
|
167
|
+
)
|
|
168
|
+
future.result() # Bloquea hasta confirmar publicación
|
|
169
|
+
|
|
170
|
+
# Procesar en suscriptor (Cloud Run o Cloud Function con HTTP push)
|
|
171
|
+
def procesar_mensaje(message: pubsub_v1.subscriber.message.Message) -> None:
|
|
172
|
+
datos = json.loads(message.data.decode("utf-8"))
|
|
173
|
+
try:
|
|
174
|
+
procesar_pago(datos)
|
|
175
|
+
message.ack()
|
|
176
|
+
except Exception:
|
|
177
|
+
message.nack() # Reencola para reintentos
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 5. IAM — mínimo privilegio por servicio
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# Crear service account dedicado por servicio
|
|
186
|
+
gcloud iam service-accounts create mi-api-sa \
|
|
187
|
+
--display-name="Service account para mi-api" \
|
|
188
|
+
--project=$PROJECT_ID
|
|
189
|
+
|
|
190
|
+
# Otorgar solo los permisos necesarios
|
|
191
|
+
gcloud projects add-iam-policy-binding $PROJECT_ID \
|
|
192
|
+
--member="serviceAccount:mi-api-sa@$PROJECT_ID.iam.gserviceaccount.com" \
|
|
193
|
+
--role="roles/cloudsql.client"
|
|
194
|
+
|
|
195
|
+
gcloud secrets add-iam-policy-binding database-url \
|
|
196
|
+
--member="serviceAccount:mi-api-sa@$PROJECT_ID.iam.gserviceaccount.com" \
|
|
197
|
+
--role="roles/secretmanager.secretAccessor"
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## 6. Reglas obligatorias
|
|
203
|
+
|
|
204
|
+
| Regla | Justificación | Verificación |
|
|
205
|
+
|-------|--------------|--------------|
|
|
206
|
+
| Service account dedicado por servicio | La SA por defecto tiene permisos excesivos | Verificar que `serviceAccountName` está en cada deployment |
|
|
207
|
+
| Secretos en Secret Manager, no en env vars | Las env vars aparecen en logs y dashboards | Buscar `secretKeyRef` en lugar de valores hardcodeados |
|
|
208
|
+
| NUNCA usar roles primitivos en producción | Owner/Editor tienen acceso total al proyecto | Usar roles predefinidos granulares o custom roles |
|
|
209
|
+
| Etiquetas en todos los recursos | Sin etiquetas no se puede analizar el costo por servicio | `gcloud ... --labels=env=prod,equipo=backend` |
|
|
210
|
+
| Workload Identity para GKE | Las claves de SA en archivos son un riesgo de seguridad | Ver [recursos/gke.md](recursos/gke.md) |
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## 7. Anti-patrones
|
|
215
|
+
|
|
216
|
+
| MAL | BIEN |
|
|
217
|
+
|-----|------|
|
|
218
|
+
| Credenciales JSON de SA montadas como archivo en contenedor | Workload Identity o Application Default Credentials |
|
|
219
|
+
| `gcloud auth application-default` en producción | Service account con mínimo privilegio |
|
|
220
|
+
| Cloud SQL con IP pública sin autorización de red | Cloud SQL Auth Proxy o Python Connector |
|
|
221
|
+
| `roles/editor` o `roles/owner` para un servicio | Roles granulares: `roles/cloudsql.client` |
|
|
222
|
+
| f-strings con inputs de usuario en BigQuery | `QueryJobConfig` con `query_parameters` |
|
|
223
|
+
| `minScale: "0"` en API REST pública | `minScale: "1"` para evitar cold starts |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 8. Checklist de verificación
|
|
228
|
+
|
|
229
|
+
- [ ] Cada servicio tiene su propio service account (no el SA por defecto)
|
|
230
|
+
- [ ] Los secretos vienen de Secret Manager vía `secretKeyRef`
|
|
231
|
+
- [ ] No hay credenciales en variables de entorno planas ni en el código
|
|
232
|
+
- [ ] Cloud SQL usa Auth Proxy (Cloud Run) o Python Connector (GKE/local)
|
|
233
|
+
- [ ] IAM usa roles predefinidos o custom, nunca Owner/Editor en producción
|
|
234
|
+
- [ ] Todos los recursos tienen etiquetas `env`, `equipo` y `servicio`
|
|
235
|
+
- [ ] Queries BigQuery usan `query_parameters`, nunca concatenación de strings
|
|
236
|
+
- [ ] Cloud Run tiene `minScale` explícito según tolerancia a cold starts
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 9. Referencias
|
|
241
|
+
|
|
242
|
+
| Tema | Recurso |
|
|
243
|
+
|------|---------|
|
|
244
|
+
| GKE: clusters, node pools, Workload Identity, HPA | [recursos/gke.md](recursos/gke.md) |
|
|
245
|
+
| Terraform para GCP: providers, módulos, state remoto | [recursos/terraform-gcp.md](recursos/terraform-gcp.md) |
|
|
246
|
+
| Cloud Run pricing y cuotas | [cloud.google.com/run/pricing](https://cloud.google.com/run/pricing) |
|
|
247
|
+
| IAM roles predefinidos completos | [cloud.google.com/iam/docs/understanding-roles](https://cloud.google.com/iam/docs/understanding-roles) |
|
|
248
|
+
| Secret Manager guía | [cloud.google.com/secret-manager/docs](https://cloud.google.com/secret-manager/docs) |
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Gotchas / Errores comunes no obvios
|
|
253
|
+
|
|
254
|
+
**Cloud Run con `minScale: "0"` tiene cold start de 2-8 segundos para imágenes Python con dependencias pesadas (pandas, sqlalchemy, cryptography), y el primer request del usuario experimenta un timeout 504 si el health check de Cloud Run expira antes de que la app esté lista**: una imagen de 800MB con FastAPI + pandas tarda ~6 segundos en arrancar; el timeout default del load balancer de Cloud Run es 60s pero el timeout de startup del contenedor es 240s. Sin embargo, si el primer request llega mientras el contenedor arranca y el cliente tiene un timeout de 5s, el request falla. Causa: `minScale: "0"` es incompatible con SLAs de latencia estrictos para APIs sincrónicas. Fix: para APIs con latencia requerida < 2s, usar `minScale: "1"`. Para reducir cold start con `minScale: "0"`, optimizar la imagen: usar imagen base `python:3.12-slim`, separar las dependencias pesadas en layers, y considerar instancias precalentadas de Cloud Run (preview feature).
|
|
255
|
+
|
|
256
|
+
**`gcloud iam service-accounts create` crea el service account en el proyecto correcto pero `gcloud secrets add-iam-policy-binding` falla con `PERMISSION_DENIED` porque el binding se hace sobre el secreto del proyecto A desde un context de proyecto B cuando hay múltiples proyectos en el PATH**: un desarrollador que tiene `gcloud config set project proyecto-dev` en su shell y ejecuta el script de setup hace el binding en `proyecto-dev` en lugar de `proyecto-prod` donde vive el secreto. Causa: `gcloud` usa el proyecto configurado en el contexto activo como default, y los comandos de IAM de recursos específicos (secrets, buckets) no siempre verifican que el recurso pertenece al proyecto configurado. Fix: siempre especificar `--project` explícitamente en comandos de IAM sobre recursos: `gcloud secrets add-iam-policy-binding database-url --project=proyecto-prod --member=...`. En scripts de IaC, hardcodear el project ID en lugar de depender del contexto activo.
|
|
257
|
+
|
|
258
|
+
**El Cloud SQL Python Connector con `pool_size=5` en Cloud Run causa `TimeoutError: QueuePool limit reached` bajo carga porque cada instancia de Cloud Run crea su propio pool de 5 conexiones y con 20 instancias se generan 100 conexiones simultáneas, saturando el límite de conexiones de Cloud SQL (default 100)**: durante un pico de tráfico con auto-scaling a 20 instancias Cloud Run, Cloud SQL comienza a rechazar nuevas conexiones con error `FATAL: too many connections`. La aplicación reporta 503 aunque el CPU y memoria de Cloud SQL estén al 30%. Causa: Cloud Run escala instancias independientemente y cada instancia tiene su propio pool; el número de conexiones totales = instancias × pool_size. Fix: usar `pool_size=2, max_overflow=1` para Cloud Run (máximo 3 conexiones por instancia), y aumentar `max_connections` en Cloud SQL según `instancias_max × 3 + buffer`. Considerar usar `pgBouncer` o Cloud SQL Proxy con pooling habilitado para workloads con muchas instancias.
|
|
259
|
+
|
|
260
|
+
**`future.result()` en Pub/Sub publisher bloquea el thread hasta confirmación de publicación y en código síncrono dentro de Cloud Run causa que el request quede colgado si el tópico de Pub/Sub tiene alta latencia o está temporalmente indisponible**: una función que publica 50 eventos por request con `[publisher.publish(...).result() for evento in eventos]` tarda el tiempo total de las 50 confirmaciones en serie, convirtiendo una operación de 200ms en 2-3 segundos cuando Pub/Sub tiene latencia alta. Causa: `future.result()` es una operación bloqueante síncrona; publicar en serie espera la confirmación de cada mensaje antes de enviar el siguiente. Fix: recolectar todos los futures primero y esperar las confirmaciones al final: `futures = [publisher.publish(topic_path, data) for data in payloads]`, luego `[f.result() for f in futures]`. Para volúmenes mayores, usar `PublisherOptions(enable_message_ordering=False)` y procesar los futures con `concurrent.futures.as_completed()`.
|