agentic-kdd 3.0.4 → 3.2.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.
@@ -0,0 +1,425 @@
1
+ /**
2
+ * Agentic KDD — llms.txt Generator v1.0
3
+ *
4
+ * Genera automáticamente:
5
+ * .agentic/llms.txt — mapa estructural mínimo para agentes externos
6
+ * .agentic/llms-full.txt — versión expandida con todas las reglas vigentes
7
+ * .agentic/knowledge-graph.json — grafo causal serializado para Git versioning
8
+ *
9
+ * ¿Qué resuelve?
10
+ * Gap: "Discoverability" — agentes externos no saben qué hay en Agentic KDD sin indexar todo
11
+ * Solución: llms.txt es el estándar emergente (equiv a robots.txt pero para LLMs)
12
+ *
13
+ * Gap: "Grafo descentralizado" — el reporte pide que el grafo viaje en el repo vía Git
14
+ * Solución: knowledge-graph.json en .agentic/ → versión del grafo junto al código
15
+ *
16
+ * Gap: "Progressive disclosure" — developer nuevo no sabe por dónde empezar
17
+ * Solución: llms.txt actúa como mapa de onboarding estructurado
18
+ *
19
+ * Se ejecuta automáticamente en: akdd sync, akdd update
20
+ * También se puede correr manualmente: node llms-generator.cjs
21
+ *
22
+ * Uso:
23
+ * node .agentic/grafo/llms-generator.cjs generate
24
+ * node .agentic/grafo/llms-generator.cjs graph
25
+ * node .agentic/grafo/llms-generator.cjs all
26
+ */
27
+
28
+ 'use strict';
29
+
30
+ const path = require('path');
31
+ const fs = require('fs');
32
+
33
+ // ─── DB HELPER ────────────────────────────────────────────────────────────────
34
+
35
+ function openDB(projectRoot) {
36
+ const dbPath = path.join(projectRoot, '.agentic/memoria.db');
37
+ try { return new (require('better-sqlite3'))(dbPath); } catch {}
38
+ try { const { DatabaseSync } = require('node:sqlite'); return new DatabaseSync(dbPath); } catch {}
39
+ return null; // Si no hay DB, generar desde config.md
40
+ }
41
+
42
+ // ─── LEER CONFIG DEL PROYECTO ────────────────────────────────────────────────
43
+
44
+ function readProjectConfig(projectRoot) {
45
+ const configPath = path.join(projectRoot, '.agentic', 'config.md');
46
+ if (!fs.existsSync(configPath)) return {};
47
+
48
+ const content = fs.readFileSync(configPath, 'utf8');
49
+ const config = {};
50
+
51
+ // Extraer campos clave del config.md
52
+ const extractField = (key) => {
53
+ const match = content.match(new RegExp(`${key}:\\s*(.+)`));
54
+ return match ? match[1].trim() : null;
55
+ };
56
+
57
+ config.proyecto = extractField('PROYECTO');
58
+ config.stack = extractField('STACK');
59
+ config.descripcion= extractField('DESCRIPCIÓN') || extractField('DESCRIPCION');
60
+ config.modulos = [];
61
+
62
+ // Extraer módulos listados
63
+ const modulosMatch = content.match(/MÓDULOS[^\n]*\n([\s\S]*?)(?=\n##|\n\*\*|$)/i);
64
+ if (modulosMatch) {
65
+ config.modulos = modulosMatch[1]
66
+ .split('\n')
67
+ .map(l => l.replace(/^[-*\s]+/, '').trim())
68
+ .filter(Boolean)
69
+ .slice(0, 20);
70
+ }
71
+
72
+ return config;
73
+ }
74
+
75
+ // ─── GENERAR llms.txt ─────────────────────────────────────────────────────────
76
+ /**
77
+ * llms.txt: formato estándar emergente para que LLMs se orienten en un proyecto.
78
+ * Minimalista. Agentes externos lo leen antes de explorar el codebase.
79
+ */
80
+ function generateLlmsTxt(projectRoot, db) {
81
+ const config = readProjectConfig(projectRoot);
82
+
83
+ const lines = [];
84
+ const now = new Date().toISOString().split('T')[0];
85
+
86
+ lines.push(`# ${config.proyecto || path.basename(projectRoot)}`);
87
+ lines.push('');
88
+ if (config.descripcion) {
89
+ lines.push(`> ${config.descripcion}`);
90
+ lines.push('');
91
+ }
92
+ lines.push(`> Agentic KDD v3.2 — Knowledge-Driven Development`);
93
+ lines.push(`> Generated: ${now}`);
94
+ lines.push('');
95
+
96
+ // Stack
97
+ if (config.stack) {
98
+ lines.push('## Stack');
99
+ lines.push('');
100
+ config.stack.split(/[,/]/).map(s => s.trim()).filter(Boolean).forEach(s => {
101
+ lines.push(`- ${s}`);
102
+ });
103
+ lines.push('');
104
+ }
105
+
106
+ // Módulos del proyecto
107
+ if (db) {
108
+ try {
109
+ const entities = db.prepare(`
110
+ SELECT nombre, tipo, descripcion, area
111
+ FROM entidades WHERE tipo IN ('modulo','archivo','api','tabla')
112
+ ORDER BY tipo, nombre LIMIT 30
113
+ `).all();
114
+
115
+ if (entities.length > 0) {
116
+ lines.push('## Architecture');
117
+ lines.push('');
118
+ const byType = {};
119
+ entities.forEach(e => {
120
+ if (!byType[e.tipo]) byType[e.tipo] = [];
121
+ byType[e.tipo].push(e);
122
+ });
123
+ Object.entries(byType).forEach(([tipo, ents]) => {
124
+ lines.push(`### ${tipo.charAt(0).toUpperCase() + tipo.slice(1)}s`);
125
+ ents.slice(0, 10).forEach(e => {
126
+ lines.push(`- **${e.nombre}**: ${e.descripcion || e.area || tipo}`);
127
+ });
128
+ lines.push('');
129
+ });
130
+ }
131
+ } catch {}
132
+ } else if (config.modulos?.length > 0) {
133
+ lines.push('## Modules');
134
+ lines.push('');
135
+ config.modulos.forEach(m => lines.push(`- ${m}`));
136
+ lines.push('');
137
+ }
138
+
139
+ // Reglas vigentes HIGH
140
+ if (db) {
141
+ try {
142
+ const rules = db.prepare(`
143
+ SELECT titulo, area, tipo
144
+ FROM nodos
145
+ WHERE confianza = 'ALTA'
146
+ AND estado = 'ACTIVO'
147
+ AND (vigencia_tipo = 'VIGENTE' OR vigencia_tipo IS NULL)
148
+ ORDER BY aplicado DESC LIMIT 15
149
+ `).all();
150
+
151
+ if (rules.length > 0) {
152
+ lines.push('## Key Rules (HIGH confidence)');
153
+ lines.push('');
154
+ rules.forEach(r => {
155
+ lines.push(`- [${r.tipo}] ${r.titulo} (${r.area || 'global'})`);
156
+ });
157
+ lines.push('');
158
+ }
159
+ } catch {}
160
+ }
161
+
162
+ // ADRs activos
163
+ if (db) {
164
+ try {
165
+ const adrs = db.prepare(`
166
+ SELECT titulo, decision, status FROM knowledge_docs
167
+ WHERE status = 'accepted' LIMIT 10
168
+ `).all();
169
+
170
+ if (adrs.length > 0) {
171
+ lines.push('## Architecture Decisions');
172
+ lines.push('');
173
+ adrs.forEach(a => {
174
+ lines.push(`- **${a.titulo}**: ${a.decision?.substring(0, 80) || ''}`);
175
+ });
176
+ lines.push('');
177
+ }
178
+ } catch {}
179
+ }
180
+
181
+ // Errores frecuentes (memoria causal)
182
+ if (db) {
183
+ try {
184
+ const errors = db.prepare(`
185
+ SELECT titulo FROM nodos
186
+ WHERE tipo = 'error'
187
+ AND confianza IN ('ALTA','MEDIA')
188
+ AND estado = 'ACTIVO'
189
+ ORDER BY aplicado DESC LIMIT 10
190
+ `).all();
191
+
192
+ if (errors.length > 0) {
193
+ lines.push('## Known Pitfalls');
194
+ lines.push('');
195
+ errors.forEach(e => lines.push(`- ${e.titulo}`));
196
+ lines.push('');
197
+ }
198
+ } catch {}
199
+ }
200
+
201
+ // Footer
202
+ lines.push('## Agentic KDD Tools');
203
+ lines.push('');
204
+ lines.push('This project uses Agentic KDD for persistent AI memory. Available MCP tools:');
205
+ lines.push('- `grafo_buscar` — hybrid search across 4 CoALA memory layers');
206
+ lines.push('- `ast_impact` — pre-change impact analysis');
207
+ lines.push('- `knowledge_query` — query ADRs and gotchas');
208
+ lines.push('- `verdad_vigente` — currently valid rules only');
209
+ lines.push('- `decision_trail` — decision observability');
210
+ lines.push('- `health_check` — full system diagnostic');
211
+ lines.push('');
212
+ lines.push('Run `akdd health` to verify system state before working.');
213
+ lines.push('');
214
+
215
+ return lines.join('\n');
216
+ }
217
+
218
+ // ─── GENERAR llms-full.txt ────────────────────────────────────────────────────
219
+ /**
220
+ * Versión expandida con TODO el conocimiento vigente del proyecto.
221
+ * Para agentes que necesitan contexto completo antes de empezar.
222
+ */
223
+ function generateLlmsFullTxt(projectRoot, db) {
224
+ if (!db) return null;
225
+
226
+ const lines = [];
227
+ const minimal = generateLlmsTxt(projectRoot, db);
228
+ lines.push(minimal);
229
+
230
+ lines.push('---');
231
+ lines.push('## Full Knowledge Base');
232
+ lines.push('');
233
+
234
+ // Todos los patrones ALTA y MEDIA vigentes
235
+ try {
236
+ const patterns = db.prepare(`
237
+ SELECT titulo, contenido, tipo, area, aplicado, util
238
+ FROM nodos
239
+ WHERE estado = 'ACTIVO'
240
+ AND confianza IN ('ALTA', 'MEDIA')
241
+ AND (vigencia_tipo = 'VIGENTE' OR vigencia_tipo IS NULL)
242
+ ORDER BY confianza DESC, aplicado DESC
243
+ LIMIT 50
244
+ `).all();
245
+
246
+ if (patterns.length > 0) {
247
+ lines.push('### All Active Patterns');
248
+ lines.push('');
249
+ patterns.forEach(p => {
250
+ lines.push(`#### [${p.tipo}] ${p.titulo} (${p.area || 'global'})`);
251
+ if (p.contenido) lines.push(p.contenido.substring(0, 300));
252
+ lines.push(`*Applied: ${p.aplicado || 0}× | Useful: ${p.util || 0}×*`);
253
+ lines.push('');
254
+ });
255
+ }
256
+ } catch {}
257
+
258
+ // Causal edges activos
259
+ try {
260
+ const edges = db.prepare(`
261
+ SELECT desde_entidad, tipo, hacia_entidad, descripcion
262
+ FROM relaciones_semanticas
263
+ WHERE tipo IN ('caused_failure','was_fixed_by','tested_by','regressed_by')
264
+ AND (invalid_at IS NULL OR invalid_at = '')
265
+ ORDER BY valid_at DESC LIMIT 30
266
+ `).all();
267
+
268
+ if (edges.length > 0) {
269
+ lines.push('### Causal Memory');
270
+ lines.push('');
271
+ edges.forEach(e => {
272
+ lines.push(`- ${e.desde_entidad} --${e.tipo}--> ${e.hacia_entidad}`);
273
+ if (e.descripcion) lines.push(` *${e.descripcion.substring(0, 100)}*`);
274
+ });
275
+ lines.push('');
276
+ }
277
+ } catch {}
278
+
279
+ return lines.join('\n');
280
+ }
281
+
282
+ // ─── GENERAR knowledge-graph.json ────────────────────────────────────────────
283
+ /**
284
+ * Grafo causal serializado para Git versioning.
285
+ * Viaja con el repo → el equipo comparte el grafo sin infraestructura externa.
286
+ * Inspirado en Graphify y Understand Anything.
287
+ */
288
+ function generateKnowledgeGraph(projectRoot, db) {
289
+ if (!db) return null;
290
+
291
+ const graph = {
292
+ version: '3.2',
293
+ generated: new Date().toISOString(),
294
+ project: path.basename(projectRoot),
295
+ nodes: [],
296
+ edges: [],
297
+ decisions: [],
298
+ stats: {},
299
+ };
300
+
301
+ // Nodos procedurales vigentes
302
+ try {
303
+ graph.nodes = db.prepare(`
304
+ SELECT id, tipo, titulo, area, confianza, aplicado, util,
305
+ decay_score, vigencia_tipo, fecha_creacion
306
+ FROM nodos
307
+ WHERE estado = 'ACTIVO'
308
+ AND (vigencia_tipo = 'VIGENTE' OR vigencia_tipo IS NULL)
309
+ AND confianza IN ('ALTA', 'MEDIA')
310
+ ORDER BY confianza DESC, aplicado DESC
311
+ LIMIT 200
312
+ `).all();
313
+ } catch {}
314
+
315
+ // Edges causales activos
316
+ try {
317
+ graph.edges = db.prepare(`
318
+ SELECT desde_entidad, tipo, hacia_entidad, descripcion, confidence, valid_at
319
+ FROM relaciones_semanticas
320
+ WHERE tipo IN ('caused_failure','was_fixed_by','tested_by','regressed_by','depends_on_decision')
321
+ AND (invalid_at IS NULL OR invalid_at = '')
322
+ ORDER BY valid_at DESC LIMIT 300
323
+ `).all();
324
+ } catch {}
325
+
326
+ // ADRs
327
+ try {
328
+ graph.decisions = db.prepare(`
329
+ SELECT doc_id, titulo, decision, status, afecta, fecha_indexado
330
+ FROM knowledge_docs
331
+ WHERE status = 'accepted'
332
+ LIMIT 50
333
+ `).all();
334
+ } catch {}
335
+
336
+ // Stats
337
+ graph.stats = {
338
+ total_nodes: graph.nodes.length,
339
+ total_edges: graph.edges.length,
340
+ total_decisions: graph.decisions.length,
341
+ high_confidence: graph.nodes.filter(n => n.confianza === 'ALTA').length,
342
+ };
343
+
344
+ return graph;
345
+ }
346
+
347
+ // ─── GENERAR TODO ─────────────────────────────────────────────────────────────
348
+
349
+ function generateAll(projectRoot) {
350
+ projectRoot = projectRoot || process.cwd();
351
+ const db = openDB(projectRoot);
352
+
353
+ const results = { llms_txt: false, llms_full: false, knowledge_graph: false };
354
+
355
+ // 1. llms.txt
356
+ try {
357
+ const content = generateLlmsTxt(projectRoot, db);
358
+ fs.writeFileSync(path.join(projectRoot, '.agentic', 'llms.txt'), content);
359
+ results.llms_txt = true;
360
+ console.log('[LLMS] ✅ .agentic/llms.txt generado');
361
+ } catch (e) {
362
+ console.error('[LLMS] Error llms.txt:', e.message);
363
+ }
364
+
365
+ // 2. llms-full.txt
366
+ if (db) {
367
+ try {
368
+ const content = generateLlmsFullTxt(projectRoot, db);
369
+ if (content) {
370
+ fs.writeFileSync(path.join(projectRoot, '.agentic', 'llms-full.txt'), content);
371
+ results.llms_full = true;
372
+ console.log('[LLMS] ✅ .agentic/llms-full.txt generado');
373
+ }
374
+ } catch (e) {
375
+ console.error('[LLMS] Error llms-full.txt:', e.message);
376
+ }
377
+ }
378
+
379
+ // 3. knowledge-graph.json
380
+ if (db) {
381
+ try {
382
+ const graph = generateKnowledgeGraph(projectRoot, db);
383
+ if (graph) {
384
+ fs.writeFileSync(
385
+ path.join(projectRoot, '.agentic', 'knowledge-graph.json'),
386
+ JSON.stringify(graph, null, 2)
387
+ );
388
+ results.knowledge_graph = true;
389
+ console.log(`[LLMS] ✅ .agentic/knowledge-graph.json generado (${graph.stats.total_nodes} nodos, ${graph.stats.total_edges} edges)`);
390
+ }
391
+ } catch (e) {
392
+ console.error('[LLMS] Error knowledge-graph.json:', e.message);
393
+ }
394
+ }
395
+
396
+ return results;
397
+ }
398
+
399
+ // ─── CLI ──────────────────────────────────────────────────────────────────────
400
+
401
+ if (require.main === module) {
402
+ const [,, cmd] = process.argv;
403
+ const projectRoot = process.cwd();
404
+
405
+ switch (cmd) {
406
+ case 'generate':
407
+ const db = openDB(projectRoot);
408
+ const content = generateLlmsTxt(projectRoot, db);
409
+ fs.writeFileSync(path.join(projectRoot, '.agentic', 'llms.txt'), content);
410
+ console.log('✅ .agentic/llms.txt generado');
411
+ break;
412
+ case 'graph':
413
+ const db2 = openDB(projectRoot);
414
+ if (!db2) { console.error('DB no disponible'); break; }
415
+ const graph = generateKnowledgeGraph(projectRoot, db2);
416
+ fs.writeFileSync(path.join(projectRoot, '.agentic', 'knowledge-graph.json'), JSON.stringify(graph, null, 2));
417
+ console.log(`✅ knowledge-graph.json: ${graph.stats.total_nodes} nodos, ${graph.stats.total_edges} edges`);
418
+ break;
419
+ case 'all':
420
+ default:
421
+ generateAll(projectRoot);
422
+ }
423
+ }
424
+
425
+ module.exports = { generateLlmsTxt, generateLlmsFullTxt, generateKnowledgeGraph, generateAll };