@optave/codegraph 3.1.3 → 3.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.
Files changed (232) hide show
  1. package/README.md +38 -84
  2. package/package.json +13 -8
  3. package/src/ast-analysis/engine.js +32 -12
  4. package/src/ast-analysis/shared.js +6 -5
  5. package/src/cli/commands/ast.js +22 -0
  6. package/src/cli/commands/audit.js +45 -0
  7. package/src/cli/commands/batch.js +68 -0
  8. package/src/cli/commands/branch-compare.js +21 -0
  9. package/src/cli/commands/build.js +26 -0
  10. package/src/cli/commands/cfg.js +26 -0
  11. package/src/cli/commands/check.js +74 -0
  12. package/src/cli/commands/children.js +28 -0
  13. package/src/cli/commands/co-change.js +67 -0
  14. package/src/cli/commands/communities.js +19 -0
  15. package/src/cli/commands/complexity.js +46 -0
  16. package/src/cli/commands/context.js +30 -0
  17. package/src/cli/commands/cycles.js +32 -0
  18. package/src/cli/commands/dataflow.js +28 -0
  19. package/src/cli/commands/deps.js +12 -0
  20. package/src/cli/commands/diff-impact.js +26 -0
  21. package/src/cli/commands/embed.js +30 -0
  22. package/src/cli/commands/export.js +78 -0
  23. package/src/cli/commands/exports.js +14 -0
  24. package/src/cli/commands/flow.js +32 -0
  25. package/src/cli/commands/fn-impact.js +26 -0
  26. package/src/cli/commands/impact.js +12 -0
  27. package/src/cli/commands/info.js +76 -0
  28. package/src/cli/commands/map.js +19 -0
  29. package/src/cli/commands/mcp.js +18 -0
  30. package/src/cli/commands/models.js +19 -0
  31. package/src/cli/commands/owners.js +25 -0
  32. package/src/cli/commands/path.js +36 -0
  33. package/src/cli/commands/plot.js +89 -0
  34. package/src/cli/commands/query.js +45 -0
  35. package/src/cli/commands/registry.js +100 -0
  36. package/src/cli/commands/roles.js +30 -0
  37. package/src/cli/commands/search.js +42 -0
  38. package/src/cli/commands/sequence.js +28 -0
  39. package/src/cli/commands/snapshot.js +66 -0
  40. package/src/cli/commands/stats.js +15 -0
  41. package/src/cli/commands/structure.js +33 -0
  42. package/src/cli/commands/triage.js +78 -0
  43. package/src/cli/commands/watch.js +12 -0
  44. package/src/cli/commands/where.js +20 -0
  45. package/src/cli/index.js +124 -0
  46. package/src/cli/shared/open-graph.js +13 -0
  47. package/src/cli/shared/options.js +59 -0
  48. package/src/cli/shared/output.js +1 -0
  49. package/src/cli.js +11 -1522
  50. package/src/db/connection.js +130 -7
  51. package/src/{db.js → db/index.js} +17 -5
  52. package/src/db/migrations.js +42 -1
  53. package/src/db/query-builder.js +20 -12
  54. package/src/db/repository/base.js +201 -0
  55. package/src/db/repository/graph-read.js +7 -4
  56. package/src/db/repository/in-memory-repository.js +575 -0
  57. package/src/db/repository/index.js +5 -1
  58. package/src/db/repository/nodes.js +60 -6
  59. package/src/db/repository/sqlite-repository.js +219 -0
  60. package/src/domain/analysis/context.js +408 -0
  61. package/src/domain/analysis/dependencies.js +341 -0
  62. package/src/domain/analysis/exports.js +134 -0
  63. package/src/domain/analysis/impact.js +466 -0
  64. package/src/domain/analysis/module-map.js +322 -0
  65. package/src/domain/analysis/roles.js +45 -0
  66. package/src/domain/analysis/symbol-lookup.js +238 -0
  67. package/src/domain/graph/builder/context.js +85 -0
  68. package/src/domain/graph/builder/helpers.js +218 -0
  69. package/src/domain/graph/builder/incremental.js +178 -0
  70. package/src/domain/graph/builder/pipeline.js +130 -0
  71. package/src/domain/graph/builder/stages/build-edges.js +297 -0
  72. package/src/domain/graph/builder/stages/build-structure.js +113 -0
  73. package/src/domain/graph/builder/stages/collect-files.js +44 -0
  74. package/src/domain/graph/builder/stages/detect-changes.js +413 -0
  75. package/src/domain/graph/builder/stages/finalize.js +139 -0
  76. package/src/domain/graph/builder/stages/insert-nodes.js +195 -0
  77. package/src/domain/graph/builder/stages/parse-files.js +28 -0
  78. package/src/domain/graph/builder/stages/resolve-imports.js +143 -0
  79. package/src/domain/graph/builder/stages/run-analyses.js +44 -0
  80. package/src/domain/graph/builder.js +11 -0
  81. package/src/{change-journal.js → domain/graph/change-journal.js} +1 -1
  82. package/src/domain/graph/cycles.js +82 -0
  83. package/src/{journal.js → domain/graph/journal.js} +1 -1
  84. package/src/{resolve.js → domain/graph/resolve.js} +3 -3
  85. package/src/{watcher.js → domain/graph/watcher.js} +10 -150
  86. package/src/{parser.js → domain/parser.js} +5 -5
  87. package/src/domain/queries.js +48 -0
  88. package/src/domain/search/generator.js +163 -0
  89. package/src/domain/search/index.js +13 -0
  90. package/src/domain/search/models.js +218 -0
  91. package/src/domain/search/search/cli-formatter.js +151 -0
  92. package/src/domain/search/search/filters.js +46 -0
  93. package/src/domain/search/search/hybrid.js +121 -0
  94. package/src/domain/search/search/keyword.js +68 -0
  95. package/src/domain/search/search/prepare.js +66 -0
  96. package/src/domain/search/search/semantic.js +145 -0
  97. package/src/domain/search/stores/fts5.js +27 -0
  98. package/src/domain/search/stores/sqlite-blob.js +24 -0
  99. package/src/domain/search/strategies/source.js +14 -0
  100. package/src/domain/search/strategies/structured.js +43 -0
  101. package/src/domain/search/strategies/text-utils.js +43 -0
  102. package/src/extractors/csharp.js +10 -2
  103. package/src/extractors/go.js +3 -1
  104. package/src/extractors/helpers.js +71 -0
  105. package/src/extractors/java.js +9 -2
  106. package/src/extractors/javascript.js +39 -2
  107. package/src/extractors/php.js +3 -1
  108. package/src/extractors/python.js +14 -3
  109. package/src/extractors/rust.js +3 -1
  110. package/src/{ast.js → features/ast.js} +8 -8
  111. package/src/{audit.js → features/audit.js} +16 -44
  112. package/src/{batch.js → features/batch.js} +6 -5
  113. package/src/{boundaries.js → features/boundaries.js} +2 -2
  114. package/src/{branch-compare.js → features/branch-compare.js} +3 -3
  115. package/src/{cfg.js → features/cfg.js} +11 -12
  116. package/src/{check.js → features/check.js} +13 -30
  117. package/src/{cochange.js → features/cochange.js} +5 -5
  118. package/src/{communities.js → features/communities.js} +18 -90
  119. package/src/{complexity.js → features/complexity.js} +13 -13
  120. package/src/{dataflow.js → features/dataflow.js} +12 -13
  121. package/src/features/export.js +378 -0
  122. package/src/{flow.js → features/flow.js} +4 -4
  123. package/src/features/graph-enrichment.js +327 -0
  124. package/src/{manifesto.js → features/manifesto.js} +6 -6
  125. package/src/{owners.js → features/owners.js} +2 -2
  126. package/src/{sequence.js → features/sequence.js} +16 -52
  127. package/src/{snapshot.js → features/snapshot.js} +8 -7
  128. package/src/{structure.js → features/structure.js} +20 -45
  129. package/src/{triage.js → features/triage.js} +27 -79
  130. package/src/graph/algorithms/bfs.js +49 -0
  131. package/src/graph/algorithms/centrality.js +16 -0
  132. package/src/graph/algorithms/index.js +5 -0
  133. package/src/graph/algorithms/louvain.js +26 -0
  134. package/src/graph/algorithms/shortest-path.js +41 -0
  135. package/src/graph/algorithms/tarjan.js +49 -0
  136. package/src/graph/builders/dependency.js +110 -0
  137. package/src/graph/builders/index.js +3 -0
  138. package/src/graph/builders/structure.js +40 -0
  139. package/src/graph/builders/temporal.js +33 -0
  140. package/src/graph/classifiers/index.js +2 -0
  141. package/src/graph/classifiers/risk.js +85 -0
  142. package/src/graph/classifiers/roles.js +64 -0
  143. package/src/graph/index.js +13 -0
  144. package/src/graph/model.js +230 -0
  145. package/src/index.cjs +16 -0
  146. package/src/index.js +42 -219
  147. package/src/{native.js → infrastructure/native.js} +3 -1
  148. package/src/infrastructure/result-formatter.js +2 -21
  149. package/src/mcp/index.js +2 -0
  150. package/src/mcp/middleware.js +26 -0
  151. package/src/mcp/server.js +128 -0
  152. package/src/{mcp.js → mcp/tool-registry.js} +6 -675
  153. package/src/mcp/tools/ast-query.js +14 -0
  154. package/src/mcp/tools/audit.js +21 -0
  155. package/src/mcp/tools/batch-query.js +11 -0
  156. package/src/mcp/tools/branch-compare.js +12 -0
  157. package/src/mcp/tools/cfg.js +21 -0
  158. package/src/mcp/tools/check.js +43 -0
  159. package/src/mcp/tools/co-changes.js +20 -0
  160. package/src/mcp/tools/code-owners.js +12 -0
  161. package/src/mcp/tools/communities.js +15 -0
  162. package/src/mcp/tools/complexity.js +18 -0
  163. package/src/mcp/tools/context.js +17 -0
  164. package/src/mcp/tools/dataflow.js +26 -0
  165. package/src/mcp/tools/diff-impact.js +24 -0
  166. package/src/mcp/tools/execution-flow.js +26 -0
  167. package/src/mcp/tools/export-graph.js +57 -0
  168. package/src/mcp/tools/file-deps.js +12 -0
  169. package/src/mcp/tools/file-exports.js +13 -0
  170. package/src/mcp/tools/find-cycles.js +15 -0
  171. package/src/mcp/tools/fn-impact.js +15 -0
  172. package/src/mcp/tools/impact-analysis.js +12 -0
  173. package/src/mcp/tools/index.js +71 -0
  174. package/src/mcp/tools/list-functions.js +14 -0
  175. package/src/mcp/tools/list-repos.js +11 -0
  176. package/src/mcp/tools/module-map.js +6 -0
  177. package/src/mcp/tools/node-roles.js +14 -0
  178. package/src/mcp/tools/path.js +12 -0
  179. package/src/mcp/tools/query.js +30 -0
  180. package/src/mcp/tools/semantic-search.js +65 -0
  181. package/src/mcp/tools/sequence.js +17 -0
  182. package/src/mcp/tools/structure.js +15 -0
  183. package/src/mcp/tools/symbol-children.js +14 -0
  184. package/src/mcp/tools/triage.js +35 -0
  185. package/src/mcp/tools/where.js +13 -0
  186. package/src/{commands → presentation}/audit.js +2 -2
  187. package/src/{commands → presentation}/batch.js +1 -1
  188. package/src/{commands → presentation}/branch-compare.js +2 -2
  189. package/src/{commands → presentation}/cfg.js +1 -1
  190. package/src/{commands → presentation}/check.js +6 -6
  191. package/src/presentation/colors.js +44 -0
  192. package/src/{commands → presentation}/communities.js +1 -1
  193. package/src/{commands → presentation}/complexity.js +1 -1
  194. package/src/{commands → presentation}/dataflow.js +1 -1
  195. package/src/presentation/export.js +444 -0
  196. package/src/{commands → presentation}/flow.js +2 -2
  197. package/src/{commands → presentation}/manifesto.js +4 -4
  198. package/src/{commands → presentation}/owners.js +1 -1
  199. package/src/presentation/queries-cli/exports.js +46 -0
  200. package/src/presentation/queries-cli/impact.js +198 -0
  201. package/src/presentation/queries-cli/index.js +5 -0
  202. package/src/presentation/queries-cli/inspect.js +334 -0
  203. package/src/presentation/queries-cli/overview.js +197 -0
  204. package/src/presentation/queries-cli/path.js +58 -0
  205. package/src/presentation/queries-cli.js +27 -0
  206. package/src/{commands → presentation}/query.js +1 -1
  207. package/src/presentation/result-formatter.js +144 -0
  208. package/src/presentation/sequence-renderer.js +43 -0
  209. package/src/{commands → presentation}/sequence.js +2 -2
  210. package/src/{commands → presentation}/structure.js +2 -2
  211. package/src/presentation/table.js +47 -0
  212. package/src/{commands → presentation}/triage.js +1 -1
  213. package/src/{viewer.js → presentation/viewer.js} +68 -382
  214. package/src/{constants.js → shared/constants.js} +1 -1
  215. package/src/shared/errors.js +78 -0
  216. package/src/shared/file-utils.js +153 -0
  217. package/src/shared/generators.js +125 -0
  218. package/src/shared/hierarchy.js +27 -0
  219. package/src/shared/normalize.js +59 -0
  220. package/src/builder.js +0 -1486
  221. package/src/cycles.js +0 -137
  222. package/src/embedder.js +0 -1097
  223. package/src/export.js +0 -681
  224. package/src/queries-cli.js +0 -866
  225. package/src/queries.js +0 -2289
  226. /package/src/{config.js → infrastructure/config.js} +0 -0
  227. /package/src/{logger.js → infrastructure/logger.js} +0 -0
  228. /package/src/{registry.js → infrastructure/registry.js} +0 -0
  229. /package/src/{update-check.js → infrastructure/update-check.js} +0 -0
  230. /package/src/{commands → presentation}/cochange.js +0 -0
  231. /package/src/{kinds.js → shared/kinds.js} +0 -0
  232. /package/src/{paginate.js → shared/paginate.js} +0 -0
