code-graph-builder 0.8.0 → 0.11.0
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/cli.mjs +264 -18
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -285,20 +285,174 @@ async function runSetup() {
|
|
|
285
285
|
log(" Embedding: " + embedDisplay);
|
|
286
286
|
log(" Workspace: " + workspace);
|
|
287
287
|
log("");
|
|
288
|
-
|
|
288
|
+
|
|
289
|
+
// --- Verify installation ---
|
|
290
|
+
log("── Verifying installation ──────────────────────────────────");
|
|
289
291
|
log("");
|
|
290
|
-
|
|
292
|
+
|
|
293
|
+
// Step 1: Python available?
|
|
294
|
+
if (!PYTHON_CMD) {
|
|
295
|
+
log(" ✗ Python 3 not found on PATH");
|
|
296
|
+
log(" Install Python 3.10+ and re-run: npx code-graph-builder --setup");
|
|
297
|
+
log("");
|
|
298
|
+
rl.close();
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
log(` ✓ Python found: ${PYTHON_CMD}`);
|
|
302
|
+
|
|
303
|
+
// Step 2: Package installed? If not, auto-install.
|
|
304
|
+
if (!pythonPackageInstalled()) {
|
|
305
|
+
log(` … Installing ${PYTHON_PACKAGE} via pip...`);
|
|
306
|
+
const pip = findPip();
|
|
307
|
+
if (pip) {
|
|
308
|
+
try {
|
|
309
|
+
execSync(
|
|
310
|
+
[...pip, "install", PYTHON_PACKAGE].map(s => `"${s}"`).join(" "),
|
|
311
|
+
{ stdio: "pipe", shell: true }
|
|
312
|
+
);
|
|
313
|
+
} catch { /* handled below */ }
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (pythonPackageInstalled()) {
|
|
318
|
+
log(` ✓ Python package installed: ${PYTHON_PACKAGE}`);
|
|
319
|
+
} else {
|
|
320
|
+
log(` ✗ Python package not installed`);
|
|
321
|
+
log(` Run manually: pip install ${PYTHON_PACKAGE}`);
|
|
322
|
+
log("");
|
|
323
|
+
rl.close();
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Step 3: MCP server smoke test — spawn server, send initialize, check tools/list
|
|
328
|
+
log(" … Starting MCP server smoke test...");
|
|
329
|
+
|
|
330
|
+
const verified = await new Promise((resolve) => {
|
|
331
|
+
const envVars = loadEnvFile();
|
|
332
|
+
const mergedEnv = { ...process.env, ...envVars };
|
|
333
|
+
if (!mergedEnv.CGB_WORKSPACE) mergedEnv.CGB_WORKSPACE = WORKSPACE_DIR;
|
|
334
|
+
|
|
335
|
+
const child = spawn(PYTHON_CMD, ["-m", MODULE_PATH], {
|
|
336
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
337
|
+
env: mergedEnv,
|
|
338
|
+
shell: IS_WIN,
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
let stdout = "";
|
|
342
|
+
let resolved = false;
|
|
343
|
+
|
|
344
|
+
const finish = (success, detail) => {
|
|
345
|
+
if (resolved) return;
|
|
346
|
+
resolved = true;
|
|
347
|
+
try { child.kill(); } catch {}
|
|
348
|
+
resolve({ success, detail });
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// Timeout after 15s
|
|
352
|
+
const timer = setTimeout(() => finish(false, "Server did not respond within 15s"), 15000);
|
|
353
|
+
|
|
354
|
+
child.stderr.on("data", () => {}); // Suppress server logs
|
|
355
|
+
|
|
356
|
+
child.stdout.on("data", (chunk) => {
|
|
357
|
+
stdout += chunk.toString();
|
|
358
|
+
// MCP stdio uses JSON lines (one JSON-RPC message per line)
|
|
359
|
+
const lines = stdout.split("\n");
|
|
360
|
+
for (const line of lines) {
|
|
361
|
+
const trimmed = line.trim();
|
|
362
|
+
if (!trimmed || !trimmed.startsWith("{")) continue;
|
|
363
|
+
try {
|
|
364
|
+
const msg = JSON.parse(trimmed);
|
|
365
|
+
if (msg.result && msg.result.capabilities) {
|
|
366
|
+
// Got initialize response, now request tools/list
|
|
367
|
+
const toolsReq = JSON.stringify({
|
|
368
|
+
jsonrpc: "2.0", id: 2, method: "tools/list", params: {},
|
|
369
|
+
});
|
|
370
|
+
child.stdin.write(toolsReq + "\n");
|
|
371
|
+
stdout = "";
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (msg.result && msg.result.tools) {
|
|
375
|
+
clearTimeout(timer);
|
|
376
|
+
finish(true, `${msg.result.tools.length} tools available`);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
} catch { /* partial JSON, wait for more */ }
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
child.on("error", (err) => {
|
|
384
|
+
clearTimeout(timer);
|
|
385
|
+
finish(false, err.message);
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
child.on("exit", (code) => {
|
|
389
|
+
clearTimeout(timer);
|
|
390
|
+
if (!resolved) finish(false, `Server exited with code ${code}`);
|
|
391
|
+
});
|
|
392
|
+
|
|
393
|
+
// Send MCP initialize request as JSON line
|
|
394
|
+
const initReq = JSON.stringify({
|
|
395
|
+
jsonrpc: "2.0",
|
|
396
|
+
id: 1,
|
|
397
|
+
method: "initialize",
|
|
398
|
+
params: {
|
|
399
|
+
protocolVersion: "2024-11-05",
|
|
400
|
+
capabilities: {},
|
|
401
|
+
clientInfo: { name: "setup-verify", version: "1.0.0" },
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
child.stdin.write(initReq + "\n");
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
if (verified.success) {
|
|
408
|
+
log(` ✓ MCP server started successfully (${verified.detail})`);
|
|
409
|
+
} else {
|
|
410
|
+
log(` ✗ MCP server smoke test failed: ${verified.detail}`);
|
|
411
|
+
log(" The server may still work — try: npx code-graph-builder --server");
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Step 4: Auto-register in Claude Code if available
|
|
291
415
|
log("");
|
|
292
|
-
log(
|
|
293
|
-
log(' "mcpServers": {');
|
|
294
|
-
log(' "code-graph-builder": {');
|
|
295
|
-
log(' "command": "npx",');
|
|
296
|
-
log(' "args": ["-y", "code-graph-builder@latest", "--server"]');
|
|
297
|
-
log(" }");
|
|
298
|
-
log(" }");
|
|
299
|
-
log(" }");
|
|
416
|
+
log("── Registering MCP server ─────────────────────────────────");
|
|
300
417
|
log("");
|
|
301
|
-
|
|
418
|
+
|
|
419
|
+
if (commandExists("claude")) {
|
|
420
|
+
try {
|
|
421
|
+
// Remove existing entry first (ignore errors if not found)
|
|
422
|
+
try {
|
|
423
|
+
execSync("claude mcp remove code-graph-builder", { stdio: "pipe", shell: true });
|
|
424
|
+
} catch { /* not found, fine */ }
|
|
425
|
+
|
|
426
|
+
const addCmd = IS_WIN
|
|
427
|
+
? 'claude mcp add --transport stdio code-graph-builder -- cmd /c npx -y code-graph-builder@latest --server'
|
|
428
|
+
: 'claude mcp add --transport stdio code-graph-builder -- npx -y code-graph-builder@latest --server';
|
|
429
|
+
|
|
430
|
+
execSync(addCmd, { stdio: "pipe", shell: true });
|
|
431
|
+
log(" ✓ Registered in Claude Code: code-graph-builder");
|
|
432
|
+
} catch (err) {
|
|
433
|
+
log(" ⚠ Failed to register in Claude Code automatically");
|
|
434
|
+
log(" Run manually:");
|
|
435
|
+
if (IS_WIN) {
|
|
436
|
+
log(' claude mcp add --transport stdio code-graph-builder -- cmd /c npx -y code-graph-builder@latest --server');
|
|
437
|
+
} else {
|
|
438
|
+
log(' claude mcp add --transport stdio code-graph-builder -- npx -y code-graph-builder@latest --server');
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
} else {
|
|
442
|
+
log(" Claude Code CLI not found. Add manually to your MCP client config:");
|
|
443
|
+
log("");
|
|
444
|
+
log(' {');
|
|
445
|
+
log(' "mcpServers": {');
|
|
446
|
+
log(' "code-graph-builder": {');
|
|
447
|
+
log(' "command": "npx",');
|
|
448
|
+
log(' "args": ["-y", "code-graph-builder@latest", "--server"]');
|
|
449
|
+
log(" }");
|
|
450
|
+
log(" }");
|
|
451
|
+
log(" }");
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
log("");
|
|
455
|
+
log("── Setup complete ─────────────────────────────────────────");
|
|
302
456
|
log("");
|
|
303
457
|
}
|
|
304
458
|
|
|
@@ -396,15 +550,104 @@ function autoInstallAndStart(extraArgs) {
|
|
|
396
550
|
runServer(PYTHON_CMD, ["-m", MODULE_PATH]);
|
|
397
551
|
}
|
|
398
552
|
|
|
553
|
+
// ---------------------------------------------------------------------------
|
|
554
|
+
// Uninstall — remove Python package, config, workspace data, Claude MCP entry
|
|
555
|
+
// ---------------------------------------------------------------------------
|
|
556
|
+
|
|
557
|
+
async function runUninstall() {
|
|
558
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
559
|
+
const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
560
|
+
const log = (msg) => process.stderr.write(msg + "\n");
|
|
561
|
+
|
|
562
|
+
log("");
|
|
563
|
+
log("╔══════════════════════════════════════════════════════════╗");
|
|
564
|
+
log("║ code-graph-builder Uninstall ║");
|
|
565
|
+
log("╚══════════════════════════════════════════════════════════╝");
|
|
566
|
+
log("");
|
|
567
|
+
|
|
568
|
+
// 1. Show what will be removed
|
|
569
|
+
const pip = findPip();
|
|
570
|
+
const hasPythonPkg = pythonPackageInstalled();
|
|
571
|
+
const hasWorkspace = existsSync(WORKSPACE_DIR);
|
|
572
|
+
const hasEnv = existsSync(ENV_FILE);
|
|
573
|
+
|
|
574
|
+
// Check Claude Code MCP config
|
|
575
|
+
let hasClaudeConfig = false;
|
|
576
|
+
try {
|
|
577
|
+
execFileSync("claude", ["mcp", "list"], { stdio: "pipe" });
|
|
578
|
+
hasClaudeConfig = true;
|
|
579
|
+
} catch { /* claude CLI not available */ }
|
|
580
|
+
|
|
581
|
+
log(" The following will be removed:");
|
|
582
|
+
log("");
|
|
583
|
+
if (hasPythonPkg) log(" ✓ Python package: code-graph-builder");
|
|
584
|
+
else log(" - Python package: not installed");
|
|
585
|
+
if (hasWorkspace) log(` ✓ Workspace data: ${WORKSPACE_DIR}`);
|
|
586
|
+
else log(" - Workspace data: not found");
|
|
587
|
+
if (hasEnv) log(` ✓ Config file: ${ENV_FILE}`);
|
|
588
|
+
if (hasClaudeConfig) log(" ✓ Claude Code MCP server entry");
|
|
589
|
+
log("");
|
|
590
|
+
|
|
591
|
+
const answer = (await ask(" Proceed with uninstall? [y/N]: ")).trim().toLowerCase();
|
|
592
|
+
rl.close();
|
|
593
|
+
|
|
594
|
+
if (answer !== "y" && answer !== "yes") {
|
|
595
|
+
log("\n Uninstall cancelled.\n");
|
|
596
|
+
process.exit(0);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
log("");
|
|
600
|
+
|
|
601
|
+
// 2. Remove Claude Code MCP entry
|
|
602
|
+
if (hasClaudeConfig) {
|
|
603
|
+
try {
|
|
604
|
+
execSync("claude mcp remove code-graph-builder", { stdio: "pipe", shell: true });
|
|
605
|
+
log(" ✓ Removed Claude Code MCP entry");
|
|
606
|
+
} catch {
|
|
607
|
+
log(" ⚠ Could not remove Claude Code MCP entry (may not exist)");
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// 3. Uninstall Python package
|
|
612
|
+
if (hasPythonPkg && pip) {
|
|
613
|
+
try {
|
|
614
|
+
execSync(
|
|
615
|
+
[...pip, "uninstall", "-y", PYTHON_PACKAGE].map(s => `"${s}"`).join(" "),
|
|
616
|
+
{ stdio: "inherit", shell: true }
|
|
617
|
+
);
|
|
618
|
+
log(" ✓ Uninstalled Python package");
|
|
619
|
+
} catch {
|
|
620
|
+
log(" ⚠ Failed to uninstall Python package. Try manually: pip uninstall code-graph-builder");
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// 4. Remove workspace data
|
|
625
|
+
if (hasWorkspace) {
|
|
626
|
+
const { rmSync } = await import("node:fs");
|
|
627
|
+
try {
|
|
628
|
+
rmSync(WORKSPACE_DIR, { recursive: true, force: true });
|
|
629
|
+
log(` ✓ Removed workspace: ${WORKSPACE_DIR}`);
|
|
630
|
+
} catch (err) {
|
|
631
|
+
log(` ⚠ Failed to remove workspace: ${err.message}`);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
log("");
|
|
636
|
+
log(" Uninstall complete.");
|
|
637
|
+
log(" To also clear the npx cache: npx clear-npx-cache");
|
|
638
|
+
log("");
|
|
639
|
+
}
|
|
640
|
+
|
|
399
641
|
function startServer(extraArgs = []) {
|
|
400
|
-
|
|
642
|
+
// Prefer pip-installed package first (most reliable, includes all deps)
|
|
643
|
+
if (pythonPackageInstalled()) {
|
|
644
|
+
runServer(PYTHON_CMD, ["-m", MODULE_PATH]);
|
|
645
|
+
} else if (commandExists("uvx")) {
|
|
401
646
|
runServer("uvx", [PYTHON_PACKAGE, ...extraArgs]);
|
|
402
647
|
} else if (commandExists("uv")) {
|
|
403
648
|
runServer("uv", ["tool", "run", PYTHON_PACKAGE, ...extraArgs]);
|
|
404
649
|
} else if (commandExists("pipx")) {
|
|
405
650
|
runServer("pipx", ["run", PYTHON_PACKAGE, ...extraArgs]);
|
|
406
|
-
} else if (pythonPackageInstalled()) {
|
|
407
|
-
runServer(PYTHON_CMD, ["-m", MODULE_PATH]);
|
|
408
651
|
} else {
|
|
409
652
|
// Auto-install via pip
|
|
410
653
|
autoInstallAndStart(extraArgs);
|
|
@@ -435,14 +678,17 @@ if (mode === "--setup") {
|
|
|
435
678
|
} else {
|
|
436
679
|
startServer(args.slice(1));
|
|
437
680
|
}
|
|
681
|
+
} else if (mode === "--uninstall") {
|
|
682
|
+
runUninstall();
|
|
438
683
|
} else if (mode === "--help" || mode === "-h") {
|
|
439
684
|
process.stderr.write(
|
|
440
685
|
`code-graph-builder - Code knowledge graph MCP server\n\n` +
|
|
441
686
|
`Usage:\n` +
|
|
442
|
-
` npx code-graph-builder
|
|
443
|
-
` npx code-graph-builder --server
|
|
444
|
-
` npx code-graph-builder --setup
|
|
445
|
-
` npx code-graph-builder --
|
|
687
|
+
` npx code-graph-builder Interactive setup wizard\n` +
|
|
688
|
+
` npx code-graph-builder --server Start MCP server\n` +
|
|
689
|
+
` npx code-graph-builder --setup Re-run setup wizard\n` +
|
|
690
|
+
` npx code-graph-builder --uninstall Completely uninstall\n` +
|
|
691
|
+
` npx code-graph-builder --help Show this help\n\n` +
|
|
446
692
|
`Config: ${ENV_FILE}\n`
|
|
447
693
|
);
|
|
448
694
|
} else {
|