@saulwade/swl-ses 2.6.0 → 2.8.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 +209 -197
- package/README.md +647 -600
- package/agentes/accesibilidad-wcag-swl.md +690 -690
- package/agentes/arquitecto-swl.md +267 -267
- package/agentes/auto-evolucion-swl.md +932 -932
- package/agentes/backend-csharp-swl.md +420 -420
- package/agentes/backend-go-swl.md +390 -390
- package/agentes/backend-java-swl.md +281 -281
- package/agentes/backend-rust-swl.md +364 -364
- package/agentes/backend-workers-swl.md +482 -482
- package/agentes/cloud-infra-swl.md +509 -509
- package/agentes/consolidador-swl.md +541 -541
- package/agentes/depurador-swl.md +352 -352
- package/agentes/devops-ci-swl.md +400 -400
- package/agentes/disenador-ui-swl.md +569 -569
- package/agentes/documentador-swl.md +345 -345
- package/agentes/frontend-angular-swl.md +621 -621
- package/agentes/frontend-css-swl.md +716 -716
- package/agentes/frontend-react-swl.md +692 -692
- package/agentes/frontend-swl.md +496 -496
- package/agentes/frontend-tailwind-swl.md +826 -826
- package/agentes/investigador-swl.md +432 -432
- package/agentes/investigador-ux-swl.md +505 -505
- package/agentes/migrador-swl.md +442 -442
- package/agentes/mobile-android-swl.md +511 -511
- package/agentes/mobile-cross-swl.md +541 -541
- package/agentes/mobile-ios-swl.md +502 -502
- package/agentes/mobile-testing-swl.md +302 -302
- package/agentes/nemesis-auditor-swl.md +285 -285
- package/agentes/observabilidad-swl.md +438 -438
- package/agentes/pagos-swl.md +310 -310
- package/agentes/perfilador-usuario-swl.md +321 -321
- package/agentes/planificador-swl.md +399 -399
- package/agentes/producto-prd-swl.md +589 -589
- package/agentes/red-team-swl.md +218 -218
- package/agentes/release-manager-swl.md +590 -590
- package/agentes/rendimiento-swl.md +713 -713
- package/agentes/revisor-angular-swl.md +278 -278
- package/agentes/revisor-csharp-swl.md +264 -264
- package/agentes/revisor-go-swl.md +259 -259
- package/agentes/revisor-java-swl.md +257 -257
- package/agentes/revisor-kotlin-swl.md +273 -273
- package/agentes/revisor-nextjs-swl.md +281 -281
- package/agentes/revisor-php-swl.md +271 -271
- package/agentes/revisor-react-swl.md +278 -278
- package/agentes/revisor-rust-swl.md +346 -346
- package/agentes/revisor-seguridad-swl.md +399 -399
- package/agentes/revisor-swift-swl.md +268 -268
- package/agentes/revisor-typescript-swl.md +346 -346
- package/agentes/tdd-qa-swl.md +393 -393
- package/bin/swl-ses.js +10 -0
- package/comandos/swl/actualizar.md +174 -174
- package/comandos/swl/adoptar-proyecto.md +265 -265
- package/comandos/swl/aprender.md +836 -836
- package/comandos/swl/aprobar-plan.md +146 -146
- package/comandos/swl/auditar-deps.md +134 -134
- package/comandos/swl/autoresearch.md +264 -264
- package/comandos/swl/ayuda.md +224 -224
- package/comandos/swl/brainstorm.md +52 -51
- package/comandos/swl/checkpoint.md +325 -325
- package/comandos/swl/claudemd.md +234 -234
- package/comandos/swl/compactar.md +310 -310
- package/comandos/swl/configurar-ci.md +235 -235
- package/comandos/swl/contexto.md +110 -110
- package/comandos/swl/crear-skill.md +292 -292
- package/comandos/swl/cron.md +194 -194
- package/comandos/swl/deuda-codigo.md +97 -97
- package/comandos/swl/discutir-fase.md +169 -169
- package/comandos/swl/ejecutar-fase.md +233 -233
- package/comandos/swl/evaluar-skill.md +520 -520
- package/comandos/swl/evolucion-continua.md +73 -73
- package/comandos/swl/evolucionar.md +267 -267
- package/comandos/swl/exportar-vault.md +583 -583
- package/comandos/swl/fix.md +118 -118
- package/comandos/swl/gateway.md +158 -158
- package/comandos/swl/inbox.md +116 -116
- package/comandos/swl/instalar.md +220 -220
- package/comandos/swl/instintos.md +86 -86
- package/comandos/swl/mapear-codebase.md +312 -312
- package/comandos/swl/mcp-status.md +176 -175
- package/comandos/swl/modelo.md +100 -100
- package/comandos/swl/nemesis.md +433 -433
- package/comandos/swl/notificaciones.md +299 -299
- package/comandos/swl/nuevo-proyecto.md +251 -251
- package/comandos/swl/planear-fase.md +263 -263
- package/comandos/swl/plugins.md +256 -256
- package/comandos/swl/predecir.md +169 -169
- package/comandos/swl/reflect-skills.md +125 -125
- package/comandos/swl/release.md +450 -450
- package/comandos/swl/revisar-impacto.md +201 -201
- package/comandos/swl/revisar.md +330 -330
- package/comandos/swl/seguridad.md +189 -189
- package/comandos/swl/sesiones.md +200 -200
- package/comandos/swl/skill-search.md +113 -113
- package/comandos/swl/status.md +345 -345
- package/comandos/swl/verificar.md +817 -817
- package/comandos/swl/wiki.md +620 -620
- package/gateway/cron/jobs.example.json +12 -12
- package/gateway/lib/event-channel.js +191 -191
- package/habilidades/agent-deep-links/SKILL.md +148 -148
- package/habilidades/auto-evolucion-protocolo/SKILL.md +294 -294
- package/habilidades/backend-async-postgres-testing/SKILL.md +216 -215
- package/habilidades/backend-error-design/SKILL.md +221 -221
- package/habilidades/backend-production-resilience/SKILL.md +288 -288
- package/habilidades/calidad-anti-patrones-universales/SKILL.md +105 -1
- package/habilidades/calidad-contract-testing/SKILL.md +165 -165
- package/habilidades/calidad-mutation-testing/SKILL.md +25 -1
- package/habilidades/changelog-generator/SKILL.md +174 -174
- package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -60
- package/habilidades/ci-cd-pipelines/SKILL.md +5 -1
- package/habilidades/compactacion-contexto/SKILL.md +2 -1
- package/habilidades/contenedores-docker/SKILL.md +4 -2
- package/habilidades/css-moderno/SKILL.md +7 -1
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/doubt-driven-review/SKILL.md +207 -207
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/drift-detection/SKILL.md +1 -1
- package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -57
- package/habilidades/extractor-de-aprendizajes/SKILL.md +12 -2
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
- package/habilidades/git-worktrees-paralelo/SKILL.md +19 -1
- package/habilidades/harness-claude-code/SKILL.md +315 -314
- package/habilidades/instalar-sistema/SKILL.md +227 -227
- package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
- package/habilidades/perfil-usuario/SKILL.md +200 -200
- package/habilidades/planear-fase/SKILL.md +358 -358
- package/habilidades/prevencion-sobreingenieria/recursos/EXAMPLES.md +580 -580
- package/habilidades/proceso-ddia-streaming/SKILL.md +231 -231
- package/habilidades/proceso-discovery-machote/SKILL.md +157 -157
- package/habilidades/proceso-dynamic-workflows/SKILL.md +60 -0
- package/habilidades/proceso-dynamic-workflows/recursos/template-adversarial-verify.js +65 -65
- package/habilidades/proceso-dynamic-workflows/recursos/template-triage.js +65 -65
- package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -147
- package/habilidades/proceso-intent-engineering/SKILL.md +269 -269
- package/habilidades/proceso-modular-split/SKILL.md +256 -256
- package/habilidades/release-semver/SKILL.md +2 -2
- package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
- package/habilidades/swl-claudemd/recursos/contrato-aprender.md +83 -83
- package/habilidades/swl-claudemd/recursos/duplicacion-reglas-globales.md +85 -85
- package/habilidades/swl-claudemd/recursos/plantillas-init.md +94 -94
- package/habilidades/tdd-workflow/SKILL.md +749 -749
- package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -111
- package/hooks/agente-lifecycle.js +1 -1
- package/hooks/audit-trail.js +1 -1
- package/hooks/auto-consolidacion.js +1 -1
- package/hooks/calidad-pre-commit.js +159 -10
- package/hooks/captura-acciones-post.js +1 -1
- package/hooks/captura-acciones-session.js +1 -1
- package/hooks/captura-feedback-usuario.js +1 -1
- package/hooks/ciclo-evolucion-subagente.js +26 -26
- package/hooks/ciclo-evolucion.js +26 -26
- package/hooks/contexto-iteracion.js +1 -1
- package/hooks/degradacion-instintos.js +1 -1
- package/hooks/grafo-contexto.js +1 -1
- package/hooks/guardrail-modelo.js +1 -1
- package/hooks/inbox-aviso.js +1 -1
- package/hooks/inyeccion-contexto.js +1 -1
- package/hooks/lib/agent-matcher.js +1 -1
- package/hooks/lib/agent-routing.js +1 -1
- package/hooks/lib/auto-consolidator.js +335 -335
- package/hooks/lib/captura-acciones.js +1 -1
- package/hooks/lib/ciclo-evolucion.js +47 -47
- package/hooks/lib/deep-links.js +185 -185
- package/hooks/lib/error-classifier.js +308 -308
- package/hooks/lib/etapa-metricas.js +1 -1
- package/hooks/lib/evolution-tracker.js +1 -1
- package/hooks/lib/gateway-notify.js +193 -193
- package/hooks/lib/mcp-health.js +1 -1
- package/hooks/lib/notificacion-formato.js +92 -0
- package/hooks/lib/nudge-tracker.js +1 -1
- package/hooks/lib/otlp-exporter.js +1 -1
- package/hooks/lib/propose-step.js +1 -1
- package/hooks/lib/provenance-tracker.js +191 -191
- package/hooks/lib/raiz-proyecto.js +158 -102
- package/hooks/lib/resource-quota.js +122 -122
- package/hooks/lib/retry-jitter.js +165 -165
- package/hooks/lib/run-log.js +1 -1
- package/hooks/lib/security-net.js +201 -201
- package/hooks/lib/singleton-guard.js +20 -13
- package/hooks/lib/skill-auditor.js +588 -588
- package/hooks/lib/sync-status.js +228 -228
- package/hooks/lib/taint-tracker.js +107 -107
- package/hooks/lib/telegram-cliente.js +11 -3
- package/hooks/lib/text-similarity.js +241 -241
- package/hooks/lib/toon-compressor.js +245 -245
- package/hooks/notificacion-telegram.js +17 -13
- package/hooks/preservar-estado-pre-compact.js +1 -1
- package/hooks/registro-turnos.js +1 -1
- package/hooks/resumen-sesion.js +1 -1
- package/hooks/risk-scoring.js +1 -1
- package/hooks/session-briefing.js +13 -5
- package/hooks/spec-gate.js +1 -1
- package/hooks/sugerir-regenerar-inventario.js +1 -1
- package/hooks/tdd-gate.js +1 -1
- package/hooks/telemetria-agentes.js +1 -1
- package/hooks/telemetria-skill-routing.js +1 -1
- package/hooks/tracking-costos.js +1 -1
- package/hooks/validar-formato-post-subagente.js +1 -1
- package/hooks/validar-intent-spec.js +1 -1
- package/hooks/validar-planning-paths.js +1 -1
- package/instintos/autonomia.yaml +27 -27
- package/instintos/prompt-appendices.yaml +57 -57
- package/llms.txt +29 -29
- package/manifiestos/agent-output-schemas.json +57 -57
- package/manifiestos/canonical-hashes.json +6250 -5257
- package/manifiestos/harness-ir.json +47536 -0
- package/manifiestos/modulos.json +1429 -1428
- package/manifiestos/policy-bundle.json +2065 -0
- package/manifiestos/policy-corpus-w2.json +3926 -0
- package/manifiestos/runtime-adapters-core3.json +208 -0
- package/manifiestos/runtime-conformance.json +139 -0
- package/manifiestos/skills-lock.json +1275 -1275
- package/package.json +94 -94
- package/plantillas/auditor-veto-template.md +105 -105
- package/plantillas/github-workflows/release-please.yml +44 -44
- package/plantillas/github-workflows/swl-ci.yml +107 -107
- package/plantillas/github-workflows/swl-security.yml +51 -51
- package/plugin.json +369 -369
- package/reglas/accesibilidad.md +10 -10
- package/reglas/auditorias-documentales-estructurales.md +7 -7
- package/reglas/cloud-infra.md +8 -8
- package/reglas/consultar-vault-primero.md +195 -195
- package/reglas/git-workflow.md +1 -0
- package/reglas/hooks.md +6 -6
- package/reglas/intent-engineering.md +218 -218
- package/reglas/markitdown.md +8 -8
- package/reglas/monitor-ci.md +12 -0
- package/reglas/patrones.md +6 -6
- package/reglas/testing.md +7 -7
- package/reglas/tests-cleanup.md +224 -224
- package/schemas/agent-message.schema.json +73 -73
- package/schemas/agent-output-implementacion.schema.json +114 -114
- package/schemas/agent-output-planificacion.schema.json +150 -150
- package/schemas/agent-output-review.schema.json +98 -98
- package/schemas/diary-entry.schema.json +112 -112
- package/schemas/gate-state.schema.json +76 -0
- package/schemas/harness-ir.schema.json +369 -0
- package/schemas/hook-profiles.schema.json +54 -54
- package/schemas/hooks-config.schema.json +89 -89
- package/schemas/legacy-gates.schema.json +45 -0
- package/schemas/modulos.schema.json +38 -38
- package/schemas/perfiles.schema.json +36 -36
- package/schemas/plugin.schema.json +77 -77
- package/schemas/policy-bundle.schema.json +140 -0
- package/schemas/policy-enforcement.schema.json +117 -0
- package/schemas/policy-operation.schema.json +261 -0
- package/schemas/runtime-adapter.schema.json +176 -0
- package/schemas/runtime-build-attestation.schema.json +100 -0
- package/schemas/runtime-conformance.schema.json +239 -0
- package/schemas/runtime-diagnostic.schema.json +395 -0
- package/schemas/skill-evals.schema.json +119 -119
- package/schemas/skill-frontmatter.schema.json +245 -245
- package/schemas/w4-certification-request.schema.json +72 -0
- package/schemas/w4-certification-verdict.schema.json +224 -0
- package/schemas/w4-corpus.schema.json +172 -0
- package/schemas/w4-mutation-report.schema.json +116 -0
- package/schemas/w4-replay-result.schema.json +164 -0
- package/schemas/w4-scoring-report.schema.json +89 -0
- package/scripts/audit-tools/audit-history.js +330 -330
- package/scripts/audit-tools/bundle-tracker.js +290 -290
- package/scripts/audit-tools/canary-monitor.js +352 -352
- package/scripts/audit-tools/code-profiler.js +605 -605
- package/scripts/audit-tools/dep-doctor.js +320 -320
- package/scripts/audit-tools/env-validator.js +206 -206
- package/scripts/audit-tools/lib/fs-walk.js +48 -48
- package/scripts/audit-tools/lib/output.js +23 -23
- package/scripts/audit-tools/migration-checker.js +392 -392
- package/scripts/audit-tools/pentest-scanner.js +1436 -1436
- package/scripts/auditar-clases-conocidas.js +134 -134
- package/scripts/bootstrap-instintos.js +88 -14
- package/scripts/canario-hooks.js +166 -166
- package/scripts/cli/aprobar-plan.js +73 -73
- package/scripts/cli/autonomia.js +23 -23
- package/scripts/cli/benchmark-memoria.js +37 -37
- package/scripts/cli/briefing.js +23 -23
- package/scripts/cli/ciclo-autonomo.js +73 -73
- package/scripts/cli/ciclo-evolucion.js +26 -26
- package/scripts/cli/ciclo-fase-b.js +102 -102
- package/scripts/cli/derivar-feature-list.js +25 -25
- package/scripts/cli/detectar-host.js +27 -27
- package/scripts/cli/diary-entry.js +69 -69
- package/scripts/cli/execution-state.js +18 -18
- package/scripts/cli/gateway-notify.js +41 -41
- package/scripts/cli/guardrail-metrics.js +39 -39
- package/scripts/cli/liberar-fase.js +42 -42
- package/scripts/cli/mark-evolved.js +56 -56
- package/scripts/cli/memoria-search.js +69 -69
- package/scripts/cli/metricas-dora.js +26 -26
- package/scripts/cli/near-duplicate.js +55 -55
- package/scripts/cli/notificaciones.js +123 -123
- package/scripts/cli/nudge-accionar.js +39 -39
- package/scripts/cli/propose-step.js +29 -29
- package/scripts/cli/run-eval.js +38 -38
- package/scripts/cli/schedule-parse.js +19 -19
- package/scripts/cli/sugerir-modelo.js +20 -20
- package/scripts/cli/verificar-plan.js +36 -36
- package/scripts/cli/verificar-trazabilidad.js +35 -35
- package/scripts/comandos/install-asistido.js +8 -7
- package/scripts/configurar-branch-protection.js +418 -418
- package/scripts/detectar-aprendizajes-duplicados.js +151 -151
- package/scripts/doctor.js +61 -13
- package/scripts/evidencia-valor.js +101 -101
- package/scripts/field-report.js +16 -16
- package/scripts/generar-checklists-consolidados.js +273 -273
- package/scripts/generar-claims-runtime.js +1342 -0
- package/scripts/generar-harness-ir.js +257 -0
- package/scripts/generar-inventario.js +52 -54
- package/scripts/generar-policy-bundle.js +202 -0
- package/scripts/instalador.js +39 -7
- package/scripts/lib/activar-hooks-proyecto.js +116 -116
- package/scripts/lib/approval-receipts.js +190 -0
- package/scripts/lib/artefactos-python.js +43 -43
- package/scripts/lib/benchmark-metrics.js +160 -160
- package/scripts/lib/budget-enforcer.js +252 -252
- package/scripts/lib/certificacion-loop-state.js +421 -0
- package/scripts/lib/ci-reader.js +193 -193
- package/scripts/lib/ciclo-autonomo/candidatos.js +174 -174
- package/scripts/lib/ciclo-autonomo/config.js +165 -165
- package/scripts/lib/ciclo-autonomo/drenador-feedback.js +174 -174
- package/scripts/lib/ciclo-autonomo/fallback.js +77 -77
- package/scripts/lib/ciclo-autonomo/guard-convivencia.js +139 -139
- package/scripts/lib/ciclo-autonomo/higiene-nudges.js +112 -112
- package/scripts/lib/ciclo-autonomo/index.js +301 -301
- package/scripts/lib/ciclo-autonomo/lock.js +124 -124
- package/scripts/lib/ciclo-autonomo/presupuesto.js +122 -122
- package/scripts/lib/ciclo-autonomo/puente-degradacion.js +240 -240
- package/scripts/lib/ciclo-autonomo/runner-fase-b.js +248 -248
- package/scripts/lib/ciclo-autonomo/writer-instintos.js +190 -190
- package/scripts/lib/ciclo-autonomo/yaml-instintos.js +591 -535
- package/scripts/lib/clasificar-directorio.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -217
- package/scripts/lib/detectar-host-swl.js +175 -175
- package/scripts/lib/detectar-runtime.js +29 -20
- package/scripts/lib/detectar-stack-detallado.js +307 -307
- package/scripts/lib/detector-autoduplicacion-intra-archivo.js +234 -234
- package/scripts/lib/detector-reglas-duplicadas.js +220 -220
- package/scripts/lib/eval-metrics-store.js +218 -218
- package/scripts/lib/eval-quality.js +171 -171
- package/scripts/lib/eval-schemas.js +144 -144
- package/scripts/lib/eval-self-correct.js +106 -106
- package/scripts/lib/eval-validator.js +185 -185
- package/scripts/lib/evidence-verifier.js +192 -0
- package/scripts/lib/evidencia-release.js +322 -322
- package/scripts/lib/evidencia-valor.js +228 -228
- package/scripts/lib/expandir-targets.js +71 -71
- package/scripts/lib/frontmatter-canonico.js +509 -0
- package/scripts/lib/gate-engine.js +871 -0
- package/scripts/lib/gate-hooks-requires.js +249 -249
- package/scripts/lib/gate-licencias.js +212 -212
- package/scripts/lib/git-config-preflight.js +48 -0
- package/scripts/lib/git-metricas.js +257 -257
- package/scripts/lib/harness-ir.js +778 -0
- package/scripts/lib/harness-source-snapshot.js +309 -0
- package/scripts/lib/integrity-ledger.js +1147 -0
- package/scripts/lib/jaccard-similarity.js +98 -98
- package/scripts/lib/legacy-gate-migration.js +324 -0
- package/scripts/lib/limpiar-basura-global.js +204 -0
- package/scripts/lib/longmemeval-runner.js +125 -125
- package/scripts/lib/metricas-dora.js +204 -204
- package/scripts/lib/notificaciones-telegram.js +1 -0
- package/scripts/lib/npm-version.js +1 -0
- package/scripts/lib/paquetes-conocidos.js +50 -50
- package/scripts/lib/plan-lock.js +61 -13
- package/scripts/lib/policy-broker.js +338 -0
- package/scripts/lib/policy-bundle.js +342 -0
- package/scripts/lib/policy-context-provider.js +310 -0
- package/scripts/lib/policy-contract.js +479 -0
- package/scripts/lib/policy-verifier-utils.js +65 -0
- package/scripts/lib/pr-analyzer.js +399 -399
- package/scripts/lib/principal-verifier.js +178 -0
- package/scripts/lib/prompt-builder.js +264 -264
- package/scripts/lib/resolver-plan-fase.js +37 -37
- package/scripts/lib/rrf-fusion.js +175 -175
- package/scripts/lib/runtime-adapter-contract.js +267 -0
- package/scripts/lib/runtime-artifact-verifier.js +426 -0
- package/scripts/lib/runtime-build-attestation.js +127 -0
- package/scripts/lib/runtime-bundle-installer.js +586 -0
- package/scripts/lib/runtime-compiler.js +327 -0
- package/scripts/lib/runtime-conformance.js +202 -0
- package/scripts/lib/runtime-doctor-core3.js +567 -0
- package/scripts/lib/runtime-doctor-input.js +59 -0
- package/scripts/lib/runtime-operation-adapter.js +267 -0
- package/scripts/lib/schema-version.js +164 -164
- package/scripts/lib/semantic-search.js +252 -252
- package/scripts/lib/signed-envelope.js +545 -0
- package/scripts/lib/single-use-store.js +359 -0
- package/scripts/lib/skills-externas.js +31 -0
- package/scripts/lib/toml-merge.js +204 -204
- package/scripts/lib/transformadores/codex.js +15 -8
- package/scripts/lib/transformadores/gemini.js +79 -5
- package/scripts/lib/w4-attestation-adapter.js +158 -0
- package/scripts/lib/w4-canario.js +337 -0
- package/scripts/lib/w4-claims.js +182 -0
- package/scripts/lib/w4-corpus-generador.js +542 -0
- package/scripts/lib/w4-gate-c5.js +115 -0
- package/scripts/lib/w4-harness-bajo-prueba.js +155 -0
- package/scripts/lib/w4-matriz-combos.js +55 -0
- package/scripts/lib/w4-motor-mutacion.js +1348 -0
- package/scripts/lib/w4-motor-replay.js +735 -0
- package/scripts/lib/w4-pin-origen.js +54 -0
- package/scripts/lib/w4-publicar-request.js +132 -0
- package/scripts/lib/w4-revocacion.js +62 -0
- package/scripts/lib/w4-runtimes-core3.js +38 -0
- package/scripts/lib/w4-scorer-certificacion.js +692 -0
- package/scripts/lib/w4-superficie-candidato.js +49 -0
- package/scripts/lib/w4-veredicto.js +452 -0
- package/scripts/lib/w4-verificar-veredicto.js +302 -0
- package/scripts/limpiar-artefactos-python.js +131 -131
- package/scripts/mcp-server/auth.js +105 -105
- package/scripts/mcp-server/cache.js +106 -106
- package/scripts/migrar-csv-a-array.js +168 -168
- package/scripts/migrar-fase-dominio.js +200 -200
- package/scripts/migrar-gates-legacy.js +108 -0
- package/scripts/publicar-certification-request.js +115 -0
- package/scripts/runtime-doctor.js +107 -0
- package/scripts/tui/componentes/selector-multi.js +189 -189
- package/scripts/tui/componentes/selector-unico.js +158 -158
- package/scripts/tui/ejecutores.js +375 -375
- package/scripts/tui/lib/colores.js +129 -129
- package/scripts/tui/lib/render.js +264 -264
- package/scripts/tui/lib/teclas.js +113 -113
- package/scripts/tui/pantallas/install-wizard.js +408 -403
- package/scripts/tui/pantallas/menu-principal.js +52 -52
- package/scripts/tui/pantallas/progreso.js +274 -274
- package/scripts/tui/pantallas/resumen.js +132 -132
- package/scripts/validar-userland-vacio.js +110 -110
- package/scripts/verificar-aislamiento-swl-eval.js +87 -0
- package/scripts/verificar-empaquetado-downstream.js +375 -0
- package/scripts/verificar-loop-constructor.js +215 -0
- package/scripts/verificar-trazabilidad.js +13 -6
- package/scripts/verificar-veredicto-real.js +84 -0
- package/instintos/.backups/perfil-usuario.yaml.2026-07-10-165128.bak +0 -53
- package/instintos/.backups/proyecto.yaml.2026-07-10-165128.bak +0 -372
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Verificador del `CertificationVerdict` (ADR-0053 § Decisión pieza 5, F32/T-06,
|
|
5
|
+
* REQ-32-06). Núcleo PURO con el puerto de attestation INYECTADO
|
|
6
|
+
* (`attestationVerifier`) — este módulo nunca invoca `gh`, nunca hace red ni
|
|
7
|
+
* filesystem por su cuenta; el adaptador real de `gh attestation verify`
|
|
8
|
+
* origin-pinned es T-09 (fuera del alcance de esta tarea).
|
|
9
|
+
*
|
|
10
|
+
* C3a — honestidad del modo dev (ADR-0053 § Honestidad del red-team, C6): en
|
|
11
|
+
* F32/T-06 este verificador SÓLO puede ejercitarse contra un
|
|
12
|
+
* `attestationVerifier` SIMULADO (un stub de test, nunca `gh` real). Ningún
|
|
13
|
+
* resultado `{ok:true}` producido con un stub constituye "origen verificado"
|
|
14
|
+
* en el sentido de ADR-0053 — esa garantía exige el adaptador real de T-09,
|
|
15
|
+
* el environment protegido `certificacion` y el resto del provisioning
|
|
16
|
+
* humano (H-3/H-4/H-6/H-7/H-10). El propio veredicto lo declara: en modo
|
|
17
|
+
* dev, `firma.dev.nota` (constante fija, validada por
|
|
18
|
+
* `w4-veredicto.js#validateCertificationVerdict`) dice explícitamente
|
|
19
|
+
* "verificador dev, adaptador de attestation simulado" — y este verificador
|
|
20
|
+
* NUNCA certifica un veredicto dev (`VERDICT_DEV_NO_CERTIFICANTE`),
|
|
21
|
+
* cualquiera sea el resultado del puerto.
|
|
22
|
+
*
|
|
23
|
+
* Solo lectura: nunca muta `verdict`. Nunca lanza — todo camino de error
|
|
24
|
+
* retorna `{ ok:false, codigo }` (fail-closed en cada borde, incluyendo
|
|
25
|
+
* cualquier excepción del puerto inyectado — C4).
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
const crypto = require('node:crypto');
|
|
29
|
+
|
|
30
|
+
const { validateCertificationVerdict } = require('./w4-veredicto');
|
|
31
|
+
const { canonicalizarIJson } = require('./signed-envelope');
|
|
32
|
+
|
|
33
|
+
const MAX_BUNDLE_BYTES = 8 * 1024 * 1024;
|
|
34
|
+
|
|
35
|
+
const CODIGOS = Object.freeze({
|
|
36
|
+
MALFORMED: 'VERDICT_MALFORMED',
|
|
37
|
+
REQUEST_REQUIRED: 'VERDICT_REQUEST_REQUIRED',
|
|
38
|
+
REQUEST_MISMATCH: 'VERDICT_REQUEST_MISMATCH',
|
|
39
|
+
DEV_NO_CERTIFICANTE: 'VERDICT_DEV_NO_CERTIFICANTE',
|
|
40
|
+
SIGNATURE_INVALID: 'VERDICT_SIGNATURE_INVALID',
|
|
41
|
+
ORIGIN_MISMATCH: 'VERDICT_ORIGIN_MISMATCH',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
function esObjetoPlano(valor) {
|
|
45
|
+
return Boolean(valor) && typeof valor === 'object' && !Array.isArray(valor)
|
|
46
|
+
&& Object.getPrototypeOf(valor) === Object.prototype
|
|
47
|
+
&& Object.getOwnPropertySymbols(valor).length === 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function congelarProfundo(valor) {
|
|
51
|
+
if (valor && typeof valor === 'object' && !Object.isFrozen(valor)) {
|
|
52
|
+
Object.values(valor).forEach(congelarProfundo);
|
|
53
|
+
Object.freeze(valor);
|
|
54
|
+
}
|
|
55
|
+
return valor;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function rechazo(codigo) {
|
|
59
|
+
return Object.freeze({ ok: false, codigo });
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function clavesExactas(valor, esperadas) {
|
|
63
|
+
return esObjetoPlano(valor)
|
|
64
|
+
&& JSON.stringify(Object.keys(valor).sort()) === JSON.stringify([...esperadas].sort());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// C2 — anti-replay: requestEsperado es obligatorio, comparación exacta.
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
|
|
71
|
+
// Defensa en profundidad deliberadamente redundante: `runtime`/`os`/`model`
|
|
72
|
+
// (vía w4-veredicto.js#validarMatrixEntry, enum + `IDENTIFICADOR` ASCII) y
|
|
73
|
+
// `commit`/`tarballDigest` (hex ASCII) ya restringen estos campos a ASCII
|
|
74
|
+
// antes de llegar aquí, así que hoy ningún valor real requiere normalización
|
|
75
|
+
// NFKC. Se conserva porque es barata (una llamada nativa por campo) y actúa
|
|
76
|
+
// como anti-regresión: si el validador upstream (`validarRequestEsperadoShape`
|
|
77
|
+
// / `validateCertificationVerdict`) alguna vez se relaja a Unicode más amplio,
|
|
78
|
+
// esta normalización sigue cerrando el vector de confusión NFKC sin requerir
|
|
79
|
+
// un cambio coordinado en este módulo.
|
|
80
|
+
function normalizarNFKC(valor) {
|
|
81
|
+
return typeof valor === 'string' ? valor.normalize('NFKC') : valor;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function validarRequestEsperadoShape(valor) {
|
|
85
|
+
if (!clavesExactas(valor, ['commit', 'tarballDigest', 'matrix'])) return false;
|
|
86
|
+
if (typeof valor.commit !== 'string' || typeof valor.tarballDigest !== 'string') return false;
|
|
87
|
+
if (!Array.isArray(valor.matrix) || valor.matrix.length === 0) return false;
|
|
88
|
+
return valor.matrix.every((entrada) => (
|
|
89
|
+
clavesExactas(entrada, ['runtime', 'os', 'model'])
|
|
90
|
+
&& typeof entrada.runtime === 'string' && typeof entrada.os === 'string' && typeof entrada.model === 'string'
|
|
91
|
+
));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function claveMatrixEntry(entrada) {
|
|
95
|
+
return `${normalizarNFKC(entrada.runtime)}|${normalizarNFKC(entrada.os)}|${normalizarNFKC(entrada.model)}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Comparación EXACTA (C2) de `verdict.request` contra `requestEsperado`, con
|
|
100
|
+
* normalización NFKC por campo — el arreglo `matrix` se compara como
|
|
101
|
+
* multiconjunto (el orden de las entradas nunca es información de
|
|
102
|
+
* seguridad); cualquier entrada distinta, faltante o sobrante rechaza.
|
|
103
|
+
*/
|
|
104
|
+
function coincideRequest(verdictRequest, requestEsperado) {
|
|
105
|
+
if (normalizarNFKC(verdictRequest.commit) !== normalizarNFKC(requestEsperado.commit)) return false;
|
|
106
|
+
if (normalizarNFKC(verdictRequest.tarballDigest) !== normalizarNFKC(requestEsperado.tarballDigest)) return false;
|
|
107
|
+
if (verdictRequest.matrix.length !== requestEsperado.matrix.length) return false;
|
|
108
|
+
const propias = verdictRequest.matrix.map(claveMatrixEntry).sort();
|
|
109
|
+
const esperadas = requestEsperado.matrix.map(claveMatrixEntry).sort();
|
|
110
|
+
return JSON.stringify(propias) === JSON.stringify(esperadas);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// C1 — binding firma <-> payload: el núcleo calcula el digest esperado.
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* `sha256(canonicalizarIJson(verdict SIN el bloque 'firma')))` — puro,
|
|
119
|
+
* independientemente testeable (C1: "la comparación vive en el core
|
|
120
|
+
* testeable"). Excluir `firma` es deliberado: el digest identifica el
|
|
121
|
+
* CONTENIDO atestiguado, no la firma misma (que se añade después de
|
|
122
|
+
* calcular el digest, en el flujo real de `gh attestation sign`).
|
|
123
|
+
*/
|
|
124
|
+
function sha256Utf8(texto) {
|
|
125
|
+
return crypto.createHash('sha256').update(texto, 'utf8').digest('hex');
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function bytesVerdictSinFirma(verdict) {
|
|
129
|
+
const { firma, ...sinFirma } = verdict;
|
|
130
|
+
void firma;
|
|
131
|
+
return canonicalizarIJson(sinFirma);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function digestVerdictSinFirma(verdict) {
|
|
135
|
+
return sha256Utf8(bytesVerdictSinFirma(verdict));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// C3/C4 — contrato documentado del adaptador real + fail-closed en su salida.
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Contrato documentado del adaptador REAL de `gh attestation verify`
|
|
144
|
+
* (T-09, NO ejecutado en F32/T-06 — este módulo sólo recibe el puerto
|
|
145
|
+
* inyectado). Entrada, tres argumentos (ADR-0056):
|
|
146
|
+
* `(bundle: Buffer, expectedArtifactDigest: string sha256 hex,
|
|
147
|
+
* artifactBytes: string)`
|
|
148
|
+
* donde `artifactBytes` son los bytes canónicos I-JSON del veredicto SIN el
|
|
149
|
+
* bloque `firma` (los mismos cuyo sha256 es `expectedArtifactDigest`).
|
|
150
|
+
* Salida esperada, `exactKeys` estricto (C3c/C4): SIN campos adicionales,
|
|
151
|
+
* SIN tipos laxos —
|
|
152
|
+
*
|
|
153
|
+
* { identidadOIDC: { repo: string, workflow: string, ref: string },
|
|
154
|
+
* firmaValida: boolean }
|
|
155
|
+
*
|
|
156
|
+
* El `gh` real (v2.89.0, verificado en T-09) EXIGE el artefacto en disco
|
|
157
|
+
* (`gh attestation verify <file-path> --owner … --signer-workflow …`) y NO
|
|
158
|
+
* soporta un modo `--digest` de digest-desnudo; por eso el núcleo pasa los
|
|
159
|
+
* `artifactBytes`, que el adaptador escribe a un archivo temporal 0600 y
|
|
160
|
+
* entrega a `gh`. `gh` computa el sha256 del archivo y lo compara contra el
|
|
161
|
+
* sujeto atestiguado por Sigstore — así se materializa la comparación C1 en
|
|
162
|
+
* el mundo real. `expectedArtifactDigest` se pasa además como cross-check
|
|
163
|
+
* barato (el adaptador puede aseverar `sha256(artifactBytes) === expected`
|
|
164
|
+
* antes de invocar `gh`). Este verificador nunca parsea el bundle Sigstore
|
|
165
|
+
* ni toca disco/red por sí mismo (el efecto vive en el adaptador de T-09).
|
|
166
|
+
*/
|
|
167
|
+
function validarFormaSalidaAttestation(valor) {
|
|
168
|
+
if (!clavesExactas(valor, ['identidadOIDC', 'firmaValida'])) return false;
|
|
169
|
+
if (typeof valor.firmaValida !== 'boolean') return false;
|
|
170
|
+
const identidad = valor.identidadOIDC;
|
|
171
|
+
if (!clavesExactas(identidad, ['repo', 'workflow', 'ref'])) return false;
|
|
172
|
+
return typeof identidad.repo === 'string' && identidad.repo.length > 0
|
|
173
|
+
&& typeof identidad.workflow === 'string' && identidad.workflow.length > 0
|
|
174
|
+
&& typeof identidad.ref === 'string' && identidad.ref.length > 0;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Contrato de ENTRADA del adaptador real: `bundle` son bytes crudos
|
|
179
|
+
* acotados (mismo patrón fail-closed que
|
|
180
|
+
* `scripts/lib/runtime-build-attestation.js#validateRawBytes` — prototipo
|
|
181
|
+
* `Buffer`/`Uint8Array`, sin propiedades intrusas, tamaño en
|
|
182
|
+
* `(0, MAX_BUNDLE_BYTES]`). Este módulo NO parsea el bundle como I-JSON
|
|
183
|
+
* (ese formato lo define Sigstore, no ADR-0053) — sólo acota su forma antes
|
|
184
|
+
* de calcular su digest (C7) y de pasarlo al puerto.
|
|
185
|
+
*/
|
|
186
|
+
function validarBundleBytes(bundle) {
|
|
187
|
+
if (!bundle || typeof bundle !== 'object') return false;
|
|
188
|
+
const prototipo = Object.getPrototypeOf(bundle);
|
|
189
|
+
if (prototipo !== Buffer.prototype && prototipo !== Uint8Array.prototype) return false;
|
|
190
|
+
if (['buffer', 'byteOffset', 'byteLength'].some((propiedad) => Object.hasOwn(bundle, propiedad))) return false;
|
|
191
|
+
return bundle.byteLength > 0 && bundle.byteLength <= MAX_BUNDLE_BYTES;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function validarPinOrigen(valor) {
|
|
195
|
+
return clavesExactas(valor, ['repo', 'workflow', 'ref'])
|
|
196
|
+
&& typeof valor.repo === 'string' && valor.repo.length > 0
|
|
197
|
+
&& typeof valor.workflow === 'string' && valor.workflow.length > 0
|
|
198
|
+
&& typeof valor.ref === 'string' && valor.ref.length > 0;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
// verificarVeredicto — orquestador fail-closed.
|
|
203
|
+
// ---------------------------------------------------------------------------
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Verifica un `CertificationVerdict` contra el mecanismo de aislamiento de
|
|
207
|
+
* ADR-0053. Nunca lanza: retorna `{ok:false, codigo}` en cualquier borde de
|
|
208
|
+
* fallo, o `{ok:true, verdict, identidadOIDC}` (deep-frozen) sólo cuando
|
|
209
|
+
* TODAS las condiciones se cumplen — estructura válida, request coincidente
|
|
210
|
+
* (C2), modo `real` con firma protegida verificada con origen pineado
|
|
211
|
+
* (C1/C3/C4/C7). Un veredicto `modo:'dev'` NUNCA certifica, aunque esté
|
|
212
|
+
* perfectamente bien formado (C3a).
|
|
213
|
+
*
|
|
214
|
+
* @param {unknown} verdict
|
|
215
|
+
* @param {{pinOrigen: unknown, requestEsperado: unknown,
|
|
216
|
+
* attestationVerifier: (bundle: Buffer, expectedArtifactDigest: string,
|
|
217
|
+
* artifactBytes: string) => Promise<unknown> | unknown, bundle: unknown}} opciones
|
|
218
|
+
*/
|
|
219
|
+
async function verificarVeredicto(verdict, opciones) {
|
|
220
|
+
let sano;
|
|
221
|
+
try {
|
|
222
|
+
sano = validateCertificationVerdict(verdict);
|
|
223
|
+
} catch {
|
|
224
|
+
return rechazo(CODIGOS.MALFORMED);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const opcionesSanas = esObjetoPlano(opciones) ? opciones : {};
|
|
228
|
+
const { pinOrigen, requestEsperado, attestationVerifier, bundle } = opcionesSanas;
|
|
229
|
+
|
|
230
|
+
// C2: "nunca acepta sin request" — precondición incondicional, antes de
|
|
231
|
+
// ramificar por modo dev/real.
|
|
232
|
+
if (!validarRequestEsperadoShape(requestEsperado)) return rechazo(CODIGOS.REQUEST_REQUIRED);
|
|
233
|
+
if (!coincideRequest(sano.request, requestEsperado)) return rechazo(CODIGOS.REQUEST_MISMATCH);
|
|
234
|
+
|
|
235
|
+
// C6 (delegado a validateCertificationVerdict, ejecutado arriba): un
|
|
236
|
+
// veredicto dev con `firma.dev.nota` distinta del literal fijo ya fue
|
|
237
|
+
// rechazado como VERDICT_MALFORMED. Llegar aquí con modo:'dev' significa
|
|
238
|
+
// que la nota es exactamente la esperada — igual NUNCA certifica (C3a).
|
|
239
|
+
if (sano.firma.modo === 'dev') return rechazo(CODIGOS.DEV_NO_CERTIFICANTE);
|
|
240
|
+
|
|
241
|
+
// ---- Camino 'real' — bloque sigstore completo, C1/C3/C4/C7. --------------
|
|
242
|
+
|
|
243
|
+
if (typeof attestationVerifier !== 'function') return rechazo(CODIGOS.SIGNATURE_INVALID);
|
|
244
|
+
if (!validarBundleBytes(bundle)) return rechazo(CODIGOS.SIGNATURE_INVALID);
|
|
245
|
+
|
|
246
|
+
// C7: el bundle presentado en esta verificación debe ser el mismo que el
|
|
247
|
+
// veredicto declaró al emitirse — nunca invocar el puerto con un bundle
|
|
248
|
+
// sustituido después de los hechos.
|
|
249
|
+
const bundleDigest = crypto.createHash('sha256').update(bundle).digest('hex');
|
|
250
|
+
if (bundleDigest !== sano.firma.bundleDigest) return rechazo(CODIGOS.SIGNATURE_INVALID);
|
|
251
|
+
|
|
252
|
+
if (!validarPinOrigen(pinOrigen)) return rechazo(CODIGOS.SIGNATURE_INVALID);
|
|
253
|
+
|
|
254
|
+
// C1 (ADR-0056): el núcleo puro deriva del CONTENIDO del propio veredicto
|
|
255
|
+
// tanto los bytes canónicos como su digest — nunca de un valor que el caller
|
|
256
|
+
// pudiera inyectar — y ambos se pasan al puerto: el adaptador real necesita
|
|
257
|
+
// los bytes para presentarle a `gh attestation verify` el artefacto en disco
|
|
258
|
+
// (no existe modo digest-desnudo), y el digest queda como cross-check.
|
|
259
|
+
const artifactBytes = bytesVerdictSinFirma(sano);
|
|
260
|
+
const expectedArtifactDigest = sha256Utf8(artifactBytes);
|
|
261
|
+
|
|
262
|
+
let salidaCruda;
|
|
263
|
+
try {
|
|
264
|
+
salidaCruda = await attestationVerifier(bundle, expectedArtifactDigest, artifactBytes);
|
|
265
|
+
} catch {
|
|
266
|
+
// C4: cualquier excepción del puerto -> rechazo, nunca propagar.
|
|
267
|
+
return rechazo(CODIGOS.SIGNATURE_INVALID);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// C3/C4: forma exacta y tipos estrictos antes de confiar en nada de la salida.
|
|
271
|
+
if (!validarFormaSalidaAttestation(salidaCruda)) return rechazo(CODIGOS.SIGNATURE_INVALID);
|
|
272
|
+
if (salidaCruda.firmaValida !== true) return rechazo(CODIGOS.SIGNATURE_INVALID);
|
|
273
|
+
|
|
274
|
+
// Origen exacto: repo, workflow Y ref, los tres, igualdad estricta de string.
|
|
275
|
+
const { identidadOIDC } = salidaCruda;
|
|
276
|
+
if (identidadOIDC.repo !== pinOrigen.repo || identidadOIDC.workflow !== pinOrigen.workflow
|
|
277
|
+
|| identidadOIDC.ref !== pinOrigen.ref) {
|
|
278
|
+
return rechazo(CODIGOS.ORIGIN_MISMATCH);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// El veredicto es AUTÉNTICO y de ORIGEN correcto. Pero `ok:true` NO autoriza
|
|
282
|
+
// por sí solo un badge: un veredicto real de un candidato que falló los SLO
|
|
283
|
+
// trae `certifica:false`. Se expone `certifica` al tope del resultado para que
|
|
284
|
+
// el generador de claims (T-10) NUNCA pueda leer `ok` aislado — el badge exige
|
|
285
|
+
// `ok === true && certifica === true`. Ver gate W4-H (32-PLAN.md).
|
|
286
|
+
return congelarProfundo({
|
|
287
|
+
ok: true,
|
|
288
|
+
certifica: sano.certifica === true,
|
|
289
|
+
verdict: sano,
|
|
290
|
+
identidadOIDC: { ...identidadOIDC },
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
module.exports = {
|
|
295
|
+
CODIGOS,
|
|
296
|
+
MAX_BUNDLE_BYTES,
|
|
297
|
+
bytesVerdictSinFirma,
|
|
298
|
+
digestVerdictSinFirma,
|
|
299
|
+
validarBundleBytes,
|
|
300
|
+
validarFormaSalidaAttestation,
|
|
301
|
+
verificarVeredicto,
|
|
302
|
+
};
|
|
@@ -1,131 +1,131 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* limpiar-artefactos-python.js — limpia caché Python antes de empaquetar.
|
|
6
|
-
*
|
|
7
|
-
* Se ejecuta como `prepack` antes de `npm pack` y `npm publish` para evitar
|
|
8
|
-
* que artefactos locales (.pyc, __pycache__/) contaminen el tarball publicado.
|
|
9
|
-
*
|
|
10
|
-
* Reglas de seguridad (defensa en profundidad):
|
|
11
|
-
* 1. Aborta si cwd no coincide con la raíz del package.json del repo.
|
|
12
|
-
* 2. Profundidad máxima de recursión: 3 niveles desde la raíz.
|
|
13
|
-
* 3. Allowlist explícita de directorios a EXCLUIR de la búsqueda
|
|
14
|
-
* (node_modules, .git, temp, .planning, respositorios-git, _userland).
|
|
15
|
-
* 4. Solo elimina directorios cuyo nombre coincide exactamente con el
|
|
16
|
-
* conjunto cerrado: __pycache__, .pytest_cache, .mypy_cache, .ruff_cache.
|
|
17
|
-
* 5. Solo elimina archivos sueltos con extensiones .pyc, .pyo.
|
|
18
|
-
* 6. En CI no-interactivo respeta el flag SWL_PREPACK_DRY=1 (no borra,
|
|
19
|
-
* solo lista).
|
|
20
|
-
*
|
|
21
|
-
* Exit codes:
|
|
22
|
-
* 0 — OK (limpieza ejecutada o nada que limpiar)
|
|
23
|
-
* 1 — error de invariante (cwd incorrecto, package.json no encontrado)
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
const fs = require('fs');
|
|
27
|
-
const path = require('path');
|
|
28
|
-
|
|
29
|
-
const { NOMBRES_VALIDOS } = require('./lib/paquetes-conocidos');
|
|
30
|
-
const {
|
|
31
|
-
DIRS_ARTEFACTOS_PYTHON: DIRS_A_LIMPIAR,
|
|
32
|
-
EXTS_ARTEFACTOS_PYTHON: EXTS_A_LIMPIAR,
|
|
33
|
-
} = require('./lib/artefactos-python');
|
|
34
|
-
|
|
35
|
-
const PROFUNDIDAD_MAX = 3;
|
|
36
|
-
const DIRS_EXCLUIDOS = new Set([
|
|
37
|
-
'node_modules', '.git', 'temp', '.planning', 'respositorios-git',
|
|
38
|
-
'_userland', 'tests', '.github',
|
|
39
|
-
]);
|
|
40
|
-
|
|
41
|
-
const dryRun = process.env.SWL_PREPACK_DRY === '1';
|
|
42
|
-
|
|
43
|
-
function log(msg) { process.stdout.write(`[prepack] ${msg}\n`); }
|
|
44
|
-
function err(msg) { process.stderr.write(`[prepack] ERROR: ${msg}\n`); }
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Verifica que el cwd actual contiene el package.json del repo swl-ses.
|
|
48
|
-
* Esto evita que el script borre directorios en la máquina del usuario si
|
|
49
|
-
* algún día se invocara desde un cwd incorrecto (ej. dentro de un tarball
|
|
50
|
-
* extraído por npm en .npm/_cacache).
|
|
51
|
-
*/
|
|
52
|
-
function verificarRaiz() {
|
|
53
|
-
const cwd = process.cwd();
|
|
54
|
-
const pkgPath = path.join(cwd, 'package.json');
|
|
55
|
-
if (!fs.existsSync(pkgPath)) {
|
|
56
|
-
err(`no existe package.json en cwd: ${cwd}`);
|
|
57
|
-
process.exit(1);
|
|
58
|
-
}
|
|
59
|
-
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
60
|
-
if (!NOMBRES_VALIDOS.includes(pkg.name)) {
|
|
61
|
-
err(`package.json en ${cwd} no corresponde a swl-ses (name: ${pkg.name}). Abortando por seguridad.`);
|
|
62
|
-
process.exit(1);
|
|
63
|
-
}
|
|
64
|
-
return cwd;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Recorre el árbol desde root con profundidad limitada y elimina los
|
|
69
|
-
* artefactos Python detectados. No sigue symlinks.
|
|
70
|
-
*/
|
|
71
|
-
function limpiar(root, profundidad = 0) {
|
|
72
|
-
if (profundidad > PROFUNDIDAD_MAX) return { dirs: 0, files: 0 };
|
|
73
|
-
|
|
74
|
-
let dirsEliminados = 0;
|
|
75
|
-
let filesEliminados = 0;
|
|
76
|
-
|
|
77
|
-
let entries;
|
|
78
|
-
try {
|
|
79
|
-
entries = fs.readdirSync(root, { withFileTypes: true });
|
|
80
|
-
} catch (e) {
|
|
81
|
-
err(`no se pudo leer ${root}: ${e.message}`);
|
|
82
|
-
return { dirs: 0, files: 0 };
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
for (const entry of entries) {
|
|
86
|
-
if (entry.isSymbolicLink()) continue;
|
|
87
|
-
const fullPath = path.join(root, entry.name);
|
|
88
|
-
|
|
89
|
-
if (entry.isDirectory()) {
|
|
90
|
-
if (DIRS_A_LIMPIAR.has(entry.name)) {
|
|
91
|
-
if (dryRun) {
|
|
92
|
-
log(`[dry-run] borraría dir: ${path.relative(process.cwd(), fullPath)}`);
|
|
93
|
-
} else {
|
|
94
|
-
fs.rmSync(fullPath, { recursive: true, force: true });
|
|
95
|
-
log(`borrado dir: ${path.relative(process.cwd(), fullPath)}`);
|
|
96
|
-
}
|
|
97
|
-
dirsEliminados++;
|
|
98
|
-
} else if (!DIRS_EXCLUIDOS.has(entry.name) && !entry.name.startsWith('.')) {
|
|
99
|
-
const sub = limpiar(fullPath, profundidad + 1);
|
|
100
|
-
dirsEliminados += sub.dirs;
|
|
101
|
-
filesEliminados += sub.files;
|
|
102
|
-
}
|
|
103
|
-
} else if (entry.isFile()) {
|
|
104
|
-
const ext = path.extname(entry.name).toLowerCase();
|
|
105
|
-
if (EXTS_A_LIMPIAR.has(ext)) {
|
|
106
|
-
if (dryRun) {
|
|
107
|
-
log(`[dry-run] borraría archivo: ${path.relative(process.cwd(), fullPath)}`);
|
|
108
|
-
} else {
|
|
109
|
-
fs.rmSync(fullPath, { force: true });
|
|
110
|
-
}
|
|
111
|
-
filesEliminados++;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return { dirs: dirsEliminados, files: filesEliminados };
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function main() {
|
|
120
|
-
const root = verificarRaiz();
|
|
121
|
-
const result = limpiar(root);
|
|
122
|
-
|
|
123
|
-
if (result.dirs === 0 && result.files === 0) {
|
|
124
|
-
log('sin artefactos Python que limpiar.');
|
|
125
|
-
} else {
|
|
126
|
-
const accion = dryRun ? 'detectados' : 'eliminados';
|
|
127
|
-
log(`${accion}: ${result.dirs} directorios + ${result.files} archivos.`);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
main();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* limpiar-artefactos-python.js — limpia caché Python antes de empaquetar.
|
|
6
|
+
*
|
|
7
|
+
* Se ejecuta como `prepack` antes de `npm pack` y `npm publish` para evitar
|
|
8
|
+
* que artefactos locales (.pyc, __pycache__/) contaminen el tarball publicado.
|
|
9
|
+
*
|
|
10
|
+
* Reglas de seguridad (defensa en profundidad):
|
|
11
|
+
* 1. Aborta si cwd no coincide con la raíz del package.json del repo.
|
|
12
|
+
* 2. Profundidad máxima de recursión: 3 niveles desde la raíz.
|
|
13
|
+
* 3. Allowlist explícita de directorios a EXCLUIR de la búsqueda
|
|
14
|
+
* (node_modules, .git, temp, .planning, respositorios-git, _userland).
|
|
15
|
+
* 4. Solo elimina directorios cuyo nombre coincide exactamente con el
|
|
16
|
+
* conjunto cerrado: __pycache__, .pytest_cache, .mypy_cache, .ruff_cache.
|
|
17
|
+
* 5. Solo elimina archivos sueltos con extensiones .pyc, .pyo.
|
|
18
|
+
* 6. En CI no-interactivo respeta el flag SWL_PREPACK_DRY=1 (no borra,
|
|
19
|
+
* solo lista).
|
|
20
|
+
*
|
|
21
|
+
* Exit codes:
|
|
22
|
+
* 0 — OK (limpieza ejecutada o nada que limpiar)
|
|
23
|
+
* 1 — error de invariante (cwd incorrecto, package.json no encontrado)
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const fs = require('fs');
|
|
27
|
+
const path = require('path');
|
|
28
|
+
|
|
29
|
+
const { NOMBRES_VALIDOS } = require('./lib/paquetes-conocidos');
|
|
30
|
+
const {
|
|
31
|
+
DIRS_ARTEFACTOS_PYTHON: DIRS_A_LIMPIAR,
|
|
32
|
+
EXTS_ARTEFACTOS_PYTHON: EXTS_A_LIMPIAR,
|
|
33
|
+
} = require('./lib/artefactos-python');
|
|
34
|
+
|
|
35
|
+
const PROFUNDIDAD_MAX = 3;
|
|
36
|
+
const DIRS_EXCLUIDOS = new Set([
|
|
37
|
+
'node_modules', '.git', 'temp', '.planning', 'respositorios-git',
|
|
38
|
+
'_userland', 'tests', '.github',
|
|
39
|
+
]);
|
|
40
|
+
|
|
41
|
+
const dryRun = process.env.SWL_PREPACK_DRY === '1';
|
|
42
|
+
|
|
43
|
+
function log(msg) { process.stdout.write(`[prepack] ${msg}\n`); }
|
|
44
|
+
function err(msg) { process.stderr.write(`[prepack] ERROR: ${msg}\n`); }
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Verifica que el cwd actual contiene el package.json del repo swl-ses.
|
|
48
|
+
* Esto evita que el script borre directorios en la máquina del usuario si
|
|
49
|
+
* algún día se invocara desde un cwd incorrecto (ej. dentro de un tarball
|
|
50
|
+
* extraído por npm en .npm/_cacache).
|
|
51
|
+
*/
|
|
52
|
+
function verificarRaiz() {
|
|
53
|
+
const cwd = process.cwd();
|
|
54
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
55
|
+
if (!fs.existsSync(pkgPath)) {
|
|
56
|
+
err(`no existe package.json en cwd: ${cwd}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
60
|
+
if (!NOMBRES_VALIDOS.includes(pkg.name)) {
|
|
61
|
+
err(`package.json en ${cwd} no corresponde a swl-ses (name: ${pkg.name}). Abortando por seguridad.`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
return cwd;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Recorre el árbol desde root con profundidad limitada y elimina los
|
|
69
|
+
* artefactos Python detectados. No sigue symlinks.
|
|
70
|
+
*/
|
|
71
|
+
function limpiar(root, profundidad = 0) {
|
|
72
|
+
if (profundidad > PROFUNDIDAD_MAX) return { dirs: 0, files: 0 };
|
|
73
|
+
|
|
74
|
+
let dirsEliminados = 0;
|
|
75
|
+
let filesEliminados = 0;
|
|
76
|
+
|
|
77
|
+
let entries;
|
|
78
|
+
try {
|
|
79
|
+
entries = fs.readdirSync(root, { withFileTypes: true });
|
|
80
|
+
} catch (e) {
|
|
81
|
+
err(`no se pudo leer ${root}: ${e.message}`);
|
|
82
|
+
return { dirs: 0, files: 0 };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
for (const entry of entries) {
|
|
86
|
+
if (entry.isSymbolicLink()) continue;
|
|
87
|
+
const fullPath = path.join(root, entry.name);
|
|
88
|
+
|
|
89
|
+
if (entry.isDirectory()) {
|
|
90
|
+
if (DIRS_A_LIMPIAR.has(entry.name)) {
|
|
91
|
+
if (dryRun) {
|
|
92
|
+
log(`[dry-run] borraría dir: ${path.relative(process.cwd(), fullPath)}`);
|
|
93
|
+
} else {
|
|
94
|
+
fs.rmSync(fullPath, { recursive: true, force: true });
|
|
95
|
+
log(`borrado dir: ${path.relative(process.cwd(), fullPath)}`);
|
|
96
|
+
}
|
|
97
|
+
dirsEliminados++;
|
|
98
|
+
} else if (!DIRS_EXCLUIDOS.has(entry.name) && !entry.name.startsWith('.')) {
|
|
99
|
+
const sub = limpiar(fullPath, profundidad + 1);
|
|
100
|
+
dirsEliminados += sub.dirs;
|
|
101
|
+
filesEliminados += sub.files;
|
|
102
|
+
}
|
|
103
|
+
} else if (entry.isFile()) {
|
|
104
|
+
const ext = path.extname(entry.name).toLowerCase();
|
|
105
|
+
if (EXTS_A_LIMPIAR.has(ext)) {
|
|
106
|
+
if (dryRun) {
|
|
107
|
+
log(`[dry-run] borraría archivo: ${path.relative(process.cwd(), fullPath)}`);
|
|
108
|
+
} else {
|
|
109
|
+
fs.rmSync(fullPath, { force: true });
|
|
110
|
+
}
|
|
111
|
+
filesEliminados++;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return { dirs: dirsEliminados, files: filesEliminados };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function main() {
|
|
120
|
+
const root = verificarRaiz();
|
|
121
|
+
const result = limpiar(root);
|
|
122
|
+
|
|
123
|
+
if (result.dirs === 0 && result.files === 0) {
|
|
124
|
+
log('sin artefactos Python que limpiar.');
|
|
125
|
+
} else {
|
|
126
|
+
const accion = dryRun ? 'detectados' : 'eliminados';
|
|
127
|
+
log(`${accion}: ${result.dirs} directorios + ${result.files} archivos.`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
main();
|