@saulwade/swl-ses 1.3.8 → 1.4.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 +15 -6
- package/README.md +15 -14
- package/agentes/nemesis-auditor-swl.md +161 -0
- package/bin/swl-mcp-server.js +187 -187
- package/bin/swl-webhook-server.js +198 -0
- package/comandos/swl/.evolved.json +22 -22
- package/comandos/swl/adoptar-proyecto.md +21 -1
- package/comandos/swl/claudemd.md +14 -1
- package/comandos/swl/contribuir.md +233 -233
- package/comandos/swl/exportar-vault.md +108 -0
- package/comandos/swl/nemesis.md +122 -0
- package/comandos/swl/nuevo-proyecto.md +24 -2
- package/comandos/swl/salud.md +34 -0
- package/comandos/swl/verificar.md +45 -0
- package/gateway/adapters/base.js +109 -0
- package/gateway/adapters/discord.js +167 -0
- package/gateway/adapters/email.js +221 -0
- package/gateway/adapters/slack.js +192 -0
- package/gateway/adapters/telegram.js +183 -0
- package/gateway/adapters/webhook.js +113 -0
- package/gateway/adapters/whatsapp.js +214 -0
- package/gateway/agent-executor.js +322 -0
- package/gateway/command-relay.js +271 -0
- package/gateway/cron/jobs.js +263 -0
- package/gateway/cron/scheduler.js +322 -0
- package/gateway/cron/store.js +335 -0
- package/gateway/index.js +320 -0
- package/gateway/lib/event-channel.js +191 -0
- package/gateway/session.js +131 -0
- package/gateway/webhook-server.js +324 -0
- package/habilidades/backend-production-resilience/SKILL.md +288 -288
- package/habilidades/benchmark-memoria/SKILL.md +186 -186
- package/habilidades/build-errors-nextjs/SKILL.md +55 -1
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -276
- package/habilidades/doubt-driven-review/SKILL.md +171 -171
- package/habilidades/doubt-driven-review/recursos/EXAMPLES.md +130 -130
- package/habilidades/eval-framework/SKILL.md +212 -212
- package/habilidades/extractor-de-aprendizajes/SKILL.md +20 -10
- package/habilidades/feynman-auditor-swl/SKILL.md +123 -0
- package/habilidades/feynman-auditor-swl/recursos/preguntas-language-agnostic.md +108 -0
- 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/nextjs-testing/SKILL.md +89 -5
- package/habilidades/node-experto/SKILL.md +37 -1
- 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/react-experto/SKILL.md +45 -4
- package/habilidades/release-semver/.evolved.json +8 -8
- package/habilidades/state-inconsistency-auditor-swl/SKILL.md +166 -0
- package/habilidades/state-inconsistency-auditor-swl/recursos/coupled-state-patterns.md +147 -0
- package/habilidades/tdd-workflow/SKILL.md +36 -4
- package/habilidades/testing-python/SKILL.md +340 -340
- package/habilidades/web-fetcher-routing/SKILL.md +75 -0
- package/hooks/claudemd-bloat-detector.js +161 -161
- package/hooks/inyeccion-contexto.js +8 -3
- 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-ip.js +177 -0
- 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 -0
- 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/lib/webhook-dedup.js +184 -0
- package/hooks/lib/webhook-verify.js +123 -0
- package/hooks/proteccion-rutas.js +120 -15
- 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 +31 -0
- package/manifiestos/skills-lock.json +1114 -1093
- package/package.json +6 -4
- 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 +2 -2
- 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/reglas/usar-sistema-swl.md +251 -0
- package/schemas/diary-entry.schema.json +80 -80
- package/scripts/audit-tools/audit-history.js +330 -0
- package/scripts/audit-tools/bundle-tracker.js +290 -0
- package/scripts/audit-tools/canary-monitor.js +352 -0
- package/scripts/audit-tools/code-profiler.js +605 -0
- package/scripts/audit-tools/dep-doctor.js +320 -0
- package/scripts/audit-tools/env-validator.js +206 -0
- package/scripts/audit-tools/lib/fs-walk.js +48 -0
- package/scripts/audit-tools/lib/output.js +23 -0
- package/scripts/audit-tools/migration-checker.js +392 -0
- package/scripts/audit-tools/pentest-scanner.js +1436 -0
- package/scripts/benchmark-memoria.js +167 -167
- package/scripts/comandos/skills.js +251 -2
- package/scripts/configurar-branch-protection.js +418 -418
- package/scripts/detectar-aprendizajes-duplicados.js +151 -151
- 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/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-stack-detallado.js +307 -307
- package/scripts/lib/diary-entry.js +234 -234
- 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/jaccard-similarity.js +98 -98
- package/scripts/lib/longmemeval-runner.js +125 -125
- package/scripts/lib/npm-version.js +261 -261
- package/scripts/lib/paquetes-conocidos.js +50 -50
- 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/limpiar-artefactos-python.js +131 -131
- package/scripts/mcp-server/README.md +128 -128
- package/scripts/mcp-server/handlers.js +206 -206
- 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 +195 -195
- package/scripts/validar-userland-vacio.js +110 -110
- package/scripts/verificar-release.js +110 -0
package/bin/swl-mcp-server.js
CHANGED
|
@@ -1,187 +1,187 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* swl-mcp-server — Servidor MCP **EXPERIMENTAL** para exponer la memoria
|
|
6
|
-
* de swl-ses a clientes MCP externos (Cursor, Gemini CLI, OpenCode, etc.).
|
|
7
|
-
*
|
|
8
|
-
* **NO PRODUCCIÓN — STUB EXPERIMENTAL**.
|
|
9
|
-
* Ver `scripts/mcp-server/README.md` para limitaciones detalladas.
|
|
10
|
-
*
|
|
11
|
-
* Modo de transporte: stdio (JSON-RPC sobre stdin/stdout).
|
|
12
|
-
* No HTTP, no auth, no rate limiting.
|
|
13
|
-
*
|
|
14
|
-
* Uso (cliente MCP):
|
|
15
|
-
* - Configurar el cliente para ejecutar `node /path/to/swl-ses/bin/swl-mcp-server.js`
|
|
16
|
-
* con stdio.
|
|
17
|
-
* - Los handlers leen el cwd del proceso para localizar `.planning/`,
|
|
18
|
-
* `instintos/`, `APRENDIZAJES.md`. Por defecto usa `process.cwd()`.
|
|
19
|
-
* - Override con env var `SWL_MCP_BASE_DIR` si el cliente arranca el server
|
|
20
|
-
* desde otro directorio.
|
|
21
|
-
*
|
|
22
|
-
* Protocolo MCP soportado (subset):
|
|
23
|
-
* - initialize / initialized
|
|
24
|
-
* - tools/list
|
|
25
|
-
* - tools/call
|
|
26
|
-
*
|
|
27
|
-
* NO soporta:
|
|
28
|
-
* - resources/list, prompts/list
|
|
29
|
-
* - logging, sampling
|
|
30
|
-
* - cancellation, progress
|
|
31
|
-
* - HTTP transport
|
|
32
|
-
*
|
|
33
|
-
* Trigger documentado para implementación completa: "uso ≥2 runtimes
|
|
34
|
-
* diferentes (Cursor + Claude Code o similar) consistentemente por
|
|
35
|
-
* ≥1 mes". Hoy: 0 instalaciones reportadas.
|
|
36
|
-
*/
|
|
37
|
-
|
|
38
|
-
const path = require('path');
|
|
39
|
-
|
|
40
|
-
const { HANDLERS } = require('../scripts/mcp-server/handlers');
|
|
41
|
-
|
|
42
|
-
const SERVER_NAME = 'swl-mcp-server';
|
|
43
|
-
const SERVER_VERSION = '0.1.0-experimental';
|
|
44
|
-
const PROTOCOL_VERSION = '2024-11-05';
|
|
45
|
-
|
|
46
|
-
const baseDir = process.env.SWL_MCP_BASE_DIR || process.cwd();
|
|
47
|
-
|
|
48
|
-
// ── logging ───────────────────────────────────────────────────────────────────
|
|
49
|
-
|
|
50
|
-
// Stderr para evitar contaminar stdout (que es JSON-RPC).
|
|
51
|
-
function log(level, msg, data) {
|
|
52
|
-
const linea = JSON.stringify({
|
|
53
|
-
timestamp: new Date().toISOString(),
|
|
54
|
-
level,
|
|
55
|
-
msg,
|
|
56
|
-
...(data ? { data } : {}),
|
|
57
|
-
});
|
|
58
|
-
process.stderr.write(linea + '\n');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// ── JSON-RPC helpers ──────────────────────────────────────────────────────────
|
|
62
|
-
|
|
63
|
-
function respuesta(id, result) {
|
|
64
|
-
return JSON.stringify({ jsonrpc: '2.0', id, result });
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function errorResp(id, code, message) {
|
|
68
|
-
return JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } });
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ── routing ───────────────────────────────────────────────────────────────────
|
|
72
|
-
|
|
73
|
-
function manejarInitialize(request) {
|
|
74
|
-
return respuesta(request.id, {
|
|
75
|
-
protocolVersion: PROTOCOL_VERSION,
|
|
76
|
-
capabilities: {
|
|
77
|
-
tools: { listChanged: false },
|
|
78
|
-
},
|
|
79
|
-
serverInfo: {
|
|
80
|
-
name: SERVER_NAME,
|
|
81
|
-
version: SERVER_VERSION,
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function manejarToolsList(request) {
|
|
87
|
-
const tools = Object.entries(HANDLERS).map(([name, def]) => ({
|
|
88
|
-
name,
|
|
89
|
-
description: def.description,
|
|
90
|
-
inputSchema: def.inputSchema,
|
|
91
|
-
}));
|
|
92
|
-
return respuesta(request.id, { tools });
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function manejarToolsCall(request) {
|
|
96
|
-
const { name, arguments: args } = request.params || {};
|
|
97
|
-
const def = HANDLERS[name];
|
|
98
|
-
if (!def) {
|
|
99
|
-
return errorResp(request.id, -32601, `Tool no encontrado: ${name}`);
|
|
100
|
-
}
|
|
101
|
-
try {
|
|
102
|
-
const result = def.handler(baseDir, args || {});
|
|
103
|
-
return respuesta(request.id, {
|
|
104
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
105
|
-
});
|
|
106
|
-
} catch (err) {
|
|
107
|
-
log('error', `Excepción en handler ${name}`, { error: err.message });
|
|
108
|
-
return errorResp(request.id, -32603, `Error interno: ${err.message}`);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function rutear(request) {
|
|
113
|
-
switch (request.method) {
|
|
114
|
-
case 'initialize':
|
|
115
|
-
return manejarInitialize(request);
|
|
116
|
-
case 'initialized':
|
|
117
|
-
case 'notifications/initialized':
|
|
118
|
-
return null; // notification — sin respuesta
|
|
119
|
-
case 'tools/list':
|
|
120
|
-
return manejarToolsList(request);
|
|
121
|
-
case 'tools/call':
|
|
122
|
-
return manejarToolsCall(request);
|
|
123
|
-
case 'ping':
|
|
124
|
-
return respuesta(request.id, {});
|
|
125
|
-
default:
|
|
126
|
-
return errorResp(request.id, -32601, `Método no soportado: ${request.method}`);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// ── loop principal ────────────────────────────────────────────────────────────
|
|
131
|
-
|
|
132
|
-
function arrancar() {
|
|
133
|
-
log('warn', '⚠ swl-mcp-server stub experimental — NO usar en producción');
|
|
134
|
-
log('info', `Server iniciando`, { name: SERVER_NAME, version: SERVER_VERSION, baseDir });
|
|
135
|
-
|
|
136
|
-
let buffer = '';
|
|
137
|
-
|
|
138
|
-
process.stdin.setEncoding('utf8');
|
|
139
|
-
process.stdin.on('data', (chunk) => {
|
|
140
|
-
buffer += chunk;
|
|
141
|
-
|
|
142
|
-
// Cada mensaje JSON-RPC termina con \n
|
|
143
|
-
let nlIndex;
|
|
144
|
-
while ((nlIndex = buffer.indexOf('\n')) >= 0) {
|
|
145
|
-
const linea = buffer.slice(0, nlIndex).trim();
|
|
146
|
-
buffer = buffer.slice(nlIndex + 1);
|
|
147
|
-
|
|
148
|
-
if (!linea) continue;
|
|
149
|
-
|
|
150
|
-
let request;
|
|
151
|
-
try {
|
|
152
|
-
request = JSON.parse(linea);
|
|
153
|
-
} catch (err) {
|
|
154
|
-
log('error', 'JSON inválido recibido', { error: err.message, linea: linea.slice(0, 100) });
|
|
155
|
-
process.stdout.write(errorResp(null, -32700, 'Parse error') + '\n');
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const respuestaStr = rutear(request);
|
|
160
|
-
if (respuestaStr) {
|
|
161
|
-
process.stdout.write(respuestaStr + '\n');
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
process.stdin.on('end', () => {
|
|
167
|
-
log('info', 'stdin cerrado, server termina');
|
|
168
|
-
process.exit(0);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
// Manejo de errores no capturados — nunca crashear silenciosamente
|
|
172
|
-
process.on('uncaughtException', (err) => {
|
|
173
|
-
log('error', 'uncaughtException', { error: err.message, stack: err.stack });
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (require.main === module) {
|
|
178
|
-
arrancar();
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
module.exports = {
|
|
182
|
-
rutear,
|
|
183
|
-
arrancar,
|
|
184
|
-
SERVER_NAME,
|
|
185
|
-
SERVER_VERSION,
|
|
186
|
-
PROTOCOL_VERSION,
|
|
187
|
-
};
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* swl-mcp-server — Servidor MCP **EXPERIMENTAL** para exponer la memoria
|
|
6
|
+
* de swl-ses a clientes MCP externos (Cursor, Gemini CLI, OpenCode, etc.).
|
|
7
|
+
*
|
|
8
|
+
* **NO PRODUCCIÓN — STUB EXPERIMENTAL**.
|
|
9
|
+
* Ver `scripts/mcp-server/README.md` para limitaciones detalladas.
|
|
10
|
+
*
|
|
11
|
+
* Modo de transporte: stdio (JSON-RPC sobre stdin/stdout).
|
|
12
|
+
* No HTTP, no auth, no rate limiting.
|
|
13
|
+
*
|
|
14
|
+
* Uso (cliente MCP):
|
|
15
|
+
* - Configurar el cliente para ejecutar `node /path/to/swl-ses/bin/swl-mcp-server.js`
|
|
16
|
+
* con stdio.
|
|
17
|
+
* - Los handlers leen el cwd del proceso para localizar `.planning/`,
|
|
18
|
+
* `instintos/`, `APRENDIZAJES.md`. Por defecto usa `process.cwd()`.
|
|
19
|
+
* - Override con env var `SWL_MCP_BASE_DIR` si el cliente arranca el server
|
|
20
|
+
* desde otro directorio.
|
|
21
|
+
*
|
|
22
|
+
* Protocolo MCP soportado (subset):
|
|
23
|
+
* - initialize / initialized
|
|
24
|
+
* - tools/list
|
|
25
|
+
* - tools/call
|
|
26
|
+
*
|
|
27
|
+
* NO soporta:
|
|
28
|
+
* - resources/list, prompts/list
|
|
29
|
+
* - logging, sampling
|
|
30
|
+
* - cancellation, progress
|
|
31
|
+
* - HTTP transport
|
|
32
|
+
*
|
|
33
|
+
* Trigger documentado para implementación completa: "uso ≥2 runtimes
|
|
34
|
+
* diferentes (Cursor + Claude Code o similar) consistentemente por
|
|
35
|
+
* ≥1 mes". Hoy: 0 instalaciones reportadas.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
const path = require('path');
|
|
39
|
+
|
|
40
|
+
const { HANDLERS } = require('../scripts/mcp-server/handlers');
|
|
41
|
+
|
|
42
|
+
const SERVER_NAME = 'swl-mcp-server';
|
|
43
|
+
const SERVER_VERSION = '0.1.0-experimental';
|
|
44
|
+
const PROTOCOL_VERSION = '2024-11-05';
|
|
45
|
+
|
|
46
|
+
const baseDir = process.env.SWL_MCP_BASE_DIR || process.cwd();
|
|
47
|
+
|
|
48
|
+
// ── logging ───────────────────────────────────────────────────────────────────
|
|
49
|
+
|
|
50
|
+
// Stderr para evitar contaminar stdout (que es JSON-RPC).
|
|
51
|
+
function log(level, msg, data) {
|
|
52
|
+
const linea = JSON.stringify({
|
|
53
|
+
timestamp: new Date().toISOString(),
|
|
54
|
+
level,
|
|
55
|
+
msg,
|
|
56
|
+
...(data ? { data } : {}),
|
|
57
|
+
});
|
|
58
|
+
process.stderr.write(linea + '\n');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// ── JSON-RPC helpers ──────────────────────────────────────────────────────────
|
|
62
|
+
|
|
63
|
+
function respuesta(id, result) {
|
|
64
|
+
return JSON.stringify({ jsonrpc: '2.0', id, result });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function errorResp(id, code, message) {
|
|
68
|
+
return JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ── routing ───────────────────────────────────────────────────────────────────
|
|
72
|
+
|
|
73
|
+
function manejarInitialize(request) {
|
|
74
|
+
return respuesta(request.id, {
|
|
75
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
76
|
+
capabilities: {
|
|
77
|
+
tools: { listChanged: false },
|
|
78
|
+
},
|
|
79
|
+
serverInfo: {
|
|
80
|
+
name: SERVER_NAME,
|
|
81
|
+
version: SERVER_VERSION,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function manejarToolsList(request) {
|
|
87
|
+
const tools = Object.entries(HANDLERS).map(([name, def]) => ({
|
|
88
|
+
name,
|
|
89
|
+
description: def.description,
|
|
90
|
+
inputSchema: def.inputSchema,
|
|
91
|
+
}));
|
|
92
|
+
return respuesta(request.id, { tools });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function manejarToolsCall(request) {
|
|
96
|
+
const { name, arguments: args } = request.params || {};
|
|
97
|
+
const def = HANDLERS[name];
|
|
98
|
+
if (!def) {
|
|
99
|
+
return errorResp(request.id, -32601, `Tool no encontrado: ${name}`);
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
const result = def.handler(baseDir, args || {});
|
|
103
|
+
return respuesta(request.id, {
|
|
104
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
105
|
+
});
|
|
106
|
+
} catch (err) {
|
|
107
|
+
log('error', `Excepción en handler ${name}`, { error: err.message });
|
|
108
|
+
return errorResp(request.id, -32603, `Error interno: ${err.message}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function rutear(request) {
|
|
113
|
+
switch (request.method) {
|
|
114
|
+
case 'initialize':
|
|
115
|
+
return manejarInitialize(request);
|
|
116
|
+
case 'initialized':
|
|
117
|
+
case 'notifications/initialized':
|
|
118
|
+
return null; // notification — sin respuesta
|
|
119
|
+
case 'tools/list':
|
|
120
|
+
return manejarToolsList(request);
|
|
121
|
+
case 'tools/call':
|
|
122
|
+
return manejarToolsCall(request);
|
|
123
|
+
case 'ping':
|
|
124
|
+
return respuesta(request.id, {});
|
|
125
|
+
default:
|
|
126
|
+
return errorResp(request.id, -32601, `Método no soportado: ${request.method}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ── loop principal ────────────────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
function arrancar() {
|
|
133
|
+
log('warn', '⚠ swl-mcp-server stub experimental — NO usar en producción');
|
|
134
|
+
log('info', `Server iniciando`, { name: SERVER_NAME, version: SERVER_VERSION, baseDir });
|
|
135
|
+
|
|
136
|
+
let buffer = '';
|
|
137
|
+
|
|
138
|
+
process.stdin.setEncoding('utf8');
|
|
139
|
+
process.stdin.on('data', (chunk) => {
|
|
140
|
+
buffer += chunk;
|
|
141
|
+
|
|
142
|
+
// Cada mensaje JSON-RPC termina con \n
|
|
143
|
+
let nlIndex;
|
|
144
|
+
while ((nlIndex = buffer.indexOf('\n')) >= 0) {
|
|
145
|
+
const linea = buffer.slice(0, nlIndex).trim();
|
|
146
|
+
buffer = buffer.slice(nlIndex + 1);
|
|
147
|
+
|
|
148
|
+
if (!linea) continue;
|
|
149
|
+
|
|
150
|
+
let request;
|
|
151
|
+
try {
|
|
152
|
+
request = JSON.parse(linea);
|
|
153
|
+
} catch (err) {
|
|
154
|
+
log('error', 'JSON inválido recibido', { error: err.message, linea: linea.slice(0, 100) });
|
|
155
|
+
process.stdout.write(errorResp(null, -32700, 'Parse error') + '\n');
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const respuestaStr = rutear(request);
|
|
160
|
+
if (respuestaStr) {
|
|
161
|
+
process.stdout.write(respuestaStr + '\n');
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
process.stdin.on('end', () => {
|
|
167
|
+
log('info', 'stdin cerrado, server termina');
|
|
168
|
+
process.exit(0);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Manejo de errores no capturados — nunca crashear silenciosamente
|
|
172
|
+
process.on('uncaughtException', (err) => {
|
|
173
|
+
log('error', 'uncaughtException', { error: err.message, stack: err.stack });
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (require.main === module) {
|
|
178
|
+
arrancar();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
module.exports = {
|
|
182
|
+
rutear,
|
|
183
|
+
arrancar,
|
|
184
|
+
SERVER_NAME,
|
|
185
|
+
SERVER_VERSION,
|
|
186
|
+
PROTOCOL_VERSION,
|
|
187
|
+
};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* swl-webhook-server — Bootstrap CLI del receptor de webhooks entrantes.
|
|
6
|
+
*
|
|
7
|
+
* Lee variables de entorno opt-in, construye las dependencias inyectadas,
|
|
8
|
+
* arranca el servidor HTTP y maneja shutdown limpio (SIGTERM/SIGINT).
|
|
9
|
+
*
|
|
10
|
+
* Activación: requiere SWL_WEBHOOK_LISTEN_PORT. Sin esa variable, el
|
|
11
|
+
* proceso imprime un mensaje informativo y sale con código 0 (no es
|
|
12
|
+
* error — sólo opt-in no activado).
|
|
13
|
+
*
|
|
14
|
+
* Variables de entorno (ver `docs/variables-entorno.md` § Webhook entrante
|
|
15
|
+
* para descripción completa):
|
|
16
|
+
*
|
|
17
|
+
* SWL_WEBHOOK_LISTEN_PORT unset → no arranca
|
|
18
|
+
* SWL_WEBHOOK_LISTEN_HOST 127.0.0.1
|
|
19
|
+
* SWL_WEBHOOK_GITHUB_SECRET unset → /webhooks/github deshabilitado
|
|
20
|
+
* SWL_WEBHOOK_BEARER_SECRET unset → /webhooks/generic deshabilitado
|
|
21
|
+
* SWL_WEBHOOK_RATE_LIMIT_RPM 60
|
|
22
|
+
* SWL_WEBHOOK_ALLOW_IPS unset (CSV)
|
|
23
|
+
* SWL_WEBHOOK_MAX_PAYLOAD_BYTES 1048576 (1 MB)
|
|
24
|
+
* SWL_WEBHOOK_INBOX_DIR .planning/inbox
|
|
25
|
+
* SWL_WEBHOOK_LEDGER_PATH .planning/webhook-events.jsonl
|
|
26
|
+
*
|
|
27
|
+
* Uso típico con supervisor (no incluido en SWL — el usuario elige):
|
|
28
|
+
*
|
|
29
|
+
* SWL_WEBHOOK_LISTEN_PORT=8787 SWL_WEBHOOK_GITHUB_SECRET=xxx \
|
|
30
|
+
* pm2 start bin/swl-webhook-server.js --name swl-webhook
|
|
31
|
+
*
|
|
32
|
+
* # systemd: ver MANUAL_USO.md § Webhook server.
|
|
33
|
+
*
|
|
34
|
+
* @module bin/swl-webhook-server
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
const path = require('path');
|
|
38
|
+
const { crearServidor } = require('../gateway/webhook-server');
|
|
39
|
+
const { RateLimiterIP } = require('../hooks/lib/rate-limit-ip');
|
|
40
|
+
const { WebhookDedup } = require('../hooks/lib/webhook-dedup');
|
|
41
|
+
|
|
42
|
+
const PUERTO_MIN = 1;
|
|
43
|
+
const PUERTO_MAX = 65535;
|
|
44
|
+
const RPM_DEFAULT = 60;
|
|
45
|
+
const MAX_PAYLOAD_DEFAULT = 1024 * 1024;
|
|
46
|
+
const HOST_DEFAULT = '127.0.0.1';
|
|
47
|
+
const INBOX_DIR_DEFAULT = path.join('.planning', 'inbox');
|
|
48
|
+
const LEDGER_PATH_DEFAULT = path.join('.planning', 'webhook-events.jsonl');
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Construye el objeto de configuración + deps desde variables de entorno.
|
|
52
|
+
*
|
|
53
|
+
* Separado del main() para testear sin tocar process.env real.
|
|
54
|
+
*
|
|
55
|
+
* @param {object} env Objeto con las variables (típicamente process.env).
|
|
56
|
+
* @returns {{configurado: boolean, errores: string[], config: object|null, deps: object|null}}
|
|
57
|
+
*/
|
|
58
|
+
function construirDepsDesdeEnv(env) {
|
|
59
|
+
const errores = [];
|
|
60
|
+
|
|
61
|
+
// Opt-in: sin LISTEN_PORT, no se arranca nada
|
|
62
|
+
if (!env.SWL_WEBHOOK_LISTEN_PORT) {
|
|
63
|
+
return { configurado: false, errores: [], config: null, deps: null };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const port = Number.parseInt(env.SWL_WEBHOOK_LISTEN_PORT, 10);
|
|
67
|
+
if (!Number.isInteger(port) || port < PUERTO_MIN || port > PUERTO_MAX) {
|
|
68
|
+
errores.push(`SWL_WEBHOOK_LISTEN_PORT inválido: "${env.SWL_WEBHOOK_LISTEN_PORT}" (debe ser entero ${PUERTO_MIN}-${PUERTO_MAX})`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const host = env.SWL_WEBHOOK_LISTEN_HOST || HOST_DEFAULT;
|
|
72
|
+
|
|
73
|
+
const githubSecret = env.SWL_WEBHOOK_GITHUB_SECRET || null;
|
|
74
|
+
const bearerSecret = env.SWL_WEBHOOK_BEARER_SECRET || null;
|
|
75
|
+
|
|
76
|
+
if (!githubSecret && !bearerSecret) {
|
|
77
|
+
errores.push('Ningún endpoint configurado: definir SWL_WEBHOOK_GITHUB_SECRET o SWL_WEBHOOK_BEARER_SECRET (o ambos).');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const rpm = parseEntero(env.SWL_WEBHOOK_RATE_LIMIT_RPM, RPM_DEFAULT);
|
|
81
|
+
if (rpm <= 0) {
|
|
82
|
+
errores.push(`SWL_WEBHOOK_RATE_LIMIT_RPM inválido: "${env.SWL_WEBHOOK_RATE_LIMIT_RPM}" (debe ser entero > 0)`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const maxPayloadBytes = parseEntero(env.SWL_WEBHOOK_MAX_PAYLOAD_BYTES, MAX_PAYLOAD_DEFAULT);
|
|
86
|
+
if (maxPayloadBytes <= 0) {
|
|
87
|
+
errores.push(`SWL_WEBHOOK_MAX_PAYLOAD_BYTES inválido: "${env.SWL_WEBHOOK_MAX_PAYLOAD_BYTES}" (debe ser entero > 0)`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const allowIps = parseCsv(env.SWL_WEBHOOK_ALLOW_IPS);
|
|
91
|
+
|
|
92
|
+
const inboxDir = env.SWL_WEBHOOK_INBOX_DIR || INBOX_DIR_DEFAULT;
|
|
93
|
+
const ledgerPath = env.SWL_WEBHOOK_LEDGER_PATH || LEDGER_PATH_DEFAULT;
|
|
94
|
+
|
|
95
|
+
if (errores.length > 0) {
|
|
96
|
+
return { configurado: true, errores, config: null, deps: null };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const config = { port, host, githubSecret, bearerSecret, rpm, maxPayloadBytes, allowIps, inboxDir, ledgerPath };
|
|
100
|
+
const deps = {
|
|
101
|
+
inboxDir,
|
|
102
|
+
dedup: new WebhookDedup({ rutaLedger: ledgerPath }),
|
|
103
|
+
rateLimiter: new RateLimiterIP({ rpm }),
|
|
104
|
+
githubSecret,
|
|
105
|
+
bearerSecret,
|
|
106
|
+
maxPayloadBytes,
|
|
107
|
+
allowIps,
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
return { configurado: true, errores: [], config, deps };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function parseEntero(raw, defecto) {
|
|
114
|
+
if (raw === undefined || raw === null || raw === '') return defecto;
|
|
115
|
+
const n = Number.parseInt(raw, 10);
|
|
116
|
+
return Number.isInteger(n) ? n : -1; // -1 = inválido (la validación lo captura)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function parseCsv(raw) {
|
|
120
|
+
if (!raw || typeof raw !== 'string') return null;
|
|
121
|
+
const items = raw.split(',').map(s => s.trim()).filter(Boolean);
|
|
122
|
+
return items.length > 0 ? items : null;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Punto de entrada del CLI. Llamado sólo cuando este archivo se ejecuta
|
|
127
|
+
* directamente (no en require/import).
|
|
128
|
+
*/
|
|
129
|
+
function main() {
|
|
130
|
+
const { configurado, errores, config, deps } = construirDepsDesdeEnv(process.env);
|
|
131
|
+
|
|
132
|
+
if (!configurado) {
|
|
133
|
+
console.error('SWL_WEBHOOK_LISTEN_PORT no está definido. El webhook server no se arranca.');
|
|
134
|
+
console.error('Para activar, definir las variables opt-in. Ver docs/variables-entorno.md § Webhook entrante.');
|
|
135
|
+
process.exit(0);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (errores.length > 0) {
|
|
139
|
+
for (const err of errores) console.error(`[error] ${err}`);
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const server = crearServidor(deps);
|
|
144
|
+
|
|
145
|
+
server.on('error', err => {
|
|
146
|
+
console.error(JSON.stringify({ nivel: 'error', msg: 'server-error', err: err.message }));
|
|
147
|
+
process.exit(1);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
server.listen(config.port, config.host, () => {
|
|
151
|
+
const addr = server.address();
|
|
152
|
+
const endpoints = [];
|
|
153
|
+
if (config.githubSecret) endpoints.push('/webhooks/github');
|
|
154
|
+
if (config.bearerSecret) endpoints.push('/webhooks/generic');
|
|
155
|
+
endpoints.push('/healthz');
|
|
156
|
+
|
|
157
|
+
console.log(JSON.stringify({
|
|
158
|
+
nivel: 'info',
|
|
159
|
+
msg: 'webhook-server-started',
|
|
160
|
+
bind: `${addr.address}:${addr.port}`,
|
|
161
|
+
endpoints,
|
|
162
|
+
inboxDir: config.inboxDir,
|
|
163
|
+
ledgerPath: config.ledgerPath,
|
|
164
|
+
rpm: config.rpm,
|
|
165
|
+
maxPayloadBytes: config.maxPayloadBytes,
|
|
166
|
+
allowIpsCount: config.allowIps ? config.allowIps.length : 0,
|
|
167
|
+
ts: new Date().toISOString(),
|
|
168
|
+
}));
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const shutdown = (sig) => {
|
|
172
|
+
console.log(JSON.stringify({ nivel: 'info', msg: 'shutdown', sig, ts: new Date().toISOString() }));
|
|
173
|
+
server.close(() => process.exit(0));
|
|
174
|
+
// Forzar salida si el server tarda demasiado en cerrar conexiones
|
|
175
|
+
setTimeout(() => process.exit(1), 10000).unref();
|
|
176
|
+
};
|
|
177
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
178
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Sólo arrancar si se invoca directamente (no en require)
|
|
182
|
+
if (require.main === module) {
|
|
183
|
+
main();
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
module.exports = {
|
|
187
|
+
construirDepsDesdeEnv,
|
|
188
|
+
// Para tests
|
|
189
|
+
_defaults: {
|
|
190
|
+
PUERTO_MIN,
|
|
191
|
+
PUERTO_MAX,
|
|
192
|
+
RPM_DEFAULT,
|
|
193
|
+
MAX_PAYLOAD_DEFAULT,
|
|
194
|
+
HOST_DEFAULT,
|
|
195
|
+
INBOX_DIR_DEFAULT,
|
|
196
|
+
LEDGER_PATH_DEFAULT,
|
|
197
|
+
},
|
|
198
|
+
};
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
{
|
|
2
|
-
"release.md": {
|
|
3
|
-
"evolved": true,
|
|
4
|
-
"evolvedFrom": "5.4.0",
|
|
5
|
-
"evolvedAt": "2026-04-11",
|
|
6
|
-
"evolvedBy": "aprender",
|
|
7
|
-
"evolvedNote": "mejora de metodología: checklist obligatoria de archivos de versión en paso 6"
|
|
8
|
-
},
|
|
9
|
-
"aprender.md": {
|
|
10
|
-
"evolved": true,
|
|
11
|
-
"evolvedFrom": "5.12.3",
|
|
12
|
-
"evolvedAt": "2026-04-25",
|
|
13
|
-
"evolvedBy": "aprender",
|
|
14
|
-
"evolvedNote": "Paso 2 — filtro crítico obligatorio sobre reportes de sub-agentes Explore para evitar sobre-ingeniería al analizar papers académicos"
|
|
15
|
-
},
|
|
16
|
-
"verificar.md": {
|
|
17
|
-
"evolved": true,
|
|
18
|
-
"evolvedFrom": "5.12.3",
|
|
19
|
-
"evolvedAt": "2026-04-26",
|
|
20
|
-
"evolvedBy": "evolucionar",
|
|
21
|
-
"evolvedNote": "flag --until-converge para iterar verificar→corregir→re-verificar hasta 0 hallazgos CRÍTICO+ALTO+MAYOR (max-iter=5, --no-prompt CI, detección adversarial ≥5 hallazgos nuevos)"
|
|
22
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"release.md": {
|
|
3
|
+
"evolved": true,
|
|
4
|
+
"evolvedFrom": "5.4.0",
|
|
5
|
+
"evolvedAt": "2026-04-11",
|
|
6
|
+
"evolvedBy": "aprender",
|
|
7
|
+
"evolvedNote": "mejora de metodología: checklist obligatoria de archivos de versión en paso 6"
|
|
8
|
+
},
|
|
9
|
+
"aprender.md": {
|
|
10
|
+
"evolved": true,
|
|
11
|
+
"evolvedFrom": "5.12.3",
|
|
12
|
+
"evolvedAt": "2026-04-25",
|
|
13
|
+
"evolvedBy": "aprender",
|
|
14
|
+
"evolvedNote": "Paso 2 — filtro crítico obligatorio sobre reportes de sub-agentes Explore para evitar sobre-ingeniería al analizar papers académicos"
|
|
15
|
+
},
|
|
16
|
+
"verificar.md": {
|
|
17
|
+
"evolved": true,
|
|
18
|
+
"evolvedFrom": "5.12.3",
|
|
19
|
+
"evolvedAt": "2026-04-26",
|
|
20
|
+
"evolvedBy": "evolucionar",
|
|
21
|
+
"evolvedNote": "flag --until-converge para iterar verificar→corregir→re-verificar hasta 0 hallazgos CRÍTICO+ALTO+MAYOR (max-iter=5, --no-prompt CI, detección adversarial ≥5 hallazgos nuevos)"
|
|
22
|
+
}
|
|
23
23
|
}
|
|
@@ -168,7 +168,26 @@ Si `/swl:mapear-codebase` ya lo generó (opción B), solo verificar. Si no:
|
|
|
168
168
|
- Dependencias con CVEs conocidos (si `pip-audit` o `npm audit` están disponibles)
|
|
169
169
|
- Archivos con más de 500 líneas
|
|
170
170
|
|
|
171
|
-
## Paso 8 —
|
|
171
|
+
## Paso 8 — Verificar/actualizar CLAUDE.md del proyecto
|
|
172
|
+
|
|
173
|
+
Verificar el estado de `CLAUDE.md` en la raíz del proyecto:
|
|
174
|
+
|
|
175
|
+
- **Si NO existe**: generarlo con la estructura mínima de `/swl:claudemd init-project`.
|
|
176
|
+
**OBLIGATORIO** incluir como primera sección bajo el título:
|
|
177
|
+
```markdown
|
|
178
|
+
## Reglas obligatorias
|
|
179
|
+
|
|
180
|
+
@reglas/usar-sistema-swl.md
|
|
181
|
+
```
|
|
182
|
+
- **Si existe pero NO incluye `@reglas/usar-sistema-swl.md`**: agregar la
|
|
183
|
+
referencia en una sección "Reglas obligatorias" cerca del inicio del
|
|
184
|
+
archivo, preservando el contenido existente.
|
|
185
|
+
- **Si existe e incluye la referencia**: no tocar.
|
|
186
|
+
|
|
187
|
+
Esta referencia carga la matriz operacional del sistema SWL al inicio de cada
|
|
188
|
+
sesión y es el contrato base de uso del sistema para el proyecto adoptado.
|
|
189
|
+
|
|
190
|
+
## Paso 9 — Reporte final
|
|
172
191
|
|
|
173
192
|
```
|
|
174
193
|
=== Proyecto adoptado exitosamente ===
|
|
@@ -183,6 +202,7 @@ Archivos generados:
|
|
|
183
202
|
✓ .planning/research/FUNCIONALIDADES.md — inventario de funcionalidades
|
|
184
203
|
✓ .planning/research/RESUMEN.md — resumen ejecutivo consolidado
|
|
185
204
|
✓ .planning/research/TRAMPAS.md — deuda técnica y anti-patrones
|
|
205
|
+
✓ CLAUDE.md — creado o actualizado con @reglas/usar-sistema-swl.md
|
|
186
206
|
|
|
187
207
|
Hallazgos clave:
|
|
188
208
|
1. [hallazgo más importante]
|