Skip to content

Commit f3e36ad

Browse files
feat: louvain community detection for module boundary analysis (#133)
Add `codegraph communities` command that runs Louvain clustering on the dependency graph, compares discovered communities against directory structure, and surfaces architectural drift (split/merge candidates, drift score). Supports file-level (default) and function-level modes, configurable resolution, and drift-only output. Integrated into stats, MCP, and programmatic API. Impact: 9 functions changed, 8 affected Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 1c60b88 commit f3e36ad

9 files changed

Lines changed: 741 additions & 6 deletions

File tree

package-lock.json

Lines changed: 95 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@
5757
"dependencies": {
5858
"better-sqlite3": "^12.6.2",
5959
"commander": "^14.0.3",
60+
"graphology": "^0.25.4",
61+
"graphology-communities-louvain": "^2.0.2",
6062
"web-tree-sitter": "^0.26.5"
6163
},
6264
"peerDependencies": {

src/cli.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ program
137137
.option('-T, --no-tests', 'Exclude test/spec files from results')
138138
.option('--include-tests', 'Include test/spec files (overrides excludeTests config)')
139139
.option('-j, --json', 'Output as JSON')
140-
.action((opts) => {
141-
stats(opts.db, { noTests: resolveNoTests(opts), json: opts.json });
140+
.action(async (opts) => {
141+
await stats(opts.db, { noTests: resolveNoTests(opts), json: opts.json });
142142
});
143143

144144
program
@@ -742,6 +742,27 @@ program
742742
});
743743
});
744744

745+
program
746+
.command('communities')
747+
.description('Detect natural module boundaries using Louvain community detection')
748+
.option('--functions', 'Function-level instead of file-level')
749+
.option('--resolution <n>', 'Louvain resolution parameter (default 1.0)', '1.0')
750+
.option('--drift', 'Show only drift analysis')
751+
.option('-d, --db <path>', 'Path to graph.db')
752+
.option('-T, --no-tests', 'Exclude test/spec files from results')
753+
.option('--include-tests', 'Include test/spec files (overrides excludeTests config)')
754+
.option('-j, --json', 'Output as JSON')
755+
.action(async (opts) => {
756+
const { communities } = await import('./communities.js');
757+
communities(opts.db, {
758+
functions: opts.functions,
759+
resolution: parseFloat(opts.resolution),
760+
drift: opts.drift,
761+
noTests: resolveNoTests(opts),
762+
json: opts.json,
763+
});
764+
});
765+
745766
program
746767
.command('branch-compare <base> <target>')
747768
.description('Compare code structure between two branches/refs')

0 commit comments

Comments
 (0)