@saulwade/swl-ses 1.0.1 → 1.1.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 +7 -5
- package/README.md +2 -2
- package/agentes/accesibilidad-wcag-swl.md +5 -7
- package/agentes/arquitecto-swl.md +5 -3
- package/agentes/auto-evolucion-swl.md +42 -12
- package/agentes/backend-api-swl.md +5 -3
- package/agentes/backend-csharp-swl.md +5 -3
- package/agentes/backend-go-swl.md +5 -3
- package/agentes/backend-java-swl.md +5 -3
- package/agentes/backend-node-swl.md +5 -3
- package/agentes/backend-python-swl.md +5 -3
- package/agentes/backend-rust-swl.md +5 -3
- package/agentes/backend-workers-swl.md +5 -3
- package/agentes/cloud-infra-swl.md +5 -6
- package/agentes/consolidador-swl.md +5 -3
- package/agentes/datos-swl.md +5 -7
- package/agentes/depurador-swl.md +6 -3
- package/agentes/devops-ci-swl.md +5 -3
- package/agentes/disenador-ui-swl.md +5 -7
- package/agentes/documentador-swl.md +5 -3
- package/agentes/frontend-angular-swl.md +5 -11
- package/agentes/frontend-css-swl.md +5 -9
- package/agentes/frontend-react-swl.md +5 -9
- package/agentes/frontend-swl.md +5 -9
- package/agentes/frontend-tailwind-swl.md +5 -9
- package/agentes/implementador-swl.md +6 -3
- package/agentes/investigador-swl.md +5 -3
- package/agentes/investigador-ux-swl.md +5 -9
- package/agentes/llm-apps-swl.md +5 -3
- package/agentes/migrador-swl.md +6 -3
- package/agentes/mobile-android-swl.md +5 -3
- package/agentes/mobile-cross-swl.md +5 -3
- package/agentes/mobile-ios-swl.md +5 -3
- package/agentes/mobile-testing-swl.md +5 -3
- package/agentes/notificador-swl.md +5 -3
- package/agentes/observabilidad-swl.md +5 -3
- package/agentes/orquestador-swl.md +29 -8
- package/agentes/pagos-swl.md +5 -3
- package/agentes/perfilador-usuario-swl.md +4 -2
- package/agentes/planificador-swl.md +5 -3
- package/agentes/producto-prd-swl.md +5 -3
- package/agentes/red-team-swl.md +4 -2
- package/agentes/release-manager-swl.md +6 -8
- package/agentes/rendimiento-swl.md +5 -6
- package/agentes/resolutor-build-swl.md +5 -3
- package/agentes/revisor-angular-swl.md +5 -3
- package/agentes/revisor-codigo-swl.md +5 -3
- package/agentes/revisor-csharp-swl.md +5 -3
- package/agentes/revisor-go-swl.md +5 -3
- package/agentes/revisor-java-swl.md +5 -3
- package/agentes/revisor-kotlin-swl.md +5 -3
- package/agentes/revisor-nextjs-swl.md +5 -3
- package/agentes/revisor-php-swl.md +5 -3
- package/agentes/revisor-react-swl.md +5 -3
- package/agentes/revisor-rust-swl.md +5 -3
- package/agentes/revisor-seguridad-swl.md +5 -3
- package/agentes/revisor-swift-swl.md +5 -3
- package/agentes/revisor-typescript-swl.md +5 -3
- package/agentes/sre-swl.md +5 -3
- package/agentes/tdd-qa-swl.md +5 -3
- package/agentes/ux-disenador-swl.md +5 -9
- package/comandos/swl/evaluar-skill.md +18 -0
- package/comandos/swl/evolucion-estado.md +49 -0
- package/comandos/swl/release.md +41 -0
- package/comandos/swl/salud.md +23 -0
- package/hooks/auto-evolucion.js +35 -1
- package/hooks/clasificador-mensajes.js +50 -3
- package/hooks/lib/agent-routing.js +107 -0
- package/hooks/lib/delegation-tracker.js +162 -44
- package/hooks/lib/evolution-tracker.js +12 -3
- package/hooks/lib/memory-search.js +59 -1
- package/hooks/lib/nudge-tracker.js +10 -1
- package/hooks/lib/provenance-tracker.js +11 -3
- package/hooks/lib/text-similarity.js +241 -0
- package/hooks/metricas-evolucion.js +168 -1
- package/hooks/monitor-contexto.js +54 -6
- package/hooks/preservar-estado-pre-compact.js +11 -1
- package/hooks/risk-scoring.js +10 -1
- package/hooks/tracking-costos.js +10 -1
- package/hooks/validar-formato-post-subagente.js +140 -0
- package/hooks/validar-memoria-hook.js +218 -0
- package/manifiestos/agent-output-schemas.json +57 -0
- package/manifiestos/hooks-config.json +18 -0
- package/manifiestos/modulos.json +3 -0
- package/manifiestos/skills-lock.json +1065 -0
- package/package.json +1 -1
- package/plugin.json +1 -1
- package/reglas/arquitectura.md +20 -0
- package/reglas/fragmentos-compartidos.md +152 -0
- package/reglas/gobernanza.md +10 -1
- package/reglas/seguridad-agentes.md +12 -0
- package/reglas/skills-estandar.md +19 -0
- package/schemas/agent-frontmatter.schema.json +18 -0
- package/scripts/auditar-agentes-gaps.js +9 -1
- package/scripts/auditar-cobertura-frameworks.js +9 -1
- package/scripts/auditar-skills-gaps.js +9 -1
- package/scripts/bootstrap-instintos.js +11 -1
- package/scripts/generar-inventario.js +112 -9
- package/scripts/generar-matriz-lenguajes.js +271 -0
- package/scripts/generar-skills-lock.js +190 -0
- package/scripts/lib/estado.js +12 -2
- package/scripts/lib/gitignore-manifest.js +32 -2
- package/scripts/migrar-csv-a-array.js +168 -0
- package/scripts/migrar-fase-dominio.js +201 -0
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook: validar-formato-post-subagente.js
|
|
6
|
+
* Tipo: SubagentStop (async: true — fire-and-forget)
|
|
7
|
+
*
|
|
8
|
+
* Cuando un subagente SWL termina, valida que su output cumple con el
|
|
9
|
+
* schema declarado en `manifiestos/agent-output-schemas.json`. Si el
|
|
10
|
+
* agente no tiene schema declarado, el hook no hace nada — no asume
|
|
11
|
+
* que todo agente debe seguir el formato compacto.
|
|
12
|
+
*
|
|
13
|
+
* Registra el resultado en `.planning/evolucion/formato-violaciones.jsonl`
|
|
14
|
+
* para que `metricas-evolucion.js` calcule la tasa de violación por
|
|
15
|
+
* agente y la incluya en el dashboard de calidad conductual.
|
|
16
|
+
*
|
|
17
|
+
* Schema simple: lista de patrones regex que DEBEN aparecer en el output.
|
|
18
|
+
* Si todos matchean → conforme. Si falta alguno → violación con detalle.
|
|
19
|
+
*
|
|
20
|
+
* Opt-out: SWL_FORMATO_VALIDACION=0 desactiva el hook.
|
|
21
|
+
*
|
|
22
|
+
* El hook nunca bloquea — solo registra para análisis posterior.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const fs = require('fs');
|
|
26
|
+
const path = require('path');
|
|
27
|
+
|
|
28
|
+
const CWD = process.cwd();
|
|
29
|
+
const SCHEMAS_PATH = path.join(CWD, 'manifiestos', 'agent-output-schemas.json');
|
|
30
|
+
const LOG_PATH = path.join(CWD, '.planning', 'evolucion', 'formato-violaciones.jsonl');
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Carga del schema (una vez)
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
function cargarSchemas() {
|
|
37
|
+
try {
|
|
38
|
+
const raw = fs.readFileSync(SCHEMAS_PATH, 'utf8');
|
|
39
|
+
const parsed = JSON.parse(raw);
|
|
40
|
+
return parsed.schemas || {};
|
|
41
|
+
} catch {
|
|
42
|
+
return {};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Validación
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Compara el output contra el schema. Devuelve { violation, errors }.
|
|
52
|
+
* @param {string} output - Texto del output del subagente
|
|
53
|
+
* @param {object} schema - { patronesRequeridos: string[] }
|
|
54
|
+
*/
|
|
55
|
+
function validarOutput(output, schema) {
|
|
56
|
+
const errors = [];
|
|
57
|
+
const patrones = Array.isArray(schema.patronesRequeridos)
|
|
58
|
+
? schema.patronesRequeridos
|
|
59
|
+
: [];
|
|
60
|
+
for (const patron of patrones) {
|
|
61
|
+
// El schema puede declarar inline flags estilo (?im) por compatibilidad
|
|
62
|
+
// con regex POSIX. JavaScript no los soporta inline — los stripeamos
|
|
63
|
+
// y aplicamos 'im' siempre (case-insensitive + multiline).
|
|
64
|
+
const limpio = patron.replace(/^\(\?[imsxu]+\)/, '');
|
|
65
|
+
let regex;
|
|
66
|
+
try { regex = new RegExp(limpio, 'im'); }
|
|
67
|
+
catch { errors.push(`Patrón inválido en schema: ${patron}`); continue; }
|
|
68
|
+
if (!regex.test(output)) {
|
|
69
|
+
errors.push(`Falta patrón requerido: ${patron}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { violation: errors.length > 0, errors };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Extrae el output textual del subagente del payload del hook.
|
|
77
|
+
* El payload del SubagentStop expone el resultado en distintos lugares
|
|
78
|
+
* según versión de Claude Code; intentamos varias rutas.
|
|
79
|
+
*/
|
|
80
|
+
function extraerOutput(data) {
|
|
81
|
+
const r = data.tool_response || data.tool_result || data.response || {};
|
|
82
|
+
// Posibles ubicaciones del output del subagente
|
|
83
|
+
if (typeof r.text === 'string') return r.text;
|
|
84
|
+
if (typeof r.content === 'string') return r.content;
|
|
85
|
+
if (Array.isArray(r.messages)) {
|
|
86
|
+
return r.messages
|
|
87
|
+
.map(m => (typeof m.content === 'string' ? m.content : ''))
|
|
88
|
+
.filter(Boolean)
|
|
89
|
+
.join('\n');
|
|
90
|
+
}
|
|
91
|
+
if (typeof r.output === 'string') return r.output;
|
|
92
|
+
return '';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function ensureDir() {
|
|
96
|
+
try { fs.mkdirSync(path.dirname(LOG_PATH), { recursive: true }); } catch { /* ignore */ }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ---------------------------------------------------------------------------
|
|
100
|
+
// Entrypoint
|
|
101
|
+
// ---------------------------------------------------------------------------
|
|
102
|
+
|
|
103
|
+
let inputRaw = '';
|
|
104
|
+
process.stdin.on('data', chunk => { inputRaw += chunk; });
|
|
105
|
+
|
|
106
|
+
process.stdin.on('end', () => {
|
|
107
|
+
try {
|
|
108
|
+
if (process.env.SWL_FORMATO_VALIDACION === '0') return;
|
|
109
|
+
|
|
110
|
+
const data = JSON.parse(inputRaw);
|
|
111
|
+
const subagentType =
|
|
112
|
+
data.tool_input?.subagent_type ||
|
|
113
|
+
data.tool?.input?.subagent_type ||
|
|
114
|
+
data.subagent_type ||
|
|
115
|
+
null;
|
|
116
|
+
if (!subagentType) return;
|
|
117
|
+
|
|
118
|
+
const schemas = cargarSchemas();
|
|
119
|
+
const schema = schemas[subagentType];
|
|
120
|
+
if (!schema) return; // agente sin schema → no se evalúa
|
|
121
|
+
|
|
122
|
+
const output = extraerOutput(data);
|
|
123
|
+
if (!output || output.length < 10) return; // output trivial — no evaluar
|
|
124
|
+
|
|
125
|
+
const { violation, errors } = validarOutput(output, schema);
|
|
126
|
+
const entry = {
|
|
127
|
+
ts: new Date().toISOString(),
|
|
128
|
+
sessionId: String(data.session_id || 'default'),
|
|
129
|
+
agente: subagentType,
|
|
130
|
+
violation,
|
|
131
|
+
errors,
|
|
132
|
+
outputLen: output.length,
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
ensureDir();
|
|
136
|
+
fs.appendFileSync(LOG_PATH, JSON.stringify(entry) + '\n', 'utf8');
|
|
137
|
+
} catch {
|
|
138
|
+
// SubagentStop hook nunca bloquea por error interno.
|
|
139
|
+
}
|
|
140
|
+
});
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Hook: validar-memoria-hook.js
|
|
6
|
+
* Tipo: PostToolUse (matcher: Write|Edit|MultiEdit)
|
|
7
|
+
*
|
|
8
|
+
* Cierra el gap señalado en `reglas/memoria-consolidada.md`: el script
|
|
9
|
+
* `scripts/validar-memoria.js` solo se ejecuta manualmente vía CLI, así
|
|
10
|
+
* que la contaminación entre canales (perfil-usuario, APRENDIZAJES,
|
|
11
|
+
* instintos) sucedía sin que nadie se enterara hasta que un humano
|
|
12
|
+
* corría el validador.
|
|
13
|
+
*
|
|
14
|
+
* Este hook dispara `validar-memoria.js` en modo JSON cada vez que se
|
|
15
|
+
* escribe un archivo de memoria sensible:
|
|
16
|
+
* - `.planning/APRENDIZAJES.md`
|
|
17
|
+
* - `instintos/perfil-usuario.yaml`
|
|
18
|
+
* - `instintos/proyecto.yaml`
|
|
19
|
+
* - `instintos/global.yaml`
|
|
20
|
+
*
|
|
21
|
+
* Comportamiento:
|
|
22
|
+
* - Sin violaciones → silencioso (exit 0).
|
|
23
|
+
* - Violaciones menores (canal incorrecto, duplicación cross-canal) →
|
|
24
|
+
* emite nudge informativo via systemMessage.
|
|
25
|
+
* - Violaciones críticas (secretos detectados) → emite mensaje fuerte
|
|
26
|
+
* pero NO bloquea (siguiendo el contrato de hooks PostToolUse: ya pasó).
|
|
27
|
+
* El bloqueo de secretos en escritura corresponde a `escaneo-secretos`
|
|
28
|
+
* (PreToolUse), este hook es la red de defensa secundaria.
|
|
29
|
+
*
|
|
30
|
+
* Opt-out: SWL_VALIDAR_MEMORIA=0 desactiva el hook.
|
|
31
|
+
*
|
|
32
|
+
* El hook nunca bloquea el flujo (siempre exit 0). Los errores internos
|
|
33
|
+
* se ignoran silenciosamente — la regla "PostToolUse no rompe nada".
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
const fs = require('fs');
|
|
37
|
+
const path = require('path');
|
|
38
|
+
const { spawnSync } = require('child_process');
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
// Configuración
|
|
42
|
+
// ---------------------------------------------------------------------------
|
|
43
|
+
|
|
44
|
+
/** Archivos cuya modificación dispara la validación. Paths relativos al CWD. */
|
|
45
|
+
const ARCHIVOS_MEMORIA = [
|
|
46
|
+
'.planning/APRENDIZAJES.md',
|
|
47
|
+
'instintos/perfil-usuario.yaml',
|
|
48
|
+
'instintos/proyecto.yaml',
|
|
49
|
+
'instintos/global.yaml',
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
/** Path del validador. */
|
|
53
|
+
const VALIDADOR = path.join(process.cwd(), 'scripts', 'validar-memoria.js');
|
|
54
|
+
|
|
55
|
+
/** Timeout para el validador (ms). Si tarda más, se aborta sin bloquear. */
|
|
56
|
+
const TIMEOUT_MS = 5000;
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Utilidades
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
|
|
62
|
+
/** Normaliza un path a forma POSIX para comparar contra ARCHIVOS_MEMORIA. */
|
|
63
|
+
function normalizar(p) {
|
|
64
|
+
if (!p) return '';
|
|
65
|
+
return String(p).replace(/\\/g, '/').replace(/^\.\//, '');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** ¿El path tocado coincide con algún archivo de memoria? */
|
|
69
|
+
function esArchivoMemoria(filePath) {
|
|
70
|
+
const norm = normalizar(filePath);
|
|
71
|
+
return ARCHIVOS_MEMORIA.some(target => norm.endsWith(target));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Extrae el(los) path(s) afectado(s) por la herramienta del payload del hook.
|
|
76
|
+
* @param {object} data - Payload del hook (tool_input).
|
|
77
|
+
* @returns {string[]} Lista de paths afectados.
|
|
78
|
+
*/
|
|
79
|
+
function extraerPaths(data) {
|
|
80
|
+
const ti = data.tool_input || {};
|
|
81
|
+
const paths = [];
|
|
82
|
+
if (ti.file_path) paths.push(ti.file_path);
|
|
83
|
+
if (ti.notebook_path) paths.push(ti.notebook_path);
|
|
84
|
+
// MultiEdit: file_path único + edits[]; ya cubierto arriba.
|
|
85
|
+
return paths;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Ejecuta el validador y devuelve un resumen normalizado.
|
|
90
|
+
* Schema esperado del validador (--json):
|
|
91
|
+
* {
|
|
92
|
+
* totalNoCriticas: N,
|
|
93
|
+
* totalCriticas: N,
|
|
94
|
+
* issues: {
|
|
95
|
+
* usuario_en_aprendizajes: [...],
|
|
96
|
+
* anti_tecnico_en_perfil: [...],
|
|
97
|
+
* duplicados_cross_canal: [...],
|
|
98
|
+
* secretos: [...], // críticas
|
|
99
|
+
* pii: [...], // críticas
|
|
100
|
+
* }
|
|
101
|
+
* }
|
|
102
|
+
*
|
|
103
|
+
* Si el validador falla o no existe, devuelve null (silencio).
|
|
104
|
+
*/
|
|
105
|
+
function ejecutarValidador() {
|
|
106
|
+
if (!fs.existsSync(VALIDADOR)) return null;
|
|
107
|
+
try {
|
|
108
|
+
const r = spawnSync(process.execPath, [VALIDADOR, '--json'], {
|
|
109
|
+
cwd: process.cwd(),
|
|
110
|
+
encoding: 'utf8',
|
|
111
|
+
timeout: TIMEOUT_MS,
|
|
112
|
+
windowsHide: true,
|
|
113
|
+
});
|
|
114
|
+
if (r.status === null) return null;
|
|
115
|
+
if (!r.stdout) return null;
|
|
116
|
+
const parsed = JSON.parse(r.stdout);
|
|
117
|
+
const issues = parsed.issues || {};
|
|
118
|
+
return {
|
|
119
|
+
totalNoCriticas: Number.isInteger(parsed.totalNoCriticas) ? parsed.totalNoCriticas : 0,
|
|
120
|
+
totalCriticas: Number.isInteger(parsed.totalCriticas) ? parsed.totalCriticas : 0,
|
|
121
|
+
criticas: [
|
|
122
|
+
...(issues.secretos || []).map(x => ({ tipo: 'secreto', detalle: x })),
|
|
123
|
+
...(issues.pii || []).map(x => ({ tipo: 'pii', detalle: x })),
|
|
124
|
+
],
|
|
125
|
+
menores: [
|
|
126
|
+
...(issues.usuario_en_aprendizajes || []).map(x => ({ tipo: 'canal: usuario en aprendizajes', detalle: x })),
|
|
127
|
+
...(issues.anti_tecnico_en_perfil || []).map(x => ({ tipo: 'canal: anti-patrón técnico en perfil', detalle: x })),
|
|
128
|
+
...(issues.duplicados_cross_canal || []).map(x => ({ tipo: 'duplicación cross-canal', detalle: x })),
|
|
129
|
+
],
|
|
130
|
+
};
|
|
131
|
+
} catch (_) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Trunca y limpia un detalle para mostrarlo en una línea. */
|
|
137
|
+
function describir(item) {
|
|
138
|
+
if (typeof item === 'string') return item.slice(0, 120);
|
|
139
|
+
if (item && typeof item === 'object') {
|
|
140
|
+
const partes = [];
|
|
141
|
+
if (item.titulo) partes.push(item.titulo);
|
|
142
|
+
if (item.canal) partes.push(`canal=${item.canal}`);
|
|
143
|
+
if (item.linea) partes.push(`L${item.linea}`);
|
|
144
|
+
if (item.muestra) partes.push(item.muestra);
|
|
145
|
+
if (partes.length === 0) return JSON.stringify(item).slice(0, 120);
|
|
146
|
+
return partes.join(' | ').slice(0, 120);
|
|
147
|
+
}
|
|
148
|
+
return String(item).slice(0, 120);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Construye el mensaje de nudge según el resultado.
|
|
153
|
+
*/
|
|
154
|
+
function construirMensaje(resultado, archivo) {
|
|
155
|
+
const { criticas, menores } = resultado;
|
|
156
|
+
if (criticas.length > 0) {
|
|
157
|
+
const lineas = [
|
|
158
|
+
'',
|
|
159
|
+
'╔══════════════════════════════════════════════════════╗',
|
|
160
|
+
'║ MEMORIA: VIOLACIÓN CRÍTICA DETECTADA ║',
|
|
161
|
+
'╚══════════════════════════════════════════════════════╝',
|
|
162
|
+
` Archivo modificado: ${archivo}`,
|
|
163
|
+
` Críticas: ${criticas.length}`,
|
|
164
|
+
];
|
|
165
|
+
for (const c of criticas.slice(0, 3)) {
|
|
166
|
+
lineas.push(` • ${c.tipo}: ${describir(c.detalle)}`);
|
|
167
|
+
}
|
|
168
|
+
lineas.push(' Acción recomendada: revertir el cambio o sanitizar antes de commit.');
|
|
169
|
+
lineas.push(' Ver: reglas/memoria-consolidada.md');
|
|
170
|
+
lineas.push('');
|
|
171
|
+
return lineas.join('\n');
|
|
172
|
+
}
|
|
173
|
+
if (menores.length > 0) {
|
|
174
|
+
const lineas = [
|
|
175
|
+
'',
|
|
176
|
+
'⚠ Memoria: posibles violaciones de canal',
|
|
177
|
+
` Archivo: ${archivo} | ${menores.length} hallazgo(s)`,
|
|
178
|
+
];
|
|
179
|
+
for (const v of menores.slice(0, 3)) {
|
|
180
|
+
lineas.push(` • ${v.tipo}: ${describir(v.detalle)}`);
|
|
181
|
+
}
|
|
182
|
+
if (menores.length > 3) {
|
|
183
|
+
lineas.push(` • (y ${menores.length - 3} más — ejecutar: node scripts/validar-memoria.js)`);
|
|
184
|
+
}
|
|
185
|
+
lineas.push(' Ver: reglas/memoria-consolidada.md (canal correcto por tipo de dato)');
|
|
186
|
+
lineas.push('');
|
|
187
|
+
return lineas.join('\n');
|
|
188
|
+
}
|
|
189
|
+
return '';
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// ---------------------------------------------------------------------------
|
|
193
|
+
// Entrypoint
|
|
194
|
+
// ---------------------------------------------------------------------------
|
|
195
|
+
|
|
196
|
+
let inputRaw = '';
|
|
197
|
+
process.stdin.on('data', chunk => { inputRaw += chunk; });
|
|
198
|
+
|
|
199
|
+
process.stdin.on('end', () => {
|
|
200
|
+
try {
|
|
201
|
+
if (process.env.SWL_VALIDAR_MEMORIA === '0') return;
|
|
202
|
+
|
|
203
|
+
const data = JSON.parse(inputRaw);
|
|
204
|
+
const paths = extraerPaths(data);
|
|
205
|
+
const archivoTocado = paths.find(esArchivoMemoria);
|
|
206
|
+
if (!archivoTocado) return;
|
|
207
|
+
|
|
208
|
+
const resultado = ejecutarValidador();
|
|
209
|
+
if (!resultado) return;
|
|
210
|
+
|
|
211
|
+
const mensaje = construirMensaje(resultado, normalizar(archivoTocado));
|
|
212
|
+
if (mensaje) {
|
|
213
|
+
process.stdout.write(JSON.stringify({ systemMessage: mensaje }));
|
|
214
|
+
}
|
|
215
|
+
} catch (_) {
|
|
216
|
+
// PostToolUse no bloquea por errores internos.
|
|
217
|
+
}
|
|
218
|
+
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"descripcion": "Schemas de output esperado por agente — formato compacto declarado en reglas/brevedad-output.md. El hook validar-formato-post-subagente.js usa estos patrones para detectar cuándo un agente devuelve output fuera de contrato.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"schemas": {
|
|
6
|
+
"revisor-codigo-swl": {
|
|
7
|
+
"descripcion": "Revisión de calidad — formato compacto",
|
|
8
|
+
"patronesRequeridos": [
|
|
9
|
+
"(?im)VEREDICTO\\s*:\\s*(APROBADO|APROBADO_CON_OBSERVACIONES|RECHAZADO|REQUIERE_CORRECCIONES|CUMPLE|PARCIAL|NO\\s+CUMPLE)",
|
|
10
|
+
"(?im)CR[IÍ]TICOS\\s*:\\s*\\d+",
|
|
11
|
+
"(?im)MAYORES\\s*:\\s*\\d+",
|
|
12
|
+
"(?im)MENORES\\s*:\\s*\\d+",
|
|
13
|
+
"(?im)HALLAZGOS\\s*:"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"revisor-seguridad-swl": {
|
|
17
|
+
"descripcion": "Revisión de seguridad OWASP — formato compacto",
|
|
18
|
+
"patronesRequeridos": [
|
|
19
|
+
"(?im)VEREDICTO\\s*:\\s*(APROBADO|APROBADO_CON_OBSERVACIONES|RECHAZADO|REQUIERE_CORRECCIONES)",
|
|
20
|
+
"(?im)CR[IÍ]TICOS\\s*:\\s*\\d+",
|
|
21
|
+
"(?im)MAYORES\\s*:\\s*\\d+",
|
|
22
|
+
"(?im)HALLAZGOS\\s*:"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"revisor-typescript-swl": {
|
|
26
|
+
"descripcion": "Revisión TypeScript — formato compacto",
|
|
27
|
+
"patronesRequeridos": [
|
|
28
|
+
"(?im)VEREDICTO\\s*:\\s*\\w+",
|
|
29
|
+
"(?im)CR[IÍ]TICOS\\s*:\\s*\\d+",
|
|
30
|
+
"(?im)HALLAZGOS\\s*:"
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
"revisor-react-swl": {
|
|
34
|
+
"descripcion": "Revisión React — formato compacto",
|
|
35
|
+
"patronesRequeridos": [
|
|
36
|
+
"(?im)VEREDICTO\\s*:\\s*\\w+",
|
|
37
|
+
"(?im)CR[IÍ]TICOS\\s*:\\s*\\d+",
|
|
38
|
+
"(?im)HALLAZGOS\\s*:"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
"revisor-angular-swl": {
|
|
42
|
+
"descripcion": "Revisión Angular — formato compacto",
|
|
43
|
+
"patronesRequeridos": [
|
|
44
|
+
"(?im)VEREDICTO\\s*:\\s*\\w+",
|
|
45
|
+
"(?im)CR[IÍ]TICOS\\s*:\\s*\\d+",
|
|
46
|
+
"(?im)HALLAZGOS\\s*:"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"tdd-qa-swl": {
|
|
50
|
+
"descripcion": "QA con TDD — reporte de implementación",
|
|
51
|
+
"patronesRequeridos": [
|
|
52
|
+
"(?im)ESTADO\\s*:\\s*(COMPLETADO|PARCIAL|BLOQUEADO)",
|
|
53
|
+
"(?im)(SLICES|TESTS)\\s*:"
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -81,6 +81,15 @@
|
|
|
81
81
|
"maxConsecutiveFailures": 3,
|
|
82
82
|
"degradeOnFailure": "skip"
|
|
83
83
|
},
|
|
84
|
+
"validar-memoria-hook.js": {
|
|
85
|
+
"event": "PostToolUse",
|
|
86
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
87
|
+
"description": "Ejecuta scripts/validar-memoria.js cuando se modifica APRENDIZAJES.md, perfil-usuario.yaml o instintos/{proyecto,global}.yaml. Emite nudge si detecta canal incorrecto, duplicación cross-canal, secretos o PII. Opt-out con SWL_VALIDAR_MEMORIA=0.",
|
|
88
|
+
"blocking": false,
|
|
89
|
+
"async": true,
|
|
90
|
+
"maxConsecutiveFailures": 3,
|
|
91
|
+
"degradeOnFailure": "skip"
|
|
92
|
+
},
|
|
84
93
|
"sugerir-regenerar-inventario.js": {
|
|
85
94
|
"event": "PostToolUse",
|
|
86
95
|
"matcher": "Write|Edit|MultiEdit",
|
|
@@ -186,6 +195,15 @@
|
|
|
186
195
|
"maxConsecutiveFailures": 5,
|
|
187
196
|
"degradeOnFailure": "skip"
|
|
188
197
|
},
|
|
198
|
+
"validar-formato-post-subagente.js": {
|
|
199
|
+
"event": "SubagentStop",
|
|
200
|
+
"matcher": "",
|
|
201
|
+
"description": "Valida output de subagentes con schema declarado en manifiestos/agent-output-schemas.json (revisor-* y tdd-qa). Registra violaciones en .planning/evolucion/formato-violaciones.jsonl. Opt-out: SWL_FORMATO_VALIDACION=0.",
|
|
202
|
+
"blocking": false,
|
|
203
|
+
"async": true,
|
|
204
|
+
"maxConsecutiveFailures": 3,
|
|
205
|
+
"degradeOnFailure": "skip"
|
|
206
|
+
},
|
|
189
207
|
"telemetria-agentes.js": {
|
|
190
208
|
"event": "PostToolUse",
|
|
191
209
|
"matcher": "Agent",
|
package/manifiestos/modulos.json
CHANGED
|
@@ -857,6 +857,7 @@
|
|
|
857
857
|
"reglas/api-diseno.md",
|
|
858
858
|
"reglas/cloud-infra.md",
|
|
859
859
|
"reglas/skills-estandar.md",
|
|
860
|
+
"reglas/fragmentos-compartidos.md",
|
|
860
861
|
"reglas/gobernanza.md",
|
|
861
862
|
"reglas/hooks.md",
|
|
862
863
|
"reglas/patrones.md",
|
|
@@ -933,6 +934,8 @@
|
|
|
933
934
|
"hooks/linea-estado.js",
|
|
934
935
|
"hooks/monitor-contexto.js",
|
|
935
936
|
"hooks/extraccion-aprendizajes.js",
|
|
937
|
+
"hooks/validar-memoria-hook.js",
|
|
938
|
+
"hooks/validar-formato-post-subagente.js",
|
|
936
939
|
"hooks/inyeccion-contexto.js",
|
|
937
940
|
"hooks/auto-consolidacion.js",
|
|
938
941
|
"hooks/auto-background.js",
|