@@ -1,10 +1,11 @@
1
1
  import { execFileSync } from 'node:child_process';
2
2
  import fs from 'node:fs';
3
3
  import path from 'node:path';
4
- import { loadConfig } from './config.js';
5
- import { findCycles } from './cycles.js';
6
- import { findDbPath, openReadonlyOrFail } from './db.js';
7
- import { isTestFile } from './infrastructure/test-filter.js';
4
+ import { findDbPath, openReadonlyOrFail } from '../db/index.js';
5
+ import { bfsTransitiveCallers } from '../domain/analysis/impact.js';
6
+ import { findCycles } from '../domain/graph/cycles.js';
7
+ import { loadConfig } from '../infrastructure/config.js';
8
+ import { isTestFile } from '../infrastructure/test-filter.js';
8
9
  import { matchOwners, parseCodeowners } from './owners.js';
9
10
 
10
11
  // ─── Diff Parser ──────────────────────────────────────────────────────
@@ -96,31 +97,10 @@ export function checkMaxBlastRadius(db, changedRanges, threshold, noTests, maxDe
96
97
  }
97
98
  if (!overlaps) continue;
98
99
 
99
- // BFS transitive callers
100
- const visited = new Set([def.id]);
101
- let frontier = [def.id];
102
- let totalCallers = 0;
103
- for (let d = 1; d <= maxDepth; d++) {
104
- const nextFrontier = [];
105
- for (const fid of frontier) {
106
- const callers = db
107
- .prepare(
108
- `SELECT DISTINCT n.id, n.name, n.kind, n.file, n.line
109
- FROM edges e JOIN nodes n ON e.source_id = n.id
110
- WHERE e.target_id = ? AND e.kind = 'calls'`,
111
- )
112
- .all(fid);
113
- for (const c of callers) {
114
- if (!visited.has(c.id) && (!noTests || !isTestFile(c.file))) {
115
- visited.add(c.id);
116
- nextFrontier.push(c.id);
117
- totalCallers++;
118
- }
119
- }
120
- }
121
- frontier = nextFrontier;
122
- if (frontier.length === 0) break;
123
- }
100
+ const { totalDependents: totalCallers } = bfsTransitiveCallers(db, def.id, {
101
+ noTests,
102
+ maxDepth,
103
+ });
124
104
 
