codesift-mcp 0.1.0 → 0.2.1
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/LICENSE +66 -21
- package/README.md +402 -56
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +11 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/commands.d.ts.map +1 -1
- package/dist/cli/commands.js +177 -67
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.d.ts.map +1 -1
- package/dist/cli/help.js +157 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/hooks.d.ts +3 -0
- package/dist/cli/hooks.d.ts.map +1 -0
- package/dist/cli/hooks.js +163 -0
- package/dist/cli/hooks.js.map +1 -0
- package/dist/cli/setup.d.ts +25 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js +400 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -0
- package/dist/config.js.map +1 -1
- package/dist/formatters-shortening.d.ts +7 -0
- package/dist/formatters-shortening.d.ts.map +1 -0
- package/dist/formatters-shortening.js +68 -0
- package/dist/formatters-shortening.js.map +1 -0
- package/dist/formatters.d.ts +314 -0
- package/dist/formatters.d.ts.map +1 -0
- package/dist/formatters.js +396 -0
- package/dist/formatters.js.map +1 -0
- package/dist/instructions.d.ts +6 -0
- package/dist/instructions.d.ts.map +1 -0
- package/dist/instructions.js +72 -0
- package/dist/instructions.js.map +1 -0
- package/dist/lsp/lsp-client.d.ts +21 -0
- package/dist/lsp/lsp-client.d.ts.map +1 -0
- package/dist/lsp/lsp-client.js +122 -0
- package/dist/lsp/lsp-client.js.map +1 -0
- package/dist/lsp/lsp-manager.d.ts +12 -0
- package/dist/lsp/lsp-manager.d.ts.map +1 -0
- package/dist/lsp/lsp-manager.js +82 -0
- package/dist/lsp/lsp-manager.js.map +1 -0
- package/dist/lsp/lsp-servers.d.ts +13 -0
- package/dist/lsp/lsp-servers.d.ts.map +1 -0
- package/dist/lsp/lsp-servers.js +57 -0
- package/dist/lsp/lsp-servers.js.map +1 -0
- package/dist/lsp/lsp-tools.d.ts +67 -0
- package/dist/lsp/lsp-tools.d.ts.map +1 -0
- package/dist/lsp/lsp-tools.js +359 -0
- package/dist/lsp/lsp-tools.js.map +1 -0
- package/dist/parser/extractors/_shared.d.ts +11 -0
- package/dist/parser/extractors/_shared.d.ts.map +1 -0
- package/dist/parser/extractors/_shared.js +38 -0
- package/dist/parser/extractors/_shared.js.map +1 -0
- package/dist/parser/extractors/astro.d.ts +15 -0
- package/dist/parser/extractors/astro.d.ts.map +1 -0
- package/dist/parser/extractors/astro.js +104 -0
- package/dist/parser/extractors/astro.js.map +1 -0
- package/dist/parser/extractors/conversation.d.ts +16 -0
- package/dist/parser/extractors/conversation.d.ts.map +1 -0
- package/dist/parser/extractors/conversation.js +196 -0
- package/dist/parser/extractors/conversation.js.map +1 -0
- package/dist/parser/extractors/go.d.ts.map +1 -1
- package/dist/parser/extractors/go.js +22 -45
- package/dist/parser/extractors/go.js.map +1 -1
- package/dist/parser/extractors/python.d.ts +1 -1
- package/dist/parser/extractors/python.d.ts.map +1 -1
- package/dist/parser/extractors/python.js +19 -50
- package/dist/parser/extractors/python.js.map +1 -1
- package/dist/parser/extractors/rust.d.ts +1 -1
- package/dist/parser/extractors/rust.d.ts.map +1 -1
- package/dist/parser/extractors/rust.js +7 -34
- package/dist/parser/extractors/rust.js.map +1 -1
- package/dist/parser/extractors/typescript.d.ts +1 -1
- package/dist/parser/extractors/typescript.d.ts.map +1 -1
- package/dist/parser/extractors/typescript.js +99 -68
- package/dist/parser/extractors/typescript.js.map +1 -1
- package/dist/parser/parser-manager.d.ts.map +1 -1
- package/dist/parser/parser-manager.js +12 -2
- package/dist/parser/parser-manager.js.map +1 -1
- package/dist/parser/symbol-extractor.d.ts +2 -0
- package/dist/parser/symbol-extractor.d.ts.map +1 -1
- package/dist/parser/symbol-extractor.js +2 -0
- package/dist/parser/symbol-extractor.js.map +1 -1
- package/dist/register-tools.d.ts +127 -0
- package/dist/register-tools.d.ts.map +1 -0
- package/dist/register-tools.js +1453 -0
- package/dist/register-tools.js.map +1 -0
- package/dist/retrieval/codebase-retrieval.d.ts +4 -26
- package/dist/retrieval/codebase-retrieval.d.ts.map +1 -1
- package/dist/retrieval/codebase-retrieval.js +105 -403
- package/dist/retrieval/codebase-retrieval.js.map +1 -1
- package/dist/retrieval/retrieval-constants.d.ts +27 -0
- package/dist/retrieval/retrieval-constants.d.ts.map +1 -0
- package/dist/retrieval/retrieval-constants.js +27 -0
- package/dist/retrieval/retrieval-constants.js.map +1 -0
- package/dist/retrieval/retrieval-schemas.d.ts +107 -0
- package/dist/retrieval/retrieval-schemas.d.ts.map +1 -0
- package/dist/retrieval/retrieval-schemas.js +102 -0
- package/dist/retrieval/retrieval-schemas.js.map +1 -0
- package/dist/retrieval/retrieval-utils.d.ts +40 -0
- package/dist/retrieval/retrieval-utils.d.ts.map +1 -0
- package/dist/retrieval/retrieval-utils.js +139 -0
- package/dist/retrieval/retrieval-utils.js.map +1 -0
- package/dist/retrieval/semantic-handlers.d.ts +8 -0
- package/dist/retrieval/semantic-handlers.d.ts.map +1 -0
- package/dist/retrieval/semantic-handlers.js +152 -0
- package/dist/retrieval/semantic-handlers.js.map +1 -0
- package/dist/search/bm25.d.ts +6 -1
- package/dist/search/bm25.d.ts.map +1 -1
- package/dist/search/bm25.js +95 -32
- package/dist/search/bm25.js.map +1 -1
- package/dist/search/chunker.d.ts +10 -0
- package/dist/search/chunker.d.ts.map +1 -1
- package/dist/search/chunker.js +63 -11
- package/dist/search/chunker.js.map +1 -1
- package/dist/search/reranker.d.ts +15 -0
- package/dist/search/reranker.d.ts.map +1 -0
- package/dist/search/reranker.js +126 -0
- package/dist/search/reranker.js.map +1 -0
- package/dist/search/semantic.d.ts +1 -1
- package/dist/search/semantic.d.ts.map +1 -1
- package/dist/search/semantic.js +40 -45
- package/dist/search/semantic.js.map +1 -1
- package/dist/server-helpers.d.ts +29 -0
- package/dist/server-helpers.d.ts.map +1 -0
- package/dist/server-helpers.js +312 -0
- package/dist/server-helpers.js.map +1 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +11 -271
- package/dist/server.js.map +1 -1
- package/dist/storage/_shared.d.ts +9 -0
- package/dist/storage/_shared.d.ts.map +1 -0
- package/dist/storage/_shared.js +26 -0
- package/dist/storage/_shared.js.map +1 -0
- package/dist/storage/chunk-store.d.ts.map +1 -1
- package/dist/storage/chunk-store.js +23 -63
- package/dist/storage/chunk-store.js.map +1 -1
- package/dist/storage/embedding-store.d.ts +6 -3
- package/dist/storage/embedding-store.d.ts.map +1 -1
- package/dist/storage/embedding-store.js +54 -30
- package/dist/storage/embedding-store.js.map +1 -1
- package/dist/storage/graph-store.d.ts +48 -0
- package/dist/storage/graph-store.d.ts.map +1 -0
- package/dist/storage/graph-store.js +52 -0
- package/dist/storage/graph-store.js.map +1 -0
- package/dist/storage/index-store.d.ts +5 -0
- package/dist/storage/index-store.d.ts.map +1 -1
- package/dist/storage/index-store.js +28 -16
- package/dist/storage/index-store.js.map +1 -1
- package/dist/storage/registry.d.ts +4 -0
- package/dist/storage/registry.d.ts.map +1 -1
- package/dist/storage/registry.js +16 -16
- package/dist/storage/registry.js.map +1 -1
- package/dist/storage/usage-stats.d.ts +6 -0
- package/dist/storage/usage-stats.d.ts.map +1 -1
- package/dist/storage/usage-stats.js +59 -11
- package/dist/storage/usage-stats.js.map +1 -1
- package/dist/storage/usage-tracker.d.ts +3 -0
- package/dist/storage/usage-tracker.d.ts.map +1 -1
- package/dist/storage/usage-tracker.js +50 -132
- package/dist/storage/usage-tracker.js.map +1 -1
- package/dist/storage/watcher.d.ts +2 -1
- package/dist/storage/watcher.d.ts.map +1 -1
- package/dist/storage/watcher.js +16 -16
- package/dist/storage/watcher.js.map +1 -1
- package/dist/tools/ast-query-tools.d.ts +29 -0
- package/dist/tools/ast-query-tools.d.ts.map +1 -0
- package/dist/tools/ast-query-tools.js +110 -0
- package/dist/tools/ast-query-tools.js.map +1 -0
- package/dist/tools/boundary-tools.d.ts +31 -0
- package/dist/tools/boundary-tools.d.ts.map +1 -0
- package/dist/tools/boundary-tools.js +62 -0
- package/dist/tools/boundary-tools.js.map +1 -0
- package/dist/tools/clone-tools.d.ts +35 -0
- package/dist/tools/clone-tools.d.ts.map +1 -0
- package/dist/tools/clone-tools.js +181 -0
- package/dist/tools/clone-tools.js.map +1 -0
- package/dist/tools/community-tools.d.ts +23 -0
- package/dist/tools/community-tools.d.ts.map +1 -0
- package/dist/tools/community-tools.js +297 -0
- package/dist/tools/community-tools.js.map +1 -0
- package/dist/tools/complexity-tools.d.ts +34 -0
- package/dist/tools/complexity-tools.d.ts.map +1 -0
- package/dist/tools/complexity-tools.js +135 -0
- package/dist/tools/complexity-tools.js.map +1 -0
- package/dist/tools/context-tools.d.ts +44 -3
- package/dist/tools/context-tools.d.ts.map +1 -1
- package/dist/tools/context-tools.js +329 -99
- package/dist/tools/context-tools.js.map +1 -1
- package/dist/tools/conversation-tools.d.ts +107 -0
- package/dist/tools/conversation-tools.d.ts.map +1 -0
- package/dist/tools/conversation-tools.js +419 -0
- package/dist/tools/conversation-tools.js.map +1 -0
- package/dist/tools/coordinator-tools.d.ts +73 -0
- package/dist/tools/coordinator-tools.d.ts.map +1 -0
- package/dist/tools/coordinator-tools.js +153 -0
- package/dist/tools/coordinator-tools.js.map +1 -0
- package/dist/tools/cross-repo-tools.d.ts +43 -0
- package/dist/tools/cross-repo-tools.d.ts.map +1 -0
- package/dist/tools/cross-repo-tools.js +55 -0
- package/dist/tools/cross-repo-tools.js.map +1 -0
- package/dist/tools/diff-tools.d.ts +4 -1
- package/dist/tools/diff-tools.d.ts.map +1 -1
- package/dist/tools/diff-tools.js +23 -5
- package/dist/tools/diff-tools.js.map +1 -1
- package/dist/tools/frequency-tools.d.ts +46 -0
- package/dist/tools/frequency-tools.d.ts.map +1 -0
- package/dist/tools/frequency-tools.js +184 -0
- package/dist/tools/frequency-tools.js.map +1 -0
- package/dist/tools/generate-tools.d.ts.map +1 -1
- package/dist/tools/generate-tools.js +13 -2
- package/dist/tools/generate-tools.js.map +1 -1
- package/dist/tools/graph-tools.d.ts +44 -11
- package/dist/tools/graph-tools.d.ts.map +1 -1
- package/dist/tools/graph-tools.js +147 -104
- package/dist/tools/graph-tools.js.map +1 -1
- package/dist/tools/hotspot-tools.d.ts +24 -0
- package/dist/tools/hotspot-tools.d.ts.map +1 -0
- package/dist/tools/hotspot-tools.js +122 -0
- package/dist/tools/hotspot-tools.js.map +1 -0
- package/dist/tools/impact-tools.d.ts +13 -0
- package/dist/tools/impact-tools.d.ts.map +1 -0
- package/dist/tools/impact-tools.js +238 -0
- package/dist/tools/impact-tools.js.map +1 -0
- package/dist/tools/index-tools.d.ts +44 -3
- package/dist/tools/index-tools.d.ts.map +1 -1
- package/dist/tools/index-tools.js +530 -222
- package/dist/tools/index-tools.js.map +1 -1
- package/dist/tools/memory-tools.d.ts +35 -0
- package/dist/tools/memory-tools.d.ts.map +1 -0
- package/dist/tools/memory-tools.js +229 -0
- package/dist/tools/memory-tools.js.map +1 -0
- package/dist/tools/outline-tools.d.ts +24 -13
- package/dist/tools/outline-tools.d.ts.map +1 -1
- package/dist/tools/outline-tools.js +113 -87
- package/dist/tools/outline-tools.js.map +1 -1
- package/dist/tools/pattern-tools.d.ts +32 -0
- package/dist/tools/pattern-tools.d.ts.map +1 -0
- package/dist/tools/pattern-tools.js +116 -0
- package/dist/tools/pattern-tools.js.map +1 -0
- package/dist/tools/report-tools.d.ts +5 -0
- package/dist/tools/report-tools.d.ts.map +1 -0
- package/dist/tools/report-tools.js +167 -0
- package/dist/tools/report-tools.js.map +1 -0
- package/dist/tools/review-diff-tools.d.ts +148 -0
- package/dist/tools/review-diff-tools.d.ts.map +1 -0
- package/dist/tools/review-diff-tools.js +852 -0
- package/dist/tools/review-diff-tools.js.map +1 -0
- package/dist/tools/route-tools.d.ts +32 -0
- package/dist/tools/route-tools.d.ts.map +1 -0
- package/dist/tools/route-tools.js +276 -0
- package/dist/tools/route-tools.js.map +1 -0
- package/dist/tools/search-ranker.d.ts +5 -0
- package/dist/tools/search-ranker.d.ts.map +1 -0
- package/dist/tools/search-ranker.js +142 -0
- package/dist/tools/search-ranker.js.map +1 -0
- package/dist/tools/search-tools.d.ts +24 -1
- package/dist/tools/search-tools.d.ts.map +1 -1
- package/dist/tools/search-tools.js +459 -225
- package/dist/tools/search-tools.js.map +1 -1
- package/dist/tools/secret-tools.d.ts +104 -0
- package/dist/tools/secret-tools.d.ts.map +1 -0
- package/dist/tools/secret-tools.js +410 -0
- package/dist/tools/secret-tools.js.map +1 -0
- package/dist/tools/symbol-tools.d.ts +90 -2
- package/dist/tools/symbol-tools.d.ts.map +1 -1
- package/dist/tools/symbol-tools.js +576 -42
- package/dist/tools/symbol-tools.js.map +1 -1
- package/dist/types.d.ts +34 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/framework-detect.d.ts +5 -0
- package/dist/utils/framework-detect.d.ts.map +1 -0
- package/dist/utils/framework-detect.js +36 -0
- package/dist/utils/framework-detect.js.map +1 -0
- package/dist/utils/glob.d.ts +19 -0
- package/dist/utils/glob.d.ts.map +1 -0
- package/dist/utils/glob.js +74 -0
- package/dist/utils/glob.js.map +1 -0
- package/dist/utils/import-graph.d.ts +29 -0
- package/dist/utils/import-graph.d.ts.map +1 -0
- package/dist/utils/import-graph.js +125 -0
- package/dist/utils/import-graph.js.map +1 -0
- package/dist/utils/test-file.d.ts.map +1 -1
- package/dist/utils/test-file.js +1 -0
- package/dist/utils/test-file.js.map +1 -1
- package/dist/utils/walk.d.ts +45 -0
- package/dist/utils/walk.d.ts.map +1 -0
- package/dist/utils/walk.js +87 -0
- package/dist/utils/walk.js.map +1 -0
- package/package.json +12 -5
- package/rules/codesift.md +187 -0
- package/rules/codesift.mdc +192 -0
- package/rules/codex.md +187 -0
- package/rules/gemini.md +187 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { getCodeIndex } from "./index-tools.js";
|
|
2
|
+
import { collectImportEdges } from "../utils/import-graph.js";
|
|
3
|
+
/**
|
|
4
|
+
* Check architecture boundary rules against the import graph.
|
|
5
|
+
*
|
|
6
|
+
* Rules use path substring matching:
|
|
7
|
+
* { from: "src/domain", cannot_import: ["src/infrastructure", "src/api"] }
|
|
8
|
+
* { from: "src/api", can_only_import: ["src/domain", "src/application"] }
|
|
9
|
+
*
|
|
10
|
+
* `cannot_import` — files matching `from` must NOT import files matching any listed pattern.
|
|
11
|
+
* `can_only_import` — files matching `from` may ONLY import files matching one of the listed patterns.
|
|
12
|
+
*/
|
|
13
|
+
export async function checkBoundaries(repo, rules, options) {
|
|
14
|
+
if (!rules.length) {
|
|
15
|
+
return { violations: [], edges_checked: 0, rules_applied: 0, passed: true };
|
|
16
|
+
}
|
|
17
|
+
const index = await getCodeIndex(repo);
|
|
18
|
+
if (!index)
|
|
19
|
+
throw new Error(`Repository not found: ${repo}`);
|
|
20
|
+
const edges = await collectImportEdges(index);
|
|
21
|
+
const violations = [];
|
|
22
|
+
let edgesChecked = 0;
|
|
23
|
+
for (const edge of edges) {
|
|
24
|
+
if (options?.file_pattern && !edge.from.includes(options.file_pattern))
|
|
25
|
+
continue;
|
|
26
|
+
edgesChecked++;
|
|
27
|
+
for (const rule of rules) {
|
|
28
|
+
if (!edge.from.includes(rule.from))
|
|
29
|
+
continue;
|
|
30
|
+
if (rule.cannot_import) {
|
|
31
|
+
for (const forbidden of rule.cannot_import) {
|
|
32
|
+
if (edge.to.includes(forbidden)) {
|
|
33
|
+
violations.push({
|
|
34
|
+
file: edge.from,
|
|
35
|
+
imports: edge.to,
|
|
36
|
+
rule_from: rule.from,
|
|
37
|
+
reason: `"${rule.from}" cannot import "${forbidden}"`,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (rule.can_only_import) {
|
|
43
|
+
const allowed = rule.can_only_import.some((pattern) => edge.to.includes(pattern));
|
|
44
|
+
if (!allowed) {
|
|
45
|
+
violations.push({
|
|
46
|
+
file: edge.from,
|
|
47
|
+
imports: edge.to,
|
|
48
|
+
rule_from: rule.from,
|
|
49
|
+
reason: `"${rule.from}" can only import [${rule.can_only_import.join(", ")}]`,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
violations,
|
|
57
|
+
edges_checked: edgesChecked,
|
|
58
|
+
rules_applied: rules.length,
|
|
59
|
+
passed: violations.length === 0,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=boundary-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"boundary-tools.js","sourceRoot":"","sources":["../../src/tools/boundary-tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAsB9D;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,KAAqB,EACrB,OAA+C;IAE/C,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,aAAa,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAC9E,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;IACvC,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,yBAAyB,IAAI,EAAE,CAAC,CAAC;IAE7D,MAAM,KAAK,GAAG,MAAM,kBAAkB,CAAC,KAAK,CAAC,CAAC;IAE9C,MAAM,UAAU,GAAwB,EAAE,CAAC;IAC3C,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,OAAO,EAAE,YAAY,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,YAAY,CAAC;YAAE,SAAS;QACjF,YAAY,EAAE,CAAC;QAEf,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,SAAS;YAE7C,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;gBACvB,KAAK,MAAM,SAAS,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;oBAC3C,IAAI,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;wBAChC,UAAU,CAAC,IAAI,CAAC;4BACd,IAAI,EAAE,IAAI,CAAC,IAAI;4BACf,OAAO,EAAE,IAAI,CAAC,EAAE;4BAChB,SAAS,EAAE,IAAI,CAAC,IAAI;4BACpB,MAAM,EAAE,IAAI,IAAI,CAAC,IAAI,oBAAoB,SAAS,GAAG;yBACtD,CAAC,CAAC;oBACL,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;gBACzB,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;gBAClF,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,UAAU,CAAC,IAAI,CAAC;wBACd,IAAI,EAAE,IAAI,CAAC,IAAI;wBACf,OAAO,EAAE,IAAI,CAAC,EAAE;wBAChB,SAAS,EAAE,IAAI,CAAC,IAAI;wBACpB,MAAM,EAAE,IAAI,IAAI,CAAC,IAAI,sBAAsB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;qBAC9E,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,UAAU;QACV,aAAa,EAAE,YAAY;QAC3B,aAAa,EAAE,KAAK,CAAC,MAAM;QAC3B,MAAM,EAAE,UAAU,CAAC,MAAM,KAAK,CAAC;KAChC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { SymbolKind } from "../types.js";
|
|
2
|
+
export interface CodeClone {
|
|
3
|
+
symbol_a: {
|
|
4
|
+
name: string;
|
|
5
|
+
kind: SymbolKind;
|
|
6
|
+
file: string;
|
|
7
|
+
start_line: number;
|
|
8
|
+
end_line: number;
|
|
9
|
+
};
|
|
10
|
+
symbol_b: {
|
|
11
|
+
name: string;
|
|
12
|
+
kind: SymbolKind;
|
|
13
|
+
file: string;
|
|
14
|
+
start_line: number;
|
|
15
|
+
end_line: number;
|
|
16
|
+
};
|
|
17
|
+
similarity: number;
|
|
18
|
+
shared_lines: number;
|
|
19
|
+
}
|
|
20
|
+
export interface CloneResult {
|
|
21
|
+
clones: CodeClone[];
|
|
22
|
+
scanned_symbols: number;
|
|
23
|
+
threshold: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Find code clones: pairs of symbols with similar normalized source.
|
|
27
|
+
* Uses hash-based bucketing for O(n) average case instead of O(n²) all-pairs.
|
|
28
|
+
*/
|
|
29
|
+
export declare function findClones(repo: string, options?: {
|
|
30
|
+
file_pattern?: string | undefined;
|
|
31
|
+
min_similarity?: number | undefined;
|
|
32
|
+
min_lines?: number | undefined;
|
|
33
|
+
include_tests?: boolean | undefined;
|
|
34
|
+
}): Promise<CloneResult>;
|
|
35
|
+
//# sourceMappingURL=clone-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone-tools.d.ts","sourceRoot":"","sources":["../../src/tools/clone-tools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ9C,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACjG,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACjG,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AA2LD;;;GAGG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IACR,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC,GACA,OAAO,CAAC,WAAW,CAAC,CAuBtB"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { getCodeIndex } from "./index-tools.js";
|
|
2
|
+
import { isTestFileStrict as isTestFile } from "../utils/test-file.js";
|
|
3
|
+
const MIN_CLONE_LINES = 10;
|
|
4
|
+
const MAX_CLONES = 50;
|
|
5
|
+
const DEFAULT_MIN_SIMILARITY = 0.7;
|
|
6
|
+
/** Max line-count ratio for near-match comparison (30% tolerance) */
|
|
7
|
+
const MAX_LINE_RATIO = 1.3;
|
|
8
|
+
const ANALYZABLE_KINDS = new Set([
|
|
9
|
+
"function", "method", "class",
|
|
10
|
+
]);
|
|
11
|
+
/**
|
|
12
|
+
* Normalize source for comparison: strip whitespace, comments, string literals.
|
|
13
|
+
* Returns array of normalized non-empty lines.
|
|
14
|
+
*/
|
|
15
|
+
function normalizeSource(source) {
|
|
16
|
+
return source
|
|
17
|
+
.split("\n")
|
|
18
|
+
.map((line) => {
|
|
19
|
+
let l = line.trim();
|
|
20
|
+
// Strip single-line comments
|
|
21
|
+
const commentIdx = l.indexOf("//");
|
|
22
|
+
if (commentIdx >= 0)
|
|
23
|
+
l = l.slice(0, commentIdx).trim();
|
|
24
|
+
// Normalize whitespace
|
|
25
|
+
l = l.replace(/\s+/g, " ");
|
|
26
|
+
return l;
|
|
27
|
+
})
|
|
28
|
+
.filter((l) => l.length > 0 && l !== "{" && l !== "}" && l !== ");");
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Simple fingerprint: hash of normalized lines joined.
|
|
32
|
+
* Uses djb2 for speed (not crypto).
|
|
33
|
+
*/
|
|
34
|
+
function hashLines(lines) {
|
|
35
|
+
let hash = 5381;
|
|
36
|
+
for (const line of lines) {
|
|
37
|
+
for (let i = 0; i < line.length; i++) {
|
|
38
|
+
hash = ((hash << 5) + hash + line.charCodeAt(i)) | 0;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return hash;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Compute line-level similarity between two normalized sources.
|
|
45
|
+
* Uses set intersection of lines (bag-of-lines similarity).
|
|
46
|
+
*/
|
|
47
|
+
function computeSimilarity(linesA, linesB) {
|
|
48
|
+
const setA = new Set(linesA);
|
|
49
|
+
const setB = new Set(linesB);
|
|
50
|
+
let shared = 0;
|
|
51
|
+
for (const line of setA) {
|
|
52
|
+
if (setB.has(line))
|
|
53
|
+
shared++;
|
|
54
|
+
}
|
|
55
|
+
const total = Math.max(setA.size, setB.size);
|
|
56
|
+
return {
|
|
57
|
+
similarity: total > 0 ? Math.round((shared / total) * 100) / 100 : 0,
|
|
58
|
+
sharedLines: shared,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/** Build a CodeClone from two entries and their similarity result */
|
|
62
|
+
function buildClone(a, b, similarity, sharedLines) {
|
|
63
|
+
return {
|
|
64
|
+
symbol_a: { name: a.name, kind: a.kind, file: a.file, start_line: a.start_line, end_line: a.end_line },
|
|
65
|
+
symbol_b: { name: b.name, kind: b.kind, file: b.file, start_line: b.start_line, end_line: b.end_line },
|
|
66
|
+
similarity,
|
|
67
|
+
shared_lines: sharedLines,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/** Filter, normalize, and hash symbols into clone-comparable entries */
|
|
71
|
+
function prepareEntries(symbols, minLines, includeTests, filePattern) {
|
|
72
|
+
const entries = [];
|
|
73
|
+
for (const sym of symbols) {
|
|
74
|
+
if (!ANALYZABLE_KINDS.has(sym.kind))
|
|
75
|
+
continue;
|
|
76
|
+
if (!sym.source)
|
|
77
|
+
continue;
|
|
78
|
+
if (!includeTests && isTestFile(sym.file))
|
|
79
|
+
continue;
|
|
80
|
+
if (filePattern && !sym.file.includes(filePattern))
|
|
81
|
+
continue;
|
|
82
|
+
const lines = normalizeSource(sym.source);
|
|
83
|
+
if (lines.length < minLines)
|
|
84
|
+
continue;
|
|
85
|
+
entries.push({
|
|
86
|
+
name: sym.name,
|
|
87
|
+
kind: sym.kind,
|
|
88
|
+
file: sym.file,
|
|
89
|
+
start_line: sym.start_line,
|
|
90
|
+
end_line: sym.end_line,
|
|
91
|
+
lines,
|
|
92
|
+
hash: hashLines(lines),
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
return entries;
|
|
96
|
+
}
|
|
97
|
+
/** Phase 1: Find exact hash matches via O(n) bucketing */
|
|
98
|
+
function findExactMatches(entries, minSimilarity, minLines, maxClones) {
|
|
99
|
+
const clones = [];
|
|
100
|
+
const hashBuckets = new Map();
|
|
101
|
+
for (const entry of entries) {
|
|
102
|
+
const bucket = hashBuckets.get(entry.hash);
|
|
103
|
+
if (bucket)
|
|
104
|
+
bucket.push(entry);
|
|
105
|
+
else
|
|
106
|
+
hashBuckets.set(entry.hash, [entry]);
|
|
107
|
+
}
|
|
108
|
+
for (const bucket of hashBuckets.values()) {
|
|
109
|
+
if (bucket.length < 2)
|
|
110
|
+
continue;
|
|
111
|
+
for (let i = 0; i < bucket.length; i++) {
|
|
112
|
+
for (let j = i + 1; j < bucket.length; j++) {
|
|
113
|
+
if (clones.length >= maxClones)
|
|
114
|
+
break;
|
|
115
|
+
const a = bucket[i];
|
|
116
|
+
const b = bucket[j];
|
|
117
|
+
if (a.file === b.file && a.start_line === b.start_line)
|
|
118
|
+
continue;
|
|
119
|
+
const { similarity, sharedLines } = computeSimilarity(a.lines, b.lines);
|
|
120
|
+
if (similarity >= minSimilarity && sharedLines >= minLines) {
|
|
121
|
+
clones.push(buildClone(a, b, similarity, sharedLines));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return clones;
|
|
127
|
+
}
|
|
128
|
+
/** Phase 2: Find near-matches by comparing entries with similar line counts */
|
|
129
|
+
function findNearMatches(entries, existingClones, minSimilarity, minLines, maxClones) {
|
|
130
|
+
const clones = [];
|
|
131
|
+
const remaining = maxClones - existingClones.length;
|
|
132
|
+
if (remaining <= 0)
|
|
133
|
+
return clones;
|
|
134
|
+
const sorted = [...entries].sort((a, b) => a.lines.length - b.lines.length);
|
|
135
|
+
for (let i = 0; i < sorted.length && clones.length < remaining; i++) {
|
|
136
|
+
for (let j = i + 1; j < sorted.length && clones.length < remaining; j++) {
|
|
137
|
+
const a = sorted[i];
|
|
138
|
+
const b = sorted[j];
|
|
139
|
+
if (b.lines.length > a.lines.length * MAX_LINE_RATIO)
|
|
140
|
+
break;
|
|
141
|
+
if (a.hash === b.hash)
|
|
142
|
+
continue;
|
|
143
|
+
if (a.file === b.file && a.start_line === b.start_line)
|
|
144
|
+
continue;
|
|
145
|
+
const alreadyFound = existingClones.some((c) => (c.symbol_a.file === a.file && c.symbol_a.start_line === a.start_line &&
|
|
146
|
+
c.symbol_b.file === b.file && c.symbol_b.start_line === b.start_line));
|
|
147
|
+
if (alreadyFound)
|
|
148
|
+
continue;
|
|
149
|
+
const { similarity, sharedLines } = computeSimilarity(a.lines, b.lines);
|
|
150
|
+
if (similarity >= minSimilarity && sharedLines >= minLines) {
|
|
151
|
+
clones.push(buildClone(a, b, similarity, sharedLines));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return clones;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Find code clones: pairs of symbols with similar normalized source.
|
|
159
|
+
* Uses hash-based bucketing for O(n) average case instead of O(n²) all-pairs.
|
|
160
|
+
*/
|
|
161
|
+
export async function findClones(repo, options) {
|
|
162
|
+
const index = await getCodeIndex(repo);
|
|
163
|
+
if (!index) {
|
|
164
|
+
throw new Error(`Repository "${repo}" not found. Index it first with index_folder.`);
|
|
165
|
+
}
|
|
166
|
+
const minSimilarity = options?.min_similarity ?? DEFAULT_MIN_SIMILARITY;
|
|
167
|
+
const minLines = options?.min_lines ?? MIN_CLONE_LINES;
|
|
168
|
+
const includeTests = options?.include_tests ?? false;
|
|
169
|
+
const filePattern = options?.file_pattern;
|
|
170
|
+
const entries = prepareEntries(index.symbols, minLines, includeTests, filePattern);
|
|
171
|
+
const exactClones = findExactMatches(entries, minSimilarity, minLines, MAX_CLONES);
|
|
172
|
+
const nearClones = findNearMatches(entries, exactClones, minSimilarity, minLines, MAX_CLONES);
|
|
173
|
+
const allClones = [...exactClones, ...nearClones];
|
|
174
|
+
allClones.sort((a, b) => b.similarity - a.similarity);
|
|
175
|
+
return {
|
|
176
|
+
clones: allClones.slice(0, MAX_CLONES),
|
|
177
|
+
scanned_symbols: entries.length,
|
|
178
|
+
threshold: minSimilarity,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=clone-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone-tools.js","sourceRoot":"","sources":["../../src/tools/clone-tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface Community {
|
|
2
|
+
id: number;
|
|
3
|
+
name: string;
|
|
4
|
+
files: string[];
|
|
5
|
+
symbol_count: number;
|
|
6
|
+
internal_edges: number;
|
|
7
|
+
external_edges: number;
|
|
8
|
+
cohesion: number;
|
|
9
|
+
}
|
|
10
|
+
export interface CommunityResult {
|
|
11
|
+
communities: Community[];
|
|
12
|
+
modularity: number;
|
|
13
|
+
total_files: number;
|
|
14
|
+
algorithm: "louvain";
|
|
15
|
+
resolution: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Detect code communities using Louvain algorithm on the import graph.
|
|
19
|
+
*/
|
|
20
|
+
export declare function detectCommunities(repo: string, focus?: string, resolution?: number, outputFormat?: "json" | "mermaid"): Promise<CommunityResult | {
|
|
21
|
+
mermaid: string;
|
|
22
|
+
}>;
|
|
23
|
+
//# sourceMappingURL=community-tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"community-tools.d.ts","sourceRoot":"","sources":["../../src/tools/community-tools.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AA2ND;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,GAChC,OAAO,CAAC,eAAe,GAAG;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CA6FhD"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Louvain community detection — discover code clusters from the import graph.
|
|
3
|
+
*/
|
|
4
|
+
import { getCodeIndex } from "./index-tools.js";
|
|
5
|
+
import { collectImportEdges } from "../utils/import-graph.js";
|
|
6
|
+
/**
|
|
7
|
+
* Louvain method for community detection on an undirected weighted graph.
|
|
8
|
+
* Returns mapping: node → community ID.
|
|
9
|
+
*/
|
|
10
|
+
function louvain(nodes, adj, resolution) {
|
|
11
|
+
const community = new Map();
|
|
12
|
+
const nodeSet = new Set(nodes);
|
|
13
|
+
// Init: each node in its own community
|
|
14
|
+
let nextId = 0;
|
|
15
|
+
for (const node of nodes) {
|
|
16
|
+
community.set(node, nextId++);
|
|
17
|
+
}
|
|
18
|
+
// Total edge weight
|
|
19
|
+
let totalWeight = 0;
|
|
20
|
+
for (const [, neighbors] of adj) {
|
|
21
|
+
for (const [, w] of neighbors)
|
|
22
|
+
totalWeight += w;
|
|
23
|
+
}
|
|
24
|
+
totalWeight /= 2; // Each edge counted twice
|
|
25
|
+
if (totalWeight === 0)
|
|
26
|
+
return community;
|
|
27
|
+
// Degree (sum of edge weights per node)
|
|
28
|
+
const degree = new Map();
|
|
29
|
+
for (const node of nodes) {
|
|
30
|
+
let d = 0;
|
|
31
|
+
const neighbors = adj.get(node);
|
|
32
|
+
if (neighbors)
|
|
33
|
+
for (const [, w] of neighbors)
|
|
34
|
+
d += w;
|
|
35
|
+
degree.set(node, d);
|
|
36
|
+
}
|
|
37
|
+
// Phase 1: Local moves
|
|
38
|
+
const MAX_PASSES = 20;
|
|
39
|
+
for (let pass = 0; pass < MAX_PASSES; pass++) {
|
|
40
|
+
let improved = false;
|
|
41
|
+
for (const node of nodes) {
|
|
42
|
+
if (!nodeSet.has(node))
|
|
43
|
+
continue;
|
|
44
|
+
const currentComm = community.get(node);
|
|
45
|
+
const ki = degree.get(node) ?? 0;
|
|
46
|
+
const neighbors = adj.get(node);
|
|
47
|
+
if (!neighbors)
|
|
48
|
+
continue;
|
|
49
|
+
// Calculate weight to each neighboring community
|
|
50
|
+
const commWeights = new Map();
|
|
51
|
+
for (const [neighbor, w] of neighbors) {
|
|
52
|
+
const nc = community.get(neighbor);
|
|
53
|
+
commWeights.set(nc, (commWeights.get(nc) ?? 0) + w);
|
|
54
|
+
}
|
|
55
|
+
// Sum of degrees in current community (excluding this node)
|
|
56
|
+
let sigmaCurrentWithout = 0;
|
|
57
|
+
for (const [n, c] of community) {
|
|
58
|
+
if (c === currentComm && n !== node)
|
|
59
|
+
sigmaCurrentWithout += degree.get(n) ?? 0;
|
|
60
|
+
}
|
|
61
|
+
const weightToCurrentComm = commWeights.get(currentComm) ?? 0;
|
|
62
|
+
const removeCost = weightToCurrentComm - resolution * ki * sigmaCurrentWithout / (2 * totalWeight);
|
|
63
|
+
let bestComm = currentComm;
|
|
64
|
+
let bestGain = 0;
|
|
65
|
+
for (const [targetComm, weightToTarget] of commWeights) {
|
|
66
|
+
if (targetComm === currentComm)
|
|
67
|
+
continue;
|
|
68
|
+
let sigmaTarget = 0;
|
|
69
|
+
for (const [n, c] of community) {
|
|
70
|
+
if (c === targetComm)
|
|
71
|
+
sigmaTarget += degree.get(n) ?? 0;
|
|
72
|
+
}
|
|
73
|
+
const gain = (weightToTarget - resolution * ki * sigmaTarget / (2 * totalWeight)) - removeCost;
|
|
74
|
+
if (gain > bestGain) {
|
|
75
|
+
bestGain = gain;
|
|
76
|
+
bestComm = targetComm;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (bestComm !== currentComm) {
|
|
80
|
+
community.set(node, bestComm);
|
|
81
|
+
improved = true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (!improved)
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
// Renumber communities to be contiguous (0, 1, 2, ...)
|
|
88
|
+
const commMap = new Map();
|
|
89
|
+
let nextComm = 0;
|
|
90
|
+
for (const [, c] of community) {
|
|
91
|
+
if (!commMap.has(c))
|
|
92
|
+
commMap.set(c, nextComm++);
|
|
93
|
+
}
|
|
94
|
+
for (const [node, c] of community) {
|
|
95
|
+
community.set(node, commMap.get(c));
|
|
96
|
+
}
|
|
97
|
+
return community;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Calculate modularity Q for a partition.
|
|
101
|
+
*/
|
|
102
|
+
function calculateModularity(community, adj) {
|
|
103
|
+
let totalWeight = 0;
|
|
104
|
+
for (const [, neighbors] of adj) {
|
|
105
|
+
for (const [, w] of neighbors)
|
|
106
|
+
totalWeight += w;
|
|
107
|
+
}
|
|
108
|
+
totalWeight /= 2;
|
|
109
|
+
if (totalWeight === 0)
|
|
110
|
+
return 0;
|
|
111
|
+
const degree = new Map();
|
|
112
|
+
for (const [node, neighbors] of adj) {
|
|
113
|
+
let d = 0;
|
|
114
|
+
for (const [, w] of neighbors)
|
|
115
|
+
d += w;
|
|
116
|
+
degree.set(node, d);
|
|
117
|
+
}
|
|
118
|
+
let Q = 0;
|
|
119
|
+
for (const [i, neighbors] of adj) {
|
|
120
|
+
for (const [j, Aij] of neighbors) {
|
|
121
|
+
if (community.get(i) !== community.get(j))
|
|
122
|
+
continue;
|
|
123
|
+
const ki = degree.get(i) ?? 0;
|
|
124
|
+
const kj = degree.get(j) ?? 0;
|
|
125
|
+
Q += Aij - (ki * kj) / (2 * totalWeight);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return Q / (2 * totalWeight);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Auto-name a community from the most specific common path prefix.
|
|
132
|
+
* Falls back to most frequent directory if no unique prefix.
|
|
133
|
+
*/
|
|
134
|
+
function nameCommunity(files, id) {
|
|
135
|
+
if (files.length === 0)
|
|
136
|
+
return `community-${id}`;
|
|
137
|
+
if (files.length === 1) {
|
|
138
|
+
const dir = files[0].split("/").slice(0, -1).join("/");
|
|
139
|
+
return dir || files[0];
|
|
140
|
+
}
|
|
141
|
+
// Find deepest common prefix
|
|
142
|
+
const parts = files.map((f) => f.split("/"));
|
|
143
|
+
const minLen = Math.min(...parts.map((p) => p.length));
|
|
144
|
+
let common = 0;
|
|
145
|
+
for (let i = 0; i < minLen - 1; i++) {
|
|
146
|
+
if (parts.every((p) => p[i] === parts[0][i]))
|
|
147
|
+
common = i + 1;
|
|
148
|
+
else
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
// If common prefix is too short (just "src"), use most frequent subdirectory
|
|
152
|
+
if (common <= 1 && minLen > 2) {
|
|
153
|
+
const dirCounts = new Map();
|
|
154
|
+
for (const p of parts) {
|
|
155
|
+
const dir = p.slice(0, Math.min(3, p.length - 1)).join("/");
|
|
156
|
+
dirCounts.set(dir, (dirCounts.get(dir) ?? 0) + 1);
|
|
157
|
+
}
|
|
158
|
+
const topDir = [...dirCounts.entries()].sort((a, b) => b[1] - a[1])[0];
|
|
159
|
+
if (topDir)
|
|
160
|
+
return topDir[0];
|
|
161
|
+
}
|
|
162
|
+
return common > 0
|
|
163
|
+
? parts[0].slice(0, common).join("/")
|
|
164
|
+
: `community-${id}`;
|
|
165
|
+
}
|
|
166
|
+
const MAX_MERMAID_COMMUNITIES = 15;
|
|
167
|
+
const MAX_MERMAID_FILES_PER = 5;
|
|
168
|
+
function communityToMermaid(result, edges) {
|
|
169
|
+
const lines = ["graph LR"];
|
|
170
|
+
const comms = result.communities.slice(0, MAX_MERMAID_COMMUNITIES);
|
|
171
|
+
const fileToCommunity = new Map();
|
|
172
|
+
for (const c of comms) {
|
|
173
|
+
for (const f of c.files) {
|
|
174
|
+
if (!f.startsWith("..."))
|
|
175
|
+
fileToCommunity.set(f, c.id);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
for (const c of comms) {
|
|
179
|
+
const safeId = `c${c.id}`;
|
|
180
|
+
const label = `${c.name} (${c.files.length} files)`;
|
|
181
|
+
lines.push(` subgraph ${safeId}["${label}"]`);
|
|
182
|
+
const showFiles = c.files.filter((f) => !f.startsWith("...")).slice(0, MAX_MERMAID_FILES_PER);
|
|
183
|
+
for (const f of showFiles) {
|
|
184
|
+
const short = f.split("/").pop()?.replace(/\.\w+$/, "") ?? f;
|
|
185
|
+
const nodeId = (safeId + "_" + short).replace(/[^a-zA-Z0-9_]/g, "_");
|
|
186
|
+
lines.push(` ${nodeId}["${short}"]`);
|
|
187
|
+
}
|
|
188
|
+
lines.push(" end");
|
|
189
|
+
}
|
|
190
|
+
const crossEdges = new Set();
|
|
191
|
+
for (const edge of edges) {
|
|
192
|
+
const fromC = fileToCommunity.get(edge.from);
|
|
193
|
+
const toC = fileToCommunity.get(edge.to);
|
|
194
|
+
if (fromC !== undefined && toC !== undefined && fromC !== toC) {
|
|
195
|
+
const key = fromC < toC ? `c${fromC}-->c${toC}` : `c${toC}-->c${fromC}`;
|
|
196
|
+
if (!crossEdges.has(key)) {
|
|
197
|
+
crossEdges.add(key);
|
|
198
|
+
lines.push(` c${Math.min(fromC, toC)} --> c${Math.max(fromC, toC)}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return lines.join("\n");
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Detect code communities using Louvain algorithm on the import graph.
|
|
206
|
+
*/
|
|
207
|
+
export async function detectCommunities(repo, focus, resolution, outputFormat) {
|
|
208
|
+
const index = await getCodeIndex(repo);
|
|
209
|
+
if (!index)
|
|
210
|
+
throw new Error(`Repository "${repo}" not found.`);
|
|
211
|
+
// Filter files by focus; cap without focus to prevent 66K tok responses
|
|
212
|
+
const MAX_UNFOCUSED_FILES = 500;
|
|
213
|
+
const MAX_COMMUNITIES = 20;
|
|
214
|
+
let files = focus
|
|
215
|
+
? index.files.filter((f) => f.path.includes(focus))
|
|
216
|
+
: index.files;
|
|
217
|
+
if (!focus && files.length > MAX_UNFOCUSED_FILES) {
|
|
218
|
+
// Keep files with most symbols (most architecturally relevant)
|
|
219
|
+
files = [...files].sort((a, b) => b.symbol_count - a.symbol_count).slice(0, MAX_UNFOCUSED_FILES);
|
|
220
|
+
}
|
|
221
|
+
const fileSet = new Set(files.map((f) => f.path));
|
|
222
|
+
const edges = await collectImportEdges(index, fileSet);
|
|
223
|
+
// Build weighted undirected adjacency
|
|
224
|
+
const adj = new Map();
|
|
225
|
+
for (const node of fileSet)
|
|
226
|
+
adj.set(node, new Map());
|
|
227
|
+
for (const edge of edges) {
|
|
228
|
+
if (!fileSet.has(edge.from) || !fileSet.has(edge.to))
|
|
229
|
+
continue;
|
|
230
|
+
const fromAdj = adj.get(edge.from);
|
|
231
|
+
fromAdj.set(edge.to, (fromAdj.get(edge.to) ?? 0) + 1);
|
|
232
|
+
const toAdj = adj.get(edge.to);
|
|
233
|
+
toAdj.set(edge.from, (toAdj.get(edge.from) ?? 0) + 1);
|
|
234
|
+
}
|
|
235
|
+
const res = resolution ?? 1.0;
|
|
236
|
+
const communityMap = louvain([...fileSet], adj, res);
|
|
237
|
+
const modularity = calculateModularity(communityMap, adj);
|
|
238
|
+
// Group files by community
|
|
239
|
+
const groups = new Map();
|
|
240
|
+
for (const [file, comm] of communityMap) {
|
|
241
|
+
let list = groups.get(comm);
|
|
242
|
+
if (!list) {
|
|
243
|
+
list = [];
|
|
244
|
+
groups.set(comm, list);
|
|
245
|
+
}
|
|
246
|
+
list.push(file);
|
|
247
|
+
}
|
|
248
|
+
// Symbol count per file
|
|
249
|
+
const symCountByFile = new Map();
|
|
250
|
+
for (const f of index.files)
|
|
251
|
+
symCountByFile.set(f.path, f.symbol_count);
|
|
252
|
+
// Build community objects
|
|
253
|
+
const communities = [];
|
|
254
|
+
for (const [id, communityFiles] of [...groups.entries()].sort((a, b) => b[1].length - a[1].length)) {
|
|
255
|
+
const fileSetComm = new Set(communityFiles);
|
|
256
|
+
let internal = 0;
|
|
257
|
+
let external = 0;
|
|
258
|
+
for (const edge of edges) {
|
|
259
|
+
const fromIn = fileSetComm.has(edge.from);
|
|
260
|
+
const toIn = fileSetComm.has(edge.to);
|
|
261
|
+
if (fromIn && toIn)
|
|
262
|
+
internal++;
|
|
263
|
+
else if (fromIn || toIn)
|
|
264
|
+
external++;
|
|
265
|
+
}
|
|
266
|
+
const MAX_FILES_PER_COMMUNITY = 20;
|
|
267
|
+
const sortedFiles = communityFiles.sort();
|
|
268
|
+
communities.push({
|
|
269
|
+
id,
|
|
270
|
+
name: nameCommunity(communityFiles, id),
|
|
271
|
+
files: sortedFiles.length > MAX_FILES_PER_COMMUNITY
|
|
272
|
+
? [...sortedFiles.slice(0, MAX_FILES_PER_COMMUNITY), `... +${sortedFiles.length - MAX_FILES_PER_COMMUNITY} more`]
|
|
273
|
+
: sortedFiles,
|
|
274
|
+
symbol_count: communityFiles.reduce((sum, f) => sum + (symCountByFile.get(f) ?? 0), 0),
|
|
275
|
+
internal_edges: internal,
|
|
276
|
+
external_edges: external,
|
|
277
|
+
cohesion: internal + external > 0 ? internal / (internal + external) : 0,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
// Cap communities output
|
|
281
|
+
const cappedCommunities = communities.slice(0, MAX_COMMUNITIES);
|
|
282
|
+
const result = {
|
|
283
|
+
communities: cappedCommunities,
|
|
284
|
+
modularity: Math.round(modularity * 1000) / 1000,
|
|
285
|
+
total_files: files.length,
|
|
286
|
+
...(communities.length > MAX_COMMUNITIES
|
|
287
|
+
? { truncated: true, total_communities: communities.length }
|
|
288
|
+
: {}),
|
|
289
|
+
algorithm: "louvain",
|
|
290
|
+
resolution: res,
|
|
291
|
+
};
|
|
292
|
+
if (outputFormat === "mermaid") {
|
|
293
|
+
return { mermaid: communityToMermaid(result, edges) };
|
|
294
|
+
}
|
|
295
|
+
return result;
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=community-tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"community-tools.js","sourceRoot":"","sources":["../../src/tools/community-tools.ts"],"names":[],"mappings":"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"}
|