agentic-kdd 2.2.13 → 3.0.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 CHANGED
@@ -1,14 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- const { init } = require('../src/init');
5
- const { update } = require('../src/update');
6
- const { graph } = require('../src/graph');
4
+ const { init } = require('../src/init');
5
+ const { update } = require('../src/update');
6
+ const { graph } = require('../src/graph');
7
7
  const { dashboard } = require('../src/dashboard');
8
- const { analyze } = require('../src/analyze');
9
- const pkg = require('../package.json');
8
+ const { analyze } = require('../src/analyze');
9
+ const { mcpSetup, mcpStatus } = require('../src/mcp-setup');
10
+ const pkg = require('../package.json');
10
11
  const path = require('path');
11
- const fs = require('fs');
12
+ const fs = require('fs');
12
13
  const { execSync } = require('child_process');
13
14
 
14
15
  const args = process.argv.slice(2);
@@ -18,92 +19,115 @@ const arg2 = args[2];
18
19
 
19
20
  const HELP = `
20
21
  Agentic KDD v${pkg.version}
21
- Autonomous development pipeline with Knowledge-Driven Development
22
+ Autonomous development pipeline one developer, full-department output.
22
23
 
23
- Usage:
24
+ Setup:
24
25
  akdd init Install Agentic KDD in the current project
25
26
  akdd update Update agents + engine (memory stays intact)
26
- akdd analyze Analyze project code and auto-build knowledge graph
27
+ akdd health System health check what's configured, what's missing
28
+ akdd health --fix Auto-fix common issues
29
+
30
+ Memory & Knowledge:
27
31
  akdd sync Sync memory files to SQLite graph
28
- akdd graph Sync memory + show graph stats
32
+ akdd graph Sync + show graph stats
29
33
  akdd stats Show graph stats and HIGH rules
30
- akdd coala Show CoALA memory stats (procedural + episodic + semantic)
31
- akdd metricas Show agent KPIs (Goal Attainment, Autonomy, etc.)
32
- akdd buscar Hybrid search across all 3 memory layers
33
- akdd impacto Show impact of touching a module/file
34
+ akdd coala Show CoALA memory stats (4 layers)
35
+ akdd buscar Hybrid search across all memory layers
36
+ akdd impacto Semantic impact of a module/entity
34
37
  akdd decay Apply temporal decay to stale patterns
35
- akdd dashboard Open visual dashboard in browser
38
+ akdd audit Memory audit stale entries, contradictions, proposals
39
+ akdd forget <id> Forget a memory entry with documented reason
40
+
41
+ AST & Impact Analysis:
42
+ akdd ast Index project AST (symbols, imports, call graph, PageRank)
43
+ akdd ast stats Show AST index stats
44
+ akdd ast symbols <f> Show symbols in a file
45
+ akdd ast-impact <f> Full impact analysis of a file/module
46
+ akdd why <entity> Explain why something exists (causal chain)
47
+
48
+ Specs & Autonomy:
49
+ akdd spec list List all module specs
50
+ akdd spec <module> Show spec status + next wave
51
+ akdd spec create <m> Create feature spec for a module
52
+ akdd spec create <m> --bugfix Create bugfix spec
53
+
54
+ Knowledge Base:
55
+ akdd adr Ingest ADRs from docs/adr/
56
+ akdd knowledge Ingest gotchas/conventions from docs/
57
+
58
+ Metrics & Observability:
59
+ akdd metrics Project KPIs — success rate, rework, autonomy score
60
+ akdd metrics trend Show trend of last 10 cycles
61
+ akdd trail Recent decision trails (what changed and why)
62
+ akdd trail <ciclo_id> Full trail of a specific cycle
63
+ akdd trail why <f> Why does this file/entity exist?
36
64
 
37
65
  Intelligence v2.2:
38
- akdd git-context Analyze git diff + risk assessment from episodic memory
39
- akdd predict Show predictive patterns detected from episodic memory
40
- akdd embed-status Check local embeddings status (all-MiniLM-L6-v2)
41
- akdd embed-install Install local embeddings (~23MB, 100% offline)
42
- akdd ci-install Install GitHub Actions workflow for auto CI/CD memory
43
- akdd ci-status Show last CI/CD reports stored in memory
44
- akdd ci-report Report CI result to memory (called by CI workflow)
45
-
46
- akdd --version Show version
47
- akdd --help Show this help
48
-
49
- After init, open the project in Cursor or Claude Code and type:
50
- aa: [your task]
66
+ akdd git-context Analyze git diff + risk assessment
67
+ akdd predict Predictive risk patterns from episodic memory
68
+ akdd embed-status Local embeddings status
69
+ akdd embed-install Install local embeddings (~23MB, offline)
70
+ akdd jina-install Install jina-v2-code embeddings (~500MB, code-optimized)
71
+ akdd ci-install Install GitHub Actions CI/CD workflow
72
+ akdd ci-status Show last CI/CD reports
73
+
74
+ Dashboard:
75
+ akdd dashboard Open visual dashboard in browser
76
+
77
+ MCP Setup (Cursor / Claude Code / VS Code):
78
+ akdd mcp Auto-configure MCP in all IDEs (recommended)
79
+ akdd mcp --global Configure MCP globally for all projects
80
+ akdd mcp status Check MCP configuration status
81
+ (manual fallback: imprime el JSON exacto con tu ruta real)
82
+
83
+ akdd --version / akdd --help
51
84
  `;
