@colbymchenry/codegraph-darwin-x64 1.1.3 → 1.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/dist/extraction/index.d.ts.map +1 -1
- package/lib/dist/extraction/index.js +50 -11
- package/lib/dist/extraction/index.js.map +1 -1
- package/lib/dist/extraction/languages/c-cpp.d.ts +23 -0
- package/lib/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/lib/dist/extraction/languages/c-cpp.js +34 -1
- package/lib/dist/extraction/languages/c-cpp.js.map +1 -1
- package/lib/dist/mcp/tools.d.ts.map +1 -1
- package/lib/dist/mcp/tools.js +103 -1
- package/lib/dist/mcp/tools.js.map +1 -1
- package/lib/node_modules/.package-lock.json +1 -1
- package/lib/package.json +1 -1
- package/package.json +1 -1
package/lib/dist/mcp/tools.js
CHANGED
|
@@ -2435,11 +2435,24 @@ class ToolHandler {
|
|
|
2435
2435
|
// trace endpoint picker uses) and inject it as an entry, so every symbol the
|
|
2436
2436
|
// agent explicitly named is in the subgraph and its file is scored.
|
|
2437
2437
|
const namedSeedIds = new Set();
|
|
2438
|
+
// The subset of named seeds that earns the named-FIRST sort tier. We still
|
|
2439
|
+
// SEED every ≤3-def name (so RWR / flow ranking is unchanged), but only the
|
|
2440
|
+
// most-substantive def is tiered — a bare name's unrelated namesakes (Go's
|
|
2441
|
+
// `NewClient` = real client + test fake + xds pool) must not fill the tier
|
|
2442
|
+
// and crowd out the real answer file (grpc's `dialoptions.go`). Corroborated
|
|
2443
|
+
// overloads (the query also named the type) all earn it. (#1064)
|
|
2444
|
+
const tierSeedIds = new Set();
|
|
2438
2445
|
{
|
|
2439
2446
|
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)$/i;
|
|
2440
2447
|
const CALLABLE = new Set(['method', 'function', 'component', 'constructor']);
|
|
2441
2448
|
const isTestPath = (p) => /(^|\/)(tests?|specs?|__tests__|testdata|mocks?|fixtures?)\//i.test(p) || /\.(test|spec)\.[a-z]+$/i.test(p);
|
|
2442
2449
|
const bodyLines = (n) => Math.max(0, (n.endLine ?? n.startLine) - n.startLine);
|
|
2450
|
+
const callerCount = (n) => { try {
|
|
2451
|
+
return cg.getCallers(n.id).length;
|
|
2452
|
+
}
|
|
2453
|
+
catch {
|
|
2454
|
+
return 0;
|
|
2455
|
+
} };
|
|
2443
2456
|
const tokens = [...new Set(query.split(/[\s,()[\]]+/)
|
|
2444
2457
|
.map((t) => t.replace(FILE_EXT, '').trim())
|
|
2445
2458
|
.filter((t) => t.length >= 3 && /^[A-Za-z_$][\w$]*(?:(?:::|\.)[\w$]+)*$/.test(t)))].slice(0, 16);
|
|
@@ -2475,12 +2488,23 @@ class ToolHandler {
|
|
|
2475
2488
|
// capped; else fall back to the single most-substantive def. This is the
|
|
2476
2489
|
// explore-side mirror of codegraph_node's overload disambiguation.
|
|
2477
2490
|
let picks;
|
|
2491
|
+
let tierPicks; // subset that earns the named-first tier (#1064)
|
|
2478
2492
|
if (cands.length <= 3) {
|
|
2479
2493
|
picks = cands;
|
|
2494
|
+
// Centrality de-noise: tier the most-substantive def PLUS any co-named
|
|
2495
|
+
// def of comparable centrality (a real overload/wrapper — excalidraw's
|
|
2496
|
+
// `mutateElement` lives in mutateElement.ts, App.tsx AND Scene.ts, all
|
|
2497
|
+
// within ~2x callers). EXCLUDE a vastly-less-central namesake (Go's
|
|
2498
|
+
// `NewClient`: real client 492 callers vs xds-pool 11, test-fake 3 →
|
|
2499
|
+
// ratio <0.025) so it doesn't fill the tier and crowd out the answer.
|
|
2500
|
+
const counts = new Map(cands.map((c) => [c.id, callerCount(c)]));
|
|
2501
|
+
const maxCallers = Math.max(1, ...counts.values());
|
|
2502
|
+
tierPicks = cands.filter((c, i) => i === 0 || (counts.get(c.id) ?? 0) >= maxCallers * 0.25);
|
|
2480
2503
|
}
|
|
2481
2504
|
else {
|
|
2482
2505
|
const ctx = cands.filter(inNamedContext);
|
|
2483
2506
|
picks = ctx.length > 0 ? ctx.slice(0, 4) : cands.slice(0, 1);
|
|
2507
|
+
tierPicks = picks; // corroborated overloads (or the single fallback) all earn it
|
|
2484
2508
|
}
|
|
2485
2509
|
for (const n of picks) {
|
|
2486
2510
|
if (!subgraph.nodes.has(n.id))
|
|
@@ -2492,6 +2516,8 @@ class ToolHandler {
|
|
|
2492
2516
|
// so a named symbol FTS already gathered never sorted to the top.)
|
|
2493
2517
|
namedSeedIds.add(n.id);
|
|
2494
2518
|
}
|
|
2519
|
+
for (const n of tierPicks)
|
|
2520
|
+
tierSeedIds.add(n.id);
|
|
2495
2521
|
}
|
|
2496
2522
|
}
|
|
2497
2523
|
// Step 2: Group nodes by file, score by relevance
|
|
@@ -2505,6 +2531,46 @@ class ToolHandler {
|
|
|
2505
2531
|
if (entryNodeIds.has(edge.target))
|
|
2506
2532
|
connectedToEntry.add(edge.source);
|
|
2507
2533
|
}
|
|
2534
|
+
// CHANGE SURFACE (#1064): a named method's signature types — its parameter
|
|
2535
|
+
// and return types — are part of what you'd edit to "add a parameter to X",
|
|
2536
|
+
// yet they can be lexically dissimilar to the query ("add a parameter to
|
|
2537
|
+
// NewClient" shares no words with `dialoptions.go`, which defines NewClient's
|
|
2538
|
+
// `DialOption`) and sit a hop away. COLLECT them here from each named-seed
|
|
2539
|
+
// callable's outgoing signature edges (full graph — the type is often not in
|
|
2540
|
+
// the subgraph); the decision to surface one is DEFERRED to the buried-rescue
|
|
2541
|
+
// pass below, which fires only when the type's file would otherwise be
|
|
2542
|
+
// dropped — so a well-connected type (excalidraw's element types, Alamofire's
|
|
2543
|
+
// `DataRequest` on a flow query) is left to rank on its own and never
|
|
2544
|
+
// displaces a flow-central file. Bounded: only the few named seeds, only the
|
|
2545
|
+
// types in their signatures.
|
|
2546
|
+
const CALLABLE_KINDS = new Set(['method', 'function', 'component', 'constructor']);
|
|
2547
|
+
const TYPE_KINDS = new Set(['class', 'struct', 'interface', 'trait', 'protocol', 'enum', 'type_alias']);
|
|
2548
|
+
const SIG_EDGE = new Set(['references', 'type_of', 'returns']);
|
|
2549
|
+
const changeSurfaceCandidates = [];
|
|
2550
|
+
const seenChangeSurface = new Set();
|
|
2551
|
+
for (const seedId of tierSeedIds) {
|
|
2552
|
+
const seedNode = subgraph.nodes.get(seedId);
|
|
2553
|
+
if (!seedNode || !CALLABLE_KINDS.has(seedNode.kind))
|
|
2554
|
+
continue;
|
|
2555
|
+
let outs = [];
|
|
2556
|
+
try {
|
|
2557
|
+
outs = cg.getOutgoingEdges(seedId);
|
|
2558
|
+
}
|
|
2559
|
+
catch {
|
|
2560
|
+
continue;
|
|
2561
|
+
}
|
|
2562
|
+
for (const e of outs) {
|
|
2563
|
+
if (!SIG_EDGE.has(e.kind))
|
|
2564
|
+
continue;
|
|
2565
|
+
const tgt = cg.getNode(e.target);
|
|
2566
|
+
if (!tgt || !TYPE_KINDS.has(tgt.kind) || namedSeedIds.has(tgt.id))
|
|
2567
|
+
continue;
|
|
2568
|
+
if (seenChangeSurface.has(tgt.id))
|
|
2569
|
+
continue;
|
|
2570
|
+
seenChangeSurface.add(tgt.id);
|
|
2571
|
+
changeSurfaceCandidates.push(tgt);
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2508
2574
|
for (const node of subgraph.nodes.values()) {
|
|
2509
2575
|
// Skip import/export nodes — they add noise without information
|
|
2510
2576
|
if (node.kind === 'import' || node.kind === 'export')
|
|
@@ -2624,6 +2690,36 @@ class ToolHandler {
|
|
|
2624
2690
|
if (n)
|
|
2625
2691
|
entryFiles.add(n.filePath);
|
|
2626
2692
|
}
|
|
2693
|
+
// Buried-rescue pass (#1064): surface a named method's signature type ONLY
|
|
2694
|
+
// when its file is genuinely buried — near-zero graph mass AND not lexically
|
|
2695
|
+
// matched. That is the invisible case (grpc's `DialOption` → `dialoptions.go`,
|
|
2696
|
+
// g≈0, 0 term hits): reachable but ranked nowhere, so the agent greps. A
|
|
2697
|
+
// well-connected type file (excalidraw element types, Alamofire `DataRequest`)
|
|
2698
|
+
// is NOT buried and is left alone — rescuing it would displace a flow-central
|
|
2699
|
+
// file (App.tsx, Validation.swift). Buried is judged on the PRE-rescue graph,
|
|
2700
|
+
// so injecting the type below can't make it look connected. A rescued file is
|
|
2701
|
+
// injected (so it renders), force-kept (gate + relevantFiles), and tiered.
|
|
2702
|
+
const changeSurfaceFiles = new Set();
|
|
2703
|
+
for (const t of changeSurfaceCandidates) {
|
|
2704
|
+
const fp = t.filePath;
|
|
2705
|
+
const buried = (fileGraphScore.get(fp) ?? 0) < maxGraph * 0.06
|
|
2706
|
+
&& (fileTermHits.get(fp) ?? 0) < 2;
|
|
2707
|
+
if (!buried)
|
|
2708
|
+
continue;
|
|
2709
|
+
changeSurfaceFiles.add(fp);
|
|
2710
|
+
if (!subgraph.nodes.has(t.id))
|
|
2711
|
+
subgraph.nodes.set(t.id, t);
|
|
2712
|
+
let group = fileGroups.get(fp);
|
|
2713
|
+
if (!group) {
|
|
2714
|
+
group = { nodes: [], score: 0 };
|
|
2715
|
+
fileGroups.set(fp, group);
|
|
2716
|
+
}
|
|
2717
|
+
if (!group.nodes.some((n) => n.id === t.id))
|
|
2718
|
+
group.nodes.push(t);
|
|
2719
|
+
group.score = Math.max(group.score, 45);
|
|
2720
|
+
if (!relevantFiles.some(([f]) => f === fp))
|
|
2721
|
+
relevantFiles.push([fp, group]);
|
|
2722
|
+
}
|
|
2627
2723
|
// Relevance gate (so the generous budget is a CEILING, not a target): keep a
|
|
2628
2724
|
// file only if it is STRUCTURALLY relevant by ANY of:
|
|
2629
2725
|
// - graph score within a fraction of the top (it's on/near the flow), OR
|
|
@@ -2640,6 +2736,7 @@ class ToolHandler {
|
|
|
2640
2736
|
const gated = relevantFiles.filter(([fp]) => (fileGraphScore.get(fp) ?? 0) >= maxGraph * 0.06
|
|
2641
2737
|
|| centralFiles.has(fp)
|
|
2642
2738
|
|| entryFiles.has(fp)
|
|
2739
|
+
|| changeSurfaceFiles.has(fp)
|
|
2643
2740
|
|| (fileTermHits.get(fp) ?? 0) >= 2);
|
|
2644
2741
|
if (gated.length >= 2)
|
|
2645
2742
|
relevantFiles = gated;
|
|
@@ -2654,11 +2751,16 @@ class ToolHandler {
|
|
|
2654
2751
|
// in other files (`Validation.swift`), falls outside the budget, and the
|
|
2655
2752
|
// agent Reads it. The named file is the answer — rank it at the top.
|
|
2656
2753
|
const namedSeedFiles = new Set();
|
|
2657
|
-
for (const id of
|
|
2754
|
+
for (const id of tierSeedIds) {
|
|
2658
2755
|
const n = subgraph.nodes.get(id);
|
|
2659
2756
|
if (n)
|
|
2660
2757
|
namedSeedFiles.add(n.filePath);
|
|
2661
2758
|
}
|
|
2759
|
+
// A rescued change-surface file (only the genuinely-buried ones — see the
|
|
2760
|
+
// buried-rescue pass) is the lexically-dissimilar answer; give it the named
|
|
2761
|
+
// tier so it isn't buried under files that merely share surface words (#1064).
|
|
2762
|
+
for (const fp of changeSurfaceFiles)
|
|
2763
|
+
namedSeedFiles.add(fp);
|
|
2662
2764
|
// Multi-term corroboration tier: a file that is BOTH (a) an entry/central file
|
|
2663
2765
|
// (a search root, named seed, or graph-central hub — i.e. structurally part of
|
|
2664
2766
|
// the answer) AND (b) matched by ≥2 DISTINCT query terms must not be buried by
|