@optave/codegraph 3.1.3 → 3.1.4

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 (185) hide show
  1. package/README.md +17 -19
  2. package/package.json +10 -7
  3. package/src/analysis/context.js +408 -0
  4. package/src/analysis/dependencies.js +341 -0
  5. package/src/analysis/exports.js +130 -0
  6. package/src/analysis/impact.js +463 -0
  7. package/src/analysis/module-map.js +322 -0
  8. package/src/analysis/roles.js +45 -0
  9. package/src/analysis/symbol-lookup.js +232 -0
  10. package/src/ast-analysis/shared.js +5 -4
  11. package/src/batch.js +2 -1
  12. package/src/builder/context.js +85 -0
  13. package/src/builder/helpers.js +218 -0
  14. package/src/builder/incremental.js +178 -0
  15. package/src/builder/pipeline.js +130 -0
  16. package/src/builder/stages/build-edges.js +297 -0
  17. package/src/builder/stages/build-structure.js +113 -0
  18. package/src/builder/stages/collect-files.js +44 -0
  19. package/src/builder/stages/detect-changes.js +413 -0
  20. package/src/builder/stages/finalize.js +139 -0
  21. package/src/builder/stages/insert-nodes.js +195 -0
  22. package/src/builder/stages/parse-files.js +28 -0
  23. package/src/builder/stages/resolve-imports.js +143 -0
  24. package/src/builder/stages/run-analyses.js +44 -0
  25. package/src/builder.js +10 -1485
  26. package/src/cfg.js +1 -2
  27. package/src/cli/commands/ast.js +26 -0
  28. package/src/cli/commands/audit.js +46 -0
  29. package/src/cli/commands/batch.js +68 -0
  30. package/src/cli/commands/branch-compare.js +21 -0
  31. package/src/cli/commands/build.js +26 -0
  32. package/src/cli/commands/cfg.js +30 -0
  33. package/src/cli/commands/check.js +79 -0
  34. package/src/cli/commands/children.js +31 -0
  35. package/src/cli/commands/co-change.js +65 -0
  36. package/src/cli/commands/communities.js +23 -0
  37. package/src/cli/commands/complexity.js +45 -0
  38. package/src/cli/commands/context.js +34 -0
  39. package/src/cli/commands/cycles.js +28 -0
  40. package/src/cli/commands/dataflow.js +32 -0
  41. package/src/cli/commands/deps.js +16 -0
  42. package/src/cli/commands/diff-impact.js +30 -0
  43. package/src/cli/commands/embed.js +30 -0
  44. package/src/cli/commands/export.js +75 -0
  45. package/src/cli/commands/exports.js +18 -0
  46. package/src/cli/commands/flow.js +36 -0
  47. package/src/cli/commands/fn-impact.js +30 -0
  48. package/src/cli/commands/impact.js +16 -0
  49. package/src/cli/commands/info.js +76 -0
  50. package/src/cli/commands/map.js +19 -0
  51. package/src/cli/commands/mcp.js +18 -0
  52. package/src/cli/commands/models.js +19 -0
  53. package/src/cli/commands/owners.js +25 -0
  54. package/src/cli/commands/path.js +36 -0
  55. package/src/cli/commands/plot.js +80 -0
  56. package/src/cli/commands/query.js +49 -0
  57. package/src/cli/commands/registry.js +100 -0
  58. package/src/cli/commands/roles.js +34 -0
  59. package/src/cli/commands/search.js +42 -0
  60. package/src/cli/commands/sequence.js +32 -0
  61. package/src/cli/commands/snapshot.js +61 -0
  62. package/src/cli/commands/stats.js +15 -0
  63. package/src/cli/commands/structure.js +32 -0
  64. package/src/cli/commands/triage.js +78 -0
  65. package/src/cli/commands/watch.js +12 -0
  66. package/src/cli/commands/where.js +24 -0
  67. package/src/cli/index.js +118 -0
  68. package/src/cli/shared/options.js +39 -0
  69. package/src/cli/shared/output.js +1 -0
  70. package/src/cli.js +11 -1522
  71. package/src/commands/check.js +5 -5
  72. package/src/commands/manifesto.js +3 -3
  73. package/src/commands/structure.js +1 -1
  74. package/src/communities.js +15 -87
  75. package/src/cycles.js +30 -85
  76. package/src/dataflow.js +1 -2
  77. package/src/db/connection.js +4 -4
  78. package/src/db/migrations.js +41 -0
  79. package/src/db/query-builder.js +6 -5
  80. package/src/db/repository/base.js +201 -0
  81. package/src/db/repository/graph-read.js +5 -2
  82. package/src/db/repository/in-memory-repository.js +584 -0
  83. package/src/db/repository/index.js +5 -1
  84. package/src/db/repository/nodes.js +63 -4
  85. package/src/db/repository/sqlite-repository.js +219 -0
  86. package/src/db.js +5 -0
  87. package/src/embeddings/generator.js +163 -0
  88. package/src/embeddings/index.js +13 -0
  89. package/src/embeddings/models.js +218 -0
  90. package/src/embeddings/search/cli-formatter.js +151 -0
  91. package/src/embeddings/search/filters.js +46 -0
  92. package/src/embeddings/search/hybrid.js +121 -0
  93. package/src/embeddings/search/keyword.js +68 -0
  94. package/src/embeddings/search/prepare.js +66 -0
  95. package/src/embeddings/search/semantic.js +145 -0
  96. package/src/embeddings/stores/fts5.js +27 -0
  97. package/src/embeddings/stores/sqlite-blob.js +24 -0
  98. package/src/embeddings/strategies/source.js +14 -0
  99. package/src/embeddings/strategies/structured.js +43 -0
  100. package/src/embeddings/strategies/text-utils.js +43 -0
  101. package/src/errors.js +78 -0
  102. package/src/export.js +217 -520
  103. package/src/extractors/csharp.js +10 -2
  104. package/src/extractors/go.js +3 -1
  105. package/src/extractors/helpers.js +71 -0
  106. package/src/extractors/java.js +9 -2
  107. package/src/extractors/javascript.js +38 -1
  108. package/src/extractors/php.js +3 -1
  109. package/src/extractors/python.js +14 -3
  110. package/src/extractors/rust.js +3 -1
  111. package/src/graph/algorithms/bfs.js +49 -0
  112. package/src/graph/algorithms/centrality.js +16 -0
  113. package/src/graph/algorithms/index.js +5 -0
  114. package/src/graph/algorithms/louvain.js +26 -0
  115. package/src/graph/algorithms/shortest-path.js +41 -0
  116. package/src/graph/algorithms/tarjan.js +49 -0
  117. package/src/graph/builders/dependency.js +91 -0
  118. package/src/graph/builders/index.js +3 -0
  119. package/src/graph/builders/structure.js +40 -0
  120. package/src/graph/builders/temporal.js +33 -0
  121. package/src/graph/classifiers/index.js +2 -0
  122. package/src/graph/classifiers/risk.js +85 -0
  123. package/src/graph/classifiers/roles.js +64 -0
  124. package/src/graph/index.js +13 -0
  125. package/src/graph/model.js +230 -0
  126. package/src/index.js +33 -210
  127. package/src/infrastructure/result-formatter.js +2 -21
  128. package/src/mcp/index.js +2 -0
  129. package/src/mcp/middleware.js +26 -0
  130. package/src/mcp/server.js +128 -0
  131. package/src/mcp/tool-registry.js +801 -0
  132. package/src/mcp/tools/ast-query.js +14 -0
  133. package/src/mcp/tools/audit.js +21 -0
  134. package/src/mcp/tools/batch-query.js +11 -0
  135. package/src/mcp/tools/branch-compare.js +10 -0
  136. package/src/mcp/tools/cfg.js +21 -0
  137. package/src/mcp/tools/check.js +43 -0
  138. package/src/mcp/tools/co-changes.js +20 -0
  139. package/src/mcp/tools/code-owners.js +12 -0
  140. package/src/mcp/tools/communities.js +15 -0
  141. package/src/mcp/tools/complexity.js +18 -0
  142. package/src/mcp/tools/context.js +17 -0
  143. package/src/mcp/tools/dataflow.js +26 -0
  144. package/src/mcp/tools/diff-impact.js +24 -0
  145. package/src/mcp/tools/execution-flow.js +26 -0
  146. package/src/mcp/tools/export-graph.js +57 -0
  147. package/src/mcp/tools/file-deps.js +12 -0
  148. package/src/mcp/tools/file-exports.js +13 -0
  149. package/src/mcp/tools/find-cycles.js +15 -0
  150. package/src/mcp/tools/fn-impact.js +15 -0
  151. package/src/mcp/tools/impact-analysis.js +12 -0
  152. package/src/mcp/tools/index.js +71 -0
  153. package/src/mcp/tools/list-functions.js +14 -0
  154. package/src/mcp/tools/list-repos.js +11 -0
  155. package/src/mcp/tools/module-map.js +6 -0
  156. package/src/mcp/tools/node-roles.js +14 -0
  157. package/src/mcp/tools/path.js +12 -0
  158. package/src/mcp/tools/query.js +30 -0
  159. package/src/mcp/tools/semantic-search.js +65 -0
  160. package/src/mcp/tools/sequence.js +17 -0
  161. package/src/mcp/tools/structure.js +15 -0
  162. package/src/mcp/tools/symbol-children.js +14 -0
  163. package/src/mcp/tools/triage.js +35 -0
  164. package/src/mcp/tools/where.js +13 -0
  165. package/src/mcp.js +2 -1470
  166. package/src/native.js +3 -1
  167. package/src/presentation/colors.js +44 -0
  168. package/src/presentation/export.js +444 -0
  169. package/src/presentation/result-formatter.js +21 -0
  170. package/src/presentation/sequence-renderer.js +43 -0
  171. package/src/presentation/table.js +47 -0
  172. package/src/presentation/viewer.js +634 -0
  173. package/src/queries.js +35 -2276
  174. package/src/resolve.js +1 -1
  175. package/src/sequence.js +2 -38
  176. package/src/shared/file-utils.js +153 -0
  177. package/src/shared/generators.js +125 -0
  178. package/src/shared/hierarchy.js +27 -0
  179. package/src/shared/normalize.js +59 -0
  180. package/src/snapshot.js +6 -5
  181. package/src/structure.js +15 -40
  182. package/src/triage.js +20 -72
  183. package/src/viewer.js +35 -656
  184. package/src/watcher.js +8 -148
  185. package/src/embedder.js +0 -1097
