purecontext-mcp 1.1.7 → 1.2.0

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 (182) hide show
  1. package/AGENT_INSTRUCTIONS.md +393 -0
  2. package/AGENT_INSTRUCTIONS_SHORT.md +53 -0
  3. package/AST-SEARCH.md +274 -0
  4. package/CHANGELOG.md +62 -0
  5. package/CODE-INTELLIGENCE.md +369 -0
  6. package/HEALTH-DASHBOARDS.md +241 -0
  7. package/README.md +7 -0
  8. package/REFACTORING-SAFELY.md +279 -0
  9. package/UNDERSTANDING-RELATIONSHIPS.md +240 -0
  10. package/USER-GUIDE.md +14 -0
  11. package/VISUALIZING-CODE.md +199 -0
  12. package/WORKFLOW-TECH-DEBT.md +286 -0
  13. package/dist/core/db/dep-store.d.ts +75 -0
  14. package/dist/core/db/dep-store.d.ts.map +1 -1
  15. package/dist/core/db/dep-store.js +277 -0
  16. package/dist/core/db/dep-store.js.map +1 -1
  17. package/dist/core/db/schema.d.ts.map +1 -1
  18. package/dist/core/db/schema.js +12 -0
  19. package/dist/core/db/schema.js.map +1 -1
  20. package/dist/core/index-manager.js +1 -1
  21. package/dist/core/index-manager.js.map +1 -1
  22. package/dist/core/token-tracker.d.ts +0 -9
  23. package/dist/core/token-tracker.d.ts.map +1 -1
  24. package/dist/core/token-tracker.js +0 -21
  25. package/dist/core/token-tracker.js.map +1 -1
  26. package/dist/core/types.d.ts +5 -0
  27. package/dist/core/types.d.ts.map +1 -1
  28. package/dist/graph/diagram-renderer.d.ts +83 -0
  29. package/dist/graph/diagram-renderer.d.ts.map +1 -0
  30. package/dist/graph/diagram-renderer.js +294 -0
  31. package/dist/graph/diagram-renderer.js.map +1 -0
  32. package/dist/graph/graph-traversal.d.ts +92 -0
  33. package/dist/graph/graph-traversal.d.ts.map +1 -1
  34. package/dist/graph/graph-traversal.js +440 -2
  35. package/dist/graph/graph-traversal.js.map +1 -1
  36. package/dist/server/http-server.d.ts.map +1 -1
  37. package/dist/server/http-server.js +30 -1
  38. package/dist/server/http-server.js.map +1 -1
  39. package/dist/server/mcp-server.d.ts.map +1 -1
  40. package/dist/server/mcp-server.js +145 -0
  41. package/dist/server/mcp-server.js.map +1 -1
  42. package/dist/server/tools/_meta.d.ts +0 -2
  43. package/dist/server/tools/_meta.d.ts.map +1 -1
  44. package/dist/server/tools/_meta.js +1 -4
  45. package/dist/server/tools/_meta.js.map +1 -1
  46. package/dist/server/tools/check-delete-safe.d.ts +50 -0
  47. package/dist/server/tools/check-delete-safe.d.ts.map +1 -0
  48. package/dist/server/tools/check-delete-safe.js +308 -0
  49. package/dist/server/tools/check-delete-safe.js.map +1 -0
  50. package/dist/server/tools/check-move-safe.d.ts +44 -0
  51. package/dist/server/tools/check-move-safe.d.ts.map +1 -0
  52. package/dist/server/tools/check-move-safe.js +266 -0
  53. package/dist/server/tools/check-move-safe.js.map +1 -0
  54. package/dist/server/tools/check-rename-safe.d.ts +48 -0
  55. package/dist/server/tools/check-rename-safe.d.ts.map +1 -0
  56. package/dist/server/tools/check-rename-safe.js +218 -0
  57. package/dist/server/tools/check-rename-safe.js.map +1 -0
  58. package/dist/server/tools/diff-health-radar.d.ts +44 -0
  59. package/dist/server/tools/diff-health-radar.d.ts.map +1 -0
  60. package/dist/server/tools/diff-health-radar.js +192 -0
  61. package/dist/server/tools/diff-health-radar.js.map +1 -0
  62. package/dist/server/tools/find-cycles.d.ts +31 -0
  63. package/dist/server/tools/find-cycles.d.ts.map +1 -0
  64. package/dist/server/tools/find-cycles.js +85 -0
  65. package/dist/server/tools/find-cycles.js.map +1 -0
  66. package/dist/server/tools/find-implementations.d.ts +47 -0
  67. package/dist/server/tools/find-implementations.d.ts.map +1 -0
  68. package/dist/server/tools/find-implementations.js +167 -0
  69. package/dist/server/tools/find-implementations.js.map +1 -0
  70. package/dist/server/tools/find-untested-symbols.d.ts +52 -0
  71. package/dist/server/tools/find-untested-symbols.d.ts.map +1 -0
  72. package/dist/server/tools/find-untested-symbols.js +308 -0
  73. package/dist/server/tools/find-untested-symbols.js.map +1 -0
  74. package/dist/server/tools/get-architecture-snapshot.d.ts +43 -0
  75. package/dist/server/tools/get-architecture-snapshot.d.ts.map +1 -0
  76. package/dist/server/tools/get-architecture-snapshot.js +292 -0
  77. package/dist/server/tools/get-architecture-snapshot.js.map +1 -0
  78. package/dist/server/tools/get-call-hierarchy.d.ts +43 -0
  79. package/dist/server/tools/get-call-hierarchy.d.ts.map +1 -0
  80. package/dist/server/tools/get-call-hierarchy.js +119 -0
  81. package/dist/server/tools/get-call-hierarchy.js.map +1 -0
  82. package/dist/server/tools/get-class-hierarchy.d.ts +36 -0
  83. package/dist/server/tools/get-class-hierarchy.d.ts.map +1 -0
  84. package/dist/server/tools/get-class-hierarchy.js +125 -0
  85. package/dist/server/tools/get-class-hierarchy.js.map +1 -0
  86. package/dist/server/tools/get-complexity-hotspots.d.ts +50 -0
  87. package/dist/server/tools/get-complexity-hotspots.d.ts.map +1 -0
  88. package/dist/server/tools/get-complexity-hotspots.js +282 -0
  89. package/dist/server/tools/get-complexity-hotspots.js.map +1 -0
  90. package/dist/server/tools/get-coupling-map.d.ts +39 -0
  91. package/dist/server/tools/get-coupling-map.d.ts.map +1 -0
  92. package/dist/server/tools/get-coupling-map.js +107 -0
  93. package/dist/server/tools/get-coupling-map.js.map +1 -0
  94. package/dist/server/tools/get-debt-report.d.ts +44 -0
  95. package/dist/server/tools/get-debt-report.d.ts.map +1 -0
  96. package/dist/server/tools/get-debt-report.js +606 -0
  97. package/dist/server/tools/get-debt-report.js.map +1 -0
  98. package/dist/server/tools/get-entry-points.d.ts +79 -0
  99. package/dist/server/tools/get-entry-points.d.ts.map +1 -0
  100. package/dist/server/tools/get-entry-points.js +362 -0
  101. package/dist/server/tools/get-entry-points.js.map +1 -0
  102. package/dist/server/tools/get-public-api.d.ts +53 -0
  103. package/dist/server/tools/get-public-api.d.ts.map +1 -0
  104. package/dist/server/tools/get-public-api.js +218 -0
  105. package/dist/server/tools/get-public-api.js.map +1 -0
  106. package/dist/server/tools/get-savings-stats.d.ts.map +1 -1
  107. package/dist/server/tools/get-savings-stats.js +1 -3
  108. package/dist/server/tools/get-savings-stats.js.map +1 -1
  109. package/dist/server/tools/get-test-coverage-map.d.ts +66 -0
  110. package/dist/server/tools/get-test-coverage-map.d.ts.map +1 -0
  111. package/dist/server/tools/get-test-coverage-map.js +588 -0
  112. package/dist/server/tools/get-test-coverage-map.js.map +1 -0
  113. package/dist/server/tools/get-todos.d.ts +51 -0
  114. package/dist/server/tools/get-todos.d.ts.map +1 -0
  115. package/dist/server/tools/get-todos.js +180 -0
  116. package/dist/server/tools/get-todos.js.map +1 -0
  117. package/dist/server/tools/get-type-graph.d.ts +73 -0
  118. package/dist/server/tools/get-type-graph.d.ts.map +1 -0
  119. package/dist/server/tools/get-type-graph.js +437 -0
  120. package/dist/server/tools/get-type-graph.js.map +1 -0
  121. package/dist/server/tools/health-radar.d.ts +50 -0
  122. package/dist/server/tools/health-radar.d.ts.map +1 -0
  123. package/dist/server/tools/health-radar.js +426 -0
  124. package/dist/server/tools/health-radar.js.map +1 -0
  125. package/dist/server/tools/plan-refactoring.d.ts +74 -0
  126. package/dist/server/tools/plan-refactoring.d.ts.map +1 -0
  127. package/dist/server/tools/plan-refactoring.js +644 -0
  128. package/dist/server/tools/plan-refactoring.js.map +1 -0
  129. package/dist/server/tools/render-call-graph.d.ts +40 -0
  130. package/dist/server/tools/render-call-graph.d.ts.map +1 -0
  131. package/dist/server/tools/render-call-graph.js +215 -0
  132. package/dist/server/tools/render-call-graph.js.map +1 -0
  133. package/dist/server/tools/render-class-hierarchy.d.ts +42 -0
  134. package/dist/server/tools/render-class-hierarchy.d.ts.map +1 -0
  135. package/dist/server/tools/render-class-hierarchy.js +265 -0
  136. package/dist/server/tools/render-class-hierarchy.js.map +1 -0
  137. package/dist/server/tools/render-dep-matrix.d.ts +38 -0
  138. package/dist/server/tools/render-dep-matrix.d.ts.map +1 -0
  139. package/dist/server/tools/render-dep-matrix.js +186 -0
  140. package/dist/server/tools/render-dep-matrix.js.map +1 -0
  141. package/dist/server/tools/render-diagram.d.ts +47 -0
  142. package/dist/server/tools/render-diagram.d.ts.map +1 -0
  143. package/dist/server/tools/render-diagram.js +266 -0
  144. package/dist/server/tools/render-diagram.js.map +1 -0
  145. package/dist/server/tools/render-import-graph.d.ts +41 -0
  146. package/dist/server/tools/render-import-graph.d.ts.map +1 -0
  147. package/dist/server/tools/render-import-graph.js +158 -0
  148. package/dist/server/tools/render-import-graph.js.map +1 -0
  149. package/dist/server/tools/search-ast.d.ts +55 -0
  150. package/dist/server/tools/search-ast.d.ts.map +1 -0
  151. package/dist/server/tools/search-ast.js +279 -0
  152. package/dist/server/tools/search-ast.js.map +1 -0
  153. package/dist/server/tools/search-by-complexity.d.ts +92 -0
  154. package/dist/server/tools/search-by-complexity.d.ts.map +1 -0
  155. package/dist/server/tools/search-by-complexity.js +268 -0
  156. package/dist/server/tools/search-by-complexity.js.map +1 -0
  157. package/dist/server/tools/search-by-decorator.d.ts +48 -0
  158. package/dist/server/tools/search-by-decorator.d.ts.map +1 -0
  159. package/dist/server/tools/search-by-decorator.js +518 -0
  160. package/dist/server/tools/search-by-decorator.js.map +1 -0
  161. package/dist/server/tools/search-by-signature.d.ts +56 -0
  162. package/dist/server/tools/search-by-signature.d.ts.map +1 -0
  163. package/dist/server/tools/search-by-signature.js +200 -0
  164. package/dist/server/tools/search-by-signature.js.map +1 -0
  165. package/dist/ui/assets/BlastRadius-QdgESOL8.js +1 -0
  166. package/dist/ui/assets/{DependencyGraph-CDtBHM0U.js → DependencyGraph-BSMhzwWV.js} +6 -6
  167. package/dist/ui/assets/{NotFound-Cdt6X8pl.js → NotFound-CipFP_s1.js} +1 -1
  168. package/dist/ui/assets/RepoDetail-Dfp5z5Kq.js +1 -0
  169. package/dist/ui/assets/{RepoList-B9LaZvob.js → RepoList-BKtST3hB.js} +1 -1
  170. package/dist/ui/assets/{Search-CLqv2KGV.js → Search-DzhGDViy.js} +1 -1
  171. package/dist/ui/assets/{SymbolView-BlbDR1DU.js → SymbolView-ryVEwAHG.js} +1 -1
  172. package/dist/ui/assets/{index-DADf5y_L.css → index-Ny8gn9F0.css} +1 -1
  173. package/dist/ui/assets/{index-i3Q1XbEh.js → index-nX2chMqi.js} +6 -6
  174. package/dist/ui/assets/{useSearch-mbMk6-M1.js → useSearch-BnBCRKui.js} +1 -1
  175. package/dist/ui/index.html +2 -2
  176. package/dist/version.d.ts +1 -1
  177. package/dist/version.js +1 -1
  178. package/docs/dev/jcodemunch-gap-analysis.md +198 -0
  179. package/package.json +9 -1
  180. package/user-manual.md +2466 -0
  181. package/dist/ui/assets/BlastRadius-BDZWhEk-.js +0 -1
  182. package/dist/ui/assets/RepoDetail-M6WaYbZ3.js +0 -1
