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

Method buildBlastRadiusSection

src/mcp/tools.ts:2368–2418  ·  view source on GitHub ↗

* Compact "blast radius" for the entry symbols of an explore result: who * depends on each (callers) and which test files cover it — LOCATIONS ONLY, * no source, so the agent knows what to update / re-verify before editing * without reaching for a separate impact call. Always-on, but skips

(cg: CodeGraph, subgraph: Subgraph)

Source from the content-addressed store, hash-verified

2366 * qualify so a leaf-only exploration stays clean.
2367 */
2368 private buildBlastRadiusSection(cg: CodeGraph, subgraph: Subgraph): string {
2369 const ROOT_CAP = 5; // only the symbols the query actually targeted
2370 const FILE_CAP = 4; // caller files listed per symbol before "+N more"
2371 const MEANINGFUL = new Set<string>([
2372 'function', 'method', 'class', 'interface', 'struct', 'trait', 'protocol',
2373 'enum', 'type_alias', 'component', 'constant', 'variable', 'property', 'field',
2374 ]);
2375 const rel = (p: string) => p.replace(/\\/g, '/');
2376
2377 const roots = subgraph.roots
2378 .map((id) => subgraph.nodes.get(id))
2379 .filter((n): n is Node => !!n && MEANINGFUL.has(n.kind))
2380 .slice(0, ROOT_CAP);
2381 if (roots.length === 0) return '';
2382
2383 const entries: string[] = [];
2384 for (const root of roots) {
2385 let callers: Array<{ node: Node }> = [];
2386 try { callers = cg.getCallers(root.id) as Array<{ node: Node }>; } catch { /* skip this root */ }
2387
2388 const seen = new Set<string>();
2389 const uniq: Node[] = [];
2390 for (const c of callers) {
2391 if (c?.node && !seen.has(c.node.id)) { seen.add(c.node.id); uniq.push(c.node); }
2392 }
2393 if (uniq.length === 0) continue; // no blast radius → nothing to flag
2394
2395 const callerFiles = [...new Set(uniq.map((n) => rel(n.filePath)))];
2396 const testFiles = callerFiles.filter((f) => isTestFile(f));
2397 const nonTest = callerFiles.filter((f) => !isTestFile(f));
2398
2399 const shown = nonTest.slice(0, FILE_CAP).map((f) => `\`${f}\``).join(', ');
2400 const more = nonTest.length > FILE_CAP ? ` +${nonTest.length - FILE_CAP} more` : '';
2401 const where = nonTest.length > 0 ? ` in ${shown}${more}` : '';
2402 const tests = testFiles.length > 0
2403 ? `; tests: ${testFiles.slice(0, FILE_CAP).map((f) => `\`${f}\``).join(', ')}${testFiles.length > FILE_CAP ? ` +${testFiles.length - FILE_CAP}` : ''}`
2404 : '; ⚠️ no covering tests found';
2405
2406 entries.push(
2407 `- \`${root.name}\` (${rel(root.filePath)}:${root.startLine}) — ${uniq.length} caller${uniq.length === 1 ? '' : 's'}${where}${tests}`,
2408 );
2409 }
2410 if (entries.length === 0) return '';
2411
2412 return [
2413 '**Blast radius — what depends on these (update/verify before editing)**',
2414 '',
2415 ...entries,
2416 '',
2417 ].join('\n');
2418 }
2419
2420 /**
2421 * Graph-connectivity relevance via Random-Walk-with-Restart (personalized

Callers 1

handleExploreMethod · 0.95

Calls 5

isTestFileFunction · 0.90
hasMethod · 0.80
getMethod · 0.65
getCallersMethod · 0.45
joinMethod · 0.45

Tested by

no test coverage detected