agentic-kdd 3.0.2 → 3.0.3

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 CHANGED
@@ -62,6 +62,13 @@ const HELP = `
62
62
  akdd trail <ciclo_id> Full trail of a specific cycle
63
63
  akdd trail why <f> Why does this file/entity exist?
64
64
 
65
+ Collaborative Mode (Legion):
66
+ akdd collab init Activate collaborative mode — creates shared DB automatically
67
+ akdd collab join <url> <token> Join an existing team's shared memory
68
+ akdd collab push Push your learnings to the team
69
+ akdd collab pull Pull team's latest learnings
70
+ akdd collab status Check collaborative sync status
71
+
65
72
  Intelligence v2.2:
66
73
  akdd git-context Analyze git diff + risk assessment
67
74
  akdd predict Predictive risk patterns from episodic memory
@@ -78,7 +85,6 @@ const HELP = `
78
85
  akdd mcp Auto-configure MCP in all IDEs (recommended)
79
86
  akdd mcp --global Configure MCP globally for all projects
80
87
  akdd mcp status Check MCP configuration status
81
- (manual fallback: imprime el JSON exacto con tu ruta real)
82
88
 
83
89
  akdd --version / akdd --help
84
90
  `;
@@ -99,11 +105,7 @@ function runGrafo(cmd, extra) {
99
105
  function runModule(name, cmd, extra) {
100
106
  const p = path.join(process.cwd(), '.agentic', 'grafo', name);
101
107
  if (!fs.existsSync(p)) { console.log(`\n ${name} not found. Run: akdd update\n`); process.exit(1); }
102
- const fullCmd = [
103
- `node "${p}"`,
104
- cmd || '',
105
- extra || ''
106
- ].join(' ').trim().replace(/\s+/g,' ');
108
+ const fullCmd = [`node "${p}"`, cmd || '', extra || ''].join(' ').trim().replace(/\s+/g,' ');
107
109
  try { execSync(fullCmd, { stdio: 'inherit', cwd: process.cwd() }); }
108
110
  catch(e) { process.exit(e.status || 1); }
109
111
  }
@@ -114,14 +116,14 @@ switch (command) {
114
116
  case 'update': update(); break;
115
117
  case 'analyze': analyze(); break;
116
118
 
117
- // ── v3.0: Health ────────────────────────────────────────────────────────
119
+ // ── v3.0: Health ──────────────────────────────────────────────────────
118
120
  case 'health': {
119
121
  const fixFlag = args.includes('--fix') ? '--fix' : '';
120
122
  runModule('health-check.cjs', fixFlag);
121
123
  break;
122
124
  }
123
125
 
124
- // ── Core memory ────────────────────────────────────────────────────────
126
+ // ── Core memory ───────────────────────────────────────────────────────
125
127
  case 'sync': runGrafo('sync'); break;
126
128
  case 'graph': graph(); break;
127
129
  case 'stats': runGrafo('stats'); break;
@@ -139,7 +141,7 @@ switch (command) {
139
141
  runGrafo('impacto', `"${arg1}"`);
140
142
  break;
141
143
 
142
- // ── v3.0: Memory Audit ─────────────────────────────────────────────────
144
+ // ── v3.0: Memory Audit ────────────────────────────────────────────────
143
145
  case 'audit': runModule('memory-audit.cjs', 'report'); break;
144
146
 
145
147
  case 'forget': {
@@ -150,11 +152,11 @@ switch (command) {
150
152
  break;
151
153
  }
152
154
 
153
- // ── v3.0: AST ──────────────────────────────────────────────────────────
155
+ // ── v3.0: AST ─────────────────────────────────────────────────────────
154
156
  case 'ast': {
155
157
  const sub = arg1 || 'index';
156
158
  const tgt = arg2 || '';
157
- if (sub === 'stats') runModule('ast-indexer.cjs', 'stats');
159
+ if (sub === 'stats') runModule('ast-indexer.cjs', 'stats');
158
160
  else if (sub === 'symbols') {
159
161
  if (!tgt) { console.log('\n Uso: akdd ast symbols <archivo>\n'); break; }
160
162
  runModule('ast-indexer.cjs', 'symbols', `"${tgt}"`);
@@ -174,17 +176,17 @@ switch (command) {
174
176
  runModule('decision-trail.cjs', 'why', `"${arg1}"`);
175
177
  break;
176
178
 
177
- // ── v3.0: Specs ────────────────────────────────────────────────────────
179
+ // ── v3.0: Specs ───────────────────────────────────────────────────────
178
180
  case 'spec': {
179
181
  const sub = arg1;
180
182
  const mod = arg2;
181
- if (!sub || sub === 'list') runModule('spec-manager.cjs', 'list');
183
+ if (!sub || sub === 'list') runModule('spec-manager.cjs', 'list');
182
184
  else if (sub === 'create') {
183
185
  if (!mod) { console.log('\n Uso: akdd spec create <módulo> [--bugfix]\n'); break; }
184
186
  runModule('spec-manager.cjs', 'create', `"${mod}"${args.includes('--bugfix') ? ' --bugfix' : ''}`);
185
187
  }
186
- else if (sub === 'waves') { if (!mod) { console.log('\n Uso: akdd spec waves <módulo>\n'); break; } runModule('spec-manager.cjs', 'waves', `"${mod}"`); }
187
- else if (sub === 'validate') { if (!mod) { console.log('\n Uso: akdd spec validate <módulo>\n'); break; } runModule('spec-manager.cjs', 'validate', `"${mod}"`); }
188
+ else if (sub === 'waves') { if (!mod) { console.log('\n Uso: akdd spec waves <módulo>\n'); break; } runModule('spec-manager.cjs', 'waves', `"${mod}"`); }
189
+ else if (sub === 'validate') { if (!mod) { console.log('\n Uso: akdd spec validate <módulo>\n'); break; } runModule('spec-manager.cjs', 'validate', `"${mod}"`); }
188
190
  else runModule('spec-manager.cjs', 'status', `"${sub}"`);
189
191
  break;
190
192
  }
@@ -194,7 +196,7 @@ switch (command) {
194
196
  runModule('spec-manager.cjs', 'create', `"${arg1}"${args.includes('--bugfix') ? ' --bugfix' : ''}`);
195
197
  break;
196
198
 
197
- // ── v3.0: Knowledge ────────────────────────────────────────────────────
199
+ // ── v3.0: Knowledge ───────────────────────────────────────────────────
198
200
  case 'adr':
199
201
  runModule('adr-ingestor.cjs', 'ingest', arg1 || 'docs/adr');
200
202
  break;
@@ -203,24 +205,45 @@ switch (command) {
203
205
  runModule('knowledge-ingestor.cjs', 'ingest', arg1 || '');
204
206
  break;
205
207
 
206
- // ── v3.0: Metrics ──────────────────────────────────────────────────────
208
+ // ── v3.0: Metrics ─────────────────────────────────────────────────────
207
209
  case 'metrics':
208
210
  runModule('metrics.cjs', arg1 || 'summary');
209
211
  break;
210
212
 
211
- // ── v3.0: Decision Trail ───────────────────────────────────────────────
213
+ // ── v3.0: Decision Trail ──────────────────────────────────────────────
212
214
  case 'trail': {
213
- if (!arg1) runModule('decision-trail.cjs', 'recent', '5');
214
- else if (arg1 === 'why') { if (!arg2) { console.log('\n Uso: akdd trail why <entidad>\n'); break; } runModule('decision-trail.cjs', 'why', `"${arg2}"`); }
215
- else if (arg1 === 'timeline'){ if (!arg2) { console.log('\n Uso: akdd trail timeline <módulo>\n'); break; } runModule('decision-trail.cjs', 'timeline', `"${arg2}"`); }
216
- else runModule('decision-trail.cjs', 'ciclo', `"${arg1}"`);
215
+ if (!arg1) runModule('decision-trail.cjs', 'recent', '5');
216
+ else if (arg1 === 'why') { if (!arg2) { console.log('\n Uso: akdd trail why <entidad>\n'); break; } runModule('decision-trail.cjs', 'why', `"${arg2}"`); }
217
+ else if (arg1 === 'timeline') { if (!arg2) { console.log('\n Uso: akdd trail timeline <módulo>\n'); break; } runModule('decision-trail.cjs', 'timeline', `"${arg2}"`); }
218
+ else runModule('decision-trail.cjs', 'ciclo', `"${arg1}"`);
217
219
  break;
218
220
  }
219
221
 
220
- // ── Dashboard ──────────────────────────────────────────────────────────
222
+ // ── v3.0: Collaborative Mode (Legion) ────────────────────────────────
223
+ case 'collab': {
224
+ const sub = arg1 || 'status';
225
+ if (sub === 'init') {
226
+ runModule('collab-manager.cjs', 'init');
227
+ } else if (sub === 'join') {
228
+ if (!arg2 || !args[3]) {
229
+ console.log('\n Uso: akdd collab join <url> <token>\n');
230
+ break;
231
+ }
232
+ runModule('collab-manager.cjs', 'join', `"${arg2}" "${args[3]}"`);
233
+ } else if (sub === 'push') {
234
+ runModule('collab-manager.cjs', 'push');
235
+ } else if (sub === 'pull') {
236
+ runModule('collab-manager.cjs', 'pull');
237
+ } else {
238
+ runModule('collab-manager.cjs', 'status');
239
+ }
240
+ break;
241
+ }
242
+
243
+ // ── Dashboard ─────────────────────────────────────────────────────────
221
244
  case 'dashboard': dashboard(); break;
222
245
 
223
- // ── v2.2: Intelligence ─────────────────────────────────────────────────
246
+ // ── v2.2: Intelligence ────────────────────────────────────────────────
224
247
  case 'git-context': runGrafo('git-context', args.includes('--install-hook') ? '--install-hook' : ''); break;
225
248
  case 'predict': runGrafo('predict'); break;
226
249
  case 'embed-status': runGrafo('embed-status'); break;
@@ -245,16 +268,12 @@ switch (command) {
245
268
  break;
246
269
  }
247
270
 
248
-
249
- // ── v3.0: MCP Setup ────────────────────────────────────────────────────
271
+ // ── v3.0: MCP Setup ───────────────────────────────────────────────────
250
272
  case 'mcp': {
251
273
  const sub = arg1;
252
274
  const opts = { global: args.includes('--global') };
253
- if (sub === 'status') {
254
- mcpStatus(process.cwd());
255
- } else {
256
- mcpSetup(process.cwd(), opts);
257
- }
275
+ if (sub === 'status') mcpStatus(process.cwd());
276
+ else mcpSetup(process.cwd(), opts);
258
277
  break;
259
278
  }
260
279
 
@@ -0,0 +1,403 @@
1
+ /**
2
+ * Agentic KDD — Collab Manager v2.0
3
+ * Modo colaborativo automático via Turso + Cloudflare Worker.
4
+ *
5
+ * El usuario solo corre: akdd collab init
6
+ * El sistema crea la DB en Turso automáticamente.
7
+ * El usuario nunca sabe que Turso existe.
8
+ *
9
+ * Uso:
10
+ * node .agentic/grafo/collab-manager.cjs init
11
+ * node .agentic/grafo/collab-manager.cjs push
12
+ * node .agentic/grafo/collab-manager.cjs pull
13
+ * node .agentic/grafo/collab-manager.cjs status
14
+ * node .agentic/grafo/collab-manager.cjs join <url> <token>
15
+ */
16
+
17
+ 'use strict';
18
+
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+ const os = require('os');
22
+ const { execSync } = require('child_process');
23
+
24
+ // URL de tu Cloudflare Worker — actualizar después de deploy
25
+ const PROVISIONER_URL = 'https://agentic-collab.adrianlpz-game.workers.dev';
26
+
27
+ const COLLAB_CONFIG_PATH = '.agentic/collab.json';
28
+
29
+ const SYNC_TABLES = [
30
+ 'nodos',
31
+ 'relaciones_semanticas',
32
+ 'episodios',
33
+ 'knowledge_docs',
34
+ 'ast_symbols',
35
+ 'ast_edges',
36
+ ];
37
+
38
+ // ─── DB LOCAL ──────────────────────────────────────────────────────────────────
39
+
40
+ function openLocalDB(projectRoot) {
41
+ const dbPath = path.join(projectRoot, '.agentic/memoria.db');
42
+ try { return new (require('better-sqlite3'))(dbPath); } catch {}
43
+ try { const { DatabaseSync } = require('node:sqlite'); return new DatabaseSync(dbPath); } catch {}
44
+ throw new Error('No SQLite driver disponible');
45
+ }
46
+
47
+ // ─── CONFIG ───────────────────────────────────────────────────────────────────
48
+
49
+ function loadConfig(projectRoot) {
50
+ const configPath = path.join(projectRoot, COLLAB_CONFIG_PATH);
51
+ if (!fs.existsSync(configPath)) return null;
52
+ try { return JSON.parse(fs.readFileSync(configPath, 'utf8')); } catch { return null; }
53
+ }
54
+
55
+ function saveConfig(projectRoot, config) {
56
+ const configPath = path.join(projectRoot, COLLAB_CONFIG_PATH);
57
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
58
+
59
+ // Asegurar que collab.json está en .gitignore
60
+ const gitignorePath = path.join(projectRoot, '.gitignore');
61
+ if (fs.existsSync(gitignorePath)) {
62
+ const gi = fs.readFileSync(gitignorePath, 'utf8');
63
+ if (!gi.includes('collab.json')) {
64
+ fs.appendFileSync(gitignorePath, '\n# Agentic KDD collab credentials\n.agentic/collab.json\n');
65
+ }
66
+ }
67
+ }
68
+
69
+ // ─── GENERAR PROJECT ID ───────────────────────────────────────────────────────
70
+
71
+ function getProjectId(projectRoot) {
72
+ // Usar el nombre del directorio + un hash corto para que sea único y legible
73
+ const dirName = path.basename(projectRoot).toLowerCase().replace(/[^a-z0-9]/g, '-');
74
+ const hash = require('crypto')
75
+ .createHash('md5')
76
+ .update(projectRoot)
77
+ .digest('hex')
78
+ .substring(0, 6);
79
+ return `${dirName}-${hash}`;
80
+ }
81
+
82
+ // ─── INIT — PROVISIONAR DB AUTOMÁTICAMENTE ───────────────────────────────────
83
+
84
+ async function collabInit(projectRoot) {
85
+ console.log('\n[COLLAB] Activando modo colaborativo...\n');
86
+
87
+ // Verificar si ya está configurado
88
+ const existing = loadConfig(projectRoot);
89
+ if (existing?.enabled && existing?.url) {
90
+ console.log('[COLLAB] Ya configurado. URL:', existing.url);
91
+ console.log('[COLLAB] Para re-configurar: borrar .agentic/collab.json y correr de nuevo.');
92
+ return existing;
93
+ }
94
+
95
+ const projectId = getProjectId(projectRoot);
96
+ console.log(`[COLLAB] Project ID: ${projectId}`);
97
+ console.log('[COLLAB] Creando base de datos compartida...');
98
+
99
+ // Llamar al Cloudflare Worker para provisionar la DB
100
+ let provisionResult;
101
+ try {
102
+ const response = await fetch(PROVISIONER_URL, {
103
+ method: 'POST',
104
+ headers: { 'Content-Type': 'application/json' },
105
+ body: JSON.stringify({ projectId }),
106
+ });
107
+
108
+ if (!response.ok) {
109
+ const err = await response.text();
110
+ throw new Error(`Provisioner error: ${err}`);
111
+ }
112
+
113
+ provisionResult = await response.json();
114
+ } catch (e) {
115
+ console.error('[COLLAB] Error conectando con el servidor de provisión:', e.message);
116
+ console.error('[COLLAB] Verificar que el Cloudflare Worker está activo.');
117
+ process.exit(1);
118
+ }
119
+
120
+ if (!provisionResult.ok) {
121
+ console.error('[COLLAB] Error creando DB:', provisionResult.error);
122
+ process.exit(1);
123
+ }
124
+
125
+ // Guardar credenciales localmente
126
+ const config = {
127
+ enabled: true,
128
+ url: provisionResult.url,
129
+ token: provisionResult.token,
130
+ db: provisionResult.db,
131
+ project_id: projectId,
132
+ member_id: os.userInfo().username,
133
+ sync_on_cycle_end: true,
134
+ last_sync: null,
135
+ created_at: new Date().toISOString(),
136
+ };
137
+
138
+ saveConfig(projectRoot, config);
139
+
140
+ console.log('\n[COLLAB] ✅ Modo colaborativo activado.');
141
+ console.log(`[COLLAB] DB: ${provisionResult.db}`);
142
+ console.log('[COLLAB] Credenciales guardadas en .agentic/collab.json (gitignored)');
143
+ console.log('\n[COLLAB] Para que otros miembros del equipo se unan:');
144
+ console.log(` Compárteles: URL y token de .agentic/collab.json`);
145
+ console.log(` Ellos corren: akdd collab join <url> <token>\n`);
146
+
147
+ // Primer push
148
+ console.log('[COLLAB] Sincronizando memoria local → compartida...');
149
+ await syncUp(projectRoot);
150
+
151
+ return config;
152
+ }
153
+
154
+ // ─── JOIN — PARA EL DEV QUE SE UNE AL EQUIPO ─────────────────────────────────
155
+
156
+ async function collabJoin(projectRoot, url, token) {
157
+ console.log('\n[COLLAB] Uniéndose al equipo...\n');
158
+
159
+ const config = {
160
+ enabled: true,
161
+ url,
162
+ token,
163
+ member_id: os.userInfo().username,
164
+ sync_on_cycle_end: true,
165
+ last_sync: null,
166
+ joined_at: new Date().toISOString(),
167
+ };
168
+
169
+ saveConfig(projectRoot, config);
170
+
171
+ console.log('[COLLAB] ✅ Conectado al equipo.');
172
+ console.log('[COLLAB] Descargando memoria del equipo...');
173
+
174
+ await syncDown(projectRoot);
175
+
176
+ console.log('[COLLAB] ✅ Listo. Ya tienes toda la memoria del equipo.\n');
177
+ }
178
+
179
+ // ─── SYNC UP (local → Turso) ──────────────────────────────────────────────────
180
+
181
+ async function syncUp(projectRoot) {
182
+ const config = loadConfig(projectRoot);
183
+ if (!config?.enabled) {
184
+ console.log('[COLLAB] Modo colaborativo no activado. Correr: akdd collab init');
185
+ return { synced: false };
186
+ }
187
+
188
+ let client;
189
+ try {
190
+ const { createClient } = require('@libsql/client');
191
+ client = createClient({ url: config.url, authToken: config.token });
192
+ } catch {
193
+ console.log('[COLLAB] @libsql/client no instalado. Correr: npm install @libsql/client');
194
+ return { synced: false };
195
+ }
196
+
197
+ const localDB = openLocalDB(projectRoot);
198
+ const lastSync = config.last_sync || '1970-01-01T00:00:00.000Z';
199
+ let totalRows = 0;
200
+
201
+ // Schema push — crear tablas en remoto si no existen
202
+ await pushSchema(client, localDB);
203
+
204
+ for (const table of SYNC_TABLES) {
205
+ try {
206
+ // Solo filas nuevas/modificadas desde el último sync
207
+ const dateField = getDateField(table);
208
+ const rows = localDB.prepare(
209
+ `SELECT * FROM ${table} WHERE ${dateField} > ? LIMIT 500`
210
+ ).all(lastSync);
211
+
212
+ if (rows.length === 0) continue;
213
+
214
+ console.log(`[COLLAB] ${table}: ${rows.length} filas a sincronizar`);
215
+
216
+ for (const row of rows) {
217
+ const keys = Object.keys(row);
218
+ const vals = Object.values(row);
219
+ const placeholders = keys.map(() => '?').join(', ');
220
+ try {
221
+ await client.execute({
222
+ sql: `INSERT OR REPLACE INTO ${table} (${keys.join(', ')}) VALUES (${placeholders})`,
223
+ args: vals,
224
+ });
225
+ totalRows++;
226
+ } catch {}
227
+ }
228
+ } catch {}
229
+ }
230
+
231
+ // Actualizar last_sync
232
+ config.last_sync = new Date().toISOString();
233
+ saveConfig(projectRoot, config);
234
+
235
+ console.log(`[COLLAB] ✅ Sync up: ${totalRows} filas enviadas.`);
236
+ return { synced: true, rows: totalRows };
237
+ }
238
+
239
+ // ─── SYNC DOWN (Turso → local) ────────────────────────────────────────────────
240
+
241
+ async function syncDown(projectRoot) {
242
+ const config = loadConfig(projectRoot);
243
+ if (!config?.enabled) return { synced: false };
244
+
245
+ let client;
246
+ try {
247
+ const { createClient } = require('@libsql/client');
248
+ client = createClient({ url: config.url, authToken: config.token });
249
+ } catch {
250
+ console.log('[COLLAB] @libsql/client no instalado. Correr: npm install @libsql/client');
251
+ return { synced: false };
252
+ }
253
+
254
+ const localDB = openLocalDB(projectRoot);
255
+ let totalRows = 0;
256
+
257
+ for (const table of SYNC_TABLES) {
258
+ try {
259
+ const dateField = getDateField(table);
260
+ const lastSync = config.last_sync || '1970-01-01T00:00:00.000Z';
261
+
262
+ const rs = await client.execute(
263
+ `SELECT * FROM ${table} WHERE ${dateField} > ? LIMIT 1000`,
264
+ [lastSync]
265
+ );
266
+
267
+ if (!rs.rows?.length) continue;
268
+
269
+ console.log(`[COLLAB] ${table}: recibiendo ${rs.rows.length} filas`);
270
+
271
+ for (const row of rs.rows) {
272
+ const keys = Object.keys(row);
273
+ const vals = keys.map(k => row[k]);
274
+ const placeholders = keys.map(() => '?').join(', ');
275
+
276
+ // Estrategia por tabla:
277
+ // episodios → INSERT OR IGNORE (son aditivos, no sobrescribir locales)
278
+ // resto → INSERT OR REPLACE (toma la versión más reciente)
279
+ const strategy = table === 'episodios' ? 'OR IGNORE' : 'OR REPLACE';
280
+
281
+ try {
282
+ localDB.prepare(
283
+ `INSERT ${strategy} INTO ${table} (${keys.join(', ')}) VALUES (${placeholders})`
284
+ ).run(vals);
285
+ totalRows++;
286
+ } catch {}
287
+ }
288
+ } catch {}
289
+ }
290
+
291
+ // Actualizar last_sync
292
+ config.last_sync = new Date().toISOString();
293
+ saveConfig(projectRoot, config);
294
+
295
+ console.log(`[COLLAB] ✅ Sync down: ${totalRows} filas recibidas.`);
296
+ return { synced: true, rows: totalRows };
297
+ }
298
+
299
+ // ─── SCHEMA PUSH ──────────────────────────────────────────────────────────────
300
+ // Crea las tablas en la DB remota si no existen (primera vez)
301
+
302
+ async function pushSchema(client, localDB) {
303
+ const tables = localDB.prepare(
304
+ "SELECT name, sql FROM sqlite_master WHERE type='table' AND sql IS NOT NULL"
305
+ ).all();
306
+
307
+ for (const table of tables) {
308
+ if (!SYNC_TABLES.includes(table.name)) continue;
309
+ try {
310
+ await client.execute(
311
+ table.sql.replace('CREATE TABLE', 'CREATE TABLE IF NOT EXISTS')
312
+ );
313
+ } catch {}
314
+ }
315
+ }
316
+
317
+ // ─── STATUS ───────────────────────────────────────────────────────────────────
318
+
319
+ async function status(projectRoot) {
320
+ const config = loadConfig(projectRoot);
321
+
322
+ console.log('\n[COLLAB] Estado del modo colaborativo:\n');
323
+
324
+ if (!config?.enabled) {
325
+ console.log(' ❌ No activado.');
326
+ console.log(' Correr: akdd collab init\n');
327
+ return;
328
+ }
329
+
330
+ console.log(` ✅ Activado`);
331
+ console.log(` DB: ${config.db || config.url}`);
332
+ console.log(` Miembro: ${config.member_id}`);
333
+ console.log(` Último sync: ${config.last_sync || 'nunca'}`);
334
+ console.log(` Auto-sync: ${config.sync_on_cycle_end ? 'sí (al final de cada aa:)' : 'no'}`);
335
+
336
+ // Test de conexión
337
+ try {
338
+ const { createClient } = require('@libsql/client');
339
+ const client = createClient({ url: config.url, authToken: config.token });
340
+ await client.execute('SELECT 1');
341
+ console.log(' Conexión: ✅ OK\n');
342
+ } catch {
343
+ console.log(' Conexión: ❌ Error — verificar credenciales\n');
344
+ }
345
+ }
346
+
347
+ // ─── HELPER ───────────────────────────────────────────────────────────────────
348
+
349
+ function getDateField(table) {
350
+ const fields = {
351
+ nodos: 'fecha_update',
352
+ episodios: 'fecha',
353
+ relaciones_semanticas: 'valid_at',
354
+ knowledge_docs: 'last_indexed',
355
+ ast_symbols: 'last_indexed',
356
+ ast_edges: 'last_indexed',
357
+ };
358
+ return fields[table] || 'rowid';
359
+ }
360
+
361
+ // ─── CLI ──────────────────────────────────────────────────────────────────────
362
+
363
+ if (require.main === module) {
364
+ const [,, cmd, arg1, arg2] = process.argv;
365
+ const projectRoot = process.cwd();
366
+
367
+ switch (cmd) {
368
+ case 'init':
369
+ collabInit(projectRoot).catch(console.error);
370
+ break;
371
+ case 'join':
372
+ if (!arg1 || !arg2) {
373
+ console.error('Uso: collab-manager.cjs join <url> <token>');
374
+ process.exit(1);
375
+ }
376
+ collabJoin(projectRoot, arg1, arg2).catch(console.error);
377
+ break;
378
+ case 'push':
379
+ syncUp(projectRoot).then(r => {
380
+ process.exit(r.synced ? 0 : 1);
381
+ }).catch(console.error);
382
+ break;
383
+ case 'pull':
384
+ syncDown(projectRoot).then(r => {
385
+ process.exit(r.synced ? 0 : 1);
386
+ }).catch(console.error);
387
+ break;
388
+ case 'status':
389
+ status(projectRoot).catch(console.error);
390
+ break;
391
+ default:
392
+ console.log('Uso: node collab-manager.cjs [init | join <url> <token> | push | pull | status]');
393
+ }
394
+ }
395
+
396
+ module.exports = {
397
+ collabInit,
398
+ collabJoin,
399
+ syncUp,
400
+ syncDown,
401
+ status,
402
+ loadConfig,
403
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentic-kdd",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
4
4
  "description": "Autonomous development pipeline — aa: · ag: · audit: · AST graph · Harness · Specs · Impact analysis · Decision trail · Metrics · MCP server. Works with Cursor and Claude Code.",
5
5
  "main": "src/index.js",
6
6
  "bin": {