@saulwade/swl-ses 1.4.1 → 1.5.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 +3 -3
- package/README.md +561 -560
- package/agentes/nemesis-auditor-swl.md +161 -161
- package/bin/swl-mcp-server.js +49 -22
- package/bin/swl-ses.js +74 -0
- package/comandos/swl/.evolved.json +22 -22
- package/comandos/swl/contribuir.md +233 -233
- package/comandos/swl/ejecutar-fase.md +33 -4
- package/comandos/swl/metricas.md +72 -0
- package/comandos/swl/nemesis.md +122 -122
- package/gateway/lib/event-channel.js +191 -191
- package/habilidades/backend-production-resilience/SKILL.md +288 -288
- package/habilidades/benchmark-memoria/SKILL.md +186 -186
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/discutir-fase/SKILL.md +50 -2
- package/habilidades/doubt-driven-review/SKILL.md +171 -171
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -0
- package/habilidades/eval-framework/SKILL.md +212 -212
- package/habilidades/feynman-auditor-swl/SKILL.md +123 -123
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -108
- package/habilidades/harness-claude-code/SKILL.md +299 -299
- package/habilidades/infra-github-actions/SKILL.md +166 -166
- package/habilidades/legacy-code-rescue/SKILL.md +267 -267
- package/habilidades/manejo-errores/.evolved.json +8 -8
- package/habilidades/meta-skills-estandar/recursos/convencion-examples.md +93 -93
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -163
- package/habilidades/patrones-python/SKILL.md +229 -229
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -469
- package/habilidades/planear-fase/SKILL.md +319 -319
- package/habilidades/protocolo-revision-swl/SKILL.md +276 -0
- package/habilidades/release-semver/.evolved.json +8 -8
- package/habilidades/state-inconsistency-auditor-swl/SKILL.md +166 -166
- package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -147
- package/habilidades/testing-python/SKILL.md +340 -340
- package/habilidades/verificar-trabajo/SKILL.md +49 -5
- package/habilidades/web-fetcher-routing/SKILL.md +75 -75
- package/hooks/claudemd-bloat-detector.js +161 -161
- package/hooks/lib/agent-routing.js +107 -107
- package/hooks/lib/auto-consolidator.js +335 -335
- package/hooks/lib/error-classifier.js +308 -308
- package/hooks/lib/merkle-audit.js +96 -96
- 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/toon-compressor.js +245 -245
- package/hooks/registro-turnos.js +209 -209
- package/hooks/sugerir-regenerar-inventario.js +170 -170
- package/hooks/validar-formato-post-subagente.js +140 -140
- package/hooks/validar-memoria-hook.js +218 -218
- package/instintos/prompt-appendices.yaml +57 -57
- package/manifiestos/agent-output-schemas.json +57 -57
- package/manifiestos/modulos.json +1321 -1262
- package/manifiestos/perfiles.json +2 -1
- package/manifiestos/skills-lock.json +1114 -1114
- package/package.json +3 -3
- 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 +351 -343
- package/reglas/analisis-previo-tareas-grandes.md +172 -172
- package/reglas/arreglar-al-detectar.md +147 -147
- package/reglas/fragmentos-compartidos.md +152 -152
- package/reglas/harness-claude-code.md +213 -213
- package/reglas/usar-context7.md +226 -226
- package/schemas/diary-entry.schema.json +80 -80
- 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/configurar-branch-protection.js +418 -418
- package/scripts/derivar-feature-list.js +489 -0
- package/scripts/detectar-aprendizajes-duplicados.js +151 -151
- package/scripts/doctor.js +31 -4
- package/scripts/field-report.js +199 -199
- package/scripts/generar-checklists-consolidados.js +273 -273
- package/scripts/generar-inventario.js +420 -420
- package/scripts/generar-matriz-lenguajes.js +271 -271
- package/scripts/instalador.js +56 -5
- 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/configurar-ci.js +380 -380
- package/scripts/lib/contadores-inventario.js +217 -217
- package/scripts/lib/detectar-runtime.js +75 -9
- package/scripts/lib/detectar-stack-detallado.js +307 -307
- package/scripts/lib/diary-entry.js +234 -234
- package/scripts/lib/estado.js +13 -1
- 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/expandir-targets.js +71 -0
- package/scripts/lib/jaccard-similarity.js +98 -98
- package/scripts/lib/longmemeval-runner.js +125 -125
- package/scripts/lib/manifiestos.js +42 -1
- package/scripts/lib/npm-version.js +261 -261
- package/scripts/lib/paquetes-conocidos.js +50 -50
- package/scripts/lib/parsear-opciones.js +3 -0
- package/scripts/lib/prompt-builder.js +264 -264
- package/scripts/lib/rrf-fusion.js +175 -175
- package/scripts/lib/scoring-instintos.js +277 -277
- package/scripts/lib/semantic-search.js +252 -252
- package/scripts/lib/toml-merge.js +204 -0
- package/scripts/lib/transformadores/base.js +43 -9
- package/scripts/lib/transformadores/codex.js +375 -115
- package/scripts/lib/transformadores/cursor.js +359 -0
- package/scripts/lib/transformadores/index.js +2 -0
- package/scripts/limpiar-artefactos-python.js +131 -131
- package/scripts/mcp-server/README.md +122 -80
- package/scripts/mcp-server/auth.js +105 -0
- package/scripts/mcp-server/cache.js +106 -0
- package/scripts/mcp-server/handlers.js +386 -206
- package/scripts/mcp-server/telemetry.js +78 -0
- package/scripts/migrar-csv-a-array.js +168 -168
- package/scripts/migrar-fase-dominio.js +201 -201
- package/scripts/publicar.js +511 -511
- package/scripts/run-eval.js +141 -141
- package/scripts/validar-manifest.js +231 -195
- package/scripts/validar-userland-vacio.js +110 -110
|
@@ -1,217 +1,217 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* contadores-inventario.js
|
|
5
|
-
*
|
|
6
|
-
* Funciones puras zero-deps para validar consistencia entre los contadores
|
|
7
|
-
* de inventario (agentes, skills, comandos, hooks, reglas) declarados en
|
|
8
|
-
* `INVENTARIO.md` (fuente de verdad regenerada por
|
|
9
|
-
* `scripts/generar-inventario.js`) y los contadores citados en los demás
|
|
10
|
-
* documentos canónicos del repositorio.
|
|
11
|
-
*
|
|
12
|
-
* Motivado por el drift recurrente detectado el 2026-04-29: MAPEO_SKILLS_AGENTES.md
|
|
13
|
-
* decía "153 skills" cuando la realidad eran 150; COMPACTACION.md reportaba
|
|
14
|
-
* "147 skills, 40 comandos, 31 hooks". El hook `verificar-release.js` valida
|
|
15
|
-
* versión pero no contadores. Este módulo cierra ese hueco.
|
|
16
|
-
*
|
|
17
|
-
* Cobertura intencional:
|
|
18
|
-
* - Patrón resumen "X agentes, Y skills, Z comandos, W reglas, V hooks"
|
|
19
|
-
* (separadores `,` o `+` o `y`) — valida los 5 números a la vez.
|
|
20
|
-
* - Patrón "X agentes + Y habilidades + Z comandos + W reglas + V hooks"
|
|
21
|
-
* común en tablas de perfiles `completo`.
|
|
22
|
-
* - Patrón "Total de agentes: X" / "Total de skills: X" en MAPEO.
|
|
23
|
-
*
|
|
24
|
-
* Cobertura intencionalmente excluida (falsos positivos clásicos):
|
|
25
|
-
* - "los 17 skills de Anthropic" (skills externos)
|
|
26
|
-
* - "8 lenguajes × 5 reglas" (multiplicación)
|
|
27
|
-
* - perfiles parciales "2 hooks", "6 hooks" (no son totales)
|
|
28
|
-
* - notas históricas "estimé 28 hooks visualmente y propagué el error"
|
|
29
|
-
* - referencias a versiones pasadas en MAPEO ("136 skills tras release X")
|
|
30
|
-
* - filas de tabla histórica con SemVer + fecha ("| 5.4.0 | 2026-04-10 | 57 agentes...")
|
|
31
|
-
*
|
|
32
|
-
* Estas se ignoran porque el patrón resumen es el único que tiene los 5
|
|
33
|
-
* componentes alineados; las menciones aisladas de un solo número se dejan
|
|
34
|
-
* para una auditoría aparte (no bloqueante).
|
|
35
|
-
*/
|
|
36
|
-
|
|
37
|
-
const COMPONENTES = ['agentes', 'skills', 'comandos', 'hooks', 'reglas'];
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* Parsea la sección "## Resumen" de INVENTARIO.md y retorna un mapa con
|
|
41
|
-
* los contadores reales del sistema.
|
|
42
|
-
*
|
|
43
|
-
* Espera tabla del tipo:
|
|
44
|
-
* ## Resumen
|
|
45
|
-
* | Componente | Cantidad |
|
|
46
|
-
* |-----------|----------|
|
|
47
|
-
* | Agentes SWL | 59 |
|
|
48
|
-
* | Habilidades | 150 |
|
|
49
|
-
* | Comandos | 41 |
|
|
50
|
-
* | Reglas base | 20 |
|
|
51
|
-
* | Reglas por lenguaje | 40 |
|
|
52
|
-
* | Hooks | 36 |
|
|
53
|
-
*
|
|
54
|
-
* Retorna `{ agentes, skills, comandos, hooks, reglas }`.
|
|
55
|
-
* `skills` y `habilidades` se mapean al mismo número.
|
|
56
|
-
* `reglas` = base + por_lenguaje.
|
|
57
|
-
*/
|
|
58
|
-
function parsearInventario(rawMd) {
|
|
59
|
-
const lineas = rawMd.split(/\r?\n/);
|
|
60
|
-
const resumen = {};
|
|
61
|
-
let enResumen = false;
|
|
62
|
-
for (const linea of lineas) {
|
|
63
|
-
if (/^##\s+Resumen\s*$/.test(linea)) { enResumen = true; continue; }
|
|
64
|
-
if (enResumen && /^##\s+/.test(linea)) break;
|
|
65
|
-
if (!enResumen) continue;
|
|
66
|
-
const m = linea.match(/^\|\s*([^|]+?)\s*\|\s*(\d+)\s*\|/);
|
|
67
|
-
if (m) resumen[m[1].trim()] = parseInt(m[2], 10);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const reglasBase = resumen['Reglas base'] || 0;
|
|
71
|
-
const reglasLeng = resumen['Reglas por lenguaje'] || 0;
|
|
72
|
-
|
|
73
|
-
return {
|
|
74
|
-
agentes: resumen['Agentes SWL'] || 0,
|
|
75
|
-
skills: resumen['Habilidades'] || 0,
|
|
76
|
-
comandos: resumen['Comandos'] || 0,
|
|
77
|
-
hooks: resumen['Hooks'] || 0,
|
|
78
|
-
reglas: reglasBase + reglasLeng,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Detecta el patrón resumen en una línea y retorna los números encontrados.
|
|
84
|
-
* Soporta separadores `,`, `+` y `y`. Tolera el orden canónico
|
|
85
|
-
* agentes → skills/habilidades → comandos → reglas → hooks.
|
|
86
|
-
*
|
|
87
|
-
* Ejemplos que matchean:
|
|
88
|
-
* "59 agentes, 150 skills, 41 comandos, 60 reglas, 36 hooks"
|
|
89
|
-
* "59 agentes + 150 habilidades + 41 comandos + 60 reglas + 36 hooks"
|
|
90
|
-
* "59 agentes, 150 skills, 41 comandos, 60 reglas y 36 hooks"
|
|
91
|
-
* "Frontmatter: 59 agentes + 150 skills + 41 comandos verificados"
|
|
92
|
-
* (los 3 primeros se validan; los 2 últimos faltan → no full match,
|
|
93
|
-
* se devuelve match parcial con flags)
|
|
94
|
-
*
|
|
95
|
-
* Retorna `null` si no encuentra al menos `agentes` y un segundo componente.
|
|
96
|
-
*/
|
|
97
|
-
function extraerResumenDeLinea(linea) {
|
|
98
|
-
// Patrón principal: 5 componentes en orden
|
|
99
|
-
const re5 = /(\d{1,4})\s+agentes?[\s,+y]+\s*(\d{1,4})\s+(?:skills|habilidades)[\s,+y]+\s*(\d{1,4})\s+comandos[\s,+y]+\s*(\d{1,4})\s+reglas[\s,+y]+\s*(\d{1,4})\s+hooks/i;
|
|
100
|
-
const m5 = linea.match(re5);
|
|
101
|
-
if (m5) {
|
|
102
|
-
return {
|
|
103
|
-
tipo: 'resumen5',
|
|
104
|
-
texto: m5[0],
|
|
105
|
-
agentes: parseInt(m5[1], 10),
|
|
106
|
-
skills: parseInt(m5[2], 10),
|
|
107
|
-
comandos: parseInt(m5[3], 10),
|
|
108
|
-
reglas: parseInt(m5[4], 10),
|
|
109
|
-
hooks: parseInt(m5[5], 10),
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
// Patrón parcial: 3 componentes (agentes, skills/habilidades, comandos)
|
|
114
|
-
const re3 = /(\d{1,4})\s+agentes?[\s,+y]+\s*(\d{1,4})\s+(?:skills|habilidades)[\s,+y]+\s*(\d{1,4})\s+comandos/i;
|
|
115
|
-
const m3 = linea.match(re3);
|
|
116
|
-
if (m3) {
|
|
117
|
-
return {
|
|
118
|
-
tipo: 'resumen3',
|
|
119
|
-
texto: m3[0],
|
|
120
|
-
agentes: parseInt(m3[1], 10),
|
|
121
|
-
skills: parseInt(m3[2], 10),
|
|
122
|
-
comandos: parseInt(m3[3], 10),
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Decide si una línea debe ignorarse por ser obviamente histórica
|
|
131
|
-
* (fila de changelog/timeline con versión SemVer + fecha en formato tabla).
|
|
132
|
-
*/
|
|
133
|
-
function esLineaHistorica(linea) {
|
|
134
|
-
// Tabla con versión SemVer + fecha ISO: "| 5.4.0 | 2026-04-10 | ..."
|
|
135
|
-
if (/^\s*\|\s*\d+\.\d+\.\d+\s*\|\s*\d{4}-\d{2}-\d{2}/.test(linea)) return true;
|
|
136
|
-
// "Baseline:" suele ser nota histórica
|
|
137
|
-
if (/\bBaseline\s*:/i.test(linea)) return true;
|
|
138
|
-
// "antes de v|previa a|tras release N" sugiere historia
|
|
139
|
-
if (/\b(?:antes de v|previa a|tras release|en v\d+\.\d+)\b/i.test(linea)) return true;
|
|
140
|
-
// Línea entre comillas dobles (cita textual de un patrón documentado): "22 hooks"
|
|
141
|
-
if (/"\s*\d+\s+(?:agentes|skills|habilidades|comandos|hooks|reglas)\s*"/i.test(linea)) return true;
|
|
142
|
-
return false;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Valida un archivo contra los contadores reales.
|
|
147
|
-
* Solo flagea las líneas que contienen patrón resumen identificable.
|
|
148
|
-
*
|
|
149
|
-
* Retorna { ok, lineas_revisadas, discrepancias: [{linea, encontrado, esperado, tipo, contexto}] }
|
|
150
|
-
*/
|
|
151
|
-
function validarArchivo(rawMd, contadoresReales) {
|
|
152
|
-
const lineas = rawMd.split(/\r?\n/);
|
|
153
|
-
const discrepancias = [];
|
|
154
|
-
let lineasRevisadas = 0;
|
|
155
|
-
|
|
156
|
-
for (let i = 0; i < lineas.length; i++) {
|
|
157
|
-
if (esLineaHistorica(lineas[i])) continue;
|
|
158
|
-
const r = extraerResumenDeLinea(lineas[i]);
|
|
159
|
-
if (!r) continue;
|
|
160
|
-
lineasRevisadas++;
|
|
161
|
-
|
|
162
|
-
const campos = r.tipo === 'resumen5'
|
|
163
|
-
? COMPONENTES
|
|
164
|
-
: ['agentes', 'skills', 'comandos'];
|
|
165
|
-
|
|
166
|
-
for (const campo of campos) {
|
|
167
|
-
if (r[campo] !== contadoresReales[campo]) {
|
|
168
|
-
discrepancias.push({
|
|
169
|
-
linea: i + 1,
|
|
170
|
-
campo,
|
|
171
|
-
encontrado: r[campo],
|
|
172
|
-
esperado: contadoresReales[campo],
|
|
173
|
-
tipo: r.tipo,
|
|
174
|
-
contexto: lineas[i].trim().slice(0, 110),
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
// Patrón nominal: "**Total de agentes**: N", "**Total de skills**: N"
|
|
181
|
-
const reTotal = /\*?\*?Total\s+de\s+(agentes|skills|habilidades|comandos|hooks|reglas)\*?\*?\s*:\s*(\d{1,4})/gi;
|
|
182
|
-
for (let i = 0; i < lineas.length; i++) {
|
|
183
|
-
if (esLineaHistorica(lineas[i])) continue;
|
|
184
|
-
let m;
|
|
185
|
-
reTotal.lastIndex = 0;
|
|
186
|
-
while ((m = reTotal.exec(lineas[i])) !== null) {
|
|
187
|
-
const palabra = m[1].toLowerCase();
|
|
188
|
-
const campo = palabra === 'habilidades' ? 'skills' : palabra;
|
|
189
|
-
const num = parseInt(m[2], 10);
|
|
190
|
-
lineasRevisadas++;
|
|
191
|
-
if (num !== contadoresReales[campo]) {
|
|
192
|
-
discrepancias.push({
|
|
193
|
-
linea: i + 1,
|
|
194
|
-
campo,
|
|
195
|
-
encontrado: num,
|
|
196
|
-
esperado: contadoresReales[campo],
|
|
197
|
-
tipo: 'total_nominal',
|
|
198
|
-
contexto: lineas[i].trim().slice(0, 110),
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return {
|
|
205
|
-
ok: discrepancias.length === 0,
|
|
206
|
-
lineas_revisadas: lineasRevisadas,
|
|
207
|
-
discrepancias,
|
|
208
|
-
};
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
module.exports = {
|
|
212
|
-
COMPONENTES,
|
|
213
|
-
parsearInventario,
|
|
214
|
-
extraerResumenDeLinea,
|
|
215
|
-
esLineaHistorica,
|
|
216
|
-
validarArchivo,
|
|
217
|
-
};
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* contadores-inventario.js
|
|
5
|
+
*
|
|
6
|
+
* Funciones puras zero-deps para validar consistencia entre los contadores
|
|
7
|
+
* de inventario (agentes, skills, comandos, hooks, reglas) declarados en
|
|
8
|
+
* `INVENTARIO.md` (fuente de verdad regenerada por
|
|
9
|
+
* `scripts/generar-inventario.js`) y los contadores citados en los demás
|
|
10
|
+
* documentos canónicos del repositorio.
|
|
11
|
+
*
|
|
12
|
+
* Motivado por el drift recurrente detectado el 2026-04-29: MAPEO_SKILLS_AGENTES.md
|
|
13
|
+
* decía "153 skills" cuando la realidad eran 150; COMPACTACION.md reportaba
|
|
14
|
+
* "147 skills, 40 comandos, 31 hooks". El hook `verificar-release.js` valida
|
|
15
|
+
* versión pero no contadores. Este módulo cierra ese hueco.
|
|
16
|
+
*
|
|
17
|
+
* Cobertura intencional:
|
|
18
|
+
* - Patrón resumen "X agentes, Y skills, Z comandos, W reglas, V hooks"
|
|
19
|
+
* (separadores `,` o `+` o `y`) — valida los 5 números a la vez.
|
|
20
|
+
* - Patrón "X agentes + Y habilidades + Z comandos + W reglas + V hooks"
|
|
21
|
+
* común en tablas de perfiles `completo`.
|
|
22
|
+
* - Patrón "Total de agentes: X" / "Total de skills: X" en MAPEO.
|
|
23
|
+
*
|
|
24
|
+
* Cobertura intencionalmente excluida (falsos positivos clásicos):
|
|
25
|
+
* - "los 17 skills de Anthropic" (skills externos)
|
|
26
|
+
* - "8 lenguajes × 5 reglas" (multiplicación)
|
|
27
|
+
* - perfiles parciales "2 hooks", "6 hooks" (no son totales)
|
|
28
|
+
* - notas históricas "estimé 28 hooks visualmente y propagué el error"
|
|
29
|
+
* - referencias a versiones pasadas en MAPEO ("136 skills tras release X")
|
|
30
|
+
* - filas de tabla histórica con SemVer + fecha ("| 5.4.0 | 2026-04-10 | 57 agentes...")
|
|
31
|
+
*
|
|
32
|
+
* Estas se ignoran porque el patrón resumen es el único que tiene los 5
|
|
33
|
+
* componentes alineados; las menciones aisladas de un solo número se dejan
|
|
34
|
+
* para una auditoría aparte (no bloqueante).
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
const COMPONENTES = ['agentes', 'skills', 'comandos', 'hooks', 'reglas'];
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Parsea la sección "## Resumen" de INVENTARIO.md y retorna un mapa con
|
|
41
|
+
* los contadores reales del sistema.
|
|
42
|
+
*
|
|
43
|
+
* Espera tabla del tipo:
|
|
44
|
+
* ## Resumen
|
|
45
|
+
* | Componente | Cantidad |
|
|
46
|
+
* |-----------|----------|
|
|
47
|
+
* | Agentes SWL | 59 |
|
|
48
|
+
* | Habilidades | 150 |
|
|
49
|
+
* | Comandos | 41 |
|
|
50
|
+
* | Reglas base | 20 |
|
|
51
|
+
* | Reglas por lenguaje | 40 |
|
|
52
|
+
* | Hooks | 36 |
|
|
53
|
+
*
|
|
54
|
+
* Retorna `{ agentes, skills, comandos, hooks, reglas }`.
|
|
55
|
+
* `skills` y `habilidades` se mapean al mismo número.
|
|
56
|
+
* `reglas` = base + por_lenguaje.
|
|
57
|
+
*/
|
|
58
|
+
function parsearInventario(rawMd) {
|
|
59
|
+
const lineas = rawMd.split(/\r?\n/);
|
|
60
|
+
const resumen = {};
|
|
61
|
+
let enResumen = false;
|
|
62
|
+
for (const linea of lineas) {
|
|
63
|
+
if (/^##\s+Resumen\s*$/.test(linea)) { enResumen = true; continue; }
|
|
64
|
+
if (enResumen && /^##\s+/.test(linea)) break;
|
|
65
|
+
if (!enResumen) continue;
|
|
66
|
+
const m = linea.match(/^\|\s*([^|]+?)\s*\|\s*(\d+)\s*\|/);
|
|
67
|
+
if (m) resumen[m[1].trim()] = parseInt(m[2], 10);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const reglasBase = resumen['Reglas base'] || 0;
|
|
71
|
+
const reglasLeng = resumen['Reglas por lenguaje'] || 0;
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
agentes: resumen['Agentes SWL'] || 0,
|
|
75
|
+
skills: resumen['Habilidades'] || 0,
|
|
76
|
+
comandos: resumen['Comandos'] || 0,
|
|
77
|
+
hooks: resumen['Hooks'] || 0,
|
|
78
|
+
reglas: reglasBase + reglasLeng,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Detecta el patrón resumen en una línea y retorna los números encontrados.
|
|
84
|
+
* Soporta separadores `,`, `+` y `y`. Tolera el orden canónico
|
|
85
|
+
* agentes → skills/habilidades → comandos → reglas → hooks.
|
|
86
|
+
*
|
|
87
|
+
* Ejemplos que matchean:
|
|
88
|
+
* "59 agentes, 150 skills, 41 comandos, 60 reglas, 36 hooks"
|
|
89
|
+
* "59 agentes + 150 habilidades + 41 comandos + 60 reglas + 36 hooks"
|
|
90
|
+
* "59 agentes, 150 skills, 41 comandos, 60 reglas y 36 hooks"
|
|
91
|
+
* "Frontmatter: 59 agentes + 150 skills + 41 comandos verificados"
|
|
92
|
+
* (los 3 primeros se validan; los 2 últimos faltan → no full match,
|
|
93
|
+
* se devuelve match parcial con flags)
|
|
94
|
+
*
|
|
95
|
+
* Retorna `null` si no encuentra al menos `agentes` y un segundo componente.
|
|
96
|
+
*/
|
|
97
|
+
function extraerResumenDeLinea(linea) {
|
|
98
|
+
// Patrón principal: 5 componentes en orden
|
|
99
|
+
const re5 = /(\d{1,4})\s+agentes?[\s,+y]+\s*(\d{1,4})\s+(?:skills|habilidades)[\s,+y]+\s*(\d{1,4})\s+comandos[\s,+y]+\s*(\d{1,4})\s+reglas[\s,+y]+\s*(\d{1,4})\s+hooks/i;
|
|
100
|
+
const m5 = linea.match(re5);
|
|
101
|
+
if (m5) {
|
|
102
|
+
return {
|
|
103
|
+
tipo: 'resumen5',
|
|
104
|
+
texto: m5[0],
|
|
105
|
+
agentes: parseInt(m5[1], 10),
|
|
106
|
+
skills: parseInt(m5[2], 10),
|
|
107
|
+
comandos: parseInt(m5[3], 10),
|
|
108
|
+
reglas: parseInt(m5[4], 10),
|
|
109
|
+
hooks: parseInt(m5[5], 10),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Patrón parcial: 3 componentes (agentes, skills/habilidades, comandos)
|
|
114
|
+
const re3 = /(\d{1,4})\s+agentes?[\s,+y]+\s*(\d{1,4})\s+(?:skills|habilidades)[\s,+y]+\s*(\d{1,4})\s+comandos/i;
|
|
115
|
+
const m3 = linea.match(re3);
|
|
116
|
+
if (m3) {
|
|
117
|
+
return {
|
|
118
|
+
tipo: 'resumen3',
|
|
119
|
+
texto: m3[0],
|
|
120
|
+
agentes: parseInt(m3[1], 10),
|
|
121
|
+
skills: parseInt(m3[2], 10),
|
|
122
|
+
comandos: parseInt(m3[3], 10),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Decide si una línea debe ignorarse por ser obviamente histórica
|
|
131
|
+
* (fila de changelog/timeline con versión SemVer + fecha en formato tabla).
|
|
132
|
+
*/
|
|
133
|
+
function esLineaHistorica(linea) {
|
|
134
|
+
// Tabla con versión SemVer + fecha ISO: "| 5.4.0 | 2026-04-10 | ..."
|
|
135
|
+
if (/^\s*\|\s*\d+\.\d+\.\d+\s*\|\s*\d{4}-\d{2}-\d{2}/.test(linea)) return true;
|
|
136
|
+
// "Baseline:" suele ser nota histórica
|
|
137
|
+
if (/\bBaseline\s*:/i.test(linea)) return true;
|
|
138
|
+
// "antes de v|previa a|tras release N" sugiere historia
|
|
139
|
+
if (/\b(?:antes de v|previa a|tras release|en v\d+\.\d+)\b/i.test(linea)) return true;
|
|
140
|
+
// Línea entre comillas dobles (cita textual de un patrón documentado): "22 hooks"
|
|
141
|
+
if (/"\s*\d+\s+(?:agentes|skills|habilidades|comandos|hooks|reglas)\s*"/i.test(linea)) return true;
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Valida un archivo contra los contadores reales.
|
|
147
|
+
* Solo flagea las líneas que contienen patrón resumen identificable.
|
|
148
|
+
*
|
|
149
|
+
* Retorna { ok, lineas_revisadas, discrepancias: [{linea, encontrado, esperado, tipo, contexto}] }
|
|
150
|
+
*/
|
|
151
|
+
function validarArchivo(rawMd, contadoresReales) {
|
|
152
|
+
const lineas = rawMd.split(/\r?\n/);
|
|
153
|
+
const discrepancias = [];
|
|
154
|
+
let lineasRevisadas = 0;
|
|
155
|
+
|
|
156
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
157
|
+
if (esLineaHistorica(lineas[i])) continue;
|
|
158
|
+
const r = extraerResumenDeLinea(lineas[i]);
|
|
159
|
+
if (!r) continue;
|
|
160
|
+
lineasRevisadas++;
|
|
161
|
+
|
|
162
|
+
const campos = r.tipo === 'resumen5'
|
|
163
|
+
? COMPONENTES
|
|
164
|
+
: ['agentes', 'skills', 'comandos'];
|
|
165
|
+
|
|
166
|
+
for (const campo of campos) {
|
|
167
|
+
if (r[campo] !== contadoresReales[campo]) {
|
|
168
|
+
discrepancias.push({
|
|
169
|
+
linea: i + 1,
|
|
170
|
+
campo,
|
|
171
|
+
encontrado: r[campo],
|
|
172
|
+
esperado: contadoresReales[campo],
|
|
173
|
+
tipo: r.tipo,
|
|
174
|
+
contexto: lineas[i].trim().slice(0, 110),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Patrón nominal: "**Total de agentes**: N", "**Total de skills**: N"
|
|
181
|
+
const reTotal = /\*?\*?Total\s+de\s+(agentes|skills|habilidades|comandos|hooks|reglas)\*?\*?\s*:\s*(\d{1,4})/gi;
|
|
182
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
183
|
+
if (esLineaHistorica(lineas[i])) continue;
|
|
184
|
+
let m;
|
|
185
|
+
reTotal.lastIndex = 0;
|
|
186
|
+
while ((m = reTotal.exec(lineas[i])) !== null) {
|
|
187
|
+
const palabra = m[1].toLowerCase();
|
|
188
|
+
const campo = palabra === 'habilidades' ? 'skills' : palabra;
|
|
189
|
+
const num = parseInt(m[2], 10);
|
|
190
|
+
lineasRevisadas++;
|
|
191
|
+
if (num !== contadoresReales[campo]) {
|
|
192
|
+
discrepancias.push({
|
|
193
|
+
linea: i + 1,
|
|
194
|
+
campo,
|
|
195
|
+
encontrado: num,
|
|
196
|
+
esperado: contadoresReales[campo],
|
|
197
|
+
tipo: 'total_nominal',
|
|
198
|
+
contexto: lineas[i].trim().slice(0, 110),
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
return {
|
|
205
|
+
ok: discrepancias.length === 0,
|
|
206
|
+
lineas_revisadas: lineasRevisadas,
|
|
207
|
+
discrepancias,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = {
|
|
212
|
+
COMPONENTES,
|
|
213
|
+
parsearInventario,
|
|
214
|
+
extraerResumenDeLinea,
|
|
215
|
+
esLineaHistorica,
|
|
216
|
+
validarArchivo,
|
|
217
|
+
};
|
|
@@ -81,19 +81,29 @@ const RUNTIMES = {
|
|
|
81
81
|
tiposSoportados: ['agentes', 'habilidades', 'comandos', 'reglas', 'hooks'],
|
|
82
82
|
},
|
|
83
83
|
codex: {
|
|
84
|
+
// ADR-0019 Sub-fase 1 → ampliada en Sub-fase 8 (mismo v1.5.0).
|
|
85
|
+
// Codex CLI lee:
|
|
86
|
+
// - AGENTS.md jerárquico (project + ~/.codex/AGENTS.md global)
|
|
87
|
+
// - ${CODEX_HOME:-$HOME/.codex}/skills/<name>/SKILL.md (skills propias)
|
|
88
|
+
// - ~/.codex/config.toml con [mcp_servers.NAME] (MCP)
|
|
89
|
+
// - hooks.json con PreToolUse/PostToolUse/Stop (NO mapeado por SWL — formato distinto)
|
|
90
|
+
// Codex NO expone agents/ individual desde filesystem — los agentes SWL
|
|
91
|
+
// van consolidados en AGENTS.md como tabla referencial.
|
|
84
92
|
nombre: 'Codex CLI',
|
|
85
93
|
global: path.join(os.homedir(), '.codex'),
|
|
86
94
|
local: '.codex',
|
|
87
|
-
archivosConfig: [],
|
|
88
|
-
dirAgentes:
|
|
89
|
-
dirHabilidades:
|
|
90
|
-
dirComandos: null,
|
|
91
|
-
dirReglas: null,
|
|
92
|
-
formatoAgente: '
|
|
93
|
-
soportaHooks:
|
|
94
|
-
|
|
95
|
+
archivosConfig: ['config.toml'],
|
|
96
|
+
dirAgentes: 'agents', // ~/.codex/agents/<name>.toml — Sub-fase 11 v1.5.0 (formato TOML)
|
|
97
|
+
dirHabilidades: 'skills', // path real `~/.agents/skills/` resuelto por transformador (Sub-fase 10)
|
|
98
|
+
dirComandos: null, // Codex no soporta slash custom filesystem
|
|
99
|
+
dirReglas: null, // consolidado en AGENTS.md (Codex rules son Starlark, no portable)
|
|
100
|
+
formatoAgente: 'toml', // Sub-fase 11: cada agente es un .toml individual
|
|
101
|
+
soportaHooks: true, // Sub-fase 10: ~/.codex/hooks.json (6 eventos)
|
|
102
|
+
hookConfig: 'hooks.json',
|
|
103
|
+
soporte: 'completo',
|
|
95
104
|
archivoPrincipal: 'AGENTS.md',
|
|
96
|
-
tiposSoportados: ['agentes', 'reglas'],
|
|
105
|
+
tiposSoportados: ['agentes', 'habilidades', 'reglas', 'hooks'],
|
|
106
|
+
notas: 'Agentes en ~/.codex/agents/<name>.toml (formato TOML — Sub-fase 11). Skills en ~/.agents/skills/ (path oficial OpenAI — Sub-fase 10). Hooks en ~/.codex/hooks.json. MCP server en ~/.codex/config.toml. AGENTS.md sigue conteniendo tabla referencial como índice.',
|
|
97
107
|
},
|
|
98
108
|
gemini: {
|
|
99
109
|
nombre: 'Gemini CLI',
|
|
@@ -111,6 +121,34 @@ const RUNTIMES = {
|
|
|
111
121
|
archivoPrincipal: 'GEMINI.md',
|
|
112
122
|
tiposSoportados: ['agentes', 'habilidades', 'comandos', 'reglas', 'hooks'],
|
|
113
123
|
},
|
|
124
|
+
cursor: {
|
|
125
|
+
// ADR-0019 Sub-fase 2 → refinada en Sub-fase 7 (mismo v1.5.0).
|
|
126
|
+
// Tras verificar docs oficiales de Cursor (cursor.com/es/docs/{subagents,skills,rules,mcp}):
|
|
127
|
+
// Cursor SÍ soporta subagents y skills filesystem nativamente.
|
|
128
|
+
// - `.cursor/agents/<name>.md` con frontmatter Claude-compatible
|
|
129
|
+
// (name, description, model=inherit, readonly, is_background).
|
|
130
|
+
// Legacy: lee `.claude/agents/`, `.codex/agents/`.
|
|
131
|
+
// - `.cursor/skills/<name>/SKILL.md` (mismo formato Anthropic Skills).
|
|
132
|
+
// Legacy: lee `.agents/skills/`, `.claude/skills/`, `.codex/skills/`.
|
|
133
|
+
// - `.cursor/rules/*.mdc` con frontmatter description/alwaysApply/globs.
|
|
134
|
+
// - `.cursor/mcp.json` o `~/.cursor/mcp.json` para MCP servers.
|
|
135
|
+
// - NO soporta nativamente: slash commands custom, hooks (PreToolUse, etc).
|
|
136
|
+
nombre: 'Cursor',
|
|
137
|
+
global: path.join(os.homedir(), '.cursor'),
|
|
138
|
+
local: '.cursor',
|
|
139
|
+
archivosConfig: ['mcp.json'],
|
|
140
|
+
dirAgentes: 'agents', // .cursor/agents/<name>.md
|
|
141
|
+
dirHabilidades: 'skills', // .cursor/skills/<name>/SKILL.md
|
|
142
|
+
dirComandos: null, // Cursor no tiene slash custom filesystem (skills cumplen ese rol)
|
|
143
|
+
dirReglas: 'rules', // .cursor/rules/*.mdc
|
|
144
|
+
formatoAgente: 'markdown-frontmatter',
|
|
145
|
+
soportaHooks: true, // Sub-fase 10: .cursor/hooks.json (17 eventos)
|
|
146
|
+
hookConfig: 'hooks.json',
|
|
147
|
+
soporte: 'completo',
|
|
148
|
+
archivoPrincipal: null,
|
|
149
|
+
tiposSoportados: ['agentes', 'habilidades', 'reglas', 'hooks'],
|
|
150
|
+
notas: 'Subagents en .cursor/agents/, skills en .cursor/skills/<name>/SKILL.md, reglas en .cursor/rules/*.mdc, hooks en .cursor/hooks.json (17 eventos camelCase), MCP en .cursor/mcp.json. Slash commands custom: usar skills (se invocan con /<name>).',
|
|
151
|
+
},
|
|
114
152
|
};
|
|
115
153
|
|
|
116
154
|
/**
|
|
@@ -269,6 +307,33 @@ function detectarInstalacionesDuales(runtimeId, opciones = {}) {
|
|
|
269
307
|
};
|
|
270
308
|
}
|
|
271
309
|
|
|
310
|
+
/**
|
|
311
|
+
* Lista los IDs de runtimes "instalables" — es decir, los que tienen
|
|
312
|
+
* transformador disponible y soporte declarado (completo o parcial).
|
|
313
|
+
*
|
|
314
|
+
* Se usa para expandir `--all-runtimes` en multi-target install (ADR-0019 Sub-fase 2.5).
|
|
315
|
+
*
|
|
316
|
+
* Excluye alias (openclaude comparte el dir .claude/ con claude — incluirlo en
|
|
317
|
+
* --all-runtimes produciría doble instalación al mismo destino).
|
|
318
|
+
*
|
|
319
|
+
* Orden estable: el orden de la lista importa porque define el orden de
|
|
320
|
+
* ejecución de --all-runtimes. Si un target falla los siguientes igual se
|
|
321
|
+
* intentan (ADR-0019 punto 9: atomicidad por target, no rollback).
|
|
322
|
+
*
|
|
323
|
+
* @returns {string[]} Lista de runtime IDs ordenada de "más usado" a "menos usado".
|
|
324
|
+
*/
|
|
325
|
+
function listarRuntimesInstalables() {
|
|
326
|
+
return [
|
|
327
|
+
'claude', // Soporte completo, primer ciudadano
|
|
328
|
+
'cursor', // Soporte parcial — reglas + MCP
|
|
329
|
+
'codex', // Soporte parcial — AGENTS.md + MCP (v1.5.0+)
|
|
330
|
+
'opencode', // Soporte completo
|
|
331
|
+
'gemini', // Soporte completo
|
|
332
|
+
'copilot', // Soporte parcial — agentes consolidados
|
|
333
|
+
// 'openclaude' intencionalmente excluido — comparte dir con claude
|
|
334
|
+
];
|
|
335
|
+
}
|
|
336
|
+
|
|
272
337
|
module.exports = {
|
|
273
338
|
RUNTIMES,
|
|
274
339
|
detectarRuntimes,
|
|
@@ -276,4 +341,5 @@ module.exports = {
|
|
|
276
341
|
obtenerRuntime,
|
|
277
342
|
calcularRutas,
|
|
278
343
|
resumenDeteccion,
|
|
344
|
+
listarRuntimesInstalables,
|
|
279
345
|
};
|