@saulwade/swl-ses 2.4.2 → 2.5.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 +194 -241
- package/README.md +600 -597
- package/agentes/_intent-spec.md +73 -73
- package/agentes/_propose-step.md +90 -90
- package/agentes/abogado-diablo-swl.md +145 -0
- package/agentes/accesibilidad-wcag-swl.md +690 -690
- package/agentes/arquitecto-swl.md +267 -267
- package/agentes/auto-evolucion-swl.md +908 -908
- package/agentes/backend-api-swl.md +1 -1
- 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-node-swl.md +1 -1
- package/agentes/backend-python-swl.md +1 -1
- 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/datos-swl.md +1 -1
- 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/gh-fix-ci-swl.md +6 -1
- package/agentes/implementador-swl.md +1 -1
- package/agentes/investigador-swl.md +432 -432
- package/agentes/investigador-ux-swl.md +505 -505
- package/agentes/llm-apps-swl.md +1 -1
- 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/notificador-swl.md +1 -1
- 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/resolutor-build-swl.md +10 -1
- package/agentes/revisor-angular-swl.md +278 -278
- package/agentes/revisor-codigo-swl.md +1 -1
- 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/sre-swl.md +1 -1
- package/agentes/tdd-qa-swl.md +393 -393
- package/bin/lib/bot-comandos.js +1 -1
- package/bin/swl-ses.js +6 -0
- package/comandos/swl/adoptar-proyecto.md +14 -2
- package/comandos/swl/configurar-ci.md +8 -1
- package/comandos/swl/deuda-codigo.md +97 -97
- package/comandos/swl/discutir-fase.md +22 -118
- package/comandos/swl/fix.md +118 -0
- package/comandos/swl/nuevo-proyecto.md +54 -3
- package/comandos/swl/predecir.md +32 -2
- package/comandos/swl/seguridad.md +189 -0
- package/comandos/swl/status.md +5 -3
- package/habilidades/aprendizaje-continuo/SKILL.md +3 -1
- package/habilidades/discutir-fase/SKILL.md +84 -81
- package/habilidades/discutir-fase/recursos/plantilla-contexto.md +136 -0
- package/habilidades/doc-sync/SKILL.md +3 -1
- package/habilidades/doubt-driven-review/SKILL.md +15 -1
- package/habilidades/ejecutar-task-iterativo/SKILL.md +278 -278
- package/habilidades/estructura-proyecto-claude/SKILL.md +11 -2
- package/habilidades/harness-claude-code/SKILL.md +3 -1
- package/habilidades/instalar-sistema/SKILL.md +3 -1
- package/habilidades/meta-reglas-extendido/SKILL.md +92 -0
- package/habilidades/meta-reglas-extendido/recursos/analisis-previo-tareas-grandes.md +186 -0
- package/habilidades/meta-reglas-extendido/recursos/analizar-directorios-antes-de-escribir.md +235 -0
- package/habilidades/meta-reglas-extendido/recursos/api-diseno.md +413 -0
- package/habilidades/meta-reglas-extendido/recursos/arquitectura.md +491 -0
- package/habilidades/meta-reglas-extendido/recursos/arreglar-al-detectar.md +264 -0
- package/habilidades/meta-reglas-extendido/recursos/debatir-antes-de-aceptar.md +152 -0
- package/habilidades/meta-reglas-extendido/recursos/git-workflow.md +259 -0
- package/habilidades/meta-reglas-extendido/recursos/gobernanza.md +291 -0
- package/habilidades/meta-reglas-extendido/recursos/memoria-consolidada.md +263 -0
- package/habilidades/meta-reglas-extendido/recursos/seguridad-agentes.md +443 -0
- package/habilidades/meta-reglas-extendido/recursos/sesiones-paralelas.md +190 -0
- package/habilidades/meta-reglas-extendido/recursos/sin-duplicacion-reglas-globales.md +179 -0
- package/habilidades/meta-reglas-extendido/recursos/skills-estandar.md +394 -0
- package/habilidades/meta-reglas-extendido/recursos/usar-code-review-graph.md +156 -0
- package/habilidades/meta-reglas-extendido/recursos/usar-context7.md +236 -0
- package/habilidades/meta-reglas-extendido/recursos/usar-sistema-swl.md +253 -0
- package/habilidades/meta-reglas-extendido/recursos/verificar-citas-normativas.md +527 -0
- package/habilidades/meta-skills-estandar/SKILL.md +3 -1
- package/habilidades/nuevo-proyecto/SKILL.md +20 -3
- package/habilidades/php-experto/SKILL.md +10 -3
- package/habilidades/{filament-admin/SKILL.md → php-experto/recursos/filament-admin.md} +23 -39
- 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-debate-adversarial/recursos/personas.md +5 -4
- package/habilidades/proceso-ingenieria-requerimientos/SKILL.md +147 -0
- package/hooks/check-update.js +19 -10
- package/hooks/contexto-subagente.js +68 -68
- package/hooks/degradacion-instintos.js +1 -1
- package/hooks/extraccion-aprendizajes.js +2 -2
- package/hooks/lib/briefing.js +3 -3
- package/hooks/lib/nudge-tracker.js +1 -1
- package/hooks/lib/otlp-exporter.js +1 -1
- package/hooks/lib/webhook-dedup.js +1 -1
- package/hooks/session-briefing.js +1 -1
- package/llms.txt +6 -6
- package/manifiestos/canonical-hashes.json +989 -0
- package/manifiestos/hooks-config.json +469 -469
- package/manifiestos/invariantes-criticos.json +30 -30
- package/manifiestos/modulos.json +168 -135
- package/manifiestos/perfiles.json +0 -2
- package/manifiestos/skills-lock.json +52 -59
- package/package.json +7 -5
- package/plantillas/github-workflows/README.md +15 -1
- package/plantillas/github-workflows/swl-devsecops.yml +70 -0
- package/plugin.json +5 -5
- package/reglas/analisis-previo-tareas-grandes.md +30 -156
- package/reglas/analizar-directorios-antes-de-escribir.md +30 -211
- package/reglas/api-diseno.md +28 -398
- package/reglas/arquitectura.md +35 -456
- package/reglas/arreglar-al-detectar.md +30 -230
- package/reglas/debatir-antes-de-aceptar.md +30 -143
- package/reglas/docs.md +7 -0
- package/reglas/estilo-codigo.md +9 -0
- package/reglas/fragmentos-compartidos.md +6 -0
- package/reglas/git-workflow.md +44 -240
- package/reglas/gobernanza.md +23 -262
- package/reglas/memoria-consolidada.md +34 -228
- package/reglas/performance.md +8 -0
- package/reglas/pruebas.md +12 -0
- package/reglas/seguridad-agentes.md +37 -418
- package/reglas/seguridad.md +12 -0
- package/reglas/sesiones-paralelas.md +29 -162
- package/reglas/sin-duplicacion-reglas-globales.md +25 -166
- package/reglas/skills-estandar.md +23 -373
- package/reglas/usar-code-review-graph.md +31 -140
- package/reglas/usar-context7.md +30 -208
- package/reglas/usar-sistema-swl.md +47 -242
- package/reglas/verificar-citas-normativas.md +47 -537
- package/scripts/actualizar.js +253 -253
- package/scripts/audit-tools/auditar-relleno-inventario.js +145 -0
- package/scripts/auditar-clases-conocidas.js +106 -0
- package/scripts/bootstrap-instintos.js +2 -2
- package/scripts/canario-hooks.js +166 -0
- package/scripts/cli/configurar-ci.js +2 -1
- package/scripts/evidencia-valor.js +93 -0
- package/scripts/field-report.js +1 -1
- package/scripts/generar-comandos.js +143 -0
- package/scripts/generar-inventario.js +236 -23
- package/scripts/generar-matriz-lenguajes.js +1 -1
- package/scripts/instalador.js +15 -1
- package/scripts/lib/configurar-ci.js +10 -3
- package/scripts/lib/detectar-runtime.js +12 -3
- package/scripts/lib/diary-entry.js +3 -1
- package/scripts/lib/drift-detector.js +1 -1
- package/scripts/lib/evidencia-valor.js +189 -0
- package/scripts/lib/expandir-targets.js +71 -71
- package/scripts/lib/frontmatter-md.js +63 -0
- package/scripts/lib/parsear-opciones.js +2 -0
- package/scripts/lib/prune-componentes.js +180 -0
- package/scripts/lib/reglas-globales-conocidas.json +16 -2
- package/scripts/lib/scoring-instintos.js +2 -2
- package/scripts/lib/toml-merge.js +204 -204
- package/scripts/lib/transformadores/claude.js +1 -1
- package/scripts/lib/transformadores/codex.js +1 -1
- package/scripts/lib/transformadores/copilot.js +1 -1
- package/scripts/lib/transformadores/cursor.js +1 -1
- package/scripts/lib/transformadores/gemini.js +22 -2
- package/scripts/lib/transformadores/opencode.js +1 -1
- package/scripts/mcp-server/auth.js +105 -105
- package/scripts/mcp-server/cache.js +106 -106
- package/scripts/prune.js +102 -0
- package/scripts/publicar.js +18 -2
- package/scripts/tui/pantallas/inspect.js +175 -175
- package/scripts/tui/pantallas/uninstall-wizard.js +210 -210
- package/scripts/tui/pantallas/update-wizard.js +234 -234
- package/scripts/tui/pantallas/welcome.js +189 -189
- package/habilidades/paid-media-tracking/SKILL.md +0 -269
- package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +0 -220
- package/habilidades/paid-media-tracking/recursos/google-ads-api.md +0 -215
- package/habilidades/tracking-measurement/SKILL.md +0 -239
- package/habilidades/tracking-measurement/recursos/consent-mode.md +0 -231
- package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +0 -216
- package/habilidades/tracking-measurement/recursos/meta-capi.md +0 -262
|
@@ -44,18 +44,47 @@ function leerFrontmatter(ruta) {
|
|
|
44
44
|
const match = contenido.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
45
45
|
if (!match) return {};
|
|
46
46
|
const fm = {};
|
|
47
|
-
|
|
47
|
+
const lineas = match[1].split(/\r?\n/);
|
|
48
|
+
for (let i = 0; i < lineas.length; i++) {
|
|
49
|
+
const linea = lineas[i];
|
|
50
|
+
if (/^\s/.test(linea)) continue; // continuación de multilínea, la consume el bloque de abajo
|
|
48
51
|
const idx = linea.indexOf(':');
|
|
49
|
-
if (idx
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
if (idx <= 0) continue;
|
|
53
|
+
const key = linea.slice(0, idx).trim();
|
|
54
|
+
let val = linea.slice(idx + 1).trim().replace(/^["']|["']$/g, '');
|
|
55
|
+
// Escalares plegados YAML (`description: >` / `|`): juntar las líneas indentadas siguientes.
|
|
56
|
+
if (val === '>' || val === '|' || val === '>-' || val === '|-' || val === '') {
|
|
57
|
+
const partes = [];
|
|
58
|
+
for (let j = i + 1; j < lineas.length && /^\s+\S/.test(lineas[j]); j++) {
|
|
59
|
+
partes.push(lineas[j].trim());
|
|
60
|
+
}
|
|
61
|
+
if (partes.length > 0) val = partes.join(' ');
|
|
53
62
|
}
|
|
63
|
+
fm[key] = val;
|
|
54
64
|
}
|
|
55
65
|
return fm;
|
|
56
66
|
} catch { return {}; }
|
|
57
67
|
}
|
|
58
68
|
|
|
69
|
+
/** Recorta una descripción a n caracteres en límite de palabra, colapsando whitespace. */
|
|
70
|
+
function resumir(texto, n = 110) {
|
|
71
|
+
const limpio = String(texto || '').replace(/\s+/g, ' ').replace(/\|/g, '/').trim();
|
|
72
|
+
if (limpio.length <= n) return limpio;
|
|
73
|
+
const corte = limpio.lastIndexOf(' ', n);
|
|
74
|
+
return limpio.slice(0, corte > 40 ? corte : n) + '…';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function contarArchivosRec(dir, ext) {
|
|
78
|
+
let total = 0;
|
|
79
|
+
try {
|
|
80
|
+
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
81
|
+
if (e.isDirectory()) total += contarArchivosRec(path.join(dir, e.name), ext);
|
|
82
|
+
else if (e.name.endsWith(ext)) total++;
|
|
83
|
+
}
|
|
84
|
+
} catch { /* dir inexistente → 0 */ }
|
|
85
|
+
return total;
|
|
86
|
+
}
|
|
87
|
+
|
|
59
88
|
function contarArchivos(dir, ext) {
|
|
60
89
|
try {
|
|
61
90
|
return fs.readdirSync(dir).filter(f => f.endsWith(ext)).length;
|
|
@@ -94,6 +123,12 @@ function recolectarAgentes() {
|
|
|
94
123
|
version: fm.version || '?',
|
|
95
124
|
model: fm.model || '?',
|
|
96
125
|
nivelRiesgo: fm.nivelRiesgo || '?',
|
|
126
|
+
description: fm.description || '',
|
|
127
|
+
skillsInvocables: (fm.skillsInvocables || '')
|
|
128
|
+
.replace(/^\[|\]$/g, '')
|
|
129
|
+
.split(',')
|
|
130
|
+
.map(s => s.trim())
|
|
131
|
+
.filter(Boolean),
|
|
97
132
|
};
|
|
98
133
|
});
|
|
99
134
|
}
|
|
@@ -105,7 +140,24 @@ function recolectarSkills() {
|
|
|
105
140
|
);
|
|
106
141
|
return dirs.map(d => {
|
|
107
142
|
const fm = leerFrontmatter(path.join(dir, d, 'SKILL.md'));
|
|
108
|
-
return {
|
|
143
|
+
return {
|
|
144
|
+
dir: d,
|
|
145
|
+
name: fm.name || d,
|
|
146
|
+
version: fm.version || '—',
|
|
147
|
+
description: fm.description || '',
|
|
148
|
+
};
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function recolectarComandos() {
|
|
153
|
+
const dir = path.join(RAIZ, 'comandos', 'swl');
|
|
154
|
+
return fs.readdirSync(dir).filter(f => f.endsWith('.md')).map(f => {
|
|
155
|
+
const fm = leerFrontmatter(path.join(dir, f));
|
|
156
|
+
return {
|
|
157
|
+
archivo: f,
|
|
158
|
+
name: fm.name || `swl:${f.replace('.md', '')}`,
|
|
159
|
+
description: fm.description || '',
|
|
160
|
+
};
|
|
109
161
|
});
|
|
110
162
|
}
|
|
111
163
|
|
|
@@ -139,19 +191,38 @@ function generarInventario() {
|
|
|
139
191
|
const skills = recolectarSkills();
|
|
140
192
|
const hooks = recolectarHooks();
|
|
141
193
|
const libs = recolectarLibs();
|
|
142
|
-
const comandos =
|
|
194
|
+
const comandos = recolectarComandos();
|
|
143
195
|
const reglasBase = contarArchivos(path.join(RAIZ, 'reglas'), '.md');
|
|
144
196
|
const reglasLang = fs.readdirSync(path.join(RAIZ, 'reglas', 'lenguajes'))
|
|
145
197
|
.filter(d => fs.statSync(path.join(RAIZ, 'reglas', 'lenguajes', d)).isDirectory())
|
|
146
198
|
.reduce((acc, d) => acc + contarArchivos(path.join(RAIZ, 'reglas', 'lenguajes', d), '.md'), 0);
|
|
147
|
-
const
|
|
148
|
-
const
|
|
199
|
+
const schemasList = fs.readdirSync(path.join(RAIZ, 'schemas')).filter(f => f.endsWith('.json')).sort();
|
|
200
|
+
const scriptsLibList = fs.readdirSync(path.join(RAIZ, 'scripts', 'lib'))
|
|
201
|
+
.filter(f => f.endsWith('.js') || f.endsWith('.py')).sort();
|
|
202
|
+
// Tipos antes omitidos del inventario (auditoría 2026-07-08)
|
|
203
|
+
const fragmentos = fs.readdirSync(path.join(RAIZ, 'agentes')).filter(f => f.startsWith('_') && f.endsWith('.md'));
|
|
204
|
+
const gatewayJs = contarArchivosRec(path.join(RAIZ, 'gateway'), '.js');
|
|
205
|
+
const manifiestosJson = contarArchivos(path.join(RAIZ, 'manifiestos'), '.json');
|
|
206
|
+
const contextos = contarArchivos(path.join(RAIZ, 'contextos'), '.md');
|
|
207
|
+
const plantillasTotal = contarArchivosRec(path.join(RAIZ, 'plantillas'), '.md') + contarArchivosRec(path.join(RAIZ, 'plantillas'), '.yml');
|
|
208
|
+
const scriptsTop = contarArchivos(path.join(RAIZ, 'scripts'), '.js');
|
|
209
|
+
|
|
210
|
+
// Mapa skill → agentes que la declaran en skillsInvocables
|
|
211
|
+
const skillAAgentes = new Map();
|
|
212
|
+
for (const a of agentes) {
|
|
213
|
+
for (const s of a.skillsInvocables) {
|
|
214
|
+
if (!skillAAgentes.has(s)) skillAAgentes.set(s, []);
|
|
215
|
+
skillAAgentes.get(s).push(a.name);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
149
218
|
|
|
150
219
|
const lines = [];
|
|
151
220
|
lines.push(`# INVENTARIO.md — Referencia completa de componentes SWL v${pkg.version}`);
|
|
152
221
|
lines.push('');
|
|
153
222
|
lines.push('> Archivo generado automáticamente por `node scripts/generar-inventario.js`.');
|
|
154
223
|
lines.push('> NO editar manualmente — se regenera con cada release.');
|
|
224
|
+
lines.push('> Índice de descubrimiento: cada catálogo incluye la descripción del');
|
|
225
|
+
lines.push('> componente para decidir qué usar sin abrir su archivo.');
|
|
155
226
|
lines.push('');
|
|
156
227
|
lines.push('## Resumen');
|
|
157
228
|
lines.push('');
|
|
@@ -159,13 +230,19 @@ function generarInventario() {
|
|
|
159
230
|
lines.push('|-----------|----------|');
|
|
160
231
|
lines.push(`| Agentes SWL | ${agentes.length} |`);
|
|
161
232
|
lines.push(`| Habilidades | ${skills.length} |`);
|
|
162
|
-
lines.push(`| Comandos | ${comandos} |`);
|
|
233
|
+
lines.push(`| Comandos | ${comandos.length} |`);
|
|
163
234
|
lines.push(`| Reglas base | ${reglasBase} |`);
|
|
164
235
|
lines.push(`| Reglas por lenguaje | ${reglasLang} |`);
|
|
165
236
|
lines.push(`| Hooks | ${hooks.length} |`);
|
|
166
237
|
lines.push(`| Librerías de hooks | ${libs.length} |`);
|
|
167
|
-
lines.push(`| Schemas | ${
|
|
168
|
-
lines.push(`| Scripts lib | ${
|
|
238
|
+
lines.push(`| Schemas | ${schemasList.length} |`);
|
|
239
|
+
lines.push(`| Scripts lib | ${scriptsLibList.length} |`);
|
|
240
|
+
lines.push(`| Scripts top-level | ${scriptsTop} |`);
|
|
241
|
+
lines.push(`| Fragmentos de agentes | ${fragmentos.length} |`);
|
|
242
|
+
lines.push(`| Gateway (archivos .js) | ${gatewayJs} |`);
|
|
243
|
+
lines.push(`| Manifiestos | ${manifiestosJson} |`);
|
|
244
|
+
lines.push(`| Contextos | ${contextos} |`);
|
|
245
|
+
lines.push(`| Plantillas | ${plantillasTotal} |`);
|
|
169
246
|
lines.push('');
|
|
170
247
|
|
|
171
248
|
// Equipos
|
|
@@ -174,22 +251,47 @@ function generarInventario() {
|
|
|
174
251
|
lines.push('| Equipo | Líder | Miembros paralelos | Cuándo |');
|
|
175
252
|
lines.push('|--------|-------|-------------------|--------|');
|
|
176
253
|
lines.push('| Discovery | investigador-swl | investigador-ux-swl, producto-prd-swl | Proyecto nuevo |');
|
|
177
|
-
lines.push('| Arquitectura | arquitecto-swl | rendimiento-swl, revisor-seguridad-swl | Decisión de diseño |');
|
|
254
|
+
lines.push('| Arquitectura | arquitecto-swl | rendimiento-swl, revisor-seguridad-swl, abogado-diablo-swl | Decisión de diseño |');
|
|
178
255
|
lines.push('| Frontend | frontend-swl | frontend-react-swl, frontend-css-swl, frontend-tailwind-swl | Feature UI compleja |');
|
|
179
256
|
lines.push('| Backend | backend-python-swl | backend-api-swl, backend-workers-swl | Feature backend compleja |');
|
|
180
257
|
lines.push('| Mobile | mobile-cross-swl | mobile-android-swl, mobile-ios-swl, mobile-testing-swl | Feature mobile |');
|
|
181
258
|
lines.push('| Calidad | tdd-qa-swl | revisor-codigo-swl, revisor-seguridad-swl, accesibilidad-wcag-swl | Pre-release |');
|
|
182
|
-
lines.push('|
|
|
259
|
+
lines.push('| Auditoría profunda | nemesis-auditor-swl | feynman-auditor-swl, state-inconsistency-auditor-swl | Lógica compleja con estado acoplado |');
|
|
260
|
+
lines.push('| Operaciones | devops-ci-swl | cloud-infra-swl, observabilidad-swl, sre-swl, gh-fix-ci-swl | Deploy, infra, confiabilidad, fallas CI |');
|
|
183
261
|
lines.push('| Cierre | consolidador-swl | documentador-swl, release-manager-swl, notificador-swl | Fase completada |');
|
|
184
262
|
lines.push('');
|
|
185
263
|
|
|
186
264
|
// Agentes
|
|
187
265
|
lines.push(`## Agentes SWL — Registro completo (${agentes.length})`);
|
|
188
266
|
lines.push('');
|
|
189
|
-
lines.push('| Agente | Versión | Modelo | Riesgo |');
|
|
190
|
-
lines.push('
|
|
267
|
+
lines.push('| Agente | Versión | Modelo | Riesgo | Qué hace / cuándo invocarlo |');
|
|
268
|
+
lines.push('|--------|---------|--------|--------|------------------------------|');
|
|
191
269
|
for (const a of agentes.sort((x, y) => x.name.localeCompare(y.name))) {
|
|
192
|
-
lines.push(`| ${a.name} | ${a.version} | ${a.model} | ${a.nivelRiesgo} |`);
|
|
270
|
+
lines.push(`| ${a.name} | ${a.version} | ${a.model} | ${a.nivelRiesgo} | ${resumir(a.description, 160)} |`);
|
|
271
|
+
}
|
|
272
|
+
lines.push('');
|
|
273
|
+
|
|
274
|
+
// Habilidades — catálogo consultable (antes solo se contaban)
|
|
275
|
+
lines.push(`## Habilidades — Catálogo completo (${skills.length})`);
|
|
276
|
+
lines.push('');
|
|
277
|
+
lines.push('La columna "Agentes" lista quién la declara en `skillsInvocables`;');
|
|
278
|
+
lines.push('"—" significa que se invoca por descripción o desde comandos.');
|
|
279
|
+
lines.push('');
|
|
280
|
+
lines.push('| Skill | Versión | Descripción | Agentes |');
|
|
281
|
+
lines.push('|-------|---------|-------------|---------|');
|
|
282
|
+
for (const s of [...skills].sort((x, y) => x.name.localeCompare(y.name))) {
|
|
283
|
+
const invocadores = (skillAAgentes.get(s.name) || []).join(', ') || '—';
|
|
284
|
+
lines.push(`| ${s.name} | ${s.version} | ${resumir(s.description, 140)} | ${invocadores} |`);
|
|
285
|
+
}
|
|
286
|
+
lines.push('');
|
|
287
|
+
|
|
288
|
+
// Comandos — catálogo consultable (antes solo se contaban)
|
|
289
|
+
lines.push(`## Comandos /swl:* — Catálogo completo (${comandos.length})`);
|
|
290
|
+
lines.push('');
|
|
291
|
+
lines.push('| Comando | Descripción |');
|
|
292
|
+
lines.push('|---------|-------------|');
|
|
293
|
+
for (const c of [...comandos].sort((x, y) => x.name.localeCompare(y.name))) {
|
|
294
|
+
lines.push(`| /${c.name} | ${resumir(c.description, 180)} |`);
|
|
193
295
|
}
|
|
194
296
|
lines.push('');
|
|
195
297
|
|
|
@@ -243,6 +345,26 @@ function generarInventario() {
|
|
|
243
345
|
}
|
|
244
346
|
lines.push('');
|
|
245
347
|
|
|
348
|
+
// Schemas — superficie de contrato del sistema
|
|
349
|
+
lines.push(`## Schemas (${schemasList.length})`);
|
|
350
|
+
lines.push('');
|
|
351
|
+
lines.push('| Schema | Archivo |');
|
|
352
|
+
lines.push('|--------|---------|');
|
|
353
|
+
for (const s of schemasList) {
|
|
354
|
+
lines.push(`| ${s.replace('.schema.json', '').replace('.json', '')} | \`schemas/${s}\` |`);
|
|
355
|
+
}
|
|
356
|
+
lines.push('');
|
|
357
|
+
|
|
358
|
+
// Scripts lib — enumerados (antes solo se contaban)
|
|
359
|
+
lines.push(`## Librerías de scripts (scripts/lib/) — ${scriptsLibList.length}`);
|
|
360
|
+
lines.push('');
|
|
361
|
+
lines.push('| Librería | Archivo |');
|
|
362
|
+
lines.push('|----------|---------|');
|
|
363
|
+
for (const s of scriptsLibList) {
|
|
364
|
+
lines.push(`| ${s.replace(/\.(js|py)$/, '')} | \`scripts/lib/${s}\` |`);
|
|
365
|
+
}
|
|
366
|
+
lines.push('');
|
|
367
|
+
|
|
246
368
|
return lines.join('\n');
|
|
247
369
|
}
|
|
248
370
|
|
|
@@ -353,7 +475,9 @@ function generarSalud() {
|
|
|
353
475
|
const lines = [];
|
|
354
476
|
lines.push('# Reporte de Salud del Sistema SWL');
|
|
355
477
|
lines.push('');
|
|
356
|
-
|
|
478
|
+
// Fecha LOCAL (no UTC): en horario de México la tarde ya es "mañana" en UTC
|
|
479
|
+
// y el reporte quedaba con fecha futura. 'sv' formatea como YYYY-MM-DD.
|
|
480
|
+
lines.push(`**Generado**: ${new Date().toLocaleDateString('sv')}`);
|
|
357
481
|
lines.push(`**Versión del sistema**: ${pkg.version}`);
|
|
358
482
|
lines.push('');
|
|
359
483
|
lines.push('> Archivo generado automáticamente por `node scripts/generar-inventario.js --salud`.');
|
|
@@ -463,11 +587,12 @@ function generarLlmsTxt() {
|
|
|
463
587
|
L.push('');
|
|
464
588
|
L.push('## Componentes');
|
|
465
589
|
L.push('');
|
|
466
|
-
|
|
467
|
-
L.push(`- ${
|
|
468
|
-
L.push(`- ${
|
|
469
|
-
L.push(`- ${
|
|
470
|
-
L.push(`- ${
|
|
590
|
+
// llmstxt.org: cada entrada de sección debe ser un link markdown navegable.
|
|
591
|
+
L.push(`- [${agentes} agentes especializados](AGENTS.md): orquestación, implementación por stack, revisión, calidad, diseño — fuente en \`agentes/\``);
|
|
592
|
+
L.push(`- [${skills} habilidades cargables bajo demanda](INVENTARIO.md): conocimiento operacional con divulgación progresiva — fuente en \`habilidades/\``);
|
|
593
|
+
L.push(`- [${comandos} comandos /swl:*](COMANDOS.md): ciclo GSD, calidad, release, diagnóstico — fuente en \`comandos/swl/\``);
|
|
594
|
+
L.push(`- [${reglasBase} reglas base + ${reglasLang} por lenguaje](INVENTARIO.md): políticas obligatorias por matcher — fuente en \`reglas/\``);
|
|
595
|
+
L.push(`- [${hooks} hooks](INVENTARIO.md): telemetría, validación, seguridad; zero-deps, escrituras atómicas — fuente en \`hooks/\``);
|
|
471
596
|
L.push('');
|
|
472
597
|
L.push('## Opcional');
|
|
473
598
|
L.push('');
|
|
@@ -479,6 +604,83 @@ function generarLlmsTxt() {
|
|
|
479
604
|
return L.join('\n');
|
|
480
605
|
}
|
|
481
606
|
|
|
607
|
+
// ── MAPEO_SKILLS_AGENTES.md ───────────────────────────────────────────
|
|
608
|
+
// Antes se mantenía a mano y era el peor infractor de drift del sistema
|
|
609
|
+
// (auditoría 2026-07-08: mencionaba skills retiradas, mapeos falsos en 3/5
|
|
610
|
+
// agentes muestreados y totales stale, pese a ser insumo del gate de release).
|
|
611
|
+
// Se deriva por completo de los skillsInvocables del frontmatter de agentes.
|
|
612
|
+
function generarMapeo() {
|
|
613
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(RAIZ, 'package.json'), 'utf8'));
|
|
614
|
+
const agentes = recolectarAgentes();
|
|
615
|
+
const skills = recolectarSkills();
|
|
616
|
+
const nombresSkill = new Set(skills.map(s => s.name));
|
|
617
|
+
|
|
618
|
+
const L = [];
|
|
619
|
+
L.push(`# MAPEO_SKILLS_AGENTES.md — v${pkg.version}`);
|
|
620
|
+
L.push('');
|
|
621
|
+
L.push('> Archivo generado automáticamente por `node scripts/generar-inventario.js`.');
|
|
622
|
+
L.push('> NO editar manualmente — se deriva de los `skillsInvocables` declarados');
|
|
623
|
+
L.push('> en el frontmatter de `agentes/*.md`. El mapa inverso (skill → agentes)');
|
|
624
|
+
L.push('> vive en `INVENTARIO.md § Habilidades — Catálogo completo`.');
|
|
625
|
+
L.push('');
|
|
626
|
+
L.push(`Total de agentes: ${agentes.length}`);
|
|
627
|
+
L.push(`Total de skills: ${skills.length}`);
|
|
628
|
+
L.push('');
|
|
629
|
+
L.push('## Agente → skills que declara invocables');
|
|
630
|
+
L.push('');
|
|
631
|
+
L.push('| Agente | # | skillsInvocables |');
|
|
632
|
+
L.push('|--------|---|------------------|');
|
|
633
|
+
// Skills de la colección oficial Anthropic (opt-in, instaladas en
|
|
634
|
+
// .claude/skills/ vía `swl-ses skills add anthropics/skills`) — referencias
|
|
635
|
+
// legítimas aunque no vivan en habilidades/. Ver MANUAL_USO § Anthropic Skills.
|
|
636
|
+
const SKILLS_ANTHROPIC = new Set([
|
|
637
|
+
'pdf', 'docx', 'xlsx', 'pptx', 'frontend-design', 'web-artifacts-builder',
|
|
638
|
+
'canvas-design', 'algorithmic-art', 'theme-factory', 'slack-gif-creator',
|
|
639
|
+
'claude-api', 'mcp-builder', 'webapp-testing', 'doc-coauthoring',
|
|
640
|
+
'internal-comms', 'brand-guidelines', 'skill-creator',
|
|
641
|
+
]);
|
|
642
|
+
const externas = new Set();
|
|
643
|
+
const inexistentes = [];
|
|
644
|
+
for (const a of [...agentes].sort((x, y) => x.name.localeCompare(y.name))) {
|
|
645
|
+
for (const s of a.skillsInvocables) {
|
|
646
|
+
if (s === 'todos') continue; // centinela: el agente puede invocar cualquier skill
|
|
647
|
+
if (nombresSkill.has(s)) continue;
|
|
648
|
+
if (SKILLS_ANTHROPIC.has(s)) externas.add(s);
|
|
649
|
+
else inexistentes.push(`${a.name} → ${s}`);
|
|
650
|
+
}
|
|
651
|
+
const etiqueta = a.skillsInvocables.includes('todos')
|
|
652
|
+
? 'todos (acceso a cualquier skill)'
|
|
653
|
+
: (a.skillsInvocables.join(', ') || '—');
|
|
654
|
+
L.push(`| ${a.name} | ${a.skillsInvocables.includes('todos') ? skills.length : a.skillsInvocables.length} | ${etiqueta} |`);
|
|
655
|
+
}
|
|
656
|
+
L.push('');
|
|
657
|
+
if (externas.size > 0) {
|
|
658
|
+
L.push(`## Skills externas referenciadas (colección Anthropic, opt-in) — ${externas.size}`);
|
|
659
|
+
L.push('');
|
|
660
|
+
L.push('No viven en `habilidades/`; se instalan con `swl-ses skills add anthropics/skills`.');
|
|
661
|
+
L.push('Si la colección no está instalada, el agente degrada sin fallar.');
|
|
662
|
+
L.push('');
|
|
663
|
+
L.push([...externas].sort().map(s => `\`${s}\``).join(', '));
|
|
664
|
+
L.push('');
|
|
665
|
+
}
|
|
666
|
+
if (inexistentes.length > 0) {
|
|
667
|
+
L.push('## ⚠ Referencias a skills inexistentes (corregir en el frontmatter del agente)');
|
|
668
|
+
L.push('');
|
|
669
|
+
for (const i of inexistentes) L.push(`- ${i}`);
|
|
670
|
+
L.push('');
|
|
671
|
+
}
|
|
672
|
+
const declaradas = new Set(agentes.flatMap(a => a.skillsInvocables));
|
|
673
|
+
const sinAgente = skills.filter(s => !declaradas.has(s.name));
|
|
674
|
+
L.push(`## Skills sin agente declarado (${sinAgente.length})`);
|
|
675
|
+
L.push('');
|
|
676
|
+
L.push('No es error: se invocan por descripción (matching nativo del runtime),');
|
|
677
|
+
L.push('desde comandos `/swl:*`, o son infraestructura del sistema.');
|
|
678
|
+
L.push('');
|
|
679
|
+
L.push(sinAgente.map(s => `\`${s.name}\``).join(', '));
|
|
680
|
+
L.push('');
|
|
681
|
+
return L.join('\n');
|
|
682
|
+
}
|
|
683
|
+
|
|
482
684
|
// ── Ejecutar ──────────────────────────────────────────────────────────
|
|
483
685
|
|
|
484
686
|
if (AMBOS || SOLO_INV) {
|
|
@@ -513,3 +715,14 @@ if (AMBOS || SOLO_LLMS) {
|
|
|
513
715
|
console.log('llms.txt generado correctamente.');
|
|
514
716
|
}
|
|
515
717
|
}
|
|
718
|
+
|
|
719
|
+
if (AMBOS || args.has('--mapeo')) {
|
|
720
|
+
const mapeo = generarMapeo();
|
|
721
|
+
if (DRY) {
|
|
722
|
+
console.log('\n=== MAPEO_SKILLS_AGENTES.md (dry-run) ===\n');
|
|
723
|
+
console.log(mapeo.substring(0, 1500) + '\n...(truncado)');
|
|
724
|
+
} else {
|
|
725
|
+
atomicWriteSync(path.join(RAIZ, '.planning', 'MAPEO_SKILLS_AGENTES.md'), mapeo, 'utf8');
|
|
726
|
+
console.log('MAPEO_SKILLS_AGENTES.md generado correctamente.');
|
|
727
|
+
}
|
|
728
|
+
}
|
|
@@ -207,7 +207,7 @@ function renderResumen() {
|
|
|
207
207
|
// ---------------------------------------------------------------------------
|
|
208
208
|
|
|
209
209
|
function main() {
|
|
210
|
-
const fecha = new Date().
|
|
210
|
+
const fecha = new Date().toLocaleDateString('sv'); // local, no UTC (regla CLAUDE.md Code style)
|
|
211
211
|
const contenido = `# Matriz de cobertura SWL × lenguaje
|
|
212
212
|
|
|
213
213
|
> **Generado automáticamente** por \`scripts/generar-matriz-lenguajes.js\`.
|
package/scripts/instalador.js
CHANGED
|
@@ -857,7 +857,20 @@ async function install(opciones) {
|
|
|
857
857
|
accion: resMerge.accion,
|
|
858
858
|
});
|
|
859
859
|
} else {
|
|
860
|
-
// Comportamiento clásico: sobrescribir archivo completo (codex/gemini/copilot/opencode)
|
|
860
|
+
// Comportamiento clásico: sobrescribir archivo completo (codex/gemini/copilot/opencode).
|
|
861
|
+
// GUARD anti-clobber (bug 2026-07-08): si el destino YA existe y NO fue
|
|
862
|
+
// generado por SWL (sin el marcador "Generado por swl-ses"), es contenido
|
|
863
|
+
// del usuario o documentación canónica del proyecto — sobreescribirlo es
|
|
864
|
+
// pérdida de datos (caso real: install --target opencode pisó el AGENTS.md
|
|
865
|
+
// canónico del repo madre, 420 líneas). Preservar y avisar; el usuario
|
|
866
|
+
// puede borrar el archivo manualmente si quiere el generado.
|
|
867
|
+
const yaExiste = fs.existsSync(rutaInstrucciones);
|
|
868
|
+
const esGeneradoSwl = yaExiste
|
|
869
|
+
? fs.readFileSync(rutaInstrucciones, 'utf-8').includes('Generado por swl-ses')
|
|
870
|
+
: false;
|
|
871
|
+
if (yaExiste && !esGeneradoSwl) {
|
|
872
|
+
console.log(` = ${instrucciones.rutaRelativa} NO modificado — existe contenido propio del proyecto (sin marcador "Generado por swl-ses"). Borra el archivo y reinstala si quieres el generado.`);
|
|
873
|
+
} else {
|
|
861
874
|
if (!fs.existsSync(dirInstrucciones)) {
|
|
862
875
|
fs.mkdirSync(dirInstrucciones, { recursive: true });
|
|
863
876
|
}
|
|
@@ -868,6 +881,7 @@ async function install(opciones) {
|
|
|
868
881
|
destino: rutaInstrucciones,
|
|
869
882
|
tipo: 'instrucciones',
|
|
870
883
|
});
|
|
884
|
+
} // cierre del guard anti-clobber
|
|
871
885
|
}
|
|
872
886
|
}
|
|
873
887
|
} catch (err) {
|
|
@@ -44,9 +44,10 @@ const WORKFLOWS_DIR = '.github/workflows';
|
|
|
44
44
|
|
|
45
45
|
/** Workflows que este módulo gestiona (identificados por nombre de archivo). */
|
|
46
46
|
const WORKFLOWS_SWL = {
|
|
47
|
-
security:
|
|
48
|
-
ci:
|
|
49
|
-
release:
|
|
47
|
+
security: 'swl-security.yml',
|
|
48
|
+
ci: 'swl-ci.yml',
|
|
49
|
+
release: 'release-please.yml',
|
|
50
|
+
devsecops: 'swl-devsecops.yml',
|
|
50
51
|
};
|
|
51
52
|
|
|
52
53
|
/** Secrets que requiere cada workflow. */
|
|
@@ -54,6 +55,9 @@ const SECRETS_REQUERIDOS = {
|
|
|
54
55
|
'swl-security.yml': ['CLAUDE_API_KEY'],
|
|
55
56
|
'swl-ci.yml': [],
|
|
56
57
|
'release-please.yml': [],
|
|
58
|
+
// GITLEAKS_LICENSE solo es necesaria en repos de organización (gratuita
|
|
59
|
+
// para individuos) — no se lista como requerida para no bloquear el caso común.
|
|
60
|
+
'swl-devsecops.yml': [],
|
|
57
61
|
};
|
|
58
62
|
|
|
59
63
|
// ---------------------------------------------------------------------------
|
|
@@ -121,6 +125,7 @@ function listarPlantillas() {
|
|
|
121
125
|
* @param {boolean} [opciones.withSecurity=true] Instalar swl-security.yml
|
|
122
126
|
* @param {boolean} [opciones.withCi=true] Instalar swl-ci.yml
|
|
123
127
|
* @param {boolean} [opciones.withReleasePlease=false] Instalar release-please.yml
|
|
128
|
+
* @param {boolean} [opciones.withDevsecops=false] Instalar swl-devsecops.yml (gitleaks + audit de deps)
|
|
124
129
|
* @param {boolean} [opciones.dryRun=false] Solo mostrar cambios, no copiar
|
|
125
130
|
* @param {boolean} [opciones.force=false] Sobreescribir archivos existentes
|
|
126
131
|
* @param {string} [opciones._proyectoPathOverride] Path del proyecto (tests)
|
|
@@ -130,6 +135,7 @@ function init({
|
|
|
130
135
|
withSecurity = true,
|
|
131
136
|
withCi = true,
|
|
132
137
|
withReleasePlease = false,
|
|
138
|
+
withDevsecops = false,
|
|
133
139
|
dryRun = false,
|
|
134
140
|
force = false,
|
|
135
141
|
_proyectoPathOverride,
|
|
@@ -141,6 +147,7 @@ function init({
|
|
|
141
147
|
if (withSecurity) seleccionados.push(WORKFLOWS_SWL.security);
|
|
142
148
|
if (withCi) seleccionados.push(WORKFLOWS_SWL.ci);
|
|
143
149
|
if (withReleasePlease) seleccionados.push(WORKFLOWS_SWL.release);
|
|
150
|
+
if (withDevsecops) seleccionados.push(WORKFLOWS_SWL.devsecops);
|
|
144
151
|
|
|
145
152
|
const copiados = [];
|
|
146
153
|
const existentes = [];
|
|
@@ -378,16 +378,25 @@ function detectarInstalacionesDuales(runtimeId, opciones = {}) {
|
|
|
378
378
|
*
|
|
379
379
|
* @returns {string[]} Lista de runtime IDs ordenada de "más usado" a "menos usado".
|
|
380
380
|
*/
|
|
381
|
-
function listarRuntimesInstalables() {
|
|
382
|
-
|
|
381
|
+
function listarRuntimesInstalables(opciones = {}) {
|
|
382
|
+
const existeDir = opciones.existeDir || fs.existsSync;
|
|
383
|
+
const base = [
|
|
383
384
|
'claude', // Soporte completo, primer ciudadano
|
|
384
385
|
'cursor', // Soporte parcial — reglas + MCP
|
|
385
386
|
'codex', // Soporte parcial — AGENTS.md + MCP (v1.5.0+)
|
|
386
387
|
'opencode', // Soporte completo
|
|
387
388
|
'gemini', // Soporte completo
|
|
388
389
|
'copilot', // Soporte parcial — agentes consolidados
|
|
389
|
-
// 'openclaude' intencionalmente excluido — comparte dir con claude
|
|
390
390
|
];
|
|
391
|
+
// OpenClaude comparte el dir de PROYECTO (.claude/) con Claude Code, así
|
|
392
|
+
// que NO se bootstrapea por default (evita duplicados para quien no lo
|
|
393
|
+
// usa). Pero su GLOBAL (~/.openclaude) es un dir propio: si YA existe (el
|
|
394
|
+
// usuario lo instaló alguna vez), --all-runtimes DEBE actualizarlo —
|
|
395
|
+
// excluirlo incondicionalmente dejaba un drift de versión permanente que
|
|
396
|
+
// ningún reinstall masivo cerraba (caso real doctor 2026-07-03: todo el
|
|
397
|
+
// parque en 2.4.2 y ~/.openclaude clavado en 2.4.1 pese a --all-runtimes).
|
|
398
|
+
if (existeDir(RUNTIMES.openclaude.global)) base.splice(1, 0, 'openclaude');
|
|
399
|
+
return base;
|
|
391
400
|
}
|
|
392
401
|
|
|
393
402
|
module.exports = {
|
|
@@ -38,7 +38,9 @@ function nowIso() {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
function todayDate() {
|
|
41
|
-
|
|
41
|
+
// Fecha LOCAL, no UTC: desde México la tarde ya es "mañana" en UTC y el id
|
|
42
|
+
// del diary quedaba fechado en el futuro (regla CLAUDE.md § Code style).
|
|
43
|
+
return new Date().toLocaleDateString('sv');
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
function shortHash(input) {
|
|
@@ -367,7 +367,7 @@ function generarLineaTemporal({
|
|
|
367
367
|
for (let i = dias - 1; i >= 0; i--) {
|
|
368
368
|
const inicioDia = ahora - (i + 1) * 24 * 3600 * 1000;
|
|
369
369
|
const finDia = ahora - i * 24 * 3600 * 1000;
|
|
370
|
-
const fecha = new Date(inicioDia).
|
|
370
|
+
const fecha = new Date(inicioDia).toLocaleDateString('sv');
|
|
371
371
|
|
|
372
372
|
const del_dia = eventos.filter(e => {
|
|
373
373
|
const ms = aMs(e.timestamp ?? e.ts ?? e.inicio ?? e.created_at);
|