MCPcopy
hub / github.com/colbymchenry/codegraph / handleImpact

Method handleImpact

src/mcp/tools.ts:1680–1739  ·  view source on GitHub ↗

* Handle codegraph_impact

(args: Record<string, unknown>)

Source from the content-addressed store, hash-verified

1678 * Handle codegraph_impact
1679 */
1680 private async handleImpact(args: Record<string, unknown>): Promise<ToolResult> {
1681 const symbol = this.validateString(args.symbol, 'symbol');
1682 if (typeof symbol !== 'string') return symbol;
1683
1684 const cg = this.getCodeGraph(args.projectPath as string | undefined);
1685 const depth = clamp((args.depth as number) || 2, 1, 10);
1686 const fileFilter = typeof args.file === 'string' ? args.file : undefined;
1687
1688 const allMatches = this.findAllSymbols(cg, symbol);
1689 if (allMatches.nodes.length === 0) {
1690 return this.textResult(`Symbol "${symbol}" not found in the codebase`);
1691 }
1692
1693 const { groups, filteredOut } = this.groupDefinitions(allMatches.nodes, fileFilter);
1694 const filterNote = filteredOut
1695 ? `\n\n> **Note:** no definition of "${symbol}" matches file "${fileFilter}" — showing all definitions instead.`
1696 : '';
1697
1698 const impactOf = (defNodes: Node[]) => {
1699 const mergedNodes = new Map<string, Node>();
1700 const mergedEdges: Edge[] = [];
1701 const seenEdges = new Set<string>();
1702 for (const node of defNodes) {
1703 const impact = cg.getImpactRadius(node.id, depth);
1704 for (const [id, n] of impact.nodes) {
1705 mergedNodes.set(id, n);
1706 }
1707 for (const e of impact.edges) {
1708 const key = `${e.source}->${e.target}:${e.kind}`;
1709 if (!seenEdges.has(key)) {
1710 seenEdges.add(key);
1711 mergedEdges.push(e);
1712 }
1713 }
1714 }
1715 return { nodes: mergedNodes, edges: mergedEdges, roots: defNodes.map((n) => n.id) };
1716 };
1717
1718 // Single definition (or same-file overloads): the familiar merged report.
1719 if (groups.length === 1) {
1720 const formatted = this.formatImpact(symbol, impactOf(groups[0]!)) + (fileFilter && !filteredOut ? "" : allMatches.note) + filterNote;
1721 return this.textResult(this.truncateOutput(formatted));
1722 }
1723
1724 // Multiple DISTINCT definitions (#764): a blast radius PER definition —
1725 // merging unrelated same-named classes (one UserService per monorepo app)
1726 // overstated impact and confused agents. Narrow with `file`.
1727 const sections: string[] = [
1728 `**Impact of ${symbol} — ${groups.length} distinct definitions (each with its own blast radius; narrow with \`file\`)**`,
1729 ];
1730 for (const group of groups) {
1731 const head = group[0]!;
1732 const line = head.startLine ? `:${head.startLine}` : '';
1733 sections.push(
1734 '',
1735 this.formatImpact(`${head.qualifiedName} (${head.filePath}${line})`, impactOf(group))
1736 );
1737 }

Callers 1

dispatchToolMethod · 0.95

Calls 9

validateStringMethod · 0.95
getCodeGraphMethod · 0.95
findAllSymbolsMethod · 0.95
textResultMethod · 0.95
groupDefinitionsMethod · 0.95
formatImpactMethod · 0.95
truncateOutputMethod · 0.95
clampFunction · 0.90
joinMethod · 0.80

Tested by

no test coverage detected