code-graph-builder 0.8.0 → 0.9.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 +227 -8
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -285,7 +285,134 @@ 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 ──────────────────────────────────");
|
|
291
|
+
log("");
|
|
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.stdout.on("data", (chunk) => {
|
|
355
|
+
stdout += chunk.toString();
|
|
356
|
+
// Look for a valid JSON-RPC response
|
|
357
|
+
const lines = stdout.split("\n");
|
|
358
|
+
for (const line of lines) {
|
|
359
|
+
// MCP uses Content-Length header framing
|
|
360
|
+
if (line.startsWith("{")) {
|
|
361
|
+
try {
|
|
362
|
+
const msg = JSON.parse(line);
|
|
363
|
+
if (msg.result && msg.result.capabilities) {
|
|
364
|
+
// Got initialize response, now request tools/list
|
|
365
|
+
const toolsReq =
|
|
366
|
+
`Content-Length: 80\r\n\r\n` +
|
|
367
|
+
JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/list", params: {} });
|
|
368
|
+
child.stdin.write(toolsReq);
|
|
369
|
+
stdout = "";
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (msg.result && msg.result.tools) {
|
|
373
|
+
clearTimeout(timer);
|
|
374
|
+
finish(true, `${msg.result.tools.length} tools available`);
|
|
375
|
+
return;
|
|
376
|
+
}
|
|
377
|
+
} catch { /* partial JSON, wait for more */ }
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
child.on("error", (err) => {
|
|
383
|
+
clearTimeout(timer);
|
|
384
|
+
finish(false, err.message);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
child.on("exit", (code) => {
|
|
388
|
+
clearTimeout(timer);
|
|
389
|
+
if (!resolved) finish(false, `Server exited with code ${code}`);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// Send MCP initialize request
|
|
393
|
+
const initReq = JSON.stringify({
|
|
394
|
+
jsonrpc: "2.0",
|
|
395
|
+
id: 1,
|
|
396
|
+
method: "initialize",
|
|
397
|
+
params: {
|
|
398
|
+
protocolVersion: "2024-11-05",
|
|
399
|
+
capabilities: {},
|
|
400
|
+
clientInfo: { name: "setup-verify", version: "1.0.0" },
|
|
401
|
+
},
|
|
402
|
+
});
|
|
403
|
+
const header = `Content-Length: ${Buffer.byteLength(initReq)}\r\n\r\n`;
|
|
404
|
+
child.stdin.write(header + initReq);
|
|
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
|
+
log("");
|
|
415
|
+
log("── Setup complete ─────────────────────────────────────────");
|
|
289
416
|
log("");
|
|
290
417
|
log(" Add to your MCP client config:");
|
|
291
418
|
log("");
|
|
@@ -396,15 +523,104 @@ function autoInstallAndStart(extraArgs) {
|
|
|
396
523
|
runServer(PYTHON_CMD, ["-m", MODULE_PATH]);
|
|
397
524
|
}
|
|
398
525
|
|
|
526
|
+
// ---------------------------------------------------------------------------
|
|
527
|
+
// Uninstall — remove Python package, config, workspace data, Claude MCP entry
|
|
528
|
+
// ---------------------------------------------------------------------------
|
|
529
|
+
|
|
530
|
+
async function runUninstall() {
|
|
531
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
532
|
+
const ask = (q) => new Promise((resolve) => rl.question(q, resolve));
|
|
533
|
+
const log = (msg) => process.stderr.write(msg + "\n");
|
|
534
|
+
|
|
535
|
+
log("");
|
|
536
|
+
log("╔══════════════════════════════════════════════════════════╗");
|
|
537
|
+
log("║ code-graph-builder Uninstall ║");
|
|
538
|
+
log("╚══════════════════════════════════════════════════════════╝");
|
|
539
|
+
log("");
|
|
540
|
+
|
|
541
|
+
// 1. Show what will be removed
|
|
542
|
+
const pip = findPip();
|
|
543
|
+
const hasPythonPkg = pythonPackageInstalled();
|
|
544
|
+
const hasWorkspace = existsSync(WORKSPACE_DIR);
|
|
545
|
+
const hasEnv = existsSync(ENV_FILE);
|
|
546
|
+
|
|
547
|
+
// Check Claude Code MCP config
|
|
548
|
+
let hasClaudeConfig = false;
|
|
549
|
+
try {
|
|
550
|
+
execFileSync("claude", ["mcp", "list"], { stdio: "pipe" });
|
|
551
|
+
hasClaudeConfig = true;
|
|
552
|
+
} catch { /* claude CLI not available */ }
|
|
553
|
+
|
|
554
|
+
log(" The following will be removed:");
|
|
555
|
+
log("");
|
|
556
|
+
if (hasPythonPkg) log(" ✓ Python package: code-graph-builder");
|
|
557
|
+
else log(" - Python package: not installed");
|
|
558
|
+
if (hasWorkspace) log(` ✓ Workspace data: ${WORKSPACE_DIR}`);
|
|
559
|
+
else log(" - Workspace data: not found");
|
|
560
|
+
if (hasEnv) log(` ✓ Config file: ${ENV_FILE}`);
|
|
561
|
+
if (hasClaudeConfig) log(" ✓ Claude Code MCP server entry");
|
|
562
|
+
log("");
|
|
563
|
+
|
|
564
|
+
const answer = (await ask(" Proceed with uninstall? [y/N]: ")).trim().toLowerCase();
|
|
565
|
+
rl.close();
|
|
566
|
+
|
|
567
|
+
if (answer !== "y" && answer !== "yes") {
|
|
568
|
+
log("\n Uninstall cancelled.\n");
|
|
569
|
+
process.exit(0);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
log("");
|
|
573
|
+
|
|
574
|
+
// 2. Remove Claude Code MCP entry
|
|
575
|
+
if (hasClaudeConfig) {
|
|
576
|
+
try {
|
|
577
|
+
execSync("claude mcp remove code-graph-builder", { stdio: "pipe", shell: true });
|
|
578
|
+
log(" ✓ Removed Claude Code MCP entry");
|
|
579
|
+
} catch {
|
|
580
|
+
log(" ⚠ Could not remove Claude Code MCP entry (may not exist)");
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// 3. Uninstall Python package
|
|
585
|
+
if (hasPythonPkg && pip) {
|
|
586
|
+
try {
|
|
587
|
+
execSync(
|
|
588
|
+
[...pip, "uninstall", "-y", PYTHON_PACKAGE].map(s => `"${s}"`).join(" "),
|
|
589
|
+
{ stdio: "inherit", shell: true }
|
|
590
|
+
);
|
|
591
|
+
log(" ✓ Uninstalled Python package");
|
|
592
|
+
} catch {
|
|
593
|
+
log(" ⚠ Failed to uninstall Python package. Try manually: pip uninstall code-graph-builder");
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// 4. Remove workspace data
|
|
598
|
+
if (hasWorkspace) {
|
|
599
|
+
const { rmSync } = await import("node:fs");
|
|
600
|
+
try {
|
|
601
|
+
rmSync(WORKSPACE_DIR, { recursive: true, force: true });
|
|
602
|
+
log(` ✓ Removed workspace: ${WORKSPACE_DIR}`);
|
|
603
|
+
} catch (err) {
|
|
604
|
+
log(` ⚠ Failed to remove workspace: ${err.message}`);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
log("");
|
|
609
|
+
log(" Uninstall complete.");
|
|
610
|
+
log(" To also clear the npx cache: npx clear-npx-cache");
|
|
611
|
+
log("");
|
|
612
|
+
}
|
|
613
|
+
|
|
399
614
|
function startServer(extraArgs = []) {
|
|
400
|
-
|
|
615
|
+
// Prefer pip-installed package first (most reliable, includes all deps)
|
|
616
|
+
if (pythonPackageInstalled()) {
|
|
617
|
+
runServer(PYTHON_CMD, ["-m", MODULE_PATH]);
|
|
618
|
+
} else if (commandExists("uvx")) {
|
|
401
619
|
runServer("uvx", [PYTHON_PACKAGE, ...extraArgs]);
|
|
402
620
|
} else if (commandExists("uv")) {
|
|
403
621
|
runServer("uv", ["tool", "run", PYTHON_PACKAGE, ...extraArgs]);
|
|
404
622
|
} else if (commandExists("pipx")) {
|
|
405
623
|
runServer("pipx", ["run", PYTHON_PACKAGE, ...extraArgs]);
|
|
406
|
-
} else if (pythonPackageInstalled()) {
|
|
407
|
-
runServer(PYTHON_CMD, ["-m", MODULE_PATH]);
|
|
408
624
|
} else {
|
|
409
625
|
// Auto-install via pip
|
|
410
626
|
autoInstallAndStart(extraArgs);
|
|
@@ -435,14 +651,17 @@ if (mode === "--setup") {
|
|
|
435
651
|
} else {
|
|
436
652
|
startServer(args.slice(1));
|
|
437
653
|
}
|
|
654
|
+
} else if (mode === "--uninstall") {
|
|
655
|
+
runUninstall();
|
|
438
656
|
} else if (mode === "--help" || mode === "-h") {
|
|
439
657
|
process.stderr.write(
|
|
440
658
|
`code-graph-builder - Code knowledge graph MCP server\n\n` +
|
|
441
659
|
`Usage:\n` +
|
|
442
|
-
` npx code-graph-builder
|
|
443
|
-
` npx code-graph-builder --server
|
|
444
|
-
` npx code-graph-builder --setup
|
|
445
|
-
` npx code-graph-builder --
|
|
660
|
+
` npx code-graph-builder Interactive setup wizard\n` +
|
|
661
|
+
` npx code-graph-builder --server Start MCP server\n` +
|
|
662
|
+
` npx code-graph-builder --setup Re-run setup wizard\n` +
|
|
663
|
+
` npx code-graph-builder --uninstall Completely uninstall\n` +
|
|
664
|
+
` npx code-graph-builder --help Show this help\n\n` +
|
|
446
665
|
`Config: ${ENV_FILE}\n`
|
|
447
666
|
);
|
|
448
667
|
} else {
|