@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,1031 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* swl-ses install
|
|
5
|
+
* Instala componentes SWL en el runtime destino.
|
|
6
|
+
*
|
|
7
|
+
* Flujo:
|
|
8
|
+
* 1. Detectar/validar runtime target
|
|
9
|
+
* 2. Resolver perfil → módulos → archivos
|
|
10
|
+
* 3. Detectar _userland/ y hacer merge
|
|
11
|
+
* 4. Mostrar plan de instalación
|
|
12
|
+
* 5. Aplicar (copiar archivos, adaptar formato si necesario)
|
|
13
|
+
* 6. Guardar estado de instalación
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const fs = require('fs');
|
|
17
|
+
const path = require('path');
|
|
18
|
+
|
|
19
|
+
const { obtenerRuntime, calcularRutas, resumenDeteccion, detectarInstalacionesDuales } = require('./lib/detectar-runtime');
|
|
20
|
+
const { preguntarSiNo, ES_TTY } = require('./lib/ui');
|
|
21
|
+
const { resolverPerfil, generarPlan } = require('./lib/manifiestos');
|
|
22
|
+
const { crearEstado, registrarArchivo, registrarComponente, guardarEstado, cargarEstado } = require('./lib/estado');
|
|
23
|
+
const { validarRuta, esArchivoSensible, filtrarSecretos } = require('./lib/seguridad');
|
|
24
|
+
const { registrarHooks, registrarOptimizaciones, rutaSettings, cargarHooksConfig } = require('./lib/hooks-settings');
|
|
25
|
+
const { obtenerTransformador } = require('./lib/transformadores');
|
|
26
|
+
const {
|
|
27
|
+
esProtegido,
|
|
28
|
+
crearBackup,
|
|
29
|
+
registrarBackup,
|
|
30
|
+
limpiarBackups,
|
|
31
|
+
mergeInstintos,
|
|
32
|
+
mergeSkills,
|
|
33
|
+
} = require('./lib/preservar-usuario');
|
|
34
|
+
const {
|
|
35
|
+
decideUpdateStrategy,
|
|
36
|
+
mergeEvolved,
|
|
37
|
+
scanEvolved,
|
|
38
|
+
} = require('../hooks/lib/evolution-tracker');
|
|
39
|
+
const { detectarStack, filtrarReglasPorStack } = require('./lib/detectar-stack');
|
|
40
|
+
const { actualizarGitignore, entradasParaRuntime, limpiarTracked, leerManifest, escribirManifest } = require('./lib/gitignore-manifest');
|
|
41
|
+
|
|
42
|
+
const RAIZ_PKG = path.resolve(__dirname, '..');
|
|
43
|
+
const VERSION = require('../package.json').version;
|
|
44
|
+
|
|
45
|
+
async function install(opciones) {
|
|
46
|
+
// Leer manifest .swl-ses si existe — sus valores son defaults que el CLI puede sobreescribir
|
|
47
|
+
const manifest = leerManifest(process.cwd());
|
|
48
|
+
if (manifest && !opciones.target && !opciones.profile) {
|
|
49
|
+
console.log(`[manifest] Usando configuración de .swl-ses: target=${manifest.target}, profile=${manifest.profile}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const target = opciones.target || (manifest && manifest.target) || 'claude';
|
|
53
|
+
const perfil = opciones.profile || (manifest && manifest.profile) || 'core';
|
|
54
|
+
const esGlobal = opciones.global || false;
|
|
55
|
+
const dryRun = opciones.dry_run || false;
|
|
56
|
+
const force = opciones.force || false;
|
|
57
|
+
const allLangs = opciones.all_langs || false;
|
|
58
|
+
const syncMode = opciones.sync_mode || (manifest && manifest.syncMode) || 'copy'; // copy | symlink | flat
|
|
59
|
+
const flatNaming = opciones.flat_naming || syncMode === 'flat'; // Convierte path/to/skill → path__to__skill
|
|
60
|
+
|
|
61
|
+
console.log(`swl-ses install v${VERSION}`);
|
|
62
|
+
console.log(`${'='.repeat(40)}`);
|
|
63
|
+
|
|
64
|
+
// 1. Validar runtime
|
|
65
|
+
let runtime;
|
|
66
|
+
try {
|
|
67
|
+
runtime = obtenerRuntime(target);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.error(err.message);
|
|
70
|
+
console.log('\n' + resumenDeteccion());
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (runtime.soporte === 'parcial') {
|
|
75
|
+
console.log(`Nota: Runtime "${target}" (${runtime.nombre}) tiene soporte parcial — solo agentes y reglas.\n`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// 1b. Detectar conflicto dual-scope: instalar en un scope cuando el opuesto
|
|
79
|
+
// ya tiene SWL instalado causa duplicación visible de comandos en la UI.
|
|
80
|
+
// Con --force se omite el prompt (asume que el caller sabe lo que hace).
|
|
81
|
+
// En modo no-TTY solo se muestra advertencia informativa y se continúa.
|
|
82
|
+
if (!force && !dryRun) {
|
|
83
|
+
const dual = detectarInstalacionesDuales(target);
|
|
84
|
+
const tieneOpuesto = esGlobal ? dual.local : dual.global;
|
|
85
|
+
|
|
86
|
+
if (tieneOpuesto) {
|
|
87
|
+
const scopeActual = esGlobal ? 'global' : 'proyecto';
|
|
88
|
+
const scopeOpuesto = esGlobal ? 'proyecto' : 'global';
|
|
89
|
+
const dirOpuesto = esGlobal ? dual.localDir : dual.globalDir;
|
|
90
|
+
|
|
91
|
+
console.log('');
|
|
92
|
+
console.log(` Ya existe una instalación SWL de ${runtime.nombre} en scope ${scopeOpuesto}:`);
|
|
93
|
+
console.log(` ${dirOpuesto}`);
|
|
94
|
+
console.log('');
|
|
95
|
+
console.log(` Instalar también en scope ${scopeActual} duplicará comandos/agentes en la UI`);
|
|
96
|
+
console.log(` porque ${runtime.nombre} lee componentes de ambos scopes y los muestra como`);
|
|
97
|
+
console.log(` entradas separadas.`);
|
|
98
|
+
console.log('');
|
|
99
|
+
console.log(` Recomendación: usa un solo scope.`);
|
|
100
|
+
console.log('');
|
|
101
|
+
|
|
102
|
+
if (ES_TTY) {
|
|
103
|
+
const proceder = await preguntarSiNo(
|
|
104
|
+
`¿Continuar e instalar en ambos scopes de todos modos?`,
|
|
105
|
+
false
|
|
106
|
+
);
|
|
107
|
+
console.log('');
|
|
108
|
+
if (!proceder) {
|
|
109
|
+
console.log(' Instalación cancelada.');
|
|
110
|
+
console.log(` Si solo quieres usar el scope ${scopeOpuesto}, ya está instalado.`);
|
|
111
|
+
console.log(` Si quieres cambiar de scope: ejecuta 'swl-ses uninstall${esGlobal ? '' : ' --global'}' primero.`);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
} else {
|
|
115
|
+
// No-TTY (CI, pipes): no podemos preguntar, pero avisamos.
|
|
116
|
+
console.log(' [no-TTY] Procediendo con la instalación — usa --force para suprimir este aviso.');
|
|
117
|
+
console.log('');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// 2. Resolver perfil
|
|
123
|
+
let resolucion;
|
|
124
|
+
try {
|
|
125
|
+
resolucion = resolverPerfil(perfil, {
|
|
126
|
+
target,
|
|
127
|
+
with: opciones.with,
|
|
128
|
+
without: opciones.without,
|
|
129
|
+
});
|
|
130
|
+
} catch (err) {
|
|
131
|
+
console.error(err.message);
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 2b. Filtrar reglas de lenguaje por stack detectado
|
|
136
|
+
// El stack se detecta siempre que: hay reglas de lenguaje en el perfil, O
|
|
137
|
+
// se ejecuta con --force (actualización) para poder limpiar las ya instaladas.
|
|
138
|
+
const tieneReglasLenguaje = resolucion.archivos.some(
|
|
139
|
+
a => a.rutaRelativa && a.rutaRelativa.startsWith('reglas/lenguajes/')
|
|
140
|
+
);
|
|
141
|
+
const necesitaStack = (tieneReglasLenguaje || force) && !allLangs;
|
|
142
|
+
|
|
143
|
+
let stackDetectado = null;
|
|
144
|
+
|
|
145
|
+
if (necesitaStack) {
|
|
146
|
+
stackDetectado = detectarStack(process.cwd());
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (tieneReglasLenguaje) {
|
|
150
|
+
if (allLangs) {
|
|
151
|
+
console.log('\n[stack] --all-langs activado: se instalan reglas de todos los lenguajes.');
|
|
152
|
+
} else {
|
|
153
|
+
if (stackDetectado.size > 0) {
|
|
154
|
+
console.log(`\n[stack] Lenguajes detectados en el proyecto: ${[...stackDetectado].join(', ')}`);
|
|
155
|
+
} else {
|
|
156
|
+
console.log('\n[stack] No se detectaron lenguajes específicos en el proyecto.');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const resultado = filtrarReglasPorStack(resolucion.archivos, stackDetectado);
|
|
160
|
+
if (resultado.excluidos > 0) {
|
|
161
|
+
resolucion.archivos = resultado.archivos;
|
|
162
|
+
console.log(
|
|
163
|
+
`[stack] ${resultado.excluidos} reglas excluidas (lenguajes no presentes: ${resultado.lenguajesExcluidos.join(', ')})`
|
|
164
|
+
);
|
|
165
|
+
console.log('[stack] Usa --all-langs para forzar instalación de todos los lenguajes.');
|
|
166
|
+
} else {
|
|
167
|
+
console.log('[stack] Todas las reglas de lenguaje coinciden con el proyecto detectado.');
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 3. Calcular rutas destino
|
|
173
|
+
const rutas = calcularRutas(target, { global: esGlobal });
|
|
174
|
+
|
|
175
|
+
// 3b. En actualización (--force) limpiar reglas de lenguajes que ya no son del stack.
|
|
176
|
+
// Corre incluso si el perfil actual no incluye reglas-lenguajes, para eliminar
|
|
177
|
+
// subdirectorios de instalaciones anteriores con perfiles más amplios (e.g. completo).
|
|
178
|
+
if (force && stackDetectado !== null && rutas.reglas) {
|
|
179
|
+
const limpiadosStack = limpiarReglasSinStack(rutas.reglas, stackDetectado);
|
|
180
|
+
if (limpiadosStack.eliminados > 0) {
|
|
181
|
+
console.log(`\n[stack] Limpieza: ${limpiadosStack.eliminados} regla(s) de lenguaje eliminadas (${limpiadosStack.lenguajes.join(', ')})`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 4. Detectar _userland/
|
|
186
|
+
const userlandAgentes = path.join(process.cwd(), '_userland', 'agentes');
|
|
187
|
+
const userlandHabilidades = path.join(process.cwd(), '_userland', 'habilidades');
|
|
188
|
+
let archivosUserland = [];
|
|
189
|
+
|
|
190
|
+
if (fs.existsSync(userlandAgentes)) {
|
|
191
|
+
const agentesUser = fs.readdirSync(userlandAgentes)
|
|
192
|
+
.filter(f => f.endsWith('.md') && f !== '.gitkeep');
|
|
193
|
+
for (const a of agentesUser) {
|
|
194
|
+
archivosUserland.push({
|
|
195
|
+
origen: path.join(userlandAgentes, a),
|
|
196
|
+
rutaRelativa: `_userland/agentes/${a}`,
|
|
197
|
+
tipo: 'agentes',
|
|
198
|
+
modulo: 'userland',
|
|
199
|
+
esUserland: true,
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (fs.existsSync(userlandHabilidades)) {
|
|
205
|
+
const habsUser = fs.readdirSync(userlandHabilidades)
|
|
206
|
+
.filter(f => !f.startsWith('.'));
|
|
207
|
+
for (const h of habsUser) {
|
|
208
|
+
const skillPath = path.join(userlandHabilidades, h, 'SKILL.md');
|
|
209
|
+
if (fs.existsSync(skillPath)) {
|
|
210
|
+
archivosUserland.push({
|
|
211
|
+
origen: path.join(userlandHabilidades, h),
|
|
212
|
+
rutaRelativa: `_userland/habilidades/${h}`,
|
|
213
|
+
tipo: 'habilidades',
|
|
214
|
+
modulo: 'userland',
|
|
215
|
+
esUserland: true,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// 5. Mostrar plan
|
|
222
|
+
console.log(generarPlan(resolucion, rutas));
|
|
223
|
+
|
|
224
|
+
if (archivosUserland.length > 0) {
|
|
225
|
+
console.log(`\n[userland] (${archivosUserland.length} componentes del usuario)`);
|
|
226
|
+
for (const u of archivosUserland) {
|
|
227
|
+
console.log(` + ${u.rutaRelativa} (prioridad: usuario > core)`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (dryRun) {
|
|
232
|
+
console.log('\n(modo --dry-run: sin cambios aplicados)');
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 6. Detectar versión anterior para backup (Nivel 2)
|
|
237
|
+
let versionAnterior = null;
|
|
238
|
+
const estadoAnterior = cargarEstado(rutas.base);
|
|
239
|
+
if (estadoAnterior) {
|
|
240
|
+
versionAnterior = estadoAnterior.versionSistema;
|
|
241
|
+
if (versionAnterior && versionAnterior !== VERSION) {
|
|
242
|
+
console.log(`\n[preservar] Actualizando v${versionAnterior} → v${VERSION}`);
|
|
243
|
+
console.log(`[preservar] Datos de usuario serán preservados automáticamente.`);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// 6b. Migración LEARNINGS.md → APRENDIZAJES.md (v5.1.3+)
|
|
248
|
+
const learningsPath = path.join(process.cwd(), '.planning', 'LEARNINGS.md');
|
|
249
|
+
const aprendizajesPath = path.join(process.cwd(), '.planning', 'APRENDIZAJES.md');
|
|
250
|
+
if (fs.existsSync(learningsPath)) {
|
|
251
|
+
try {
|
|
252
|
+
const learningsContent = fs.readFileSync(learningsPath, 'utf8').trim();
|
|
253
|
+
if (learningsContent.length > 0) {
|
|
254
|
+
// Fusionar contenido en APRENDIZAJES.md
|
|
255
|
+
let aprendizajesContent = '';
|
|
256
|
+
if (fs.existsSync(aprendizajesPath)) {
|
|
257
|
+
aprendizajesContent = fs.readFileSync(aprendizajesPath, 'utf8');
|
|
258
|
+
}
|
|
259
|
+
// Solo fusionar si el contenido no está ya duplicado
|
|
260
|
+
if (!aprendizajesContent.includes(learningsContent.substring(0, 100))) {
|
|
261
|
+
const header = aprendizajesContent ? '' : '# Registro de aprendizajes\n\n---\n';
|
|
262
|
+
fs.writeFileSync(aprendizajesPath, aprendizajesContent + '\n\n' + header + learningsContent, 'utf8');
|
|
263
|
+
console.log(' ⊕ Migración: LEARNINGS.md fusionado en APRENDIZAJES.md');
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
// Eliminar el archivo obsoleto
|
|
267
|
+
fs.unlinkSync(learningsPath);
|
|
268
|
+
console.log(' ✓ Migración: LEARNINGS.md eliminado (unificado en APRENDIZAJES.md)');
|
|
269
|
+
} catch (err) {
|
|
270
|
+
console.log(` ! Migración LEARNINGS.md: ${err.message}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// 6c. Migración de archivos .planning/ renombrados de inglés a español (v5.6.0+)
|
|
275
|
+
// Los proyectos que actualizan desde versiones anteriores pueden tener
|
|
276
|
+
// archivos con nombres en inglés que los hooks ya no encuentran.
|
|
277
|
+
const MIGRACIONES_PLANNING = [
|
|
278
|
+
{ viejo: 'STATE.md', nuevo: 'ESTADO.md' },
|
|
279
|
+
{ viejo: 'COMPACT.md', nuevo: 'COMPACTACION.md' },
|
|
280
|
+
{ viejo: 'ROADMAP.md', nuevo: 'HOJA-RUTA.md' },
|
|
281
|
+
{ viejo: 'PROJECT.md', nuevo: 'PROYECTO.md' },
|
|
282
|
+
{ viejo: 'REQUIREMENTS.md', nuevo: 'REQUISITOS.md' },
|
|
283
|
+
{ viejo: 'GRAPH_REPORT.md', nuevo: 'REPORTE-GRAFO.md' },
|
|
284
|
+
{ viejo: 'METRICS.md', nuevo: 'METRICAS.md' },
|
|
285
|
+
];
|
|
286
|
+
|
|
287
|
+
let migracionesAplicadas = 0;
|
|
288
|
+
for (const m of MIGRACIONES_PLANNING) {
|
|
289
|
+
const rutaVieja = path.join(process.cwd(), '.planning', m.viejo);
|
|
290
|
+
const rutaNueva = path.join(process.cwd(), '.planning', m.nuevo);
|
|
291
|
+
|
|
292
|
+
if (!fs.existsSync(rutaVieja)) continue;
|
|
293
|
+
|
|
294
|
+
try {
|
|
295
|
+
const contenidoViejo = fs.readFileSync(rutaVieja, 'utf8').trim();
|
|
296
|
+
if (contenidoViejo.length === 0) {
|
|
297
|
+
// Archivo vacío: solo eliminar
|
|
298
|
+
fs.unlinkSync(rutaVieja);
|
|
299
|
+
console.log(` ✓ Migración: ${m.viejo} eliminado (vacío)`);
|
|
300
|
+
migracionesAplicadas++;
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (!fs.existsSync(rutaNueva)) {
|
|
305
|
+
// Caso 1: solo existe el viejo → renombrar
|
|
306
|
+
fs.renameSync(rutaVieja, rutaNueva);
|
|
307
|
+
console.log(` ✓ Migración: ${m.viejo} → ${m.nuevo} (renombrado)`);
|
|
308
|
+
} else {
|
|
309
|
+
// Caso 2: ambos existen → fusionar contenido del viejo en el nuevo
|
|
310
|
+
const contenidoNuevo = fs.readFileSync(rutaNueva, 'utf8');
|
|
311
|
+
// Solo fusionar si el contenido no está ya duplicado
|
|
312
|
+
const muestra = contenidoViejo.substring(0, 100);
|
|
313
|
+
if (!contenidoNuevo.includes(muestra)) {
|
|
314
|
+
const separador = '\n\n---\n\n<!-- Contenido migrado desde ' + m.viejo + ' -->\n\n';
|
|
315
|
+
fs.writeFileSync(rutaNueva, contenidoNuevo + separador + contenidoViejo, 'utf8');
|
|
316
|
+
console.log(` ⊕ Migración: ${m.viejo} fusionado en ${m.nuevo}`);
|
|
317
|
+
}
|
|
318
|
+
// Eliminar el archivo obsoleto
|
|
319
|
+
fs.unlinkSync(rutaVieja);
|
|
320
|
+
console.log(` ✓ Migración: ${m.viejo} eliminado (unificado en ${m.nuevo})`);
|
|
321
|
+
}
|
|
322
|
+
migracionesAplicadas++;
|
|
323
|
+
} catch (err) {
|
|
324
|
+
console.log(` ! Migración ${m.viejo}: ${err.message}`);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
if (migracionesAplicadas > 0) {
|
|
329
|
+
console.log(` [migración] ${migracionesAplicadas} archivo(s) de .planning/ migrado(s) de inglés a español`);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// 6d. Filtrar skills por targets declarados en SKILL.md frontmatter (patrón skillshare)
|
|
333
|
+
// Si un skill declara targets: [claude, copilot], solo se instala en esos runtimes.
|
|
334
|
+
// Si no declara targets, se instala en todos (comportamiento por defecto).
|
|
335
|
+
let skillsFiltradosPorTarget = 0;
|
|
336
|
+
resolucion.archivos = resolucion.archivos.filter(archivo => {
|
|
337
|
+
if (archivo.tipo !== 'habilidades') return true;
|
|
338
|
+
|
|
339
|
+
const skillMdPath = path.join(archivo.origen, 'SKILL.md');
|
|
340
|
+
if (!fs.existsSync(skillMdPath)) return true;
|
|
341
|
+
|
|
342
|
+
try {
|
|
343
|
+
const contenido = fs.readFileSync(skillMdPath, 'utf8');
|
|
344
|
+
// Extraer frontmatter targets (formato: targets: [claude, copilot])
|
|
345
|
+
const targetsMatch = contenido.match(/^targets:\s*\[([^\]]+)\]/m);
|
|
346
|
+
if (!targetsMatch) return true; // Sin targets declarados → incluir en todos
|
|
347
|
+
|
|
348
|
+
const declaredTargets = targetsMatch[1].split(',').map(t => t.trim().replace(/['"]/g, ''));
|
|
349
|
+
if (declaredTargets.length === 0) return true;
|
|
350
|
+
|
|
351
|
+
// Normalizar target actual (claude-code → claude, etc.)
|
|
352
|
+
const targetNormalizado = target.replace(/-code$/, '');
|
|
353
|
+
if (declaredTargets.includes(targetNormalizado) || declaredTargets.includes(target)) {
|
|
354
|
+
return true;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
skillsFiltradosPorTarget++;
|
|
358
|
+
return false;
|
|
359
|
+
} catch {
|
|
360
|
+
return true; // Error leyendo → incluir por defecto
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
if (skillsFiltradosPorTarget > 0) {
|
|
365
|
+
console.log(`\n[targets] ${skillsFiltradosPorTarget} skill(s) excluidos (no declaran target "${target}")`);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// 7. Aplicar instalación
|
|
369
|
+
console.log('\nAplicando instalación...\n');
|
|
370
|
+
|
|
371
|
+
const estado = crearEstado({
|
|
372
|
+
versionSistema: VERSION,
|
|
373
|
+
target,
|
|
374
|
+
perfil,
|
|
375
|
+
rutaBase: rutas.base,
|
|
376
|
+
global: esGlobal,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
let instalados = 0;
|
|
380
|
+
let errores = 0;
|
|
381
|
+
let colisiones = 0;
|
|
382
|
+
let protegidos = 0;
|
|
383
|
+
let respaldados = 0;
|
|
384
|
+
let evolucionados = 0;
|
|
385
|
+
|
|
386
|
+
// Escanear componentes evolucionados antes de instalar
|
|
387
|
+
if (force && fs.existsSync(rutas.base)) {
|
|
388
|
+
const evolved = [
|
|
389
|
+
...scanEvolved(rutas.agentes || ''),
|
|
390
|
+
...scanEvolved(rutas.habilidades || ''),
|
|
391
|
+
...scanEvolved(rutas.comandos || ''),
|
|
392
|
+
...scanEvolved(rutas.reglas || ''),
|
|
393
|
+
];
|
|
394
|
+
if (evolved.length > 0) {
|
|
395
|
+
console.log(`[evolución] ${evolved.length} componente(s) evolucionado(s) detectado(s):`);
|
|
396
|
+
for (const e of evolved) {
|
|
397
|
+
console.log(` ★ ${path.basename(e.path)} (por ${e.evolvedBy || 'auto-evolución'}, desde v${e.evolvedFrom || '?'})`);
|
|
398
|
+
}
|
|
399
|
+
console.log('');
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Nivel 3: Merge de instintos antes de instalar (si existe proyecto.yaml en destino)
|
|
404
|
+
const instintosOrigen = path.join(RAIZ_PKG, 'instintos', 'proyecto.yaml');
|
|
405
|
+
const instintosDestino = path.join(process.cwd(), 'instintos', 'proyecto.yaml');
|
|
406
|
+
if (fs.existsSync(instintosDestino) && fs.existsSync(instintosOrigen)) {
|
|
407
|
+
const mergeResult = mergeInstintos(instintosOrigen, instintosDestino);
|
|
408
|
+
if (mergeResult.merged) {
|
|
409
|
+
console.log(` ⊕ Instintos: ${mergeResult.preservados} preservados, ${mergeResult.nuevos} nuevos agregados`);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Instalar archivos core
|
|
414
|
+
for (const archivo of resolucion.archivos) {
|
|
415
|
+
try {
|
|
416
|
+
const resultado = instalarArchivo(archivo, rutas, runtime, {
|
|
417
|
+
force,
|
|
418
|
+
versionAnterior,
|
|
419
|
+
versionActual: VERSION,
|
|
420
|
+
estado,
|
|
421
|
+
syncMode,
|
|
422
|
+
flatNaming,
|
|
423
|
+
});
|
|
424
|
+
if (resultado.instalado) {
|
|
425
|
+
registrarArchivo(estado, {
|
|
426
|
+
origen: archivo.rutaRelativa,
|
|
427
|
+
destino: resultado.destino,
|
|
428
|
+
tipo: archivo.tipo,
|
|
429
|
+
});
|
|
430
|
+
instalados++;
|
|
431
|
+
} else if (resultado.colision) {
|
|
432
|
+
colisiones++;
|
|
433
|
+
} else if (resultado.protegido) {
|
|
434
|
+
protegidos++;
|
|
435
|
+
} else if (resultado.evolucionado) {
|
|
436
|
+
// Registrar en el estado aunque no se sobrescribió — el archivo
|
|
437
|
+
// existe en disco (versión evolucionada del usuario) y el doctor
|
|
438
|
+
// necesita contarlo para la verificación de conteo de componentes.
|
|
439
|
+
registrarArchivo(estado, {
|
|
440
|
+
origen: archivo.rutaRelativa,
|
|
441
|
+
destino: resultado.destino,
|
|
442
|
+
tipo: archivo.tipo,
|
|
443
|
+
});
|
|
444
|
+
evolucionados++;
|
|
445
|
+
}
|
|
446
|
+
} catch (err) {
|
|
447
|
+
console.error(` ! Error: ${archivo.rutaRelativa}: ${err.message}`);
|
|
448
|
+
errores++;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Instalar userland (prioridad sobre core)
|
|
453
|
+
for (const archivo of archivosUserland) {
|
|
454
|
+
try {
|
|
455
|
+
const resultado = instalarArchivo(archivo, rutas, runtime, { force: true });
|
|
456
|
+
if (resultado.instalado) {
|
|
457
|
+
registrarArchivo(estado, {
|
|
458
|
+
origen: archivo.rutaRelativa,
|
|
459
|
+
destino: resultado.destino,
|
|
460
|
+
tipo: archivo.tipo,
|
|
461
|
+
});
|
|
462
|
+
instalados++;
|
|
463
|
+
console.log(` * Userland: ${path.basename(archivo.origen)} (prioridad usuario)`);
|
|
464
|
+
}
|
|
465
|
+
} catch (err) {
|
|
466
|
+
console.error(` ! Error userland: ${archivo.rutaRelativa}: ${err.message}`);
|
|
467
|
+
errores++;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
// Registrar componentes
|
|
472
|
+
for (const modulo of resolucion.modulos) {
|
|
473
|
+
registrarComponente(estado, modulo);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// 7. Registrar hooks en settings.json del runtime
|
|
477
|
+
// Los hooks solo se registran a nivel PROYECTO (no global) para evitar
|
|
478
|
+
// ejecucion duplicada cuando Claude Code combina hooks de ambos scopes.
|
|
479
|
+
let hooksRegistrados = 0;
|
|
480
|
+
let hooksPreservados = 0;
|
|
481
|
+
|
|
482
|
+
if (runtime.soportaHooks) {
|
|
483
|
+
// hooks-config.json es la fuente de verdad para hooks registrables.
|
|
484
|
+
// No filtrar por tipo de módulo porque hooks como grafo-contexto.js
|
|
485
|
+
// pueden pertenecer a módulos con tipo distinto a "hooks".
|
|
486
|
+
const hooksConfig = cargarHooksConfig();
|
|
487
|
+
const hookFilesInstalados = resolucion.archivos
|
|
488
|
+
.filter(a => (a.rutaRelativa || a.origen).endsWith('.js') && hooksConfig[path.basename(a.origen)])
|
|
489
|
+
.map(a => path.basename(a.origen));
|
|
490
|
+
|
|
491
|
+
if (hookFilesInstalados.length > 0) {
|
|
492
|
+
if (esGlobal) {
|
|
493
|
+
console.log(' ~ Hooks: omitiendo registro en settings global (solo se registran a nivel proyecto)');
|
|
494
|
+
console.log(' Los hooks se activan al instalar a nivel proyecto con: npx swl-ses@latest install --target claude');
|
|
495
|
+
} else {
|
|
496
|
+
const settingsPath = rutaSettings(runtime, rutas.base);
|
|
497
|
+
try {
|
|
498
|
+
const resultado = registrarHooks({
|
|
499
|
+
settingsPath,
|
|
500
|
+
hooksDir: rutas.hooks,
|
|
501
|
+
esGlobal: false,
|
|
502
|
+
hookFiles: hookFilesInstalados,
|
|
503
|
+
});
|
|
504
|
+
hooksRegistrados = resultado.registrados;
|
|
505
|
+
hooksPreservados = resultado.preservados;
|
|
506
|
+
console.log(` + Hooks registrados en settings.json (proyecto): ${hooksRegistrados}`);
|
|
507
|
+
if (hooksPreservados > 0) {
|
|
508
|
+
console.log(` (${hooksPreservados} hooks externos preservados)`);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
// Registrar optimizaciones de rendimiento en settings.json
|
|
512
|
+
const optResult = registrarOptimizaciones(settingsPath);
|
|
513
|
+
if (optResult.aplicadas > 0) {
|
|
514
|
+
console.log(` + Optimizaciones de rendimiento aplicadas: ${optResult.aplicadas}`);
|
|
515
|
+
}
|
|
516
|
+
} catch (err) {
|
|
517
|
+
console.error(` ! Error registrando hooks en settings.json: ${err.message}`);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// 8. Generar archivo de instrucciones principal (si el target lo requiere)
|
|
524
|
+
const transformador = obtenerTransformador(target, runtime);
|
|
525
|
+
if (runtime.archivoPrincipal) {
|
|
526
|
+
try {
|
|
527
|
+
// Recopilar contexto para el archivo de instrucciones
|
|
528
|
+
const agentesInstalados = resolucion.archivos
|
|
529
|
+
.filter(a => a.tipo === 'agentes')
|
|
530
|
+
.map(a => {
|
|
531
|
+
try {
|
|
532
|
+
return { nombre: path.basename(a.origen, '.md'), contenido: fs.readFileSync(a.origen, 'utf-8') };
|
|
533
|
+
} catch { return null; }
|
|
534
|
+
})
|
|
535
|
+
.filter(Boolean);
|
|
536
|
+
|
|
537
|
+
const reglasInstaladas = resolucion.archivos
|
|
538
|
+
.filter(a => a.tipo === 'reglas')
|
|
539
|
+
.map(a => {
|
|
540
|
+
try {
|
|
541
|
+
return { nombre: path.basename(a.origen, '.md'), contenido: fs.readFileSync(a.origen, 'utf-8') };
|
|
542
|
+
} catch { return null; }
|
|
543
|
+
})
|
|
544
|
+
.filter(Boolean);
|
|
545
|
+
|
|
546
|
+
const skillsInstalados = resolucion.archivos
|
|
547
|
+
.filter(a => a.tipo === 'habilidades')
|
|
548
|
+
.map(a => {
|
|
549
|
+
const nombre = path.basename(a.origen);
|
|
550
|
+
const skillMd = path.join(a.origen, 'SKILL.md');
|
|
551
|
+
let descripcion = '';
|
|
552
|
+
try {
|
|
553
|
+
const contenido = fs.readFileSync(skillMd, 'utf-8');
|
|
554
|
+
const match = contenido.match(/description:\s*>?\s*\n?\s*(.+)/);
|
|
555
|
+
if (match) descripcion = match[1].trim();
|
|
556
|
+
} catch { /* sin descripcion */ }
|
|
557
|
+
return { nombre, descripcion };
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
const conteos = {
|
|
561
|
+
agentes: agentesInstalados.length,
|
|
562
|
+
skills: skillsInstalados.length,
|
|
563
|
+
reglas: reglasInstaladas.length,
|
|
564
|
+
comandos: resolucion.archivos.filter(a => a.tipo === 'comandos').length,
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
const instrucciones = transformador.generarArchivoInstrucciones({
|
|
568
|
+
version: VERSION,
|
|
569
|
+
perfil,
|
|
570
|
+
agentes: agentesInstalados,
|
|
571
|
+
reglas: reglasInstaladas,
|
|
572
|
+
skills: skillsInstalados,
|
|
573
|
+
conteos,
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
if (instrucciones) {
|
|
577
|
+
const dirBase = instrucciones.dirBase
|
|
578
|
+
? path.resolve(instrucciones.dirBase)
|
|
579
|
+
: rutas.base;
|
|
580
|
+
const rutaInstrucciones = path.join(dirBase, instrucciones.rutaRelativa);
|
|
581
|
+
const dirInstrucciones = path.dirname(rutaInstrucciones);
|
|
582
|
+
|
|
583
|
+
// Opt-out explícito: --no-claudemd para Claude Code
|
|
584
|
+
// Respeta al usuario que prefiere mantener su CLAUDE.md 100% manual.
|
|
585
|
+
const esClaudeMd = instrucciones.rutaRelativa === 'CLAUDE.md';
|
|
586
|
+
if (esClaudeMd && opciones.no_claudemd) {
|
|
587
|
+
console.log(' = CLAUDE.md no modificado (--no-claudemd)');
|
|
588
|
+
} else if (instrucciones.merge && instrucciones.merge.tipo === 'marcadores') {
|
|
589
|
+
// Merge idempotente con marcadores — preserva contenido del usuario.
|
|
590
|
+
if (!fs.existsSync(dirInstrucciones)) {
|
|
591
|
+
fs.mkdirSync(dirInstrucciones, { recursive: true });
|
|
592
|
+
}
|
|
593
|
+
const { mergeConMarcadores } = require('./lib/append-con-marcadores');
|
|
594
|
+
const resMerge = mergeConMarcadores(rutaInstrucciones, instrucciones.contenido, {
|
|
595
|
+
beginTag: instrucciones.merge.beginTag,
|
|
596
|
+
endTag: instrucciones.merge.endTag,
|
|
597
|
+
beginPrefix: instrucciones.merge.beginPrefix,
|
|
598
|
+
});
|
|
599
|
+
const etiqueta = {
|
|
600
|
+
'creado': '+ CLAUDE.md creado con bloque SWL',
|
|
601
|
+
'append': '+ Bloque SWL agregado al final de CLAUDE.md (contenido del usuario preservado)',
|
|
602
|
+
'reemplazado': '* Bloque SWL actualizado en CLAUDE.md (contenido del usuario preservado)',
|
|
603
|
+
'sin-cambios': '= CLAUDE.md ya tenía el bloque SWL actualizado',
|
|
604
|
+
'error': '! Error al fusionar CLAUDE.md',
|
|
605
|
+
}[resMerge.accion] || `${resMerge.accion} ${resMerge.archivo}`;
|
|
606
|
+
console.log(` ${etiqueta}${resMerge.detalle ? ': ' + resMerge.detalle : ''}`);
|
|
607
|
+
registrarArchivo(estado, {
|
|
608
|
+
origen: 'generado-merge',
|
|
609
|
+
destino: rutaInstrucciones,
|
|
610
|
+
tipo: 'instrucciones-merge',
|
|
611
|
+
accion: resMerge.accion,
|
|
612
|
+
});
|
|
613
|
+
} else {
|
|
614
|
+
// Comportamiento clásico: sobrescribir archivo completo (codex/gemini/copilot/opencode)
|
|
615
|
+
if (!fs.existsSync(dirInstrucciones)) {
|
|
616
|
+
fs.mkdirSync(dirInstrucciones, { recursive: true });
|
|
617
|
+
}
|
|
618
|
+
fs.writeFileSync(rutaInstrucciones, instrucciones.contenido, 'utf-8');
|
|
619
|
+
console.log(` + Archivo principal generado: ${instrucciones.rutaRelativa}`);
|
|
620
|
+
registrarArchivo(estado, {
|
|
621
|
+
origen: 'generado',
|
|
622
|
+
destino: rutaInstrucciones,
|
|
623
|
+
tipo: 'instrucciones',
|
|
624
|
+
});
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
} catch (err) {
|
|
628
|
+
console.error(` ! Error generando archivo de instrucciones: ${err.message}`);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// 9. Opt-in interactivo de notificaciones Telegram
|
|
633
|
+
// Nota: SWL solo registra hooks a nivel proyecto, excepto bajo opt-in explícito
|
|
634
|
+
// del usuario en este flujo. Ver ADR-0009 y scripts/lib/hooks-settings.js.
|
|
635
|
+
const noNotificaciones = opciones.no_notificaciones || false;
|
|
636
|
+
const withNotificaciones = opciones.with_notificaciones || null; // 'token,chatId'
|
|
637
|
+
|
|
638
|
+
if (!noNotificaciones) {
|
|
639
|
+
try {
|
|
640
|
+
const notif = require('./lib/notificaciones-telegram');
|
|
641
|
+
|
|
642
|
+
// Modo headless explícito: --with-notificaciones=token,chatId
|
|
643
|
+
if (withNotificaciones) {
|
|
644
|
+
const [tokenHl, chatIdHl] = withNotificaciones.split(',');
|
|
645
|
+
if (tokenHl && chatIdHl) {
|
|
646
|
+
const resHl = await notif.init({
|
|
647
|
+
token: tokenHl.trim(),
|
|
648
|
+
chatId: chatIdHl.trim(),
|
|
649
|
+
esTty: false,
|
|
650
|
+
hooksDir: rutas.hooks || null,
|
|
651
|
+
});
|
|
652
|
+
if (resHl.resultado === 'completado') {
|
|
653
|
+
console.log(' + Notificaciones Telegram configuradas (modo headless).');
|
|
654
|
+
} else {
|
|
655
|
+
console.log(` ~ Notificaciones Telegram: ${resHl.resultado} — ${resHl.detalle || ''}`);
|
|
656
|
+
}
|
|
657
|
+
} else {
|
|
658
|
+
console.log(' ! --with-notificaciones: formato esperado token,chatId — omitiendo notificaciones.');
|
|
659
|
+
}
|
|
660
|
+
} else if (!ES_TTY) {
|
|
661
|
+
// No-TTY y sin flags headless → saltar automáticamente
|
|
662
|
+
console.log(' ~ Notificaciones Telegram: omitido en modo no-interactivo (usar /swl:notificaciones init para activarlo después).');
|
|
663
|
+
} else {
|
|
664
|
+
// TTY → flujo interactivo
|
|
665
|
+
const resInteractivo = await notif.init({
|
|
666
|
+
esTty: true,
|
|
667
|
+
hooksDir: rutas.hooks || null,
|
|
668
|
+
dryRun: dryRun,
|
|
669
|
+
});
|
|
670
|
+
if (resInteractivo.resultado === 'completado') {
|
|
671
|
+
console.log(' + Notificaciones Telegram configuradas.');
|
|
672
|
+
} else if (resInteractivo.resultado === 'omitido') {
|
|
673
|
+
// Silencioso — ya se imprimió mensaje en init()
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
} catch (err) {
|
|
677
|
+
// No romper la instalación entera por un fallo de notificaciones
|
|
678
|
+
console.error(` ! Notificaciones Telegram: error no esperado (instalación continúa): ${err.message}`);
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// 10. Guardar estado
|
|
683
|
+
estado.hooksRegistrados = hooksRegistrados;
|
|
684
|
+
const rutaEstado = guardarEstado(estado, rutas.base);
|
|
685
|
+
|
|
686
|
+
// 9.5. En instalación global: copiar vendors a ~/.claude/scripts/vendor/
|
|
687
|
+
// Permite que los scripts funcionen en proyectos que no tienen la copia local
|
|
688
|
+
if (esGlobal) {
|
|
689
|
+
const vendorsGlobal = ['claude-usage', 'markitdown'];
|
|
690
|
+
for (const vendorNombre of vendorsGlobal) {
|
|
691
|
+
const vendorOrigen = path.join(RAIZ_PKG, 'scripts', 'vendor', vendorNombre);
|
|
692
|
+
const vendorDestino = path.join(rutas.base, 'scripts', 'vendor', vendorNombre);
|
|
693
|
+
if (fs.existsSync(vendorOrigen)) {
|
|
694
|
+
try {
|
|
695
|
+
copiarDirectorio(vendorOrigen, vendorDestino);
|
|
696
|
+
console.log(`[vendor] ${vendorNombre} copiado a ${vendorDestino}`);
|
|
697
|
+
} catch (err) {
|
|
698
|
+
console.error(` ! Error copiando ${vendorNombre}: ${err.message}`);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
// 10. Reporte final
|
|
705
|
+
console.log('\n' + '='.repeat(40));
|
|
706
|
+
console.log('Resultado de instalación');
|
|
707
|
+
console.log('='.repeat(40));
|
|
708
|
+
console.log(` Target: ${target} (${runtime.nombre})`);
|
|
709
|
+
console.log(` Perfil: ${perfil}`);
|
|
710
|
+
console.log(` Ubicación: ${rutas.base}`);
|
|
711
|
+
console.log(` Instalados: ${instalados}`);
|
|
712
|
+
console.log(` Protegidos: ${protegidos} (datos de usuario preservados)`);
|
|
713
|
+
console.log(` Evolucionados: ${evolucionados} (mejorados por auto-evolución, preservados)`);
|
|
714
|
+
console.log(` Respaldados: ${estado.backups ? estado.backups.length : 0}`);
|
|
715
|
+
console.log(` Colisiones: ${colisiones}`);
|
|
716
|
+
console.log(` Errores: ${errores}`);
|
|
717
|
+
console.log(` Estado: ${rutaEstado}`);
|
|
718
|
+
|
|
719
|
+
if (resolucion.warnings.length > 0) {
|
|
720
|
+
console.log('\nAdvertencias:');
|
|
721
|
+
for (const w of resolucion.warnings) {
|
|
722
|
+
console.log(` ! ${w}`);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// 11. Cleanup automático de backups antiguos (conservar últimas 3 versiones)
|
|
727
|
+
const cleanup = limpiarBackups(process.cwd(), 3);
|
|
728
|
+
if (cleanup.eliminados > 0) {
|
|
729
|
+
console.log(`\n[cleanup] ${cleanup.eliminados} backup(s) antiguo(s) eliminado(s) (${cleanup.liberadoMB} MB liberados, ${cleanup.conservados} conservados)`);
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
// 12. Actualizar manifest y .gitignore (solo para instalaciones locales)
|
|
733
|
+
if (!esGlobal) {
|
|
734
|
+
const cwd = process.cwd();
|
|
735
|
+
|
|
736
|
+
// Actualiza manifest con target y profile realmente usados
|
|
737
|
+
escribirManifest(cwd, { target, profile: perfil, version: VERSION });
|
|
738
|
+
|
|
739
|
+
// Agrega entradas gitignore específicas del runtime si no son las base (claude)
|
|
740
|
+
const extrasRuntime = entradasParaRuntime(target);
|
|
741
|
+
actualizarGitignore(cwd, extrasRuntime);
|
|
742
|
+
console.log('[manifest] .swl-ses actualizado.');
|
|
743
|
+
console.log('[gitignore] Sección swl-ses actualizada.');
|
|
744
|
+
|
|
745
|
+
// 13. Limpiar archivos swl-ses que estén tracked en git
|
|
746
|
+
// SWL-SES es tooling (como node_modules), no se commitea.
|
|
747
|
+
// Si el usuario commiteó archivos antes de tener el .gitignore correcto,
|
|
748
|
+
// los quitamos del índice para que git deje de trackearlos.
|
|
749
|
+
const limpieza = limpiarTracked(cwd, extrasRuntime);
|
|
750
|
+
if (limpieza.eliminados > 0) {
|
|
751
|
+
console.log(`[git] ${limpieza.eliminados} archivo(s) swl-ses removido(s) del índice de git (los archivos siguen en disco).`);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
console.log('\nSiguiente paso:');
|
|
756
|
+
console.log(' npx swl-ses@latest doctor');
|
|
757
|
+
console.log('');
|
|
758
|
+
console.log(' (usar @latest evita el caché stale de npx — ver MANUAL_USO.md)');
|
|
759
|
+
console.log('');
|
|
760
|
+
|
|
761
|
+
if (errores > 0) {
|
|
762
|
+
process.exit(1);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
/**
|
|
767
|
+
* Instala un archivo individual en el directorio destino correcto
|
|
768
|
+
*/
|
|
769
|
+
function instalarArchivo(archivo, rutas, runtime, opciones = {}) {
|
|
770
|
+
// Verificar que el target soporta este tipo de componente
|
|
771
|
+
if (runtime.tiposSoportados && !runtime.tiposSoportados.includes(archivo.tipo)) {
|
|
772
|
+
return { instalado: false, razon: `Target "${runtime.id}" no soporta "${archivo.tipo}"` };
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
let dirDestino;
|
|
776
|
+
|
|
777
|
+
switch (archivo.tipo) {
|
|
778
|
+
case 'agentes':
|
|
779
|
+
dirDestino = rutas.agentes;
|
|
780
|
+
break;
|
|
781
|
+
case 'habilidades':
|
|
782
|
+
dirDestino = rutas.habilidades;
|
|
783
|
+
break;
|
|
784
|
+
case 'comandos':
|
|
785
|
+
dirDestino = rutas.comandos;
|
|
786
|
+
break;
|
|
787
|
+
case 'reglas':
|
|
788
|
+
dirDestino = rutas.reglas;
|
|
789
|
+
break;
|
|
790
|
+
case 'hooks':
|
|
791
|
+
dirDestino = rutas.hooks;
|
|
792
|
+
break;
|
|
793
|
+
case 'plantillas':
|
|
794
|
+
// Las plantillas van a .planning/
|
|
795
|
+
dirDestino = path.join(process.cwd(), '.planning');
|
|
796
|
+
break;
|
|
797
|
+
default:
|
|
798
|
+
dirDestino = rutas.base;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
if (!dirDestino) {
|
|
802
|
+
return { instalado: false, razon: `Target no soporta tipo "${archivo.tipo}"` };
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
// Crear directorio destino si no existe
|
|
806
|
+
if (!fs.existsSync(dirDestino)) {
|
|
807
|
+
fs.mkdirSync(dirDestino, { recursive: true });
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
let nombreArchivo = path.basename(archivo.origen);
|
|
811
|
+
|
|
812
|
+
// Flat naming: convierte rutas jerárquicas en nombres planos con __
|
|
813
|
+
// Ejemplo: habilidades/build-errors-python → build-errors-python (sin cambio, ya es plano)
|
|
814
|
+
// Ejemplo: reglas/lenguajes/java/java-estilo.md → java__java-estilo.md
|
|
815
|
+
// Patrón adoptado de skillshare (internal/sync/naming.go)
|
|
816
|
+
if (opciones.flatNaming && archivo.rutaRelativa) {
|
|
817
|
+
const partes = archivo.rutaRelativa.split('/');
|
|
818
|
+
if (partes.length > 2) {
|
|
819
|
+
// Tomar desde el segundo nivel en adelante, unir con __
|
|
820
|
+
nombreArchivo = partes.slice(1).join('__');
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// Reglas de lenguaje: preservar subdirectorio (reglas/lenguajes/LANG/archivo.md → .claude/rules/LANG/archivo.md)
|
|
825
|
+
// Sin esto todos los archivos colisionarían con el mismo nombre en la raíz.
|
|
826
|
+
let destino;
|
|
827
|
+
if (
|
|
828
|
+
archivo.tipo === 'reglas' &&
|
|
829
|
+
archivo.rutaRelativa &&
|
|
830
|
+
archivo.rutaRelativa.startsWith('reglas/lenguajes/')
|
|
831
|
+
) {
|
|
832
|
+
const resto = archivo.rutaRelativa.slice('reglas/lenguajes/'.length);
|
|
833
|
+
const partes = resto.split('/');
|
|
834
|
+
if (partes.length >= 2) {
|
|
835
|
+
const subdirLang = path.join(dirDestino, partes[0]);
|
|
836
|
+
if (!fs.existsSync(subdirLang)) {
|
|
837
|
+
fs.mkdirSync(subdirLang, { recursive: true });
|
|
838
|
+
}
|
|
839
|
+
destino = path.join(subdirLang, partes[1]);
|
|
840
|
+
} else {
|
|
841
|
+
destino = path.join(dirDestino, nombreArchivo);
|
|
842
|
+
}
|
|
843
|
+
} else {
|
|
844
|
+
destino = path.join(dirDestino, nombreArchivo);
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// Seguridad: validar ruta
|
|
848
|
+
validarRuta(dirDestino, nombreArchivo);
|
|
849
|
+
|
|
850
|
+
// Verificar archivo sensible
|
|
851
|
+
if (esArchivoSensible(nombreArchivo)) {
|
|
852
|
+
console.log(` ! Archivo sensible omitido: ${nombreArchivo}`);
|
|
853
|
+
return { instalado: false, razon: 'archivo sensible' };
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// Nivel 1: Verificar si el destino está protegido (datos de usuario)
|
|
857
|
+
const rutaRelativaProyecto = path.relative(process.cwd(), destino);
|
|
858
|
+
const proteccion = esProtegido(rutaRelativaProyecto);
|
|
859
|
+
if (proteccion.protegido && fs.existsSync(destino)) {
|
|
860
|
+
console.log(` ~ Protegido: ${nombreArchivo} (${proteccion.razon})`);
|
|
861
|
+
return { instalado: false, protegido: true };
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
// Evolución: Verificar si el destino fue evolucionado por auto-evolución
|
|
865
|
+
const esComponenteEvolucionable = ['agentes', 'habilidades', 'comandos', 'reglas'].includes(archivo.tipo);
|
|
866
|
+
if (esComponenteEvolucionable && fs.existsSync(destino) && opciones.force) {
|
|
867
|
+
// Resolver ruta absoluta del origen (archivo.origen es relativo al paquete)
|
|
868
|
+
const origenAbsoluto = path.resolve(RAIZ_PKG, archivo.origen);
|
|
869
|
+
const strategy = decideUpdateStrategy(destino, origenAbsoluto, opciones.versionActual || '');
|
|
870
|
+
if (strategy.strategy === 'preserve') {
|
|
871
|
+
console.log(` ★ Evolucionado: ${nombreArchivo} — preservado (${strategy.reason})`);
|
|
872
|
+
return { instalado: false, evolucionado: true, destino };
|
|
873
|
+
}
|
|
874
|
+
if (strategy.strategy === 'conflict') {
|
|
875
|
+
// Crear backup del archivo evolucionado ANTES de sobrescribir
|
|
876
|
+
if (opciones.versionAnterior) {
|
|
877
|
+
const backup = crearBackup(process.cwd(), destino, opciones.versionAnterior);
|
|
878
|
+
if (backup.respaldado) {
|
|
879
|
+
console.log(` ⚠ Conflicto: ${nombreArchivo} — evolucionado localmente + cambios en versión nueva`);
|
|
880
|
+
console.log(` ↩ Backup evolucionado: ${path.relative(process.cwd(), backup.rutaBackup)}`);
|
|
881
|
+
if (opciones.estado) {
|
|
882
|
+
registrarBackup(opciones.estado, {
|
|
883
|
+
rutaOriginal: destino,
|
|
884
|
+
rutaBackup: backup.rutaBackup,
|
|
885
|
+
version: opciones.versionAnterior,
|
|
886
|
+
evolucionado: true,
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
// Intentar merge: generar diff de mutaciones para re-aplicación
|
|
892
|
+
const merge = mergeEvolved(destino, origenAbsoluto, opciones.versionActual || '');
|
|
893
|
+
if (merge.merged && merge.diffPath) {
|
|
894
|
+
console.log(` ⊕ Diff generado: ${path.relative(process.cwd(), merge.diffPath)} (${merge.diffsCount} mutaciones)`);
|
|
895
|
+
console.log(` → Ejecutar /swl:autoresearch para re-aplicar mutaciones sobre v${opciones.versionActual}`);
|
|
896
|
+
} else if (merge.merged) {
|
|
897
|
+
console.log(` ⊕ Merge exitoso: campos evolved re-aplicados sin cambios de contenido`);
|
|
898
|
+
return { instalado: false, evolucionado: true, destino };
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// Verificar colisión
|
|
904
|
+
if (fs.existsSync(destino) && !opciones.force) {
|
|
905
|
+
console.log(` - Colisión: ${nombreArchivo} (usa --force para sobreescribir)`);
|
|
906
|
+
return { instalado: false, colision: true };
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// Nivel 2: Backup antes de sobreescribir con --force
|
|
910
|
+
if (fs.existsSync(destino) && opciones.force && opciones.versionAnterior) {
|
|
911
|
+
const backup = crearBackup(process.cwd(), destino, opciones.versionAnterior);
|
|
912
|
+
if (backup.respaldado) {
|
|
913
|
+
console.log(` ↩ Backup: ${nombreArchivo} → ${path.relative(process.cwd(), backup.rutaBackup)}`);
|
|
914
|
+
if (opciones.estado) {
|
|
915
|
+
registrarBackup(opciones.estado, {
|
|
916
|
+
rutaOriginal: destino,
|
|
917
|
+
rutaBackup: backup.rutaBackup,
|
|
918
|
+
version: opciones.versionAnterior,
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
// Copiar, symlink o flat-copy según syncMode
|
|
925
|
+
if (fs.existsSync(archivo.origen)) {
|
|
926
|
+
const stat = fs.statSync(archivo.origen);
|
|
927
|
+
const modo = opciones.syncMode || 'copy';
|
|
928
|
+
|
|
929
|
+
if (modo === 'symlink') {
|
|
930
|
+
// Symlink mode: crear enlace simbólico en lugar de copiar.
|
|
931
|
+
// Cambios en la fuente se reflejan instantáneamente en el destino.
|
|
932
|
+
// Ideal para desarrollo del repo fuente de swl-ses.
|
|
933
|
+
try {
|
|
934
|
+
if (fs.existsSync(destino)) {
|
|
935
|
+
const dStat = fs.lstatSync(destino);
|
|
936
|
+
if (dStat.isSymbolicLink()) fs.unlinkSync(destino);
|
|
937
|
+
else if (dStat.isDirectory()) fs.rmSync(destino, { recursive: true });
|
|
938
|
+
else fs.unlinkSync(destino);
|
|
939
|
+
}
|
|
940
|
+
const origenAbsoluto = path.resolve(archivo.origen);
|
|
941
|
+
fs.symlinkSync(origenAbsoluto, destino, stat.isDirectory() ? 'junction' : 'file');
|
|
942
|
+
console.log(` ~ ${path.relative(rutas.base, destino)} (symlink)`);
|
|
943
|
+
return { instalado: true, destino };
|
|
944
|
+
} catch (symlinkErr) {
|
|
945
|
+
// Fallback a copy si symlink falla (permisos, filesystem)
|
|
946
|
+
console.log(` ! Symlink falló (${symlinkErr.code || symlinkErr.message}), usando copy`);
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
// Copy mode (default) o fallback de symlink
|
|
951
|
+
if (stat.isDirectory()) {
|
|
952
|
+
copiarDirectorio(archivo.origen, path.join(dirDestino, nombreArchivo));
|
|
953
|
+
} else {
|
|
954
|
+
fs.copyFileSync(archivo.origen, destino);
|
|
955
|
+
}
|
|
956
|
+
console.log(` + ${path.relative(rutas.base, destino)}`);
|
|
957
|
+
return { instalado: true, destino };
|
|
958
|
+
} else {
|
|
959
|
+
return { instalado: false, razon: 'origen no existe' };
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Copia un directorio recursivamente
|
|
965
|
+
*/
|
|
966
|
+
function copiarDirectorio(origen, destino) {
|
|
967
|
+
if (!fs.existsSync(destino)) {
|
|
968
|
+
fs.mkdirSync(destino, { recursive: true });
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
const entradas = fs.readdirSync(origen, { withFileTypes: true });
|
|
972
|
+
for (const entrada of entradas) {
|
|
973
|
+
const src = path.join(origen, entrada.name);
|
|
974
|
+
const dst = path.join(destino, entrada.name);
|
|
975
|
+
|
|
976
|
+
if (entrada.isDirectory()) {
|
|
977
|
+
copiarDirectorio(src, dst);
|
|
978
|
+
} else {
|
|
979
|
+
fs.copyFileSync(src, dst);
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/**
|
|
985
|
+
* Elimina subdirectorios de reglas de lenguaje en .claude/rules/ para lenguajes
|
|
986
|
+
* que NO están en el stack detectado del proyecto.
|
|
987
|
+
*
|
|
988
|
+
* Solo borra subdirectorios cuyo nombre coincide con un lenguaje conocido del sistema
|
|
989
|
+
* (java, go, rust, etc.). Nunca toca archivos en la raíz de .claude/rules/.
|
|
990
|
+
*
|
|
991
|
+
* @param {string} dirReglas - Ruta a .claude/rules/ (rutas.reglas)
|
|
992
|
+
* @param {Set<string>} stackDetectado - Lenguajes detectados por detectarStack()
|
|
993
|
+
* @returns {{ eliminados: number, lenguajes: string[] }}
|
|
994
|
+
*/
|
|
995
|
+
function limpiarReglasSinStack(dirReglas, stackDetectado) {
|
|
996
|
+
const { LENGUAJES_CONOCIDOS } = require('./lib/detectar-stack');
|
|
997
|
+
const lenguajesEliminados = [];
|
|
998
|
+
|
|
999
|
+
if (!fs.existsSync(dirReglas)) {
|
|
1000
|
+
return { eliminados: 0, lenguajes: [] };
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
let entradas;
|
|
1004
|
+
try {
|
|
1005
|
+
entradas = fs.readdirSync(dirReglas, { withFileTypes: true });
|
|
1006
|
+
} catch {
|
|
1007
|
+
return { eliminados: 0, lenguajes: [] };
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
for (const entrada of entradas) {
|
|
1011
|
+
if (!entrada.isDirectory()) continue;
|
|
1012
|
+
|
|
1013
|
+
const lang = entrada.name;
|
|
1014
|
+
// Solo actuar sobre subdirectorios que son lenguajes conocidos del sistema
|
|
1015
|
+
if (!LENGUAJES_CONOCIDOS.has(lang)) continue;
|
|
1016
|
+
// Si el lenguaje está en el stack detectado, conservar
|
|
1017
|
+
if (stackDetectado.has(lang)) continue;
|
|
1018
|
+
|
|
1019
|
+
const dirLang = path.join(dirReglas, lang);
|
|
1020
|
+
try {
|
|
1021
|
+
fs.rmSync(dirLang, { recursive: true, force: true });
|
|
1022
|
+
lenguajesEliminados.push(lang);
|
|
1023
|
+
} catch (err) {
|
|
1024
|
+
console.log(` ! No se pudo eliminar ${dirLang}: ${err.message}`);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
return { eliminados: lenguajesEliminados.length, lenguajes: lenguajesEliminados.sort() };
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
module.exports = install;
|