purecontext-mcp 1.1.8 → 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 (167) 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/types.d.ts +5 -0
  23. package/dist/core/types.d.ts.map +1 -1
  24. package/dist/graph/diagram-renderer.d.ts +83 -0
  25. package/dist/graph/diagram-renderer.d.ts.map +1 -0
  26. package/dist/graph/diagram-renderer.js +294 -0
  27. package/dist/graph/diagram-renderer.js.map +1 -0
  28. package/dist/graph/graph-traversal.d.ts +92 -0
  29. package/dist/graph/graph-traversal.d.ts.map +1 -1
  30. package/dist/graph/graph-traversal.js +440 -2
  31. package/dist/graph/graph-traversal.js.map +1 -1
  32. package/dist/server/mcp-server.d.ts.map +1 -1
  33. package/dist/server/mcp-server.js +145 -0
  34. package/dist/server/mcp-server.js.map +1 -1
  35. package/dist/server/tools/check-delete-safe.d.ts +50 -0
  36. package/dist/server/tools/check-delete-safe.d.ts.map +1 -0
  37. package/dist/server/tools/check-delete-safe.js +308 -0
  38. package/dist/server/tools/check-delete-safe.js.map +1 -0
  39. package/dist/server/tools/check-move-safe.d.ts +44 -0
  40. package/dist/server/tools/check-move-safe.d.ts.map +1 -0
  41. package/dist/server/tools/check-move-safe.js +266 -0
  42. package/dist/server/tools/check-move-safe.js.map +1 -0
  43. package/dist/server/tools/check-rename-safe.d.ts +48 -0
  44. package/dist/server/tools/check-rename-safe.d.ts.map +1 -0
  45. package/dist/server/tools/check-rename-safe.js +218 -0
  46. package/dist/server/tools/check-rename-safe.js.map +1 -0
  47. package/dist/server/tools/diff-health-radar.d.ts +44 -0
  48. package/dist/server/tools/diff-health-radar.d.ts.map +1 -0
  49. package/dist/server/tools/diff-health-radar.js +192 -0
  50. package/dist/server/tools/diff-health-radar.js.map +1 -0
  51. package/dist/server/tools/find-cycles.d.ts +31 -0
  52. package/dist/server/tools/find-cycles.d.ts.map +1 -0
  53. package/dist/server/tools/find-cycles.js +85 -0
  54. package/dist/server/tools/find-cycles.js.map +1 -0
  55. package/dist/server/tools/find-implementations.d.ts +47 -0
  56. package/dist/server/tools/find-implementations.d.ts.map +1 -0
  57. package/dist/server/tools/find-implementations.js +167 -0
  58. package/dist/server/tools/find-implementations.js.map +1 -0
  59. package/dist/server/tools/find-untested-symbols.d.ts +52 -0
  60. package/dist/server/tools/find-untested-symbols.d.ts.map +1 -0
  61. package/dist/server/tools/find-untested-symbols.js +308 -0
  62. package/dist/server/tools/find-untested-symbols.js.map +1 -0
  63. package/dist/server/tools/get-architecture-snapshot.d.ts +43 -0
  64. package/dist/server/tools/get-architecture-snapshot.d.ts.map +1 -0
  65. package/dist/server/tools/get-architecture-snapshot.js +292 -0
  66. package/dist/server/tools/get-architecture-snapshot.js.map +1 -0
  67. package/dist/server/tools/get-call-hierarchy.d.ts +43 -0
  68. package/dist/server/tools/get-call-hierarchy.d.ts.map +1 -0
  69. package/dist/server/tools/get-call-hierarchy.js +119 -0
  70. package/dist/server/tools/get-call-hierarchy.js.map +1 -0
  71. package/dist/server/tools/get-class-hierarchy.d.ts +36 -0
  72. package/dist/server/tools/get-class-hierarchy.d.ts.map +1 -0
  73. package/dist/server/tools/get-class-hierarchy.js +125 -0
  74. package/dist/server/tools/get-class-hierarchy.js.map +1 -0
  75. package/dist/server/tools/get-complexity-hotspots.d.ts +50 -0
  76. package/dist/server/tools/get-complexity-hotspots.d.ts.map +1 -0
  77. package/dist/server/tools/get-complexity-hotspots.js +282 -0
  78. package/dist/server/tools/get-complexity-hotspots.js.map +1 -0
  79. package/dist/server/tools/get-coupling-map.d.ts +39 -0
  80. package/dist/server/tools/get-coupling-map.d.ts.map +1 -0
  81. package/dist/server/tools/get-coupling-map.js +107 -0
  82. package/dist/server/tools/get-coupling-map.js.map +1 -0
  83. package/dist/server/tools/get-debt-report.d.ts +44 -0
  84. package/dist/server/tools/get-debt-report.d.ts.map +1 -0
  85. package/dist/server/tools/get-debt-report.js +606 -0
  86. package/dist/server/tools/get-debt-report.js.map +1 -0
  87. package/dist/server/tools/get-entry-points.d.ts +79 -0
  88. package/dist/server/tools/get-entry-points.d.ts.map +1 -0
  89. package/dist/server/tools/get-entry-points.js +362 -0
  90. package/dist/server/tools/get-entry-points.js.map +1 -0
  91. package/dist/server/tools/get-public-api.d.ts +53 -0
  92. package/dist/server/tools/get-public-api.d.ts.map +1 -0
  93. package/dist/server/tools/get-public-api.js +218 -0
  94. package/dist/server/tools/get-public-api.js.map +1 -0
  95. package/dist/server/tools/get-test-coverage-map.d.ts +66 -0
  96. package/dist/server/tools/get-test-coverage-map.d.ts.map +1 -0
  97. package/dist/server/tools/get-test-coverage-map.js +588 -0
  98. package/dist/server/tools/get-test-coverage-map.js.map +1 -0
  99. package/dist/server/tools/get-todos.d.ts +51 -0
  100. package/dist/server/tools/get-todos.d.ts.map +1 -0
  101. package/dist/server/tools/get-todos.js +180 -0
  102. package/dist/server/tools/get-todos.js.map +1 -0
  103. package/dist/server/tools/get-type-graph.d.ts +73 -0
  104. package/dist/server/tools/get-type-graph.d.ts.map +1 -0
  105. package/dist/server/tools/get-type-graph.js +437 -0
  106. package/dist/server/tools/get-type-graph.js.map +1 -0
  107. package/dist/server/tools/health-radar.d.ts +50 -0
  108. package/dist/server/tools/health-radar.d.ts.map +1 -0
  109. package/dist/server/tools/health-radar.js +426 -0
  110. package/dist/server/tools/health-radar.js.map +1 -0
  111. package/dist/server/tools/plan-refactoring.d.ts +74 -0
  112. package/dist/server/tools/plan-refactoring.d.ts.map +1 -0
  113. package/dist/server/tools/plan-refactoring.js +644 -0
  114. package/dist/server/tools/plan-refactoring.js.map +1 -0
  115. package/dist/server/tools/render-call-graph.d.ts +40 -0
  116. package/dist/server/tools/render-call-graph.d.ts.map +1 -0
  117. package/dist/server/tools/render-call-graph.js +215 -0
  118. package/dist/server/tools/render-call-graph.js.map +1 -0
  119. package/dist/server/tools/render-class-hierarchy.d.ts +42 -0
  120. package/dist/server/tools/render-class-hierarchy.d.ts.map +1 -0
  121. package/dist/server/tools/render-class-hierarchy.js +265 -0
  122. package/dist/server/tools/render-class-hierarchy.js.map +1 -0
  123. package/dist/server/tools/render-dep-matrix.d.ts +38 -0
  124. package/dist/server/tools/render-dep-matrix.d.ts.map +1 -0
  125. package/dist/server/tools/render-dep-matrix.js +186 -0
  126. package/dist/server/tools/render-dep-matrix.js.map +1 -0
  127. package/dist/server/tools/render-diagram.d.ts +47 -0
  128. package/dist/server/tools/render-diagram.d.ts.map +1 -0
  129. package/dist/server/tools/render-diagram.js +266 -0
  130. package/dist/server/tools/render-diagram.js.map +1 -0
  131. package/dist/server/tools/render-import-graph.d.ts +41 -0
  132. package/dist/server/tools/render-import-graph.d.ts.map +1 -0
  133. package/dist/server/tools/render-import-graph.js +158 -0
  134. package/dist/server/tools/render-import-graph.js.map +1 -0
  135. package/dist/server/tools/search-ast.d.ts +55 -0
  136. package/dist/server/tools/search-ast.d.ts.map +1 -0
  137. package/dist/server/tools/search-ast.js +279 -0
  138. package/dist/server/tools/search-ast.js.map +1 -0
  139. package/dist/server/tools/search-by-complexity.d.ts +92 -0
  140. package/dist/server/tools/search-by-complexity.d.ts.map +1 -0
  141. package/dist/server/tools/search-by-complexity.js +268 -0
  142. package/dist/server/tools/search-by-complexity.js.map +1 -0
  143. package/dist/server/tools/search-by-decorator.d.ts +48 -0
  144. package/dist/server/tools/search-by-decorator.d.ts.map +1 -0
  145. package/dist/server/tools/search-by-decorator.js +518 -0
  146. package/dist/server/tools/search-by-decorator.js.map +1 -0
  147. package/dist/server/tools/search-by-signature.d.ts +56 -0
  148. package/dist/server/tools/search-by-signature.d.ts.map +1 -0
  149. package/dist/server/tools/search-by-signature.js +200 -0
  150. package/dist/server/tools/search-by-signature.js.map +1 -0
  151. package/dist/ui/assets/BlastRadius-QdgESOL8.js +1 -0
  152. package/dist/ui/assets/{DependencyGraph-B60SMPbX.js → DependencyGraph-BSMhzwWV.js} +1 -1
  153. package/dist/ui/assets/{NotFound-Bsg8Wppk.js → NotFound-CipFP_s1.js} +1 -1
  154. package/dist/ui/assets/{RepoDetail-Cie0D4_s.js → RepoDetail-Dfp5z5Kq.js} +1 -1
  155. package/dist/ui/assets/{RepoList-CldNt89M.js → RepoList-BKtST3hB.js} +1 -1
  156. package/dist/ui/assets/{Search-CgvpHMOi.js → Search-DzhGDViy.js} +1 -1
  157. package/dist/ui/assets/{SymbolView-B9h0LZTz.js → SymbolView-ryVEwAHG.js} +1 -1
  158. package/dist/ui/assets/{index-DADf5y_L.css → index-Ny8gn9F0.css} +1 -1
  159. package/dist/ui/assets/{index-eK0wMkUR.js → index-nX2chMqi.js} +2 -2
  160. package/dist/ui/assets/{useSearch-KAl3Qyi2.js → useSearch-BnBCRKui.js} +1 -1
  161. package/dist/ui/index.html +2 -2
  162. package/dist/version.d.ts +1 -1
  163. package/dist/version.js +1 -1
  164. package/docs/dev/jcodemunch-gap-analysis.md +198 -0
  165. package/package.json +9 -1
  166. package/user-manual.md +2466 -0
  167. package/dist/ui/assets/BlastRadius-RP7vJEyQ.js +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-health-radar.d.ts","sourceRoot":"","sources":["../../../src/server/tools/diff-health-radar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAIzE,eAAO,MAAM,IAAI,sBAAsB,CAAC;AAExC,eAAO,MAAM,WAAW,QAMwB,CAAC;AAEjD,eAAO,MAAM,WAAW;;;;;CAqBvB,CAAC;AAkGF,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,GAAG,OAAO,CAAC,cAAc,CAAC,CAuH1B"}