52
85
 
53
86
  function findGrafo() {
54
87
  const p = path.join(process.cwd(), '.agentic', 'grafo', 'grafo.cjs');
55
- if (!fs.existsSync(p)) {
56
- console.log('\n grafo.cjs not found. Run: akdd update\n');
57
- process.exit(1);
58
- }
88
+ if (!fs.existsSync(p)) { console.log('\n grafo.cjs not found. Run: akdd update\n'); process.exit(1); }
59
89
  return p;
60
90
  }
61
91
 
62
92
  function runGrafo(cmd, extra) {
63
93
  const grafo = findGrafo();
64
- try {
65
- execSync(`node "${grafo}" ${cmd}${extra ? ' ' + extra : ''}`, {
66
- stdio: 'inherit', cwd: process.cwd()
67
- });
68
- } catch(e) { process.exit(1); }
94
+ const fullCmd = extra ? `node "${grafo}" ${cmd} ${extra}` : `node "${grafo}" ${cmd}`;
95
+ try { execSync(fullCmd, { stdio: 'inherit', cwd: process.cwd() }); }
96
+ catch(e) { process.exit(e.status || 1); }
69
97
  }
70
98
 
71
- function runGrafoPipe(cmd, extra) {
72
- const grafo = findGrafo();
73
- try {
74
- return execSync(`node "${grafo}" ${cmd}${extra ? ' ' + extra : ''}`, {
75
- stdio: 'pipe', cwd: process.cwd()
76
- }).toString();
77
- } catch(e) { return ''; }
99
+ function runModule(name, cmd, extra) {
100
+ const p = path.join(process.cwd(), '.agentic', 'grafo', name);
101
+ 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,' ');
107
+ try { execSync(fullCmd, { stdio: 'inherit', cwd: process.cwd() }); }
108
+ catch(e) { process.exit(e.status || 1); }
78
109
  }
79
110
 
