@infinitedusky/indusk-mcp 1.1.2 → 1.1.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.
@@ -176,7 +176,12 @@ export async function init(projectRoot, options = {}) {
176
176
  console.info("\n[Hooks]");
177
177
  const hooksSource = join(packageRoot, "hooks");
178
178
  const hooksTarget = join(projectRoot, ".claude/hooks");
179
- const hookFiles = ["check-gates.js", "gate-reminder.js", "validate-impl-structure.js", "check-catchup.js"];
179
+ const hookFiles = [
180
+ "check-gates.js",
181
+ "gate-reminder.js",
182
+ "validate-impl-structure.js",
183
+ "check-catchup.js",
184
+ ];
180
185
  if (existsSync(hooksSource)) {
181
186
  mkdirSync(hooksTarget, { recursive: true });
182
187
  for (const file of hookFiles) {
@@ -6,22 +6,58 @@ function cgcPath() {
6
6
  const paths = [join(process.env.HOME ?? "", ".local/bin/cgc"), "/usr/local/bin/cgc"];
7
7
  return paths.find((p) => existsSync(p)) ?? null;
8
8
  }
9
- function runCgc(args, projectRoot) {
9
+ function getFalkorHost() {
10
+ if (process.env.FALKORDB_HOST)
11
+ return process.env.FALKORDB_HOST;
12
+ // Try OrbStack hostname first, fall back to localhost
13
+ try {
14
+ execSync("ping -c 1 -W 1 falkordb.orb.local", {
15
+ stdio: ["ignore", "ignore", "ignore"],
16
+ timeout: 2000,
17
+ });
18
+ return "falkordb.orb.local";
19
+ }
20
+ catch {
21
+ return "localhost";
22
+ }
23
+ }
24
+ function checkFalkorConnection(host) {
25
+ try {
26
+ // Fast TCP check — try to connect to Redis port
27
+ execSync(`node -e "const s=require('net').connect(6379,'${host}');s.setTimeout(2000);s.on('connect',()=>{s.end();process.exit(0)});s.on('error',()=>process.exit(1));s.on('timeout',()=>process.exit(1))"`, { timeout: 3000, stdio: ["ignore", "ignore", "ignore"] });
28
+ return true;
29
+ }
30
+ catch {
31
+ return false;
32
+ }
33
+ }
34
+ function runCgc(args, projectRoot, options) {
10
35
  const cgc = cgcPath();
11
36
  if (!cgc) {
12
37
  return JSON.stringify({ error: "CGC not installed — run: pipx install codegraphcontext" });
13
38
  }
39
+ const host = getFalkorHost();
40
+ const timeout = options?.timeout ?? 15000;
41
+ // Fast pre-check: is FalkorDB reachable?
42
+ if (!options?.skipConnectionCheck && !checkFalkorConnection(host)) {
43
+ return JSON.stringify({
44
+ error: `FalkorDB not reachable at ${host}:6379. Is the container running? Try: docker start falkordb`,
45
+ host,
46
+ suggestion: host === "localhost"
47
+ ? "OrbStack not detected. If using OrbStack, ensure it's running."
48
+ : "Try: docker start falkordb — or check if OrbStack is running.",
49
+ });
50
+ }
14
51
  try {
15
52
  return execSync(`${cgc} ${args}`, {
16
53
  encoding: "utf-8",
17
- timeout: 60000,
54
+ timeout,
18
55
  stdio: ["ignore", "pipe", "pipe"],
19
56
  cwd: projectRoot,
20
57
  env: {
21
58
  ...process.env,
22
59
  DATABASE_TYPE: "falkordb-remote",
23
- FALKORDB_HOST: process.env.FALKORDB_HOST ?? "falkordb.orb.local",
24
- FALKORDB_PORT: process.env.FALKORDB_PORT ?? "6379",
60
+ FALKORDB_HOST: host,
25
61
  FALKORDB_GRAPH_NAME: process.env.FALKORDB_GRAPH_NAME ?? basename(projectRoot),
26
62
  },
27
63
  }).trim();
@@ -38,10 +74,16 @@ export function indexProject(projectRoot) {
38
74
  if (!cgc) {
39
75
  return { success: false, output: "CGC not installed — run: pipx install codegraphcontext" };
40
76
  }
77
+ const host = getFalkorHost();
78
+ if (!checkFalkorConnection(host)) {
79
+ return {
80
+ success: false,
81
+ output: `FalkorDB not reachable at ${host}:6379. Is the container running? Try: docker start falkordb`,
82
+ };
83
+ }
41
84
  const graphName = process.env.FALKORDB_GRAPH_NAME ?? basename(projectRoot);
85
+ const hasIgnore = existsSync(join(projectRoot, ".cgcignore"));
42
86
  try {
43
- // Check if .cgcignore exists
44
- const hasIgnore = existsSync(join(projectRoot, ".cgcignore"));
45
87
  const output = execSync(`${cgc} index ${projectRoot}`, {
46
88
  encoding: "utf-8",
47
89
  timeout: 120000,
@@ -49,8 +91,7 @@ export function indexProject(projectRoot) {
49
91
  env: {
50
92
  ...process.env,
51
93
  DATABASE_TYPE: "falkordb-remote",
52
- FALKORDB_HOST: process.env.FALKORDB_HOST ?? "falkordb.orb.local",
53
- FALKORDB_PORT: process.env.FALKORDB_PORT ?? "6379",
94
+ FALKORDB_HOST: host,
54
95
  FALKORDB_GRAPH_NAME: graphName,
55
96
  },
56
97
  }).trim();
@@ -268,4 +309,141 @@ export function registerGraphTools(server, projectRoot) {
268
309
  content: [{ type: "text", text: output }],
269
310
  };
270
311
  });
312
+ server.registerTool("graph_ensure", {
313
+ description: "Validate and fix the entire code graph stack: FalkorDB container, CGC connection, repo indexing. Call this during catchup or when graph tools fail. Attempts auto-repair for common issues.",
314
+ }, async () => {
315
+ const steps = [];
316
+ // 1. Check CGC installed
317
+ const cgc = cgcPath();
318
+ if (!cgc) {
319
+ steps.push({
320
+ step: "cgc-installed",
321
+ status: "error",
322
+ detail: "CGC not installed — run: pipx install codegraphcontext",
323
+ });
324
+ return {
325
+ content: [{ type: "text", text: JSON.stringify({ steps }, null, 2) }],
326
+ isError: true,
327
+ };
328
+ }
329
+ steps.push({ step: "cgc-installed", status: "ok", detail: cgc });
330
+ // 2. Check FalkorDB container exists and is running
331
+ try {
332
+ const status = execSync("docker ps --filter name=falkordb --format '{{.Status}}'", {
333
+ encoding: "utf-8",
334
+ timeout: 5000,
335
+ stdio: ["ignore", "pipe", "pipe"],
336
+ }).trim();
337
+ if (status) {
338
+ steps.push({ step: "falkordb-container", status: "ok", detail: status });
339
+ }
340
+ else {
341
+ // Container exists but not running — try to start
342
+ try {
343
+ execSync("docker start falkordb", {
344
+ timeout: 10000,
345
+ stdio: ["ignore", "pipe", "pipe"],
346
+ });
347
+ steps.push({
348
+ step: "falkordb-container",
349
+ status: "fixed",
350
+ detail: "Started existing container",
351
+ });
352
+ }
353
+ catch {
354
+ // Container doesn't exist — create it
355
+ try {
356
+ execSync("docker run -d --name falkordb --restart unless-stopped -v falkordb-global:/var/lib/falkordb/data falkordb/falkordb:latest", { timeout: 30000, stdio: ["ignore", "pipe", "pipe"] });
357
+ steps.push({
358
+ step: "falkordb-container",
359
+ status: "fixed",
360
+ detail: "Created new container",
361
+ });
362
+ }
363
+ catch (e) {
364
+ const err = e;
365
+ steps.push({
366
+ step: "falkordb-container",
367
+ status: "error",
368
+ detail: err.message ?? "Failed to create container",
369
+ });
370
+ }
371
+ }
372
+ }
373
+ }
374
+ catch {
375
+ steps.push({
376
+ step: "falkordb-container",
377
+ status: "error",
378
+ detail: "Docker not available — is OrbStack running?",
379
+ });
380
+ }
381
+ // 3. Check connectivity
382
+ const host = getFalkorHost();
383
+ if (checkFalkorConnection(host)) {
384
+ steps.push({
385
+ step: "falkordb-connection",
386
+ status: "ok",
387
+ detail: `Connected to ${host}:6379`,
388
+ });
389
+ }
390
+ else {
391
+ // Wait a moment if we just started the container
392
+ const justStarted = steps.some((s) => s.step === "falkordb-container" && s.status === "fixed");
393
+ if (justStarted) {
394
+ await new Promise((r) => setTimeout(r, 3000));
395
+ if (checkFalkorConnection(host)) {
396
+ steps.push({
397
+ step: "falkordb-connection",
398
+ status: "ok",
399
+ detail: `Connected to ${host}:6379 (after wait)`,
400
+ });
401
+ }
402
+ else {
403
+ steps.push({
404
+ step: "falkordb-connection",
405
+ status: "error",
406
+ detail: `Cannot connect to ${host}:6379`,
407
+ });
408
+ }
409
+ }
410
+ else {
411
+ steps.push({
412
+ step: "falkordb-connection",
413
+ status: "error",
414
+ detail: `Cannot connect to ${host}:6379`,
415
+ });
416
+ }
417
+ }
418
+ // 4. Check if repo is indexed
419
+ if (steps.every((s) => s.status !== "error")) {
420
+ const listOutput = runCgc("list", projectRoot, { skipConnectionCheck: true });
421
+ if (listOutput.includes(projectRoot) || listOutput.includes(basename(projectRoot))) {
422
+ steps.push({ step: "repo-indexed", status: "ok", detail: "Repository is indexed" });
423
+ }
424
+ else {
425
+ steps.push({
426
+ step: "repo-indexed",
427
+ status: "error",
428
+ detail: "Repository not indexed — call index_project to index",
429
+ });
430
+ }
431
+ }
432
+ const hasErrors = steps.some((s) => s.status === "error");
433
+ const hasFixed = steps.some((s) => s.status === "fixed");
434
+ return {
435
+ content: [
436
+ {
437
+ type: "text",
438
+ text: JSON.stringify({
439
+ healthy: !hasErrors,
440
+ autoRepaired: hasFixed,
441
+ host,
442
+ steps,
443
+ }, null, 2),
444
+ },
445
+ ],
446
+ isError: hasErrors,
447
+ };
448
+ });
271
449
  }
@@ -6,6 +6,10 @@
6
6
  {
7
7
  "name": "falkordb-container",
8
8
  "command": "docker ps --filter name=falkordb --format '{{.Status}}'"
9
+ },
10
+ {
11
+ "name": "falkordb-connection",
12
+ "command": "node -e \"const s=require('net').connect(6379,process.env.FALKORDB_HOST||'falkordb.orb.local');s.setTimeout(3000);s.on('connect',()=>{console.log('connected');s.end();process.exit(0)});s.on('error',e=>{console.error(e.message);process.exit(1)});s.on('timeout',()=>{console.error('timeout');process.exit(1)})\""
9
13
  }
10
14
  ],
11
15
  "env_vars": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infinitedusky/indusk-mcp",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "description": "InDusk development system — skills, MCP tools, and CLI for structured AI-assisted development",
5
5
  "type": "module",
6
6
  "files": [
package/skills/catchup.md CHANGED
@@ -64,7 +64,7 @@ Understand what each skill does and when to use it. You should be able to answer
64
64
  **After reviewing, edit the handoff to check off:** `- [x] skills` and `- [x] extensions`
65
65
 
66
66
  ### 7. Check Code Graph
67
- Call `graph_stats` to understand the codebase size and structure. This gives you a sense of what's indexed and queryable. If it fails, call `graph_doctor` to diagnose. If FalkorDB is down or the repo isn't indexed, flag it.
67
+ Call `graph_ensure` to validate the entire code graph stack: FalkorDB container, CGC connection, repo indexing. This tool auto-repairs common issues (starts stopped containers, detects the right host). If it reports errors it couldn't fix, tell the user what's wrong and how to fix it. If the repo isn't indexed, call `index_project`.
68
68
 
69
69
  **After checking, edit the handoff to check off:** `- [x] graph`
70
70