@@ -0,0 +1,192 @@
1
+ /**
2
+ * diff-health-radar.ts
3
+ *
4
+ * MCP tool: diff_health_radar
5
+ *
6
+ * Compare health radar scores between two indexed repos (or two states of the
7
+ * same codebase). Primary use cases:
8
+ *
9
+ * • PR review: index main branch → index feature branch → compare
10
+ * • Refactoring validation: index before → refactor → re-index → compare
11
+ * • Cross-repo benchmark: compare health of two different projects
12
+ *
13
+ * Runs health_radar on both repos, then computes per-axis deltas (head − base).
14
+ * Positive delta = improvement; negative delta = regression.
15
+ *
16
+ * Output:
17
+ * • base snapshot — health scores from baseRepoId
18
+ * • head snapshot — health scores from headRepoId
19
+ * • axes delta map — score change per axis with trend label
20
+ * • overallDelta — change in overall health (head − base)
21
+ * • trend — 'improved' | 'degraded' | 'stable' (based on overallDelta)
22
+ * • regressions — axis names that degraded by > SIGNIFICANT_DELTA
23
+ * • improvements — axis names that improved by > SIGNIFICANT_DELTA
24
+ *
25
+ * A delta of +5 or more is treated as a meaningful improvement.
26
+ * A delta of −5 or more (negative) is treated as a meaningful regression.
27
+ */
28
+ import { z } from 'zod';
29
+ import { handler as healthRadarHandler } from './health-radar.js';
30
+ import { buildMeta } from './_meta.js';
31
+ // ─── Tool exports ─────────────────────────────────────────────────────────────
32
+ export const name = 'diff_health_radar';
33
+ export const description = 'Compare health radar scores between two indexed repos (or two states of the same codebase). ' +
34
+ 'Runs health_radar on baseRepoId and headRepoId, then computes per-axis deltas. ' +
35
+ 'Positive delta = improvement; negative delta = regression. ' +
36
+ 'Primary use cases: PR review (index main vs feature branch), refactoring validation ' +
37
+ '(index before/after), and cross-repo health benchmarking. ' +
38
+ 'Use health_radar for a single-repo snapshot.';
39
+ export const inputSchema = {
40
+ baseRepoId: z
41
+ .string()
42
+ .describe('Baseline repo ID (e.g. main branch). From index_folder or resolve_repo.'),
43
+ headRepoId: z
44
+ .string()
45
+ .describe('Head repo ID to compare against the baseline (e.g. feature branch).'),
46
+ scope: z
47
+ .string()
48
+ .optional()
49
+ .describe('Directory prefix filter applied to both repos (e.g. "src/core/"). ' +
50
+ 'Narrows analysis to the same subtree in each repo.'),
51
+ includeStability: z
52
+ .boolean()
53
+ .optional()
54
+ .describe('Include churn-based stability axis in both snapshots (requires git metadata; default true). ' +
55
+ 'Set false to skip git queries when git data is absent.'),
56
+ };
57
+ // ─── Constants ────────────────────────────────────────────────────────────────
58
+ const SIGNIFICANT_DELTA = 5; // Minimum delta (absolute) to count as meaningful
59
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
60
+ function toTrend(delta) {
61
+ if (delta >= SIGNIFICANT_DELTA)
62
+ return 'improved';
63
+ if (delta <= -SIGNIFICANT_DELTA)
64
+ return 'degraded';
65
+ return 'stable';
66
+ }
67
+ function parseSnapshot(result, repoId) {
68
+ if (result.isError)
69
+ return null;
70
+ const text = result.content[0]?.text;
71
+ if (!text)
72
+ return null;
73
+ try {
74
+ return JSON.parse(text);
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ }
80
+ const AXIS_NAMES = [
81
+ 'complexity',
82
+ 'coupling',
83
+ 'maintainability',
84
+ 'documentation',
85
+ 'stability',
86
+ ];
87
+ // ─── Handler ──────────────────────────────────────────────────────────────────
88
+ export async function handler(args) {
89
+ const t0 = Date.now();
90
+ const { baseRepoId, headRepoId, scope, includeStability = true } = args;
91
+ // ── Run health_radar on both repos in parallel ────────────────────────────
92
+ const [baseResult, headResult] = await Promise.all([
93
+ healthRadarHandler({ repoId: baseRepoId, scope, includeStability }),
94
+ healthRadarHandler({ repoId: headRepoId, scope, includeStability }),
95
+ ]);
96
+ // ── Validate both succeeded ────────────────────────────────────────────────
97
+ const baseJson = parseSnapshot(baseResult, baseRepoId);
98
+ const headJson = parseSnapshot(headResult, headRepoId);
99
+ if (!baseJson) {
100
+ // Forward the base error
101
+ if (baseResult.isError)
102
+ return baseResult;
103
+ return {
104
+ content: [{ type: 'text', text: JSON.stringify({ error: `Failed to compute health radar for base repo "${baseRepoId}"` }) }],
105
+ isError: true,
106
+ };
107
+ }
108
+ if (!headJson) {
109
+ // Forward the head error
110
+ if (headResult.isError)
111
+ return headResult;
112
+ return {
113
+ content: [{ type: 'text', text: JSON.stringify({ error: `Failed to compute health radar for head repo "${headRepoId}"` }) }],
114
+ isError: true,
115
+ };
116
+ }
117
+ // ── Compute per-axis deltas ────────────────────────────────────────────────
118
+ const axes = {};
119
+ const regressions = [];
120
+ const improvements = [];
121
+ for (const axisName of AXIS_NAMES) {
122
+ const baseAxis = baseJson.axes[axisName];
123
+ const headAxis = headJson.axes[axisName];
124
+ const baseScore = baseAxis.score;
125
+ const headScore = headAxis.score;
126
+ const delta = headScore - baseScore;
127
+ const trend = toTrend(delta);
128
+ axes[axisName] = {
129
+ baseScore,
130
+ headScore,
131
+ delta,
132
+ trend,
133
+ baseAvailable: baseAxis.available,
134
+ headAvailable: headAxis.available,
135
+ };
136
+ if (trend === 'degraded')
137
+ regressions.push(axisName);
138
+ if (trend === 'improved')
139
+ improvements.push(axisName);
140
+ }
141
+ // ── Overall delta and trend ────────────────────────────────────────────────
142
+ const overallDelta = headJson.overallHealth - baseJson.overallHealth;
143
+ const trend = toTrend(overallDelta);
144
+ // ── Snapshots (subset for output) ─────────────────────────────────────────
145
+ const base = {
146
+ repoId: baseRepoId,
147
+ overallHealth: baseJson.overallHealth,
148
+ grade: baseJson.grade,
149
+ axes: baseJson.axes,
150
+ gitDataAvailable: baseJson.summary.gitDataAvailable,
151
+ };
152
+ const head = {
153
+ repoId: headRepoId,
154
+ overallHealth: headJson.overallHealth,
155
+ grade: headJson.grade,
156
+ axes: headJson.axes,
157
+ gitDataAvailable: headJson.summary.gitDataAvailable,
158
+ };
159
+ // ── Summary ────────────────────────────────────────────────────────────────
160
+ const axesCompared = AXIS_NAMES.filter((n) => axes[n].baseAvailable || axes[n].headAvailable).length;
161
+ const gradeChange = base.grade === head.grade
162
+ ? base.grade
163
+ : `${base.grade} → ${head.grade}`;
164
+ const output = {
165
+ baseRepoId,
166
+ headRepoId,
167
+ scope,
168
+ generatedAt: new Date().toISOString(),
169
+ base,
170
+ head,
171
+ axes,
172
+ overallDelta,
173
+ trend,
174
+ regressions,
175
+ improvements,
176
+ summary: {
177
+ axesCompared,
178
+ regressionCount: regressions.length,
179
+ improvementCount: improvements.length,
180
+ stableCount: AXIS_NAMES.length - regressions.length - improvements.length,
181
+ overallGradeChange: gradeChange,
182
+ },
183
+ _tokenEstimate: 0,
184
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
185
+ };
186
+ const text = JSON.stringify(output, null, 2);
187
+ output._tokenEstimate = Math.ceil(text.length / 4);
188
+ return {
189
+ content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
190
+ };
191
+ }
192
+ //# sourceMappingURL=diff-health-radar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff-health-radar.js","sourceRoot":"","sources":["../../../src/server/tools/diff-health-radar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * find-cycles.ts
3
+ *
4
+ * MCP tool: find_cycles
5
+ *
6
+ * Detect all import cycles in the dependency graph and return them as ordered
7
+ * file paths. Unlike detect_antipatterns (which reports only a count and
8
+ * severity), this tool returns the actual cycle paths so an agent can understand
9
+ * and resolve circular dependencies.
10
+ *
11
+ * Algorithm: DFS with path stack. Each cycle is reported exactly once, rooted
12
+ * at its lexicographically smallest file. Severity is 'error' for tight 2–3-node
13
+ * cycles (tightly coupled pairs/triangles) and 'warning' for longer chains.
14
+ */
15
+ import { z } from 'zod';
16
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
17
+ export declare const name = "find_cycles";
18
+ export declare const description: string;
19
+ export declare const inputSchema: {
20
+ repoId: z.ZodString;
21
+ filePath: z.ZodOptional<z.ZodString>;
22
+ maxCycles: z.ZodOptional<z.ZodNumber>;
23
+ minLength: z.ZodOptional<z.ZodNumber>;
24
+ };
25
+ export declare function handler(args: {
26
+ repoId: string;
27
+ filePath?: string;
28
+ maxCycles?: number;
29
+ minLength?: number;
30
+ }): Promise<CallToolResult>;
31
+ //# sourceMappingURL=find-cycles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-cycles.d.ts","sourceRoot":"","sources":["../../../src/server/tools/find-cycles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,eAAO,MAAM,IAAI,gBAAgB,CAAC;AAElC,eAAO,MAAM,WAAW,QAK0D,CAAC;AAEnF,eAAO,MAAM,WAAW;;;;;CA0BvB,CAAC;AAoBF,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,cAAc,CAAC,CAuC1B"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * find-cycles.ts
3
+ *
4
+ * MCP tool: find_cycles
5
+ *
6
+ * Detect all import cycles in the dependency graph and return them as ordered
7
+ * file paths. Unlike detect_antipatterns (which reports only a count and
8
+ * severity), this tool returns the actual cycle paths so an agent can understand
9
+ * and resolve circular dependencies.
10
+ *
11
+ * Algorithm: DFS with path stack. Each cycle is reported exactly once, rooted
12
+ * at its lexicographically smallest file. Severity is 'error' for tight 2–3-node
13
+ * cycles (tightly coupled pairs/triangles) and 'warning' for longer chains.
14
+ */
15
+ import { z } from 'zod';
16
+ import { openDatabase, getRepo } from '../../core/db/schema.js';
17
+ import { findImportCycles } from '../../graph/graph-traversal.js';
18
+ import { buildMeta } from './_meta.js';
19
+ export const name = 'find_cycles';
20
+ export const description = 'Detect all import cycles in the dependency graph and return them as ordered ' +
21
+ 'file paths. Unlike detect_antipatterns (which only counts cycles), this tool ' +
22
+ 'returns the actual cycle paths so you can understand and resolve circular ' +
23
+ 'dependencies. Severity is "error" for tight 2–3 node cycles and "warning" ' +
24
+ 'for longer chains. Use filePath to scope results to cycles involving one file.';
25
+ export const inputSchema = {
26
+ repoId: z.string().describe('Repo ID from index_folder or resolve_repo'),
27
+ filePath: z
28
+ .string()
29
+ .optional()
30
+ .describe('Scope to cycles that involve this file (relative to repo root). ' +
31
+ 'If omitted, all cycles in the repo are returned up to maxCycles.'),
32
+ maxCycles: z
33
+ .number()
34
+ .int()
35
+ .min(1)
36
+ .max(500)
37
+ .optional()
38
+ .describe('Stop after finding this many cycles (default 20)'),
39
+ minLength: z
40
+ .number()
41
+ .int()
42
+ .min(2)
43
+ .max(20)
44
+ .optional()
45
+ .describe('Minimum cycle length to report (default 2). ' +
46
+ 'A mutual import A→B→A has length 2. Raise this to skip direct pairs.'),
47
+ };
48
+ // ─── Handler ──────────────────────────────────────────────────────────────────
49
+ export async function handler(args) {
50
+ const t0 = Date.now();
51
+ const { repoId, filePath, maxCycles = 20, minLength = 2 } = args;
52
+ const db = openDatabase(repoId);
53
+ try {
54
+ const repo = getRepo(db, repoId);
55
+ if (!repo) {
56
+ return {
57
+ content: [
58
+ {
59
+ type: 'text',
60
+ text: JSON.stringify({
61
+ error: `Repo "${repoId}" not found. Run index_folder first.`,
62
+ }),
63
+ },
64
+ ],
65
+ isError: true,
66
+ };
67
+ }
68
+ const result = findImportCycles(repoId, db, filePath, maxCycles, minLength);
69
+ const responseText = JSON.stringify(result.cycles);
70
+ const output = {
71
+ cycles: result.cycles,
72
+ totalFound: result.totalFound,
73
+ truncated: result.truncated,
74
+ _tokenEstimate: Math.ceil(responseText.length / 4),
75
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
76
+ };
77
+ return {
78
+ content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
79
+ };
80
+ }
81
+ finally {
82
+ db.close();
83
+ }
84
+ }
85
+ //# sourceMappingURL=find-cycles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-cycles.js","sourceRoot":"","sources":["../../../src/server/tools/find-cycles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAGvC,MAAM,CAAC,MAAM,IAAI,GAAG,aAAa,CAAC;AAElC,MAAM,CAAC,MAAM,WAAW,GACtB,8EAA8E;IAC9E,+EAA+E;IAC/E,4EAA4E;IAC5E,4EAA4E;IAC5E,gFAAgF,CAAC;AAEnF,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;IACxE,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,kEAAkE;QAClE,kEAAkE,CACnE;IACH,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,GAAG,CAAC;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,kDAAkD,CAAC;IAC/D,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;SACP,QAAQ,EAAE;SACV,QAAQ,CACP,8CAA8C;QAC9C,sEAAsE,CACvE;CACJ,CAAC;AAkBF,iFAAiF;AAEjF,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAK7B;IACC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,GAAG,EAAE,EAAE,SAAS,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC;IAEjE,MAAM,EAAE,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IAEhC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO;gBACL,OAAO,EAAE;oBACP;wBACE,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,SAAS,MAAM,sCAAsC;yBAC7D,CAAC;qBACH;iBACF;gBACD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,gBAAgB,CAAC,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAE5E,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QACnD,MAAM,MAAM,GAAqB;YAC/B,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,UAAU,EAAE,MAAM,CAAC,UAAU;YAC7B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,cAAc,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC;YAClD,KAAK,EAAE,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;SAChD,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACnE,CAAC;IACJ,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * find-implementations.ts
3
+ *
4
+ * MCP tool: find_implementations
5
+ *
6
+ * Find all concrete implementations of a TypeScript interface or abstract class,
7
+ * and all method overrides for a given base method.
8
+ *
9
+ * Detection strategy (two-pass):
10
+ * 1. Name-based: search class symbols whose signature contains
11
+ * `implements InterfaceName` or `extends ClassName` via LIKE on symbols.signature.
12
+ * 2. Import-based: any file that imports the interface's file is also scanned
13
+ * for classes that match, catching cases where the name-based pass missed due
14
+ * to signature truncation.
15
+ *
16
+ * `implementedMethods` / `missingMethods` are computed by comparing the method
17
+ * symbols stored under the interface name against those stored under the
18
+ * implementing class name.
19
+ */
20
+ import { z } from 'zod';
21
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
22
+ export declare const name = "find_implementations";
23
+ export declare const description: string;
24
+ export declare const inputSchema: {
25
+ repoId: z.ZodString;
26
+ symbolId: z.ZodString;
27
+ includeAbstract: z.ZodOptional<z.ZodBoolean>;
28
+ limit: z.ZodOptional<z.ZodNumber>;
29
+ };
30
+ export interface ImplementationRecord {
31
+ symbolId: string;
32
+ name: string;
33
+ kind: string;
34
+ filePath: string;
35
+ startLine: number;
36
+ signature: string;
37
+ summary: string;
38
+ implementedMethods: string[];
39
+ missingMethods: string[];
40
+ }
41
+ export declare function handler(args: {
42
+ repoId: string;
43
+ symbolId: string;
44
+ includeAbstract?: boolean;
45
+ limit?: number;
46
+ }): Promise<CallToolResult>;
47
+ //# sourceMappingURL=find-implementations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-implementations.d.ts","sourceRoot":"","sources":["../../../src/server/tools/find-implementations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AASxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE,eAAO,MAAM,IAAI,yBAAyB,CAAC;AAE3C,eAAO,MAAM,WAAW,QAI6D,CAAC;AAEtF,eAAO,MAAM,WAAW;;;;;CAmBvB,CAAC;AAIF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAyBD,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,cAAc,CAAC,CAgI1B"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * find-implementations.ts
3
+ *
4
+ * MCP tool: find_implementations
5
+ *
6
+ * Find all concrete implementations of a TypeScript interface or abstract class,
7
+ * and all method overrides for a given base method.
8
+ *
9
+ * Detection strategy (two-pass):
10
+ * 1. Name-based: search class symbols whose signature contains
11
+ * `implements InterfaceName` or `extends ClassName` via LIKE on symbols.signature.
12
+ * 2. Import-based: any file that imports the interface's file is also scanned
13
+ * for classes that match, catching cases where the name-based pass missed due
14
+ * to signature truncation.
15
+ *
16
+ * `implementedMethods` / `missingMethods` are computed by comparing the method
17
+ * symbols stored under the interface name against those stored under the
18
+ * implementing class name.
19
+ */
20
+ import { z } from 'zod';
21
+ import { openDatabase, getRepo } from '../../core/db/schema.js';
22
+ import { getSymbolById } from '../../core/db/symbol-store.js';
23
+ import { findClassImplementations, getMethodNamesForSymbol, extractInterfaceMethodNames, } from '../../core/db/dep-store.js';
24
+ import { buildMeta } from './_meta.js';
25
+ import { getFileContent } from '../../core/db/file-store.js';
26
+ export const name = 'find_implementations';
27
+ export const description = 'Find all concrete implementations of a TypeScript interface or abstract class, ' +
28
+ 'and all method overrides for a given base method. ' +
29
+ 'Returns implementing classes with their implemented and missing methods. ' +
30
+ 'Use search_symbols to find the symbolId for an interface or abstract class first.';
31
+ export const inputSchema = {
32
+ repoId: z.string().describe('Repo ID from index_folder or resolve_repo'),
33
+ symbolId: z
34
+ .string()
35
+ .describe('Symbol ID of the interface or abstract class to search for'),
36
+ includeAbstract: z
37
+ .boolean()
38
+ .optional()
39
+ .describe('Include abstract subclasses in results (default false). ' +
40
+ 'When true, abstract classes that extend the target are included alongside concrete implementations.'),
41
+ limit: z
42
+ .number()
43
+ .int()
44
+ .min(1)
45
+ .max(200)
46
+ .optional()
47
+ .describe('Maximum number of implementations to return (default 50)'),
48
+ };
49
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
50
+ /** Compute 1-based line number from a byte/char offset within file content. */
51
+ function byteToLine(content, offset) {
52
+ const slice = content.slice(0, Math.min(offset, content.length));
53
+ let line = 1;
54
+ for (let i = 0; i < slice.length; i++) {
55
+ if (slice[i] === 0x0a)
56
+ line++;
57
+ }
58
+ return line;
59
+ }
60
+ // ─── Handler ──────────────────────────────────────────────────────────────────
61
+ export async function handler(args) {
62
+ const t0 = Date.now();
63
+ const { repoId, symbolId, includeAbstract = false, limit = 50 } = args;
64
+ const db = openDatabase(repoId);
65
+ try {
66
+ const repo = getRepo(db, repoId);
67
+ if (!repo) {
68
+ return {
69
+ content: [
70
+ {
71
+ type: 'text',
72
+ text: JSON.stringify({
73
+ error: `Repo "${repoId}" not found. Run index_folder first.`,
74
+ }),
75
+ },
76
+ ],
77
+ isError: true,
78
+ };
79
+ }
80
+ // Look up the target interface / abstract class
81
+ const target = getSymbolById(db, repoId, symbolId);
82
+ if (!target) {
83
+ return {
84
+ content: [
85
+ {
86
+ type: 'text',
87
+ text: JSON.stringify({
88
+ error: `Symbol "${symbolId}" not found in repo "${repoId}".`,
89
+ }),
90
+ },
91
+ ],
92
+ isError: true,
93
+ };
94
+ }
95
+ if (target.kind !== 'interface' && target.kind !== 'class') {
96
+ return {
97
+ content: [
98
+ {
99
+ type: 'text',
100
+ text: JSON.stringify({
101
+ error: `Symbol "${target.name}" has kind "${target.kind}". ` +
102
+ 'find_implementations only works with interface or class symbols.',
103
+ }),
104
+ },
105
+ ],
106
+ isError: true,
107
+ };
108
+ }
109
+ // Get interface/abstract-class method names.
110
+ // Interface methods are NOT indexed as separate symbols by the TypeScript handler,
111
+ // so we extract them from the raw file content using the target's byte range.
112
+ // For abstract classes, the indexed method symbols are used as fallback.
113
+ let interfaceMethods;
114
+ const targetFileContent = getFileContent(db, repoId, target.filePath);
115
+ if (targetFileContent) {
116
+ interfaceMethods = extractInterfaceMethodNames(targetFileContent, target.startByte, target.endByte);
117
+ }
118
+ else {
119
+ // Fallback to indexed method symbols (works for abstract classes)
120
+ interfaceMethods = getMethodNamesForSymbol(db, repoId, target.name, target.filePath);
121
+ }
122
+ // Find all classes/interfaces that implement or extend this target
123
+ const implementors = findClassImplementations(db, repoId, target.name, target.filePath, includeAbstract, limit);
124
+ // Build ImplementationRecord for each implementor
125
+ const implementations = [];
126
+ for (const impl of implementors) {
127
+ // Get the implementing class's method stems
128
+ const classMethods = getMethodNamesForSymbol(db, repoId, impl.name, impl.filePath);
129
+ const classMethodSet = new Set(classMethods);
130
+ const implementedMethods = interfaceMethods.filter((m) => classMethodSet.has(m));
131
+ const missingMethods = interfaceMethods.filter((m) => !classMethodSet.has(m));
132
+ // Compute startLine from file content
133
+ let startLine = 1;
134
+ const fileContent = getFileContent(db, repoId, impl.filePath);
135
+ if (fileContent) {
136
+ startLine = byteToLine(fileContent, impl.startByte);
137
+ }
138
+ implementations.push({
139
+ symbolId: impl.id,
140
+ name: impl.name,
141
+ kind: impl.kind,
142
+ filePath: impl.filePath,
143
+ startLine,
144
+ signature: impl.signature,
145
+ summary: impl.summary,
146
+ implementedMethods,
147
+ missingMethods,
148
+ });
149
+ }
150
+ const responseText = JSON.stringify(implementations);
151
+ const output = {
152
+ interfaceName: target.name,
153
+ interfaceFilePath: target.filePath,
154
+ implementations,
155
+ totalFound: implementations.length,
156
+ _tokenEstimate: Math.ceil(responseText.length / 4),
157
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
158
+ };
159
+ return {
160
+ content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
161
+ };
162
+ }
163
+ finally {
164
+ db.close();
165
+ }
166
+ }
167
+ //# sourceMappingURL=find-implementations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-implementations.js","sourceRoot":"","sources":["../../../src/server/tools/find-implementations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * find-untested-symbols.ts
3
+ *
4
+ * MCP tool: find_untested_symbols
5
+ *
6
+ * Identifies exported symbols (functions, methods, classes, etc.) in the
7
+ * codebase that do not appear to have any test coverage — i.e. whose names
8
+ * are not referenced in any test file.
9
+ *
10
+ * Detection strategy (static heuristic):
11
+ * 1. Identify test files by path convention:
12
+ * - Path segment is "test", "tests", "spec", "specs", or "__tests__"
13
+ * - Filename ends with .test.*, .spec.*, _test.*, or _spec.*
14
+ * 2. Extract all identifiers referenced in those test files.
15
+ * 3. Any non-test symbol whose name does NOT appear in the test identifier
16
+ * set is considered "untested".
17
+ *
18
+ * Limitations:
19
+ * - Name-based matching only; dynamic dispatch, aliases, and indirect calls
20
+ * can produce false negatives (symbol appears tested when it is not) or
21
+ * false positives (common names like `get` match unrelated things).
22
+ * - Does not read coverage reports; for accurate coverage, pipe in a
23
+ * coverage JSON file via get_test_coverage_map instead.
24
+ *
25
+ * Priority rating (per untested symbol):
26
+ * high — cyclomatic_complexity >= 5 OR line_count >= 20
27
+ * medium — cyclomatic_complexity >= 2 OR line_count >= 8
28
+ * low — all other symbols
29
+ */
30
+ import { z } from 'zod';
31
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
32
+ export declare const name = "find_untested_symbols";
33
+ export declare const description: string;
34
+ export declare const inputSchema: {
35
+ repoId: z.ZodString;
36
+ scope: z.ZodOptional<z.ZodString>;
37
+ kinds: z.ZodOptional<z.ZodArray<z.ZodString>>;
38
+ filePath: z.ZodOptional<z.ZodString>;
39
+ minLineCount: z.ZodOptional<z.ZodNumber>;
40
+ includeTestRefs: z.ZodOptional<z.ZodBoolean>;
41
+ limit: z.ZodOptional<z.ZodNumber>;
42
+ };
43
+ export declare function handler(args: {
44
+ repoId: string;
45
+ scope?: string;
46
+ kinds?: string[];
47
+ filePath?: string;
48
+ minLineCount?: number;
49
+ includeTestRefs?: boolean;
50
+ limit?: number;
51
+ }): Promise<CallToolResult>;
52
+ //# sourceMappingURL=find-untested-symbols.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find-untested-symbols.d.ts","sourceRoot":"","sources":["../../../src/server/tools/find-untested-symbols.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE,eAAO,MAAM,IAAI,0BAA0B,CAAC;AAE5C,eAAO,MAAM,WAAW,QAYyD,CAAC;AAQlF,eAAO,MAAM,WAAW;;;;;;;;CAsCvB,CAAC;AA4FF,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,cAAc,CAAC,CAoN1B"}