agentic-kdd 3.1.1 → 3.2.2
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/bin/akdd.js +47 -0
- package/contract-guard.cjs +851 -0
- package/creative-engine.cjs +560 -0
- package/package.json +1 -1
- package/session-guard.cjs +265 -0
- package/src/dashboard-template.cjs +292 -27
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agentic KDD — Session Guard v1.0
|
|
3
|
+
*
|
|
4
|
+
* Problema que resuelve:
|
|
5
|
+
* - Cursor se cierra y pierdes el hilo
|
|
6
|
+
* - Cambias de PC y empiezas chat nuevo
|
|
7
|
+
* - No recuerdas en qué ibas exactamente
|
|
8
|
+
*
|
|
9
|
+
* Solución:
|
|
10
|
+
* - Cada 5 ciclos aa: guarda un checkpoint en .agentic/checkpoint.md
|
|
11
|
+
* - akdd historial muestra el checkpoint listo para pegar en el chat nuevo
|
|
12
|
+
* - El chat nuevo recupera el contexto exacto de donde se quedó
|
|
13
|
+
*
|
|
14
|
+
* Uso:
|
|
15
|
+
* node session-guard.cjs checkpoint — genera checkpoint ahora
|
|
16
|
+
* node session-guard.cjs historial — muestra el último checkpoint
|
|
17
|
+
* node session-guard.cjs status — cuántos ciclos hasta el próximo checkpoint
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
'use strict';
|
|
21
|
+
|
|
22
|
+
const path = require('path');
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
|
|
25
|
+
const CHECKPOINT_EVERY = 5;
|
|
26
|
+
const CHECKPOINT_PATH = '.agentic/checkpoint.md';
|
|
27
|
+
const COUNTER_KEY = 'session_guard_cycle_count';
|
|
28
|
+
|
|
29
|
+
// ─── DB ───────────────────────────────────────────────────────────────────────
|
|
30
|
+
|
|
31
|
+
function openDB(projectRoot) {
|
|
32
|
+
const dbPath = path.join(projectRoot, '.agentic/memoria.db');
|
|
33
|
+
try { return new (require('better-sqlite3'))(dbPath); } catch {}
|
|
34
|
+
try { const { DatabaseSync } = require('node:sqlite'); return new DatabaseSync(dbPath); } catch {}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ─── LEER CICLOS RECIENTES ────────────────────────────────────────────────────
|
|
39
|
+
|
|
40
|
+
function getRecentCycles(db, limit = 5) {
|
|
41
|
+
try {
|
|
42
|
+
return db.prepare(`
|
|
43
|
+
SELECT ciclo_id, descripcion, tipo, estado, fecha_inicio, fecha_fin,
|
|
44
|
+
tests_corridos, patrones_aplicados, errores_encontrados, fases_completadas
|
|
45
|
+
FROM ciclos
|
|
46
|
+
ORDER BY fecha_inicio DESC
|
|
47
|
+
LIMIT ?
|
|
48
|
+
`).all(limit);
|
|
49
|
+
} catch { return []; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function getProjectStats(db) {
|
|
53
|
+
try {
|
|
54
|
+
const nodes = db.prepare("SELECT COUNT(*) as n FROM nodos WHERE estado='ACTIVO'").get()?.n || 0;
|
|
55
|
+
const high = db.prepare("SELECT COUNT(*) as n FROM nodos WHERE confianza='ALTA' AND estado='ACTIVO'").get()?.n || 0;
|
|
56
|
+
const cycles = db.prepare("SELECT COUNT(*) as n FROM ciclos").get()?.n || 0;
|
|
57
|
+
const stops = db.prepare("SELECT COUNT(*) as n FROM ciclos WHERE estado='STOP'").get()?.n || 0;
|
|
58
|
+
const errors = db.prepare("SELECT COUNT(*) as n FROM nodos WHERE tipo='error' AND estado='ACTIVO'").get()?.n || 0;
|
|
59
|
+
return { nodes, high, cycles, stops, errors };
|
|
60
|
+
} catch { return { nodes: 0, high: 0, cycles: 0, stops: 0, errors: 0 }; }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function getLastModifiedFiles(db, cicloId) {
|
|
64
|
+
try {
|
|
65
|
+
const trail = db.prepare(`
|
|
66
|
+
SELECT descripcion FROM decisiones
|
|
67
|
+
WHERE ciclo_id = ?
|
|
68
|
+
AND (descripcion LIKE '%.ts%' OR descripcion LIKE '%.js%'
|
|
69
|
+
OR descripcion LIKE '%.tsx%' OR descripcion LIKE '%.jsx%'
|
|
70
|
+
OR descripcion LIKE '%.py%')
|
|
71
|
+
LIMIT 5
|
|
72
|
+
`).all(cicloId);
|
|
73
|
+
return trail.map(t => t.descripcion?.substring(0, 60)).filter(Boolean);
|
|
74
|
+
} catch { return []; }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ─── GENERAR CHECKPOINT ───────────────────────────────────────────────────────
|
|
78
|
+
|
|
79
|
+
function generateCheckpoint(projectRoot) {
|
|
80
|
+
projectRoot = projectRoot || process.cwd();
|
|
81
|
+
const db = openDB(projectRoot);
|
|
82
|
+
if (!db) return null;
|
|
83
|
+
|
|
84
|
+
const cycles = getRecentCycles(db, 5);
|
|
85
|
+
const stats = getProjectStats(db);
|
|
86
|
+
const now = new Date();
|
|
87
|
+
const dateStr = now.toLocaleDateString('es-ES', { day:'2-digit', month:'2-digit', year:'numeric' });
|
|
88
|
+
const timeStr = now.toTimeString().substring(0, 5);
|
|
89
|
+
|
|
90
|
+
if (cycles.length === 0) {
|
|
91
|
+
db.close();
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const latest = cycles[0];
|
|
96
|
+
const prev = cycles.slice(1);
|
|
97
|
+
|
|
98
|
+
// Parsear fases completadas del último ciclo
|
|
99
|
+
let fasesInfo = '';
|
|
100
|
+
try {
|
|
101
|
+
const fases = JSON.parse(latest.fases_completadas || '[]');
|
|
102
|
+
if (fases.length > 0) fasesInfo = ` — ${fases.length} fases completadas`;
|
|
103
|
+
} catch {}
|
|
104
|
+
|
|
105
|
+
// Parsear patrones del último ciclo
|
|
106
|
+
let patronesInfo = '';
|
|
107
|
+
try {
|
|
108
|
+
const pats = JSON.parse(latest.patrones_aplicados || '[]');
|
|
109
|
+
if (pats.length > 0) patronesInfo = `, ${pats.length} patrones aplicados`;
|
|
110
|
+
} catch {}
|
|
111
|
+
|
|
112
|
+
// Archivos del último ciclo
|
|
113
|
+
const files = getLastModifiedFiles(db, latest.ciclo_id);
|
|
114
|
+
const filesStr = files.length > 0 ? `\nArchivos: ${files.join(', ')}` : '';
|
|
115
|
+
|
|
116
|
+
// Construir checkpoint
|
|
117
|
+
const lines = [
|
|
118
|
+
`# Checkpoint Agentic KDD — ${dateStr} ${timeStr}`,
|
|
119
|
+
'',
|
|
120
|
+
`> Proyecto: ${path.basename(projectRoot)}`,
|
|
121
|
+
`> Ciclos totales: ${stats.cycles}`,
|
|
122
|
+
'',
|
|
123
|
+
'---',
|
|
124
|
+
'',
|
|
125
|
+
`## Última tarea (ciclo ${stats.cycles})`,
|
|
126
|
+
`**${latest.descripcion || 'Sin descripción'}**`,
|
|
127
|
+
`Estado: ${latest.estado || 'completado'}${fasesInfo}${patronesInfo}${filesStr}`,
|
|
128
|
+
'',
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
if (prev.length > 0) {
|
|
132
|
+
lines.push('## Las anteriores');
|
|
133
|
+
prev.forEach((c, i) => {
|
|
134
|
+
const fecha = c.fecha_inicio ? new Date(c.fecha_inicio).toLocaleDateString('es-ES', {day:'2-digit', month:'2-digit'}) : '';
|
|
135
|
+
lines.push(`${i + 1}. ${fecha ? `[${fecha}] ` : ''}${c.descripcion?.substring(0, 80) || 'Sin descripción'}`);
|
|
136
|
+
});
|
|
137
|
+
lines.push('');
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
lines.push('## Estado del proyecto');
|
|
141
|
+
lines.push(`- ${stats.nodes} nodos en memoria · ${stats.high} reglas HIGH`);
|
|
142
|
+
lines.push(`- ${stats.cycles} ciclos completados · ${stats.stops} stops`);
|
|
143
|
+
lines.push(`- ${stats.errors} errores documentados`);
|
|
144
|
+
lines.push('');
|
|
145
|
+
lines.push('## Para retomar en un chat nuevo');
|
|
146
|
+
lines.push('```');
|
|
147
|
+
lines.push('akdd historial');
|
|
148
|
+
lines.push('```');
|
|
149
|
+
lines.push('Pega el output al inicio del nuevo chat y escribe:');
|
|
150
|
+
lines.push('```');
|
|
151
|
+
lines.push(`aa: continúa — ${latest.descripcion?.substring(0, 60) || 'la última tarea'}`);
|
|
152
|
+
lines.push('```');
|
|
153
|
+
lines.push('');
|
|
154
|
+
lines.push(`---`);
|
|
155
|
+
lines.push(`*Generado automáticamente por Session Guard · ${dateStr} ${timeStr}*`);
|
|
156
|
+
|
|
157
|
+
const checkpointContent = lines.join('\n');
|
|
158
|
+
const checkpointPath = path.join(projectRoot, CHECKPOINT_PATH);
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
fs.writeFileSync(checkpointPath, checkpointContent);
|
|
162
|
+
} catch {}
|
|
163
|
+
|
|
164
|
+
db.close();
|
|
165
|
+
return checkpointContent;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ─── MOSTRAR HISTORIAL (para pegar en chat nuevo) ─────────────────────────────
|
|
169
|
+
|
|
170
|
+
function showHistorial(projectRoot) {
|
|
171
|
+
projectRoot = projectRoot || process.cwd();
|
|
172
|
+
const checkpointPath = path.join(projectRoot, CHECKPOINT_PATH);
|
|
173
|
+
|
|
174
|
+
if (!fs.existsSync(checkpointPath)) {
|
|
175
|
+
// Generar uno ahora si no existe
|
|
176
|
+
const generated = generateCheckpoint(projectRoot);
|
|
177
|
+
if (!generated) {
|
|
178
|
+
console.log('\n[SESSION] Sin historial todavía — corre ciclos aa: primero.\n');
|
|
179
|
+
return null;
|
|
180
|
+
}
|
|
181
|
+
return generated;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const content = fs.readFileSync(checkpointPath, 'utf8');
|
|
185
|
+
|
|
186
|
+
console.log('\n' + '═'.repeat(60));
|
|
187
|
+
console.log(' 📋 HISTORIAL — Pegar al inicio del chat nuevo');
|
|
188
|
+
console.log('═'.repeat(60));
|
|
189
|
+
console.log('\n' + content);
|
|
190
|
+
console.log('═'.repeat(60));
|
|
191
|
+
console.log('\n Copia todo lo de arriba y pégalo en el nuevo chat.\n');
|
|
192
|
+
|
|
193
|
+
return content;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ─── CHECK Y AUTO-CHECKPOINT ──────────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Llamar al final de cada ciclo desde grafo.cjs.
|
|
200
|
+
* Genera checkpoint cada CHECKPOINT_EVERY ciclos.
|
|
201
|
+
*/
|
|
202
|
+
function maybeCheckpoint(projectRoot, currentCycleCount) {
|
|
203
|
+
if (currentCycleCount % CHECKPOINT_EVERY === 0) {
|
|
204
|
+
generateCheckpoint(projectRoot);
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// ─── STATUS ───────────────────────────────────────────────────────────────────
|
|
211
|
+
|
|
212
|
+
function getStatus(projectRoot) {
|
|
213
|
+
projectRoot = projectRoot || process.cwd();
|
|
214
|
+
const db = openDB(projectRoot);
|
|
215
|
+
if (!db) return { cycles: 0, next_checkpoint: CHECKPOINT_EVERY };
|
|
216
|
+
|
|
217
|
+
const cycles = db.prepare("SELECT COUNT(*) as n FROM ciclos").get()?.n || 0;
|
|
218
|
+
db.close();
|
|
219
|
+
|
|
220
|
+
const remaining = CHECKPOINT_EVERY - (cycles % CHECKPOINT_EVERY);
|
|
221
|
+
const checkpointExists = fs.existsSync(path.join(projectRoot, CHECKPOINT_PATH));
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
cycles,
|
|
225
|
+
checkpoint_every: CHECKPOINT_EVERY,
|
|
226
|
+
cycles_until_next: remaining === CHECKPOINT_EVERY ? 0 : remaining,
|
|
227
|
+
last_checkpoint: checkpointExists
|
|
228
|
+
? fs.statSync(path.join(projectRoot, CHECKPOINT_PATH)).mtime.toLocaleDateString('es-ES')
|
|
229
|
+
: 'nunca',
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ─── CLI ──────────────────────────────────────────────────────────────────────
|
|
234
|
+
|
|
235
|
+
if (require.main === module) {
|
|
236
|
+
const [,, cmd] = process.argv;
|
|
237
|
+
const projectRoot = process.cwd();
|
|
238
|
+
|
|
239
|
+
switch (cmd) {
|
|
240
|
+
case 'checkpoint':
|
|
241
|
+
const c = generateCheckpoint(projectRoot);
|
|
242
|
+
if (c) console.log(`\n✅ Checkpoint guardado en ${CHECKPOINT_PATH}\n`);
|
|
243
|
+
else console.log('\n❌ Sin ciclos para guardar todavía.\n');
|
|
244
|
+
break;
|
|
245
|
+
|
|
246
|
+
case 'historial':
|
|
247
|
+
showHistorial(projectRoot);
|
|
248
|
+
break;
|
|
249
|
+
|
|
250
|
+
case 'status': {
|
|
251
|
+
const s = getStatus(projectRoot);
|
|
252
|
+
console.log(`\nSession Guard Status:`);
|
|
253
|
+
console.log(` Ciclos totales: ${s.cycles}`);
|
|
254
|
+
console.log(` Checkpoint cada: ${s.checkpoint_every} ciclos`);
|
|
255
|
+
console.log(` Ciclos hasta próximo: ${s.cycles_until_next || CHECKPOINT_EVERY}`);
|
|
256
|
+
console.log(` Último checkpoint: ${s.last_checkpoint}\n`);
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
default:
|
|
261
|
+
console.log('Uso: node session-guard.cjs [checkpoint | historial | status]');
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
module.exports = { generateCheckpoint, showHistorial, maybeCheckpoint, getStatus };
|