@kage-core/kage-graph-mcp 2.2.5 → 2.2.6
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/dist/kernel.js +20 -5
- package/package.json +1 -1
package/dist/kernel.js
CHANGED
|
@@ -8533,6 +8533,12 @@ const TRUTH_COMMON_SYMBOL_NAMES = new Set([
|
|
|
8533
8533
|
"build", "parse", "load", "save", "update", "delete", "remove", "test", "validate",
|
|
8534
8534
|
"format", "process", "next", "send", "write", "read", "config", "helper", "util",
|
|
8535
8535
|
]);
|
|
8536
|
+
// Convention-named local closures that collide across unrelated code by idiom,
|
|
8537
|
+
// not duplication. Kept separate from common-names so the intent is clear.
|
|
8538
|
+
const TRUTH_DUPLICATE_NAME_DENYLIST = new Set([
|
|
8539
|
+
"decorator", "wrapper", "inner", "callback", "wrapped", "fn", "cb", "noop",
|
|
8540
|
+
"predicate", "comparator", "getter", "setter", "factory", "visit",
|
|
8541
|
+
]);
|
|
8536
8542
|
function truthExcludedPath(path) {
|
|
8537
8543
|
return /(^|\/)(tests?|__tests__|specs?|examples?|fixtures?|benchmarks?|mocks?|__mocks__|vendor|node_modules|dist|build)\//i.test(path)
|
|
8538
8544
|
|| /\.(test|spec)\.[^.]+$/i.test(path)
|
|
@@ -8619,7 +8625,14 @@ function truthReport(projectDir) {
|
|
|
8619
8625
|
// 1a. Duplicate implementations: same-name symbols spread across directories.
|
|
8620
8626
|
const symbolsByName = new Map();
|
|
8621
8627
|
for (const symbol of graph.symbols) {
|
|
8622
|
-
|
|
8628
|
+
// Methods are excluded: same-named methods on different classes (__init__,
|
|
8629
|
+
// to_dict, validate, ...) are normal polymorphism, not duplication. Only
|
|
8630
|
+
// top-level functions and classes can be genuine parallel implementations.
|
|
8631
|
+
if (!["function", "class"].includes(symbol.kind))
|
|
8632
|
+
continue;
|
|
8633
|
+
// Dunders and convention-named local closures (decorator/wrapper/inner/...)
|
|
8634
|
+
// collide by language idiom across unrelated code; never real duplicates.
|
|
8635
|
+
if (/^__.*__$/.test(symbol.name) || TRUTH_DUPLICATE_NAME_DENYLIST.has(symbol.name.toLowerCase()))
|
|
8623
8636
|
continue;
|
|
8624
8637
|
if (symbol.name.length < 4 || TRUTH_COMMON_SYMBOL_NAMES.has(symbol.name.toLowerCase()))
|
|
8625
8638
|
continue;
|
|
@@ -8641,14 +8654,16 @@ function truthReport(projectDir) {
|
|
|
8641
8654
|
signatureCounts.set(normalized, (signatureCounts.get(normalized) ?? 0) + 1);
|
|
8642
8655
|
}
|
|
8643
8656
|
const signatureMatch = [...signatureCounts.values()].some((count) => count >= 2);
|
|
8657
|
+
// A same-name-only collision across dirs is weak signal and the source of
|
|
8658
|
+
// most false positives. Require a matching signature to report it at all.
|
|
8659
|
+
if (!signatureMatch)
|
|
8660
|
+
continue;
|
|
8644
8661
|
const newestEpoch = Math.max(0, ...members.map((member) => fileNewestEpoch.get(member.path) ?? 0));
|
|
8645
8662
|
const recent = hasGit && newestEpoch > aiEraCutoff;
|
|
8646
8663
|
duplicateFindings.push({
|
|
8647
8664
|
kind: "duplicate_cluster",
|
|
8648
|
-
title: `${members[0].name} — ${paths.size} implementations across ${dirs.size} directories${recent ? " [
|
|
8649
|
-
detail:
|
|
8650
|
-
? "Same name AND near-identical signature: almost certainly parallel implementations of the same idea."
|
|
8651
|
-
: "Same name in unrelated directories: agents and humans may be solving the same problem twice.",
|
|
8665
|
+
title: `${members[0].name} — ${paths.size} implementations across ${dirs.size} directories${recent ? " [recently changed]" : ""}`,
|
|
8666
|
+
detail: "Same name and near-identical signature in unrelated directories — likely parallel implementations of the same idea, worth a look.",
|
|
8652
8667
|
evidence: members.slice(0, 5).map((member) => `${member.path}:${member.line} ${member.kind} ${member.signature.slice(0, 80)}`),
|
|
8653
8668
|
surprise: Math.min(100, 45 + paths.size * 8 + (signatureMatch ? 15 : 0) + (recent ? 20 : 0)),
|
|
8654
8669
|
});
|