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

Method buildFlowFromNamedSymbols

src/mcp/tools.ts:1954–2220  ·  view source on GitHub ↗

* Flow-from-named-symbols: an agent's codegraph_explore query is a bag of * symbol names that usually spans the flow it's investigating (e.g. * "PmsProductController getList PmsProductService list PmsProductServiceImpl"). * Surface the longest call chain AMONG those named symbols — scoped t

(cg: CodeGraph, query: string)

Source from the content-addressed store, hash-verified

1952 * dropping unrelated `OmsOrderService::list`.
1953 */
1954 private buildFlowFromNamedSymbols(cg: CodeGraph, query: string): { text: string; pathNodeIds: Set<string>; namedNodeIds: Set<string>; uniqueNamedNodeIds: Set<string>; spineCallSites: Map<string, number> } {
1955 // spineCallSites: for each spine node, the line where it CALLS the next hop —
1956 // lets the source assembler window an oversize spine method (e.g. n8n's 962-line
1957 // processRunExecutionData) to the call site instead of dumping the whole body.
1958 const EMPTY = { text: '', pathNodeIds: new Set<string>(), namedNodeIds: new Set<string>(), uniqueNamedNodeIds: new Set<string>(), spineCallSites: new Map<string, number>() };
1959 try {
1960 const CALLABLE = new Set(['method', 'function', 'component', 'constructor']);
1961 // Strip only a REAL file extension (Create.cs → Create); KEEP qualified
1962 // names (Class.method / Class::method) — the agent's most precise input,
1963 // resolved exactly by findAllSymbols. (The old strip mangled Class.method
1964 // into Class, throwing the method away.)
1965 const FILE_EXT = /\.(?:java|kt|kts|ts|tsx|js|jsx|mjs|cjs|cs|py|go|rb|php|swift|rs|cpp|cc|cxx|c|h|hpp|scala|lua|dart|vue|svelte|astro|erl|hrl)$/i;
1966 const tokens = [...new Set(
1967 query.split(/[\s,()[\]]+/)
1968 .map((t) => t.replace(FILE_EXT, '').trim())
1969 .filter((t) => t.length >= 3 && /^[A-Za-z_$][\w$]*(?:(?:::|\.)[\w$]+)*$/.test(t))
1970 )].slice(0, 16);
1971 if (tokens.length < 2) return EMPTY;
1972 // Pool of name SEGMENTS (Class + method from every token) used to
1973 // disambiguate an ambiguous SIMPLE name: keep a candidate only if its
1974 // CONTAINER class is itself named in the query.
1975 const segPool = new Set<string>();
1976 for (const t of tokens) for (const s of t.toLowerCase().split(/::|\./)) if (s) segPool.add(s);
1977 const named = new Map<string, Node>();
1978 // Nodes whose token is SPECIFIC — a (near-)unique callable name (<=3 defs in
1979 // the whole graph). These are safe to SPARE a file on: the agent named THIS
1980 // method (`getResponseWithInterceptorChain`, 1 def). A hyper-polymorphic name
1981 // (`as_sql`, 110 defs across every Expression/Compiler subclass) is NOT here,
1982 // so naming it doesn't keep every backend variant full and flood the budget.
1983 const uniqueNamedNodeIds = new Set<string>();
1984 // token → resolved node ids: drives the token-coverage check that gates
1985 // the dynamic-boundary scan (a token is covered when ANY of its nodes
1986 // lands on the main chain — overloads off the chain don't count against).
1987 const tokenNodes = new Map<string, string[]>();
1988 // token → its full same-name callable family (before the container filter).
1989 // A LARGE family that fails to connect on the chain is a polymorphic
1990 // interface/registry dispatch — surfaced by buildPolymorphicBoundaries below.
1991 const tokenFamily = new Map<string, Node[]>();
1992 // Non-callable endpoints (CONSTANT/VARIABLE/FIELD) connected by a SYNTHESIZED
1993 // edge. RTK thunks are `const X = createAsyncThunk(...)`, so a thunk→thunk hop
1994 // is constant→constant — the CALLABLE-only `named` set can't hold it, and
1995 // without this the hop is invisible to the Flow path at every tier (the
1996 // Relationships section catches it only on repos ≥500 files). Kept SEPARATE
1997 // from `named` (which drives the call-chain + source sizing, callable-only);
1998 // fed only to the dynamic-dispatch-links scan below.
1999 const dynNamed = new Map<string, Node>();
2000 const DYN_KINDS = new Set(['constant', 'variable', 'field', 'property']);
2001 const hasHeuristicEdge = (id: string): boolean =>
2002 [...cg.getCallers(id), ...cg.getCallees(id)].some(({ edge }) => edge.provenance === 'heuristic');
2003 for (const t of tokens) {
2004 const hits = this.findAllSymbols(cg, t).nodes;
2005 const cands = hits.filter((n) => CALLABLE.has(n.kind));
2006 tokenFamily.set(t, cands);
2007 // A qualified or otherwise-specific name (<=3 hits) keeps all; an
2008 // ambiguous simple name keeps only candidates whose container is named.
2009 const specific = cands.length <= 3;
2010 const pick = specific
2011 ? cands

Callers 1

handleExploreMethod · 0.95

Calls 9

findAllSymbolsMethod · 0.95
synthEdgeNoteMethod · 0.95
hasMethod · 0.80
getMethod · 0.65
setMethod · 0.45
joinMethod · 0.45
getCalleesMethod · 0.45

Tested by

no test coverage detected