@saulwade/swl-ses 2.3.0 → 2.4.1
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 +241 -199
- package/README.md +597 -597
- package/agentes/_intent-spec.md +73 -73
- package/agentes/_propose-step.md +90 -90
- package/agentes/accesibilidad-wcag-swl.md +2 -2
- package/agentes/arquitecto-swl.md +2 -2
- package/agentes/auto-evolucion-swl.md +2 -2
- package/agentes/backend-api-swl.md +2 -2
- package/agentes/backend-csharp-swl.md +2 -2
- package/agentes/backend-go-swl.md +2 -2
- package/agentes/backend-java-swl.md +2 -2
- package/agentes/backend-node-swl.md +2 -2
- package/agentes/backend-python-swl.md +2 -2
- package/agentes/backend-rust-swl.md +2 -2
- package/agentes/backend-workers-swl.md +2 -2
- package/agentes/cloud-infra-swl.md +2 -2
- package/agentes/consolidador-swl.md +2 -2
- package/agentes/datos-swl.md +2 -2
- package/agentes/depurador-swl.md +2 -2
- package/agentes/devops-ci-swl.md +2 -2
- package/agentes/disenador-ui-swl.md +2 -2
- package/agentes/documentador-swl.md +2 -2
- package/agentes/frontend-angular-swl.md +2 -2
- package/agentes/frontend-css-swl.md +2 -2
- package/agentes/frontend-react-swl.md +2 -2
- package/agentes/frontend-swl.md +2 -2
- package/agentes/frontend-tailwind-swl.md +2 -2
- package/agentes/gh-fix-ci-swl.md +275 -275
- package/agentes/implementador-swl.md +2 -2
- package/agentes/investigador-swl.md +2 -2
- package/agentes/investigador-ux-swl.md +2 -2
- package/agentes/llm-apps-swl.md +2 -2
- package/agentes/migrador-swl.md +2 -2
- package/agentes/mobile-android-swl.md +2 -2
- package/agentes/mobile-cross-swl.md +2 -2
- package/agentes/mobile-ios-swl.md +2 -2
- package/agentes/mobile-testing-swl.md +2 -2
- package/agentes/nemesis-auditor-swl.md +1 -1
- package/agentes/notificador-swl.md +2 -2
- package/agentes/observabilidad-swl.md +2 -2
- package/agentes/orquestador-swl.md +41 -14
- package/agentes/pagos-swl.md +2 -2
- package/agentes/perfilador-usuario-swl.md +2 -2
- package/agentes/planificador-swl.md +2 -2
- package/agentes/producto-prd-swl.md +2 -2
- package/agentes/red-team-swl.md +218 -218
- package/agentes/release-manager-swl.md +2 -2
- package/agentes/rendimiento-swl.md +2 -2
- package/agentes/resolutor-build-swl.md +2 -2
- package/agentes/revisor-angular-swl.md +2 -2
- package/agentes/revisor-codigo-swl.md +36 -3
- package/agentes/revisor-csharp-swl.md +2 -2
- package/agentes/revisor-go-swl.md +2 -2
- package/agentes/revisor-java-swl.md +2 -2
- package/agentes/revisor-kotlin-swl.md +2 -2
- package/agentes/revisor-nextjs-swl.md +2 -2
- package/agentes/revisor-php-swl.md +2 -2
- package/agentes/revisor-react-swl.md +2 -2
- package/agentes/revisor-rust-swl.md +2 -2
- package/agentes/revisor-seguridad-swl.md +2 -2
- package/agentes/revisor-swift-swl.md +2 -2
- package/agentes/revisor-typescript-swl.md +2 -2
- package/agentes/sre-swl.md +2 -2
- package/agentes/tdd-qa-swl.md +2 -2
- package/comandos/swl/briefing.md +119 -119
- package/comandos/swl/contexto.md +0 -2
- package/comandos/swl/contribuir.md +233 -233
- package/comandos/swl/deuda-codigo.md +97 -0
- package/comandos/swl/predecir.md +139 -139
- package/comandos/swl/sesiones.md +1 -1
- package/gateway/agent-executor.js +1 -1
- package/gateway/lib/event-channel.js +191 -191
- package/habilidades/agent-deep-links/SKILL.md +148 -148
- package/habilidades/agentes-como-servicio/SKILL.md +2 -2
- package/habilidades/angular-moderno/SKILL.md +24 -1
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -276
- package/habilidades/backend-async-postgres-testing/SKILL.md +215 -215
- package/habilidades/backend-error-design/SKILL.md +221 -221
- package/habilidades/backend-production-resilience/SKILL.md +288 -288
- package/habilidades/benchmark-memoria/SKILL.md +186 -186
- package/habilidades/calidad-anti-patrones-universales/SKILL.md +368 -368
- package/habilidades/calidad-contract-testing/SKILL.md +165 -165
- package/habilidades/calidad-mutation-testing/SKILL.md +170 -170
- package/habilidades/changelog-generator/scripts/parse-commits.js +367 -367
- package/habilidades/checklist-seguridad/recursos/stride-cobertura.md +60 -60
- package/habilidades/contenedores-docker/SKILL.md +3 -1
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/drift-detection/SKILL.md +179 -179
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +1 -1
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -57
- package/habilidades/eval-framework/SKILL.md +212 -212
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
- package/habilidades/harness-claude-code/SKILL.md +4 -4
- package/habilidades/harness-claude-code/recursos/disciplina-harness-regla.md +253 -252
- package/habilidades/legacy-code-rescue/SKILL.md +268 -267
- package/habilidades/meta-skills-estandar/SKILL.md +1 -1
- package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +2 -2
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
- package/habilidades/perfil-usuario/SKILL.md +200 -200
- package/habilidades/postgresql-experto/SKILL.md +3 -1
- package/habilidades/prevencion-sobreingenieria/SKILL.md +70 -92
- package/habilidades/prevencion-sobreingenieria/recursos/EXAMPLES.md +580 -580
- package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -0
- package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -0
- package/habilidades/proceso-ddia-fundamentos/SKILL.md +255 -255
- package/habilidades/proceso-ddia-streaming/SKILL.md +231 -231
- package/habilidades/proceso-debate-adversarial/recursos/personas.md +105 -105
- package/habilidades/proceso-discovery-machote/SKILL.md +157 -157
- package/habilidades/proceso-dynamic-workflows/SKILL.md +138 -138
- 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-intent-engineering/SKILL.md +269 -269
- package/habilidades/proceso-modular-split/SKILL.md +256 -256
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +2 -2
- package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
- package/habilidades/structured-outputs/SKILL.md +2 -2
- 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/swl-dashboard/SKILL.md +2 -2
- package/habilidades/tdd-workflow/recursos/gherkin-bdd.md +111 -111
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +1 -1
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +1 -1
- package/hooks/audit-trail.js +4 -4
- package/hooks/calidad-pre-commit.js +15 -11
- package/hooks/captura-acciones-post.js +3 -2
- package/hooks/captura-acciones-session.js +3 -2
- package/hooks/ciclo-evolucion-subagente.js +26 -26
- package/hooks/ciclo-evolucion.js +26 -26
- package/hooks/claudemd-bloat-detector.js +161 -161
- package/hooks/claudemd-duplicacion-detector.js +170 -170
- package/hooks/contexto-iteracion.js +145 -144
- package/hooks/contexto-subagente.js +68 -0
- package/hooks/guardrail-modelo.js +14 -4
- package/hooks/inyeccion-contexto.js +12 -12
- package/hooks/lib/agent-routing.js +107 -107
- package/hooks/lib/auto-consolidator.js +335 -335
- package/hooks/lib/autonomia.js +208 -208
- 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-auto-evolucion.js +701 -701
- package/hooks/lib/etapa-metricas.js +388 -388
- package/hooks/lib/etapa-perfil-usuario.js +376 -376
- package/hooks/lib/loop-telemetry.js +321 -321
- package/hooks/lib/merkle-audit.js +96 -96
- package/hooks/lib/model-router.js +2 -2
- package/hooks/lib/propose-step.js +358 -358
- package/hooks/lib/provenance-tracker.js +191 -191
- package/hooks/lib/rate-limit-tracker.js +253 -253
- package/hooks/lib/resource-quota.js +122 -122
- package/hooks/lib/retry-jitter.js +165 -165
- package/hooks/lib/security-net.js +201 -201
- 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/text-similarity.js +241 -241
- package/hooks/lib/token-estimator.js +1 -0
- package/hooks/lib/toon-compressor.js +245 -245
- package/hooks/lib/usage-model.js +1 -1
- package/hooks/registro-turnos.js +210 -209
- package/hooks/session-briefing.js +98 -98
- package/hooks/spec-gate.js +212 -211
- package/hooks/sugerir-contribuir.js +2 -1
- package/hooks/sugerir-regenerar-inventario.js +171 -170
- package/hooks/tdd-gate.js +242 -241
- package/hooks/telemetria-skill-routing.js +100 -100
- package/hooks/validar-formato-post-subagente.js +140 -140
- package/hooks/validar-intent-spec.js +242 -242
- package/hooks/validar-memoria-hook.js +218 -218
- package/hooks/validar-planning-paths.js +134 -134
- 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 +2948 -1964
- package/manifiestos/hook-profiles.json +0 -2
- package/manifiestos/hooks-config.json +469 -477
- package/manifiestos/invariantes-criticos.json +30 -0
- package/manifiestos/modulos.json +1390 -1390
- package/manifiestos/planning-paths.json +44 -44
- package/manifiestos/skills-lock.json +1282 -1282
- package/package.json +93 -93
- package/plantillas/auditor-veto-template.md +105 -105
- package/plantillas/github-workflows/README.md +47 -47
- 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 -371
- package/reglas/accesibilidad.md +10 -10
- package/reglas/analisis-previo-tareas-grandes.md +172 -172
- package/reglas/api-diseno.md +9 -9
- package/reglas/arreglar-al-detectar.md +240 -240
- 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/debatir-antes-de-aceptar.md +158 -158
- package/reglas/fragmentos-compartidos.md +183 -183
- package/reglas/hooks.md +6 -6
- package/reglas/intent-engineering.md +218 -218
- package/reglas/markitdown.md +8 -8
- package/reglas/monitor-ci.md +309 -309
- package/reglas/patrones.md +6 -6
- package/reglas/sesiones-paralelas.md +180 -180
- package/reglas/sin-duplicacion-reglas-globales.md +182 -182
- package/reglas/skills-estandar.md +6 -6
- package/reglas/testing.md +7 -7
- package/reglas/tests-cleanup.md +224 -224
- package/reglas/usar-code-review-graph.md +155 -155
- package/reglas/usar-context7.md +226 -226
- package/reglas/verificar-citas-normativas.md +548 -548
- package/schemas/agent-frontmatter.schema.json +5 -3
- 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/hook-profiles.schema.json +54 -54
- package/schemas/hooks-config.schema.json +89 -89
- package/schemas/modulos.schema.json +38 -38
- package/schemas/perfiles.schema.json +36 -36
- package/schemas/plugin.schema.json +77 -77
- package/schemas/skill-evals.schema.json +119 -119
- package/schemas/skill-frontmatter.schema.json +245 -245
- 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/benchmark-memoria.js +167 -167
- package/scripts/cli/aprobar-plan.js +73 -73
- package/scripts/cli/briefing.js +23 -23
- package/scripts/cli/ciclo-evolucion.js +26 -26
- package/scripts/cli/configurar-ci.js +40 -40
- 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/liberar-fase.js +42 -42
- package/scripts/cli/loop-telemetry.js +125 -125
- package/scripts/cli/mark-evolved.js +56 -56
- 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/propose-step.js +29 -29
- 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/configurar-branch-protection.js +418 -418
- package/scripts/detectar-aprendizajes-duplicados.js +151 -151
- package/scripts/field-report.js +199 -199
- package/scripts/generar-checklists-consolidados.js +273 -273
- package/scripts/generar-matriz-lenguajes.js +271 -271
- package/scripts/instalador.js +4 -1
- package/scripts/lib/artefactos-python.js +43 -43
- package/scripts/lib/auditar-invocaciones-comandos.js +104 -104
- package/scripts/lib/benchmark-metrics.js +160 -160
- package/scripts/lib/budget-enforcer.js +252 -252
- package/scripts/lib/ci-reader.js +193 -193
- package/scripts/lib/claude-sessions.js +1 -0
- package/scripts/lib/configurar-ci.js +380 -380
- package/scripts/lib/contadores-inventario.js +217 -217
- package/scripts/lib/detectar-host-swl.js +175 -175
- 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/diary-entry.js +234 -234
- 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/evidencia-release.js +322 -322
- package/scripts/lib/gate-hooks-requires.js +249 -249
- package/scripts/lib/gate-licencias.js +212 -212
- package/scripts/lib/git-metricas.js +257 -257
- package/scripts/lib/jaccard-similarity.js +98 -98
- package/scripts/lib/longmemeval-runner.js +125 -125
- package/scripts/lib/metricas-dora.js +204 -204
- package/scripts/lib/npm-version.js +261 -261
- package/scripts/lib/paquetes-conocidos.js +50 -50
- package/scripts/lib/plan-lock.js +275 -275
- package/scripts/lib/pr-analyzer.js +399 -399
- package/scripts/lib/preservar-usuario.js +39 -5
- package/scripts/lib/prompt-builder.js +264 -264
- package/scripts/lib/reglas-globales-conocidas.json +180 -180
- package/scripts/lib/resolver-plan-fase.js +37 -37
- package/scripts/lib/rrf-fusion.js +175 -175
- package/scripts/lib/schema-version.js +164 -164
- package/scripts/lib/scoring-instintos.js +277 -277
- package/scripts/lib/semantic-search.js +252 -252
- package/scripts/lib/tool-cost-analyzer.js +1 -0
- package/scripts/limpiar-artefactos-python.js +131 -131
- package/scripts/migrar-csv-a-array.js +168 -168
- package/scripts/migrar-fase-dominio.js +200 -200
- package/scripts/publicar.js +497 -497
- package/scripts/run-eval.js +141 -141
- 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/index.js +162 -162
- 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/inspect.js +173 -173
- package/scripts/tui/pantallas/install-wizard.js +334 -334
- 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/tui/pantallas/uninstall-wizard.js +208 -208
- package/scripts/tui/pantallas/update-wizard.js +232 -232
- package/scripts/tui/pantallas/welcome.js +187 -187
- package/scripts/validar-userland-vacio.js +110 -110
- package/scripts/validar.js +1 -1
- package/scripts/verificar-release.js +51 -0
- package/hooks/lib/context-compressor.js +0 -657
- package/hooks/linea-estado.js +0 -326
- package/hooks/monitor-contexto.js +0 -373
|
@@ -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();
|
|
@@ -1,168 +1,168 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Migración 3A — convierte campos CSV a array YAML inline en frontmatter de
|
|
4
|
-
* agentes. Afecta `tools`, `skillsInvocables`, `skillsRestringidos`.
|
|
5
|
-
*
|
|
6
|
-
* Antes: tools: Read, Write, Edit, Bash
|
|
7
|
-
* Después: tools: [Read, Write, Edit, Bash]
|
|
8
|
-
*
|
|
9
|
-
* Razón: el schema declara `type: array` pero el uso real es CSV string. YAML
|
|
10
|
-
* estándar NO convierte CSV a array — el parser produce una sola string. Esto
|
|
11
|
-
* causó bugs históricos documentados en CLAUDE.md ("regla obligatoria CSV
|
|
12
|
-
* estricto"). Migrar a array inline elimina la ambigüedad.
|
|
13
|
-
*
|
|
14
|
-
* Idempotente: skip si ya es array.
|
|
15
|
-
*
|
|
16
|
-
* Casos especiales detectados en agentes:
|
|
17
|
-
* - skillsInvocables: <ninguno> → mantener literal
|
|
18
|
-
* - skillsRestringidos: ninguno → convertir a [] (array vacío)
|
|
19
|
-
* - skillsRestringidos: \n - x\n → ya es array YAML multilinea, mantener
|
|
20
|
-
*
|
|
21
|
-
* Uso:
|
|
22
|
-
* node scripts/migrar-csv-a-array.js [--dry-run]
|
|
23
|
-
*
|
|
24
|
-
* Zero-dependencies. Compatible Windows (CRLF-safe), Node 18+.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
'use strict';
|
|
28
|
-
|
|
29
|
-
const fs = require('fs');
|
|
30
|
-
const path = require('path');
|
|
31
|
-
|
|
32
|
-
const AGENTES_DIR = path.join(__dirname, '..', 'agentes');
|
|
33
|
-
const DRY_RUN = process.argv.includes('--dry-run');
|
|
34
|
-
|
|
35
|
-
// Campos que migran de CSV a array
|
|
36
|
-
const CAMPOS_CSV = ['tools', 'skillsInvocables', 'skillsRestringidos'];
|
|
37
|
-
|
|
38
|
-
// Valores especiales que NO son listas y deben preservarse
|
|
39
|
-
const VALORES_LITERAL = new Set(['ninguno', 'ninguna', '<ninguno>', '<ninguna>', 'none', 'null']);
|
|
40
|
-
|
|
41
|
-
function parsearValorCSV(valorStr) {
|
|
42
|
-
// Detectar si ya es array inline `[a, b, c]`
|
|
43
|
-
if (/^\s*\[/.test(valorStr)) return null;
|
|
44
|
-
|
|
45
|
-
// Limpiar
|
|
46
|
-
const valor = valorStr.trim();
|
|
47
|
-
if (!valor) return [];
|
|
48
|
-
|
|
49
|
-
// Valor especial literal
|
|
50
|
-
if (VALORES_LITERAL.has(valor.toLowerCase())) return [];
|
|
51
|
-
|
|
52
|
-
// CSV split
|
|
53
|
-
return valor
|
|
54
|
-
.split(',')
|
|
55
|
-
.map((s) => s.trim())
|
|
56
|
-
.filter(Boolean);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function migrarFrontmatter(contenido) {
|
|
60
|
-
const match = contenido.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
|
|
61
|
-
if (!match) return { contenido, cambios: 0 };
|
|
62
|
-
|
|
63
|
-
const eol = match[0].includes('\r\n') ? '\r\n' : '\n';
|
|
64
|
-
const fmCompleto = match[0];
|
|
65
|
-
|
|
66
|
-
let nuevoFm = fmCompleto;
|
|
67
|
-
let cambios = 0;
|
|
68
|
-
|
|
69
|
-
for (const campo of CAMPOS_CSV) {
|
|
70
|
-
// Patrón 2 PRIMERO: array YAML multilínea
|
|
71
|
-
// skillsRestringidos:
|
|
72
|
-
// - angular-moderno
|
|
73
|
-
// - typescript-avanzado
|
|
74
|
-
// El campo está solo en su línea (sin valor) seguido de líneas con ` - X`
|
|
75
|
-
const re2 = new RegExp(`^(${campo}):[ \\t]*\\r?\\n((?:[ \\t]+-[ \\t]+[^\\r\\n]+\\r?\\n)+)`, 'm');
|
|
76
|
-
const m2 = nuevoFm.match(re2);
|
|
77
|
-
if (m2) {
|
|
78
|
-
const bloque = m2[2];
|
|
79
|
-
const items = bloque
|
|
80
|
-
.split(/\r?\n/)
|
|
81
|
-
.map((l) => l.trim())
|
|
82
|
-
.filter((l) => l.startsWith('- '))
|
|
83
|
-
.map((l) => l.slice(2).trim().replace(/^["']|["']$/g, ''));
|
|
84
|
-
if (items.length > 0) {
|
|
85
|
-
const arrayInline = `[${items.join(', ')}]`;
|
|
86
|
-
const reemplazo = `${campo}: ${arrayInline}${eol}`;
|
|
87
|
-
nuevoFm = nuevoFm.replace(re2, reemplazo);
|
|
88
|
-
cambios++;
|
|
89
|
-
}
|
|
90
|
-
continue; // procesado, no aplicar regex 1
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Patrón 1: campo en una sola línea con valor (CSV o array inline)
|
|
94
|
-
// tools: Read, Write
|
|
95
|
-
// skillsRestringidos: ninguno
|
|
96
|
-
// tools: [Read, Write] ← skip, ya es array
|
|
97
|
-
// CRÍTICO: usar [ \\t]* (NO \\s*) para no consumir newlines
|
|
98
|
-
const re1 = new RegExp(`^(${campo}):[ \\t]*([^\\r\\n]+)$`, 'm');
|
|
99
|
-
const m1 = nuevoFm.match(re1);
|
|
100
|
-
if (m1) {
|
|
101
|
-
const valorStr = m1[2];
|
|
102
|
-
const items = parsearValorCSV(valorStr);
|
|
103
|
-
if (items === null) continue; // ya es array, skip
|
|
104
|
-
const arrayInline = `[${items.join(', ')}]`;
|
|
105
|
-
const reemplazo = `${campo}: ${arrayInline}`;
|
|
106
|
-
if (m1[0] !== reemplazo) {
|
|
107
|
-
nuevoFm = nuevoFm.replace(re1, reemplazo);
|
|
108
|
-
cambios++;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
if (cambios === 0) return { contenido, cambios: 0 };
|
|
114
|
-
|
|
115
|
-
return { contenido: contenido.replace(fmCompleto, nuevoFm), cambios };
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function migrarAgente(archivo) {
|
|
119
|
-
const contenido = fs.readFileSync(archivo, 'utf-8');
|
|
120
|
-
const { contenido: nuevo, cambios } = migrarFrontmatter(contenido);
|
|
121
|
-
|
|
122
|
-
if (cambios === 0) {
|
|
123
|
-
return { archivo: path.basename(archivo), status: 'sin-cambios' };
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (DRY_RUN) {
|
|
127
|
-
return { archivo: path.basename(archivo), status: 'dry-run', cambios };
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
fs.writeFileSync(archivo, nuevo, 'utf-8');
|
|
131
|
-
return { archivo: path.basename(archivo), status: 'migrado', cambios };
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function main() {
|
|
135
|
-
console.log(`Migrando CSV → array YAML${DRY_RUN ? ' (dry-run)' : ''}...\n`);
|
|
136
|
-
|
|
137
|
-
const archivos = fs
|
|
138
|
-
.readdirSync(AGENTES_DIR)
|
|
139
|
-
.filter((f) => f.endsWith('.md') && !f.startsWith('_'))
|
|
140
|
-
.map((f) => path.join(AGENTES_DIR, f));
|
|
141
|
-
|
|
142
|
-
const resultados = archivos.map(migrarAgente);
|
|
143
|
-
|
|
144
|
-
const stats = {
|
|
145
|
-
'sin-cambios': 0,
|
|
146
|
-
migrado: 0,
|
|
147
|
-
'dry-run': 0,
|
|
148
|
-
totalCambios: 0,
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
for (const r of resultados) {
|
|
152
|
-
stats[r.status] = (stats[r.status] || 0) + 1;
|
|
153
|
-
if (r.cambios) stats.totalCambios += r.cambios;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
console.log(`Sin cambios: ${stats['sin-cambios']}`);
|
|
157
|
-
console.log(`Migrados: ${stats.migrado}`);
|
|
158
|
-
console.log(`Dry-run: ${stats['dry-run']}`);
|
|
159
|
-
console.log(`Total ediciones: ${stats.totalCambios}`);
|
|
160
|
-
|
|
161
|
-
process.exit(0);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (require.main === module) {
|
|
165
|
-
main();
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
module.exports = { parsearValorCSV, migrarFrontmatter };
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Migración 3A — convierte campos CSV a array YAML inline en frontmatter de
|
|
4
|
+
* agentes. Afecta `tools`, `skillsInvocables`, `skillsRestringidos`.
|
|
5
|
+
*
|
|
6
|
+
* Antes: tools: Read, Write, Edit, Bash
|
|
7
|
+
* Después: tools: [Read, Write, Edit, Bash]
|
|
8
|
+
*
|
|
9
|
+
* Razón: el schema declara `type: array` pero el uso real es CSV string. YAML
|
|
10
|
+
* estándar NO convierte CSV a array — el parser produce una sola string. Esto
|
|
11
|
+
* causó bugs históricos documentados en CLAUDE.md ("regla obligatoria CSV
|
|
12
|
+
* estricto"). Migrar a array inline elimina la ambigüedad.
|
|
13
|
+
*
|
|
14
|
+
* Idempotente: skip si ya es array.
|
|
15
|
+
*
|
|
16
|
+
* Casos especiales detectados en agentes:
|
|
17
|
+
* - skillsInvocables: <ninguno> → mantener literal
|
|
18
|
+
* - skillsRestringidos: ninguno → convertir a [] (array vacío)
|
|
19
|
+
* - skillsRestringidos: \n - x\n → ya es array YAML multilinea, mantener
|
|
20
|
+
*
|
|
21
|
+
* Uso:
|
|
22
|
+
* node scripts/migrar-csv-a-array.js [--dry-run]
|
|
23
|
+
*
|
|
24
|
+
* Zero-dependencies. Compatible Windows (CRLF-safe), Node 18+.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
'use strict';
|
|
28
|
+
|
|
29
|
+
const fs = require('fs');
|
|
30
|
+
const path = require('path');
|
|
31
|
+
|
|
32
|
+
const AGENTES_DIR = path.join(__dirname, '..', 'agentes');
|
|
33
|
+
const DRY_RUN = process.argv.includes('--dry-run');
|
|
34
|
+
|
|
35
|
+
// Campos que migran de CSV a array
|
|
36
|
+
const CAMPOS_CSV = ['tools', 'skillsInvocables', 'skillsRestringidos'];
|
|
37
|
+
|
|
38
|
+
// Valores especiales que NO son listas y deben preservarse
|
|
39
|
+
const VALORES_LITERAL = new Set(['ninguno', 'ninguna', '<ninguno>', '<ninguna>', 'none', 'null']);
|
|
40
|
+
|
|
41
|
+
function parsearValorCSV(valorStr) {
|
|
42
|
+
// Detectar si ya es array inline `[a, b, c]`
|
|
43
|
+
if (/^\s*\[/.test(valorStr)) return null;
|
|
44
|
+
|
|
45
|
+
// Limpiar
|
|
46
|
+
const valor = valorStr.trim();
|
|
47
|
+
if (!valor) return [];
|
|
48
|
+
|
|
49
|
+
// Valor especial literal
|
|
50
|
+
if (VALORES_LITERAL.has(valor.toLowerCase())) return [];
|
|
51
|
+
|
|
52
|
+
// CSV split
|
|
53
|
+
return valor
|
|
54
|
+
.split(',')
|
|
55
|
+
.map((s) => s.trim())
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function migrarFrontmatter(contenido) {
|
|
60
|
+
const match = contenido.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n/);
|
|
61
|
+
if (!match) return { contenido, cambios: 0 };
|
|
62
|
+
|
|
63
|
+
const eol = match[0].includes('\r\n') ? '\r\n' : '\n';
|
|
64
|
+
const fmCompleto = match[0];
|
|
65
|
+
|
|
66
|
+
let nuevoFm = fmCompleto;
|
|
67
|
+
let cambios = 0;
|
|
68
|
+
|
|
69
|
+
for (const campo of CAMPOS_CSV) {
|
|
70
|
+
// Patrón 2 PRIMERO: array YAML multilínea
|
|
71
|
+
// skillsRestringidos:
|
|
72
|
+
// - angular-moderno
|
|
73
|
+
// - typescript-avanzado
|
|
74
|
+
// El campo está solo en su línea (sin valor) seguido de líneas con ` - X`
|
|
75
|
+
const re2 = new RegExp(`^(${campo}):[ \\t]*\\r?\\n((?:[ \\t]+-[ \\t]+[^\\r\\n]+\\r?\\n)+)`, 'm');
|
|
76
|
+
const m2 = nuevoFm.match(re2);
|
|
77
|
+
if (m2) {
|
|
78
|
+
const bloque = m2[2];
|
|
79
|
+
const items = bloque
|
|
80
|
+
.split(/\r?\n/)
|
|
81
|
+
.map((l) => l.trim())
|
|
82
|
+
.filter((l) => l.startsWith('- '))
|
|
83
|
+
.map((l) => l.slice(2).trim().replace(/^["']|["']$/g, ''));
|
|
84
|
+
if (items.length > 0) {
|
|
85
|
+
const arrayInline = `[${items.join(', ')}]`;
|
|
86
|
+
const reemplazo = `${campo}: ${arrayInline}${eol}`;
|
|
87
|
+
nuevoFm = nuevoFm.replace(re2, reemplazo);
|
|
88
|
+
cambios++;
|
|
89
|
+
}
|
|
90
|
+
continue; // procesado, no aplicar regex 1
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Patrón 1: campo en una sola línea con valor (CSV o array inline)
|
|
94
|
+
// tools: Read, Write
|
|
95
|
+
// skillsRestringidos: ninguno
|
|
96
|
+
// tools: [Read, Write] ← skip, ya es array
|
|
97
|
+
// CRÍTICO: usar [ \\t]* (NO \\s*) para no consumir newlines
|
|
98
|
+
const re1 = new RegExp(`^(${campo}):[ \\t]*([^\\r\\n]+)$`, 'm');
|
|
99
|
+
const m1 = nuevoFm.match(re1);
|
|
100
|
+
if (m1) {
|
|
101
|
+
const valorStr = m1[2];
|
|
102
|
+
const items = parsearValorCSV(valorStr);
|
|
103
|
+
if (items === null) continue; // ya es array, skip
|
|
104
|
+
const arrayInline = `[${items.join(', ')}]`;
|
|
105
|
+
const reemplazo = `${campo}: ${arrayInline}`;
|
|
106
|
+
if (m1[0] !== reemplazo) {
|
|
107
|
+
nuevoFm = nuevoFm.replace(re1, reemplazo);
|
|
108
|
+
cambios++;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (cambios === 0) return { contenido, cambios: 0 };
|
|
114
|
+
|
|
115
|
+
return { contenido: contenido.replace(fmCompleto, nuevoFm), cambios };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function migrarAgente(archivo) {
|
|
119
|
+
const contenido = fs.readFileSync(archivo, 'utf-8');
|
|
120
|
+
const { contenido: nuevo, cambios } = migrarFrontmatter(contenido);
|
|
121
|
+
|
|
122
|
+
if (cambios === 0) {
|
|
123
|
+
return { archivo: path.basename(archivo), status: 'sin-cambios' };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (DRY_RUN) {
|
|
127
|
+
return { archivo: path.basename(archivo), status: 'dry-run', cambios };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
fs.writeFileSync(archivo, nuevo, 'utf-8');
|
|
131
|
+
return { archivo: path.basename(archivo), status: 'migrado', cambios };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function main() {
|
|
135
|
+
console.log(`Migrando CSV → array YAML${DRY_RUN ? ' (dry-run)' : ''}...\n`);
|
|
136
|
+
|
|
137
|
+
const archivos = fs
|
|
138
|
+
.readdirSync(AGENTES_DIR)
|
|
139
|
+
.filter((f) => f.endsWith('.md') && !f.startsWith('_'))
|
|
140
|
+
.map((f) => path.join(AGENTES_DIR, f));
|
|
141
|
+
|
|
142
|
+
const resultados = archivos.map(migrarAgente);
|
|
143
|
+
|
|
144
|
+
const stats = {
|
|
145
|
+
'sin-cambios': 0,
|
|
146
|
+
migrado: 0,
|
|
147
|
+
'dry-run': 0,
|
|
148
|
+
totalCambios: 0,
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
for (const r of resultados) {
|
|
152
|
+
stats[r.status] = (stats[r.status] || 0) + 1;
|
|
153
|
+
if (r.cambios) stats.totalCambios += r.cambios;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
console.log(`Sin cambios: ${stats['sin-cambios']}`);
|
|
157
|
+
console.log(`Migrados: ${stats.migrado}`);
|
|
158
|
+
console.log(`Dry-run: ${stats['dry-run']}`);
|
|
159
|
+
console.log(`Total ediciones: ${stats.totalCambios}`);
|
|
160
|
+
|
|
161
|
+
process.exit(0);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (require.main === module) {
|
|
165
|
+
main();
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
module.exports = { parsearValorCSV, migrarFrontmatter };
|