MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / computeGraphRelevance

Method computeGraphRelevance

src/mcp/tools.ts:2553–2606  ·  view source on GitHub ↗

* Graph-connectivity relevance via Random-Walk-with-Restart (personalized * PageRank) from the query's matched SEED nodes over the call/reference graph. * * This is the ranking signal text search (FTS/bm25) CANNOT provide, and it's * codegraph's home turf: relevance by STRUCTURE, not wor

(
    nodeIds: string[],
    edges: Edge[],
    seedIds: Set<string>,
  )

Source from the content-addressed store, hash-verified

2551 * it's a few hundred nodes × ~25 iterations — negligible cost.
2552 */
2553 private computeGraphRelevance(
2554 nodeIds: string[],
2555 edges: Edge[],
2556 seedIds: Set<string>,
2557 ): Map<string, number> {
2558 const out = new Map<string, number>();
2559 const n = nodeIds.length;
2560 if (n === 0) return out;
2561 const idx = new Map<string, number>();
2562 for (let i = 0; i < n; i++) idx.set(nodeIds[i]!, i);
2563
2564 const RANK_EDGES = new Set<string>([
2565 'calls', 'references', 'extends', 'implements', 'overrides',
2566 'instantiates', 'returns', 'type_of', 'imports',
2567 ]);
2568 const adj: number[][] = Array.from({ length: n }, () => []);
2569 for (const e of edges) {
2570 if (!RANK_EDGES.has(e.kind)) continue;
2571 const i = idx.get(e.source);
2572 const j = idx.get(e.target);
2573 if (i === undefined || j === undefined || i === j) continue;
2574 adj[i]!.push(j);
2575 adj[j]!.push(i); // undirected — reachable either direction
2576 }
2577
2578 // Restart vector: uniform over seeds present in the candidate set. (Falls
2579 // back to uniform-over-all if no seed landed in the set, so we never return
2580 // all-zero.)
2581 const r = new Array<number>(n).fill(0);
2582 let rsum = 0;
2583 for (const id of seedIds) {
2584 const i = idx.get(id);
2585 if (i !== undefined) { r[i] = 1; rsum += 1; }
2586 }
2587 if (rsum === 0) { for (let i = 0; i < n; i++) r[i] = 1; rsum = n; }
2588 for (let i = 0; i < n; i++) r[i]! /= rsum;
2589
2590 const alpha = 0.25;
2591 let s = r.slice();
2592 for (let iter = 0; iter < 25; iter++) {
2593 const next = new Array<number>(n).fill(0);
2594 for (let i = 0; i < n; i++) {
2595 const si = s[i]!;
2596 if (si === 0) continue;
2597 const d = adj[i]!.length;
2598 if (d === 0) { next[i]! += si; continue; } // dangling: keep its mass
2599 const share = si / d;
2600 for (const j of adj[i]!) next[j]! += share;
2601 }
2602 for (let i = 0; i < n; i++) s[i] = (1 - alpha) * next[i]! + alpha * r[i]!;
2603 }
2604 for (let i = 0; i < n; i++) out.set(nodeIds[i]!, s[i]!);
2605 return out;
2606 }
2607
2608 /**
2609 * Handle codegraph_explore — deep exploration in a single call

Callers 1

handleExploreMethod · 0.95

Calls 3

hasMethod · 0.80
getMethod · 0.65
setMethod · 0.45

Tested by

no test coverage detected