@@ -0,0 +1,50 @@
1
+ /**
2
+ * get-complexity-hotspots.ts
3
+ *
4
+ * MCP tool: get_complexity_hotspots
5
+ *
6
+ * Aggregates per-symbol complexity metrics to the file level and returns a
7
+ * ranked list of the files with the highest complexity concentration. Use this
8
+ * to answer "where should I focus refactoring effort?" — it surfaces files that
9
+ * contain many complex symbols, deeply nested logic, or high average cyclomatic
10
+ * complexity.
11
+ *
12
+ * Differs from related tools:
13
+ * get_quality_metrics — per-symbol composite score, not file-level aggregation
14
+ * search_by_complexity — threshold/range filter for individual symbols
15
+ * get_complexity_hotspots — file-level aggregation + hotspot ranking
16
+ *
17
+ * Designed for:
18
+ * - Identifying which files to tackle first in a refactoring sprint
19
+ * - Generating a "complexity heat map" for an architecture review
20
+ * - Spotting files that are growing too complex before they become unmaintainable
21
+ */
22
+ import { z } from 'zod';
23
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
24
+ export declare const name = "get_complexity_hotspots";
25
+ export declare const description: string;
26
+ export declare const inputSchema: {
27
+ repoId: z.ZodString;
28
+ scope: z.ZodOptional<z.ZodString>;
29
+ topN: z.ZodOptional<z.ZodNumber>;
30
+ minComplexity: z.ZodOptional<z.ZodNumber>;
31
+ metric: z.ZodOptional<z.ZodEnum<{
32
+ size: "size";
33
+ complexity: "complexity";
34
+ nesting: "nesting";
35
+ cognitive: "cognitive";
36
+ composite: "composite";
37
+ }>>;
38
+ includeSymbols: z.ZodOptional<z.ZodBoolean>;
39
+ symbolLimit: z.ZodOptional<z.ZodNumber>;
40
+ };
41
+ export declare function handler(args: {
42
+ repoId: string;
43
+ scope?: string;
44
+ topN?: number;
45
+ minComplexity?: number;
46
+ metric?: 'complexity' | 'cognitive' | 'size' | 'nesting' | 'composite';
47
+ includeSymbols?: boolean;
48
+ symbolLimit?: number;
49
+ }): Promise<CallToolResult>;
50
+ //# sourceMappingURL=get-complexity-hotspots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-complexity-hotspots.d.ts","sourceRoot":"","sources":["../../../src/server/tools/get-complexity-hotspots.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE,eAAO,MAAM,IAAI,4BAA4B,CAAC;AAE9C,eAAO,MAAM,WAAW,QAWiD,CAAC;AAE1E,eAAO,MAAM,WAAW;;;;;;;;;;;;;;CA2CvB,CAAC;AA4EF,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,YAAY,GAAG,WAAW,GAAG,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,cAAc,CAAC,CAqO1B"}
@@ -0,0 +1,282 @@
1
+ /**
2
+ * get-complexity-hotspots.ts
3
+ *
4
+ * MCP tool: get_complexity_hotspots
5
+ *
6
+ * Aggregates per-symbol complexity metrics to the file level and returns a
7
+ * ranked list of the files with the highest complexity concentration. Use this
8
+ * to answer "where should I focus refactoring effort?" — it surfaces files that
9
+ * contain many complex symbols, deeply nested logic, or high average cyclomatic
10
+ * complexity.
11
+ *
12
+ * Differs from related tools:
13
+ * get_quality_metrics — per-symbol composite score, not file-level aggregation
14
+ * search_by_complexity — threshold/range filter for individual symbols
15
+ * get_complexity_hotspots — file-level aggregation + hotspot ranking
16
+ *
17
+ * Designed for:
18
+ * - Identifying which files to tackle first in a refactoring sprint
19
+ * - Generating a "complexity heat map" for an architecture review
20
+ * - Spotting files that are growing too complex before they become unmaintainable
21
+ */
22
+ import { z } from 'zod';
23
+ import { openDatabase, getRepo } from '../../core/db/schema.js';
24
+ import { buildMeta } from './_meta.js';
25
+ export const name = 'get_complexity_hotspots';
26
+ export const description = 'Aggregate per-symbol complexity metrics to the file level and return a ranked list ' +
27
+ 'of the files with the highest complexity concentration. Use this to answer ' +
28
+ '"where should I focus refactoring effort?" — it surfaces files with many complex ' +
29
+ 'symbols, deeply nested logic, or high average cyclomatic complexity. ' +
30
+ 'Returns a hotspot score (0–100) per file, plus the top offending symbols within ' +
31
+ 'each hotspot file.' +
32
+ '\n\nDiffers from related tools:' +
33
+ '\n get_quality_metrics — per-symbol composite score ranked by worst symbols' +
34
+ '\n search_by_complexity — threshold/range filtering of individual symbols' +
35
+ '\n get_debt_report — broader tech-debt summary including comment density' +
36
+ '\n health_radar — multi-dimensional health scores per file';
37
+ export const inputSchema = {
38
+ repoId: z.string().describe('Repository ID returned by index_folder or list_repos'),
39
+ scope: z
40
+ .string()
41
+ .optional()
42
+ .describe('Restrict to a directory prefix (e.g. "src/core/"). ' +
43
+ 'Omit to analyse the entire repo.'),
44
+ topN: z
45
+ .number().int().min(1).max(100)
46
+ .optional()
47
+ .describe('Number of hotspot files to return (default 10)'),
48
+ minComplexity: z
49
+ .number().int().min(1)
50
+ .optional()
51
+ .describe('Minimum cyclomatic complexity for a symbol to count as "complex" ' +
52
+ 'when computing the complex-symbol density for each file (default 5).'),
53
+ metric: z
54
+ .enum(['complexity', 'cognitive', 'size', 'nesting', 'composite'])
55
+ .optional()
56
+ .describe('Primary metric used to rank hotspot files. ' +
57
+ '"complexity" = avg cyclomatic (default), ' +
58
+ '"cognitive" = avg cognitive complexity, ' +
59
+ '"size" = total line count, ' +
60
+ '"nesting" = max nesting depth, ' +
61
+ '"composite" = weighted hotspot score.'),
62
+ includeSymbols: z
63
+ .boolean()
64
+ .optional()
65
+ .describe('Include the top offending symbols within each hotspot file (default true). ' +
66
+ 'Set false for a compact file-level-only response.'),
67
+ symbolLimit: z
68
+ .number().int().min(1).max(20)
69
+ .optional()
70
+ .describe('Max number of symbols to include per hotspot file (default 5). ' +
71
+ 'Symbols are ranked by cyclomatic complexity descending.'),
72
+ };
73
+ // ─── Hotspot score ────────────────────────────────────────────────────────────
74
+ /**
75
+ * Composite hotspot score 0–100.
76
+ *
77
+ * Weights (must sum to 1.0):
78
+ * avg cyclomatic (35%) — ceiling at 30 (avg CC ≥ 30 → max contribution)
79
+ * max cyclomatic (30%) — ceiling at 50
80
+ * complex density (20%) — complexSymbols / symbolCount, ceiling 1.0
81
+ * max nesting (15%) — ceiling at 10 levels
82
+ */
83
+ function computeHotspotScore(stats) {
84
+ const avgCC = Math.min(stats.avgCyclomaticComplexity / 30, 1) * 100;
85
+ const maxCC = Math.min(stats.maxCyclomaticComplexity / 50, 1) * 100;
86
+ const density = stats.symbolCount > 0
87
+ ? Math.min(stats.complexSymbolCount / stats.symbolCount, 1) * 100
88
+ : 0;
89
+ const nesting = Math.min(stats.maxNestingDepth / 10, 1) * 100;
90
+ return Math.round(avgCC * 0.35 + maxCC * 0.30 + density * 0.20 + nesting * 0.15);
91
+ }
92
+ // ─── Handler ──────────────────────────────────────────────────────────────────
93
+ export async function handler(args) {
94
+ const t0 = Date.now();
95
+ const { repoId, topN = 10, minComplexity = 5, metric = 'complexity', includeSymbols = true, symbolLimit = 5, } = args;
96
+ const db = openDatabase(repoId);
97
+ try {
98
+ // ── Validate repo exists ───────────────────────────────────────────────────
99
+ const repo = getRepo(db, repoId);
100
+ if (!repo) {
101
+ return {
102
+ content: [{
103
+ type: 'text',
104
+ text: JSON.stringify({ error: `Repo "${repoId}" not found. Run index_folder first.` }),
105
+ }],
106
+ isError: true,
107
+ };
108
+ }
109
+ // ── Fetch all measurable symbols ───────────────────────────────────────────
110
+ const conditions = [
111
+ 'repo_id = @repoId',
112
+ 'line_count IS NOT NULL',
113
+ ];
114
+ const params = { repoId };
115
+ if (args.scope) {
116
+ conditions.push('(file_path = @scope OR file_path LIKE @scopePrefix)');
117
+ params['scope'] = args.scope;
118
+ params['scopePrefix'] = args.scope.endsWith('/')
119
+ ? `${args.scope}%`
120
+ : `${args.scope}/%`;
121
+ }
122
+ const sql = `
123
+ SELECT id, name, kind, file_path, start_byte, signature, summary,
124
+ COALESCE(line_count, 0) AS line_count,
125
+ COALESCE(cyclomatic_complexity, 1) AS cyclomatic_complexity,
126
+ COALESCE(cognitive_complexity, 0) AS cognitive_complexity,
127
+ COALESCE(nesting_depth, 0) AS nesting_depth,
128
+ COALESCE(param_count, 0) AS param_count,
129
+ COALESCE(return_count, 0) AS return_count
130
+ FROM symbols
131
+ WHERE ${conditions.join(' AND ')}
132
+ ORDER BY file_path ASC, cyclomatic_complexity DESC
133
+ `;
134
+ const rows = db.prepare(sql).all(params);
135
+ if (rows.length === 0) {
136
+ return {
137
+ content: [{
138
+ type: 'text',
139
+ text: JSON.stringify({
140
+ repoId,
141
+ totalFilesAnalyzed: 0,
142
+ hotspots: [],
143
+ summary: {
144
+ hotspotFileCount: 0,
145
+ avgHotspotScore: 0,
146
+ totalComplexSymbols: 0,
147
+ totalSymbolsAnalyzed: 0,
148
+ },
149
+ _tokenEstimate: 10,
150
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
151
+ }),
152
+ }],
153
+ };
154
+ }
155
+ // ── Group symbols by file ──────────────────────────────────────────────────
156
+ const fileMap = new Map();
157
+ for (const row of rows) {
158
+ const list = fileMap.get(row.file_path) ?? [];
159
+ list.push(row);
160
+ fileMap.set(row.file_path, list);
161
+ }
162
+ // ── Compute per-file stats ─────────────────────────────────────────────────
163
+ const fileStatsList = [];
164
+ for (const [filePath, syms] of fileMap) {
165
+ const symbolCount = syms.length;
166
+ const complexSymbolCount = syms.filter((s) => s.cyclomatic_complexity >= minComplexity).length;
167
+ const avgCC = syms.reduce((s, r) => s + r.cyclomatic_complexity, 0) / symbolCount;
168
+ const maxCC = Math.max(...syms.map((r) => r.cyclomatic_complexity));
169
+ const avgCog = syms.reduce((s, r) => s + r.cognitive_complexity, 0) / symbolCount;
170
+ const maxCog = Math.max(...syms.map((r) => r.cognitive_complexity));
171
+ const avgND = syms.reduce((s, r) => s + r.nesting_depth, 0) / symbolCount;
172
+ const maxND = Math.max(...syms.map((r) => r.nesting_depth));
173
+ const avgLC = syms.reduce((s, r) => s + r.line_count, 0) / symbolCount;
174
+ const totalLC = syms.reduce((s, r) => s + r.line_count, 0);
175
+ const statsWithoutScore = {
176
+ filePath,
177
+ symbolCount,
178
+ complexSymbolCount,
179
+ avgCyclomaticComplexity: Math.round(avgCC * 10) / 10,
180
+ maxCyclomaticComplexity: maxCC,
181
+ avgCognitiveComplexity: Math.round(avgCog * 10) / 10,
182
+ maxCognitiveComplexity: maxCog,
183
+ avgNestingDepth: Math.round(avgND * 10) / 10,
184
+ maxNestingDepth: maxND,
185
+ avgLineCount: Math.round(avgLC * 10) / 10,
186
+ totalLineCount: totalLC,
187
+ };
188
+ fileStatsList.push({
189
+ ...statsWithoutScore,
190
+ hotspotScore: computeHotspotScore(statsWithoutScore),
191
+ });
192
+ }
193
+ // ── Sort by chosen metric ──────────────────────────────────────────────────
194
+ fileStatsList.sort((a, b) => {
195
+ switch (metric) {
196
+ case 'cognitive': return b.avgCognitiveComplexity - a.avgCognitiveComplexity;
197
+ case 'size': return b.totalLineCount - a.totalLineCount;
198
+ case 'nesting': return b.maxNestingDepth - a.maxNestingDepth;
199
+ case 'composite': return b.hotspotScore - a.hotspotScore;
200
+ case 'complexity':
201
+ default: return b.avgCyclomaticComplexity - a.avgCyclomaticComplexity;
202
+ }
203
+ });
204
+ const topFiles = fileStatsList.slice(0, topN);
205
+ const totalFilesAnalyzed = fileStatsList.length;
206
+ // ── Resolve start lines and attach top symbols ────────────────────────────
207
+ const hotspots = [];
208
+ for (const stats of topFiles) {
209
+ const hotspot = { ...stats };
210
+ if (includeSymbols) {
211
+ const syms = fileMap.get(stats.filePath) ?? [];
212
+ // Resolve start lines from file content (best-effort)
213
+ const fileRow = db.prepare('SELECT raw_content FROM files WHERE repo_id = ? AND path = ?').get(repoId, stats.filePath);
214
+ const lineOf = (startByte) => {
215
+ if (fileRow?.raw_content) {
216
+ const slice = fileRow.raw_content.slice(0, Math.min(startByte, fileRow.raw_content.length));
217
+ let line = 1;
218
+ for (let i = 0; i < slice.length; i++) {
219
+ if (slice[i] === 0x0a)
220
+ line++;
221
+ }
222
+ return line;
223
+ }
224
+ return Math.max(1, Math.floor(startByte / 80) + 1);
225
+ };
226
+ // Top symbols ranked by cyclomatic complexity
227
+ const topSyms = [...syms]
228
+ .sort((a, b) => b.cyclomatic_complexity - a.cyclomatic_complexity)
229
+ .slice(0, symbolLimit);
230
+ hotspot.topSymbols = topSyms.map((s) => ({
231
+ symbolId: s.id,
232
+ name: s.name,
233
+ kind: s.kind,
234
+ startLine: lineOf(s.start_byte),
235
+ signature: s.signature,
236
+ summary: s.summary,
237
+ cyclomaticComplexity: s.cyclomatic_complexity,
238
+ cognitiveComplexity: s.cognitive_complexity,
239
+ lineCount: s.line_count,
240
+ nestingDepth: s.nesting_depth,
241
+ }));
242
+ }
243
+ hotspots.push(hotspot);
244
+ }
245
+ // ── Summary stats ─────────────────────────────────────────────────────────
246
+ const avgHotspotScore = topFiles.length > 0
247
+ ? Math.round(topFiles.reduce((s, f) => s + f.hotspotScore, 0) / topFiles.length)
248
+ : 0;
249
+ const totalComplexSymbols = fileStatsList.reduce((s, f) => s + f.complexSymbolCount, 0);
250
+ const totalSymbolsAnalyzed = rows.length;
251
+ // ── Token estimate ─────────────────────────────────────────────────────────
252
+ const responseBytes = hotspots.reduce((sum, h) => {
253
+ const symBytes = (h.topSymbols ?? []).reduce((s, sym) => s + sym.signature.length + sym.summary.length + 80, 0);
254
+ return sum + h.filePath.length + 150 + symBytes;
255
+ }, 0);
256
+ const tokenEstimate = Math.ceil(responseBytes / 4);
257
+ return {
258
+ content: [{
259
+ type: 'text',
260
+ text: JSON.stringify({
261
+ repoId,
262
+ totalFilesAnalyzed,
263
+ rankedBy: metric,
264
+ minComplexity,
265
+ hotspots,
266
+ summary: {
267
+ hotspotFileCount: topFiles.length,
268
+ avgHotspotScore,
269
+ totalComplexSymbols,
270
+ totalSymbolsAnalyzed,
271
+ },
272
+ _tokenEstimate: tokenEstimate,
273
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
274
+ }, null, 2),
275
+ }],
276
+ };
277
+ }
278
+ finally {
279
+ db.close();
280
+ }
281
+ }
282
+ //# sourceMappingURL=get-complexity-hotspots.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-complexity-hotspots.js","sourceRoot":"","sources":["../../../src/server/tools/get-complexity-hotspots.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * get-coupling-map.ts
3
+ *
4
+ * MCP tool: get_coupling_map
5
+ *
6
+ * Return per-file coupling scores with the named files each file depends on,
7
+ * going beyond the aggregate score in get_quality_metrics to show exactly who
8
+ * depends on whom.
9
+ *
10
+ * Metrics (Martin's instability metric):
11
+ * efferentCoupling (Ce) — files this file imports
12
+ * afferentCoupling (Ca) — files that import this file
13
+ * instability = Ce / (Ce + Ca)
14
+ * 0 = maximally stable (nothing this file depends on can break it)
15
+ * 1 = maximally unstable (leaf node — safe to change without ripple effects)
16
+ */
17
+ import { z } from 'zod';
18
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
19
+ export declare const name = "get_coupling_map";
20
+ export declare const description: string;
21
+ export declare const inputSchema: {
22
+ repoId: z.ZodString;
23
+ filePath: z.ZodOptional<z.ZodString>;
24
+ topN: z.ZodOptional<z.ZodNumber>;
25
+ minScore: z.ZodOptional<z.ZodNumber>;
26
+ direction: z.ZodOptional<z.ZodEnum<{
27
+ both: "both";
28
+ efferent: "efferent";
29
+ afferent: "afferent";
30
+ }>>;
31
+ };
32
+ export declare function handler(args: {
33
+ repoId: string;
34
+ filePath?: string;
35
+ topN?: number;
36
+ minScore?: number;
37
+ direction?: 'efferent' | 'afferent' | 'both';
38
+ }): Promise<CallToolResult>;
39
+ //# sourceMappingURL=get-coupling-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-coupling-map.d.ts","sourceRoot":"","sources":["../../../src/server/tools/get-coupling-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,eAAO,MAAM,IAAI,qBAAqB,CAAC;AAEvC,eAAO,MAAM,WAAW,QAOoE,CAAC;AAE7F,eAAO,MAAM,WAAW;;;;;;;;;;CAgCvB,CAAC;AAsBF,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,UAAU,GAAG,UAAU,GAAG,MAAM,CAAC;CAC9C,GAAG,OAAO,CAAC,cAAc,CAAC,CA4D1B"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * get-coupling-map.ts
3
+ *
4
+ * MCP tool: get_coupling_map
5
+ *
6
+ * Return per-file coupling scores with the named files each file depends on,
7
+ * going beyond the aggregate score in get_quality_metrics to show exactly who
8
+ * depends on whom.
9
+ *
10
+ * Metrics (Martin's instability metric):
11
+ * efferentCoupling (Ce) — files this file imports
12
+ * afferentCoupling (Ca) — files that import this file
13
+ * instability = Ce / (Ce + Ca)
14
+ * 0 = maximally stable (nothing this file depends on can break it)
15
+ * 1 = maximally unstable (leaf node — safe to change without ripple effects)
16
+ */
17
+ import { z } from 'zod';
18
+ import { openDatabase, getRepo } from '../../core/db/schema.js';
19
+ import { getCouplingMap } from '../../core/db/dep-store.js';
20
+ import { buildMeta } from './_meta.js';
21
+ export const name = 'get_coupling_map';
22
+ export const description = 'Return per-file coupling scores showing exactly which files each file depends on and ' +
23
+ 'which files depend on it. Goes beyond get_quality_metrics to expose the full dependency ' +
24
+ 'lists, not just aggregate counts. Uses Martin\'s instability metric: ' +
25
+ 'instability = efferentCoupling / (efferentCoupling + afferentCoupling). ' +
26
+ 'A score near 0 means the file is a stable hub (risky to change). ' +
27
+ 'A score near 1 means it is a leaf (safe to change). ' +
28
+ 'Use topN to surface the most coupled files in the repo, or filePath to inspect one file.';
29
+ export const inputSchema = {
30
+ repoId: z.string().describe('Repo ID from index_folder or resolve_repo'),
31
+ filePath: z
32
+ .string()
33
+ .optional()
34
+ .describe('Scope to a single file (relative to repo root). ' +
35
+ 'If omitted, returns the top-N most coupled files across the whole repo.'),
36
+ topN: z
37
+ .number()
38
+ .int()
39
+ .min(1)
40
+ .max(200)
41
+ .optional()
42
+ .describe('Maximum number of files to return when filePath is omitted (default 20)'),
43
+ minScore: z
44
+ .number()
45
+ .min(0)
46
+ .optional()
47
+ .describe('Only include files whose total coupling (efferent + afferent) is ≥ this value. ' +
48
+ 'Use to focus on highly coupled files only.'),
49
+ direction: z
50
+ .enum(['efferent', 'afferent', 'both'])
51
+ .optional()
52
+ .describe('"efferent" — show only outgoing deps (files this file imports); ' +
53
+ '"afferent" — show only incoming deps (files that import this file); ' +
54
+ '"both" (default) — show both. Restricting direction reduces response size.'),
55
+ };
56
+ // ─── Handler ──────────────────────────────────────────────────────────────────
57
+ export async function handler(args) {
58
+ const t0 = Date.now();
59
+ const { repoId, filePath, topN = 20, minScore, direction = 'both' } = args;
60
+ const db = openDatabase(repoId);
61
+ try {
62
+ const repo = getRepo(db, repoId);
63
+ if (!repo) {
64
+ return {
65
+ content: [
66
+ { type: 'text', text: JSON.stringify({ error: `Repo "${repoId}" not found. Run index_folder first.` }) },
67
+ ],
68
+ isError: true,
69
+ };
70
+ }
71
+ let rows = getCouplingMap(db, repoId, filePath);
72
+ // Apply minScore filter (total coupling)
73
+ if (minScore !== undefined) {
74
+ rows = rows.filter((r) => r.efferentCoupling + r.afferentCoupling >= minScore);
75
+ }
76
+ // Sort by total coupling descending, then by filePath for stable ordering
77
+ rows.sort((a, b) => b.efferentCoupling + b.afferentCoupling - (a.efferentCoupling + a.afferentCoupling) ||
78
+ a.filePath.localeCompare(b.filePath));
79
+ // Apply topN only when not scoped to a single file
80
+ if (!filePath) {
81
+ rows = rows.slice(0, topN);
82
+ }
83
+ // Strip dep lists for the omitted direction to save tokens
84
+ const files = rows.map((r) => ({
85
+ filePath: r.filePath,
86
+ efferentCoupling: r.efferentCoupling,
87
+ afferentCoupling: r.afferentCoupling,
88
+ instability: r.instability,
89
+ efferentDeps: direction !== 'afferent' ? r.efferentDeps : [],
90
+ afferentDeps: direction !== 'efferent' ? r.afferentDeps : [],
91
+ }));
92
+ const responseText = JSON.stringify(files);
93
+ const output = {
94
+ files,
95
+ totalFiles: files.length,
96
+ _tokenEstimate: Math.ceil(responseText.length / 4),
97
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
98
+ };
99
+ return {
100
+ content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
101
+ };
102
+ }
103
+ finally {
104
+ db.close();
105
+ }
106
+ }
107
+ //# sourceMappingURL=get-coupling-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-coupling-map.js","sourceRoot":"","sources":["../../../src/server/tools/get-coupling-map.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * get-debt-report.ts
3
+ *
4
+ * MCP tool: get_debt_report
5
+ *
6
+ * Generate a comprehensive technical debt report for an indexed repo.
7
+ * Aggregates signals from four debt dimensions:
8
+ *
9
+ * complexity — cyclomatic complexity, nesting depth, function length
10
+ * structural — circular dependencies, high coupling, layer violations
11
+ * maintainability — dead code, god classes, long parameter lists
12
+ * volatility — churn hotspots (requires git metadata)
13
+ *
14
+ * Produces:
15
+ * • An overall debt score (0–100, higher = more debt) with letter grade
16
+ * • Per-category scores with top issues
17
+ * • Top N debt files ranked by combined score across all dimensions
18
+ * • Prioritized action items sorted by estimated ROI
19
+ *
20
+ * All queries are read-only against the symbol and dep_edges tables — no
21
+ * sub-tool calls. This keeps latency low and error handling simple.
22
+ */
23
+ import { z } from 'zod';
24
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
25
+ export declare const name = "get_debt_report";
26
+ export declare const description: string;
27
+ export declare const inputSchema: {
28
+ repoId: z.ZodString;
29
+ scope: z.ZodOptional<z.ZodString>;
30
+ topN: z.ZodOptional<z.ZodNumber>;
31
+ includeChurn: z.ZodOptional<z.ZodBoolean>;
32
+ format: z.ZodOptional<z.ZodEnum<{
33
+ summary: "summary";
34
+ detailed: "detailed";
35
+ }>>;
36
+ };
37
+ export declare function handler(args: {
38
+ repoId: string;
39
+ scope?: string;
40
+ topN?: number;
41
+ includeChurn?: boolean;
42
+ format?: 'summary' | 'detailed';
43
+ }): Promise<CallToolResult>;
44
+ //# sourceMappingURL=get-debt-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-debt-report.d.ts","sourceRoot":"","sources":["../../../src/server/tools/get-debt-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAKzE,eAAO,MAAM,IAAI,oBAAoB,CAAC;AAEtC,eAAO,MAAM,WAAW,QAKoD,CAAC;AAE7E,eAAO,MAAM,WAAW;;;;;;;;;CA0BvB,CAAC;AA8oBF,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;CACjC,GAAG,OAAO,CAAC,cAAc,CAAC,CAuJ1B"}