@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,208 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* validar-tokens-test.js
|
|
5
|
+
*
|
|
6
|
+
* Análisis estático: detecta literales con apariencia de token Telegram real
|
|
7
|
+
* (TELEGRAM_BOT_TOKEN=<valor> o TELEGRAM_CHAT_ID=<valor>) en archivos de test.
|
|
8
|
+
*
|
|
9
|
+
* Un token Telegram real tiene formato: <bot_id>:<hash_40chars>
|
|
10
|
+
* Un chat ID real tiene formato: [-]<número de 10+ dígitos>
|
|
11
|
+
*
|
|
12
|
+
* Este script NO bloquea por tokens con sufijo _test, _fake, _mock, ni por
|
|
13
|
+
* valores de longitud claramente inválida. Bloquea cuando el valor tiene
|
|
14
|
+
* apariencia estructuralmente válida de credencial real.
|
|
15
|
+
*
|
|
16
|
+
* Propósito: prevenir que fixtures de test con credenciales de apariencia real
|
|
17
|
+
* lleguen a commits y contaminen el .env del usuario o el historial de git.
|
|
18
|
+
* Introducido en v5.12.2 como Fix E.
|
|
19
|
+
*
|
|
20
|
+
* Uso:
|
|
21
|
+
* node scripts/validar-tokens-test.js
|
|
22
|
+
* node scripts/validar-tokens-test.js [directorio]
|
|
23
|
+
*
|
|
24
|
+
* Salida:
|
|
25
|
+
* 0 — ningún problema encontrado
|
|
26
|
+
* 1 — se encontraron literales de credencial con apariencia real
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
const fs = require('node:fs');
|
|
30
|
+
const path = require('node:path');
|
|
31
|
+
|
|
32
|
+
// ─── Configuración ─────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
const DIRECTORIO_DEFAULT = path.join(__dirname, '..', 'tests');
|
|
35
|
+
const EXTENSION = '.test.js';
|
|
36
|
+
|
|
37
|
+
// Comentario de exención explícita — úsalo cuando el valor es intencionalmente
|
|
38
|
+
// similar a un token real (ej: test de validación del formato del token).
|
|
39
|
+
// Ejemplo: const token = '1234567890:AABBCCxyz'; // swl-token-test:ok
|
|
40
|
+
const EXENCION_COMENTARIO = 'swl-token-test:ok';
|
|
41
|
+
|
|
42
|
+
// Regex para detectar un token de bot Telegram con apariencia real:
|
|
43
|
+
// Formato: <dígitos>:<letras_y_símbolos_de_40+chars>
|
|
44
|
+
// Se considera "apariencia real" si la parte hash tiene ≥ 25 caracteres alfanuméricos/guiones/guiones_bajos
|
|
45
|
+
const RX_BOT_TOKEN = /TELEGRAM_BOT_TOKEN\s*=\s*['"]?(\d{8,12}:[A-Za-z0-9_\-]{25,})['"]?/;
|
|
46
|
+
|
|
47
|
+
// Regex para detectar chat ID con apariencia real:
|
|
48
|
+
// Los IDs reales tienen entre 9 y 14 dígitos, con posible prefijo -100 para grupos/canales
|
|
49
|
+
// Un valor de test "real" como -100999888777 tiene 12 dígitos — apariencia válida.
|
|
50
|
+
// Exentar si el valor es claramente sintético (todos los mismos dígitos, ej: -100111111111)
|
|
51
|
+
const RX_CHAT_ID_REAL = /TELEGRAM_CHAT_ID\s*=\s*['"]?(-?[1-9]\d{8,13})['"]?/;
|
|
52
|
+
|
|
53
|
+
// Sufijos que indican que el valor es intencionalmente sintético — no reportar
|
|
54
|
+
// Estos patrones en el token hash indican uso de prueba sin ambigüedad
|
|
55
|
+
const SUFIJOS_SINTETICOS = [
|
|
56
|
+
/^[0-9]+$/, // solo dígitos — no es un token real (que mezcla alfa + guiones)
|
|
57
|
+
/test/i,
|
|
58
|
+
/fake/i,
|
|
59
|
+
/mock/i,
|
|
60
|
+
/dummy/i,
|
|
61
|
+
/placeholder/i,
|
|
62
|
+
/example/i,
|
|
63
|
+
/invalid/i,
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
// IDs de bot conocidos como fixtures de test del sistema SWL — no son credenciales reales
|
|
67
|
+
// Estos IDs se usan en tests internos y están documentados como fixtures sintéticos.
|
|
68
|
+
const BOT_IDS_SINTETICOS = new Set([
|
|
69
|
+
'7123456789', // ID de fixture SWL-test (introducido en Slice 004, v5.12.0)
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
// Chat IDs que son claramente sintéticos por su patrón repetitivo
|
|
73
|
+
const RX_CHAT_ID_SINTETICO = /^-?1+$|^-?0+$|^-?1+0+$|^-?10+$|(\d)\1{4,}/;
|
|
74
|
+
|
|
75
|
+
// Archivos explícitamente exentos (ninguno por ahora)
|
|
76
|
+
const EXENTOS = new Set([]);
|
|
77
|
+
|
|
78
|
+
// ─── Utilidades ────────────────────────────────────────────────────────────
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Recorre un directorio recursivamente y devuelve todos los archivos .test.js
|
|
82
|
+
* @param {string} dir
|
|
83
|
+
* @returns {string[]}
|
|
84
|
+
*/
|
|
85
|
+
function obtenerArchivosTest(dir) {
|
|
86
|
+
const resultado = [];
|
|
87
|
+
if (!fs.existsSync(dir)) return resultado;
|
|
88
|
+
|
|
89
|
+
for (const entrada of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
90
|
+
const ruta = path.join(dir, entrada.name);
|
|
91
|
+
if (entrada.isDirectory()) {
|
|
92
|
+
resultado.push(...obtenerArchivosTest(ruta));
|
|
93
|
+
} else if (entrada.isFile() && entrada.name.endsWith(EXTENSION)) {
|
|
94
|
+
resultado.push(ruta);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return resultado;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Verifica si el hash de un token parece sintético (no credencial real).
|
|
102
|
+
* @param {string} hash - Parte después de ":" en el token
|
|
103
|
+
* @returns {boolean}
|
|
104
|
+
*/
|
|
105
|
+
function esHashSintetico(hash) {
|
|
106
|
+
return SUFIJOS_SINTETICOS.some(rx => rx.test(hash));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Analiza un archivo de test línea por línea.
|
|
111
|
+
* Devuelve la lista de alertas encontradas.
|
|
112
|
+
*
|
|
113
|
+
* @param {string} rutaArchivo
|
|
114
|
+
* @returns {{ archivo: string, linea: number, tipo: string, valor: string }[]}
|
|
115
|
+
*/
|
|
116
|
+
function analizarArchivo(rutaArchivo) {
|
|
117
|
+
const alertas = [];
|
|
118
|
+
const lineas = fs.readFileSync(rutaArchivo, 'utf8').split('\n');
|
|
119
|
+
|
|
120
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
121
|
+
const lineaActual = lineas[i];
|
|
122
|
+
|
|
123
|
+
// Ignorar líneas de comentario puro
|
|
124
|
+
const lineaTrimmed = lineaActual.trim();
|
|
125
|
+
if (lineaTrimmed.startsWith('//') || lineaTrimmed.startsWith('*')) continue;
|
|
126
|
+
|
|
127
|
+
// Verificar exención explícita
|
|
128
|
+
const lineaAnterior = i > 0 ? lineas[i - 1] : '';
|
|
129
|
+
const tieneExencion =
|
|
130
|
+
lineaActual.includes(EXENCION_COMENTARIO) ||
|
|
131
|
+
lineaAnterior.includes(EXENCION_COMENTARIO);
|
|
132
|
+
if (tieneExencion) continue;
|
|
133
|
+
|
|
134
|
+
// Verificar token de bot
|
|
135
|
+
const matchToken = lineaActual.match(RX_BOT_TOKEN);
|
|
136
|
+
if (matchToken) {
|
|
137
|
+
const valorCompleto = matchToken[1]; // <id>:<hash>
|
|
138
|
+
const partesToken = valorCompleto.split(':');
|
|
139
|
+
const botId = partesToken[0] || '';
|
|
140
|
+
const hash = partesToken[1] || '';
|
|
141
|
+
if (!esHashSintetico(hash) && !BOT_IDS_SINTETICOS.has(botId)) {
|
|
142
|
+
alertas.push({
|
|
143
|
+
archivo: rutaArchivo,
|
|
144
|
+
linea: i + 1,
|
|
145
|
+
tipo: 'TELEGRAM_BOT_TOKEN',
|
|
146
|
+
valor: valorCompleto.substring(0, 20) + '...',
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Verificar chat ID
|
|
152
|
+
const matchChatId = lineaActual.match(RX_CHAT_ID_REAL);
|
|
153
|
+
if (matchChatId) {
|
|
154
|
+
const valorChatId = matchChatId[1];
|
|
155
|
+
if (!RX_CHAT_ID_SINTETICO.test(valorChatId)) {
|
|
156
|
+
alertas.push({
|
|
157
|
+
archivo: rutaArchivo,
|
|
158
|
+
linea: i + 1,
|
|
159
|
+
tipo: 'TELEGRAM_CHAT_ID',
|
|
160
|
+
valor: valorChatId,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return alertas;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// ─── Main ───────────────────────────────────────────────────────────────────
|
|
170
|
+
|
|
171
|
+
function main() {
|
|
172
|
+
const args = process.argv.slice(2);
|
|
173
|
+
const directorio = args[0] ? path.resolve(args[0]) : DIRECTORIO_DEFAULT;
|
|
174
|
+
|
|
175
|
+
console.log(`Validando tokens en archivos de test: ${directorio}`);
|
|
176
|
+
console.log(`Buscando literales TELEGRAM_BOT_TOKEN/CHAT_ID con apariencia real...\n`);
|
|
177
|
+
|
|
178
|
+
const archivos = obtenerArchivosTest(directorio);
|
|
179
|
+
const todasAlertas = [];
|
|
180
|
+
|
|
181
|
+
for (const archivo of archivos) {
|
|
182
|
+
if (EXENTOS.has(path.basename(archivo))) continue;
|
|
183
|
+
const alertas = analizarArchivo(archivo);
|
|
184
|
+
todasAlertas.push(...alertas);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (todasAlertas.length === 0) {
|
|
188
|
+
console.log(`OK: ${archivos.length} archivo(s) analizados — ningún token de apariencia real encontrado.`);
|
|
189
|
+
process.exit(0);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
console.error(`ERROR: Se encontraron ${todasAlertas.length} literal(es) de credencial con apariencia real:\n`);
|
|
193
|
+
for (const a of todasAlertas) {
|
|
194
|
+
const rutaRelativa = path.relative(process.cwd(), a.archivo);
|
|
195
|
+
console.error(` ${rutaRelativa}:${a.linea}`);
|
|
196
|
+
console.error(` → ${a.tipo} = ${a.valor}`);
|
|
197
|
+
console.error('');
|
|
198
|
+
}
|
|
199
|
+
console.error(
|
|
200
|
+
'Si el valor es intencionalmente sintético, agregar comentario en la misma línea:\n' +
|
|
201
|
+
` // ${EXENCION_COMENTARIO}\n` +
|
|
202
|
+
'Ver scripts/lib/notificaciones-telegram.js para referencia de fixtures de test seguros.\n' +
|
|
203
|
+
'Si es una credencial real filtrada: rotar el token en BotFather INMEDIATAMENTE.'
|
|
204
|
+
);
|
|
205
|
+
process.exit(1);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
main();
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Validación básica de la estructura del paquete SWL.
|
|
5
|
+
* Ejecuta con: npm test
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
const RAIZ = path.resolve(__dirname, '..');
|
|
12
|
+
let errores = 0;
|
|
13
|
+
|
|
14
|
+
function verificar(condicion, mensaje) {
|
|
15
|
+
if (condicion) {
|
|
16
|
+
console.log(` [OK] ${mensaje}`);
|
|
17
|
+
} else {
|
|
18
|
+
console.log(` [FALLA] ${mensaje}`);
|
|
19
|
+
errores++;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.log('Validando estructura SWL...\n');
|
|
24
|
+
|
|
25
|
+
// 1. package.json
|
|
26
|
+
const pkg = require('../package.json');
|
|
27
|
+
const { NOMBRES_VALIDOS } = require('./lib/paquetes-conocidos');
|
|
28
|
+
verificar(
|
|
29
|
+
NOMBRES_VALIDOS.includes(pkg.name),
|
|
30
|
+
`package.json: nombre correcto (esperado uno de ${JSON.stringify(NOMBRES_VALIDOS)}; actual: ${pkg.name})`
|
|
31
|
+
);
|
|
32
|
+
verificar(pkg.bin && pkg.bin['swl-ses'], 'package.json: bin swl-ses definido');
|
|
33
|
+
verificar(pkg.engines && pkg.engines.node, 'package.json: engine de node definido');
|
|
34
|
+
|
|
35
|
+
// 2. CLI
|
|
36
|
+
verificar(fs.existsSync(path.join(RAIZ, 'bin', 'swl-ses.js')), 'bin/swl-ses.js existe');
|
|
37
|
+
|
|
38
|
+
// 3. Scripts
|
|
39
|
+
const scriptsRequeridos = ['inicializar.js', 'instalador.js', 'doctor.js', 'actualizar.js', 'desinstalar.js'];
|
|
40
|
+
for (const s of scriptsRequeridos) {
|
|
41
|
+
verificar(fs.existsSync(path.join(RAIZ, 'scripts', s)), `scripts/${s} existe`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 4. Manifiestos
|
|
45
|
+
const manifiestosRequeridos = ['perfiles.json', 'modulos.json', 'hooks-config.json'];
|
|
46
|
+
for (const m of manifiestosRequeridos) {
|
|
47
|
+
verificar(fs.existsSync(path.join(RAIZ, 'manifiestos', m)), `manifiestos/${m} existe`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// 4b. Validar hooks-config.json tiene entradas para cada hook
|
|
51
|
+
const hooksConfigPath = path.join(RAIZ, 'manifiestos', 'hooks-config.json');
|
|
52
|
+
if (fs.existsSync(hooksConfigPath)) {
|
|
53
|
+
const hooksConfig = JSON.parse(fs.readFileSync(hooksConfigPath, 'utf-8'));
|
|
54
|
+
const hooksEnConfig = Object.keys(hooksConfig.hooks || {});
|
|
55
|
+
verificar(hooksEnConfig.length >= 4, `hooks-config.json: ${hooksEnConfig.length} hooks definidos (mínimo 4)`);
|
|
56
|
+
for (const hookName of hooksEnConfig) {
|
|
57
|
+
const hc = hooksConfig.hooks[hookName];
|
|
58
|
+
const eventosValidos = ['PreToolUse', 'PostToolUse', 'Stop', 'Notification', 'SubagentStop', 'UserPromptSubmit', 'PreCompact', 'SessionStart'];
|
|
59
|
+
verificar(
|
|
60
|
+
eventosValidos.includes(hc.event),
|
|
61
|
+
`hooks-config.json: ${hookName} tiene event válido (${hc.event})`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// 5. Agentes (mínimo 12)
|
|
67
|
+
const agentes = fs.readdirSync(path.join(RAIZ, 'agentes')).filter(f => f.endsWith('.md'));
|
|
68
|
+
verificar(agentes.length >= 12, `Agentes: ${agentes.length} (mínimo 12)`);
|
|
69
|
+
|
|
70
|
+
// Verificar frontmatter en agentes
|
|
71
|
+
for (const agente of agentes) {
|
|
72
|
+
const contenido = fs.readFileSync(path.join(RAIZ, 'agentes', agente), 'utf-8');
|
|
73
|
+
verificar(contenido.startsWith('---'), `${agente}: tiene frontmatter YAML`);
|
|
74
|
+
verificar(contenido.includes('name:'), `${agente}: tiene campo name`);
|
|
75
|
+
verificar(contenido.includes('description:'), `${agente}: tiene campo description`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 6. Habilidades (mínimo 25)
|
|
79
|
+
const habilidades = fs.readdirSync(path.join(RAIZ, 'habilidades'))
|
|
80
|
+
.filter(h => {
|
|
81
|
+
const skillPath = path.join(RAIZ, 'habilidades', h, 'SKILL.md');
|
|
82
|
+
return fs.existsSync(skillPath);
|
|
83
|
+
});
|
|
84
|
+
verificar(habilidades.length >= 25, `Habilidades: ${habilidades.length} (mínimo 25)`);
|
|
85
|
+
|
|
86
|
+
// 7. Comandos
|
|
87
|
+
const comandos = fs.readdirSync(path.join(RAIZ, 'comandos', 'swl')).filter(f => f.endsWith('.md'));
|
|
88
|
+
verificar(comandos.length >= 9, `Comandos: ${comandos.length} (mínimo 9)`);
|
|
89
|
+
|
|
90
|
+
// 8. Reglas
|
|
91
|
+
const reglas = fs.readdirSync(path.join(RAIZ, 'reglas')).filter(f => f.endsWith('.md'));
|
|
92
|
+
verificar(reglas.length >= 7, `Reglas: ${reglas.length} (mínimo 7)`);
|
|
93
|
+
|
|
94
|
+
// 9. Hooks
|
|
95
|
+
const hooks = fs.readdirSync(path.join(RAIZ, 'hooks')).filter(f => f.endsWith('.js'));
|
|
96
|
+
verificar(hooks.length >= 4, `Hooks: ${hooks.length} (mínimo 4)`);
|
|
97
|
+
|
|
98
|
+
// 10. Plantillas
|
|
99
|
+
verificar(fs.existsSync(path.join(RAIZ, 'plantillas', 'PROYECTO.md')), 'plantillas/PROYECTO.md existe');
|
|
100
|
+
verificar(fs.existsSync(path.join(RAIZ, 'plantillas', 'ESTADO.md')), 'plantillas/ESTADO.md existe');
|
|
101
|
+
|
|
102
|
+
// 11. plugin.json
|
|
103
|
+
const pluginPath = path.join(RAIZ, 'plugin.json');
|
|
104
|
+
verificar(fs.existsSync(pluginPath), 'plugin.json existe');
|
|
105
|
+
if (fs.existsSync(pluginPath)) {
|
|
106
|
+
const plugin = JSON.parse(fs.readFileSync(pluginPath, 'utf-8'));
|
|
107
|
+
verificar(plugin.skills && plugin.skills.length >= 25, `plugin.json: ${(plugin.skills || []).length} skills registrados`);
|
|
108
|
+
verificar(plugin.agents && plugin.agents.length >= 12, `plugin.json: ${(plugin.agents || []).length} agentes registrados`);
|
|
109
|
+
verificar(plugin.hooks && plugin.hooks.PreToolUse, 'plugin.json: tiene hooks PreToolUse');
|
|
110
|
+
verificar(plugin.hooks && plugin.hooks.PostToolUse, 'plugin.json: tiene hooks PostToolUse');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// 12. CLAUDE.md
|
|
114
|
+
verificar(fs.existsSync(path.join(RAIZ, 'CLAUDE.md')), 'CLAUDE.md existe');
|
|
115
|
+
|
|
116
|
+
// 13. Memoria consolidada
|
|
117
|
+
const memRule = path.join(RAIZ, 'reglas', 'memoria-consolidada.md');
|
|
118
|
+
verificar(fs.existsSync(memRule), 'reglas/memoria-consolidada.md existe');
|
|
119
|
+
|
|
120
|
+
// 14. Validación de memoria: ejecuta validar-memoria.js
|
|
121
|
+
try {
|
|
122
|
+
const { execSync } = require('child_process');
|
|
123
|
+
const memoria = path.join(RAIZ, 'scripts', 'validar-memoria.js');
|
|
124
|
+
if (fs.existsSync(memoria)) {
|
|
125
|
+
try {
|
|
126
|
+
execSync(`node "${memoria}" --json`, { stdio: 'pipe' });
|
|
127
|
+
verificar(true, 'Memoria consolidada: sin violaciones');
|
|
128
|
+
} catch (e) {
|
|
129
|
+
const exitCode = e.status;
|
|
130
|
+
if (exitCode === 2) {
|
|
131
|
+
verificar(false, 'Memoria consolidada: violaciones CRÍTICAS (posibles secretos)');
|
|
132
|
+
} else if (exitCode === 1) {
|
|
133
|
+
verificar(true, "Memoria consolidada: warnings no críticos — ver 'node scripts/validar-memoria.js'");
|
|
134
|
+
} else {
|
|
135
|
+
verificar(true, 'Memoria consolidada: sin violaciones');
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
} catch { /* ignore */ }
|
|
140
|
+
|
|
141
|
+
console.log('\n' + '='.repeat(40));
|
|
142
|
+
if (errores === 0) {
|
|
143
|
+
console.log('Todas las validaciones pasaron.');
|
|
144
|
+
} else {
|
|
145
|
+
console.log(`${errores} validaciones fallaron.`);
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
"""
|
|
2
|
+
validate-markdown.py — Validador de sintaxis Markdown para skills del sistema SWL
|
|
3
|
+
|
|
4
|
+
Uso:
|
|
5
|
+
python scripts/validate-markdown.py # valida todos los .md
|
|
6
|
+
python scripts/validate-markdown.py --path habilidades/django-experto/SKILL.md
|
|
7
|
+
python scripts/validate-markdown.py --check # modo CI: exit 1 si hay errores
|
|
8
|
+
|
|
9
|
+
Valida SKILL.md y recursos/*.md de todas las habilidades en ../habilidades.
|
|
10
|
+
Exit code 0 = éxito o solo advertencias; 1 = hay errores.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import argparse
|
|
14
|
+
import re
|
|
15
|
+
import sys
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
# ---------------------------------------------------------------------------
|
|
20
|
+
# Constantes
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
REGEX_APERTURA_BLOQUE = re.compile(r"^```(\w*)\s*$")
|
|
23
|
+
REGEX_CIERRE_BLOQUE = re.compile(r"^```\s*$")
|
|
24
|
+
REGEX_FILA_TABLA = re.compile(r"^\s*\|.*\|\s*$")
|
|
25
|
+
REGEX_SEPARADOR_TABLA = re.compile(r"^\s*\|[\s|:\-]+\|\s*$")
|
|
26
|
+
REGEX_COMENTARIO_HTML = re.compile(r"<!--.*?-->", re.DOTALL)
|
|
27
|
+
REGEX_ENCABEZADO = re.compile(r"^(#{1,6})\s+\S")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
# ---------------------------------------------------------------------------
|
|
31
|
+
# Tipos de resultado
|
|
32
|
+
# ---------------------------------------------------------------------------
|
|
33
|
+
def _problema(tipo: str, codigo: str, linea: int | None, mensaje: str) -> dict:
|
|
34
|
+
return {"type": tipo, "code": codigo, "line": linea, "message": mensaje}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _error(codigo: str, linea: int | None, mensaje: str) -> dict:
|
|
38
|
+
return _problema("error", codigo, linea, mensaje)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _advertencia(codigo: str, linea: int | None, mensaje: str) -> dict:
|
|
42
|
+
return _problema("warning", codigo, linea, mensaje)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# ---------------------------------------------------------------------------
|
|
46
|
+
# Validación de bloques de código
|
|
47
|
+
# ---------------------------------------------------------------------------
|
|
48
|
+
def _validar_bloques_codigo(lineas: list[str]) -> list[dict]:
|
|
49
|
+
issues: list[dict] = []
|
|
50
|
+
dentro_bloque = False
|
|
51
|
+
linea_apertura = 0
|
|
52
|
+
|
|
53
|
+
for i, linea in enumerate(lineas, start=1):
|
|
54
|
+
if not dentro_bloque:
|
|
55
|
+
if REGEX_APERTURA_BLOQUE.match(linea):
|
|
56
|
+
dentro_bloque = True
|
|
57
|
+
linea_apertura = i
|
|
58
|
+
else:
|
|
59
|
+
if REGEX_CIERRE_BLOQUE.match(linea):
|
|
60
|
+
dentro_bloque = False
|
|
61
|
+
|
|
62
|
+
if dentro_bloque:
|
|
63
|
+
issues.append(_error(
|
|
64
|
+
"UNCLOSED_CODE_BLOCK",
|
|
65
|
+
linea_apertura,
|
|
66
|
+
f"Bloque de codigo abierto en linea {linea_apertura} nunca se cierra"
|
|
67
|
+
))
|
|
68
|
+
|
|
69
|
+
return issues
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
# Validación de tablas
|
|
74
|
+
# ---------------------------------------------------------------------------
|
|
75
|
+
def _contar_columnas(fila: str) -> int:
|
|
76
|
+
"""Cuenta el número de columnas en una fila de tabla Markdown."""
|
|
77
|
+
fila = fila.strip()
|
|
78
|
+
if fila.startswith("|"):
|
|
79
|
+
fila = fila[1:]
|
|
80
|
+
if fila.endswith("|"):
|
|
81
|
+
fila = fila[:-1]
|
|
82
|
+
return len(fila.split("|"))
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _validar_tablas(lineas: list[str]) -> list[dict]:
|
|
86
|
+
issues: list[dict] = []
|
|
87
|
+
dentro_bloque = False
|
|
88
|
+
i = 0
|
|
89
|
+
|
|
90
|
+
while i < len(lineas):
|
|
91
|
+
linea = lineas[i]
|
|
92
|
+
num_linea = i + 1
|
|
93
|
+
|
|
94
|
+
# No validar tablas dentro de bloques de código
|
|
95
|
+
if not dentro_bloque and REGEX_APERTURA_BLOQUE.match(linea):
|
|
96
|
+
dentro_bloque = True
|
|
97
|
+
elif dentro_bloque and REGEX_CIERRE_BLOQUE.match(linea):
|
|
98
|
+
dentro_bloque = False
|
|
99
|
+
elif not dentro_bloque and REGEX_FILA_TABLA.match(linea):
|
|
100
|
+
# Inicio potencial de tabla: fila de encabezado
|
|
101
|
+
fila_encabezado = linea
|
|
102
|
+
num_cols_encabezado = _contar_columnas(fila_encabezado)
|
|
103
|
+
num_linea_encabezado = num_linea
|
|
104
|
+
|
|
105
|
+
# Verificar si la siguiente línea es el separador
|
|
106
|
+
if i + 1 < len(lineas):
|
|
107
|
+
linea_siguiente = lineas[i + 1]
|
|
108
|
+
if not REGEX_SEPARADOR_TABLA.match(linea_siguiente):
|
|
109
|
+
# Puede ser tabla sin separador solo si la línea siguiente también es fila de tabla
|
|
110
|
+
if REGEX_FILA_TABLA.match(linea_siguiente):
|
|
111
|
+
issues.append(_error(
|
|
112
|
+
"TABLE_MISSING_SEPARATOR",
|
|
113
|
+
num_linea,
|
|
114
|
+
f"Tabla en linea {num_linea} no tiene separador (segunda fila debe tener |---|)"
|
|
115
|
+
))
|
|
116
|
+
else:
|
|
117
|
+
# Tiene separador: avanzar y validar columnas del resto
|
|
118
|
+
i += 2 # saltar encabezado y separador
|
|
119
|
+
while i < len(lineas) and REGEX_FILA_TABLA.match(lineas[i]):
|
|
120
|
+
num_cols_fila = _contar_columnas(lineas[i])
|
|
121
|
+
if num_cols_fila != num_cols_encabezado:
|
|
122
|
+
issues.append(_error(
|
|
123
|
+
"TABLE_INCONSISTENT_COLUMNS",
|
|
124
|
+
i + 1,
|
|
125
|
+
f"Fila {i + 1} de tabla tiene {num_cols_fila} columna(s) "
|
|
126
|
+
f"pero el encabezado (linea {num_linea_encabezado}) define {num_cols_encabezado}"
|
|
127
|
+
))
|
|
128
|
+
# Advertencia: comentarios HTML dentro de celdas de tabla
|
|
129
|
+
if REGEX_COMENTARIO_HTML.search(lineas[i]):
|
|
130
|
+
issues.append(_advertencia(
|
|
131
|
+
"HTML_COMMENT_IN_TABLE",
|
|
132
|
+
i + 1,
|
|
133
|
+
f"Comentario HTML en fila {i + 1} de tabla; puede romper el parsing en algunas herramientas"
|
|
134
|
+
))
|
|
135
|
+
i += 1
|
|
136
|
+
continue # ya avanzamos manualmente
|
|
137
|
+
|
|
138
|
+
i += 1
|
|
139
|
+
|
|
140
|
+
return issues
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# ---------------------------------------------------------------------------
|
|
144
|
+
# Validación de encabezados (salto de nivel)
|
|
145
|
+
# ---------------------------------------------------------------------------
|
|
146
|
+
def _validar_encabezados(lineas: list[str]) -> list[dict]:
|
|
147
|
+
issues: list[dict] = []
|
|
148
|
+
dentro_bloque = False
|
|
149
|
+
nivel_anterior = 0
|
|
150
|
+
|
|
151
|
+
for i, linea in enumerate(lineas, start=1):
|
|
152
|
+
if not dentro_bloque and REGEX_APERTURA_BLOQUE.match(linea):
|
|
153
|
+
dentro_bloque = True
|
|
154
|
+
continue
|
|
155
|
+
if dentro_bloque and REGEX_CIERRE_BLOQUE.match(linea):
|
|
156
|
+
dentro_bloque = False
|
|
157
|
+
continue
|
|
158
|
+
if dentro_bloque:
|
|
159
|
+
continue
|
|
160
|
+
|
|
161
|
+
m = REGEX_ENCABEZADO.match(linea)
|
|
162
|
+
if m:
|
|
163
|
+
nivel_actual = len(m.group(1))
|
|
164
|
+
if nivel_anterior > 0 and nivel_actual > nivel_anterior + 1:
|
|
165
|
+
issues.append(_advertencia(
|
|
166
|
+
"HEADING_LEVEL_SKIP",
|
|
167
|
+
i,
|
|
168
|
+
f"Encabezado salta de H{nivel_anterior} a H{nivel_actual} en linea {i} "
|
|
169
|
+
f"(se omite H{nivel_anterior + 1})"
|
|
170
|
+
))
|
|
171
|
+
nivel_anterior = nivel_actual
|
|
172
|
+
|
|
173
|
+
return issues
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# ---------------------------------------------------------------------------
|
|
177
|
+
# Validación de un archivo individual
|
|
178
|
+
# ---------------------------------------------------------------------------
|
|
179
|
+
def validar_archivo(ruta: Path) -> dict:
|
|
180
|
+
"""
|
|
181
|
+
Valida un archivo Markdown.
|
|
182
|
+
Devuelve dict con claves: archivo, status, issues.
|
|
183
|
+
"""
|
|
184
|
+
issues: list[dict] = []
|
|
185
|
+
|
|
186
|
+
if not ruta.exists():
|
|
187
|
+
return {
|
|
188
|
+
"archivo": str(ruta),
|
|
189
|
+
"status": "error",
|
|
190
|
+
"issues": [_error("FILE_NOT_FOUND", None, f"Archivo no encontrado: {ruta}")]
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
contenido = ruta.read_text(encoding="utf-8", errors="replace")
|
|
194
|
+
lineas = contenido.splitlines()
|
|
195
|
+
|
|
196
|
+
issues.extend(_validar_bloques_codigo(lineas))
|
|
197
|
+
issues.extend(_validar_tablas(lineas))
|
|
198
|
+
issues.extend(_validar_encabezados(lineas))
|
|
199
|
+
|
|
200
|
+
tiene_error = any(i["type"] == "error" for i in issues)
|
|
201
|
+
tiene_advertencia = any(i["type"] == "warning" for i in issues)
|
|
202
|
+
|
|
203
|
+
if tiene_error:
|
|
204
|
+
estado = "error"
|
|
205
|
+
elif tiene_advertencia:
|
|
206
|
+
estado = "warning"
|
|
207
|
+
else:
|
|
208
|
+
estado = "ok"
|
|
209
|
+
|
|
210
|
+
return {"archivo": str(ruta), "status": estado, "issues": issues}
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
# ---------------------------------------------------------------------------
|
|
214
|
+
# Recolección de archivos a validar
|
|
215
|
+
# ---------------------------------------------------------------------------
|
|
216
|
+
def recolectar_archivos_markdown(dir_habilidades: Path) -> list[Path]:
|
|
217
|
+
"""Devuelve todos los SKILL.md y recursos/*.md bajo dir_habilidades."""
|
|
218
|
+
archivos: list[Path] = []
|
|
219
|
+
|
|
220
|
+
for skill_dir in sorted(dir_habilidades.iterdir()):
|
|
221
|
+
if not skill_dir.is_dir():
|
|
222
|
+
continue
|
|
223
|
+
|
|
224
|
+
skill_md = skill_dir / "SKILL.md"
|
|
225
|
+
if skill_md.exists():
|
|
226
|
+
archivos.append(skill_md)
|
|
227
|
+
|
|
228
|
+
recursos_dir = skill_dir / "recursos"
|
|
229
|
+
if recursos_dir.is_dir():
|
|
230
|
+
for archivo in sorted(recursos_dir.iterdir()):
|
|
231
|
+
if archivo.suffix.lower() == ".md":
|
|
232
|
+
archivos.append(archivo)
|
|
233
|
+
|
|
234
|
+
return archivos
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
# ---------------------------------------------------------------------------
|
|
238
|
+
# Presentación de resultados
|
|
239
|
+
# ---------------------------------------------------------------------------
|
|
240
|
+
def _iconos() -> dict[str, str]:
|
|
241
|
+
"""Devuelve iconos Unicode si el terminal los soporta, ASCII en caso contrario."""
|
|
242
|
+
enc = getattr(sys.stdout, "encoding", "") or ""
|
|
243
|
+
if enc.lower().replace("-", "") in ("utf8", "utf16", "utf32"):
|
|
244
|
+
return {"ok": "\u2713", "warning": "\u26a0", "error": "\u2717"}
|
|
245
|
+
return {"ok": "[OK]", "warning": "[WARN]", "error": "[ERR]"}
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def imprimir_resultado_normal(resultado: dict, raiz: Path, iconos: dict[str, str]) -> None:
|
|
249
|
+
"""Imprime el resultado de un archivo, mostrando la ruta relativa a raiz."""
|
|
250
|
+
ruta_abs = Path(resultado["archivo"])
|
|
251
|
+
try:
|
|
252
|
+
ruta_mostrar = ruta_abs.relative_to(raiz)
|
|
253
|
+
except ValueError:
|
|
254
|
+
ruta_mostrar = ruta_abs
|
|
255
|
+
|
|
256
|
+
estado = resultado["status"]
|
|
257
|
+
icono = iconos.get(estado, "?")
|
|
258
|
+
issues = resultado["issues"]
|
|
259
|
+
|
|
260
|
+
if estado == "ok":
|
|
261
|
+
print(f"{icono} {ruta_mostrar} - OK")
|
|
262
|
+
else:
|
|
263
|
+
for issue in issues:
|
|
264
|
+
prefijo = "ERROR" if issue["type"] == "error" else "ADVERTENCIA"
|
|
265
|
+
ref_linea = f" (linea {issue['line']})" if issue.get("line") else ""
|
|
266
|
+
print(f"{icono} {ruta_mostrar}{ref_linea} - {prefijo}: {issue['message']}")
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
# ---------------------------------------------------------------------------
|
|
270
|
+
# Punto de entrada
|
|
271
|
+
# ---------------------------------------------------------------------------
|
|
272
|
+
def main() -> int:
|
|
273
|
+
parser = argparse.ArgumentParser(
|
|
274
|
+
description="Validador de sintaxis Markdown para skills del sistema SWL"
|
|
275
|
+
)
|
|
276
|
+
parser.add_argument(
|
|
277
|
+
"--path",
|
|
278
|
+
metavar="RUTA",
|
|
279
|
+
help="Validar un archivo Markdown específico"
|
|
280
|
+
)
|
|
281
|
+
parser.add_argument(
|
|
282
|
+
"--check",
|
|
283
|
+
action="store_true",
|
|
284
|
+
help="Modo CI: exit 1 si hay errores"
|
|
285
|
+
)
|
|
286
|
+
args = parser.parse_args()
|
|
287
|
+
|
|
288
|
+
raiz = Path(__file__).parent.parent
|
|
289
|
+
dir_habilidades = raiz / "habilidades"
|
|
290
|
+
|
|
291
|
+
if args.path:
|
|
292
|
+
# Ruta puede ser relativa a la raíz del proyecto o absoluta
|
|
293
|
+
ruta_archivo = Path(args.path)
|
|
294
|
+
if not ruta_archivo.is_absolute():
|
|
295
|
+
ruta_archivo = raiz / ruta_archivo
|
|
296
|
+
archivos = [ruta_archivo]
|
|
297
|
+
else:
|
|
298
|
+
if not dir_habilidades.is_dir():
|
|
299
|
+
print(
|
|
300
|
+
f"ERROR: Directorio de habilidades no encontrado: {dir_habilidades}",
|
|
301
|
+
file=sys.stderr
|
|
302
|
+
)
|
|
303
|
+
return 1
|
|
304
|
+
archivos = recolectar_archivos_markdown(dir_habilidades)
|
|
305
|
+
|
|
306
|
+
if not archivos:
|
|
307
|
+
print("No se encontraron archivos Markdown para validar.")
|
|
308
|
+
return 0
|
|
309
|
+
|
|
310
|
+
resultados: list[dict] = []
|
|
311
|
+
for ruta in archivos:
|
|
312
|
+
resultado = validar_archivo(ruta)
|
|
313
|
+
resultados.append(resultado)
|
|
314
|
+
|
|
315
|
+
# Contadores
|
|
316
|
+
n_ok = sum(1 for r in resultados if r["status"] == "ok")
|
|
317
|
+
n_warnings = sum(1 for r in resultados if r["status"] == "warning")
|
|
318
|
+
n_errors = sum(1 for r in resultados if r["status"] == "error")
|
|
319
|
+
|
|
320
|
+
iconos = _iconos()
|
|
321
|
+
for resultado in resultados:
|
|
322
|
+
imprimir_resultado_normal(resultado, raiz, iconos)
|
|
323
|
+
|
|
324
|
+
total = len(resultados)
|
|
325
|
+
partes = [f"{total} archivo(s) validado(s)", f"{n_ok} OK"]
|
|
326
|
+
if n_warnings:
|
|
327
|
+
partes.append(f"{n_warnings} advertencia(s)")
|
|
328
|
+
if n_errors:
|
|
329
|
+
partes.append(f"{n_errors} error(es)")
|
|
330
|
+
print(f"\nResumen: {', '.join(partes)}")
|
|
331
|
+
|
|
332
|
+
if args.check and n_errors > 0:
|
|
333
|
+
return 1
|
|
334
|
+
|
|
335
|
+
return 0
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
if __name__ == "__main__":
|
|
339
|
+
sys.exit(main())
|