@saulwade/swl-ses 2.5.3 → 2.6.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 +9 -9
- package/README.md +37 -37
- package/agentes/_intent-spec.md +73 -73
- package/agentes/_propose-step.md +90 -90
- package/agentes/accesibilidad-wcag-swl.md +690 -690
- package/agentes/arquitecto-swl.md +267 -267
- package/agentes/auto-evolucion-swl.md +932 -908
- 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 +32 -7
- package/comandos/swl/actualizar.md +3 -3
- package/comandos/swl/aprender.md +13 -0
- package/comandos/swl/deuda-codigo.md +97 -97
- package/comandos/swl/evaluar-skill.md +18 -3
- package/comandos/swl/evolucion-continua.md +73 -0
- package/comandos/swl/evolucionar.md +13 -0
- package/comandos/swl/instalar.md +4 -4
- package/comandos/swl/notificaciones.md +1 -1
- package/comandos/swl/status.md +2 -2
- package/gateway/cron/jobs.example.json +12 -0
- package/habilidades/auto-evolucion-protocolo/SKILL.md +19 -1
- package/habilidades/autoresearch/SKILL.md +3 -2
- package/habilidades/backend-async-postgres-testing/SKILL.md +2 -1
- package/habilidades/benchmark-memoria/SKILL.md +7 -7
- package/habilidades/changelog-generator/SKILL.md +1 -1
- package/habilidades/changelog-generator/scripts/parse-commits.js +2 -1
- package/habilidades/checkpoints-verificacion/SKILL.md +6 -0
- package/habilidades/compactacion-contexto/SKILL.md +2 -1
- package/habilidades/contenedores-docker/SKILL.md +4 -2
- package/habilidades/context-builder/SKILL.md +4 -0
- package/habilidades/doubt-driven-review/SKILL.md +17 -1
- package/habilidades/drift-detection/SKILL.md +6 -1
- package/habilidades/ejecutar-fase/SKILL.md +6 -6
- package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
- package/habilidades/eval-framework/SKILL.md +8 -3
- package/habilidades/extractor-de-aprendizajes/SKILL.md +8 -2
- package/habilidades/git-worktrees-paralelo/SKILL.md +19 -1
- package/habilidades/harness-claude-code/SKILL.md +7 -3
- package/habilidades/infra-github-actions/SKILL.md +4 -3
- package/habilidades/instalar-sistema/SKILL.md +5 -1
- package/habilidades/memoria-busqueda/SKILL.md +31 -39
- package/habilidades/planear-fase/SKILL.md +9 -1
- package/habilidades/prevencion-sobreingenieria/recursos/soluciones-nativas.md +166 -166
- package/habilidades/prevencion-sobreingenieria/recursos/variables-residuales-post-refactor.md +85 -85
- package/habilidades/proceso-ddia-fundamentos/SKILL.md +3 -2
- package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -147
- package/habilidades/release-semver/SKILL.md +2 -2
- package/habilidades/swl-claudemd/SKILL.md +6 -7
- package/habilidades/swl-dashboard/SKILL.md +11 -43
- package/habilidades/tdd-workflow/SKILL.md +12 -7
- package/habilidades/validacion-ci-sistema/SKILL.md +1 -1
- package/hooks/agente-lifecycle.js +2 -1
- package/hooks/aiisms-detector.js +13 -4
- package/hooks/audit-trail.js +2 -1
- package/hooks/auto-consolidacion.js +2 -1
- package/hooks/captura-acciones-post.js +2 -1
- package/hooks/captura-acciones-session.js +2 -1
- package/hooks/captura-feedback-usuario.js +3 -2
- package/hooks/claudemd-bloat-detector.js +12 -3
- package/hooks/claudemd-duplicacion-detector.js +13 -3
- package/hooks/contexto-iteracion.js +2 -1
- package/hooks/contexto-subagente.js +68 -68
- package/hooks/degradacion-instintos.js +2 -1
- package/hooks/extraccion-aprendizajes.js +109 -15
- package/hooks/grafo-contexto.js +2 -1
- package/hooks/guardrail-modelo.js +2 -1
- package/hooks/inbox-aviso.js +2 -1
- package/hooks/inyeccion-contexto.js +2 -1
- package/hooks/lib/agent-matcher.js +2 -1
- package/hooks/lib/agent-routing.js +2 -1
- package/hooks/lib/autonomia.js +5 -3
- package/hooks/lib/captura-acciones.js +2 -1
- package/hooks/lib/consolidation-lock.js +21 -10
- package/hooks/lib/etapa-auto-evolucion.js +10 -4
- package/hooks/lib/etapa-metricas.js +2 -1
- package/hooks/lib/etapa-perfil-usuario.js +20 -4
- package/hooks/lib/evolution-tracker.js +2 -1
- package/hooks/lib/gateway-notify.js +17 -3
- package/hooks/lib/loop-telemetry.js +5 -4
- package/hooks/lib/mcp-health.js +2 -1
- package/hooks/lib/memory-search.js +4 -0
- package/hooks/lib/merkle-audit.js +58 -6
- package/hooks/lib/notificacion-formato.js +58 -0
- package/hooks/lib/nudge-tracker.js +2 -1
- package/hooks/lib/otlp-exporter.js +2 -1
- package/hooks/lib/propose-step.js +3 -2
- package/hooks/lib/raiz-proyecto.js +127 -0
- package/hooks/lib/run-log.js +2 -1
- package/hooks/lib/singleton-guard.js +225 -27
- package/hooks/lib/telegram-cliente.js +28 -11
- package/hooks/notificacion-telegram.js +13 -3
- package/hooks/preservar-estado-pre-compact.js +2 -1
- package/hooks/proteccion-rutas.js +59 -3
- package/hooks/registro-turnos.js +2 -1
- package/hooks/resumen-sesion.js +2 -1
- package/hooks/risk-scoring.js +2 -1
- package/hooks/rotar-audit-auto.js +46 -20
- package/hooks/session-briefing.js +127 -1
- package/hooks/spec-gate.js +2 -1
- package/hooks/sugerir-contribuir.js +6 -3
- package/hooks/sugerir-regenerar-inventario.js +3 -2
- package/hooks/tdd-gate.js +2 -1
- package/hooks/telemetria-agentes.js +2 -1
- package/hooks/telemetria-skill-routing.js +2 -1
- package/hooks/tracking-costos.js +4 -3
- package/hooks/validar-formato-post-subagente.js +2 -1
- package/hooks/validar-intent-spec.js +2 -1
- package/hooks/validar-memoria-hook.js +13 -3
- package/hooks/validar-planning-paths.js +2 -1
- package/instintos/perfil-usuario.yaml +506 -3
- package/instintos/proyecto.yaml +78 -0
- package/llms.txt +29 -29
- package/manifiestos/canonical-hashes.json +5588 -4925
- package/manifiestos/hooks-config.json +469 -469
- package/manifiestos/invariantes-criticos.json +30 -30
- package/manifiestos/modulos.json +1429 -1423
- package/manifiestos/planning-paths.json +1 -0
- package/manifiestos/skills-lock.json +1275 -1275
- package/package.json +94 -95
- package/plugin.json +369 -369
- package/scripts/actualizar.js +3 -0
- package/scripts/auditar-clases-conocidas.js +134 -106
- package/scripts/benchmark-memoria.js +1 -0
- package/scripts/bootstrap-instintos.js +85 -14
- package/scripts/canario-hooks.js +166 -166
- package/scripts/cli/autonomia.js +23 -0
- package/scripts/cli/benchmark-memoria.js +37 -0
- package/scripts/cli/ciclo-autonomo.js +73 -0
- package/scripts/cli/ciclo-fase-b.js +102 -0
- package/scripts/cli/guardrail-metrics.js +39 -0
- package/scripts/cli/loop-telemetry.js +4 -2
- package/scripts/cli/memoria-search.js +69 -0
- package/scripts/cli/nudge-accionar.js +39 -0
- package/scripts/cli/run-eval.js +38 -0
- package/scripts/cli/run-skill-evals.js +13 -2
- package/scripts/derivar-feature-list.js +15 -14
- package/scripts/desinstalar.js +11 -0
- package/scripts/doctor.js +50 -13
- package/scripts/evidencia-valor.js +101 -101
- package/scripts/field-report.js +16 -16
- package/scripts/instalador.js +98 -7
- package/scripts/lib/activar-hooks-proyecto.js +116 -104
- package/scripts/lib/auditar-invocaciones-comandos.js +96 -6
- package/scripts/lib/ciclo-autonomo/candidatos.js +174 -0
- package/scripts/lib/ciclo-autonomo/config.js +165 -0
- package/scripts/lib/ciclo-autonomo/drenador-feedback.js +174 -0
- package/scripts/lib/ciclo-autonomo/fallback.js +77 -0
- package/scripts/lib/ciclo-autonomo/guard-convivencia.js +139 -0
- package/scripts/lib/ciclo-autonomo/higiene-nudges.js +112 -0
- package/scripts/lib/ciclo-autonomo/index.js +301 -0
- package/scripts/lib/ciclo-autonomo/lock.js +124 -0
- package/scripts/lib/ciclo-autonomo/presupuesto.js +122 -0
- package/scripts/lib/ciclo-autonomo/puente-degradacion.js +240 -0
- package/scripts/lib/ciclo-autonomo/runner-fase-b.js +248 -0
- package/scripts/lib/ciclo-autonomo/writer-instintos.js +190 -0
- package/scripts/lib/ciclo-autonomo/yaml-instintos.js +535 -0
- package/scripts/lib/estado.js +9 -0
- package/scripts/lib/evidencia-valor.js +228 -228
- package/scripts/lib/expandir-targets.js +71 -71
- package/scripts/lib/gitignore-manifest.js +8 -1
- package/scripts/lib/hooks-settings.js +45 -0
- package/scripts/lib/limpiar-basura-global.js +161 -0
- package/scripts/lib/toml-merge.js +204 -204
- package/scripts/mcp-server/auth.js +105 -105
- package/scripts/mcp-server/cache.js +106 -106
- package/scripts/rotar-audit-logs.js +48 -2
- package/scripts/run-eval.js +1 -0
- package/scripts/run-skill-evals.js +287 -8
- package/scripts/smoke-test.js +16 -8
- package/scripts/tui/pantallas/install-wizard.js +69 -13
- package/scripts/validar.js +40 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wrapper CLI `swl-ses memoria-search <op>` — búsqueda en la memoria del
|
|
5
|
+
* proyecto (.planning/sessions/, APRENDIZAJES.md, diary). Reemplaza los
|
|
6
|
+
* `require('./hooks/lib/memory-search')` relativos al proyecto que
|
|
7
|
+
* memoria-busqueda y benchmark-memoria instruían — rotos downstream (ver
|
|
8
|
+
* docs/invocacion-cli-cross-scope.md).
|
|
9
|
+
*
|
|
10
|
+
* Ops:
|
|
11
|
+
* search --query="..." [--limit=N] [--tipo=aprendizaje|sesion|instinto]
|
|
12
|
+
* [--desde=YYYY-MM-DD] [--hasta=YYYY-MM-DD] (default)
|
|
13
|
+
* timeline --ids=id1,id2,...
|
|
14
|
+
* fetch --id=<id>
|
|
15
|
+
*
|
|
16
|
+
* Salida: JSON a stdout. La base es la RAÍZ del proyecto (raizProyecto),
|
|
17
|
+
* no el cwd crudo — misma semántica que los hooks (DT-HOOKS-RAIZ-GIT).
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const ms = require('../../hooks/lib/memory-search');
|
|
21
|
+
const { raizProyecto } = require('../../hooks/lib/raiz-proyecto');
|
|
22
|
+
|
|
23
|
+
function memoriaSearch(opciones = {}) {
|
|
24
|
+
const op = (opciones._args && opciones._args[0]) || 'search';
|
|
25
|
+
const base = raizProyecto(process.cwd());
|
|
26
|
+
|
|
27
|
+
if (op === 'search') {
|
|
28
|
+
const query = opciones.query != null && opciones.query !== true ? String(opciones.query) : '';
|
|
29
|
+
if (!query) {
|
|
30
|
+
console.error('Error: falta --query="<términos>"');
|
|
31
|
+
process.exitCode = 1;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const filtros = {};
|
|
35
|
+
const limit = parseInt(opciones.limit, 10);
|
|
36
|
+
if (!isNaN(limit) && limit > 0) filtros.limit = limit;
|
|
37
|
+
if (opciones.tipo != null && opciones.tipo !== true) filtros.tipo = String(opciones.tipo);
|
|
38
|
+
if (opciones.desde != null && opciones.desde !== true) filtros.fecha_desde = String(opciones.desde);
|
|
39
|
+
if (opciones.hasta != null && opciones.hasta !== true) filtros.fecha_hasta = String(opciones.hasta);
|
|
40
|
+
console.log(JSON.stringify(ms.search(base, query, filtros), null, 2));
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (op === 'timeline') {
|
|
45
|
+
const ids = String(opciones.ids || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
46
|
+
if (ids.length === 0) {
|
|
47
|
+
console.error('Error: falta --ids=id1,id2,...');
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
console.log(JSON.stringify(ms.timeline(base, ids), null, 2));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (op === 'fetch') {
|
|
56
|
+
if (opciones.id == null || opciones.id === true) {
|
|
57
|
+
console.error('Error: falta --id=<id>');
|
|
58
|
+
process.exitCode = 1;
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
console.log(JSON.stringify(ms.fetch(base, String(opciones.id)), null, 2));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
console.error(`Error: op desconocida "${op}" (usa search|timeline|fetch)`);
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = memoriaSearch;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Subcomando `swl-ses nudge-accionar <id> --por <consumidor>` — cierra el
|
|
5
|
+
* ciclo de un nudge (T-09, Fase 21 / ADR-0041).
|
|
6
|
+
*
|
|
7
|
+
* Lo invocan los comandos /swl:aprender y /swl:evolucionar (y el agente
|
|
8
|
+
* auto-evolucion-swl) tras atender la sugerencia de un nudge, para que
|
|
9
|
+
* `evolution/nudges.jsonl` registre quién lo accionó. Sin este cierre los
|
|
10
|
+
* nudges se acumulan sin consumidor (174 emitidos / 0 accionados al crear
|
|
11
|
+
* la Fase 21).
|
|
12
|
+
*
|
|
13
|
+
* Uso: swl-ses nudge-accionar <id> [--por <consumidor>]
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const { marcarAccionado } = require('../lib/ciclo-autonomo/higiene-nudges');
|
|
17
|
+
|
|
18
|
+
function nudgeAccionar(opciones = {}) {
|
|
19
|
+
const id = (opciones._args || [])[0];
|
|
20
|
+
const baseDir = opciones.dir || process.cwd();
|
|
21
|
+
|
|
22
|
+
if (!id) {
|
|
23
|
+
console.error('[nudge-accionar] falta el id. Uso: swl-ses nudge-accionar <id> [--por <consumidor>]');
|
|
24
|
+
process.exitCode = 1;
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const por = opciones.por || opciones.by || 'desconocido';
|
|
29
|
+
const resultado = marcarAccionado(baseDir, { id, por });
|
|
30
|
+
|
|
31
|
+
if (resultado.marcados === 0) {
|
|
32
|
+
console.error(`[nudge-accionar] nudge "${id}" no encontrado o ya accionado`);
|
|
33
|
+
} else {
|
|
34
|
+
console.log(`[nudge-accionar] nudge "${id}" marcado como accionado por "${por}"`);
|
|
35
|
+
}
|
|
36
|
+
return resultado;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = nudgeAccionar;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Wrapper CLI `swl-ses run-eval` — ejecuta un eval del framework de validación
|
|
5
|
+
* de outputs estructurados (scripts/run-eval.js). Reemplaza el
|
|
6
|
+
* `node scripts/run-eval.js` relativo al proyecto que eval-framework
|
|
7
|
+
* instruía — roto downstream (ver docs/invocacion-cli-cross-scope.md).
|
|
8
|
+
*
|
|
9
|
+
* Uso:
|
|
10
|
+
* swl-ses run-eval <ruta-eval.json>
|
|
11
|
+
* swl-ses run-eval --rebuild-aggregate
|
|
12
|
+
*
|
|
13
|
+
* ADVERTENCIA (nemesis iter-1 S3-6): el main() envuelto llama process.exit()
|
|
14
|
+
* en todas sus ramas — este wrapper TERMINA el proceso host. Correcto vía
|
|
15
|
+
* `bin/swl-ses.js` (proceso fresco por invocación); NO invocar in-process
|
|
16
|
+
* (batch runners, tests que compongan varios wrappers) o matará el proceso.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const { main } = require('../run-eval.js');
|
|
20
|
+
|
|
21
|
+
function runEval(opciones = {}) {
|
|
22
|
+
const args = [];
|
|
23
|
+
if (opciones['rebuild-aggregate'] || opciones.rebuild_aggregate) {
|
|
24
|
+
args.push('--rebuild-aggregate');
|
|
25
|
+
} else if (opciones._args && opciones._args[0]) {
|
|
26
|
+
args.push(String(opciones._args[0]));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const argvOriginal = process.argv;
|
|
30
|
+
process.argv = ['node', 'run-eval.js', ...args];
|
|
31
|
+
try {
|
|
32
|
+
main();
|
|
33
|
+
} finally {
|
|
34
|
+
process.argv = argvOriginal;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = runEval;
|
|
@@ -11,10 +11,17 @@
|
|
|
11
11
|
* --list → listar evals del skill
|
|
12
12
|
* --json → output JSON
|
|
13
13
|
* --record-baseline → registrar score baseline
|
|
14
|
-
* --record-after → registrar score post-cambio
|
|
15
|
-
*
|
|
14
|
+
* --record-after → registrar score post-cambio (el score se LEE del
|
|
15
|
+
* artefacto de evaluación con procedencia — ver abajo)
|
|
16
|
+
* --score=<N> → score numérico (baseline/revert; en record-after
|
|
17
|
+
* solo como verificación de coincidencia)
|
|
16
18
|
* --hypothesis=<texto> → hipótesis de la mutación
|
|
17
19
|
* --invariantes-ok → marcar invariantes como OK
|
|
20
|
+
* --emitir-evaluacion → escribir artefacto de procedencia (lo invoca
|
|
21
|
+
* /swl:evaluar-skill; exige --score y --producido-por)
|
|
22
|
+
* --producido-por=<a> → actor que corrió la evaluación (≠ target)
|
|
23
|
+
* --badge=<b> → badge asignado (opcional, acompaña emitir)
|
|
24
|
+
* --evaluacion=<path> → override del path del artefacto en record-after
|
|
18
25
|
*/
|
|
19
26
|
|
|
20
27
|
const path = require('path');
|
|
@@ -32,6 +39,10 @@ function runSkillEvals(opciones) {
|
|
|
32
39
|
if (opciones && opciones.score !== undefined) args.push(`--score=${opciones.score}`);
|
|
33
40
|
if (opciones && opciones.hypothesis) args.push(`--hypothesis=${opciones.hypothesis}`);
|
|
34
41
|
if (opciones && opciones['invariantes-ok']) args.push('--invariantes-ok');
|
|
42
|
+
if (opciones && opciones['emitir-evaluacion']) args.push('--emitir-evaluacion');
|
|
43
|
+
if (opciones && opciones['producido-por']) args.push(`--producido-por=${opciones['producido-por']}`);
|
|
44
|
+
if (opciones && opciones.badge) args.push(`--badge=${opciones.badge}`);
|
|
45
|
+
if (opciones && opciones.evaluacion) args.push(`--evaluacion=${opciones.evaluacion}`);
|
|
35
46
|
|
|
36
47
|
const argvOriginal = process.argv;
|
|
37
48
|
process.argv = ['node', 'run-skill-evals.js', ...args];
|
|
@@ -102,22 +102,23 @@ function parsearTablaResumen(contenido, fases) {
|
|
|
102
102
|
|
|
103
103
|
const celdas = trim.split('|').map(c => c.trim()).filter(c => c !== '');
|
|
104
104
|
|
|
105
|
-
// Detectar header
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
105
|
+
// Detectar header — en CADA línea de tabla, no solo en la primera del
|
|
106
|
+
// archivo: el HOJA-RUTA real acumula varias tablas de fase (una por
|
|
107
|
+
// iniciativa) y fijar los índices de la primera ignoraba las demás en
|
|
108
|
+
// silencio (--check daba verde con fases ausentes del JSON).
|
|
109
|
+
const lowered = celdas.map(c => c.toLowerCase());
|
|
110
|
+
const fa = lowered.findIndex(c => c === 'fase' || c === 'phase' || c === '#');
|
|
111
|
+
const no = lowered.findIndex(c => c === 'nombre' || c === 'name');
|
|
112
|
+
const es = lowered.findIndex(c => c === 'estado' || c === 'status');
|
|
113
|
+
if (fa !== -1 && no !== -1 && es !== -1) {
|
|
114
|
+
idxFase = fa;
|
|
115
|
+
idxNombre = no;
|
|
116
|
+
idxObjetivo = lowered.findIndex(c => c === 'objetivo' || c === 'objective');
|
|
117
|
+
idxEstado = es;
|
|
118
|
+
enTabla = true;
|
|
119
119
|
continue;
|
|
120
120
|
}
|
|
121
|
+
if (idxFase === -1) continue;
|
|
121
122
|
|
|
122
123
|
// Línea separadora (|---|---|)
|
|
123
124
|
if (celdas.every(c => /^-+$/.test(c.replace(/:/g, '')))) continue;
|
package/scripts/desinstalar.js
CHANGED
|
@@ -140,6 +140,17 @@ function uninstall(opciones) {
|
|
|
140
140
|
` - ${archivo.destino}`
|
|
141
141
|
);
|
|
142
142
|
eliminados++;
|
|
143
|
+
// Subdirectorios creados por el instalador (hooks/lib/, rules/<lang>/)
|
|
144
|
+
// quedan vacíos tras borrar sus archivos: rmdir no-recursivo — solo
|
|
145
|
+
// cae si el dir quedó realmente vacío; cualquier contenido del usuario
|
|
146
|
+
// lo preserva (ENOTEMPTY ignorado). Acotado a rutas.base: un
|
|
147
|
+
// install-state manipulado no puede dirigir el rmdir fuera del árbol
|
|
148
|
+
// gestionado (endurecimiento, revisor-seguridad 2026-07-10).
|
|
149
|
+
try {
|
|
150
|
+
const padre = path.resolve(path.dirname(archivo.destino));
|
|
151
|
+
const baseGestionada = path.resolve(rutas.base);
|
|
152
|
+
if (padre.startsWith(baseGestionada + path.sep)) fs.rmdirSync(padre);
|
|
153
|
+
} catch (_) { /* no vacío o raíz gestionada */ }
|
|
143
154
|
} catch (err) {
|
|
144
155
|
_emitir(
|
|
145
156
|
{ tipo: 'error', archivo: archivo.destino, mensaje: err.message },
|
package/scripts/doctor.js
CHANGED
|
@@ -31,7 +31,13 @@ async function obtenerVersionRemota() {
|
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
async function doctor(opciones = {}) {
|
|
34
|
-
|
|
34
|
+
// Reparar exige intención EXPLÍCITA (--force). El default previo
|
|
35
|
+
// (`|| !ES_TTY`) auto-reparaba en headless: los reparadores invocan al
|
|
36
|
+
// INSTALADOR contra el cwd — en un checkout del repo eso materializaba
|
|
37
|
+
// copias dentro del fuente, reescribía settings.json y disparaba
|
|
38
|
+
// `git rm --cached` masivo vía limpiarTracked (incidente 2026-07-10,
|
|
39
|
+
// tests/CI). Sin TTY y sin --force: doctor solo DIAGNOSTICA.
|
|
40
|
+
const force = !!opciones.force;
|
|
35
41
|
const cwd = process.cwd();
|
|
36
42
|
|
|
37
43
|
let errores = 0;
|
|
@@ -166,14 +172,37 @@ async function doctor(opciones = {}) {
|
|
|
166
172
|
// en un cwd que no es un proyecto swl. Correr `doctor` desde un directorio
|
|
167
173
|
// cualquiera no debe generar clutter. Marcadores de proyecto: .planning/ o
|
|
168
174
|
// _userland/ ya presentes, o un install-state de scope proyecto.
|
|
169
|
-
|
|
175
|
+
//
|
|
176
|
+
// El HOME es la EXCEPCIÓN: un install global crea ~/_userland ahí, pero el
|
|
177
|
+
// HOME NO es un proyecto — doctor no debe sembrar ~/.planning/ (bug 2026-07-15:
|
|
178
|
+
// sembraba un scaffold espurio y los hooks volcaban telemetría en el HOME vía
|
|
179
|
+
// raiz-proyecto). Ver scripts/lib/limpiar-basura-global.js.
|
|
180
|
+
const { esPlanningEspurio, esUserlandVacio, limpiarBasuraGlobal } = require('./lib/limpiar-basura-global');
|
|
181
|
+
const esHome = path.resolve(cwd) === path.resolve(require('os').homedir());
|
|
182
|
+
const esProyectoSwl = !esHome && (
|
|
170
183
|
fs.existsSync(path.join(cwd, '.planning')) ||
|
|
171
184
|
fs.existsSync(path.join(cwd, '_userland')) ||
|
|
172
|
-
fs.existsSync(path.join(cwd, '.swl-install-state.json'))
|
|
185
|
+
fs.existsSync(path.join(cwd, '.swl-install-state.json'))
|
|
186
|
+
);
|
|
173
187
|
|
|
174
188
|
// 3. Verificar .planning/
|
|
175
189
|
const planningDir = path.join(cwd, '.planning');
|
|
176
|
-
|
|
190
|
+
const basuraHome = [];
|
|
191
|
+
if (esHome && esPlanningEspurio(cwd)) basuraHome.push('~/.planning (scaffold de doctor)');
|
|
192
|
+
if (esHome && esUserlandVacio(cwd)) basuraHome.push('~/_userland (vacío)');
|
|
193
|
+
if (basuraHome.length > 0) {
|
|
194
|
+
// Basura de instalación global en el HOME: NO "reparar" (el HOME no es un
|
|
195
|
+
// proyecto) — OFRECER eliminarla. Ver scripts/lib/limpiar-basura-global.js.
|
|
196
|
+
console.log(formatearAdvertencia('instalación global', `Directorios basura en el HOME: ${basuraHome.join(', ')} — el HOME no es un proyecto`));
|
|
197
|
+
advertencias++;
|
|
198
|
+
reparables.push({
|
|
199
|
+
descripcion: `Eliminar ${basuraHome.length} directorio(s) basura del HOME: ${basuraHome.join(', ')}`,
|
|
200
|
+
reparar: () => {
|
|
201
|
+
const r = limpiarBasuraGlobal({ home: cwd });
|
|
202
|
+
return r.eliminados.length ? `Eliminado: ${r.eliminados.join(', ')}` : 'Nada que eliminar';
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
} else if (fs.existsSync(planningDir)) {
|
|
177
206
|
const archivosEsperados = ['PROYECTO.md', 'REQUISITOS.md', 'HOJA-RUTA.md', 'ESTADO.md'];
|
|
178
207
|
const faltantes = archivosEsperados.filter(
|
|
179
208
|
f => !fs.existsSync(path.join(planningDir, f))
|
|
@@ -337,14 +366,18 @@ async function doctor(opciones = {}) {
|
|
|
337
366
|
});
|
|
338
367
|
}
|
|
339
368
|
if (resultado.incorrectos.length > 0) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
369
|
+
// NO reparar en la fase de diagnóstico: repararHooks muta
|
|
370
|
+
// settings.json. Debe pasar por el gate --force como todo lo
|
|
371
|
+
// demás (incidente 2026-07-10 — reparación no consentida).
|
|
372
|
+
console.log(formatearAdvertencia(`Hooks ${runtime.nombre}`, `${resultado.incorrectos.length} hooks con problemas`));
|
|
373
|
+
advertencias++;
|
|
374
|
+
reparables.push({
|
|
375
|
+
descripcion: `Reparar ${resultado.incorrectos.length} hooks con formato incorrecto en settings.json`,
|
|
376
|
+
reparar: () => {
|
|
377
|
+
const reparacion = repararHooks(settingsPath);
|
|
378
|
+
return `${reparacion.reparados} hooks reparados en settings.json`;
|
|
379
|
+
},
|
|
380
|
+
});
|
|
348
381
|
}
|
|
349
382
|
}
|
|
350
383
|
}
|
|
@@ -683,10 +716,14 @@ async function doctor(opciones = {}) {
|
|
|
683
716
|
console.log('');
|
|
684
717
|
|
|
685
718
|
let proceder = force;
|
|
686
|
-
if (!proceder) {
|
|
719
|
+
if (!proceder && ES_TTY) {
|
|
687
720
|
proceder = await preguntarSiNo('¿Reparar automáticamente?');
|
|
688
721
|
console.log('');
|
|
689
722
|
}
|
|
723
|
+
if (!proceder && !ES_TTY) {
|
|
724
|
+
console.log(` ${color.dim('Modo no interactivo: reparación omitida. Ejecuta `swl-ses doctor --force` para reparar.')}`);
|
|
725
|
+
console.log('');
|
|
726
|
+
}
|
|
690
727
|
|
|
691
728
|
if (proceder) {
|
|
692
729
|
let reparados = 0;
|
|
@@ -1,101 +1,101 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* evidencia-valor.js — CLI `swl-ses valor`: panel de evidencia de valor del
|
|
6
|
-
* harness en el proyecto downstream actual.
|
|
7
|
-
*
|
|
8
|
-
* Uso:
|
|
9
|
-
* swl-ses valor # panel legible (ventana 30 días)
|
|
10
|
-
* swl-ses valor --dias 90 # ventana distinta
|
|
11
|
-
* swl-ses valor --json # salida JSON para tooling
|
|
12
|
-
*
|
|
13
|
-
* Reglas duras del panel (docs/evidencia-valor.md):
|
|
14
|
-
* - Cada métrica declara su PROCEDENCIA (git / GitHub / hook-event) y su
|
|
15
|
-
* CARÁCTER (evidencia | proxy | contexto). Nunca scores autodeclarados.
|
|
16
|
-
* - Todo se lee LOCAL. El repo madre no lee estos datos.
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
const { panelEvidencia } = require('./lib/evidencia-valor.js');
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Contrato del CLI (bin/swl-ses.js): exportar UNA función(opciones) sin
|
|
23
|
-
* efectos al require. Violarlo = "modulo is not a function" tras imprimir
|
|
24
|
-
* el panel (caso real: SIGM, 2026-07-09).
|
|
25
|
-
*/
|
|
26
|
-
function valor(opciones = {}) {
|
|
27
|
-
const json = !!opciones.json;
|
|
28
|
-
const ventanaDias = parseInt(opciones.dias, 10) || 30;
|
|
29
|
-
|
|
30
|
-
const p = panelEvidencia(process.cwd(), { ventanaDias });
|
|
31
|
-
|
|
32
|
-
if (json) {
|
|
33
|
-
console.log(JSON.stringify(p, null, 2));
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
console.log(`Evidencia de valor — ventana ${p.ventanaDias} días (${p.generado})`);
|
|
38
|
-
console.log(` ${p.frontera}`);
|
|
39
|
-
console.log('');
|
|
40
|
-
|
|
41
|
-
const i = p.intercepciones;
|
|
42
|
-
console.log('1. Intercepciones de gates [evidencia · hook-event]');
|
|
43
|
-
if (!i.disponible) {
|
|
44
|
-
console.log(` no disponible — ${i.razon}`);
|
|
45
|
-
} else {
|
|
46
|
-
console.log(` intervenciones: ${i.intervenciones} de ${i.totalEventos} eventos`);
|
|
47
|
-
const tipos = Object.entries(i.porTipo).sort((a, b) => b[1] - a[1]).slice(0, 6);
|
|
48
|
-
for (const [t, n] of tipos) console.log(` - ${t}: ${n}`);
|
|
49
|
-
}
|
|
50
|
-
console.log('');
|
|
51
|
-
|
|
52
|
-
const d = p.defectos;
|
|
53
|
-
console.log('2. Presión de defectos [proxy · git log]');
|
|
54
|
-
if (!d.disponible) {
|
|
55
|
-
console.log(` no disponible — ${d.razon}`);
|
|
56
|
-
} else {
|
|
57
|
-
console.log(` commits: ${d.commits} | fix: ${d.fixes} | feat: ${d.feats} | ratio fix/feat: ${d.ratioFixFeat ?? 'n/a'}`);
|
|
58
|
-
if (d.escapes.disponible) {
|
|
59
|
-
console.log(` escapes: ${d.escapes.fixesTrasUltimaVerificacion} fix tras la última verificación (${d.escapes.ultimaVerificacion}) — ${d.escapes.nota}`);
|
|
60
|
-
} else {
|
|
61
|
-
console.log(` escapes: no disponible — ${d.escapes.razon}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
console.log('');
|
|
65
|
-
|
|
66
|
-
const dc = p.doraCi;
|
|
67
|
-
console.log('3. DORA-lite + CI [evidencia de tendencia · git + GitHub]');
|
|
68
|
-
if (!dc.disponible) {
|
|
69
|
-
console.log(` no disponible — ${dc.razon}`);
|
|
70
|
-
} else {
|
|
71
|
-
const dora = dc.dora;
|
|
72
|
-
const nd = m => `n/d (${(m && m.razon) || 'sin datos'})`;
|
|
73
|
-
const df = dora.deploymentFrequency;
|
|
74
|
-
console.log(` deployment frequency: ${df && df.disponible !== false && df.valor != null ? `${df.valor} deploys/semana [${df.clasificacion}]` : nd(df)}`);
|
|
75
|
-
const lt = dora.leadTime;
|
|
76
|
-
console.log(` lead time: ${lt && lt.disponible !== false && lt.p50Horas != null ? `p50 ${(+lt.p50Horas).toFixed(1)}h / p95 ${(+lt.p95Horas).toFixed(1)}h [${lt.clasificacion}]` : nd(lt)}`);
|
|
77
|
-
const cfr = dora.changeFailureRate;
|
|
78
|
-
console.log(` change failure rate: ${cfr && cfr.disponible !== false && cfr.valor != null ? `${cfr.valor}% [${cfr.clasificacion || ''}]` : nd(cfr)}`);
|
|
79
|
-
const mt = dora.mttr;
|
|
80
|
-
console.log(` mttr: ${mt && mt.disponible !== false && mt.mttrHoras != null ? `${mt.mttrHoras}h` : nd(mt)}`);
|
|
81
|
-
console.log(' (correlación con la adopción del flujo — no causalidad)');
|
|
82
|
-
}
|
|
83
|
-
console.log('');
|
|
84
|
-
|
|
85
|
-
const u = p.uso;
|
|
86
|
-
console.log('4. Uso del sistema [contexto · telemetría]');
|
|
87
|
-
if (!u.disponible) {
|
|
88
|
-
console.log(` no disponible — ${u.razon}`);
|
|
89
|
-
} else {
|
|
90
|
-
console.log(` invocaciones de skills: ${u.invocaciones} | top: ${u.top5.join(', ')}`);
|
|
91
|
-
}
|
|
92
|
-
console.log('');
|
|
93
|
-
console.log('Compartir agregados con el autor (opt-in): swl-ses field-report — ver docs/evidencia-valor.md');
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
module.exports = valor;
|
|
97
|
-
|
|
98
|
-
if (require.main === module) {
|
|
99
|
-
const { parsearOpciones } = require('./lib/parsear-opciones.js');
|
|
100
|
-
valor(parsearOpciones(process.argv.slice(2)));
|
|
101
|
-
}
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* evidencia-valor.js — CLI `swl-ses valor`: panel de evidencia de valor del
|
|
6
|
+
* harness en el proyecto downstream actual.
|
|
7
|
+
*
|
|
8
|
+
* Uso:
|
|
9
|
+
* swl-ses valor # panel legible (ventana 30 días)
|
|
10
|
+
* swl-ses valor --dias 90 # ventana distinta
|
|
11
|
+
* swl-ses valor --json # salida JSON para tooling
|
|
12
|
+
*
|
|
13
|
+
* Reglas duras del panel (docs/evidencia-valor.md):
|
|
14
|
+
* - Cada métrica declara su PROCEDENCIA (git / GitHub / hook-event) y su
|
|
15
|
+
* CARÁCTER (evidencia | proxy | contexto). Nunca scores autodeclarados.
|
|
16
|
+
* - Todo se lee LOCAL. El repo madre no lee estos datos.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
const { panelEvidencia } = require('./lib/evidencia-valor.js');
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Contrato del CLI (bin/swl-ses.js): exportar UNA función(opciones) sin
|
|
23
|
+
* efectos al require. Violarlo = "modulo is not a function" tras imprimir
|
|
24
|
+
* el panel (caso real: SIGM, 2026-07-09).
|
|
25
|
+
*/
|
|
26
|
+
function valor(opciones = {}) {
|
|
27
|
+
const json = !!opciones.json;
|
|
28
|
+
const ventanaDias = parseInt(opciones.dias, 10) || 30;
|
|
29
|
+
|
|
30
|
+
const p = panelEvidencia(process.cwd(), { ventanaDias });
|
|
31
|
+
|
|
32
|
+
if (json) {
|
|
33
|
+
console.log(JSON.stringify(p, null, 2));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
console.log(`Evidencia de valor — ventana ${p.ventanaDias} días (${p.generado})`);
|
|
38
|
+
console.log(` ${p.frontera}`);
|
|
39
|
+
console.log('');
|
|
40
|
+
|
|
41
|
+
const i = p.intercepciones;
|
|
42
|
+
console.log('1. Intercepciones de gates [evidencia · hook-event]');
|
|
43
|
+
if (!i.disponible) {
|
|
44
|
+
console.log(` no disponible — ${i.razon}`);
|
|
45
|
+
} else {
|
|
46
|
+
console.log(` intervenciones: ${i.intervenciones} de ${i.totalEventos} eventos`);
|
|
47
|
+
const tipos = Object.entries(i.porTipo).sort((a, b) => b[1] - a[1]).slice(0, 6);
|
|
48
|
+
for (const [t, n] of tipos) console.log(` - ${t}: ${n}`);
|
|
49
|
+
}
|
|
50
|
+
console.log('');
|
|
51
|
+
|
|
52
|
+
const d = p.defectos;
|
|
53
|
+
console.log('2. Presión de defectos [proxy · git log]');
|
|
54
|
+
if (!d.disponible) {
|
|
55
|
+
console.log(` no disponible — ${d.razon}`);
|
|
56
|
+
} else {
|
|
57
|
+
console.log(` commits: ${d.commits} | fix: ${d.fixes} | feat: ${d.feats} | ratio fix/feat: ${d.ratioFixFeat ?? 'n/a'}`);
|
|
58
|
+
if (d.escapes.disponible) {
|
|
59
|
+
console.log(` escapes: ${d.escapes.fixesTrasUltimaVerificacion} fix tras la última verificación (${d.escapes.ultimaVerificacion}) — ${d.escapes.nota}`);
|
|
60
|
+
} else {
|
|
61
|
+
console.log(` escapes: no disponible — ${d.escapes.razon}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
console.log('');
|
|
65
|
+
|
|
66
|
+
const dc = p.doraCi;
|
|
67
|
+
console.log('3. DORA-lite + CI [evidencia de tendencia · git + GitHub]');
|
|
68
|
+
if (!dc.disponible) {
|
|
69
|
+
console.log(` no disponible — ${dc.razon}`);
|
|
70
|
+
} else {
|
|
71
|
+
const dora = dc.dora;
|
|
72
|
+
const nd = m => `n/d (${(m && m.razon) || 'sin datos'})`;
|
|
73
|
+
const df = dora.deploymentFrequency;
|
|
74
|
+
console.log(` deployment frequency: ${df && df.disponible !== false && df.valor != null ? `${df.valor} deploys/semana [${df.clasificacion}]` : nd(df)}`);
|
|
75
|
+
const lt = dora.leadTime;
|
|
76
|
+
console.log(` lead time: ${lt && lt.disponible !== false && lt.p50Horas != null ? `p50 ${(+lt.p50Horas).toFixed(1)}h / p95 ${(+lt.p95Horas).toFixed(1)}h [${lt.clasificacion}]` : nd(lt)}`);
|
|
77
|
+
const cfr = dora.changeFailureRate;
|
|
78
|
+
console.log(` change failure rate: ${cfr && cfr.disponible !== false && cfr.valor != null ? `${cfr.valor}% [${cfr.clasificacion || ''}]` : nd(cfr)}`);
|
|
79
|
+
const mt = dora.mttr;
|
|
80
|
+
console.log(` mttr: ${mt && mt.disponible !== false && mt.mttrHoras != null ? `${mt.mttrHoras}h` : nd(mt)}`);
|
|
81
|
+
console.log(' (correlación con la adopción del flujo — no causalidad)');
|
|
82
|
+
}
|
|
83
|
+
console.log('');
|
|
84
|
+
|
|
85
|
+
const u = p.uso;
|
|
86
|
+
console.log('4. Uso del sistema [contexto · telemetría]');
|
|
87
|
+
if (!u.disponible) {
|
|
88
|
+
console.log(` no disponible — ${u.razon}`);
|
|
89
|
+
} else {
|
|
90
|
+
console.log(` invocaciones de skills: ${u.invocaciones} | top: ${u.top5.join(', ')}`);
|
|
91
|
+
}
|
|
92
|
+
console.log('');
|
|
93
|
+
console.log('Compartir agregados con el autor (opt-in): swl-ses field-report — ver docs/evidencia-valor.md');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
module.exports = valor;
|
|
97
|
+
|
|
98
|
+
if (require.main === module) {
|
|
99
|
+
const { parsearOpciones } = require('./lib/parsear-opciones.js');
|
|
100
|
+
valor(parsearOpciones(process.argv.slice(2)));
|
|
101
|
+
}
|
package/scripts/field-report.js
CHANGED
|
@@ -196,20 +196,20 @@ function generarReporte() {
|
|
|
196
196
|
console.log(`\n> Generado por \`node scripts/field-report.js\``);
|
|
197
197
|
}
|
|
198
198
|
|
|
199
|
-
function fieldReport(opciones = {}) {
|
|
200
|
-
DAYS = parseInt(opciones.days || opciones.dias, 10) || 0;
|
|
201
|
-
PROJECT = opciones.project || null;
|
|
202
|
-
OUTPUT = opciones.output || 'md';
|
|
203
|
-
generarReporte();
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
module.exports = fieldReport;
|
|
207
|
-
|
|
208
|
-
if (require.main === module) {
|
|
209
|
-
const args = process.argv.slice(2).reduce((acc, arg) => {
|
|
210
|
-
const [k, v] = arg.replace(/^--/, '').split('=');
|
|
211
|
-
acc[k] = v || true;
|
|
212
|
-
return acc;
|
|
213
|
-
}, {});
|
|
214
|
-
fieldReport(args);
|
|
199
|
+
function fieldReport(opciones = {}) {
|
|
200
|
+
DAYS = parseInt(opciones.days || opciones.dias, 10) || 0;
|
|
201
|
+
PROJECT = opciones.project || null;
|
|
202
|
+
OUTPUT = opciones.output || 'md';
|
|
203
|
+
generarReporte();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
module.exports = fieldReport;
|
|
207
|
+
|
|
208
|
+
if (require.main === module) {
|
|
209
|
+
const args = process.argv.slice(2).reduce((acc, arg) => {
|
|
210
|
+
const [k, v] = arg.replace(/^--/, '').split('=');
|
|
211
|
+
acc[k] = v || true;
|
|
212
|
+
return acc;
|
|
213
|
+
}, {});
|
|
214
|
+
fieldReport(args);
|
|
215
215
|
}
|