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

Method handleImpact

src/mcp/tools.ts:1787–1846  ·  view source on GitHub ↗

* Handle codegraph_impact

(args: Record<string, unknown>)

Source from the content-addressed store, hash-verified

1785 * Handle codegraph_impact
1786 */
1787 private async handleImpact(args: Record<string, unknown>): Promise<ToolResult> {
1788 const symbol = this.validateString(args.symbol, 'symbol');
1789 if (typeof symbol !== 'string') return symbol;
1790
1791 const cg = this.getCodeGraph(args.projectPath as string | undefined);
1792 const depth = clamp((args.depth as number) || 2, 1, 10);
1793 const fileFilter = typeof args.file === 'string' ? args.file : undefined;
1794
1795 const allMatches = this.findAllSymbols(cg, symbol);
1796 if (allMatches.nodes.length === 0) {
1797 return this.textResult(`Symbol "${symbol}" not found in the codebase`);
1798 }
1799
1800 const { groups, filteredOut } = this.groupDefinitions(allMatches.nodes, fileFilter);
1801 const filterNote = filteredOut
1802 ? `\n\n> **Note:** no definition of "${symbol}" matches file "${fileFilter}" — showing all definitions instead.`
1803 : '';
1804
1805 const impactOf = (defNodes: Node[]) => {
1806 const mergedNodes = new Map<string, Node>();
1807 const mergedEdges: Edge[] = [];
1808 const seenEdges = new Set<string>();
1809 for (const node of defNodes) {
1810 const impact = cg.getImpactRadius(node.id, depth);
1811 for (const [id, n] of impact.nodes) {
1812 mergedNodes.set(id, n);
1813 }
1814 for (const e of impact.edges) {
1815 const key = `${e.source}->${e.target}:${e.kind}`;
1816 if (!seenEdges.has(key)) {
1817 seenEdges.add(key);
1818 mergedEdges.push(e);
1819 }
1820 }
1821 }
1822 return { nodes: mergedNodes, edges: mergedEdges, roots: defNodes.map((n) => n.id) };
1823 };
1824
1825 // Single definition (or same-file overloads): the familiar merged report.
1826 if (groups.length === 1) {
1827 const formatted = this.formatImpact(symbol, impactOf(groups[0]!)) + (fileFilter && !filteredOut ? "" : allMatches.note) + filterNote;
1828 return this.textResult(this.truncateOutput(formatted));
1829 }
1830
1831 // Multiple DISTINCT definitions (#764): a blast radius PER definition —
1832 // merging unrelated same-named classes (one UserService per monorepo app)
1833 // overstated impact and confused agents. Narrow with `file`.
1834 const sections: string[] = [
1835 `**Impact of ${symbol} — ${groups.length} distinct definitions (each with its own blast radius; narrow with \`file\`)**`,
1836 ];
1837 for (const group of groups) {
1838 const head = group[0]!;
1839 const line = head.startLine ? `:${head.startLine}` : '';
1840 sections.push(
1841 '',
1842 this.formatImpact(`${head.qualifiedName} (${head.filePath}${line})`, impactOf(group))
1843 );
1844 }

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.45

Tested by

no test coverage detected