@saulwade/swl-ses 2.6.1 → 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 +14 -2
- package/README.md +65 -18
- package/agentes/_intent-spec.md +73 -73
- package/agentes/_propose-step.md +90 -90
- package/bin/swl-ses.js +10 -0
- package/comandos/swl/brainstorm.md +1 -0
- package/comandos/swl/briefing.md +119 -119
- package/comandos/swl/contribuir.md +233 -233
- package/comandos/swl/deuda-codigo.md +97 -97
- package/comandos/swl/mcp-status.md +1 -0
- package/gateway/lib/event-channel.js +191 -191
- package/habilidades/agent-deep-links/SKILL.md +148 -148
- package/habilidades/backend-async-postgres-testing/SKILL.md +216 -216
- 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/checklist-seguridad/recursos/stride-cobertura.md +60 -60
- package/habilidades/ci-cd-pipelines/SKILL.md +5 -1
- package/habilidades/css-moderno/SKILL.md +7 -1
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +57 -57
- package/habilidades/extractor-de-aprendizajes/SKILL.md +5 -1
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
- package/habilidades/harness-claude-code/SKILL.md +3 -2
- 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/prevencion-sobreingenieria/recursos/EXAMPLES.md +580 -580
- 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-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-intent-engineering/SKILL.md +269 -269
- package/habilidades/proceso-modular-split/SKILL.md +256 -256
- 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/recursos/gherkin-bdd.md +111 -111
- package/hooks/calidad-pre-commit.js +159 -10
- package/hooks/ciclo-evolucion-subagente.js +26 -26
- package/hooks/ciclo-evolucion.js +26 -26
- package/hooks/contexto-subagente.js +68 -68
- package/hooks/lib/auto-consolidator.js +335 -335
- 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/notificacion-formato.js +45 -11
- package/hooks/lib/provenance-tracker.js +191 -191
- package/hooks/lib/raiz-proyecto.js +35 -4
- 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/toon-compressor.js +245 -245
- package/hooks/notificacion-telegram.js +5 -11
- package/hooks/session-briefing.js +12 -4
- package/instintos/autonomia.yaml +27 -27
- package/instintos/prompt-appendices.yaml +57 -57
- package/llms.txt +1 -1
- package/manifiestos/agent-output-schemas.json +57 -57
- package/manifiestos/canonical-hashes.json +662 -0
- package/manifiestos/harness-ir.json +47536 -0
- package/manifiestos/hooks-config.json +469 -469
- package/manifiestos/invariantes-criticos.json +30 -30
- 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 +43 -43
- package/package.json +2 -2
- 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 +2 -2
- 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/bootstrap-instintos.js +3 -0
- 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/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/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/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 -36
- 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 +26 -7
- 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/yaml-instintos.js +56 -0
- 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/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 +45 -2
- 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/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/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 +12 -7
- 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
|
@@ -1,151 +1,151 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* detectar-aprendizajes-duplicados.js
|
|
6
|
-
*
|
|
7
|
-
* Detecta pares de entradas en `.planning/APRENDIZAJES.md` con alta similitud
|
|
8
|
-
* de tokens (Jaccard > umbral). Útil para identificar candidatos a fusionar
|
|
9
|
-
* cuando el hook de auto-extracción genera entradas redundantes.
|
|
10
|
-
*
|
|
11
|
-
* Patrón adoptado de `temp/agentmemory-main/src/functions/auto-forget.ts`
|
|
12
|
-
* (contradiction detection con Jaccard >= 0.9). Aquí se usa con threshold
|
|
13
|
-
* configurable más bajo (0.6 default) porque queremos sugerir, no auto-borrar.
|
|
14
|
-
*
|
|
15
|
-
* NO modifica APRENDIZAJES.md. Solo reporta. La acción de fusión queda en
|
|
16
|
-
* manos del usuario o de un comando separado (`/swl:aprender consolidar`).
|
|
17
|
-
*
|
|
18
|
-
* Uso:
|
|
19
|
-
* node scripts/detectar-aprendizajes-duplicados.js [threshold]
|
|
20
|
-
*
|
|
21
|
-
* Argumentos:
|
|
22
|
-
* threshold - Similitud mínima para reportar (default: 0.6, rango [0, 1]).
|
|
23
|
-
*
|
|
24
|
-
* Exit codes:
|
|
25
|
-
* 0 - Ejecución OK (haya o no duplicados)
|
|
26
|
-
* 1 - Error de I/O o parseo
|
|
27
|
-
*
|
|
28
|
-
* Output: tabla legible en stdout. Si se detectan ≥ 1 duplicados, también
|
|
29
|
-
* imprime sugerencia para revisar/consolidar.
|
|
30
|
-
*/
|
|
31
|
-
|
|
32
|
-
const fs = require('fs');
|
|
33
|
-
const path = require('path');
|
|
34
|
-
|
|
35
|
-
const { tokenize, jaccard } = require('./lib/jaccard-similarity');
|
|
36
|
-
|
|
37
|
-
const RUTA_APRENDIZAJES = path.join(process.cwd(), '.planning', 'APRENDIZAJES.md');
|
|
38
|
-
const DEFAULT_THRESHOLD = 0.6;
|
|
39
|
-
const MAX_PARES_REPORTADOS = 30;
|
|
40
|
-
|
|
41
|
-
function parsearEntradas(contenido) {
|
|
42
|
-
const lineas = contenido.split('\n');
|
|
43
|
-
const entradas = [];
|
|
44
|
-
let actual = null;
|
|
45
|
-
|
|
46
|
-
for (let i = 0; i < lineas.length; i++) {
|
|
47
|
-
const linea = lineas[i];
|
|
48
|
-
if (linea.startsWith('## ')) {
|
|
49
|
-
if (actual) entradas.push(actual);
|
|
50
|
-
actual = {
|
|
51
|
-
lineaInicio: i + 1,
|
|
52
|
-
titulo: linea.slice(3).trim(),
|
|
53
|
-
contenido: '',
|
|
54
|
-
};
|
|
55
|
-
} else if (actual) {
|
|
56
|
-
actual.contenido += linea + '\n';
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
if (actual) entradas.push(actual);
|
|
60
|
-
|
|
61
|
-
// Filtrar entradas vacías o triviales (< 50 chars de contenido real)
|
|
62
|
-
return entradas.filter(e => e.contenido.replace(/\s/g, '').length >= 50);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function detectarDuplicados(entradas, threshold) {
|
|
66
|
-
const tokensCache = entradas.map(e => tokenize(e.titulo + ' ' + e.contenido));
|
|
67
|
-
const pares = [];
|
|
68
|
-
|
|
69
|
-
for (let i = 0; i < entradas.length; i++) {
|
|
70
|
-
for (let j = i + 1; j < entradas.length; j++) {
|
|
71
|
-
const sim = jaccard(tokensCache[i], tokensCache[j]);
|
|
72
|
-
if (sim >= threshold) {
|
|
73
|
-
pares.push({
|
|
74
|
-
entradaA: entradas[i],
|
|
75
|
-
entradaB: entradas[j],
|
|
76
|
-
similitud: sim,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
pares.sort((a, b) => b.similitud - a.similitud);
|
|
83
|
-
return pares;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function reportarTexto(pares) {
|
|
87
|
-
if (pares.length === 0) {
|
|
88
|
-
console.log('Sin duplicados detectados sobre el umbral.');
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
console.log(`Pares con similitud Jaccard ≥ umbral: ${pares.length}`);
|
|
93
|
-
console.log('');
|
|
94
|
-
|
|
95
|
-
const limite = Math.min(pares.length, MAX_PARES_REPORTADOS);
|
|
96
|
-
for (let i = 0; i < limite; i++) {
|
|
97
|
-
const p = pares[i];
|
|
98
|
-
console.log(` [${(p.similitud * 100).toFixed(1)}%] ` +
|
|
99
|
-
`L${p.entradaA.lineaInicio} ↔ L${p.entradaB.lineaInicio}`);
|
|
100
|
-
console.log(' A: ' + p.entradaA.titulo.slice(0, 80));
|
|
101
|
-
console.log(' B: ' + p.entradaB.titulo.slice(0, 80));
|
|
102
|
-
console.log('');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (pares.length > limite) {
|
|
106
|
-
console.log(` ... ${pares.length - limite} pares adicionales no mostrados`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
console.log('Sugerencia: revisa los pares con mayor similitud y considera ' +
|
|
110
|
-
'fusionarlos en una sola entrada con `/swl:aprender consolidar` o manualmente.');
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function main() {
|
|
114
|
-
const threshold = parseFloat(process.argv[2]) || DEFAULT_THRESHOLD;
|
|
115
|
-
|
|
116
|
-
if (!Number.isFinite(threshold) || threshold < 0 || threshold > 1) {
|
|
117
|
-
console.error(`Threshold inválido: ${process.argv[2]}. Usar valor en [0, 1].`);
|
|
118
|
-
process.exit(1);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
if (!fs.existsSync(RUTA_APRENDIZAJES)) {
|
|
122
|
-
console.error(`No existe ${RUTA_APRENDIZAJES}.`);
|
|
123
|
-
process.exit(1);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
let contenido;
|
|
127
|
-
try {
|
|
128
|
-
contenido = fs.readFileSync(RUTA_APRENDIZAJES, 'utf8');
|
|
129
|
-
} catch (err) {
|
|
130
|
-
console.error(`Error leyendo ${RUTA_APRENDIZAJES}: ${err.message}`);
|
|
131
|
-
process.exit(1);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const entradas = parsearEntradas(contenido);
|
|
135
|
-
console.log(`Entradas encontradas: ${entradas.length}`);
|
|
136
|
-
console.log(`Threshold de similitud: ${threshold}`);
|
|
137
|
-
console.log('');
|
|
138
|
-
|
|
139
|
-
const pares = detectarDuplicados(entradas, threshold);
|
|
140
|
-
reportarTexto(pares);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (require.main === module) {
|
|
144
|
-
main();
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
module.exports = {
|
|
148
|
-
parsearEntradas,
|
|
149
|
-
detectarDuplicados,
|
|
150
|
-
reportarTexto,
|
|
151
|
-
};
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* detectar-aprendizajes-duplicados.js
|
|
6
|
+
*
|
|
7
|
+
* Detecta pares de entradas en `.planning/APRENDIZAJES.md` con alta similitud
|
|
8
|
+
* de tokens (Jaccard > umbral). Útil para identificar candidatos a fusionar
|
|
9
|
+
* cuando el hook de auto-extracción genera entradas redundantes.
|
|
10
|
+
*
|
|
11
|
+
* Patrón adoptado de `temp/agentmemory-main/src/functions/auto-forget.ts`
|
|
12
|
+
* (contradiction detection con Jaccard >= 0.9). Aquí se usa con threshold
|
|
13
|
+
* configurable más bajo (0.6 default) porque queremos sugerir, no auto-borrar.
|
|
14
|
+
*
|
|
15
|
+
* NO modifica APRENDIZAJES.md. Solo reporta. La acción de fusión queda en
|
|
16
|
+
* manos del usuario o de un comando separado (`/swl:aprender consolidar`).
|
|
17
|
+
*
|
|
18
|
+
* Uso:
|
|
19
|
+
* node scripts/detectar-aprendizajes-duplicados.js [threshold]
|
|
20
|
+
*
|
|
21
|
+
* Argumentos:
|
|
22
|
+
* threshold - Similitud mínima para reportar (default: 0.6, rango [0, 1]).
|
|
23
|
+
*
|
|
24
|
+
* Exit codes:
|
|
25
|
+
* 0 - Ejecución OK (haya o no duplicados)
|
|
26
|
+
* 1 - Error de I/O o parseo
|
|
27
|
+
*
|
|
28
|
+
* Output: tabla legible en stdout. Si se detectan ≥ 1 duplicados, también
|
|
29
|
+
* imprime sugerencia para revisar/consolidar.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const fs = require('fs');
|
|
33
|
+
const path = require('path');
|
|
34
|
+
|
|
35
|
+
const { tokenize, jaccard } = require('./lib/jaccard-similarity');
|
|
36
|
+
|
|
37
|
+
const RUTA_APRENDIZAJES = path.join(process.cwd(), '.planning', 'APRENDIZAJES.md');
|
|
38
|
+
const DEFAULT_THRESHOLD = 0.6;
|
|
39
|
+
const MAX_PARES_REPORTADOS = 30;
|
|
40
|
+
|
|
41
|
+
function parsearEntradas(contenido) {
|
|
42
|
+
const lineas = contenido.split('\n');
|
|
43
|
+
const entradas = [];
|
|
44
|
+
let actual = null;
|
|
45
|
+
|
|
46
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
47
|
+
const linea = lineas[i];
|
|
48
|
+
if (linea.startsWith('## ')) {
|
|
49
|
+
if (actual) entradas.push(actual);
|
|
50
|
+
actual = {
|
|
51
|
+
lineaInicio: i + 1,
|
|
52
|
+
titulo: linea.slice(3).trim(),
|
|
53
|
+
contenido: '',
|
|
54
|
+
};
|
|
55
|
+
} else if (actual) {
|
|
56
|
+
actual.contenido += linea + '\n';
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (actual) entradas.push(actual);
|
|
60
|
+
|
|
61
|
+
// Filtrar entradas vacías o triviales (< 50 chars de contenido real)
|
|
62
|
+
return entradas.filter(e => e.contenido.replace(/\s/g, '').length >= 50);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function detectarDuplicados(entradas, threshold) {
|
|
66
|
+
const tokensCache = entradas.map(e => tokenize(e.titulo + ' ' + e.contenido));
|
|
67
|
+
const pares = [];
|
|
68
|
+
|
|
69
|
+
for (let i = 0; i < entradas.length; i++) {
|
|
70
|
+
for (let j = i + 1; j < entradas.length; j++) {
|
|
71
|
+
const sim = jaccard(tokensCache[i], tokensCache[j]);
|
|
72
|
+
if (sim >= threshold) {
|
|
73
|
+
pares.push({
|
|
74
|
+
entradaA: entradas[i],
|
|
75
|
+
entradaB: entradas[j],
|
|
76
|
+
similitud: sim,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
pares.sort((a, b) => b.similitud - a.similitud);
|
|
83
|
+
return pares;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function reportarTexto(pares) {
|
|
87
|
+
if (pares.length === 0) {
|
|
88
|
+
console.log('Sin duplicados detectados sobre el umbral.');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log(`Pares con similitud Jaccard ≥ umbral: ${pares.length}`);
|
|
93
|
+
console.log('');
|
|
94
|
+
|
|
95
|
+
const limite = Math.min(pares.length, MAX_PARES_REPORTADOS);
|
|
96
|
+
for (let i = 0; i < limite; i++) {
|
|
97
|
+
const p = pares[i];
|
|
98
|
+
console.log(` [${(p.similitud * 100).toFixed(1)}%] ` +
|
|
99
|
+
`L${p.entradaA.lineaInicio} ↔ L${p.entradaB.lineaInicio}`);
|
|
100
|
+
console.log(' A: ' + p.entradaA.titulo.slice(0, 80));
|
|
101
|
+
console.log(' B: ' + p.entradaB.titulo.slice(0, 80));
|
|
102
|
+
console.log('');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (pares.length > limite) {
|
|
106
|
+
console.log(` ... ${pares.length - limite} pares adicionales no mostrados`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
console.log('Sugerencia: revisa los pares con mayor similitud y considera ' +
|
|
110
|
+
'fusionarlos en una sola entrada con `/swl:aprender consolidar` o manualmente.');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function main() {
|
|
114
|
+
const threshold = parseFloat(process.argv[2]) || DEFAULT_THRESHOLD;
|
|
115
|
+
|
|
116
|
+
if (!Number.isFinite(threshold) || threshold < 0 || threshold > 1) {
|
|
117
|
+
console.error(`Threshold inválido: ${process.argv[2]}. Usar valor en [0, 1].`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!fs.existsSync(RUTA_APRENDIZAJES)) {
|
|
122
|
+
console.error(`No existe ${RUTA_APRENDIZAJES}.`);
|
|
123
|
+
process.exit(1);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
let contenido;
|
|
127
|
+
try {
|
|
128
|
+
contenido = fs.readFileSync(RUTA_APRENDIZAJES, 'utf8');
|
|
129
|
+
} catch (err) {
|
|
130
|
+
console.error(`Error leyendo ${RUTA_APRENDIZAJES}: ${err.message}`);
|
|
131
|
+
process.exit(1);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const entradas = parsearEntradas(contenido);
|
|
135
|
+
console.log(`Entradas encontradas: ${entradas.length}`);
|
|
136
|
+
console.log(`Threshold de similitud: ${threshold}`);
|
|
137
|
+
console.log('');
|
|
138
|
+
|
|
139
|
+
const pares = detectarDuplicados(entradas, threshold);
|
|
140
|
+
reportarTexto(pares);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (require.main === module) {
|
|
144
|
+
main();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
module.exports = {
|
|
148
|
+
parsearEntradas,
|
|
149
|
+
detectarDuplicados,
|
|
150
|
+
reportarTexto,
|
|
151
|
+
};
|
package/scripts/doctor.js
CHANGED
|
@@ -168,41 +168,41 @@ async function doctor(opciones = {}) {
|
|
|
168
168
|
advertencias++;
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
// C-2: doctor DIAGNOSTICA
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
//
|
|
175
|
-
//
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
179
|
-
//
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
// 3. Verificar .planning/
|
|
171
|
+
// C-2: doctor DIAGNOSTICA según la CLASE del directorio (clasificar-directorio):
|
|
172
|
+
// - 'home' : ubicación de una instalación global, NUNCA un proyecto. Un
|
|
173
|
+
// ~/.planning (backups del install, scaffold de doctor,
|
|
174
|
+
// telemetría mal dirigida) o ~/_userland vacío es basura →
|
|
175
|
+
// OFRECER eliminar, jamás scaffoldear marcadores.
|
|
176
|
+
// - 'proyecto' : proyecto de desarrollo real (.git/stack/.planning) →
|
|
177
|
+
// verificar/reparar/inicializar la estructura .planning.
|
|
178
|
+
// - 'nuevo'/'otro' : no scaffoldear a ciegas — "No aplica".
|
|
179
|
+
// Origen del rediseño (bug 2026-07-15): `install --global` desde el HOME
|
|
180
|
+
// sembraba ~/.planning/backups y doctor ofrecía scaffoldear marcadores ahí.
|
|
181
|
+
const { clasificarDirectorio } = require('./lib/clasificar-directorio');
|
|
182
|
+
const { esUserlandVacio, esPlanningRemovibleEnHome, limpiarBasuraGlobal } = require('./lib/limpiar-basura-global');
|
|
183
|
+
const claseDir = clasificarDirectorio(cwd);
|
|
184
|
+
const esProyectoSwl = claseDir === 'proyecto'; // consumido también por la sección 4 (_userland)
|
|
185
|
+
|
|
186
|
+
// 3. Verificar .planning/ según la clase del directorio
|
|
189
187
|
const planningDir = path.join(cwd, '.planning');
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
|
|
188
|
+
if (claseDir === 'home') {
|
|
189
|
+
const basura = [];
|
|
190
|
+
if (esPlanningRemovibleEnHome(cwd)) basura.push('~/.planning');
|
|
191
|
+
if (esUserlandVacio(cwd)) basura.push('~/_userland (vacío)');
|
|
192
|
+
if (basura.length > 0) {
|
|
193
|
+
console.log(formatearAdvertencia('instalación global', `Directorios basura en el HOME: ${basura.join(', ')} — el HOME no es un proyecto`));
|
|
194
|
+
advertencias++;
|
|
195
|
+
reparables.push({
|
|
196
|
+
descripcion: `Eliminar del HOME: ${basura.join(', ')}`,
|
|
197
|
+
reparar: () => {
|
|
198
|
+
const r = limpiarBasuraGlobal({ home: cwd });
|
|
199
|
+
return r.eliminados.length ? `Eliminado: ${r.eliminados.join(', ')}` : 'Nada que eliminar';
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
} else {
|
|
203
|
+
console.log(formatearPaso('.planning/', 'No aplica — el HOME es la ubicación de instalación global, no un proyecto'));
|
|
204
|
+
}
|
|
205
|
+
} else if (claseDir === 'proyecto' && fs.existsSync(planningDir)) {
|
|
206
206
|
const archivosEsperados = ['PROYECTO.md', 'REQUISITOS.md', 'HOJA-RUTA.md', 'ESTADO.md'];
|
|
207
207
|
const faltantes = archivosEsperados.filter(
|
|
208
208
|
f => !fs.existsSync(path.join(planningDir, f))
|
|
@@ -261,9 +261,10 @@ async function doctor(opciones = {}) {
|
|
|
261
261
|
});
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
// 4. Verificar _userland/
|
|
264
|
+
// 4. Verificar _userland/ (solo relevante en un proyecto de desarrollo; en el
|
|
265
|
+
// HOME un _userland vacío ya se ofreció eliminar en la sección 3).
|
|
265
266
|
const userlandDir = path.join(cwd, '_userland');
|
|
266
|
-
if (fs.existsSync(userlandDir)) {
|
|
267
|
+
if (claseDir === 'proyecto' && fs.existsSync(userlandDir)) {
|
|
267
268
|
console.log(formatearPaso('_userland/', 'Presente'));
|
|
268
269
|
ok++;
|
|
269
270
|
|
|
@@ -694,6 +695,30 @@ async function doctor(opciones = {}) {
|
|
|
694
695
|
}
|
|
695
696
|
}
|
|
696
697
|
|
|
698
|
+
// X. Diagnóstico Core-3 (Claude Code, Codex CLI, Gemini CLI) — F31-T07.
|
|
699
|
+
// Puramente informativo: read-only, best-effort, nunca repara ni evalúa
|
|
700
|
+
// canarios conductuales. Disponibilidad != certificación (ADR-0047); por
|
|
701
|
+
// eso no suma a ok/advertencias/errores — un runtime experimental ausente
|
|
702
|
+
// no es un problema de instalación de SWL.
|
|
703
|
+
try {
|
|
704
|
+
const { diagnosticarCore3 } = require('./lib/runtime-doctor-core3');
|
|
705
|
+
const { pathEntriesFromEnv, emptyRuntimeMap } = require('./lib/runtime-doctor-input');
|
|
706
|
+
const diagnosticoCore3 = await diagnosticarCore3({
|
|
707
|
+
now: new Date().toISOString(),
|
|
708
|
+
pathEntries: pathEntriesFromEnv(),
|
|
709
|
+
bundles: emptyRuntimeMap(),
|
|
710
|
+
buildEvents: emptyRuntimeMap(),
|
|
711
|
+
});
|
|
712
|
+
console.log(formatearPaso('Runtimes Core-3', 'experimental/unverified — `swl-ses runtime-doctor --json` para detalle'));
|
|
713
|
+
for (const runtime of diagnosticoCore3.runtimes) {
|
|
714
|
+
const detalle = runtime.availability.status === 'available'
|
|
715
|
+
? `available v${runtime.availability.version}`
|
|
716
|
+
: runtime.availability.status;
|
|
717
|
+
console.log(` ${color.dim(`${runtime.runtimeId}: ${detalle}`)}`);
|
|
718
|
+
}
|
|
719
|
+
console.log('');
|
|
720
|
+
} catch { /* nunca bloquear el doctor por este check */ }
|
|
721
|
+
|
|
697
722
|
// Reporte final
|
|
698
723
|
console.log('');
|
|
699
724
|
console.log(` ${lineaSeparadora()}`);
|