@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,249 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook: resumen-sesion.js
|
|
6
|
+
* Tipo: Stop
|
|
7
|
+
*
|
|
8
|
+
* Se ejecuta cuando Claude Code termina una respuesta. Imprime un resumen
|
|
9
|
+
* compacto de la sesión: componentes SWL utilizados, tokens, costo y archivos.
|
|
10
|
+
*
|
|
11
|
+
* Solo imprime si la sesión tiene al menos 5 tool calls (evita ruido en
|
|
12
|
+
* interacciones triviales) y si hay componentes SWL registrados.
|
|
13
|
+
*
|
|
14
|
+
* Resultado:
|
|
15
|
+
* - stdout: resumen formateado (visible para Claude como contexto)
|
|
16
|
+
* - stderr: no escribe (nunca bloquea)
|
|
17
|
+
* - exit 0: siempre
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const os = require('os');
|
|
23
|
+
const { execFile } = require('child_process');
|
|
24
|
+
|
|
25
|
+
const bus = require('./lib/event-bus');
|
|
26
|
+
const runLog = require('./lib/run-log');
|
|
27
|
+
const abortRegistry = require('./lib/abort-registry');
|
|
28
|
+
|
|
29
|
+
// Umbral mínimo de tool calls para mostrar resumen cuando NO hay componentes SWL
|
|
30
|
+
// registrados. Si hay componentes, emitimos siempre (gap 3 resuelto en v5.8.1, mantenido en v5.10.0).
|
|
31
|
+
const MIN_TOOL_CALLS_SIN_COMPONENTES = 5;
|
|
32
|
+
const MIN_TOOL_CALLS_CON_COMPONENTES = 1;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Sincroniza los JSONL de Claude Code → SQLite (claude-usage) en segundo plano.
|
|
36
|
+
* No bloquea ni falla si Python no está disponible.
|
|
37
|
+
*/
|
|
38
|
+
function sincronizarUsageDB() {
|
|
39
|
+
const cliPath = path.join(__dirname, '..', 'scripts', 'vendor', 'claude-usage', 'cli.py');
|
|
40
|
+
if (!fs.existsSync(cliPath)) return;
|
|
41
|
+
|
|
42
|
+
const python = process.platform === 'win32' ? 'python' : 'python3';
|
|
43
|
+
execFile(python, [cliPath, 'scan'], { timeout: 30_000 }, () => {
|
|
44
|
+
// Silencioso — nunca bloquea el hook
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Lee el estado del bridge de tracking-costos para la sesión.
|
|
50
|
+
*/
|
|
51
|
+
function leerBridge(sessionId) {
|
|
52
|
+
const bridgePath = path.join(os.tmpdir(), `swl-costs-${sessionId}.json`);
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(fs.readFileSync(bridgePath, 'utf8'));
|
|
55
|
+
} catch (_) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Formatea número con separador de miles.
|
|
62
|
+
*/
|
|
63
|
+
function fmt(n) {
|
|
64
|
+
return n.toLocaleString('es-MX');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Genera el resumen de sesión.
|
|
69
|
+
*/
|
|
70
|
+
/**
|
|
71
|
+
* Lee los hooks SWL que se dispararon en la sesión actual.
|
|
72
|
+
* Fuente: eventos del event-bus (fallback: run-log).
|
|
73
|
+
* Esto complementa `componentesSWL.hooks` que solo captura registros manuales.
|
|
74
|
+
*/
|
|
75
|
+
function hooksDisparados(sessionId) {
|
|
76
|
+
const hooks = new Set();
|
|
77
|
+
try {
|
|
78
|
+
const eventos = (runLog.readEvents && runLog.readEvents(sessionId)) || [];
|
|
79
|
+
for (const e of eventos) {
|
|
80
|
+
if (e && typeof e.hook === 'string' && e.hook) hooks.add(e.hook);
|
|
81
|
+
}
|
|
82
|
+
} catch { /* ignore */ }
|
|
83
|
+
|
|
84
|
+
// Fallback: heurística por archivos JSONL de hooks conocidos en .planning/
|
|
85
|
+
try {
|
|
86
|
+
const planningDir = path.join(process.cwd(), '.planning');
|
|
87
|
+
const jsonlCandidatos = [
|
|
88
|
+
['evolucion/nudges.jsonl', 'nudge-tracker'],
|
|
89
|
+
['auto-evolucion/agentes.jsonl', 'auto-evolucion'],
|
|
90
|
+
['perfil-usuario/dirty.json', 'actualizar-perfil-usuario'],
|
|
91
|
+
['evolucion/metricas.json', 'metricas-evolucion'],
|
|
92
|
+
];
|
|
93
|
+
for (const [rel, nombre] of jsonlCandidatos) {
|
|
94
|
+
const p = path.join(planningDir, rel);
|
|
95
|
+
if (fs.existsSync(p)) {
|
|
96
|
+
const stat = fs.statSync(p);
|
|
97
|
+
// Si se modificó en los últimos 10 minutos, probablemente fue de esta sesión
|
|
98
|
+
if (Date.now() - stat.mtimeMs < 10 * 60 * 1000) {
|
|
99
|
+
hooks.add(nombre);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} catch { /* ignore */ }
|
|
104
|
+
|
|
105
|
+
return Array.from(hooks);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function generarResumen(estado, sessionId) {
|
|
109
|
+
const c = estado.componentesSWL || {};
|
|
110
|
+
|
|
111
|
+
// Fusionar hooks registrados con los detectados por JSONL recientes
|
|
112
|
+
const hooksDet = hooksDisparados(sessionId);
|
|
113
|
+
const hooksSet = new Set([...(c.hooks || []), ...hooksDet]);
|
|
114
|
+
const hooks = Array.from(hooksSet);
|
|
115
|
+
|
|
116
|
+
const tieneComponentes =
|
|
117
|
+
(c.agentes || []).length > 0 ||
|
|
118
|
+
(c.skills || []).length > 0 ||
|
|
119
|
+
(c.comandos || []).length > 0 ||
|
|
120
|
+
(c.scripts || []).length > 0 ||
|
|
121
|
+
(c.reglas || []).length > 0 ||
|
|
122
|
+
hooks.length > 0;
|
|
123
|
+
|
|
124
|
+
// Solo suprimir el resumen si NO hay componentes Y la sesión fue trivial.
|
|
125
|
+
const umbral = tieneComponentes
|
|
126
|
+
? MIN_TOOL_CALLS_CON_COMPONENTES
|
|
127
|
+
: MIN_TOOL_CALLS_SIN_COMPONENTES;
|
|
128
|
+
if (estado.toolCalls < umbral) return null;
|
|
129
|
+
if (!tieneComponentes && estado.toolCalls < MIN_TOOL_CALLS_SIN_COMPONENTES) return null;
|
|
130
|
+
|
|
131
|
+
// Si no hay ningún componente SWL registrado pero sí hubo muchas tool calls,
|
|
132
|
+
// emitir una nota mínima en lugar de nada (gap 3: "no se usó SWL visiblemente").
|
|
133
|
+
if (!tieneComponentes) {
|
|
134
|
+
return [
|
|
135
|
+
'',
|
|
136
|
+
'━━━ Resumen de sesión SWL ━━━',
|
|
137
|
+
` Herramientas: ${fmt(estado.toolCalls)} llamadas | Tokens: ~${fmt(estado.tokensTotal)} | Costo: ~$${estado.costoTotal.toFixed(2)} USD`,
|
|
138
|
+
' Componentes SWL usados: ninguno registrado (sesión sin delegación a agentes ni carga explícita de skills).',
|
|
139
|
+
' Tip: invoca agentes con Agent(subagent_type="...-swl") o skills con Skill("...") para registrarlos.',
|
|
140
|
+
'━━━━━━━━━━━━━━━━━━━━━━━━━━━━━',
|
|
141
|
+
'',
|
|
142
|
+
].join('\n');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const lineas = [];
|
|
146
|
+
lineas.push('');
|
|
147
|
+
lineas.push('━━━ Resumen de sesión SWL ━━━');
|
|
148
|
+
lineas.push(` Herramientas: ${fmt(estado.toolCalls)} llamadas | Tokens: ~${fmt(estado.tokensTotal)} | Costo: ~$${estado.costoTotal.toFixed(2)} USD`);
|
|
149
|
+
|
|
150
|
+
if ((c.agentes || []).length > 0) {
|
|
151
|
+
lineas.push(` Agentes (${c.agentes.length}): ${c.agentes.join(', ')}`);
|
|
152
|
+
}
|
|
153
|
+
if ((c.skills || []).length > 0) {
|
|
154
|
+
lineas.push(` Skills (${c.skills.length}): ${c.skills.join(', ')}`);
|
|
155
|
+
}
|
|
156
|
+
if ((c.comandos || []).length > 0) {
|
|
157
|
+
lineas.push(` Comandos: ${c.comandos.join(', ')}`);
|
|
158
|
+
}
|
|
159
|
+
if ((c.scripts || []).length > 0) {
|
|
160
|
+
lineas.push(` Scripts: ${c.scripts.join(', ')}`);
|
|
161
|
+
}
|
|
162
|
+
if (hooks.length > 0) {
|
|
163
|
+
lineas.push(` Hooks (${hooks.length}): ${hooks.join(', ')}`);
|
|
164
|
+
}
|
|
165
|
+
if ((c.reglas || []).length > 0) {
|
|
166
|
+
lineas.push(` Reglas: ${c.reglas.join(', ')}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Top 5 herramientas más usadas
|
|
170
|
+
const topTools = Object.entries(estado.desglosePorHerramienta || {})
|
|
171
|
+
.sort(([, a], [, b]) => b.llamadas - a.llamadas)
|
|
172
|
+
.slice(0, 5)
|
|
173
|
+
.map(([nombre, datos]) => `${nombre}(${datos.llamadas})`)
|
|
174
|
+
.join(', ');
|
|
175
|
+
if (topTools) {
|
|
176
|
+
lineas.push(` Top herramientas: ${topTools}`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
lineas.push('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
|
|
180
|
+
lineas.push('');
|
|
181
|
+
|
|
182
|
+
return lineas.join('\n');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ---------------------------------------------------------------------------
|
|
186
|
+
// Entrypoint
|
|
187
|
+
// ---------------------------------------------------------------------------
|
|
188
|
+
|
|
189
|
+
let inputRaw = '';
|
|
190
|
+
|
|
191
|
+
process.stdin.on('data', chunk => {
|
|
192
|
+
inputRaw += chunk;
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
process.stdin.on('end', () => {
|
|
196
|
+
try {
|
|
197
|
+
const data = JSON.parse(inputRaw);
|
|
198
|
+
const sessionId = String(data.session_id || 'default');
|
|
199
|
+
|
|
200
|
+
// Registrar sesión activa en abort-registry para manejo de señales
|
|
201
|
+
abortRegistry.registrarSesionActiva(sessionId);
|
|
202
|
+
|
|
203
|
+
// Sincronizar JSONL → SQLite en background (claude-usage)
|
|
204
|
+
sincronizarUsageDB();
|
|
205
|
+
|
|
206
|
+
const estado = leerBridge(sessionId);
|
|
207
|
+
|
|
208
|
+
// Registrar evento session-stop en JSONL de run (trazabilidad)
|
|
209
|
+
if (estado) {
|
|
210
|
+
runLog.sessionStop(sessionId, {
|
|
211
|
+
toolCalls: estado.toolCalls || 0,
|
|
212
|
+
tokensTotal: estado.tokensTotal || 0,
|
|
213
|
+
costoTotal: estado.costoTotal || 0,
|
|
214
|
+
modeloPredominante: estado.modeloPredominante || 'unknown',
|
|
215
|
+
});
|
|
216
|
+
bus.publish({
|
|
217
|
+
type: 'session-stop',
|
|
218
|
+
runId: sessionId,
|
|
219
|
+
toolCalls: estado.toolCalls || 0,
|
|
220
|
+
costoTotal: estado.costoTotal || 0,
|
|
221
|
+
modeloPredominante: estado.modeloPredominante || 'unknown',
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// Limpiar abort-registry post-sesión
|
|
226
|
+
abortRegistry.cleanup(sessionId);
|
|
227
|
+
|
|
228
|
+
if (!estado) return;
|
|
229
|
+
|
|
230
|
+
const resumen = generarResumen(estado, sessionId);
|
|
231
|
+
if (resumen) {
|
|
232
|
+
// Agregar diagnóstico de guardrails al resumen de sesión si hay activaciones
|
|
233
|
+
let resumenCompleto = resumen;
|
|
234
|
+
try {
|
|
235
|
+
const { getMetrics, diagnosticar } = require('./lib/guardrail-metrics');
|
|
236
|
+
const metricas = getMetrics(sessionId);
|
|
237
|
+
const advertencias = diagnosticar(metricas);
|
|
238
|
+
if (advertencias.length > 0) {
|
|
239
|
+
resumenCompleto += '\n⚠ Diagnóstico de guardrails:\n' +
|
|
240
|
+
advertencias.map(a => ' - ' + a).join('\n') + '\n';
|
|
241
|
+
}
|
|
242
|
+
} catch (_) { /* métricas opcionales */ }
|
|
243
|
+
|
|
244
|
+
process.stdout.write(resumenCompleto);
|
|
245
|
+
}
|
|
246
|
+
} catch (_) {
|
|
247
|
+
// Nunca bloquear
|
|
248
|
+
}
|
|
249
|
+
});
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook: risk-scoring.js
|
|
6
|
+
* Tipo: PreToolUse (aplica a: todas las herramientas — matcher vacío)
|
|
7
|
+
*
|
|
8
|
+
* Evalúa el riesgo de cada operación de Claude Code usando el motor de scoring
|
|
9
|
+
* compuesto definido en lib/risk-engine.js. Toma decisiones en 4 niveles:
|
|
10
|
+
*
|
|
11
|
+
* allow (score < 0.35) — Continúa silenciosamente.
|
|
12
|
+
* review (score < 0.60) — Emite advertencia en stderr y continúa.
|
|
13
|
+
* confirm (score < 0.85) — Bloquea con mensaje que solicita reformulación
|
|
14
|
+
* o aprobación explícita del usuario.
|
|
15
|
+
* block (score ≥ 0.85) — Bloquea con mensaje de operación peligrosa.
|
|
16
|
+
*
|
|
17
|
+
* La fórmula de scoring es:
|
|
18
|
+
* score = min(1.0, baseRisk + fileSensitivity + blastRadius + irreversibility)
|
|
19
|
+
*
|
|
20
|
+
* Resultado:
|
|
21
|
+
* - allow → exit 0, sin output
|
|
22
|
+
* - review → exit 0, warning en stderr
|
|
23
|
+
* - confirm → exit 2, JSON {result:"block", reason:"..."} en stdout
|
|
24
|
+
* - block → exit 2, JSON {result:"block", reason:"..."} en stdout
|
|
25
|
+
* - Error → exit 0 (nunca bloquear por fallo interno del hook)
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const fs = require('fs');
|
|
29
|
+
const path = require('path');
|
|
30
|
+
const os = require('os');
|
|
31
|
+
|
|
32
|
+
// Cargar el motor de scoring desde lib/ relativo al directorio de este script
|
|
33
|
+
const { calcularRiskScore, UMBRALES_DEFAULT } = require(
|
|
34
|
+
path.join(__dirname, 'lib', 'risk-engine.js')
|
|
35
|
+
);
|
|
36
|
+
const { getDelegationRiskFactor } = require(
|
|
37
|
+
path.join(__dirname, 'lib', 'delegation-tracker.js')
|
|
38
|
+
);
|
|
39
|
+
const { isTripped, recordFailure, recordSuccess } = require(
|
|
40
|
+
path.join(__dirname, 'lib', 'hook-circuit-breaker.js')
|
|
41
|
+
);
|
|
42
|
+
const { normalizar, formatear } = require(
|
|
43
|
+
path.join(__dirname, 'lib', 'normalize-error.js')
|
|
44
|
+
);
|
|
45
|
+
const { tracker: taintTracker } = require(
|
|
46
|
+
path.join(__dirname, 'lib', 'taint-tracker.js')
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// Override tracking — registra cuando el usuario ignora advertencias de riesgo
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
const HOOK_NAME = 'risk-scoring';
|
|
54
|
+
const MAX_HIGH_OVERRIDES = 5;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Ruta del archivo de tracking de overrides por sesión.
|
|
58
|
+
*/
|
|
59
|
+
function overrideTrackingPath() {
|
|
60
|
+
const sessionId = process.env.SWL_SESSION_ID || 'default';
|
|
61
|
+
return path.join(os.tmpdir(), `swl-risk-overrides-${sessionId}.json`);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Lee el estado de overrides.
|
|
66
|
+
*/
|
|
67
|
+
function readOverrides() {
|
|
68
|
+
try {
|
|
69
|
+
return JSON.parse(fs.readFileSync(overrideTrackingPath(), 'utf8'));
|
|
70
|
+
} catch {
|
|
71
|
+
return { highOverrides: 0, auditWritten: false, entries: [] };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Escribe el estado de overrides.
|
|
77
|
+
*/
|
|
78
|
+
function writeOverrides(state) {
|
|
79
|
+
try {
|
|
80
|
+
fs.writeFileSync(overrideTrackingPath(), JSON.stringify(state), 'utf8');
|
|
81
|
+
} catch { /* silencioso */ }
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Registra un override de nivel alto y escribe audit si supera el umbral.
|
|
86
|
+
*/
|
|
87
|
+
function trackHighOverride(score, factors, toolName) {
|
|
88
|
+
const state = readOverrides();
|
|
89
|
+
state.highOverrides += 1;
|
|
90
|
+
state.entries.push({
|
|
91
|
+
timestamp: new Date().toISOString(),
|
|
92
|
+
score: score.toFixed(2),
|
|
93
|
+
tool: toolName,
|
|
94
|
+
factors: Array.isArray(factors) ? factors : Object.keys(factors),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
if (state.highOverrides >= MAX_HIGH_OVERRIDES && !state.auditWritten) {
|
|
98
|
+
const auditPath = path.join(process.cwd(), '.planning', 'AUDITORIA.md');
|
|
99
|
+
try {
|
|
100
|
+
const auditEntry = [
|
|
101
|
+
'',
|
|
102
|
+
`## [${new Date().toISOString().slice(0, 16)}] risk-override-threshold`,
|
|
103
|
+
'',
|
|
104
|
+
`**Agente**: sesión activa`,
|
|
105
|
+
'',
|
|
106
|
+
`**Operación**: ${state.highOverrides} operaciones de riesgo alto aceptadas sin mitigación`,
|
|
107
|
+
'',
|
|
108
|
+
`**Justificación**: registro automático — umbral de ${MAX_HIGH_OVERRIDES} overrides superado`,
|
|
109
|
+
'',
|
|
110
|
+
`**Detalle de overrides**:`,
|
|
111
|
+
'',
|
|
112
|
+
...state.entries.map(e => `- ${e.timestamp.slice(0, 16)} | ${e.tool} | score ${e.score}`),
|
|
113
|
+
'',
|
|
114
|
+
`**Estado**: registrado automáticamente por risk-scoring.js`,
|
|
115
|
+
'',
|
|
116
|
+
'---',
|
|
117
|
+
'',
|
|
118
|
+
].join('\n');
|
|
119
|
+
|
|
120
|
+
if (fs.existsSync(auditPath)) {
|
|
121
|
+
fs.appendFileSync(auditPath, auditEntry);
|
|
122
|
+
} else {
|
|
123
|
+
const dir = path.dirname(auditPath);
|
|
124
|
+
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
125
|
+
fs.writeFileSync(auditPath, `# Registro de Auditoría\n\nRegistro automático de operaciones de alto riesgo generado por \`risk-scoring.js\`.\n${auditEntry}`);
|
|
126
|
+
}
|
|
127
|
+
state.auditWritten = true;
|
|
128
|
+
} catch { /* no bloquear por fallo de audit */ }
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
writeOverrides(state);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Construcción de mensajes
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Construye el mensaje de bloqueo para niveles 'confirm' y 'block'.
|
|
140
|
+
*
|
|
141
|
+
* El mensaje para 'confirm' usa un tono más suave: solicita reformulación
|
|
142
|
+
* o aprobación explícita en lugar de declarar la operación directamente
|
|
143
|
+
* peligrosa. El mensaje para 'block' usa lenguaje más firme.
|
|
144
|
+
*
|
|
145
|
+
* @param {'confirm'|'block'} level - Nivel de decisión.
|
|
146
|
+
* @param {number} score - Score calculado.
|
|
147
|
+
* @param {string[]} factors - Factores que contribuyeron al score.
|
|
148
|
+
* @param {object} umbrales - Umbrales usados en la evaluación.
|
|
149
|
+
* @returns {string}
|
|
150
|
+
*/
|
|
151
|
+
function construirMensajeBloqueo(level, score, factors, umbrales) {
|
|
152
|
+
const factoresTexto = factors.length > 0
|
|
153
|
+
? factors.map(f => ` - ${f}`).join('\n')
|
|
154
|
+
: ' - (sin factores específicos identificados)';
|
|
155
|
+
|
|
156
|
+
if (level === 'confirm') {
|
|
157
|
+
return [
|
|
158
|
+
`Operación pausada por Risk Scoring (score: ${score.toFixed(2)} / umbral de confirmación: ${umbrales.confirm}).`,
|
|
159
|
+
``,
|
|
160
|
+
`Esta operación requiere confirmación explícita antes de continuar.`,
|
|
161
|
+
``,
|
|
162
|
+
`Factores de riesgo detectados:`,
|
|
163
|
+
factoresTexto,
|
|
164
|
+
``,
|
|
165
|
+
`Para proceder:`,
|
|
166
|
+
` 1. Solicita aprobación explícita al usuario antes de ejecutar esta operación.`,
|
|
167
|
+
` 2. O reformula la operación reduciendo su alcance o riesgo.`,
|
|
168
|
+
` 3. Si el usuario ya aprobó explícitamente, indica "aprobado por el usuario" en tu mensaje.`,
|
|
169
|
+
].join('\n');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// level === 'block'
|
|
173
|
+
return [
|
|
174
|
+
`Operación bloqueada por Risk Scoring (score: ${score.toFixed(2)} / umbral: ${umbrales.confirm}).`,
|
|
175
|
+
``,
|
|
176
|
+
`Factores de riesgo detectados:`,
|
|
177
|
+
factoresTexto,
|
|
178
|
+
``,
|
|
179
|
+
`Para proceder, reformula la operación con menor riesgo o solicita aprobación explícita.`,
|
|
180
|
+
].join('\n');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Construye el mensaje de advertencia para nivel 'review'.
|
|
185
|
+
*
|
|
186
|
+
* @param {number} score - Score calculado.
|
|
187
|
+
* @param {string[]} factors - Factores que contribuyeron al score.
|
|
188
|
+
* @param {object} umbrales - Umbrales usados en la evaluación.
|
|
189
|
+
* @returns {string}
|
|
190
|
+
*/
|
|
191
|
+
function construirMensajeReview(score, factors, umbrales) {
|
|
192
|
+
const factoresTexto = factors.length > 0
|
|
193
|
+
? factors.map(f => ` - ${f}`).join('\n')
|
|
194
|
+
: ' - (sin factores específicos identificados)';
|
|
195
|
+
|
|
196
|
+
return [
|
|
197
|
+
`[risk-scoring] ADVERTENCIA — score de riesgo: ${score.toFixed(2)} (umbral review: ${umbrales.allow}, confirm: ${umbrales.review})`,
|
|
198
|
+
` Factores detectados:`,
|
|
199
|
+
factoresTexto,
|
|
200
|
+
` La operación continúa — verificar que es intencional.`,
|
|
201
|
+
].join('\n');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
// Entrypoint principal
|
|
206
|
+
// ---------------------------------------------------------------------------
|
|
207
|
+
|
|
208
|
+
let inputRaw = '';
|
|
209
|
+
|
|
210
|
+
process.stdin.on('data', chunk => {
|
|
211
|
+
inputRaw += chunk;
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
process.stdin.on('end', () => {
|
|
215
|
+
try {
|
|
216
|
+
// Circuit breaker: si el hook ha fallado demasiadas veces, degradar
|
|
217
|
+
if (isTripped(HOOK_NAME, { maxConsecutive: 5 })) {
|
|
218
|
+
process.stderr.write('[risk-scoring] Circuit breaker activo — hook degradado a pass-through\n');
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const data = JSON.parse(inputRaw);
|
|
223
|
+
|
|
224
|
+
const toolName = String(data.tool_name || data.tool?.name || '');
|
|
225
|
+
const toolInput = data.tool_input || data.tool?.input || {};
|
|
226
|
+
const sessionId = String(data.session_id || 'default');
|
|
227
|
+
|
|
228
|
+
// Sin nombre de herramienta: nada que evaluar
|
|
229
|
+
if (!toolName) {
|
|
230
|
+
recordSuccess(HOOK_NAME);
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Taint tracking: registrar sources y verificar sinks
|
|
235
|
+
const targetPath = toolInput.file_path || toolInput.command || toolInput.url || '';
|
|
236
|
+
if (/^Read$/i.test(toolName) || /^WebFetch$/i.test(toolName)) {
|
|
237
|
+
taintTracker.registrarSource(toolName, targetPath);
|
|
238
|
+
}
|
|
239
|
+
const taintViolation = taintTracker.verificarSink(toolName, targetPath);
|
|
240
|
+
if (taintViolation) {
|
|
241
|
+
const msg = [
|
|
242
|
+
`Operación bloqueada por Taint Tracking (${taintViolation.severity}).`,
|
|
243
|
+
``,
|
|
244
|
+
`Flujo de información peligroso detectado:`,
|
|
245
|
+
` ${taintViolation.flujo}`,
|
|
246
|
+
``,
|
|
247
|
+
`${taintViolation.descripcion}.`,
|
|
248
|
+
`Reformula la operación sin propagar datos sensibles a este destino.`,
|
|
249
|
+
].join('\n');
|
|
250
|
+
process.stderr.write(msg);
|
|
251
|
+
try { require('./lib/guardrail-metrics').recordActivation('risk-scoring.js', sessionId, true); } catch (_) {}
|
|
252
|
+
recordSuccess(HOOK_NAME);
|
|
253
|
+
process.exit(2);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Calcular el score de riesgo compuesto
|
|
257
|
+
const result = calcularRiskScore(toolName, toolInput, UMBRALES_DEFAULT);
|
|
258
|
+
|
|
259
|
+
// Agregar factor de profundidad de delegación (0.15 por nivel)
|
|
260
|
+
const delegationFactor = getDelegationRiskFactor();
|
|
261
|
+
result.score = Math.min(1.0, result.score + delegationFactor);
|
|
262
|
+
if (delegationFactor > 0) {
|
|
263
|
+
result.factors.delegation = delegationFactor;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Recalcular level después del ajuste por delegación
|
|
267
|
+
const { score, factors } = result;
|
|
268
|
+
const level = score >= UMBRALES_DEFAULT.confirm ? 'block'
|
|
269
|
+
: score >= UMBRALES_DEFAULT.review ? 'confirm'
|
|
270
|
+
: score >= UMBRALES_DEFAULT.allow ? 'review'
|
|
271
|
+
: 'allow';
|
|
272
|
+
|
|
273
|
+
switch (level) {
|
|
274
|
+
case 'allow':
|
|
275
|
+
// Operación segura — exit 0 (allow)
|
|
276
|
+
recordSuccess(HOOK_NAME);
|
|
277
|
+
return;
|
|
278
|
+
|
|
279
|
+
case 'review': {
|
|
280
|
+
// Advertencia visible pero no bloqueante — stdout con info, exit 0 (allow)
|
|
281
|
+
const mensajeReview = construirMensajeReview(score, factors, UMBRALES_DEFAULT);
|
|
282
|
+
process.stderr.write(mensajeReview);
|
|
283
|
+
// Registrar como override si el score era alto (>= confirm threshold)
|
|
284
|
+
if (score >= UMBRALES_DEFAULT.review) {
|
|
285
|
+
trackHighOverride(score, factors, toolName);
|
|
286
|
+
}
|
|
287
|
+
try { require('./lib/guardrail-metrics').recordActivation('risk-scoring.js', sessionId, false); } catch (_) {}
|
|
288
|
+
recordSuccess(HOOK_NAME);
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
case 'confirm': {
|
|
293
|
+
// Bloqueo suave: solicita confirmación — exit 2 (block)
|
|
294
|
+
// stderr: Claude recibe el mensaje y puede razonar con él.
|
|
295
|
+
const mensajeConfirm = construirMensajeBloqueo('confirm', score, factors, UMBRALES_DEFAULT);
|
|
296
|
+
process.stderr.write(mensajeConfirm);
|
|
297
|
+
try { require('./lib/guardrail-metrics').recordActivation('risk-scoring.js', sessionId, true); } catch (_) {}
|
|
298
|
+
recordSuccess(HOOK_NAME);
|
|
299
|
+
process.exit(2);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
case 'block': {
|
|
303
|
+
// Bloqueo firme: operación peligrosa — exit 2 (block)
|
|
304
|
+
// stderr: Claude recibe el mensaje y puede razonar con él.
|
|
305
|
+
const mensajeBlock = construirMensajeBloqueo('block', score, factors, UMBRALES_DEFAULT);
|
|
306
|
+
process.stderr.write(mensajeBlock);
|
|
307
|
+
try { require('./lib/guardrail-metrics').recordActivation('risk-scoring.js', sessionId, true); } catch (_) {}
|
|
308
|
+
recordSuccess(HOOK_NAME);
|
|
309
|
+
process.exit(2);
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
default:
|
|
313
|
+
recordSuccess(HOOK_NAME);
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
} catch (err) {
|
|
318
|
+
// El hook nunca bloquea por errores internos propios
|
|
319
|
+
const errNorm = normalizar(err, { fuente: 'risk-scoring' });
|
|
320
|
+
process.stderr.write(`[risk-scoring] ${formatear(errNorm)}\n`);
|
|
321
|
+
recordFailure(HOOK_NAME);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook: rotar-audit-auto.js
|
|
6
|
+
* Tipo: Stop
|
|
7
|
+
*
|
|
8
|
+
* Se ejecuta al terminar una respuesta. Verifica si los archivos de auditoría
|
|
9
|
+
* (.planning/audit.jsonl y audit-merkle.jsonl) superan el umbral configurable
|
|
10
|
+
* y, de ser así, invoca scripts/rotar-audit-logs.js para archivar entradas
|
|
11
|
+
* antiguas a .planning/archivo/audit/<nombre>-YYYY-MM.jsonl.gz.
|
|
12
|
+
*
|
|
13
|
+
* Política:
|
|
14
|
+
* - Umbral default: 5 MB por archivo (UMBRAL_BYTES). Configurable vía env
|
|
15
|
+
* SWL_AUDIT_ROTATE_UMBRAL_MB (valor en MB, default 5).
|
|
16
|
+
* - Retención default: 30 días (coincide con el default del script).
|
|
17
|
+
* Configurable vía env SWL_AUDIT_ROTATE_DIAS.
|
|
18
|
+
* - Desactivable con SWL_AUDIT_ROTATE_OFF=1 (para CI o escenarios donde
|
|
19
|
+
* la rotación debe ser manual).
|
|
20
|
+
* - Cooldown: no se re-ejecuta si hubo una rotación exitosa en las últimas
|
|
21
|
+
* 6 horas (marca en .planning/archivo/audit/.ultima-rotacion).
|
|
22
|
+
*
|
|
23
|
+
* Resultado:
|
|
24
|
+
* - stdout: 1-2 líneas si se rotó, silencioso si no
|
|
25
|
+
* - stderr: nunca escribe
|
|
26
|
+
* - exit 0: siempre (hook no-bloqueante)
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const fs = require('fs');
|
|
30
|
+
const path = require('path');
|
|
31
|
+
const { spawnSync } = require('child_process');
|
|
32
|
+
|
|
33
|
+
const RAIZ_PROYECTO = path.resolve(__dirname, '..');
|
|
34
|
+
const DIR_PLANNING = path.join(RAIZ_PROYECTO, '.planning');
|
|
35
|
+
const ARCHIVOS_AUDIT = [
|
|
36
|
+
path.join(DIR_PLANNING, 'audit.jsonl'),
|
|
37
|
+
path.join(DIR_PLANNING, 'audit-merkle.jsonl'),
|
|
38
|
+
];
|
|
39
|
+
const DIR_ARCHIVO = path.join(DIR_PLANNING, 'archivo', 'audit');
|
|
40
|
+
const MARCA_ULTIMA_ROTACION = path.join(DIR_ARCHIVO, '.ultima-rotacion');
|
|
41
|
+
const SCRIPT_ROTAR = path.join(RAIZ_PROYECTO, 'scripts', 'rotar-audit-logs.js');
|
|
42
|
+
|
|
43
|
+
const COOLDOWN_MS = 6 * 60 * 60 * 1000; // 6 horas
|
|
44
|
+
|
|
45
|
+
function umbralBytes() {
|
|
46
|
+
const mb = parseFloat(process.env.SWL_AUDIT_ROTATE_UMBRAL_MB || '5');
|
|
47
|
+
return isNaN(mb) || mb <= 0 ? 5 * 1024 * 1024 : mb * 1024 * 1024;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function diasRetencion() {
|
|
51
|
+
const d = parseInt(process.env.SWL_AUDIT_ROTATE_DIAS || '30', 10);
|
|
52
|
+
return isNaN(d) || d <= 0 ? 30 : d;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function algunArchivoSuperaUmbral() {
|
|
56
|
+
const limite = umbralBytes();
|
|
57
|
+
for (const ruta of ARCHIVOS_AUDIT) {
|
|
58
|
+
try {
|
|
59
|
+
const st = fs.statSync(ruta);
|
|
60
|
+
if (st.size > limite) return { excedido: true, ruta, size: st.size, limite };
|
|
61
|
+
} catch (_) {
|
|
62
|
+
// Archivo ausente — ignorar
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return { excedido: false };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function enCooldown() {
|
|
69
|
+
try {
|
|
70
|
+
const raw = fs.readFileSync(MARCA_ULTIMA_ROTACION, 'utf8').trim();
|
|
71
|
+
const ultima = parseInt(raw, 10);
|
|
72
|
+
if (isNaN(ultima)) return false;
|
|
73
|
+
return Date.now() - ultima < COOLDOWN_MS;
|
|
74
|
+
} catch (_) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function marcarRotacion() {
|
|
80
|
+
try {
|
|
81
|
+
fs.mkdirSync(DIR_ARCHIVO, { recursive: true });
|
|
82
|
+
fs.writeFileSync(MARCA_ULTIMA_ROTACION, String(Date.now()), 'utf8');
|
|
83
|
+
} catch (_) {
|
|
84
|
+
// Silencioso — no crítico
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function main() {
|
|
89
|
+
if (process.env.SWL_AUDIT_ROTATE_OFF === '1') return;
|
|
90
|
+
if (!fs.existsSync(SCRIPT_ROTAR)) return;
|
|
91
|
+
|
|
92
|
+
const check = algunArchivoSuperaUmbral();
|
|
93
|
+
if (!check.excedido) return;
|
|
94
|
+
if (enCooldown()) return;
|
|
95
|
+
|
|
96
|
+
const dias = diasRetencion();
|
|
97
|
+
const nodeBin = process.execPath;
|
|
98
|
+
const result = spawnSync(
|
|
99
|
+
nodeBin,
|
|
100
|
+
[SCRIPT_ROTAR, `--dias=${dias}`, `--raiz=${DIR_PLANNING}`],
|
|
101
|
+
{ encoding: 'utf8', timeout: 30_000, cwd: RAIZ_PROYECTO }
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
if (result.status === 0) {
|
|
105
|
+
marcarRotacion();
|
|
106
|
+
const sizeMb = (check.size / 1024 / 1024).toFixed(1);
|
|
107
|
+
const limiteMb = (check.limite / 1024 / 1024).toFixed(1);
|
|
108
|
+
const nombreArchivo = path.basename(check.ruta);
|
|
109
|
+
const match = (result.stdout || '').match(/(\d+) archivadas/g);
|
|
110
|
+
const archivadas = match ? match.map((m) => m.replace(' archivadas', '')).join('+') : '?';
|
|
111
|
+
process.stdout.write(
|
|
112
|
+
`[rotacion-audit] ${nombreArchivo}=${sizeMb}MB > ${limiteMb}MB → archivadas ${archivadas} entradas (>${dias}d)\n`
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
main();
|
|
119
|
+
} catch (_) {
|
|
120
|
+
// Nunca bloquear
|
|
121
|
+
}
|
|
122
|
+
process.exit(0);
|