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,426 @@
1
+ /**
2
+ * health-radar.ts
3
+ *
4
+ * MCP tool: health_radar
5
+ *
6
+ * Compute a multi-axis health radar for an indexed repo. Each axis is scored
7
+ * 0–100 where 100 = perfectly healthy, 0 = critical problems.
8
+ *
9
+ * Five axes:
10
+ * complexity — inverse of average/peak cyclomatic complexity
11
+ * coupling — inverse of high-coupling file density
12
+ * maintainability — inverse of dead-code and god-class density
13
+ * documentation — percentage of symbols with a non-trivial summary
14
+ * stability — inverse of churn-hotspot density (requires git metadata)
15
+ *
16
+ * Produces:
17
+ * • Per-axis AxisScore (score 0–100, label, rationale, available flag)
18
+ * • overallHealth (0–100, weighted average of available axes)
19
+ * • Letter grade (A–F)
20
+ * • Summary counts
21
+ *
22
+ * Distinguishes from get_debt_report:
23
+ * • Scores are *health* (100 = good), not *debt* (100 = bad)
24
+ * • Adds a Documentation axis absent from the debt report
25
+ * • Compact output suited for dashboard charting and CI health gates
26
+ * • No per-file breakdown or recommendations (use get_debt_report for those)
27
+ */
28
+ import { z } from 'zod';
29
+ import { openDatabase, getRepo } from '../../core/db/schema.js';
30
+ import { getAllDepEdges } from '../../core/db/dep-store.js';
31
+ import { findDeadExports } from '../../core/db/dep-store.js';
32
+ import { buildMeta } from './_meta.js';
33
+ // ─── Tool exports ─────────────────────────────────────────────────────────────
34
+ export const name = 'health_radar';
35
+ export const description = 'Compute a multi-axis health radar for an indexed repo. ' +
36
+ 'Scores five dimensions (complexity, coupling, maintainability, documentation, stability) ' +
37
+ 'on a 0–100 scale where 100 = perfectly healthy. ' +
38
+ 'Designed for dashboard charts, CI health gates, and quick repo orientation. ' +
39
+ 'Use get_debt_report for a detailed breakdown with per-file rankings and recommendations.';
40
+ export const inputSchema = {
41
+ repoId: z.string().describe('Repo ID from index_folder or resolve_repo'),
42
+ scope: z
43
+ .string()
44
+ .optional()
45
+ .describe('Directory prefix filter (e.g. "src/core/") — narrows analysis to that subtree'),
46
+ includeStability: z
47
+ .boolean()
48
+ .optional()
49
+ .describe('Include churn-based stability axis (requires git metadata; default true). ' +
50
+ 'Set false to skip git queries when git data is absent.'),
51
+ };
52
+ // ─── Scoring constants ────────────────────────────────────────────────────────
53
+ const CC_HIGH = 10;
54
+ const CC_CRITICAL = 20;
55
+ const NESTING_HIGH = 4;
56
+ const PARAM_HIGH = 7;
57
+ const LINE_HIGH = 100;
58
+ const COUPLING_CRITICAL = 20;
59
+ const COUPLING_HIGH = 10;
60
+ const GOD_CLASS_LINES = 500;
61
+ const GOD_CLASS_METHODS = 20;
62
+ const CHURN_HIGH = 10;
63
+ const CHURN_CRITICAL = 25;
64
+ const CHURN_WINDOW_DAYS = 90;
65
+ const DOC_MIN_LENGTH = 5; // Minimum summary length to count as documented
66
+ // ─── Label helper ─────────────────────────────────────────────────────────────
67
+ function toLabel(score) {
68
+ if (score >= 80)
69
+ return 'excellent';
70
+ if (score >= 60)
71
+ return 'good';
72
+ if (score >= 40)
73
+ return 'fair';
74
+ if (score >= 20)
75
+ return 'poor';
76
+ return 'critical';
77
+ }
78
+ // ─── Grade helper ─────────────────────────────────────────────────────────────
79
+ function healthGrade(score) {
80
+ if (score >= 80)
81
+ return 'A';
82
+ if (score >= 60)
83
+ return 'B';
84
+ if (score >= 40)
85
+ return 'C';
86
+ if (score >= 20)
87
+ return 'D';
88
+ return 'F';
89
+ }
90
+ // ─── Graph helpers ────────────────────────────────────────────────────────────
91
+ function buildImporterCounts(edges) {
92
+ const importersByTarget = new Map();
93
+ for (const edge of edges) {
94
+ if (!importersByTarget.has(edge.targetFile)) {
95
+ importersByTarget.set(edge.targetFile, new Set());
96
+ }
97
+ importersByTarget.get(edge.targetFile).add(edge.sourceFile);
98
+ }
99
+ const result = new Map();
100
+ for (const [target, importers] of importersByTarget) {
101
+ result.set(target, importers.size);
102
+ }
103
+ return result;
104
+ }
105
+ function computeComplexityAxis(db, repoId, scope) {
106
+ const scopeClause = scope ? `AND file_path LIKE ? || '%'` : '';
107
+ const params = [repoId];
108
+ if (scope)
109
+ params.push(scope);
110
+ const rows = db
111
+ .prepare(`SELECT cyclomatic_complexity, nesting_depth, param_count, line_count
112
+ FROM symbols
113
+ WHERE repo_id = ?
114
+ ${scopeClause}
115
+ AND kind IN ('function','method','hook','composable','middleware','route')
116
+ AND (cyclomatic_complexity IS NOT NULL OR nesting_depth IS NOT NULL OR param_count IS NOT NULL)`)
117
+ .all(...params);
118
+ if (rows.length === 0) {
119
+ return {
120
+ score: 100,
121
+ label: 'excellent',
122
+ rationale: 'No callable symbols with complexity metrics found',
123
+ available: false,
124
+ };
125
+ }
126
+ let totalDebt = 0;
127
+ let complexCount = 0;
128
+ let criticalCount = 0;
129
+ for (const row of rows) {
130
+ const cc = row.cyclomatic_complexity ?? 0;
131
+ const nd = row.nesting_depth ?? 0;
132
+ const pc = row.param_count ?? 0;
133
+ const lc = row.line_count ?? 0;
134
+ const ccScore = Math.min(cc / CC_CRITICAL, 1) * 100;
135
+ const ndScore = Math.min(nd / NESTING_HIGH, 1) * 100;
136
+ const pcScore = Math.min(pc / PARAM_HIGH, 1) * 100;
137
+ const lcScore = Math.min(lc / LINE_HIGH, 1) * 100;
138
+ const symbolDebt = ccScore * 0.5 + ndScore * 0.25 + pcScore * 0.15 + lcScore * 0.1;
139
+ totalDebt += symbolDebt;
140
+ if (cc >= CC_HIGH)
141
+ complexCount++;
142
+ if (cc >= CC_CRITICAL)
143
+ criticalCount++;
144
+ }
145
+ const avgDebt = totalDebt / rows.length;
146
+ // Health = inverse of avg debt, penalised more for critical symbols
147
+ const criticalPenalty = Math.min(criticalCount * 10, 30);
148
+ const rawHealth = Math.max(0, 100 - avgDebt - criticalPenalty);
149
+ const score = Math.round(rawHealth);
150
+ const pct = Math.round((complexCount / rows.length) * 100);
151
+ const rationale = complexCount === 0
152
+ ? `All ${rows.length} callable symbols are within complexity budget`
153
+ : `${complexCount}/${rows.length} callable symbols exceed CC≥${CC_HIGH} (${pct}%)`;
154
+ return { score, label: toLabel(score), rationale, available: true };
155
+ }
156
+ function computeCouplingAxis(db, repoId, scope) {
157
+ const edges = getAllDepEdges(db, repoId);
158
+ const scopedEdges = scope
159
+ ? edges.filter((e) => e.sourceFile.startsWith(scope) || e.targetFile.startsWith(scope))
160
+ : edges;
161
+ if (scopedEdges.length === 0) {
162
+ return {
163
+ score: 100,
164
+ label: 'excellent',
165
+ rationale: 'No dependency edges — repo has no imports',
166
+ available: false,
167
+ };
168
+ }
169
+ const importerCounts = buildImporterCounts(scopedEdges);
170
+ const highCouplingFiles = Array.from(importerCounts.values()).filter((n) => n > COUPLING_HIGH);
171
+ const criticalCouplingFiles = highCouplingFiles.filter((n) => n >= COUPLING_CRITICAL);
172
+ const totalFiles = importerCounts.size || 1;
173
+ const highRatio = highCouplingFiles.length / totalFiles;
174
+ const critPenalty = criticalCouplingFiles.length * 15;
175
+ const rawHealth = Math.max(0, 100 - highRatio * 60 - critPenalty);
176
+ const score = Math.round(rawHealth);
177
+ const maxImporters = Math.max(0, ...importerCounts.values());
178
+ const rationale = highCouplingFiles.length === 0
179
+ ? `No files exceed the coupling threshold (max ${maxImporters} importers)`
180
+ : `${highCouplingFiles.length} file(s) have >${COUPLING_HIGH} importers (max: ${maxImporters})`;
181
+ return { score, label: toLabel(score), rationale, available: true };
182
+ }
183
+ function computeMaintainabilityAxis(db, repoId, scope) {
184
+ // Dead exports
185
+ const deadSymbols = findDeadExports(db, repoId);
186
+ const deadCount = scope
187
+ ? deadSymbols.filter((s) => s.filePath.startsWith(scope)).length
188
+ : deadSymbols.length;
189
+ // God classes (by line count)
190
+ const scopeClause = scope ? `AND file_path LIKE ? || '%'` : '';
191
+ const params = [repoId, GOD_CLASS_LINES];
192
+ if (scope)
193
+ params.push(scope);
194
+ const godClassCount = (db
195
+ .prepare(`SELECT COUNT(*) AS cnt FROM symbols
196
+ WHERE repo_id = ? AND kind = 'class' AND line_count > ?
197
+ ${scopeClause}`)
198
+ .get(...params) ?? { cnt: 0 }).cnt;
199
+ // Files with too many methods
200
+ const methodParams = [repoId, GOD_CLASS_METHODS];
201
+ if (scope)
202
+ methodParams.push(scope);
203
+ const methodScopeClause = scope ? `AND file_path LIKE ? || '%'` : '';
204
+ const godMethodFileCount = (db
205
+ .prepare(`SELECT COUNT(*) AS cnt FROM (
206
+ SELECT file_path FROM symbols
207
+ WHERE repo_id = ? AND kind = 'method' ${methodScopeClause}
208
+ GROUP BY file_path
209
+ HAVING COUNT(*) > ?
210
+ )`)
211
+ .get(...methodParams) ?? { cnt: 0 }).cnt;
212
+ // Get total symbol count for context
213
+ const symParams = [repoId];
214
+ if (scope)
215
+ symParams.push(scope);
216
+ const symScopeClause = scope ? `AND file_path LIKE ? || '%'` : '';
217
+ const totalSymbols = (db
218
+ .prepare(`SELECT COUNT(*) AS cnt FROM symbols WHERE repo_id = ? ${symScopeClause}`)
219
+ .get(...symParams) ?? { cnt: 0 }).cnt;
220
+ if (totalSymbols === 0) {
221
+ return {
222
+ score: 100,
223
+ label: 'excellent',
224
+ rationale: 'No symbols found',
225
+ available: false,
226
+ };
227
+ }
228
+ const deadPenalty = Math.min(deadCount * 3, 40);
229
+ const godPenalty = Math.min((godClassCount + godMethodFileCount) * 15, 40);
230
+ const rawHealth = Math.max(0, 100 - deadPenalty - godPenalty);
231
+ const score = Math.round(rawHealth);
232
+ const issues = [];
233
+ if (deadCount > 0)
234
+ issues.push(`${deadCount} dead export(s)`);
235
+ if (godClassCount > 0)
236
+ issues.push(`${godClassCount} god class(es)`);
237
+ if (godMethodFileCount > 0)
238
+ issues.push(`${godMethodFileCount} file(s) with >${GOD_CLASS_METHODS} methods`);
239
+ const rationale = issues.length === 0
240
+ ? 'No dead code or oversized classes detected'
241
+ : issues.join(', ');
242
+ return { score, label: toLabel(score), rationale, available: true };
243
+ }
244
+ function computeDocumentationAxis(db, repoId, scope) {
245
+ const scopeClause = scope ? `AND file_path LIKE ? || '%'` : '';
246
+ const params = [repoId];
247
+ if (scope)
248
+ params.push(scope);
249
+ const totals = db
250
+ .prepare(`SELECT
251
+ COUNT(*) AS total,
252
+ SUM(CASE WHEN LENGTH(summary) > ${DOC_MIN_LENGTH} THEN 1 ELSE 0 END) AS documented
253
+ FROM symbols
254
+ WHERE repo_id = ?
255
+ ${scopeClause}
256
+ AND kind NOT IN ('type','const','enum')`)
257
+ .get(...params) ?? { total: 0, documented: 0 };
258
+ if (totals.total === 0) {
259
+ return {
260
+ score: 100,
261
+ label: 'excellent',
262
+ rationale: 'No documentable symbols found',
263
+ available: false,
264
+ };
265
+ }
266
+ const pct = Math.round((totals.documented / totals.total) * 100);
267
+ const score = pct; // 0–100 directly maps to coverage percentage
268
+ const rationale = `${totals.documented}/${totals.total} documentable symbols have summaries (${pct}%)`;
269
+ return { score, label: toLabel(score), rationale, available: true };
270
+ }
271
+ function computeStabilityAxis(db, repoId, scope) {
272
+ const hasGit = db
273
+ .prepare(`SELECT COUNT(*) AS cnt FROM git_metadata WHERE repo_id = ? LIMIT 1`)
274
+ .get(repoId);
275
+ if (!hasGit || hasGit.cnt === 0) {
276
+ return {
277
+ score: 100,
278
+ label: 'excellent',
279
+ rationale: 'No git metadata available — stability cannot be measured',
280
+ available: false,
281
+ };
282
+ }
283
+ const churnSinceMs = Date.now() - CHURN_WINDOW_DAYS * 24 * 60 * 60 * 1000;
284
+ const scopeClause = scope ? `AND file_path LIKE ? || '%'` : '';
285
+ const params = [repoId, Math.floor(churnSinceMs / 1000)];
286
+ if (scope)
287
+ params.push(scope);
288
+ const churnRows = db
289
+ .prepare(`SELECT COUNT(DISTINCT commit_sha) AS commit_count
290
+ FROM git_metadata
291
+ WHERE repo_id = ? AND commit_date >= ?
292
+ ${scopeClause}
293
+ GROUP BY file_path
294
+ HAVING COUNT(DISTINCT commit_sha) > 0`)
295
+ .all(...params);
296
+ if (churnRows.length === 0) {
297
+ return {
298
+ score: 100,
299
+ label: 'excellent',
300
+ rationale: `No file changes in the last ${CHURN_WINDOW_DAYS} days`,
301
+ available: true,
302
+ };
303
+ }
304
+ const hotspots = churnRows.filter((r) => r.commit_count >= CHURN_HIGH).length;
305
+ const critical = churnRows.filter((r) => r.commit_count >= CHURN_CRITICAL).length;
306
+ const total = churnRows.length;
307
+ const hotspotRatio = hotspots / total;
308
+ const critPenalty = critical * 10;
309
+ const rawHealth = Math.max(0, 100 - hotspotRatio * 60 - critPenalty);
310
+ const score = Math.round(rawHealth);
311
+ const rationale = hotspots === 0
312
+ ? `All ${total} changed files are within churn budget (${CHURN_WINDOW_DAYS}-day window)`
313
+ : `${hotspots}/${total} files are churn hotspots (>${CHURN_HIGH} commits in ${CHURN_WINDOW_DAYS} days)`;
314
+ return { score, label: toLabel(score), rationale, available: true };
315
+ }
316
+ // ─── Handler ──────────────────────────────────────────────────────────────────
317
+ export async function handler(args) {
318
+ const t0 = Date.now();
319
+ const { repoId, scope, includeStability = true } = args;
320
+ const db = openDatabase(repoId);
321
+ try {
322
+ const repo = getRepo(db, repoId);
323
+ if (!repo) {
324
+ return {
325
+ content: [{ type: 'text', text: JSON.stringify({ error: `Repo "${repoId}" not found` }) }],
326
+ isError: true,
327
+ };
328
+ }
329
+ // ── File / symbol counts ────────────────────────────────────────────────
330
+ const scopeClause = scope ? `AND path LIKE ? || '%'` : '';
331
+ const fileParams = [repoId];
332
+ if (scope)
333
+ fileParams.push(scope);
334
+ const totalFiles = (db
335
+ .prepare(`SELECT COUNT(*) AS cnt FROM files WHERE repo_id = ? ${scopeClause}`)
336
+ .get(...fileParams) ?? { cnt: 0 }).cnt;
337
+ const symScopeClause = scope ? `AND file_path LIKE ? || '%'` : '';
338
+ const symParams = [repoId];
339
+ if (scope)
340
+ symParams.push(scope);
341
+ const totalSymbols = (db
342
+ .prepare(`SELECT COUNT(*) AS cnt FROM symbols WHERE repo_id = ? ${symScopeClause}`)
343
+ .get(...symParams) ?? { cnt: 0 }).cnt;
344
+ // Count documented symbols
345
+ const symDocParams = [repoId];
346
+ if (scope)
347
+ symDocParams.push(scope);
348
+ const documentedSymbols = (db
349
+ .prepare(`SELECT COUNT(*) AS cnt FROM symbols
350
+ WHERE repo_id = ? ${symScopeClause}
351
+ AND LENGTH(summary) > ${DOC_MIN_LENGTH}`)
352
+ .get(...symDocParams) ?? { cnt: 0 }).cnt;
353
+ // ── Compute axes ────────────────────────────────────────────────────────
354
+ const complexityAxis = computeComplexityAxis(db, repoId, scope);
355
+ const couplingAxis = computeCouplingAxis(db, repoId, scope);
356
+ const maintainabilityAxis = computeMaintainabilityAxis(db, repoId, scope);
357
+ const documentationAxis = computeDocumentationAxis(db, repoId, scope);
358
+ const stabilityAxis = includeStability
359
+ ? computeStabilityAxis(db, repoId, scope)
360
+ : {
361
+ score: 100,
362
+ label: 'excellent',
363
+ rationale: 'Stability analysis disabled by caller',
364
+ available: false,
365
+ };
366
+ // ── Overall health ──────────────────────────────────────────────────────
367
+ // Use available axes only; documentation is lower weight (proxy metric)
368
+ const availableAxes = [
369
+ { axis: complexityAxis, weight: 0.30 },
370
+ { axis: couplingAxis, weight: 0.25 },
371
+ { axis: maintainabilityAxis, weight: 0.25 },
372
+ { axis: documentationAxis, weight: 0.10 },
373
+ { axis: stabilityAxis, weight: 0.10 },
374
+ ].filter((a) => a.axis.available);
375
+ let overallHealth;
376
+ if (availableAxes.length === 0) {
377
+ overallHealth = 100; // No data → assume healthy
378
+ }
379
+ else {
380
+ // Renormalize weights to sum to 1 for the available subset
381
+ const totalWeight = availableAxes.reduce((s, a) => s + a.weight, 0);
382
+ overallHealth = Math.round(availableAxes.reduce((s, a) => s + (a.axis.score * a.weight) / totalWeight, 0));
383
+ }
384
+ const axesWithData = [
385
+ complexityAxis,
386
+ couplingAxis,
387
+ maintainabilityAxis,
388
+ documentationAxis,
389
+ stabilityAxis,
390
+ ].filter((a) => a.available).length;
391
+ const gitDataAvailable = stabilityAxis.available &&
392
+ !stabilityAxis.rationale.includes('No git metadata');
393
+ const output = {
394
+ repoId,
395
+ generatedAt: new Date().toISOString(),
396
+ scope,
397
+ axes: {
398
+ complexity: complexityAxis,
399
+ coupling: couplingAxis,
400
+ maintainability: maintainabilityAxis,
401
+ documentation: documentationAxis,
402
+ stability: stabilityAxis,
403
+ },
404
+ overallHealth,
405
+ grade: healthGrade(overallHealth),
406
+ summary: {
407
+ totalFiles,
408
+ totalSymbols,
409
+ documentedSymbols,
410
+ axesWithData,
411
+ gitDataAvailable,
412
+ },
413
+ _tokenEstimate: 0,
414
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
415
+ };
416
+ const text = JSON.stringify(output, null, 2);
417
+ output._tokenEstimate = Math.ceil(text.length / 4);
418
+ return {
419
+ content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
420
+ };
421
+ }
422
+ finally {
423
+ db.close();
424
+ }
425
+ }
426
+ //# sourceMappingURL=health-radar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health-radar.js","sourceRoot":"","sources":["../../../src/server/tools/health-radar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * plan-refactoring.ts
3
+ *
4
+ * MCP tool: plan_refactoring
5
+ *
6
+ * Synthesize the outputs of check_rename_safe, check_delete_safe,
7
+ * check_move_safe, find_cycles, get_coupling_map, detect_antipatterns, and
8
+ * get_quality_metrics into a sequenced, risk-annotated refactoring plan.
9
+ *
10
+ * This tool is read-only — it produces a plan but writes nothing.
11
+ * Execution of the plan is left to the calling agent.
12
+ *
13
+ * Supported goals:
14
+ * 'rename-symbol' — rename a symbol everywhere (requires symbolId + newName)
15
+ * 'delete-symbol' — safely remove a symbol and its references (requires symbolId)
16
+ * 'break-cycle' — resolve a circular import dependency (requires filePath or symbolId)
17
+ * 'extract-module' — move a file to a new location (requires filePath + newFilePath)
18
+ * 'reduce-coupling' — split a highly-coupled file (requires filePath or symbolId)
19
+ * 'general' — open-ended analysis, surfaces top findings (requires filePath or symbolId)
20
+ *
21
+ * Step ordering:
22
+ * Always edit leaf files before hub files (bottom-up). For rename: update all call/import
23
+ * sites first, then rename the declaration last. For delete: remove all references first,
24
+ * then delete the declaration last.
25
+ */
26
+ import { z } from 'zod';
27
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
28
+ declare const refactoringGoalEnum: z.ZodEnum<{
29
+ "extract-module": "extract-module";
30
+ "rename-symbol": "rename-symbol";
31
+ "delete-symbol": "delete-symbol";
32
+ "break-cycle": "break-cycle";
33
+ "reduce-coupling": "reduce-coupling";
34
+ general: "general";
35
+ }>;
36
+ type RefactoringGoal = z.infer<typeof refactoringGoalEnum>;
37
+ export declare const name = "plan_refactoring";
38
+ export declare const description: string;
39
+ export declare const inputSchema: {
40
+ repoId: z.ZodString;
41
+ symbolId: z.ZodOptional<z.ZodString>;
42
+ filePath: z.ZodOptional<z.ZodString>;
43
+ goal: z.ZodEnum<{
44
+ "extract-module": "extract-module";
45
+ "rename-symbol": "rename-symbol";
46
+ "delete-symbol": "delete-symbol";
47
+ "break-cycle": "break-cycle";
48
+ "reduce-coupling": "reduce-coupling";
49
+ general: "general";
50
+ }>;
51
+ newName: z.ZodOptional<z.ZodString>;
52
+ newFilePath: z.ZodOptional<z.ZodString>;
53
+ contextHint: z.ZodOptional<z.ZodString>;
54
+ };
55
+ export interface RefactoringStep {
56
+ order: number;
57
+ action: string;
58
+ filePath: string;
59
+ line?: number;
60
+ detail: string;
61
+ automated: boolean;
62
+ risk: 'low' | 'medium' | 'high';
63
+ }
64
+ export declare function handler(args: {
65
+ repoId: string;
66
+ symbolId?: string;
67
+ filePath?: string;
68
+ goal: RefactoringGoal;
69
+ newName?: string;
70
+ newFilePath?: string;
71
+ contextHint?: string;
72
+ }): Promise<CallToolResult>;
73
+ export {};
74
+ //# sourceMappingURL=plan-refactoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan-refactoring.d.ts","sourceRoot":"","sources":["../../../src/server/tools/plan-refactoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAazE,QAAA,MAAM,mBAAmB;;;;;;;EAOvB,CAAC;AAEH,KAAK,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAE3D,eAAO,MAAM,IAAI,qBAAqB,CAAC;AAEvC,eAAO,MAAM,WAAW,QAOmD,CAAC;AAE5E,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;CAmCvB,CAAC;AAIF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,IAAI,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CACjC;AA4pBD,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,eAAe,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GAAG,OAAO,CAAC,cAAc,CAAC,CAmJ1B"}