@@ -0,0 +1,14 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'ast_query';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { astQueryData } = await import('../../ast.js');
7
+ return astQueryData(args.pattern, ctx.dbPath, {
8
+ kind: args.kind,
9
+ file: args.file,
10
+ noTests: args.no_tests,
11
+ limit: effectiveLimit(args, name),
12
+ offset: effectiveOffset(args),
13
+ });
14
+ }
@@ -0,0 +1,21 @@
1
+ import { effectiveOffset, MCP_DEFAULTS, MCP_MAX_LIMIT } from '../middleware.js';
2
+
3
+ export const name = 'audit';
4
+
5
+ export async function handler(args, ctx) {
6
+ if (args.quick) {
7
+ const { explainData } = await ctx.getQueries();
8
+ return explainData(args.target, ctx.dbPath, {
9
+ noTests: args.no_tests,
10
+ limit: Math.min(args.limit ?? MCP_DEFAULTS.explain, MCP_MAX_LIMIT),
11
+ offset: effectiveOffset(args),
12
+ });
13
+ }
14
+ const { auditData } = await import('../../audit.js');
15
+ return auditData(args.target, ctx.dbPath, {
16
+ depth: args.depth,
17
+ file: args.file,
18
+ kind: args.kind,
19
+ noTests: args.no_tests,
20
+ });
21
+ }
@@ -0,0 +1,11 @@
1
+ export const name = 'batch_query';
2
+
3
+ export async function handler(args, ctx) {
4
+ const { batchData } = await import('../../batch.js');
5
+ return batchData(args.command, args.targets, ctx.dbPath, {
6
+ depth: args.depth,
7
+ file: args.file,
8
+ kind: args.kind,
9
+ noTests: args.no_tests,
10
+ });
11
+ }
@@ -0,0 +1,10 @@
1
+ export const name = 'branch_compare';
2
+
3
+ export async function handler(args, _ctx) {
4
+ const { branchCompareData, branchCompareMermaid } = await import('../../branch-compare.js');
5
+ const bcData = await branchCompareData(args.base, args.target, {
6
+ depth: args.depth,
7
+ noTests: args.no_tests,
8
+ });
9
+ return args.format === 'mermaid' ? branchCompareMermaid(bcData) : bcData;
10
+ }
@@ -0,0 +1,21 @@
1
+ import { effectiveOffset, MCP_DEFAULTS } from '../middleware.js';
2
+
3
+ export const name = 'cfg';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { cfgData, cfgToDOT, cfgToMermaid } = await import('../../cfg.js');
7
+ const cfgResult = cfgData(args.name, ctx.dbPath, {
8
+ file: args.file,
9
+ kind: args.kind,
10
+ noTests: args.no_tests,
11
+ limit: Math.min(args.limit ?? MCP_DEFAULTS.query, ctx.MCP_MAX_LIMIT),
12
+ offset: effectiveOffset(args),
13
+ });
14
+ if (args.format === 'dot') {
15
+ return { text: cfgToDOT(cfgResult) };
16
+ }
17
+ if (args.format === 'mermaid') {
18
+ return { text: cfgToMermaid(cfgResult) };
19
+ }
20
+ return cfgResult;
21
+ }
@@ -0,0 +1,43 @@
1
+ import { effectiveOffset, MCP_DEFAULTS, MCP_MAX_LIMIT } from '../middleware.js';
2
+
3
+ export const name = 'check';
4
+
5
+ export async function handler(args, ctx) {
6
+ const isDiffMode = args.ref || args.staged;
7
+
8
+ if (!isDiffMode && !args.rules) {
9
+ const { manifestoData } = await import('../../manifesto.js');
10
+ return manifestoData(ctx.dbPath, {
11
+ file: args.file,
12
+ noTests: args.no_tests,
13
+ kind: args.kind,
14
+ limit: Math.min(args.limit ?? MCP_DEFAULTS.manifesto, MCP_MAX_LIMIT),
15
+ offset: effectiveOffset(args),
16
+ });
17
+ }
18
+
19
+ const { checkData } = await import('../../check.js');
20
+ const checkResult = checkData(ctx.dbPath, {
21
+ ref: args.ref,
22
+ staged: args.staged,
23
+ cycles: args.cycles,
24
+ blastRadius: args.blast_radius,
25
+ signatures: args.signatures,
26
+ boundaries: args.boundaries,
27
+ depth: args.depth,
28
+ noTests: args.no_tests,
29
+ });
30
+
31
+ if (args.rules) {
32
+ const { manifestoData } = await import('../../manifesto.js');
33
+ const manifestoResult = manifestoData(ctx.dbPath, {
34
+ file: args.file,
35
+ noTests: args.no_tests,
36
+ kind: args.kind,
37
+ limit: Math.min(args.limit ?? MCP_DEFAULTS.manifesto, MCP_MAX_LIMIT),
38
+ offset: effectiveOffset(args),
39
+ });
40
+ return { check: checkResult, manifesto: manifestoResult };
41
+ }
42
+ return checkResult;
43
+ }
@@ -0,0 +1,20 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'co_changes';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { coChangeData, coChangeTopData } = await import('../../cochange.js');
7
+ return args.file
8
+ ? coChangeData(args.file, ctx.dbPath, {
9
+ limit: effectiveLimit(args, name),
10
+ offset: effectiveOffset(args),
11
+ minJaccard: args.min_jaccard,
12
+ noTests: args.no_tests,
13
+ })
14
+ : coChangeTopData(ctx.dbPath, {
15
+ limit: effectiveLimit(args, name),
16
+ offset: effectiveOffset(args),
17
+ minJaccard: args.min_jaccard,
18
+ noTests: args.no_tests,
19
+ });
20
+ }
@@ -0,0 +1,12 @@
1
+ export const name = 'code_owners';
2
+
3
+ export async function handler(args, ctx) {
4
+ const { ownersData } = await import('../../owners.js');
5
+ return ownersData(ctx.dbPath, {
6
+ file: args.file,
7
+ owner: args.owner,
8
+ boundary: args.boundary,
9
+ kind: args.kind,
10
+ noTests: args.no_tests,
11
+ });
12
+ }
@@ -0,0 +1,15 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'communities';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { communitiesData } = await import('../../communities.js');
7
+ return communitiesData(ctx.dbPath, {
8
+ functions: args.functions,
9
+ resolution: args.resolution,
10
+ drift: args.drift,
11
+ noTests: args.no_tests,
12
+ limit: effectiveLimit(args, name),
13
+ offset: effectiveOffset(args),
14
+ });
15
+ }
@@ -0,0 +1,18 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'complexity';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { complexityData } = await import('../../complexity.js');
7
+ return complexityData(ctx.dbPath, {
8
+ target: args.name,
9
+ file: args.file,
10
+ limit: effectiveLimit(args, name),
11
+ offset: effectiveOffset(args),
12
+ sort: args.sort,
13
+ aboveThreshold: args.above_threshold,
14
+ health: args.health,
15
+ noTests: args.no_tests,
16
+ kind: args.kind,
17
+ });
18
+ }
@@ -0,0 +1,17 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'context';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { contextData } = await ctx.getQueries();
7
+ return contextData(args.name, ctx.dbPath, {
8
+ depth: args.depth,
9
+ file: args.file,
10
+ kind: args.kind,
11
+ noSource: args.no_source,
12
+ noTests: args.no_tests,
13
+ includeTests: args.include_tests,
14
+ limit: effectiveLimit(args, name),
15
+ offset: effectiveOffset(args),
16
+ });
17
+ }
@@ -0,0 +1,26 @@
1
+ import { effectiveOffset, MCP_DEFAULTS } from '../middleware.js';
2
+
3
+ export const name = 'dataflow';
4
+
5
+ export async function handler(args, ctx) {
6
+ const dfMode = args.mode || 'edges';
7
+ if (dfMode === 'impact') {
8
+ const { dataflowImpactData } = await import('../../dataflow.js');
9
+ return dataflowImpactData(args.name, ctx.dbPath, {
10
+ depth: args.depth,
11
+ file: args.file,
12
+ kind: args.kind,
13
+ noTests: args.no_tests,
14
+ limit: Math.min(args.limit ?? MCP_DEFAULTS.fn_impact, ctx.MCP_MAX_LIMIT),
15
+ offset: effectiveOffset(args),
16
+ });
17
+ }
18
+ const { dataflowData } = await import('../../dataflow.js');
19
+ return dataflowData(args.name, ctx.dbPath, {
20
+ file: args.file,
21
+ kind: args.kind,
22
+ noTests: args.no_tests,
23
+ limit: Math.min(args.limit ?? MCP_DEFAULTS.query, ctx.MCP_MAX_LIMIT),
24
+ offset: effectiveOffset(args),
25
+ });
26
+ }
@@ -0,0 +1,24 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'diff_impact';
4
+
5
+ export async function handler(args, ctx) {
6
+ if (args.format === 'mermaid') {
7
+ const { diffImpactMermaid } = await ctx.getQueries();
8
+ return diffImpactMermaid(ctx.dbPath, {
9
+ staged: args.staged,
10
+ ref: args.ref,
11
+ depth: args.depth,
12
+ noTests: args.no_tests,
13
+ });
14
+ }
15
+ const { diffImpactData } = await ctx.getQueries();
16
+ return diffImpactData(ctx.dbPath, {
17
+ staged: args.staged,
18
+ ref: args.ref,
19
+ depth: args.depth,
20
+ noTests: args.no_tests,
21
+ limit: effectiveLimit(args, name),
22
+ offset: effectiveOffset(args),
23
+ });
24
+ }
@@ -0,0 +1,26 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'execution_flow';
4
+
5
+ export async function handler(args, ctx) {
6
+ if (args.list) {
7
+ const { listEntryPointsData } = await import('../../flow.js');
8
+ return listEntryPointsData(ctx.dbPath, {
9
+ noTests: args.no_tests,
10
+ limit: effectiveLimit(args, name),
11
+ offset: effectiveOffset(args),
12
+ });
13
+ }
14
+ if (!args.name) {
15
+ return { error: 'Provide a name or set list=true' };
16
+ }
17
+ const { flowData } = await import('../../flow.js');
18
+ return flowData(args.name, ctx.dbPath, {
19
+ depth: args.depth,
20
+ file: args.file,
21
+ kind: args.kind,
22
+ noTests: args.no_tests,
23
+ limit: effectiveLimit(args, name),
24
+ offset: effectiveOffset(args),
25
+ });
26
+ }
@@ -0,0 +1,57 @@
1
+ import { findDbPath } from '../../db.js';
2
+ import { effectiveOffset, MCP_DEFAULTS, MCP_MAX_LIMIT } from '../middleware.js';
3
+
4
+ export const name = 'export_graph';
5
+
6
+ export async function handler(args, ctx) {
7
+ const { exportDOT, exportGraphML, exportGraphSON, exportJSON, exportMermaid, exportNeo4jCSV } =
8
+ await import('../../export.js');
9
+ const Database = ctx.getDatabase();
10
+ const db = new Database(findDbPath(ctx.dbPath), { readonly: true });
11
+ const fileLevel = args.file_level !== false;
12
+ const exportLimit = args.limit ? Math.min(args.limit, MCP_MAX_LIMIT) : MCP_DEFAULTS.export_graph;
13
+
14
+ let result;
15
+ try {
16
+ switch (args.format) {
17
+ case 'dot':
18
+ result = exportDOT(db, { fileLevel, limit: exportLimit });
19
+ break;
20
+ case 'mermaid':
21
+ result = exportMermaid(db, { fileLevel, limit: exportLimit });
22
+ break;
23
+ case 'json':
24
+ result = exportJSON(db, {
25
+ limit: exportLimit,
26
+ offset: effectiveOffset(args),
27
+ });
28
+ break;
29
+ case 'graphml':
30
+ result = exportGraphML(db, { fileLevel, limit: exportLimit });
31
+ break;
32
+ case 'graphson':
33
+ result = exportGraphSON(db, {
34
+ fileLevel,
35
+ limit: exportLimit,
36
+ offset: effectiveOffset(args),
37
+ });
38
+ break;
39
+ case 'neo4j':
40
+ result = exportNeo4jCSV(db, { fileLevel, limit: exportLimit });
41
+ break;
42
+ default:
43
+ return {
44
+ content: [
45
+ {
46
+ type: 'text',
47
+ text: `Unknown format: ${args.format}. Use dot, mermaid, json, graphml, graphson, or neo4j.`,
48
+ },
49
+ ],
50
+ isError: true,
51
+ };
52
+ }
53
+ } finally {
54
+ db.close();
55
+ }
56
+ return result;
57
+ }
@@ -0,0 +1,12 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'file_deps';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { fileDepsData } = await ctx.getQueries();
7
+ return fileDepsData(args.file, ctx.dbPath, {
8
+ noTests: args.no_tests,
9
+ limit: effectiveLimit(args, name),
10
+ offset: effectiveOffset(args),
11
+ });
12
+ }
@@ -0,0 +1,13 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'file_exports';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { exportsData } = await ctx.getQueries();
7
+ return exportsData(args.file, ctx.dbPath, {
8
+ noTests: args.no_tests,
9
+ unused: args.unused,
10
+ limit: effectiveLimit(args, name),
11
+ offset: effectiveOffset(args),
12
+ });
13
+ }
@@ -0,0 +1,15 @@
1
+ import { findCycles } from '../../cycles.js';
2
+ import { findDbPath } from '../../db.js';
3
+
4
+ export const name = 'find_cycles';
5
+
6
+ export async function handler(_args, ctx) {
7
+ const Database = ctx.getDatabase();
8
+ const db = new Database(findDbPath(ctx.dbPath), { readonly: true });
9
+ try {
10
+ const cycles = findCycles(db);
11
+ return { cycles, count: cycles.length };
12
+ } finally {
13
+ db.close();
14
+ }
15
+ }
@@ -0,0 +1,15 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'fn_impact';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { fnImpactData } = await ctx.getQueries();
7
+ return fnImpactData(args.name, ctx.dbPath, {
8
+ depth: args.depth,
9
+ file: args.file,
10
+ kind: args.kind,
11
+ noTests: args.no_tests,
12
+ limit: effectiveLimit(args, name),
13
+ offset: effectiveOffset(args),
14
+ });
15
+ }
@@ -0,0 +1,12 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'impact_analysis';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { impactAnalysisData } = await ctx.getQueries();
7
+ return impactAnalysisData(args.file, ctx.dbPath, {
8
+ noTests: args.no_tests,
9
+ limit: effectiveLimit(args, name),
10
+ offset: effectiveOffset(args),
11
+ });
12
+ }
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Barrel module — registers all MCP tool handlers.
3
+ */
4
+
5
+ import * as astQuery from './ast-query.js';
6
+ import * as audit from './audit.js';
7
+ import * as batchQuery from './batch-query.js';
8
+ import * as branchCompare from './branch-compare.js';
9
+ import * as cfg from './cfg.js';
10
+ import * as check from './check.js';
11
+ import * as coChanges from './co-changes.js';
12
+ import * as codeOwners from './code-owners.js';
13
+ import * as communities from './communities.js';
14
+ import * as complexity from './complexity.js';
15
+ import * as context from './context.js';
16
+ import * as dataflow from './dataflow.js';
17
+ import * as diffImpact from './diff-impact.js';
18
+ import * as executionFlow from './execution-flow.js';
19
+ import * as exportGraph from './export-graph.js';
20
+ import * as fileDeps from './file-deps.js';
21
+ import * as fileExports from './file-exports.js';
22
+ import * as findCycles from './find-cycles.js';
23
+ import * as fnImpact from './fn-impact.js';
24
+ import * as impactAnalysis from './impact-analysis.js';
25
+ import * as listFunctions from './list-functions.js';
26
+ import * as listRepos from './list-repos.js';
27
+ import * as moduleMap from './module-map.js';
28
+ import * as nodeRoles from './node-roles.js';
29
+ import * as path from './path.js';
30
+ import * as query from './query.js';
31
+ import * as semanticSearch from './semantic-search.js';
32
+ import * as sequence from './sequence.js';
33
+ import * as structure from './structure.js';
34
+ import * as symbolChildren from './symbol-children.js';
35
+ import * as triage from './triage.js';
36
+ import * as where from './where.js';
37
+
38
+ export const TOOL_HANDLERS = new Map([
39
+ [query.name, query],
40
+ [path.name, path],
41
+ [fileDeps.name, fileDeps],
42
+ [fileExports.name, fileExports],
43
+ [impactAnalysis.name, impactAnalysis],
44
+ [findCycles.name, findCycles],
45
+ [moduleMap.name, moduleMap],
46
+ [fnImpact.name, fnImpact],
47
+ [context.name, context],
48
+ [symbolChildren.name, symbolChildren],
49
+ [where.name, where],
50
+ [diffImpact.name, diffImpact],
51
+ [semanticSearch.name, semanticSearch],
52
+ [exportGraph.name, exportGraph],
53
+ [listFunctions.name, listFunctions],
54
+ [structure.name, structure],
55
+ [nodeRoles.name, nodeRoles],
56
+ [coChanges.name, coChanges],
57
+ [executionFlow.name, executionFlow],
58
+ [sequence.name, sequence],
59
+ [complexity.name, complexity],
60
+ [communities.name, communities],
61
+ [codeOwners.name, codeOwners],
62
+ [audit.name, audit],
63
+ [batchQuery.name, batchQuery],
64
+ [triage.name, triage],
65
+ [branchCompare.name, branchCompare],
66
+ [cfg.name, cfg],
67
+ [dataflow.name, dataflow],
68
+ [check.name, check],
69
+ [astQuery.name, astQuery],
70
+ [listRepos.name, listRepos],
71
+ ]);
@@ -0,0 +1,14 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'list_functions';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { listFunctionsData } = await ctx.getQueries();
7
+ return listFunctionsData(ctx.dbPath, {
8
+ file: args.file,
9
+ pattern: args.pattern,
10
+ noTests: args.no_tests,
11
+ limit: effectiveLimit(args, name),
12
+ offset: effectiveOffset(args),
13
+ });
14
+ }
@@ -0,0 +1,11 @@
1
+ export const name = 'list_repos';
2
+
3
+ export async function handler(_args, ctx) {
4
+ const { listRepos, pruneRegistry } = await import('../../registry.js');
5
+ pruneRegistry();
6
+ let repos = listRepos();
7
+ if (ctx.allowedRepos) {
8
+ repos = repos.filter((r) => ctx.allowedRepos.includes(r.name));
9
+ }
10
+ return { repos };
11
+ }
@@ -0,0 +1,6 @@
1
+ export const name = 'module_map';
2
+
3
+ export async function handler(args, ctx) {
4
+ const { moduleMapData } = await ctx.getQueries();
5
+ return moduleMapData(ctx.dbPath, args.limit || 20, { noTests: args.no_tests });
6
+ }
@@ -0,0 +1,14 @@
1
+ import { effectiveLimit, effectiveOffset } from '../middleware.js';
2
+
3
+ export const name = 'node_roles';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { rolesData } = await ctx.getQueries();
7
+ return rolesData(ctx.dbPath, {
8
+ role: args.role,
9
+ file: args.file,
10
+ noTests: args.no_tests,
11
+ limit: effectiveLimit(args, name),
12
+ offset: effectiveOffset(args),
13
+ });
14
+ }
@@ -0,0 +1,12 @@
1
+ export const name = 'path';
2
+
3
+ export async function handler(args, ctx) {
4
+ const { pathData } = await ctx.getQueries();
5
+ return pathData(args.from, args.to, ctx.dbPath, {
6
+ maxDepth: args.depth ?? 10,
7
+ edgeKinds: args.edge_kinds,
8
+ fromFile: args.from_file,
9
+ toFile: args.to_file,
10
+ noTests: args.no_tests,
11
+ });
12
+ }
@@ -0,0 +1,30 @@
1
+ import { effectiveOffset, MCP_DEFAULTS } from '../middleware.js';
2
+
3
+ export const name = 'query';
4
+
5
+ export async function handler(args, ctx) {
6
+ const { fnDepsData, pathData } = await ctx.getQueries();
7
+ const qMode = args.mode || 'deps';
8
+ if (qMode === 'path') {
9
+ if (!args.to) {
10
+ return { error: 'path mode requires a "to" argument' };
11
+ }
12
+ return pathData(args.name, args.to, ctx.dbPath, {
13
+ maxDepth: args.depth ?? 10,
14
+ edgeKinds: args.edge_kinds,
15
+ reverse: args.reverse,
16
+ fromFile: args.from_file,
17
+ toFile: args.to_file,
18
+ kind: args.kind,
19
+ noTests: args.no_tests,
20
+ });
21
+ }
22
+ return fnDepsData(args.name, ctx.dbPath, {
23
+ depth: args.depth,
24
+ file: args.file,
25
+ kind: args.kind,
26
+ noTests: args.no_tests,
27
+ limit: Math.min(args.limit ?? MCP_DEFAULTS.query, ctx.MCP_MAX_LIMIT),
28
+ offset: effectiveOffset(args),
29
+ });
30
+ }
@@ -0,0 +1,65 @@
1
+ import { effectiveOffset, MCP_DEFAULTS, MCP_MAX_LIMIT } from '../middleware.js';
2
+
3
+ export const name = 'semantic_search';
4
+
5
+ export async function handler(args, ctx) {
6
+ const mode = args.mode || 'hybrid';
7
+ const searchOpts = {
8
+ limit: Math.min(args.limit ?? MCP_DEFAULTS.semantic_search, MCP_MAX_LIMIT),
9
+ offset: effectiveOffset(args),
10
+ minScore: args.min_score,
11
+ };
12
+
13
+ if (mode === 'keyword') {
14
+ const { ftsSearchData } = await import('../../embeddings/index.js');
15
+ const result = ftsSearchData(args.query, ctx.dbPath, searchOpts);
16
+ if (result === null) {
17
+ return {
18
+ content: [
19
+ {
20
+ type: 'text',
21
+ text: 'No FTS5 index found. Run `codegraph embed` to build the keyword index.',
22
+ },
23
+ ],
24
+ isError: true,
25
+ };
26
+ }
27
+ return result;
28
+ }
29
+
30
+ if (mode === 'semantic') {
31
+ const { searchData } = await import('../../embeddings/index.js');
32
+ const result = await searchData(args.query, ctx.dbPath, searchOpts);
33
+ if (result === null) {
34
+ return {
35
+ content: [
36
+ {
37
+ type: 'text',
38
+ text: 'Semantic search unavailable. Run `codegraph embed` first.',
39
+ },
40
+ ],
41
+ isError: true,
42
+ };
43
+ }
44
+ return result;
45
+ }
46
+
47
+ // hybrid (default) — falls back to semantic if no FTS5
48
+ const { hybridSearchData, searchData } = await import('../../embeddings/index.js');
49
+ let result = await hybridSearchData(args.query, ctx.dbPath, searchOpts);
50
+ if (result === null) {
51
+ result = await searchData(args.query, ctx.dbPath, searchOpts);
52
+ if (result === null) {
53
+ return {
54
+ content: [
55
+ {
56
+ type: 'text',
57
+ text: 'Semantic search unavailable. Run `codegraph embed` first.',
58
+ },
59
+ ],
60
+ isError: true,
61
+ };
62
+ }
63
+ }
64
+ return result;
65
+ }