125
105
  if (totalCallers > maxFound) maxFound = totalCallers;
126
106
  if (totalCallers > threshold) {
@@ -240,7 +220,10 @@ export function checkData(customDbPath, opts = {}) {
240
220
  const maxDepth = opts.depth || 3;
241
221
 
242
222
  // Load config defaults for check predicates
243
- const config = loadConfig(repoRoot);
223
+ // NOTE: opts.config is loaded from process.cwd() at startup (via CLI context),
224
+ // which may differ from the DB's parent repo root when --db points to an external
225
+ // project. This is an acceptable trade-off to avoid duplicate I/O on the hot path.
226
+ const config = opts.config || loadConfig(repoRoot);
244
227
  const checkConfig = config.check || {};
245
228
 
246
229
  // Resolve which predicates are enabled: CLI flags ?? config ?? built-in defaults
@@ -8,11 +8,11 @@
8
8
  import { execFileSync } from 'node:child_process';
9
9
  import fs from 'node:fs';
10
10
  import path from 'node:path';
11
- import { normalizePath } from './constants.js';
12
- import { closeDb, findDbPath, initSchema, openDb, openReadonlyOrFail } from './db.js';
13
- import { isTestFile } from './infrastructure/test-filter.js';
14
- import { warn } from './logger.js';
15
- import { paginateResult } from './paginate.js';
11
+ import { closeDb, findDbPath, initSchema, openDb, openReadonlyOrFail } from '../db/index.js';
12
+ import { warn } from '../infrastructure/logger.js';
13
+ import { isTestFile } from '../infrastructure/test-filter.js';
14
+ import { normalizePath } from '../shared/constants.js';
15
+ import { paginateResult } from '../shared/paginate.js';
16
16
 
17
17
  /**
18
18
  * Scan git history and return parsed commit data.
@@ -1,78 +1,8 @@
1
1
  import path from 'node:path';
2
- import Graph from 'graphology';
3
- import louvain from 'graphology-communities-louvain';
4
- import {
5
- getCallableNodes,
6
- getCallEdges,
7
- getFileNodesAll,
8
- getImportEdges,
9
- openReadonlyOrFail,
10
- } from './db.js';
11
- import { isTestFile } from './infrastructure/test-filter.js';
12
- import { paginateResult } from './paginate.js';
13
-
14
- // ─── Graph Construction ───────────────────────────────────────────────
15
-
16
- /**
17
- * Build a graphology graph from the codegraph SQLite database.
18
- *
19
- * @param {object} db - open better-sqlite3 database (readonly)
20
- * @param {object} opts
21
- * @param {boolean} [opts.functions] - Function-level instead of file-level
22
- * @param {boolean} [opts.noTests] - Exclude test files
23
- * @returns {Graph}
24
- */
25
- function buildGraphologyGraph(db, opts = {}) {
26
- const graph = new Graph({ type: 'undirected' });
27
-
28
- if (opts.functions) {
29
- // Function-level: nodes = function/method/class symbols, edges = calls
30
- let nodes = getCallableNodes(db);
31
- if (opts.noTests) nodes = nodes.filter((n) => !isTestFile(n.file));
32
-
33
- const nodeIds = new Set();
34
- for (const n of nodes) {
35
- const key = String(n.id);
36
- graph.addNode(key, { label: n.name, file: n.file, kind: n.kind });
37
- nodeIds.add(n.id);
38
- }
39
-
40
- const edges = getCallEdges(db);
41
- for (const e of edges) {
42
- if (!nodeIds.has(e.source_id) || !nodeIds.has(e.target_id)) continue;
43
- const src = String(e.source_id);
44
- const tgt = String(e.target_id);
45
- if (src === tgt) continue;
46
- if (!graph.hasEdge(src, tgt)) {
47
- graph.addEdge(src, tgt);
48
- }
49
- }
50
- } else {
51
- // File-level: nodes = files, edges = imports + imports-type (deduplicated, cross-file)
52
- let nodes = getFileNodesAll(db);
53
- if (opts.noTests) nodes = nodes.filter((n) => !isTestFile(n.file));
54
-
55
- const nodeIds = new Set();
56
- for (const n of nodes) {
57
- const key = String(n.id);
58
- graph.addNode(key, { label: n.file, file: n.file });
59
- nodeIds.add(n.id);
60
- }
61
-
62
- const edges = getImportEdges(db);
63
- for (const e of edges) {
64
- if (!nodeIds.has(e.source_id) || !nodeIds.has(e.target_id)) continue;
65
- const src = String(e.source_id);
66
- const tgt = String(e.target_id);
67
- if (src === tgt) continue;
68
- if (!graph.hasEdge(src, tgt)) {
69
- graph.addEdge(src, tgt);
70
- }
71
- }
72
- }
73
-
74
- return graph;
75
- }
2
+ import { openRepo } from '../db/index.js';
3
+ import { louvainCommunities } from '../graph/algorithms/louvain.js';
4
+ import { buildDependencyGraph } from '../graph/builders/dependency.js';
5
+ import { paginateResult } from '../shared/paginate.js';
76
6
 
77
7
  // ─── Directory Helpers ────────────────────────────────────────────────
78
8
 
@@ -96,40 +26,39 @@ function getDirectory(filePath) {
96
26
  * @returns {{ communities: object[], modularity: number, drift: object, summary: object }}
97
27
  */
98
28
  export function communitiesData(customDbPath, opts = {}) {
99
- const db = openReadonlyOrFail(customDbPath);
100
- const resolution = opts.resolution ?? 1.0;
29
+ const { repo, close } = openRepo(customDbPath, opts);
101
30
  let graph;
102
31
  try {
103
- graph = buildGraphologyGraph(db, {
104
- functions: opts.functions,
32
+ graph = buildDependencyGraph(repo, {
33
+ fileLevel: !opts.functions,
105
34
  noTests: opts.noTests,
106
35
  });
107
36
  } finally {
108
- db.close();
37
+ close();
109
38
  }
110
39
 
111
40
  // Handle empty or trivial graphs
112
- if (graph.order === 0 || graph.size === 0) {
41
+ if (graph.nodeCount === 0 || graph.edgeCount === 0) {
113
42
  return {
114
43
  communities: [],
115
44
  modularity: 0,
116
45
  drift: { splitCandidates: [], mergeCandidates: [] },
117
- summary: { communityCount: 0, modularity: 0, nodeCount: graph.order, driftScore: 0 },
46
+ summary: { communityCount: 0, modularity: 0, nodeCount: graph.nodeCount, driftScore: 0 },
118
47
  };
119
48
  }
120
49
 
121
50
  // Run Louvain
122
- const details = louvain.detailed(graph, { resolution });
123
- const assignments = details.communities; // node community id
124
- const modularity = details.modularity;
51
+ const resolution = opts.resolution ?? 1.0;
52
+ const { assignments, modularity } = louvainCommunities(graph, { resolution });
125
53
 
126
54
  // Group nodes by community
127
55
  const communityMap = new Map(); // community id → node keys[]
128
- graph.forEachNode((key) => {
129
- const cid = assignments[key];
56
+ for (const [key] of graph.nodes()) {
57
+ const cid = assignments.get(key);
58
+ if (cid == null) continue;
130
59
  if (!communityMap.has(cid)) communityMap.set(cid, []);
131
60
  communityMap.get(cid).push(key);
132
- });
61
+ }
133
62
 
134
63
  // Build community objects
135
64
  const communities = [];
@@ -139,7 +68,7 @@ export function communitiesData(customDbPath, opts = {}) {
139
68
  const dirCounts = {};
140
69
  const memberData = [];
141
70
  for (const key of members) {
142
- const attrs = graph.getNodeAttributes(key);
71
+ const attrs = graph.getNodeAttrs(key);
143
72
  const dir = getDirectory(attrs.file);
144
73
  dirCounts[dir] = (dirCounts[dir] || 0) + 1;
145
74
  memberData.push({
@@ -196,7 +125,6 @@ export function communitiesData(customDbPath, opts = {}) {
196
125
  mergeCandidates.sort((a, b) => b.directoryCount - a.directoryCount);
197
126
 
198
127
  // Drift score: 0-100 based on how much directory structure diverges from communities
199
- // Higher = more drift (directories don't match communities)
200
128
  const totalDirs = dirToCommunities.size;
201
129
  const splitDirs = splitCandidates.length;
202
130
  const splitRatio = totalDirs > 0 ? splitDirs / totalDirs : 0;
@@ -214,7 +142,7 @@ export function communitiesData(customDbPath, opts = {}) {
214
142
  summary: {
215
143
  communityCount: communities.length,
216
144
  modularity: +modularity.toFixed(4),
217
- nodeCount: graph.order,
145
+ nodeCount: graph.nodeCount,
218
146
  driftScore,
219
147
  },
220
148
  };
@@ -3,20 +3,20 @@ import path from 'node:path';
3
3
  import {
4
4
  computeLOCMetrics as _computeLOCMetrics,
5
5
  computeMaintainabilityIndex as _computeMaintainabilityIndex,
6
- } from './ast-analysis/metrics.js';
7
- import { COMPLEXITY_RULES, HALSTEAD_RULES } from './ast-analysis/rules/index.js';
6
+ } from '../ast-analysis/metrics.js';
7
+ import { COMPLEXITY_RULES, HALSTEAD_RULES } from '../ast-analysis/rules/index.js';
8
8
  import {
9
9
  findFunctionNode as _findFunctionNode,
10
10
  buildExtensionSet,
11
11
  buildExtToLangMap,
12
- } from './ast-analysis/shared.js';
13
- import { walkWithVisitors } from './ast-analysis/visitor.js';
14
- import { createComplexityVisitor } from './ast-analysis/visitors/complexity-visitor.js';
15
- import { loadConfig } from './config.js';
16
- import { getFunctionNodeId, openReadonlyOrFail } from './db.js';
17
- import { isTestFile } from './infrastructure/test-filter.js';
18
- import { info } from './logger.js';
19
- import { paginateResult } from './paginate.js';
12
+ } from '../ast-analysis/shared.js';
13
+ import { walkWithVisitors } from '../ast-analysis/visitor.js';
14
+ import { createComplexityVisitor } from '../ast-analysis/visitors/complexity-visitor.js';
15
+ import { getFunctionNodeId, openReadonlyOrFail } from '../db/index.js';
16
+ import { loadConfig } from '../infrastructure/config.js';
17
+ import { info } from '../infrastructure/logger.js';
18
+ import { isTestFile } from '../infrastructure/test-filter.js';
19
+ import { paginateResult } from '../shared/paginate.js';
20
20
 
21
21
  // Re-export rules for backward compatibility
22
22
  export { COMPLEXITY_RULES, HALSTEAD_RULES };
@@ -360,12 +360,12 @@ export async function buildComplexityMetrics(db, fileSymbols, rootDir, _engineOp
360
360
  }
361
361
  }
362
362
  if (needsFallback) {
363
- const { createParsers } = await import('./parser.js');
363
+ const { createParsers } = await import('../domain/parser.js');
364
364
  parsers = await createParsers();
365
365
  extToLang = buildExtToLangMap();
366
366
  }
367
367
 
368
- const { getParser } = await import('./parser.js');
368
+ const { getParser } = await import('../domain/parser.js');
369
369
 
370
370
  const upsert = db.prepare(
371
371
  `INSERT OR REPLACE INTO function_complexity
@@ -524,7 +524,7 @@ export function complexityData(customDbPath, opts = {}) {
524
524
  const kindFilter = opts.kind || null;
525
525
 
526
526
  // Load thresholds from config
527
- const config = loadConfig(process.cwd());
527
+ const config = opts.config || loadConfig(process.cwd());
528
528
  const thresholds = config.manifesto?.rules || {
529
529
  cognitive: { warn: 15, fail: null },
530
530
  cyclomatic: { warn: 10, fail: null },
@@ -11,23 +11,22 @@
11
11
 
12
12
  import fs from 'node:fs';
13
13
  import path from 'node:path';
14
- import { DATAFLOW_RULES } from './ast-analysis/rules/index.js';
14
+ import { DATAFLOW_RULES } from '../ast-analysis/rules/index.js';
15
15
  import {
16
16
  makeDataflowRules as _makeDataflowRules,
17
17
  buildExtensionSet,
18
18
  buildExtToLangMap,
19
- } from './ast-analysis/shared.js';
20
- import { walkWithVisitors } from './ast-analysis/visitor.js';
21
- import { createDataflowVisitor } from './ast-analysis/visitors/dataflow-visitor.js';
22
- import { hasDataflowTable, openReadonlyOrFail } from './db.js';
23
- import { isTestFile } from './infrastructure/test-filter.js';
24
- import { info } from './logger.js';
25
- import { paginateResult } from './paginate.js';
26
- import { ALL_SYMBOL_KINDS, normalizeSymbol } from './queries.js';
19
+ } from '../ast-analysis/shared.js';
20
+ import { walkWithVisitors } from '../ast-analysis/visitor.js';
21
+ import { createDataflowVisitor } from '../ast-analysis/visitors/dataflow-visitor.js';
22
+ import { hasDataflowTable, openReadonlyOrFail } from '../db/index.js';
23
+ import { ALL_SYMBOL_KINDS, normalizeSymbol } from '../domain/queries.js';
24
+ import { info } from '../infrastructure/logger.js';
25
+ import { isTestFile } from '../infrastructure/test-filter.js';
26
+ import { paginateResult } from '../shared/paginate.js';
27
27
 
28
28
  // Re-export for backward compatibility
29
- export { DATAFLOW_RULES };
30
- export { _makeDataflowRules as makeDataflowRules };
29
+ export { _makeDataflowRules as makeDataflowRules, DATAFLOW_RULES };
31
30
 
32
31
  export const DATAFLOW_EXTENSIONS = buildExtensionSet(DATAFLOW_RULES);
33
32
 
@@ -89,13 +88,13 @@ export async function buildDataflowEdges(db, fileSymbols, rootDir, _engineOpts)
89
88
  }
90
89
 
91
90
  if (needsFallback) {
92
- const { createParsers } = await import('./parser.js');
91
+ const { createParsers } = await import('../domain/parser.js');
93
92
  parsers = await createParsers();
94
93
  }
95
94
 
96
95
  let getParserFn = null;
97
96
  if (parsers) {
98
- const mod = await import('./parser.js');
97
+ const mod = await import('../domain/parser.js');
99
98
  getParserFn = mod.getParser;
100
99
  }
101
100