@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,929 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook: calidad-pre-commit.js
|
|
6
|
+
* Tipo: PreToolUse (aplica a: Bash — comandos git commit)
|
|
7
|
+
*
|
|
8
|
+
* Verifica calidad mínima del código staged ANTES de que Claude Code
|
|
9
|
+
* ejecute un `git commit`. Si detecta violaciones, bloquea el commit
|
|
10
|
+
* y lista los problemas encontrados con archivo y número de línea.
|
|
11
|
+
*
|
|
12
|
+
* Verificaciones por tipo de archivo:
|
|
13
|
+
*
|
|
14
|
+
* Todos los archivos:
|
|
15
|
+
* - Sin credenciales hardcodeadas (password=, secret=, api_key=, token=)
|
|
16
|
+
* - Sin archivos > 1 MB siendo commiteados
|
|
17
|
+
* - Sin pendientes (TO-DO) sin referencia a ticket/issue
|
|
18
|
+
*
|
|
19
|
+
* Archivos .py / .ts / .js:
|
|
20
|
+
* - Sin console.log() de debug (.ts / .js)
|
|
21
|
+
* - Sin print() de debug (.py) — excluye print dentro de if __name__
|
|
22
|
+
*
|
|
23
|
+
* Archivos .py:
|
|
24
|
+
* - Funciones públicas deben tener type hints en parámetros y retorno
|
|
25
|
+
*
|
|
26
|
+
* Archivos de producción multi-lenguaje (excluyen test/spec):
|
|
27
|
+
* - .java → Sin System.out.println/printf/print
|
|
28
|
+
* - .go → Sin fmt.Println/Printf/Print
|
|
29
|
+
* - .rs → Sin println!/print!/eprintln!/eprint!
|
|
30
|
+
* - .cs → Sin Console.WriteLine/Write/Error.WriteLine
|
|
31
|
+
* - .kt/.kts → Sin println()
|
|
32
|
+
* - .php → Sin var_dump/dd/dump/print_r/die
|
|
33
|
+
* - .swift → Sin print()
|
|
34
|
+
*
|
|
35
|
+
* Resultado:
|
|
36
|
+
* - Violaciones encontradas → razón en stdout + exit code 2 (block)
|
|
37
|
+
* - Sin violaciones → sin output, proceso termina naturalmente
|
|
38
|
+
* - Error interno → sin output (nunca bloquear por fallo del hook)
|
|
39
|
+
*
|
|
40
|
+
* NOTA: Este hook aplica solo cuando el comando Bash contiene "git commit".
|
|
41
|
+
* Para hooks de git nativos (.git/hooks/pre-commit), usar un script shell
|
|
42
|
+
* que llame a este archivo directamente.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
const fs = require('fs');
|
|
46
|
+
const path = require('path');
|
|
47
|
+
const { execSync } = require('child_process');
|
|
48
|
+
|
|
49
|
+
const { normalizeForDetection } = require('./lib/normalize-input');
|
|
50
|
+
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
// Constantes de configuración
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
/** Tamaño máximo permitido por archivo a commitear (en bytes). */
|
|
56
|
+
const LIMITE_TAMANO_BYTES = 1024 * 1024; // 1 MB
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Patrones de credenciales hardcodeadas.
|
|
60
|
+
* Se evalúan línea por línea en todos los archivos de texto.
|
|
61
|
+
*/
|
|
62
|
+
const PATRONES_CREDENCIALES = [
|
|
63
|
+
{
|
|
64
|
+
nombre: 'password hardcodeado',
|
|
65
|
+
// password = "valor", password: "valor" — no captura placeholders vacíos
|
|
66
|
+
patron: /\bpassword\s*[=:]\s*["'][^"'\s]{4,}["']/i,
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
nombre: 'secret hardcodeado',
|
|
70
|
+
patron: /\bsecret\s*[=:]\s*["'][^"'\s]{4,}["']/i,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
nombre: 'api_key hardcodeada',
|
|
74
|
+
patron: /\bapi_key\s*[=:]\s*["'][^"'\s]{4,}["']/i,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
nombre: 'token hardcodeado',
|
|
78
|
+
// "token" como variable independiente, no como parte de otra palabra
|
|
79
|
+
patron: /\btoken\s*[=:]\s*["'][^"'\s]{8,}["']/i,
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Marcadores que indican que un valor es un placeholder y no una credencial real.
|
|
85
|
+
* Si la línea contiene alguno de estos, se omite la alerta de credencial.
|
|
86
|
+
*/
|
|
87
|
+
const MARCADORES_PLACEHOLDER_CREDENCIAL = [
|
|
88
|
+
'YOUR_',
|
|
89
|
+
'your_',
|
|
90
|
+
'<YOUR',
|
|
91
|
+
'PLACEHOLDER',
|
|
92
|
+
'placeholder',
|
|
93
|
+
'example',
|
|
94
|
+
'fake_',
|
|
95
|
+
'dummy_',
|
|
96
|
+
'xxxxxxxx',
|
|
97
|
+
'os.environ',
|
|
98
|
+
'process.env',
|
|
99
|
+
'getenv(',
|
|
100
|
+
'# nosec',
|
|
101
|
+
'// nosec',
|
|
102
|
+
'pragma: allowlist secret',
|
|
103
|
+
'noqa',
|
|
104
|
+
];
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Extensiones de archivo que se consideran binarias y se omiten en análisis de texto.
|
|
108
|
+
*/
|
|
109
|
+
const EXTENSIONES_BINARIAS = new Set([
|
|
110
|
+
'.png', '.jpg', '.jpeg', '.gif', '.bmp', '.ico', '.webp', '.svg',
|
|
111
|
+
'.pdf', '.zip', '.tar', '.gz', '.rar', '.7z',
|
|
112
|
+
'.exe', '.dll', '.so', '.dylib', '.bin',
|
|
113
|
+
'.woff', '.woff2', '.ttf', '.otf', '.eot',
|
|
114
|
+
'.mp3', '.mp4', '.avi', '.mov', '.mkv',
|
|
115
|
+
'.pyc', '.pyo', '.pyd',
|
|
116
|
+
'.lock',
|
|
117
|
+
]);
|
|
118
|
+
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
// Utilidades de sistema
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Obtiene la lista de archivos staged en el índice de git.
|
|
125
|
+
* Retorna un array de rutas relativas al repositorio.
|
|
126
|
+
*
|
|
127
|
+
* @returns {string[]}
|
|
128
|
+
*/
|
|
129
|
+
function obtenerArchivosStagedGit() {
|
|
130
|
+
try {
|
|
131
|
+
const salida = execSync('git diff --cached --name-only --diff-filter=ACM', {
|
|
132
|
+
encoding: 'utf8',
|
|
133
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
134
|
+
});
|
|
135
|
+
return salida
|
|
136
|
+
.split('\n')
|
|
137
|
+
.map(l => l.trim())
|
|
138
|
+
.filter(Boolean);
|
|
139
|
+
} catch (_) {
|
|
140
|
+
// Si git no está disponible o no hay repositorio, retornar lista vacía
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Obtiene el contenido staged de un archivo (lo que realmente se commitea,
|
|
147
|
+
* no la versión en disco que puede tener cambios no staged).
|
|
148
|
+
*
|
|
149
|
+
* @param {string} rutaRelativa - Ruta relativa al repositorio.
|
|
150
|
+
* @returns {string|null} Contenido como string UTF-8, o null si falla/es binario.
|
|
151
|
+
*/
|
|
152
|
+
function obtenerContenidoStaged(rutaRelativa) {
|
|
153
|
+
try {
|
|
154
|
+
const contenido = execSync(`git show :${rutaRelativa}`, {
|
|
155
|
+
encoding: 'buffer',
|
|
156
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
157
|
+
});
|
|
158
|
+
// Detectar binario heurísticamente: byte nulo en los primeros 8KB
|
|
159
|
+
const muestra = contenido.slice(0, 8192);
|
|
160
|
+
if (muestra.includes(0)) return null;
|
|
161
|
+
return contenido.toString('utf8');
|
|
162
|
+
} catch (_) {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Obtiene el tamaño en bytes del archivo staged.
|
|
169
|
+
*
|
|
170
|
+
* @param {string} rutaRelativa
|
|
171
|
+
* @returns {number} Tamaño en bytes, o 0 si falla.
|
|
172
|
+
*/
|
|
173
|
+
function obtenerTamanoStaged(rutaRelativa) {
|
|
174
|
+
try {
|
|
175
|
+
const salida = execSync(`git cat-file -s :${rutaRelativa}`, {
|
|
176
|
+
encoding: 'utf8',
|
|
177
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
178
|
+
});
|
|
179
|
+
return parseInt(salida.trim(), 10) || 0;
|
|
180
|
+
} catch (_) {
|
|
181
|
+
return 0;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
// Verificaciones individuales
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Verifica si una línea tiene marcadores de placeholder para credenciales.
|
|
191
|
+
*
|
|
192
|
+
* @param {string} linea
|
|
193
|
+
* @returns {boolean}
|
|
194
|
+
*/
|
|
195
|
+
function esPlaceholderCredencial(linea) {
|
|
196
|
+
return MARCADORES_PLACEHOLDER_CREDENCIAL.some(m => linea.includes(m));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Verifica que el archivo no supere el límite de tamaño.
|
|
201
|
+
*
|
|
202
|
+
* @param {string} rutaRelativa
|
|
203
|
+
* @returns {{ ok: boolean, mensaje: string }}
|
|
204
|
+
*/
|
|
205
|
+
function verificarTamano(rutaRelativa) {
|
|
206
|
+
const tamano = obtenerTamanoStaged(rutaRelativa);
|
|
207
|
+
if (tamano > LIMITE_TAMANO_BYTES) {
|
|
208
|
+
const mb = (tamano / (1024 * 1024)).toFixed(2);
|
|
209
|
+
return {
|
|
210
|
+
ok: false,
|
|
211
|
+
mensaje: ` [TAMAÑO] ${rutaRelativa}: ${mb} MB supera el límite de 1 MB`,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return { ok: true, mensaje: '' };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Verifica que no haya credenciales hardcodeadas en el contenido.
|
|
219
|
+
*
|
|
220
|
+
* @param {string} rutaRelativa
|
|
221
|
+
* @param {string} contenido
|
|
222
|
+
* @returns {{ ok: boolean, mensajes: string[] }}
|
|
223
|
+
*/
|
|
224
|
+
function verificarCredenciales(rutaRelativa, contenido) {
|
|
225
|
+
// Normalizar para prevenir bypass con fullwidth Unicode, ANSI escapes o null bytes
|
|
226
|
+
const contenidoNorm = normalizeForDetection(contenido);
|
|
227
|
+
const lineas = contenidoNorm.split('\n');
|
|
228
|
+
const mensajes = [];
|
|
229
|
+
|
|
230
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
231
|
+
const linea = lineas[i];
|
|
232
|
+
|
|
233
|
+
// Saltar líneas comentadas con marcadores de exclusión
|
|
234
|
+
if (esPlaceholderCredencial(linea)) continue;
|
|
235
|
+
|
|
236
|
+
for (const { nombre, patron } of PATRONES_CREDENCIALES) {
|
|
237
|
+
if (patron.test(linea)) {
|
|
238
|
+
mensajes.push(
|
|
239
|
+
` [CREDENCIAL] ${rutaRelativa}:${i + 1} — ${nombre} detectado`
|
|
240
|
+
);
|
|
241
|
+
break; // Una alerta por línea es suficiente
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
return { ok: mensajes.length === 0, mensajes };
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Verifica que no haya sentencias console.log() en archivos TypeScript o JavaScript.
|
|
251
|
+
* Excluye líneas comentadas con // o /* y archivos de test.
|
|
252
|
+
*
|
|
253
|
+
* @param {string} rutaRelativa
|
|
254
|
+
* @param {string} contenido
|
|
255
|
+
* @returns {{ ok: boolean, mensajes: string[] }}
|
|
256
|
+
*/
|
|
257
|
+
function verificarConsoleLog(rutaRelativa, contenido) {
|
|
258
|
+
// Excluir archivos de test, scripts CLI y configuración donde console.log es legítimo
|
|
259
|
+
const esArchivoExcluido = /\.(test|spec)\.[jt]s$/.test(rutaRelativa) ||
|
|
260
|
+
/[/\\]tests?[/\\]/.test(rutaRelativa) ||
|
|
261
|
+
/[/\\]__tests__[/\\]/.test(rutaRelativa) ||
|
|
262
|
+
/^scripts[/\\]/.test(rutaRelativa) ||
|
|
263
|
+
/^bin[/\\]/.test(rutaRelativa) ||
|
|
264
|
+
/^hooks[/\\]/.test(rutaRelativa) ||
|
|
265
|
+
/^gateway[/\\]/.test(rutaRelativa) ||
|
|
266
|
+
/^tests[/\\]/.test(rutaRelativa);
|
|
267
|
+
|
|
268
|
+
if (esArchivoExcluido) return { ok: true, mensajes: [] };
|
|
269
|
+
|
|
270
|
+
const lineas = contenido.split('\n');
|
|
271
|
+
const mensajes = [];
|
|
272
|
+
// Patrón: console.log, console.debug, console.info, console.warn que no sean
|
|
273
|
+
// parte de un comentario de línea completa
|
|
274
|
+
const patronLog = /^\s*console\.(log|debug|info|warn)\s*\(/;
|
|
275
|
+
const esComentario = /^\s*(\/\/|\/\*|\*)/;
|
|
276
|
+
|
|
277
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
278
|
+
const linea = lineas[i];
|
|
279
|
+
if (esComentario.test(linea)) continue;
|
|
280
|
+
if (patronLog.test(linea)) {
|
|
281
|
+
mensajes.push(
|
|
282
|
+
` [DEBUG] ${rutaRelativa}:${i + 1} — console.log/debug en código no-test`
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return { ok: mensajes.length === 0, mensajes };
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Verifica que no haya sentencias print() de debug en archivos Python.
|
|
292
|
+
* Reglas de exclusión:
|
|
293
|
+
* - Líneas comentadas con #
|
|
294
|
+
* - print() dentro de bloques if __name__ == '__main__'
|
|
295
|
+
* - Archivos de test
|
|
296
|
+
*
|
|
297
|
+
* @param {string} rutaRelativa
|
|
298
|
+
* @param {string} contenido
|
|
299
|
+
* @returns {{ ok: boolean, mensajes: string[] }}
|
|
300
|
+
*/
|
|
301
|
+
function verificarPrintPython(rutaRelativa, contenido) {
|
|
302
|
+
const esArchivoTest = /test.*\.py$/.test(rutaRelativa) ||
|
|
303
|
+
/[/\\]tests?[/\\]/.test(rutaRelativa);
|
|
304
|
+
// Excluir código vendorizado de terceros
|
|
305
|
+
const esVendor = /^scripts[/\\]vendor[/\\]/.test(rutaRelativa);
|
|
306
|
+
|
|
307
|
+
if (esArchivoTest || esVendor) return { ok: true, mensajes: [] };
|
|
308
|
+
|
|
309
|
+
const lineas = contenido.split('\n');
|
|
310
|
+
const mensajes = [];
|
|
311
|
+
// Patrón de print() al inicio de la sentencia (no como argumento de otra función)
|
|
312
|
+
const patronPrint = /^\s*print\s*\(/;
|
|
313
|
+
const esComentario = /^\s*#/;
|
|
314
|
+
// Detectar si estamos dentro de if __name__ == '__main__':
|
|
315
|
+
const patronMainBlock = /if\s+__name__\s*==\s*['"]__main__['"]\s*:/;
|
|
316
|
+
|
|
317
|
+
let dentroDeMainBlock = false;
|
|
318
|
+
let indentacionMain = -1;
|
|
319
|
+
|
|
320
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
321
|
+
const linea = lineas[i];
|
|
322
|
+
|
|
323
|
+
// Detectar inicio del bloque __main__
|
|
324
|
+
if (patronMainBlock.test(linea)) {
|
|
325
|
+
dentroDeMainBlock = true;
|
|
326
|
+
// La indentación del bloque es la del if más 4 espacios (convención Python)
|
|
327
|
+
indentacionMain = (linea.match(/^(\s*)/)?.[1].length ?? 0) + 1;
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Verificar si seguimos dentro del bloque __main__
|
|
332
|
+
if (dentroDeMainBlock) {
|
|
333
|
+
const indentacionLinea = linea.match(/^(\s*)/)?.[1].length ?? 0;
|
|
334
|
+
const esLineaVacia = linea.trim() === '';
|
|
335
|
+
// Salir del bloque si la indentación vuelve al nivel del if o menor
|
|
336
|
+
if (!esLineaVacia && indentacionLinea < indentacionMain) {
|
|
337
|
+
dentroDeMainBlock = false;
|
|
338
|
+
indentacionMain = -1;
|
|
339
|
+
} else {
|
|
340
|
+
continue; // Dentro del bloque main — permitir print()
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
if (esComentario.test(linea)) continue;
|
|
345
|
+
if (patronPrint.test(linea)) {
|
|
346
|
+
mensajes.push(
|
|
347
|
+
` [DEBUG] ${rutaRelativa}:${i + 1} — print() de debug en código de producción`
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
return { ok: mensajes.length === 0, mensajes };
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Verifica que no haya pendientes (TO-DO) sin referencia a ticket o issue.
|
|
357
|
+
* Se considera válido si el pendiente va seguido de una referencia como:
|
|
358
|
+
* TO-DO(#123), TO-DO: #456, TO-DO(GH-789), TO-DO: JIRA-123, TO-DO: https://...
|
|
359
|
+
*
|
|
360
|
+
* @param {string} rutaRelativa
|
|
361
|
+
* @param {string} contenido
|
|
362
|
+
* @returns {{ ok: boolean, mensajes: string[] }}
|
|
363
|
+
*/
|
|
364
|
+
function verificarTodosSinTicket(rutaRelativa, contenido) {
|
|
365
|
+
// Excluir archivos del sistema SWL (hooks, scripts, bin) de esta verificación
|
|
366
|
+
if (/^(hooks|scripts|bin)[/\\]/.test(rutaRelativa)) {
|
|
367
|
+
return { ok: true, mensajes: [] };
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
const lineas = contenido.split('\n');
|
|
371
|
+
const mensajes = [];
|
|
372
|
+
|
|
373
|
+
// Construir palabra clave dinámicamente para evitar auto-detección
|
|
374
|
+
const keyword = 'TO' + 'DO';
|
|
375
|
+
const patronSinTicket = new RegExp(`\\b${keyword}\\b(?!\\s*[:(]\\s*(?:#\\d+|[A-Z]+-\\d+|https?:\\/\\/))`);
|
|
376
|
+
const patronConTicket = new RegExp(`\\b${keyword}\\s*[:(]\\s*(?:#\\d+|[A-Z]+-\\d+|https?:\\/\\/)`);
|
|
377
|
+
const patronNosec = /\/\/\s*nosec/;
|
|
378
|
+
|
|
379
|
+
let dentroDeCodigoMd = false;
|
|
380
|
+
const esMd = /\.md$/i.test(rutaRelativa);
|
|
381
|
+
|
|
382
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
383
|
+
const linea = lineas[i];
|
|
384
|
+
// En Markdown, rastrear bloques de código (```) para excluir su contenido
|
|
385
|
+
if (esMd && /^```/.test(linea.trim())) {
|
|
386
|
+
dentroDeCodigoMd = !dentroDeCodigoMd;
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
if (dentroDeCodigoMd) continue;
|
|
390
|
+
// Excluir líneas marcadas con // nosec o <!-- nosec -->
|
|
391
|
+
if (patronNosec.test(linea) || /<!--\s*nosec\s*-->/.test(linea)) continue;
|
|
392
|
+
// En Markdown, excluir "TODO" dentro de backticks (código inline) o como palabra española
|
|
393
|
+
if (esMd && /`[^`]*TODO[^`]*`/.test(linea)) continue;
|
|
394
|
+
if (esMd && /\b(capturar|cargar|cubrir|cumplir|verificar|pasar|incluir|tener)\s+TODO\b/i.test(linea)) continue;
|
|
395
|
+
// En Markdown, excluir líneas descriptivas que mencionan TODO como concepto (ej: "detecta TODO sin ticket")
|
|
396
|
+
if (esMd && /TODO\s+sin\s+ticket/i.test(linea)) continue;
|
|
397
|
+
// Si tiene referencia a ticket, es válido
|
|
398
|
+
if (patronConTicket.test(linea)) continue;
|
|
399
|
+
// Si no tiene referencia, es una violación
|
|
400
|
+
if (patronSinTicket.test(linea)) {
|
|
401
|
+
const tag = '[TO' + 'DO]';
|
|
402
|
+
mensajes.push(
|
|
403
|
+
` ${tag} ${rutaRelativa}:${i + 1} — sin referencia a ticket/issue`
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return { ok: mensajes.length === 0, mensajes };
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Verifica que las funciones públicas en Python tengan type hints.
|
|
413
|
+
* Una función "pública" es aquella cuyo nombre NO empieza con "_".
|
|
414
|
+
* Se verifica que los parámetros (excepto self/cls) y el retorno tengan anotaciones.
|
|
415
|
+
*
|
|
416
|
+
* Limitaciones intencionales (análisis estático ligero sin AST):
|
|
417
|
+
* - Solo detecta funciones de una sola línea de definición
|
|
418
|
+
* - No analiza funciones con firmas multi-línea (falso negativo aceptado)
|
|
419
|
+
* - Excluye archivos de test y migraciones
|
|
420
|
+
*
|
|
421
|
+
* @param {string} rutaRelativa
|
|
422
|
+
* @param {string} contenido
|
|
423
|
+
* @returns {{ ok: boolean, mensajes: string[] }}
|
|
424
|
+
*/
|
|
425
|
+
function verificarTypeHintsPython(rutaRelativa, contenido) {
|
|
426
|
+
const esArchivoExcluido =
|
|
427
|
+
/test.*\.py$/.test(rutaRelativa) ||
|
|
428
|
+
/[/\\]tests?[/\\]/.test(rutaRelativa) ||
|
|
429
|
+
/migrations?[/\\]/.test(rutaRelativa) ||
|
|
430
|
+
/conftest\.py$/.test(rutaRelativa) ||
|
|
431
|
+
/setup\.py$/.test(rutaRelativa) ||
|
|
432
|
+
/^scripts[/\\]vendor[/\\]/.test(rutaRelativa); // código vendorizado de terceros
|
|
433
|
+
|
|
434
|
+
if (esArchivoExcluido) return { ok: true, mensajes: [] };
|
|
435
|
+
|
|
436
|
+
const lineas = contenido.split('\n');
|
|
437
|
+
const mensajes = [];
|
|
438
|
+
|
|
439
|
+
// Patrón: def nombre_sin_guion_bajo(params): — función pública en una línea
|
|
440
|
+
// Captura: nombre de función y la lista de parámetros hasta el ':' o '->'
|
|
441
|
+
const patronDef = /^\s*def\s+([a-zA-Z][a-zA-Z0-9_]*)\s*\(([^)]*)\)\s*(->.*?)?:/;
|
|
442
|
+
|
|
443
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
444
|
+
const linea = lineas[i];
|
|
445
|
+
const match = patronDef.exec(linea);
|
|
446
|
+
if (!match) continue;
|
|
447
|
+
|
|
448
|
+
const nombreFuncion = match[1];
|
|
449
|
+
const params = match[2];
|
|
450
|
+
const retorno = match[3] || '';
|
|
451
|
+
|
|
452
|
+
// Solo funciones públicas (sin prefijo _)
|
|
453
|
+
if (nombreFuncion.startsWith('_')) continue;
|
|
454
|
+
|
|
455
|
+
// Verificar type hints en parámetros
|
|
456
|
+
// Excluir self, cls, *args, **kwargs de la verificación
|
|
457
|
+
const paramsList = params
|
|
458
|
+
.split(',')
|
|
459
|
+
.map(p => p.trim())
|
|
460
|
+
.filter(p => p && p !== 'self' && p !== 'cls' && !p.startsWith('*'));
|
|
461
|
+
|
|
462
|
+
// Un parámetro tiene type hint si contiene ":"
|
|
463
|
+
const paramsSinHint = paramsList.filter(p => {
|
|
464
|
+
// Excluir parámetros con valor por defecto que ya tienen hint: "x: int = 0"
|
|
465
|
+
const baseParam = p.split('=')[0].trim();
|
|
466
|
+
return baseParam && !baseParam.includes(':');
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
if (paramsSinHint.length > 0) {
|
|
470
|
+
mensajes.push(
|
|
471
|
+
` [TYPE HINT] ${rutaRelativa}:${i + 1} — def ${nombreFuncion}(): parámetros sin anotación: ${paramsSinHint.join(', ')}`
|
|
472
|
+
);
|
|
473
|
+
continue; // No duplicar alerta si también falta retorno
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Verificar type hint de retorno (-> tipo)
|
|
477
|
+
if (retorno.trim() === '') {
|
|
478
|
+
mensajes.push(
|
|
479
|
+
` [TYPE HINT] ${rutaRelativa}:${i + 1} — def ${nombreFuncion}(): falta anotación de retorno (->)`
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return { ok: mensajes.length === 0, mensajes };
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Verifica que no haya bloques catch/except vacíos o con solo pass/comentario.
|
|
489
|
+
* Detecta errores silenciosos que ocultan fallos en producción.
|
|
490
|
+
* Excluye archivos de test.
|
|
491
|
+
*
|
|
492
|
+
* Patrones detectados:
|
|
493
|
+
* - JS/TS: catch (e) {} o catch { }
|
|
494
|
+
* - Python: except: pass / except Exception: pass
|
|
495
|
+
* - Go: if err != nil { } (bloque vacío después de error check)
|
|
496
|
+
*
|
|
497
|
+
* @param {string} rutaRelativa
|
|
498
|
+
* @param {string} contenido
|
|
499
|
+
* @param {string} ext
|
|
500
|
+
* @returns {{ ok: boolean, mensajes: string[] }}
|
|
501
|
+
*/
|
|
502
|
+
function verificarErroresSilenciosos(rutaRelativa, contenido, ext) {
|
|
503
|
+
const esArchivoExcluido = /\.(test|spec)\.[jt]s$/.test(rutaRelativa) ||
|
|
504
|
+
/[/\\]tests?[/\\]/.test(rutaRelativa) ||
|
|
505
|
+
/[/\\]__tests__[/\\]/.test(rutaRelativa) ||
|
|
506
|
+
/^scripts[/\\]/.test(rutaRelativa) ||
|
|
507
|
+
/^hooks[/\\]/.test(rutaRelativa) ||
|
|
508
|
+
/^tests[/\\]/.test(rutaRelativa) ||
|
|
509
|
+
/test.*\.py$/.test(rutaRelativa) ||
|
|
510
|
+
/_test\.go$/.test(rutaRelativa);
|
|
511
|
+
|
|
512
|
+
if (esArchivoExcluido) return { ok: true, mensajes: [] };
|
|
513
|
+
|
|
514
|
+
const extensionesAplicables = new Set(['.js', '.ts', '.tsx', '.py', '.go', '.java', '.kt', '.cs', '.rs', '.php', '.swift']);
|
|
515
|
+
if (!extensionesAplicables.has(ext)) return { ok: true, mensajes: [] };
|
|
516
|
+
|
|
517
|
+
const lineas = contenido.split('\n');
|
|
518
|
+
const mensajes = [];
|
|
519
|
+
const esComentario = /^\s*(\/\/|\/\*|\*|#)/;
|
|
520
|
+
|
|
521
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
522
|
+
const linea = lineas[i];
|
|
523
|
+
if (esComentario.test(linea)) continue;
|
|
524
|
+
|
|
525
|
+
// JS/TS/Java/Kotlin/C#: catch vacío — catch(...) { } o catch { }
|
|
526
|
+
if (['.js', '.ts', '.tsx', '.java', '.kt', '.cs'].includes(ext)) {
|
|
527
|
+
if (/catch\s*(\([^)]*\))?\s*\{\s*\}/.test(linea)) {
|
|
528
|
+
mensajes.push(
|
|
529
|
+
` [SILENT] ${rutaRelativa}:${i + 1} — catch vacío: error ignorado silenciosamente`
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// Python: except: pass / except Exception: pass
|
|
535
|
+
if (ext === '.py') {
|
|
536
|
+
if (/^\s*except(\s+\w+)?(\s+as\s+\w+)?\s*:\s*$/.test(linea)) {
|
|
537
|
+
const siguienteLinea = (lineas[i + 1] || '').trim();
|
|
538
|
+
if (siguienteLinea === 'pass' || siguienteLinea === '...') {
|
|
539
|
+
mensajes.push(
|
|
540
|
+
` [SILENT] ${rutaRelativa}:${i + 1} — except con solo pass: error ignorado silenciosamente`
|
|
541
|
+
);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Go: if err != nil { } (bloque vacío)
|
|
547
|
+
if (ext === '.go') {
|
|
548
|
+
if (/if\s+err\s*!=\s*nil\s*\{\s*\}/.test(linea)) {
|
|
549
|
+
mensajes.push(
|
|
550
|
+
` [SILENT] ${rutaRelativa}:${i + 1} — error check vacío (if err != nil {})`
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// Rust: if let Err(_) = ... { } o .unwrap_or_default() sin justificación
|
|
556
|
+
// (ligero: solo catch vacío explícito)
|
|
557
|
+
if (ext === '.rs') {
|
|
558
|
+
if (/if\s+let\s+Err\s*\(_\)\s*=.*\{\s*\}/.test(linea)) {
|
|
559
|
+
mensajes.push(
|
|
560
|
+
` [SILENT] ${rutaRelativa}:${i + 1} — error match vacío: Err ignorado silenciosamente`
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// PHP: catch vacío
|
|
566
|
+
if (ext === '.php') {
|
|
567
|
+
if (/catch\s*\([^)]*\)\s*\{\s*\}/.test(linea)) {
|
|
568
|
+
mensajes.push(
|
|
569
|
+
` [SILENT] ${rutaRelativa}:${i + 1} — catch vacío: excepción ignorada silenciosamente`
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
return { ok: mensajes.length === 0, mensajes };
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// ---------------------------------------------------------------------------
|
|
579
|
+
// Verificador principal por archivo
|
|
580
|
+
// ---------------------------------------------------------------------------
|
|
581
|
+
|
|
582
|
+
/**
|
|
583
|
+
* Ejecuta todas las verificaciones aplicables sobre un archivo staged.
|
|
584
|
+
*
|
|
585
|
+
* @param {string} rutaRelativa - Ruta relativa del archivo en el repositorio.
|
|
586
|
+
* @returns {string[]} Lista de mensajes de violación. Vacía si pasa todo.
|
|
587
|
+
*/
|
|
588
|
+
function verificarArchivo(rutaRelativa) {
|
|
589
|
+
const ext = path.extname(rutaRelativa).toLowerCase();
|
|
590
|
+
const violaciones = [];
|
|
591
|
+
|
|
592
|
+
// --- Verificación de tamaño (aplica a todos) ---
|
|
593
|
+
const { ok: tamanoOk, mensaje: mensajeTamano } = verificarTamano(rutaRelativa);
|
|
594
|
+
if (!tamanoOk) {
|
|
595
|
+
violaciones.push(mensajeTamano);
|
|
596
|
+
// Si el archivo es muy grande, no intentar leerlo para análisis de texto
|
|
597
|
+
return violaciones;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
// Omitir análisis de texto en archivos binarios conocidos
|
|
601
|
+
if (EXTENSIONES_BINARIAS.has(ext)) return violaciones;
|
|
602
|
+
|
|
603
|
+
// Obtener contenido staged para análisis de texto
|
|
604
|
+
const contenido = obtenerContenidoStaged(rutaRelativa);
|
|
605
|
+
if (contenido === null) return violaciones; // Binario detectado dinámicamente
|
|
606
|
+
|
|
607
|
+
// --- Verificación de credenciales (aplica a todos los archivos de texto) ---
|
|
608
|
+
const { mensajes: msgsCredencial } = verificarCredenciales(rutaRelativa, contenido);
|
|
609
|
+
violaciones.push(...msgsCredencial);
|
|
610
|
+
|
|
611
|
+
// --- Verificación de pendientes sin ticket (aplica a todos los archivos de texto) --- // nosec
|
|
612
|
+
const { mensajes: msgsTodo } = verificarTodosSinTicket(rutaRelativa, contenido);
|
|
613
|
+
violaciones.push(...msgsTodo);
|
|
614
|
+
|
|
615
|
+
// --- Verificación de errores silenciosos (aplica a código fuente multi-lenguaje) ---
|
|
616
|
+
const { mensajes: msgsSilent } = verificarErroresSilenciosos(rutaRelativa, contenido, ext);
|
|
617
|
+
violaciones.push(...msgsSilent);
|
|
618
|
+
|
|
619
|
+
// --- Verificaciones por extensión ---
|
|
620
|
+
if (ext === '.ts' || ext === '.js') {
|
|
621
|
+
const { mensajes: msgsConsole } = verificarConsoleLog(rutaRelativa, contenido);
|
|
622
|
+
violaciones.push(...msgsConsole);
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
if (ext === '.py') {
|
|
626
|
+
const { mensajes: msgsPrint } = verificarPrintPython(rutaRelativa, contenido);
|
|
627
|
+
violaciones.push(...msgsPrint);
|
|
628
|
+
|
|
629
|
+
const { mensajes: msgsHints } = verificarTypeHintsPython(rutaRelativa, contenido);
|
|
630
|
+
violaciones.push(...msgsHints);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// --- Java: System.out.println ---
|
|
634
|
+
if (ext === '.java') {
|
|
635
|
+
const esArchivoTestJava = /Test\.java$/.test(rutaRelativa) ||
|
|
636
|
+
/[/\\]tests?[/\\]/.test(rutaRelativa) ||
|
|
637
|
+
/[/\\]spec[/\\]/.test(rutaRelativa);
|
|
638
|
+
|
|
639
|
+
if (!esArchivoTestJava) {
|
|
640
|
+
const patronJavaPrint = /^\s*System\.(out|err)\.(println|print|printf)\s*\(/;
|
|
641
|
+
const esComentarioJava = /^\s*(\/\/|\/\*|\*)/;
|
|
642
|
+
const lineas = contenido.split('\n');
|
|
643
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
644
|
+
if (esComentarioJava.test(lineas[i])) continue;
|
|
645
|
+
if (patronJavaPrint.test(lineas[i])) {
|
|
646
|
+
violaciones.push(` [DEBUG] ${rutaRelativa}:${i + 1} — System.out.println en código de producción`);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// --- Go: fmt.Println ---
|
|
653
|
+
if (ext === '.go') {
|
|
654
|
+
const esArchivoTestGo = /_test\.go$/.test(rutaRelativa) ||
|
|
655
|
+
/[/\\]tests?[/\\]/.test(rutaRelativa);
|
|
656
|
+
|
|
657
|
+
if (!esArchivoTestGo) {
|
|
658
|
+
const patronGoPrint = /^\s*fmt\.(Println|Printf|Print)\s*\(/;
|
|
659
|
+
const esComentarioGo = /^\s*\/\//;
|
|
660
|
+
const lineas = contenido.split('\n');
|
|
661
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
662
|
+
if (esComentarioGo.test(lineas[i])) continue;
|
|
663
|
+
if (patronGoPrint.test(lineas[i])) {
|
|
664
|
+
violaciones.push(` [DEBUG] ${rutaRelativa}:${i + 1} — fmt.Println en código de producción (usar slog/log)`);
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// --- Rust: println! ---
|
|
671
|
+
if (ext === '.rs') {
|
|
672
|
+
const esArchivoTestRust = /[/\\]tests?[/\\]/.test(rutaRelativa) ||
|
|
673
|
+
/test.*\.rs$/.test(rutaRelativa);
|
|
674
|
+
|
|
675
|
+
if (!esArchivoTestRust) {
|
|
676
|
+
const patronRustPrint = /^\s*(println!|print!|eprintln!|eprint!)\s*\(/;
|
|
677
|
+
const esComentarioRust = /^\s*\/\//;
|
|
678
|
+
const lineas = contenido.split('\n');
|
|
679
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
680
|
+
if (esComentarioRust.test(lineas[i])) continue;
|
|
681
|
+
if (patronRustPrint.test(lineas[i])) {
|
|
682
|
+
violaciones.push(` [DEBUG] ${rutaRelativa}:${i + 1} — println! en código de producción (usar tracing)`);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// --- C#: Console.WriteLine ---
|
|
689
|
+
if (ext === '.cs') {
|
|
690
|
+
const esArchivoTestCsharp = /[Tt]est.*\.cs$/.test(rutaRelativa) ||
|
|
691
|
+
/[/\\]tests?[/\\]/.test(rutaRelativa) ||
|
|
692
|
+
/[Ss]pec.*\.cs$/.test(rutaRelativa);
|
|
693
|
+
|
|
694
|
+
if (!esArchivoTestCsharp) {
|
|
695
|
+
const patronCsharpPrint = /^\s*Console\.(WriteLine|Write|Error\.WriteLine)\s*\(/;
|
|
696
|
+
const esComentarioCsharp = /^\s*\/\//;
|
|
697
|
+
const lineas = contenido.split('\n');
|
|
698
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
699
|
+
if (esComentarioCsharp.test(lineas[i])) continue;
|
|
700
|
+
if (patronCsharpPrint.test(lineas[i])) {
|
|
701
|
+
violaciones.push(` [DEBUG] ${rutaRelativa}:${i + 1} — Console.WriteLine en código de producción (usar ILogger)`);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// --- Kotlin: println ---
|
|
708
|
+
if (ext === '.kt' || ext === '.kts') {
|
|
709
|
+
const esArchivoTestKotlin = /[Tt]est.*\.kts?$/.test(rutaRelativa) ||
|
|
710
|
+
/[/\\]tests?[/\\]/.test(rutaRelativa) ||
|
|
711
|
+
/[Ss]pec.*\.kts?$/.test(rutaRelativa);
|
|
712
|
+
|
|
713
|
+
if (!esArchivoTestKotlin) {
|
|
714
|
+
const patronKotlinPrint = /^\s*println\s*\(/;
|
|
715
|
+
const esComentarioKotlin = /^\s*\/\//;
|
|
716
|
+
const lineas = contenido.split('\n');
|
|
717
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
718
|
+
if (esComentarioKotlin.test(lineas[i])) continue;
|
|
719
|
+
if (patronKotlinPrint.test(lineas[i])) {
|
|
720
|
+
violaciones.push(` [DEBUG] ${rutaRelativa}:${i + 1} — println en código de producción (usar Timber/logger)`);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// --- PHP: var_dump / dd / dump / print_r / die ---
|
|
727
|
+
if (ext === '.php') {
|
|
728
|
+
const esArchivoTestPhp = /[Tt]est.*\.php$/.test(rutaRelativa) ||
|
|
729
|
+
/[/\\]tests?[/\\]/.test(rutaRelativa) ||
|
|
730
|
+
/[Ss]pec.*\.php$/.test(rutaRelativa);
|
|
731
|
+
|
|
732
|
+
if (!esArchivoTestPhp) {
|
|
733
|
+
const patronPhpDebug = /^\s*(var_dump|dd|dump|print_r|die)\s*\(/;
|
|
734
|
+
const esComentarioPhp = /^\s*(\/\/|\/\*|#)/;
|
|
735
|
+
const lineas = contenido.split('\n');
|
|
736
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
737
|
+
if (esComentarioPhp.test(lineas[i])) continue;
|
|
738
|
+
if (patronPhpDebug.test(lineas[i])) {
|
|
739
|
+
const nombre = lineas[i].trim().split('(')[0].trim();
|
|
740
|
+
violaciones.push(` [DEBUG] ${rutaRelativa}:${i + 1} — ${nombre} en código de producción`);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
// --- Swift: print() ---
|
|
747
|
+
if (ext === '.swift') {
|
|
748
|
+
const esArchivoTestSwift = /[Tt]est.*\.swift$/.test(rutaRelativa) ||
|
|
749
|
+
/[/\\]tests?[/\\]/.test(rutaRelativa) ||
|
|
750
|
+
/[Ss]pec.*\.swift$/.test(rutaRelativa);
|
|
751
|
+
|
|
752
|
+
if (!esArchivoTestSwift) {
|
|
753
|
+
const patronSwiftPrint = /^\s*print\s*\(/;
|
|
754
|
+
const esComentarioSwift = /^\s*\/\//;
|
|
755
|
+
const lineas = contenido.split('\n');
|
|
756
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
757
|
+
if (esComentarioSwift.test(lineas[i])) continue;
|
|
758
|
+
if (patronSwiftPrint.test(lineas[i])) {
|
|
759
|
+
violaciones.push(` [DEBUG] ${rutaRelativa}:${i + 1} — print() en código de producción (usar os_log/Logger)`);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return violaciones;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
// ---------------------------------------------------------------------------
|
|
769
|
+
// Risk score semántico (code-review-graph)
|
|
770
|
+
// ---------------------------------------------------------------------------
|
|
771
|
+
|
|
772
|
+
/**
|
|
773
|
+
* Ejecuta code-review-graph detect-changes y retorna mensajes de violación
|
|
774
|
+
* si el risk score supera el umbral configurado (0.7).
|
|
775
|
+
*
|
|
776
|
+
* Solo actúa si `.code-review-graph/graph.db` existe — es un check opcional.
|
|
777
|
+
* Nunca bloquea el commit por fallo interno del análisis.
|
|
778
|
+
*
|
|
779
|
+
* @returns {string[]} Mensajes de violación de riesgo semántico.
|
|
780
|
+
*/
|
|
781
|
+
function verificarRiskScore() {
|
|
782
|
+
try {
|
|
783
|
+
const dbPath = path.join(process.cwd(), '.code-review-graph', 'graph.db');
|
|
784
|
+
if (!fs.existsSync(dbPath)) return []; // Grafo no inicializado — saltar silenciosamente
|
|
785
|
+
|
|
786
|
+
const UMBRAL_RIESGO = 0.7;
|
|
787
|
+
|
|
788
|
+
const salidaRaw = execSync(
|
|
789
|
+
'python -c "import sys; sys.argv=[\'crg\',\'detect-changes\']; from code_review_graph.cli import main; main()"',
|
|
790
|
+
{ encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'], timeout: 15_000 }
|
|
791
|
+
);
|
|
792
|
+
|
|
793
|
+
const resultado = JSON.parse(salidaRaw.trim());
|
|
794
|
+
const { risk_score = 0, changed_functions = [], test_gaps = [], affected_flows = [] } = resultado;
|
|
795
|
+
|
|
796
|
+
if (risk_score < UMBRAL_RIESGO) return []; // Riesgo bajo — no reportar
|
|
797
|
+
|
|
798
|
+
const mensajes = [
|
|
799
|
+
` [RIESGO] Risk score semántico: ${risk_score.toFixed(2)} — supera umbral ${UMBRAL_RIESGO}`,
|
|
800
|
+
];
|
|
801
|
+
|
|
802
|
+
if (test_gaps.length > 0) {
|
|
803
|
+
const gaps = test_gaps.slice(0, 5).map(g => ` · ${g.name || g}`).join('\n');
|
|
804
|
+
mensajes.push(` [RIESGO] Funciones modificadas sin cobertura de tests (${test_gaps.length}):\n${gaps}`);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
if (affected_flows.length > 0) {
|
|
808
|
+
const flows = affected_flows.slice(0, 3).map(f => ` · ${f.name || f}`).join('\n');
|
|
809
|
+
mensajes.push(` [RIESGO] Flujos de ejecución afectados (${affected_flows.length}):\n${flows}`);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
if (changed_functions.length > 0) {
|
|
813
|
+
const fns = changed_functions.slice(0, 5)
|
|
814
|
+
.map(f => ` · ${f.name || f} (riesgo: ${(f.risk_score || 0).toFixed(2)})`)
|
|
815
|
+
.join('\n');
|
|
816
|
+
mensajes.push(` [RIESGO] Funciones de alto impacto (${changed_functions.length}):\n${fns}`);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
mensajes.push(` [RIESGO] Ejecuta /swl:revisar-impacto cambios para análisis detallado.`);
|
|
820
|
+
return mensajes;
|
|
821
|
+
|
|
822
|
+
} catch (_) {
|
|
823
|
+
return []; /* Fallo del análisis semántico nunca bloquea el commit */
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
// ---------------------------------------------------------------------------
|
|
828
|
+
// Entrypoint principal
|
|
829
|
+
// ---------------------------------------------------------------------------
|
|
830
|
+
|
|
831
|
+
let inputRaw = '';
|
|
832
|
+
|
|
833
|
+
process.stdin.on('data', chunk => {
|
|
834
|
+
inputRaw += chunk;
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
process.stdin.on('end', () => {
|
|
838
|
+
try {
|
|
839
|
+
const data = JSON.parse(inputRaw);
|
|
840
|
+
|
|
841
|
+
const toolName = String(data.tool_name || data.tool?.name || '');
|
|
842
|
+
const toolInput = data.tool_input || data.tool?.input || {};
|
|
843
|
+
const comando = String(toolInput.command || '');
|
|
844
|
+
const sessionId = String(data.session_id || 'default');
|
|
845
|
+
|
|
846
|
+
// Este hook solo aplica cuando el comando Bash es un git commit
|
|
847
|
+
if (toolName !== 'Bash') {
|
|
848
|
+
return;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
// Verificar que el comando incluye "git commit" (excluir --amend sin cambios,
|
|
852
|
+
// git commit --dry-run, etc. siguen pasando por las verificaciones)
|
|
853
|
+
if (!/\bgit\s+commit\b/.test(comando)) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
// Obtener archivos staged
|
|
858
|
+
const archivos = obtenerArchivosStagedGit();
|
|
859
|
+
if (archivos.length === 0) {
|
|
860
|
+
// Sin archivos staged, nada que verificar
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// Verificar cada archivo
|
|
865
|
+
const todasLasViolaciones = [];
|
|
866
|
+
|
|
867
|
+
for (const archivo of archivos) {
|
|
868
|
+
const violaciones = verificarArchivo(archivo);
|
|
869
|
+
todasLasViolaciones.push(...violaciones);
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
// --- Verificación de risk score semántico (code-review-graph) ---
|
|
873
|
+
// Ejecuta detect-changes solo si el grafo existe. No bloquea si falla.
|
|
874
|
+
const riskViolaciones = verificarRiskScore();
|
|
875
|
+
todasLasViolaciones.push(...riskViolaciones);
|
|
876
|
+
|
|
877
|
+
if (todasLasViolaciones.length > 0) {
|
|
878
|
+
const totalArchivos = archivos.length;
|
|
879
|
+
const totalViolaciones = todasLasViolaciones.length;
|
|
880
|
+
|
|
881
|
+
const razon = [
|
|
882
|
+
`Commit bloqueado: se encontraron ${totalViolaciones} violación(es) de calidad en ${totalArchivos} archivo(s) staged.`,
|
|
883
|
+
``,
|
|
884
|
+
`Problemas encontrados:`,
|
|
885
|
+
...todasLasViolaciones,
|
|
886
|
+
``,
|
|
887
|
+
`Acciones requeridas:`,
|
|
888
|
+
` [CREDENCIAL] → Mover el valor a una variable de entorno (.env no commiteado).`,
|
|
889
|
+
` [DEBUG] → Eliminar o comentar las sentencias de debug:`,
|
|
890
|
+
` JS/TS: console.log/debug`,
|
|
891
|
+
` Python: print()`,
|
|
892
|
+
` Java: System.out.println → usar SLF4J/Logback`,
|
|
893
|
+
` Go: fmt.Println → usar slog o log/slog`,
|
|
894
|
+
` Rust: println! → usar tracing o log`,
|
|
895
|
+
` C#: Console.WriteLine → usar ILogger<T>`,
|
|
896
|
+
` Kotlin: println → usar Timber o android.util.Log`,
|
|
897
|
+
` PHP: var_dump/dd/dump → usar Monolog`,
|
|
898
|
+
` Swift: print() → usar os_log o Logger`,
|
|
899
|
+
` [${`TO` + `DO`}] → Agregar referencia con ticket: (#123) o JIRA-456.`,
|
|
900
|
+
` [TAMAÑO] → Usar git-lfs o excluir el archivo en .gitignore.`,
|
|
901
|
+
` [TYPE HINT] → Agregar anotaciones de tipo a la función Python.`,
|
|
902
|
+
` [SILENT] → Agregar manejo de error explícito (log + acción), no catch/except vacío.`,
|
|
903
|
+
` [RIESGO] → Revisar cobertura de tests y ejecutar /swl:revisar-impacto cambios.`,
|
|
904
|
+
``,
|
|
905
|
+
`Para omitir una verificación específica en una línea, usa:`,
|
|
906
|
+
` Python: # noqa: SWL001`,
|
|
907
|
+
` JS/TS: // nosec`,
|
|
908
|
+
` Credencial: # pragma: allowlist secret`,
|
|
909
|
+
].join('\n');
|
|
910
|
+
|
|
911
|
+
// stdout: razón completa para el framework de hooks (hookSpecificOutput)
|
|
912
|
+
process.stdout.write(razon);
|
|
913
|
+
// stderr: resumen conciso visible en la interfaz de Claude Code
|
|
914
|
+
const resumen = [
|
|
915
|
+
`Commit bloqueado: ${totalViolaciones} violación(es) de calidad.`,
|
|
916
|
+
...todasLasViolaciones,
|
|
917
|
+
].join('\n');
|
|
918
|
+
process.stderr.write(resumen);
|
|
919
|
+
try { require('./lib/guardrail-metrics').recordActivation('calidad-pre-commit.js', sessionId, true); } catch (_) {}
|
|
920
|
+
process.exit(2);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// Todas las verificaciones pasaron — permitir el commit
|
|
924
|
+
try { require('./lib/guardrail-metrics').recordActivation('calidad-pre-commit.js', sessionId, false); } catch (_) {}
|
|
925
|
+
|
|
926
|
+
} catch (err) {
|
|
927
|
+
// El hook nunca bloquea por errores internos propios
|
|
928
|
+
}
|
|
929
|
+
});
|