agentic-kdd 3.5.3 → 3.5.5
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 +81 -0
- package/contract-guard.cjs +50 -0
- package/mcp-server.cjs +973 -0
- package/package.json +1 -1
- package/regression-guard.cjs +528 -0
- package/security-gate.cjs +169 -0
- package/spec-gate.cjs +188 -0
- package/src/init.js +16 -0
- package/src/mcp-setup.js +1 -0
- package/tdd-gate.cjs +52 -2
package/mcp-server.cjs
ADDED
|
@@ -0,0 +1,973 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agentic KDD MCP Server — v2.0
|
|
3
|
+
* Expone TODOS los módulos v3 como MCP tools nativos.
|
|
4
|
+
*
|
|
5
|
+
* Tools nuevas en v2.0:
|
|
6
|
+
* ast_impact — analyzeImpact(target)
|
|
7
|
+
* ast_index — indexProject()
|
|
8
|
+
* ast_symbols — getSymbols(file)
|
|
9
|
+
* spec_waves — getWaves(module)
|
|
10
|
+
* spec_status — getStatus(module)
|
|
11
|
+
* spec_create — createSpec(module, tipo)
|
|
12
|
+
* impact_precheck — preCheck(module)
|
|
13
|
+
* impact_diff — analyzeDiff(files[])
|
|
14
|
+
* knowledge_query — queryKnowledge(module)
|
|
15
|
+
* adr_ingest — ingestADRs(dir?)
|
|
16
|
+
* causal_add — addCausalEdge(desde, tipo, hacia, descripcion)
|
|
17
|
+
* causal_query — queryCausalEdges(tipo?, entidad?)
|
|
18
|
+
* decision_trail — getCicloTrail(ciclo_id)
|
|
19
|
+
* decision_why — whyExists(target)
|
|
20
|
+
* metrics_summary — computeMetrics()
|
|
21
|
+
* health_check — runHealthCheck()
|
|
22
|
+
* memory_audit — generateAuditReport()
|
|
23
|
+
* memory_forget — forgetMemory(id, razon)
|
|
24
|
+
*
|
|
25
|
+
* Transporte: stdio (compatible con Cursor, Claude Code, VS Code)
|
|
26
|
+
*
|
|
27
|
+
* Uso:
|
|
28
|
+
* node .agentic/grafo/mcp-server.cjs
|
|
29
|
+
* (registrar como MCP server en .cursor/mcp.json o claude_desktop_config.json)
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
'use strict';
|
|
33
|
+
|
|
34
|
+
const path = require('path');
|
|
35
|
+
const fs = require('fs');
|
|
36
|
+
const readline = require('readline');
|
|
37
|
+
|
|
38
|
+
const ROOT = process.env.PROJECT_ROOT || process.cwd();
|
|
39
|
+
process.stderr.write('[Agentic KDD MCP] Starting — ROOT: ' + ROOT + '\n');
|
|
40
|
+
|
|
41
|
+
// Add project node_modules to require path at startup
|
|
42
|
+
// This ensures native deps (better-sqlite3) resolve when Cursor starts the server
|
|
43
|
+
const projectNodeModules = path.join(ROOT, 'node_modules');
|
|
44
|
+
if (fs.existsSync(projectNodeModules)) {
|
|
45
|
+
module.paths.unshift(projectNodeModules);
|
|
46
|
+
process.stderr.write('[Agentic KDD MCP] node_modules: ' + projectNodeModules + '\n');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Validate DB exists
|
|
50
|
+
const DB_PATH = path.join(ROOT, '.agentic/memoria.db');
|
|
51
|
+
if (!fs.existsSync(DB_PATH)) {
|
|
52
|
+
process.stderr.write('[Agentic KDD MCP] ⚠️ DB not found at ' + DB_PATH + '\n');
|
|
53
|
+
process.stderr.write('[Agentic KDD MCP] Run: akdd init\n');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ─── LAZY LOADERS ─────────────────────────────────────────────────────────────
|
|
57
|
+
// Carga cada módulo bajo demanda — el MCP server arranca sin cargar todo.
|
|
58
|
+
|
|
59
|
+
function loadModule(name) {
|
|
60
|
+
const p = path.join(ROOT, '.agentic/grafo', name);
|
|
61
|
+
if (fs.existsSync(p)) {
|
|
62
|
+
// Temporarily add project node_modules to require path so native deps resolve
|
|
63
|
+
const projectNodeModules = path.join(ROOT, 'node_modules');
|
|
64
|
+
if (fs.existsSync(projectNodeModules) && !module.paths.includes(projectNodeModules)) {
|
|
65
|
+
module.paths.unshift(projectNodeModules);
|
|
66
|
+
}
|
|
67
|
+
try { return require(p); }
|
|
68
|
+
catch(e) {
|
|
69
|
+
process.stderr.write('[Agentic KDD MCP] ⚠️ Error loading ' + name + ': ' + e.message + '\n');
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
process.stderr.write('[Agentic KDD MCP] ⚠️ Module not found: ' + name + ' (ROOT=' + ROOT + ')\n');
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getDB() {
|
|
78
|
+
const dbPath = path.join(ROOT, '.agentic/memoria.db');
|
|
79
|
+
|
|
80
|
+
// Try project node_modules first (works when Cursor starts server from system node)
|
|
81
|
+
const localSqlite = path.join(ROOT, 'node_modules', 'better-sqlite3');
|
|
82
|
+
if (fs.existsSync(localSqlite)) {
|
|
83
|
+
try { return new (require(localSqlite))(dbPath); } catch(e) {
|
|
84
|
+
process.stderr.write('[Agentic KDD MCP] local better-sqlite3 error: ' + e.message + '\n');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Try global require
|
|
89
|
+
try { return new (require('better-sqlite3'))(dbPath); } catch {}
|
|
90
|
+
|
|
91
|
+
// Fallback: Node.js built-in sqlite (Node 22+)
|
|
92
|
+
try { const { DatabaseSync } = require('node:sqlite'); return new DatabaseSync(dbPath); } catch {}
|
|
93
|
+
|
|
94
|
+
process.stderr.write('[Agentic KDD MCP] ⚠️ No SQLite driver found. Run: npm install better-sqlite3 in project.\n');
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ─── DEFINICIÓN DE TOOLS ──────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
const TOOLS = [
|
|
101
|
+
// ── CORE (v1, ya existían) ────────────────────────────────────────────────
|
|
102
|
+
{
|
|
103
|
+
name: 'grafo_buscar',
|
|
104
|
+
description: 'Búsqueda híbrida en las 4 capas de memoria CoALA (procedural + episódica + semántica). Retorna los items más relevantes para la tarea actual.',
|
|
105
|
+
inputSchema: {
|
|
106
|
+
type: 'object',
|
|
107
|
+
properties: {
|
|
108
|
+
query: { type: 'string', description: 'Descripción de la tarea o concepto a buscar' },
|
|
109
|
+
area: { type: 'string', description: 'Área o módulo del proyecto (opcional)' },
|
|
110
|
+
limit: { type: 'number', description: 'Máximo de resultados (default: 10)' },
|
|
111
|
+
},
|
|
112
|
+
required: ['query'],
|
|
113
|
+
},
|
|
114
|
+
handler: async ({ query, area, limit = 10 }) => {
|
|
115
|
+
const g = loadModule('grafo.cjs');
|
|
116
|
+
const r = g.buscarHibrido ? g.buscarHibrido(query, area, limit) : [];
|
|
117
|
+
return { resultados: r };
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'registrar_episodio',
|
|
122
|
+
description: 'Registra un episodio crudo en memoria episódica. Usar al final de cada ciclo para preservar lo que ocurrió.',
|
|
123
|
+
inputSchema: {
|
|
124
|
+
type: 'object',
|
|
125
|
+
properties: {
|
|
126
|
+
episodio: { type: 'object', description: 'Objeto episodio con: tipo, descripcion, resultado, archivos_tocados, area' },
|
|
127
|
+
},
|
|
128
|
+
required: ['episodio'],
|
|
129
|
+
},
|
|
130
|
+
handler: async ({ episodio }) => {
|
|
131
|
+
const g = loadModule('grafo.cjs');
|
|
132
|
+
const id = g.registrarEpisodio ? g.registrarEpisodio(episodio) : null;
|
|
133
|
+
return { episodio_id: id };
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'grafo_sync',
|
|
138
|
+
description: 'Sincroniza la memoria markdown (.md) con el grafo SQLite. Ejecutar al final de cada ciclo.',
|
|
139
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
140
|
+
handler: async () => {
|
|
141
|
+
const g = loadModule('grafo.cjs');
|
|
142
|
+
const r = g.sincronizar ? g.sincronizar() : { ok: false };
|
|
143
|
+
return r;
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: 'grafo_coala',
|
|
148
|
+
description: 'Stats completo de las 4 capas CoALA de memoria del proyecto.',
|
|
149
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
150
|
+
handler: async () => {
|
|
151
|
+
const g = loadModule('grafo.cjs');
|
|
152
|
+
if (g.statsCoala) g.statsCoala();
|
|
153
|
+
return { ok: true };
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
|
|
157
|
+
// ── AST (v2 nuevo) ────────────────────────────────────────────────────────
|
|
158
|
+
{
|
|
159
|
+
name: 'ast_impact',
|
|
160
|
+
description: 'Analiza el impacto de tocar un archivo o módulo. Retorna dependencias directas, indirectas, historial causal y severidad ALTO/MEDIO/BAJO.',
|
|
161
|
+
inputSchema: {
|
|
162
|
+
type: 'object',
|
|
163
|
+
properties: {
|
|
164
|
+
target: { type: 'string', description: 'Ruta relativa del archivo o nombre del módulo' },
|
|
165
|
+
},
|
|
166
|
+
required: ['target'],
|
|
167
|
+
},
|
|
168
|
+
handler: async ({ target }) => {
|
|
169
|
+
const m = loadModule('impact-analyzer.cjs');
|
|
170
|
+
const db = getDB();
|
|
171
|
+
return m.analyzeImpact(db, target);
|
|
172
|
+
},
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: 'ast_index',
|
|
176
|
+
description: 'Indexa el proyecto en el grafo AST. Extrae símbolos, imports, call graph y calcula PageRank. Ejecutar una vez por sesión o cuando cambien muchos archivos.',
|
|
177
|
+
inputSchema: {
|
|
178
|
+
type: 'object',
|
|
179
|
+
properties: {
|
|
180
|
+
dir: { type: 'string', description: 'Subdirectorio a indexar (opcional, default: proyecto completo)' },
|
|
181
|
+
},
|
|
182
|
+
required: [],
|
|
183
|
+
},
|
|
184
|
+
handler: async ({ dir }) => {
|
|
185
|
+
const m = loadModule('ast-indexer.cjs');
|
|
186
|
+
return m.indexProject(ROOT, dir);
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
name: 'ast_symbols',
|
|
191
|
+
description: 'Retorna todos los símbolos (funciones, clases, exports) de un archivo específico.',
|
|
192
|
+
inputSchema: {
|
|
193
|
+
type: 'object',
|
|
194
|
+
properties: {
|
|
195
|
+
file: { type: 'string', description: 'Ruta relativa del archivo' },
|
|
196
|
+
},
|
|
197
|
+
required: ['file'],
|
|
198
|
+
},
|
|
199
|
+
handler: async ({ file }) => {
|
|
200
|
+
const db = getDB();
|
|
201
|
+
try {
|
|
202
|
+
const symbols = db.prepare('SELECT symbol_name, kind, line_start, exported, pagerank FROM ast_symbols WHERE file = ? ORDER BY line_start').all(file);
|
|
203
|
+
return { file, symbols };
|
|
204
|
+
} catch { return { file, symbols: [], error: 'AST no indexado' }; }
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
// ── IMPACT (v2 nuevo) ─────────────────────────────────────────────────────
|
|
209
|
+
{
|
|
210
|
+
name: 'impact_precheck',
|
|
211
|
+
description: 'Pre-check de impacto para un módulo. Combina AST + causal + knowledge. Usar ANTES de planificar cualquier cambio.',
|
|
212
|
+
inputSchema: {
|
|
213
|
+
type: 'object',
|
|
214
|
+
properties: {
|
|
215
|
+
modulo: { type: 'string', description: 'Nombre del módulo o ruta del archivo' },
|
|
216
|
+
},
|
|
217
|
+
required: ['modulo'],
|
|
218
|
+
},
|
|
219
|
+
handler: async ({ modulo }) => {
|
|
220
|
+
const m = loadModule('impact-analyzer.cjs');
|
|
221
|
+
return m.preCheck(ROOT, modulo);
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
name: 'impact_diff',
|
|
226
|
+
description: 'Analiza el impacto combinado de un conjunto de archivos que se van a modificar. Retorna severidad máxima y recomendaciones.',
|
|
227
|
+
inputSchema: {
|
|
228
|
+
type: 'object',
|
|
229
|
+
properties: {
|
|
230
|
+
files: { type: 'array', items: { type: 'string' }, description: 'Array de rutas relativas de archivos a modificar' },
|
|
231
|
+
},
|
|
232
|
+
required: ['files'],
|
|
233
|
+
},
|
|
234
|
+
handler: async ({ files }) => {
|
|
235
|
+
const m = loadModule('impact-analyzer.cjs');
|
|
236
|
+
const db = getDB();
|
|
237
|
+
return m.analyzeDiff(db, files);
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
// ── SPECS (v2 nuevo) ──────────────────────────────────────────────────────
|
|
242
|
+
{
|
|
243
|
+
name: 'spec_waves',
|
|
244
|
+
description: 'Retorna las waves de ejecución de un módulo (wave 1 = tareas sin deps, wave 2 = deps de wave 1, etc.). Usar para saber exactamente qué ejecutar ahora.',
|
|
245
|
+
inputSchema: {
|
|
246
|
+
type: 'object',
|
|
247
|
+
properties: {
|
|
248
|
+
modulo: { type: 'string', description: 'Nombre del módulo' },
|
|
249
|
+
},
|
|
250
|
+
required: ['modulo'],
|
|
251
|
+
},
|
|
252
|
+
handler: async ({ modulo }) => {
|
|
253
|
+
const m = loadModule('spec-manager.cjs');
|
|
254
|
+
const specDir = path.join(ROOT, '.agentic/specs', modulo);
|
|
255
|
+
const tasksPath = path.join(specDir, 'tasks.md');
|
|
256
|
+
if (!fs.existsSync(tasksPath)) return { error: `spec '${modulo}' no tiene tasks.md` };
|
|
257
|
+
const tasks = m.parseTasks(fs.readFileSync(tasksPath, 'utf8'));
|
|
258
|
+
const { waves } = m.buildWaves(tasks);
|
|
259
|
+
return { modulo, waves: waves.map((w, i) => ({ wave: i + 1, tasks: w })) };
|
|
260
|
+
},
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: 'spec_status',
|
|
264
|
+
description: 'Estado actual de un spec: progreso, tareas completadas, bloqueadas, próxima wave.',
|
|
265
|
+
inputSchema: {
|
|
266
|
+
type: 'object',
|
|
267
|
+
properties: {
|
|
268
|
+
modulo: { type: 'string', description: 'Nombre del módulo' },
|
|
269
|
+
},
|
|
270
|
+
required: ['modulo'],
|
|
271
|
+
},
|
|
272
|
+
handler: async ({ modulo }) => {
|
|
273
|
+
const m = loadModule('spec-manager.cjs');
|
|
274
|
+
const specDir = path.join(ROOT, '.agentic/specs', modulo);
|
|
275
|
+
return m.getSpecStatus(specDir) ?? { error: `spec '${modulo}' no encontrado` };
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
name: 'spec_create',
|
|
280
|
+
description: 'Crea un spec nuevo para un módulo (feature o bugfix). Genera requirements.md + design.md + tasks.md con template.',
|
|
281
|
+
inputSchema: {
|
|
282
|
+
type: 'object',
|
|
283
|
+
properties: {
|
|
284
|
+
modulo: { type: 'string', description: 'Nombre del módulo' },
|
|
285
|
+
tipo: { type: 'string', enum: ['feature', 'bugfix'], description: 'Tipo de spec (default: feature)' },
|
|
286
|
+
},
|
|
287
|
+
required: ['modulo'],
|
|
288
|
+
},
|
|
289
|
+
handler: async ({ modulo, tipo = 'feature' }) => {
|
|
290
|
+
const m = loadModule('spec-manager.cjs');
|
|
291
|
+
const dir = m.createSpecFromTemplate(ROOT, modulo, tipo);
|
|
292
|
+
return { created: true, path: path.relative(ROOT, dir) };
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
|
|
296
|
+
// ── KNOWLEDGE (v2 nuevo) ──────────────────────────────────────────────────
|
|
297
|
+
{
|
|
298
|
+
name: 'knowledge_query',
|
|
299
|
+
description: 'Consulta la base de conocimiento (ADRs y gotchas) para un módulo. Retorna decisiones arquitectónicas y restricciones aplicables.',
|
|
300
|
+
inputSchema: {
|
|
301
|
+
type: 'object',
|
|
302
|
+
properties: {
|
|
303
|
+
modulo: { type: 'string', description: 'Módulo o área a consultar' },
|
|
304
|
+
tipo: { type: 'string', description: 'Filtrar por tipo: adr | gotcha | convention (opcional)' },
|
|
305
|
+
},
|
|
306
|
+
required: [],
|
|
307
|
+
},
|
|
308
|
+
handler: async ({ modulo, tipo }) => {
|
|
309
|
+
const m = loadModule('adr-ingestor.cjs');
|
|
310
|
+
const db = getDB();
|
|
311
|
+
return m.queryKnowledge(db, { modulo, tipo, status: 'accepted' });
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
name: 'adr_ingest',
|
|
316
|
+
description: 'Ingesta ADRs del directorio docs/adr/ en el grafo de conocimiento.',
|
|
317
|
+
inputSchema: {
|
|
318
|
+
type: 'object',
|
|
319
|
+
properties: {
|
|
320
|
+
dir: { type: 'string', description: 'Directorio de ADRs (default: docs/adr)' },
|
|
321
|
+
},
|
|
322
|
+
required: [],
|
|
323
|
+
},
|
|
324
|
+
handler: async ({ dir = 'docs/adr' }) => {
|
|
325
|
+
const m = loadModule('adr-ingestor.cjs');
|
|
326
|
+
return m.ingestDirectory(ROOT, dir);
|
|
327
|
+
},
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
// ── CAUSAL EDGES (v2 nuevo) ───────────────────────────────────────────────
|
|
331
|
+
{
|
|
332
|
+
name: 'causal_add',
|
|
333
|
+
description: 'Registra un edge causal en memoria. Tipos: caused_failure, was_fixed_by, tested_by, regressed_by.',
|
|
334
|
+
inputSchema: {
|
|
335
|
+
type: 'object',
|
|
336
|
+
properties: {
|
|
337
|
+
desde: { type: 'string', description: 'Entidad origen (archivo o módulo)' },
|
|
338
|
+
tipo: { type: 'string', enum: ['caused_failure','was_fixed_by','tested_by','regressed_by','depends_on_decision'] },
|
|
339
|
+
hacia: { type: 'string', description: 'Entidad destino' },
|
|
340
|
+
descripcion: { type: 'string', description: 'Descripción del edge' },
|
|
341
|
+
confidence: { type: 'string', enum: ['BAJA','MEDIA','ALTA'], description: 'Confianza del edge' },
|
|
342
|
+
},
|
|
343
|
+
required: ['desde', 'tipo', 'hacia'],
|
|
344
|
+
},
|
|
345
|
+
handler: async ({ desde, tipo, hacia, descripcion = '', confidence = 'MEDIA' }) => {
|
|
346
|
+
const m = loadModule('causal-edges.cjs');
|
|
347
|
+
const db = getDB();
|
|
348
|
+
return m.addCausalEdge(db, { desde_entidad: desde, tipo, hacia_entidad: hacia, descripcion, confidence });
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
name: 'causal_query',
|
|
353
|
+
description: 'Consulta edges causales. Usar para entender qué causó qué en el proyecto.',
|
|
354
|
+
inputSchema: {
|
|
355
|
+
type: 'object',
|
|
356
|
+
properties: {
|
|
357
|
+
tipo: { type: 'string', description: 'Tipo de edge a filtrar (opcional)' },
|
|
358
|
+
entidad: { type: 'string', description: 'Entidad a consultar (opcional)' },
|
|
359
|
+
includeHistory: { type: 'boolean', description: 'Incluir edges invalidados' },
|
|
360
|
+
},
|
|
361
|
+
required: [],
|
|
362
|
+
},
|
|
363
|
+
handler: async ({ tipo, entidad, includeHistory = false }) => {
|
|
364
|
+
const m = loadModule('causal-edges.cjs');
|
|
365
|
+
const db = getDB();
|
|
366
|
+
return m.queryCausalEdges(db, { tipo, entidad, includeHistory });
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
// ── DECISION TRAIL (v2 nuevo) ─────────────────────────────────────────────
|
|
371
|
+
{
|
|
372
|
+
name: 'decision_trail',
|
|
373
|
+
description: 'Trail completo de un ciclo: qué cambió, qué memoria influyó, qué quedó invalidado.',
|
|
374
|
+
inputSchema: {
|
|
375
|
+
type: 'object',
|
|
376
|
+
properties: {
|
|
377
|
+
ciclo_id: { type: 'string', description: 'ID del ciclo' },
|
|
378
|
+
},
|
|
379
|
+
required: ['ciclo_id'],
|
|
380
|
+
},
|
|
381
|
+
handler: async ({ ciclo_id }) => {
|
|
382
|
+
const m = loadModule('decision-trail.cjs');
|
|
383
|
+
const db = getDB();
|
|
384
|
+
return m.getCicloTrail(db, ciclo_id);
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
{
|
|
388
|
+
name: 'decision_why',
|
|
389
|
+
description: 'Explica por qué existe algo en el código/memoria: cadena causal + ADRs + episodios históricos.',
|
|
390
|
+
inputSchema: {
|
|
391
|
+
type: 'object',
|
|
392
|
+
properties: {
|
|
393
|
+
target: { type: 'string', description: 'Archivo, módulo o entidad a explicar' },
|
|
394
|
+
},
|
|
395
|
+
required: ['target'],
|
|
396
|
+
},
|
|
397
|
+
handler: async ({ target }) => {
|
|
398
|
+
const m = loadModule('decision-trail.cjs');
|
|
399
|
+
const db = getDB();
|
|
400
|
+
return m.whyExists(db, target);
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
|
|
404
|
+
// ── MÉTRICAS (v2 nuevo) ───────────────────────────────────────────────────
|
|
405
|
+
{
|
|
406
|
+
name: 'metrics_summary',
|
|
407
|
+
description: 'Métricas operacionales del proyecto: tasa de éxito, retrabajo, calidad de memoria, autonomy score, token savings estimado.',
|
|
408
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
409
|
+
handler: async () => {
|
|
410
|
+
const m = loadModule('metrics.cjs');
|
|
411
|
+
const db = getDB();
|
|
412
|
+
return {
|
|
413
|
+
cycles: m.computeCycleMetrics(db),
|
|
414
|
+
memory: m.computeMemoryMetrics(db),
|
|
415
|
+
autonomy: m.computeAutonomyScore(db),
|
|
416
|
+
tokens: m.estimateTokenSavings(db),
|
|
417
|
+
};
|
|
418
|
+
},
|
|
419
|
+
},
|
|
420
|
+
|
|
421
|
+
// ── HEALTH CHECK (v2 nuevo) ───────────────────────────────────────────────
|
|
422
|
+
{
|
|
423
|
+
name: 'health_check',
|
|
424
|
+
description: 'Diagnóstico completo del sistema: qué funciona, qué falta, qué comando ejecutar para arreglarlo.',
|
|
425
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
426
|
+
handler: async () => {
|
|
427
|
+
const m = loadModule('health-check.cjs');
|
|
428
|
+
return m.runHealthCheck(ROOT);
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
|
|
432
|
+
// ── MEMORY AUDIT (v2 nuevo) ───────────────────────────────────────────────
|
|
433
|
+
{
|
|
434
|
+
name: 'memory_audit',
|
|
435
|
+
description: 'Reporte de auditoría de memoria: entradas stale, contradicciones, consolidaciones propuestas.',
|
|
436
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
437
|
+
handler: async () => {
|
|
438
|
+
const m = loadModule('memory-audit.cjs');
|
|
439
|
+
const db = getDB();
|
|
440
|
+
m.migrateVigenciaTipo(db);
|
|
441
|
+
return m.generateAuditReport(db);
|
|
442
|
+
},
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
name: 'memory_forget',
|
|
446
|
+
description: 'Olvida explícitamente una entrada de memoria con evidencia. No borra — invalida con razón documentada.',
|
|
447
|
+
inputSchema: {
|
|
448
|
+
type: 'object',
|
|
449
|
+
properties: {
|
|
450
|
+
id: { type: 'number', description: 'ID del nodo a olvidar' },
|
|
451
|
+
razon: { type: 'string', description: 'Razón por la que se invalida (requerido para audit trail)' },
|
|
452
|
+
},
|
|
453
|
+
required: ['id', 'razon'],
|
|
454
|
+
},
|
|
455
|
+
handler: async ({ id, razon }) => {
|
|
456
|
+
const m = loadModule('memory-audit.cjs');
|
|
457
|
+
const db = getDB();
|
|
458
|
+
return m.forgetMemory(db, id, razon, ROOT);
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
{
|
|
462
|
+
name: 'verdad_vigente',
|
|
463
|
+
description: 'Retorna SOLO la memoria vigente (no histórica, no evidencia, no obsoleta). Úsalo en lugar de grafo_buscar cuando necesitas reglas que aplican HOY.',
|
|
464
|
+
inputSchema: {
|
|
465
|
+
type: 'object',
|
|
466
|
+
properties: {
|
|
467
|
+
area: { type: 'string', description: 'Área o módulo del proyecto' },
|
|
468
|
+
tipo: { type: 'string', description: 'Tipo de nodo: error | patron | decision' },
|
|
469
|
+
limit: { type: 'number', description: 'Máximo de resultados (default: 20)' },
|
|
470
|
+
},
|
|
471
|
+
required: [],
|
|
472
|
+
},
|
|
473
|
+
handler: async ({ area, tipo, limit = 20 }) => {
|
|
474
|
+
const m = loadModule('memory-audit.cjs');
|
|
475
|
+
const db = getDB();
|
|
476
|
+
m.migrateVigenciaTipo(db);
|
|
477
|
+
return m.verdadVigente(db, area, tipo, limit);
|
|
478
|
+
},
|
|
479
|
+
},
|
|
480
|
+
];
|
|
481
|
+
|
|
482
|
+
// ─── MCP PROTOCOL (JSON-RPC 2.0 over stdio) ───────────────────────────────────
|
|
483
|
+
|
|
484
|
+
const rl = readline.createInterface({ input: process.stdin, terminal: false });
|
|
485
|
+
|
|
486
|
+
rl.on('line', async (line) => {
|
|
487
|
+
let request;
|
|
488
|
+
try { request = JSON.parse(line); } catch { return; }
|
|
489
|
+
|
|
490
|
+
const { id, method, params } = request;
|
|
491
|
+
|
|
492
|
+
try {
|
|
493
|
+
if (method === 'initialize') {
|
|
494
|
+
sendResponse(id, {
|
|
495
|
+
protocolVersion: '2024-11-05',
|
|
496
|
+
capabilities: { tools: {} },
|
|
497
|
+
serverInfo: { name: 'agentic-kdd', version: '2.0.0' },
|
|
498
|
+
});
|
|
499
|
+
} else if (method === 'tools/list') {
|
|
500
|
+
sendResponse(id, {
|
|
501
|
+
tools: TOOLS.map(t => ({
|
|
502
|
+
name: t.name,
|
|
503
|
+
description: t.description,
|
|
504
|
+
inputSchema: t.inputSchema,
|
|
505
|
+
})),
|
|
506
|
+
});
|
|
507
|
+
} else if (method === 'tools/call') {
|
|
508
|
+
const { name, arguments: args = {} } = params;
|
|
509
|
+
const tool = TOOLS.find(t => t.name === name);
|
|
510
|
+
if (!tool) {
|
|
511
|
+
sendError(id, -32601, `Tool '${name}' no encontrada`);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
try {
|
|
515
|
+
const result = await tool.handler(args);
|
|
516
|
+
sendResponse(id, {
|
|
517
|
+
content: [{ type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result, null, 2) }],
|
|
518
|
+
});
|
|
519
|
+
} catch (e) {
|
|
520
|
+
sendError(id, -32603, `Error ejecutando ${name}: ${e.message}`);
|
|
521
|
+
}
|
|
522
|
+
} else {
|
|
523
|
+
sendError(id, -32601, `Método '${method}' no soportado`);
|
|
524
|
+
}
|
|
525
|
+
} catch (e) {
|
|
526
|
+
sendError(id, -32603, e.message);
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
function sendResponse(id, result) {
|
|
531
|
+
const response = JSON.stringify({ jsonrpc: '2.0', id, result });
|
|
532
|
+
process.stdout.write(response + '\n');
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function sendError(id, code, message) {
|
|
536
|
+
const response = JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } });
|
|
537
|
+
process.stdout.write(response + '\n');
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
process.on('SIGINT', () => process.exit(0));
|
|
541
|
+
process.on('SIGTERM', () => process.exit(0));
|
|
542
|
+
|
|
543
|
+
console.error(`[Agentic KDD MCP v2.0] ${TOOLS.length} tools disponibles. ROOT: ${ROOT}`);
|
|
544
|
+
|
|
545
|
+
// ─── v3.2: TOOLS ADICIONALES ──────────────────────────────────────────────────
|
|
546
|
+
// mem_curate, generate_llms_txt, report_benchmarks, causal_prune
|
|
547
|
+
|
|
548
|
+
// Lookup map para tools registradas dinámicamente (v3.2+)
|
|
549
|
+
const TOOL_MAP = {};
|
|
550
|
+
|
|
551
|
+
// Añadir al TOOL_MAP y TOOLS en runtime
|
|
552
|
+
const TOOLS_V32 = [
|
|
553
|
+
{
|
|
554
|
+
name: 'mem_curate',
|
|
555
|
+
description: 'Curation autónoma de memoria: TTL, deduplicación semántica, resolución de conflictos, scores.',
|
|
556
|
+
inputSchema: { type:'object', properties:{ mode:{type:'string',enum:['run','ttl','dedup','conflicts','score','report']} }, required:[] },
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
name: 'generate_llms_txt',
|
|
560
|
+
description: 'Genera .agentic/llms.txt, llms-full.txt y knowledge-graph.json para Git versioning.',
|
|
561
|
+
inputSchema: { type:'object', properties:{}, required:[] },
|
|
562
|
+
},
|
|
563
|
+
{
|
|
564
|
+
name: 'report_benchmarks',
|
|
565
|
+
description: 'LongMemEval + Token Reduction Index + Memory Quality Score. Evidencia pública de valor.',
|
|
566
|
+
inputSchema: { type:'object', properties:{}, required:[] },
|
|
567
|
+
},
|
|
568
|
+
{
|
|
569
|
+
name: 'causal_prune',
|
|
570
|
+
description: 'Prune semántico del grafo causal. Previene colapso de contexto por exceso de edges.',
|
|
571
|
+
inputSchema: { type:'object', properties:{ maxPerEntity:{type:'number'}, ageDays:{type:'number'} }, required:[] },
|
|
572
|
+
},
|
|
573
|
+
];
|
|
574
|
+
|
|
575
|
+
// Handler dinámico para tools v3.2
|
|
576
|
+
async function handleV32Tool(name, args={}) {
|
|
577
|
+
switch(name) {
|
|
578
|
+
case 'mem_curate': {
|
|
579
|
+
const m = require(path.join(ROOT, '.agentic/grafo/mem-curator.cjs'));
|
|
580
|
+
const db = getDB();
|
|
581
|
+
const mode = args.mode || 'run';
|
|
582
|
+
return mode==='ttl' ? m.enforceEpisodicTTL(db,ROOT)
|
|
583
|
+
: mode==='dedup' ? m.deduplicateNodes(db,ROOT)
|
|
584
|
+
: mode==='conflicts' ? m.resolveConflicts(db,ROOT)
|
|
585
|
+
: mode==='score' ? m.recalculateScores(db,ROOT)
|
|
586
|
+
: mode==='report' ? m.generateReport(ROOT)
|
|
587
|
+
: m.runCuration(ROOT);
|
|
588
|
+
}
|
|
589
|
+
case 'generate_llms_txt': {
|
|
590
|
+
const m = require(path.join(ROOT, '.agentic/grafo/llms-generator.cjs'));
|
|
591
|
+
return m.generateAll(ROOT);
|
|
592
|
+
}
|
|
593
|
+
case 'report_benchmarks': {
|
|
594
|
+
const m = require(path.join(ROOT, '.agentic/grafo/metrics.cjs'));
|
|
595
|
+
const db = getDB();
|
|
596
|
+
return m.computeReportBenchmarks(db);
|
|
597
|
+
}
|
|
598
|
+
case 'causal_prune': {
|
|
599
|
+
const m = require(path.join(ROOT, '.agentic/grafo/causal-edges.cjs'));
|
|
600
|
+
const db = getDB();
|
|
601
|
+
return m.pruneEdges ? m.pruneEdges(db, args) : { error: 'pruneEdges no disponible' };
|
|
602
|
+
}
|
|
603
|
+
default: return { error: `Tool v3.2 '${name}' no encontrada` };
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Registrar en el servidor existente
|
|
608
|
+
TOOLS.push(...TOOLS_V32);
|
|
609
|
+
TOOLS_V32.forEach(t => { TOOL_MAP[t.name] = { ...t, handler: (args) => handleV32Tool(t.name, args) }; });
|
|
610
|
+
|
|
611
|
+
process.stderr.write('[Agentic KDD MCP v3.2] +4 tools v3.2 registradas (mem_curate, generate_llms_txt, report_benchmarks, causal_prune)\n');
|
|
612
|
+
|
|
613
|
+
// ─── v3.2: CLI UNIFICATION — Tools que hoy solo existen en terminal ───────────
|
|
614
|
+
// El dev nunca sale del chat del IDE para hacer init, update, collab.
|
|
615
|
+
|
|
616
|
+
const TOOLS_CLI = [
|
|
617
|
+
{
|
|
618
|
+
name: 'init_project',
|
|
619
|
+
description: 'Instala Agentic KDD en el proyecto actual. Equivale a correr "akdd init" en terminal. Configura MCP automáticamente.',
|
|
620
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
621
|
+
},
|
|
622
|
+
{
|
|
623
|
+
name: 'update_project',
|
|
624
|
+
description: 'Actualiza agentes y módulos desde GitHub. Equivale a "akdd update". La memoria queda intacta.',
|
|
625
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
626
|
+
},
|
|
627
|
+
{
|
|
628
|
+
name: 'collab_init',
|
|
629
|
+
description: 'Activa el modo colaborativo. Crea la base de datos compartida automáticamente en Turso. Equivale a "akdd collab init".',
|
|
630
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
631
|
+
},
|
|
632
|
+
{
|
|
633
|
+
name: 'collab_invite',
|
|
634
|
+
description: 'Genera un código de invitación temporal (24h, un solo uso) para que un miembro del equipo se una. Equivale a "akdd collab invite".',
|
|
635
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
636
|
+
},
|
|
637
|
+
{
|
|
638
|
+
name: 'collab_status',
|
|
639
|
+
description: 'Muestra el estado del modo colaborativo: DB activa, último sync, conexión.',
|
|
640
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
641
|
+
},
|
|
642
|
+
{
|
|
643
|
+
name: 'system_health',
|
|
644
|
+
description: 'Diagnóstico completo del sistema Agentic KDD. Equivale a "akdd health". Retorna qué está configurado y qué falta.',
|
|
645
|
+
inputSchema: {
|
|
646
|
+
type: 'object',
|
|
647
|
+
properties: {
|
|
648
|
+
fix: { type: 'boolean', description: 'Intentar arreglar automáticamente los problemas detectados' },
|
|
649
|
+
},
|
|
650
|
+
required: [],
|
|
651
|
+
},
|
|
652
|
+
},
|
|
653
|
+
];
|
|
654
|
+
|
|
655
|
+
async function handleCLITool(name, args={}) {
|
|
656
|
+
const { execSync } = require('child_process');
|
|
657
|
+
const run = (cmd) => {
|
|
658
|
+
try {
|
|
659
|
+
const out = execSync(cmd, { cwd: ROOT, stdio: 'pipe', timeout: 60000 }).toString();
|
|
660
|
+
return { ok: true, output: out };
|
|
661
|
+
} catch (e) {
|
|
662
|
+
return { ok: false, output: e.stdout?.toString() || e.message };
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
switch(name) {
|
|
667
|
+
case 'init_project':
|
|
668
|
+
return run('akdd init --non-interactive');
|
|
669
|
+
|
|
670
|
+
case 'update_project':
|
|
671
|
+
return run('akdd update');
|
|
672
|
+
|
|
673
|
+
case 'collab_init': {
|
|
674
|
+
const m = require(path.join(ROOT, '.agentic/grafo/collab-manager.cjs'));
|
|
675
|
+
return m.collabInit(ROOT);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
case 'collab_invite': {
|
|
679
|
+
// Leer config del proyecto
|
|
680
|
+
const fs = require('fs');
|
|
681
|
+
const configPath = path.join(ROOT, '.agentic/collab.json');
|
|
682
|
+
if (!fs.existsSync(configPath)) {
|
|
683
|
+
return { ok: false, error: 'Modo colaborativo no activado. Usar collab_init primero.' };
|
|
684
|
+
}
|
|
685
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
686
|
+
const projectId = config.project_id;
|
|
687
|
+
|
|
688
|
+
// Llamar al Worker
|
|
689
|
+
const PROVISIONER_URL = 'https://agentic-collab.adrianlpz-game.workers.dev';
|
|
690
|
+
try {
|
|
691
|
+
const response = await fetch(`${PROVISIONER_URL}/invite`, {
|
|
692
|
+
method: 'POST',
|
|
693
|
+
headers: { 'Content-Type': 'application/json' },
|
|
694
|
+
body: JSON.stringify({ projectId }),
|
|
695
|
+
});
|
|
696
|
+
const result = await response.json();
|
|
697
|
+
return result;
|
|
698
|
+
} catch (e) {
|
|
699
|
+
return { ok: false, error: e.message };
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
case 'collab_status': {
|
|
704
|
+
const m = require(path.join(ROOT, '.agentic/grafo/collab-manager.cjs'));
|
|
705
|
+
// status() usa console.log, capturamos
|
|
706
|
+
const config = m.loadConfig(ROOT);
|
|
707
|
+
if (!config?.enabled) return { enabled: false, message: 'Collab no activado. Usar collab_init.' };
|
|
708
|
+
return {
|
|
709
|
+
enabled: true,
|
|
710
|
+
db: config.db || config.url,
|
|
711
|
+
member_id: config.member_id,
|
|
712
|
+
last_sync: config.last_sync,
|
|
713
|
+
sync_on_cycle_end: config.sync_on_cycle_end,
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
case 'system_health': {
|
|
718
|
+
const m = require(path.join(ROOT, '.agentic/grafo/health-check.cjs'));
|
|
719
|
+
return m.runHealthCheck(ROOT);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
default:
|
|
723
|
+
return { error: `CLI tool '${name}' no encontrada` };
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// Registrar tools CLI en el servidor
|
|
728
|
+
TOOLS.push(...TOOLS_CLI);
|
|
729
|
+
TOOLS_CLI.forEach(t => {
|
|
730
|
+
TOOL_MAP[t.name] = { ...t, handler: (args) => handleCLITool(t.name, args) };
|
|
731
|
+
});
|
|
732
|
+
|
|
733
|
+
process.stderr.write('[Agentic KDD MCP] +6 CLI tools registradas — init_project, update_project, collab_init, collab_invite, collab_status, system_health\n');
|
|
734
|
+
|
|
735
|
+
// ─── v3.3: CONTRACT GUARD + CREATIVE ENGINE MCP TOOLS ────────────────────────
|
|
736
|
+
|
|
737
|
+
const TOOLS_V33 = [
|
|
738
|
+
{ name: 'contracts_status', description: 'Contract Guard status — protected, verified, candidate, violations.', inputSchema: {type:'object',properties:{},required:[]} },
|
|
739
|
+
{ name: 'contracts_list', description: 'List verified contracts. Filter by module.', inputSchema: {type:'object',properties:{module:{type:'string'}},required:[]} },
|
|
740
|
+
{ name: 'contracts_blast', description: 'Blast radius for a file — how many contracts at risk if this file changes.', inputSchema: {type:'object',properties:{file:{type:'string'}},required:['file']} },
|
|
741
|
+
{ name: 'contracts_gate', description: 'Run Preservation Gate — checks all verified contracts still pass. Call before accepting changes.', inputSchema: {type:'object',properties:{modified_files:{type:'array',items:{type:'string'}}},required:[]} },
|
|
742
|
+
{ name: 'creative_level', description: 'Current Creative Engine level (0=strict, 1=assisted, 2=creative_controlled). Shows how many contracts needed for level 2.', inputSchema: {type:'object',properties:{},required:[]} },
|
|
743
|
+
{ name: 'creative_suggest', description: 'List pending creative suggestions — simplifications, refactors, missing tests, fragility warnings.', inputSchema: {type:'object',properties:{module:{type:'string'}},required:[]} },
|
|
744
|
+
{ name: 'creative_apply', description: 'Apply a creative suggestion (only if auto_applicable=true and blast_radius≤3).', inputSchema: {type:'object',properties:{id:{type:'string'}},required:['id']} },
|
|
745
|
+
{ name: 'creative_wins', description: 'Show applied creative improvements and their impact.', inputSchema: {type:'object',properties:{},required:[]} },
|
|
746
|
+
];
|
|
747
|
+
|
|
748
|
+
async function handleV33Tool(name, args={}) {
|
|
749
|
+
switch(name) {
|
|
750
|
+
case 'contracts_status': {
|
|
751
|
+
const m = require(path.join(ROOT, '.agentic/grafo/contract-guard.cjs'));
|
|
752
|
+
const db = getDB(); m.migrateSchema(db); return m.getStatus(db);
|
|
753
|
+
}
|
|
754
|
+
case 'contracts_list': {
|
|
755
|
+
const m = require(path.join(ROOT, '.agentic/grafo/contract-guard.cjs'));
|
|
756
|
+
const db = getDB(); m.migrateSchema(db); return m.listContracts(db, args.module);
|
|
757
|
+
}
|
|
758
|
+
case 'contracts_blast': {
|
|
759
|
+
const m = require(path.join(ROOT, '.agentic/grafo/contract-guard.cjs'));
|
|
760
|
+
const db = getDB(); m.migrateSchema(db); return m.getBlastRadiusReport(db, ROOT, args.file);
|
|
761
|
+
}
|
|
762
|
+
case 'contracts_gate': {
|
|
763
|
+
const m = require(path.join(ROOT, '.agentic/grafo/contract-guard.cjs'));
|
|
764
|
+
const db = getDB(); m.migrateSchema(db);
|
|
765
|
+
return m.runPreservationGate(db, ROOT, `mcp-${Date.now()}`, args.modified_files || []);
|
|
766
|
+
}
|
|
767
|
+
case 'creative_level': {
|
|
768
|
+
const m = require(path.join(ROOT, '.agentic/grafo/creative-engine.cjs'));
|
|
769
|
+
const db = getDB(); m.migrateSchema(db); return m.getCurrentLevel(db, ROOT);
|
|
770
|
+
}
|
|
771
|
+
case 'creative_suggest': {
|
|
772
|
+
const m = require(path.join(ROOT, '.agentic/grafo/creative-engine.cjs'));
|
|
773
|
+
const db = getDB(); m.migrateSchema(db); return m.getSuggestions(db, args.module);
|
|
774
|
+
}
|
|
775
|
+
case 'creative_apply': {
|
|
776
|
+
const m = require(path.join(ROOT, '.agentic/grafo/creative-engine.cjs'));
|
|
777
|
+
const db = getDB(); m.migrateSchema(db);
|
|
778
|
+
return m.applySuggestion(db, args.id, ROOT, `mcp-${Date.now()}`);
|
|
779
|
+
}
|
|
780
|
+
case 'creative_wins': {
|
|
781
|
+
const m = require(path.join(ROOT, '.agentic/grafo/creative-engine.cjs'));
|
|
782
|
+
const db = getDB(); m.migrateSchema(db); return m.getCreativeWins(db);
|
|
783
|
+
}
|
|
784
|
+
default: return { error: `V33 tool '${name}' not found` };
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
TOOLS.push(...TOOLS_V33);
|
|
789
|
+
TOOLS_V33.forEach(t => { TOOL_MAP[t.name] = { ...t, handler: (args) => handleV33Tool(t.name, args) }; });
|
|
790
|
+
process.stderr.write('[Agentic KDD MCP] +8 v3.3 tools (contracts_status, contracts_blast, contracts_gate, creative_level, creative_suggest, creative_apply, creative_wins)\n');
|
|
791
|
+
|
|
792
|
+
// ─── v3.3: SESSION GUARD MCP TOOL ────────────────────────────────────────────
|
|
793
|
+
TOOLS.push({
|
|
794
|
+
name: 'session_historial',
|
|
795
|
+
description: 'Recupera el checkpoint de la última sesión. Úsalo al inicio de un chat nuevo para retomar el contexto exacto de donde quedaste.',
|
|
796
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
797
|
+
});
|
|
798
|
+
TOOL_MAP['session_historial'] = {
|
|
799
|
+
name: 'session_historial',
|
|
800
|
+
description: 'Recupera el último checkpoint de sesión.',
|
|
801
|
+
inputSchema: { type: 'object', properties: {}, required: [] },
|
|
802
|
+
handler: async () => {
|
|
803
|
+
try {
|
|
804
|
+
const m = require(path.join(ROOT, '.agentic/grafo/session-guard.cjs'));
|
|
805
|
+
return m.generateCheckpoint(ROOT) || { message: 'Sin ciclos todavía — corre aa: primero' };
|
|
806
|
+
} catch (e) { return { error: e.message }; }
|
|
807
|
+
}
|
|
808
|
+
};
|
|
809
|
+
process.stderr.write('[Agentic KDD MCP] +1 session_historial tool\n');
|
|
810
|
+
|
|
811
|
+
// ─── v3.3: AUTONOMOUS DECISION ENGINE MCP TOOLS ──────────────────────────────
|
|
812
|
+
const TOOLS_AUTONOMOUS = [
|
|
813
|
+
{
|
|
814
|
+
name: 'autonomous_decide',
|
|
815
|
+
description: 'Analyzes a proposed change and returns: STOP/WARN/IMPLEMENT/IMPLEMENT_CAUTIOUS/DEFER. Checks blast radius, prerequisite chain, cross-module patterns, and contract status. Use before any significant change.',
|
|
816
|
+
inputSchema: {
|
|
817
|
+
type: 'object',
|
|
818
|
+
properties: {
|
|
819
|
+
files: { type: 'array', items: { type: 'string' }, description: 'Files to be modified' },
|
|
820
|
+
task: { type: 'string', description: 'Task description' },
|
|
821
|
+
error_signatures: { type: 'array', items: { type: 'string' }, description: 'Error signatures detected' },
|
|
822
|
+
},
|
|
823
|
+
required: ['files'],
|
|
824
|
+
},
|
|
825
|
+
},
|
|
826
|
+
{
|
|
827
|
+
name: 'autonomous_sprint',
|
|
828
|
+
description: 'Generates a sprint plan combining business objective with technical findings. Pass objective, priorities and constraints — Agentic produces an executable priority-ordered plan.',
|
|
829
|
+
inputSchema: {
|
|
830
|
+
type: 'object',
|
|
831
|
+
properties: {
|
|
832
|
+
objective: { type: 'string', description: 'Sprint objective' },
|
|
833
|
+
priorities: { type: 'array', items: { type: 'string' }, description: 'Business priorities' },
|
|
834
|
+
constraints: { type: 'array', items: { type: 'string' }, description: 'Things not to touch' },
|
|
835
|
+
},
|
|
836
|
+
required: ['objective'],
|
|
837
|
+
},
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
name: 'deferred_queue',
|
|
841
|
+
description: 'Shows the deferred action queue — things detected but not implemented in current cycle. Auto-populated by the decision engine.',
|
|
842
|
+
inputSchema: { type: 'object', properties: { flush: { type: 'boolean' } }, required: [] },
|
|
843
|
+
},
|
|
844
|
+
];
|
|
845
|
+
|
|
846
|
+
async function handleAutonomousTool(name, args={}) {
|
|
847
|
+
const m = require(path.join(ROOT, '.agentic/grafo/autonomous-decision.cjs'));
|
|
848
|
+
switch(name) {
|
|
849
|
+
case 'autonomous_decide':
|
|
850
|
+
return m.analyze({
|
|
851
|
+
files: args.files || [],
|
|
852
|
+
task: args.task || '',
|
|
853
|
+
errorSignatures: args.error_signatures || [],
|
|
854
|
+
projectRoot: ROOT,
|
|
855
|
+
});
|
|
856
|
+
case 'autonomous_sprint':
|
|
857
|
+
return m.planSprint({
|
|
858
|
+
objective: args.objective || '',
|
|
859
|
+
priorities: args.priorities || [],
|
|
860
|
+
constraints: args.constraints || [],
|
|
861
|
+
}, ROOT);
|
|
862
|
+
case 'deferred_queue':
|
|
863
|
+
return args.flush ? m.flushDeferredQueue(ROOT) : m.loadDeferredQueue(ROOT);
|
|
864
|
+
default: return { error: 'Unknown autonomous tool' };
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
TOOLS.push(...TOOLS_AUTONOMOUS);
|
|
869
|
+
TOOLS_AUTONOMOUS.forEach(t => { TOOL_MAP[t.name] = { ...t, handler: (args) => handleAutonomousTool(t.name, args) }; });
|
|
870
|
+
process.stderr.write('[Agentic KDD MCP] +3 autonomous tools (autonomous_decide, autonomous_sprint, deferred_queue)\n');
|
|
871
|
+
|
|
872
|
+
// ─── v3.4: kdd-memory + knowledge-validator + telemetry MCP TOOLS ────────────
|
|
873
|
+
const TOOLS_V34 = [
|
|
874
|
+
{ name: 'recall', description: 'Ranked memory retrieval. BM25+vector hybrid. Use instead of reading errores.md/patrones.md directly. Returns top-K relevant entries by relevance score.', inputSchema: { type:'object', properties: { query:{type:'string'}, top_k:{type:'number'}, tipo:{type:'string'}, area:{type:'string'} }, required:['query'] } },
|
|
875
|
+
{ name: 'remember', description: 'Write to memory with validation. Checks for duplicates, computes hash_contexto, adds frontmatter. Use at end of every cycle.', inputSchema: { type:'object', properties: { entry:{type:'string'}, tipo:{type:'string'}, area:{type:'string'}, confianza:{type:'string'}, archivos:{type:'array',items:{type:'string'}} }, required:['entry'] } },
|
|
876
|
+
{ name: 'validate_knowledge', description: 'Check if a memory entry is still valid before applying it. Returns: trusted, status (ACTIVO/SOSPECHOSO/OBSOLETO), recommendation.', inputSchema: { type:'object', properties: { node_id:{type:'string'} }, required:['node_id'] } },
|
|
877
|
+
{ name: 'memory_scan', description: 'Scan all memory for stale/obsolete/poisoned entries. Run periodically or before a major feature.', inputSchema: { type:'object', properties:{}, required:[] } },
|
|
878
|
+
{ name: 'telemetry_view', description: 'View execution trace for a cycle. Essential for L4 auditing.', inputSchema: { type:'object', properties:{ trace_id:{type:'string'} }, required:[] } },
|
|
879
|
+
{ name: 'telemetry_summary', description: 'Summary of all telemetry: total spans, STOPs, recalls, remembers.', inputSchema: { type:'object', properties:{}, required:[] } },
|
|
880
|
+
];
|
|
881
|
+
|
|
882
|
+
async function handleV34Tool(name, args={}) {
|
|
883
|
+
const ROOT2 = ROOT || process.cwd();
|
|
884
|
+
switch(name) {
|
|
885
|
+
case 'recall': {
|
|
886
|
+
const m = require(path.join(ROOT2, '.agentic/grafo/kdd-memory.cjs'));
|
|
887
|
+
return m.recall(args.query, { topK: args.top_k||10, tipo:args.tipo, area:args.area }, ROOT2);
|
|
888
|
+
}
|
|
889
|
+
case 'remember': {
|
|
890
|
+
const m = require(path.join(ROOT2, '.agentic/grafo/kdd-memory.cjs'));
|
|
891
|
+
return m.remember(args.entry, { tipo:args.tipo||'patron', area:args.area||'global', confianza:args.confianza||'BAJA', archivos:args.archivos||[] }, ROOT2);
|
|
892
|
+
}
|
|
893
|
+
case 'validate_knowledge': {
|
|
894
|
+
const m = require(path.join(ROOT2, '.agentic/grafo/knowledge-validator.cjs'));
|
|
895
|
+
return m.validateKnowledge(args.node_id, ROOT2);
|
|
896
|
+
}
|
|
897
|
+
case 'memory_scan': {
|
|
898
|
+
const m = require(path.join(ROOT2, '.agentic/grafo/knowledge-validator.cjs'));
|
|
899
|
+
return m.scanAll(ROOT2);
|
|
900
|
+
}
|
|
901
|
+
case 'telemetry_view': {
|
|
902
|
+
const m = require(path.join(ROOT2, '.agentic/grafo/telemetry.cjs'));
|
|
903
|
+
return m.viewTrace(args.trace_id, ROOT2);
|
|
904
|
+
}
|
|
905
|
+
case 'telemetry_summary': {
|
|
906
|
+
const m = require(path.join(ROOT2, '.agentic/grafo/telemetry.cjs'));
|
|
907
|
+
return m.getSummary(ROOT2);
|
|
908
|
+
}
|
|
909
|
+
default: return { error: 'Unknown v34 tool' };
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
TOOLS.push(...TOOLS_V34);
|
|
914
|
+
TOOLS_V34.forEach(t => { TOOL_MAP[t.name] = { ...t, handler: (args) => handleV34Tool(t.name, args) }; });
|
|
915
|
+
process.stderr.write('[Agentic KDD MCP] +6 v3.4 tools (recall, remember, validate_knowledge, memory_scan, telemetry_view, telemetry_summary)\n');
|
|
916
|
+
|
|
917
|
+
// ─── v3.5: PATTERN DETECTION + FILE RISK MCP TOOLS ──────────────────────────
|
|
918
|
+
const TOOLS_V35 = [
|
|
919
|
+
{
|
|
920
|
+
name: 'detect_patterns',
|
|
921
|
+
description: 'Detects if the same error/bug pattern exists in other modules. Returns list of findings with AUTO_FIX or WARN action per module based on file risk level and memory history.',
|
|
922
|
+
inputSchema: {
|
|
923
|
+
type: 'object',
|
|
924
|
+
properties: {
|
|
925
|
+
error_signatures: { type: 'array', items: { type: 'string' }, description: 'Error signatures to look for across modules' },
|
|
926
|
+
current_files: { type: 'array', items: { type: 'string' }, description: 'Files currently being modified' },
|
|
927
|
+
},
|
|
928
|
+
required: ['error_signatures'],
|
|
929
|
+
},
|
|
930
|
+
},
|
|
931
|
+
{
|
|
932
|
+
name: 'prerequisite_check',
|
|
933
|
+
description: 'Given pattern findings, determines which must be fixed BEFORE the current task and which can wait until after.',
|
|
934
|
+
inputSchema: {
|
|
935
|
+
type: 'object',
|
|
936
|
+
properties: {
|
|
937
|
+
findings: { type: 'array', description: 'Output from detect_patterns' },
|
|
938
|
+
current_files: { type: 'array', items: { type: 'string' } },
|
|
939
|
+
},
|
|
940
|
+
required: ['findings', 'current_files'],
|
|
941
|
+
},
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
name: 'classify_file_risk',
|
|
945
|
+
description: 'Returns CRITICAL/SENSITIVE/NORMAL/FREE risk level for a file. Determines if agent can act autonomously or must warn first.',
|
|
946
|
+
inputSchema: {
|
|
947
|
+
type: 'object',
|
|
948
|
+
properties: { file: { type: 'string' } },
|
|
949
|
+
required: ['file'],
|
|
950
|
+
},
|
|
951
|
+
},
|
|
952
|
+
];
|
|
953
|
+
|
|
954
|
+
async function handleV35Tool(name, args={}) {
|
|
955
|
+
const m = require(path.join(ROOT, '.agentic/grafo/autonomous-decision.cjs'));
|
|
956
|
+
switch(name) {
|
|
957
|
+
case 'detect_patterns': {
|
|
958
|
+
const db = getDB();
|
|
959
|
+
return m.detectPatternAcrossModules(db, args.error_signatures || [], args.current_files || [], ROOT);
|
|
960
|
+
}
|
|
961
|
+
case 'prerequisite_check': {
|
|
962
|
+
const db = getDB();
|
|
963
|
+
return m.prerequisiteCheckFindings(db, args.findings || [], args.current_files || []);
|
|
964
|
+
}
|
|
965
|
+
case 'classify_file_risk':
|
|
966
|
+
return { file: args.file, risk_level: m.classifyFileRisk(args.file, ROOT) };
|
|
967
|
+
default: return { error: 'Unknown v35 tool' };
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
TOOLS.push(...TOOLS_V35);
|
|
972
|
+
TOOLS_V35.forEach(t => { TOOL_MAP[t.name] = { ...t, handler: (args) => handleV35Tool(t.name, args) }; });
|
|
973
|
+
process.stderr.write('[Agentic KDD MCP] +3 v3.5 tools (detect_patterns, prerequisite_check, classify_file_risk)\n');
|