80
111
  switch (command) {
81
112
 
82
- // ── Comandos existentes ─────────────────────────────────────────────────────
83
- case 'init':
84
- init(); break;
85
-
86
- case 'update':
87
- update(); break;
88
-
89
- case 'analyze':
90
- case 'analizar':
91
- analyze(); break;
113
+ case 'init': init(); break;
114
+ case 'update': update(); break;
115
+ case 'analyze': analyze(); break;
92
116
 
93
- case 'graph':
94
- graph(); break;
95
-
96
- case 'sync':
97
- runGrafo('sync'); break;
98
-
99
- case 'stats':
100
- runGrafo('stats'); break;
101
-
102
- case 'coala':
103
- runGrafo('coala'); break;
117
+ // ── v3.0: Health ────────────────────────────────────────────────────────
118
+ case 'health': {
119
+ const fixFlag = args.includes('--fix') ? '--fix' : '';
120
+ runModule('health-check.cjs', fixFlag);
121
+ break;
122
+ }
104
123
 
105
- case 'metricas':
106
- runGrafo('metricas'); break;
124
+ // ── Core memory ────────────────────────────────────────────────────────
125
+ case 'sync': runGrafo('sync'); break;
126
+ case 'graph': graph(); break;
127
+ case 'stats': runGrafo('stats'); break;
128
+ case 'coala': runGrafo('coala'); break;
129
+ case 'metricas': runGrafo('metricas'); break;
130
+ case 'decay': runGrafo('decay'); break;
107
131
 
108
132
  case 'buscar':
109
133
  if (!arg1) { console.log('\n Uso: akdd buscar "query" [area]\n'); break; }
@@ -115,81 +139,130 @@ switch (command) {
115
139
  runGrafo('impacto', `"${arg1}"`);
116
140
  break;
117
141
 
118
- case 'decay':
119
- runGrafo('decay'); break;
142
+ // ── v3.0: Memory Audit ─────────────────────────────────────────────────
143
+ case 'audit': runModule('memory-audit.cjs', 'report'); break;
120
144
 
121
- case 'dashboard':
122
- dashboard(); break;
123
-
124
- // ── v2.2: Intelligence features ────────────────────────────────────────────
145
+ case 'forget': {
146
+ if (!arg1) { console.log('\n Uso: akdd forget <id> "<razón>"\n'); break; }
147
+ const reason = args.slice(2).join(' ');
148
+ if (!reason) { console.log('\n Uso: akdd forget <id> "<razón>"\n'); break; }
149
+ runModule('memory-audit.cjs', 'forget', `${arg1} "${reason}"`);
150
+ break;
151
+ }
125
152
 
126
- case 'git-context': {
127
- if (args.includes('--install-hook')) {
128
- runGrafo('git-context', '--install-hook');
129
- break;
153
+ // ── v3.0: AST ──────────────────────────────────────────────────────────
154
+ case 'ast': {
155
+ const sub = arg1 || 'index';
156
+ const tgt = arg2 || '';
157
+ if (sub === 'stats') runModule('ast-indexer.cjs', 'stats');
158
+ else if (sub === 'symbols') {
159
+ if (!tgt) { console.log('\n Uso: akdd ast symbols <archivo>\n'); break; }
160
+ runModule('ast-indexer.cjs', 'symbols', `"${tgt}"`);
161
+ } else {
162
+ runModule('ast-indexer.cjs', 'index', tgt);
130
163
  }
131
- runGrafo('git-context');
132
164
  break;
133
165
  }
134
166
 
135
- case 'predict': {
136
- runGrafo('predict');
167
+ case 'ast-impact':
168
+ if (!arg1) { console.log('\n Uso: akdd ast-impact <archivo_o_módulo>\n'); break; }
169
+ runModule('impact-analyzer.cjs', 'analyze', `"${arg1}"`);
137
170
  break;
138
- }
139
171
 
140
- case 'embed-status': {
141
- runGrafo('embed-status');
172
+ case 'why':
173
+ if (!arg1) { console.log('\n Uso: akdd why <archivo_o_entidad>\n'); break; }
174
+ runModule('decision-trail.cjs', 'why', `"${arg1}"`);
142
175
  break;
143
- }
144
176
 
145
- case 'embed-install': {
146
- runGrafo('embed-install');
177
+ // ── v3.0: Specs ────────────────────────────────────────────────────────
178
+ case 'spec': {
179
+ const sub = arg1;
180
+ const mod = arg2;
181
+ if (!sub || sub === 'list') runModule('spec-manager.cjs', 'list');
182
+ else if (sub === 'create') {
183
+ if (!mod) { console.log('\n Uso: akdd spec create <módulo> [--bugfix]\n'); break; }
184
+ runModule('spec-manager.cjs', 'create', `"${mod}"${args.includes('--bugfix') ? ' --bugfix' : ''}`);
185
+ }
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 runModule('spec-manager.cjs', 'status', `"${sub}"`);
147
189
  break;
148
190
  }
149
191
 
150
- case 'ci-install': {
151
- runGrafo('ci-install');
192
+ case 'spec-create':
193
+ if (!arg1) { console.log('\n Uso: akdd spec-create <módulo> [--bugfix]\n'); break; }
194
+ runModule('spec-manager.cjs', 'create', `"${arg1}"${args.includes('--bugfix') ? ' --bugfix' : ''}`);
195
+ break;
196
+
197
+ // ── v3.0: Knowledge ────────────────────────────────────────────────────
198
+ case 'adr':
199
+ runModule('adr-ingestor.cjs', 'ingest', arg1 || 'docs/adr');
200
+ break;
201
+
202
+ case 'knowledge':
203
+ runModule('knowledge-ingestor.cjs', 'ingest', arg1 || '');
204
+ break;
205
+
206
+ // ── v3.0: Metrics ──────────────────────────────────────────────────────
207
+ case 'metrics':
208
+ runModule('metrics.cjs', arg1 || 'summary');
152
209
  break;
153
- }
154
210
 
155
- case 'ci-status': {
156
- runGrafo('ci-status');
211
+ // ── v3.0: Decision Trail ───────────────────────────────────────────────
212
+ 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}"`);
157
217
  break;
158
218
  }
159
219
 
220
+ // ── Dashboard ──────────────────────────────────────────────────────────
221
+ case 'dashboard': dashboard(); break;
222
+
223
+ // ── v2.2: Intelligence ─────────────────────────────────────────────────
224
+ case 'git-context': runGrafo('git-context', args.includes('--install-hook') ? '--install-hook' : ''); break;
225
+ case 'predict': runGrafo('predict'); break;
226
+ case 'embed-status': runGrafo('embed-status'); break;
227
+ case 'embed-install': runGrafo('embed-install'); break;
228
+
229
+ case 'jina-install':
230
+ runModule('embeddings.cjs', 'install-jina');
231
+ break;
232
+
233
+ case 'ci-install': runGrafo('ci-install'); break;
234
+ case 'ci-status': runGrafo('ci-status'); break;
235
+
160
236
  case 'ci-report': {
161
- // Llamado por GitHub Actions — no interrumpir el CI si falla
162
237
  const grafo = path.join(process.cwd(), '.agentic', 'grafo', 'grafo.cjs');
163
238
  if (!fs.existsSync(grafo)) { process.exit(0); }
239
+ const esExito = args.includes('--success');
240
+ const outIdx = args.indexOf('--output');
241
+ const outFile = outIdx >= 0 ? args[outIdx + 1] : null;
242
+ const flags = [esExito ? '--success' : '', outFile ? `--output "${outFile}"` : ''].filter(Boolean).join(' ');
243
+ try { execSync(`node "${grafo}" ci-report ${flags}`, { stdio: 'inherit', cwd: process.cwd(), timeout: 60000 }); }
244
+ catch(e) { process.exit(0); }
245
+ break;
246
+ }
164
247
 
165
- const esExito = args.includes('--success');
166
- const outputIdx = args.indexOf('--output');
167
- const outputFile = outputIdx >= 0 ? args[outputIdx + 1] : null;
168
-
169
- const flags = [
170
- esExito ? '--success' : '',
171
- outputFile ? `--output "${outputFile}"` : ''
172
- ].filter(Boolean).join(' ');
173
248
 
174
- try {
175
- execSync(`node "${grafo}" ci-report ${flags}`, {
176
- stdio: 'inherit', cwd: process.cwd(), timeout: 60000
177
- });
178
- } catch(e) { process.exit(0); } // no fallar el CI
249
+ // ── v3.0: MCP Setup ────────────────────────────────────────────────────
250
+ case 'mcp': {
251
+ const sub = arg1;
252
+ const opts = { global: args.includes('--global') };
253
+ if (sub === 'status') {
254
+ mcpStatus(process.cwd());
255
+ } else {
256
+ mcpSetup(process.cwd(), opts);
257
+ }
179
258
  break;
180
259
  }
181
260
 
182
- // ── Meta ────────────────────────────────────────────────────────────────────
183
- case '--version':
184
- case '-v':
185
- console.log(pkg.version);
186
- break;
261
+ case '--version': case '-v':
262
+ console.log(pkg.version); break;
187
263
 
188
- case '--help':
189
- case '-h':
190
- case undefined:
191
- console.log(HELP);
192
- break;
264
+ case '--help': case '-h': case undefined:
265
+ console.log(HELP); break;
193
266
 
194
267
  default:
195
268
  console.log(`\n Unknown command: ${command}`);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agentic-kdd",
3
- "version": "2.2.13",
4
- "description": "Autonomous development pipeline with KDD — aa: · ag: · audit: · Git Context · Prediction · Local Embeddings · CI/CD. Works with Cursor and Claude Code.",
3
+ "version": "3.0.2",
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": {
7
7
  "akdd": "bin/akdd.js"
@@ -21,7 +21,12 @@
21
21
  "knowledge-driven",
22
22
  "agentic",
23
23
  "sqlite",
24
- "dashboard"
24
+ "dashboard",
25
+ "mcp",
26
+ "ast",
27
+ "harness",
28
+ "specs",
29
+ "memory"
25
30
  ],
26
31
  "author": "Adrianlpz211",
27
32
  "license": "MIT",
package/src/init.js CHANGED
@@ -1,4 +1,5 @@
1
1
  'use strict';
2
+ const { mcpSetup } = require('./mcp-setup');
2
3
 
3
4
  const fs = require('fs-extra');
4
5
  const path = require('path');
@@ -278,6 +279,14 @@ Estado: Pendiente aa: configurar
278
279
  console.log(chalk.gray(' CLAUDE.md — activa aa: / ag: / audit:'));
279
280
  console.log(chalk.gray(' .cursorrules — reglas para Cursor'));
280
281
 
282
+ // ── CONFIGURAR MCP AUTOMÁTICAMENTE ─────────────────────────────────────────
283
+ console.log(chalk.bold(" Configurando MCP server..."));
284
+ try {
285
+ await mcpSetup(projectPath, { silent: false });
286
+ } catch(e) {
287
+ console.log(chalk.gray(" (MCP: ejecuta akdd mcp para configurarlo manualmente)"));
288
+ }
289
+
281
290
  // Instrucción final
282
291
  console.log('\n' + chalk.dim(' ─────────────────────────────────────────────'));
283
292
  console.log(chalk.bold(' Último paso — abre este proyecto en'));
@@ -0,0 +1,265 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs-extra');
4
+ const path = require('path');
5
+ const os = require('os');
6
+ const { execSync } = require('child_process');
7
+ const chalk = require('chalk');
8
+
9
+ /**
10
+ * akdd mcp — Configura el MCP server automáticamente.
11
+ *
12
+ * Hace todo lo posible sin intervención del usuario:
13
+ * 1. Escribe .cursor/mcp.json en el proyecto (Cursor lo lee automáticamente)
14
+ * 2. Intenta ejecutar `claude mcp add` si el CLI está disponible
15
+ * 3. Imprime el JSON EXACTO (con ruta real del sistema, no placeholder)
16
+ * para los casos que requieran paso manual
17
+ *
18
+ * El usuario NUNCA tiene que adivinar la ruta — este comando la resuelve por él.
19
+ */
20
+
21
+ async function mcpSetup(projectPath, opts = {}) {
22
+ projectPath = projectPath || process.cwd();
23
+
24
+ // ── Verificar que Agentic está instalado ───────────────────────────────────
25
+ const serverFile = path.join(projectPath, '.agentic', 'grafo', 'mcp-server.cjs');
26
+ if (!fs.existsSync(serverFile)) {
27
+ console.log(chalk.yellow('\n mcp-server.cjs no encontrado.'));
28
+ console.log(chalk.gray(' Ejecuta: akdd update\n'));
29
+ return;
30
+ }
31
+
32
+ // ── Resolver ruta absoluta real (sin placeholders, sin adivinar) ───────────
33
+ // path.resolve() → ruta exacta del sistema actual, con nombre de usuario correcto
34
+ const serverPath = path.resolve(serverFile);
35
+ const serverPathJson = serverPath.replace(/\\/g, '\\\\'); // escaping para JSON en Windows
36
+
37
+ console.log('\n' + chalk.bold.hex('#8b5cf6')(' Agentic KDD — MCP Setup'));
38
+ console.log(chalk.gray(` Ruta del servidor: ${serverPath}\n`));
39
+
40
+ const results = {
41
+ cursor_project: false,
42
+ cursor_global: false,
43
+ claude_code: false,
44
+ };
45
+
46
+ // ══ PASO 1: Cursor — proyecto (automático, siempre funciona) ═══════════════
47
+ const cursorMcpDir = path.join(projectPath, '.cursor');
48
+ const cursorMcpFile = path.join(cursorMcpDir, 'mcp.json');
49
+
50
+ try {
51
+ fs.ensureDirSync(cursorMcpDir);
52
+
53
+ let cursorConfig = {};
54
+ if (fs.existsSync(cursorMcpFile)) {
55
+ try { cursorConfig = JSON.parse(fs.readFileSync(cursorMcpFile, 'utf8')); } catch {}
56
+ }
57
+ if (!cursorConfig.mcpServers) cursorConfig.mcpServers = {};
58
+
59
+ cursorConfig.mcpServers['agentic-kdd'] = {
60
+ command: 'node',
61
+ args: [serverPath],
62
+ };
63
+
64
+ fs.writeFileSync(cursorMcpFile, JSON.stringify(cursorConfig, null, 2));
65
+ results.cursor_project = true;
66
+ console.log(chalk.green(' ✓ Cursor (proyecto) → .cursor/mcp.json actualizado'));
67
+ console.log(chalk.gray(' Reinicia Cursor o recarga la ventana (Ctrl+Shift+P → "Reload Window")'));
68
+ } catch (e) {
69
+ console.log(chalk.yellow(` ⚠ Cursor (proyecto) → Error: ${e.message}`));
70
+ }
71
+
72
+ // ══ PASO 2: Claude Code CLI (automático si está instalado) ═════════════════
73
+ const claudeCliAvailable = isCLIAvailable('claude');
74
+ if (claudeCliAvailable) {
75
+ try {
76
+ // claude mcp add agentic-kdd -- node "/ruta/exacta/mcp-server.cjs"
77
+ execSync(`claude mcp add agentic-kdd -- node "${serverPath}"`, {
78
+ stdio: 'pipe',
79
+ cwd: projectPath,
80
+ });
81
+ results.claude_code = true;
82
+ console.log(chalk.green(' ✓ Claude Code → registrado via "claude mcp add"'));
83
+ } catch (e) {
84
+ // Puede fallar si ya existe — intentar actualizar
85
+ try {
86
+ execSync(`claude mcp remove agentic-kdd`, { stdio: 'pipe', cwd: projectPath });
87
+ execSync(`claude mcp add agentic-kdd -- node "${serverPath}"`, {
88
+ stdio: 'pipe', cwd: projectPath,
89
+ });
90
+ results.claude_code = true;
91
+ console.log(chalk.green(' ✓ Claude Code → actualizado'));
92
+ } catch {
93
+ console.log(chalk.gray(' ~ Claude Code → CLI no disponible o ya configurado'));
94
+ }
95
+ }
96
+ } else {
97
+ console.log(chalk.gray(' ~ Claude Code → CLI no detectado (config manual abajo)'));
98
+ }
99
+
100
+ // ══ PASO 3: Cursor global (opcional, solo si --global) ════════════════════
101
+ if (opts.global) {
102
+ const globalCursorConfig = getGlobalCursorConfigPath();
103
+ if (globalCursorConfig) {
104
+ try {
105
+ fs.ensureDirSync(path.dirname(globalCursorConfig));
106
+ let globalConfig = {};
107
+ if (fs.existsSync(globalCursorConfig)) {
108
+ try { globalConfig = JSON.parse(fs.readFileSync(globalCursorConfig, 'utf8')); } catch {}
109
+ }
110
+ if (!globalConfig.mcpServers) globalConfig.mcpServers = {};
111
+ globalConfig.mcpServers['agentic-kdd'] = { command: 'node', args: [serverPath] };
112
+ fs.writeFileSync(globalCursorConfig, JSON.stringify(globalConfig, null, 2));
113
+ results.cursor_global = true;
114
+ console.log(chalk.green(` ✓ Cursor (global) → ${globalCursorConfig}`));
115
+ } catch (e) {
116
+ console.log(chalk.yellow(` ⚠ Cursor (global) → ${e.message}`));
117
+ }
118
+ }
119
+ }
120
+
121
+ // ══ PASO 4: Imprimir configs manuales con ruta EXACTA ═════════════════════
122
+ console.log('\n' + chalk.bold(' ── Config manual (si necesitas hacerlo tú mismo) ──────────────────'));
123
+
124
+ // Cursor manual
125
+ const cursorJson = JSON.stringify({
126
+ mcpServers: {
127
+ 'agentic-kdd': {
128
+ command: 'node',
129
+ args: [serverPath],
130
+ }
131
+ }
132
+ }, null, 2);
133
+
134
+ console.log('\n' + chalk.cyan(' Cursor → .cursor/mcp.json'));
135
+ console.log(chalk.gray(' (Abre Cursor → Settings → MCP → Add → pega esto:)\n'));
136
+ console.log(chalk.white(cursorJson.split('\n').map(l => ' ' + l).join('\n')));
137
+
138
+ // Claude Code manual
139
+ console.log('\n' + chalk.cyan(' Claude Code → terminal'));
140
+ console.log(chalk.white(` claude mcp add agentic-kdd -- node "${serverPath}"`));
141
+
142
+ // VS Code manual
143
+ console.log('\n' + chalk.cyan(' VS Code → .vscode/settings.json'));
144
+ const vscodeJson = JSON.stringify({
145
+ 'mcp.servers': {
146
+ 'agentic-kdd': {
147
+ command: 'node',
148
+ args: [serverPath],
149
+ type: 'stdio',
150
+ }
151
+ }
152
+ }, null, 2);
153
+ console.log(chalk.white(vscodeJson.split('\n').map(l => ' ' + l).join('\n')));
154
+
155
+ // ══ RESUMEN ════════════════════════════════════════════════════════════════
156
+ console.log('\n' + chalk.dim(' ──────────────────────────────────────────────────────'));
157
+ const autoCount = Object.values(results).filter(Boolean).length;
158
+ if (autoCount > 0) {
159
+ console.log(chalk.bold.green(` ${autoCount} configuración(es) automática(s) completada(s).`));
160
+ }
161
+
162
+ if (results.cursor_project) {
163
+ console.log(chalk.green(' Cursor listo:') + chalk.gray(' Reload Window → las tools aparecen automáticamente.'));
164
+ }
165
+ if (results.claude_code) {
166
+ console.log(chalk.green(' Claude Code listo:') + chalk.gray(' cierra y abre el proyecto.'));
167
+ }
168
+
169
+ console.log('\n' + chalk.gray(' Para configurar globalmente (todos tus proyectos):'));
170
+ console.log(chalk.gray(' akdd mcp --global\n'));
171
+ }
172
+
173
+ // ─── HELPERS ──────────────────────────────────────────────────────────────────
174
+
175
+ function isCLIAvailable(cmd) {
176
+ try {
177
+ execSync(`${cmd} --version`, { stdio: 'pipe', timeout: 5000 });
178
+ return true;
179
+ } catch { return false; }
180
+ }
181
+
182
+ function getGlobalCursorConfigPath() {
183
+ const platform = os.platform();
184
+ const home = os.homedir();
185
+
186
+ if (platform === 'win32') {
187
+ // Windows: %APPDATA%\Cursor\User\globalStorage\mcp.json
188
+ const appData = process.env.APPDATA || path.join(home, 'AppData', 'Roaming');
189
+ return path.join(appData, 'Cursor', 'User', 'globalStorage', 'mcp.json');
190
+ }
191
+ if (platform === 'darwin') {
192
+ // macOS: ~/Library/Application Support/Cursor/User/globalStorage/mcp.json
193
+ return path.join(home, 'Library', 'Application Support', 'Cursor', 'User', 'globalStorage', 'mcp.json');
194
+ }
195
+ // Linux: ~/.config/Cursor/User/globalStorage/mcp.json
196
+ return path.join(home, '.config', 'Cursor', 'User', 'globalStorage', 'mcp.json');
197
+ }
198
+
199
+ /**
200
+ * Verifica y muestra el estado actual de la config MCP.
201
+ * akdd mcp status
202
+ */
203
+ function mcpStatus(projectPath) {
204
+ projectPath = projectPath || process.cwd();
205
+
206
+ const serverFile = path.join(projectPath, '.agentic', 'grafo', 'mcp-server.cjs');
207
+ const cursorProject = path.join(projectPath, '.cursor', 'mcp.json');
208
+ const globalCursor = getGlobalCursorConfigPath();
209
+
210
+ console.log('\n' + chalk.bold(' Agentic KDD — MCP Status\n'));
211
+
212
+ // Server file
213
+ const hasServer = fs.existsSync(serverFile);
214
+ console.log(hasServer
215
+ ? chalk.green(' ✓ mcp-server.cjs encontrado')
216
+ : chalk.red(' ✗ mcp-server.cjs NO encontrado — ejecutar: akdd update'));
217
+
218
+ // Cursor project config
219
+ let cursorProjectOk = false;
220
+ if (fs.existsSync(cursorProject)) {
221
+ try {
222
+ const config = JSON.parse(fs.readFileSync(cursorProject, 'utf8'));
223
+ cursorProjectOk = !!(config?.mcpServers?.['agentic-kdd']);
224
+ } catch {}
225
+ }
226
+ console.log(cursorProjectOk
227
+ ? chalk.green(' ✓ Cursor (proyecto) .cursor/mcp.json configurado')
228
+ : chalk.yellow(' ~ Cursor (proyecto) No configurado — ejecutar: akdd mcp'));
229
+
230
+ // Cursor global config
231
+ let cursorGlobalOk = false;
232
+ if (globalCursor && fs.existsSync(globalCursor)) {
233
+ try {
234
+ const config = JSON.parse(fs.readFileSync(globalCursor, 'utf8'));
235
+ cursorGlobalOk = !!(config?.mcpServers?.['agentic-kdd']);
236
+ } catch {}
237
+ }
238
+ console.log(cursorGlobalOk
239
+ ? chalk.green(' ✓ Cursor (global) configurado')
240
+ : chalk.gray(' ~ Cursor (global) No configurado — opcional: akdd mcp --global'));
241
+
242
+ // Claude Code
243
+ const claudeAvailable = isCLIAvailable('claude');
244
+ if (claudeAvailable) {
245
+ try {
246
+ const mcpList = execSync('claude mcp list', { stdio: 'pipe' }).toString();
247
+ const hasAgentic = mcpList.includes('agentic-kdd');
248
+ console.log(hasAgentic
249
+ ? chalk.green(' ✓ Claude Code registrado')
250
+ : chalk.yellow(' ~ Claude Code No registrado — ejecutar: akdd mcp'));
251
+ } catch {
252
+ console.log(chalk.gray(' ~ Claude Code CLI disponible pero sin listar MCPs'));
253
+ }
254
+ } else {
255
+ console.log(chalk.gray(' ~ Claude Code CLI No instalado'));
256
+ }
257
+
258
+ if (hasServer && !cursorProjectOk) {
259
+ console.log('\n' + chalk.bold(' → Ejecuta: akdd mcp\n'));
260
+ } else if (hasServer && cursorProjectOk) {
261
+ console.log('\n' + chalk.green(' Todo configurado. Recarga la ventana en Cursor si es necesario.\n'));
262
+ }
263
+ }
264
+
265
+ module.exports = { mcpSetup, mcpStatus };