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,308 @@
1
+ /**
2
+ * check-delete-safe.ts
3
+ *
4
+ * MCP tool: check_delete_safe
5
+ *
6
+ * Pre-flight check for deleting a symbol or file. Returns a binary verdict
7
+ * and all live references that would break — so an agent can decide whether
8
+ * deletion is safe without manually interpreting find_references output.
9
+ *
10
+ * Safety rules:
11
+ * safe: false — if any live (non-test) references exist in the repo
12
+ * safe: false — if symbol is exported AND includeExternalRisk: true
13
+ * (exported symbols may be consumed by external npm packages)
14
+ * safe: false — if symbol is detected as an entry point
15
+ * safe: true — zero live refs, not exported (or external risk ignored),
16
+ * and not an entry point
17
+ *
18
+ * Modes:
19
+ * symbolId — check a single named symbol
20
+ * filePath — check all symbols in a file (aggregate verdict)
21
+ *
22
+ * Risk kinds:
23
+ * 'live-reference' — production code that imports or calls the symbol
24
+ * 'exported-symbol' — symbol is exported (potential external consumers)
25
+ * 'entry-point' — symbol is a route handler, main function, or framework default
26
+ * 'test-subject' — test file references the symbol (informational, not a hard block)
27
+ */
28
+ import { z } from 'zod';
29
+ import { openDatabase, getRepo } from '../../core/db/schema.js';
30
+ import { getSymbolById } from '../../core/db/symbol-store.js';
31
+ import { getAllFilesWithContent } from '../../core/db/file-store.js';
32
+ import { buildMeta } from './_meta.js';
33
+ export const name = 'check_delete_safe';
34
+ export const description = 'Pre-flight check for deleting a symbol or file. Returns a verdict and all live ' +
35
+ 'references that would break if the symbol were removed. ' +
36
+ 'safe: false when live references exist, the symbol is exported (external consumers), ' +
37
+ 'or the symbol is an entry point (route handler, main export). ' +
38
+ 'Supports two modes: symbolId (single symbol) or filePath (all symbols in a file). ' +
39
+ 'Use search_symbols or get_file_outline to find a symbolId first.';
40
+ export const inputSchema = {
41
+ repoId: z
42
+ .string()
43
+ .describe('Repo ID from index_folder or resolve_repo'),
44
+ symbolId: z
45
+ .string()
46
+ .optional()
47
+ .describe('Symbol ID of the symbol to check. Mutually exclusive with filePath. ' +
48
+ 'Use search_symbols to find the symbolId.'),
49
+ filePath: z
50
+ .string()
51
+ .optional()
52
+ .describe('File path relative to the repo root — checks all symbols in the file and ' +
53
+ 'produces an aggregate verdict. Mutually exclusive with symbolId.'),
54
+ includeExternalRisk: z
55
+ .boolean()
56
+ .optional()
57
+ .describe('Warn when a symbol is exported but has no internal references ' +
58
+ '(may be consumed by external npm packages). Default true. ' +
59
+ 'Set false to suppress this warning.'),
60
+ };
61
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
62
+ function escapeRegex(str) {
63
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
64
+ }
65
+ /**
66
+ * Return true when a file path looks like a test file.
67
+ * Matches: *.test.ts, *.spec.ts, /__tests__/, /test/, /tests/
68
+ */
69
+ function isTestFile(filePath) {
70
+ const p = filePath.replace(/\\/g, '/');
71
+ return (/\.test\.[jt]sx?$/.test(p) ||
72
+ /\.spec\.[jt]sx?$/.test(p) ||
73
+ /\/__tests__\//.test(p) ||
74
+ /\/tests?\//.test(p));
75
+ }
76
+ /** Return true when the signature contains the `export` keyword. */
77
+ function isExportedSignature(signature) {
78
+ return /\bexport\b/.test(signature);
79
+ }
80
+ /**
81
+ * Heuristic entry-point detection.
82
+ * A symbol is considered an entry point when:
83
+ * - its name is one of the well-known entry names (main, default, handler, index)
84
+ * - its signature contains a route/controller decorator
85
+ * - it is a default export from an index file
86
+ */
87
+ function isEntryPointSymbol(name, signature, filePath) {
88
+ if (['main', 'default', 'handler', 'index'].includes(name))
89
+ return true;
90
+ if (/@(Get|Post|Put|Delete|Patch|Route|Controller)\b/.test(signature))
91
+ return true;
92
+ const fp = filePath.replace(/\\/g, '/');
93
+ if (/\/index\.[jt]sx?$/.test(fp) && /\bdefault\b/.test(signature))
94
+ return true;
95
+ return false;
96
+ }
97
+ /**
98
+ * Scan all cached file contents for references to `symbolName`.
99
+ * The definition file is excluded (deleting the symbol removes its definition too).
100
+ * References found in test files are tagged 'test-subject'; all others 'live-reference'.
101
+ */
102
+ function findRisksForSymbol(symbolName, definitionFilePath, files) {
103
+ const pattern = new RegExp(`\\b${escapeRegex(symbolName)}\\b`);
104
+ const risks = [];
105
+ let liveReferenceCount = 0;
106
+ for (const { path, rawContent } of files) {
107
+ if (!rawContent)
108
+ continue;
109
+ if (path === definitionFilePath)
110
+ continue;
111
+ const text = rawContent.toString('utf8');
112
+ const lines = text.split('\n');
113
+ const test = isTestFile(path);
114
+ for (let i = 0; i < lines.length; i++) {
115
+ const line = lines[i];
116
+ if (!pattern.test(line))
117
+ continue;
118
+ const context = line.trim().length > 120 ? line.trim().slice(0, 120) : line.trim();
119
+ if (test) {
120
+ risks.push({
121
+ kind: 'test-subject',
122
+ filePath: path,
123
+ line: i + 1,
124
+ detail: `Test file references "${symbolName}": ${context}`,
125
+ });
126
+ }
127
+ else {
128
+ liveReferenceCount++;
129
+ risks.push({
130
+ kind: 'live-reference',
131
+ filePath: path,
132
+ line: i + 1,
133
+ detail: context,
134
+ });
135
+ }
136
+ }
137
+ }
138
+ return { risks, liveReferenceCount };
139
+ }
140
+ /**
141
+ * Run the full safety check for one symbol and return aggregated risk data.
142
+ */
143
+ function checkOneSymbol(symbolName, symbolFilePath, symbolSignature, includeExternalRisk, files) {
144
+ const { risks, liveReferenceCount } = findRisksForSymbol(symbolName, symbolFilePath, files);
145
+ const exported = isExportedSignature(symbolSignature);
146
+ const entryPoint = isEntryPointSymbol(symbolName, symbolSignature, symbolFilePath);
147
+ if (exported && includeExternalRisk) {
148
+ risks.push({
149
+ kind: 'exported-symbol',
150
+ filePath: symbolFilePath,
151
+ detail: `"${symbolName}" is exported and may be consumed by external packages. ` +
152
+ `No internal references were found.`,
153
+ });
154
+ }
155
+ if (entryPoint) {
156
+ risks.push({
157
+ kind: 'entry-point',
158
+ filePath: symbolFilePath,
159
+ detail: `"${symbolName}" appears to be an entry point (route handler, main export, or framework default).`,
160
+ });
161
+ }
162
+ return { risks, liveReferenceCount, isExported: exported, isEntryPoint: entryPoint };
163
+ }
164
+ /**
165
+ * Build a human-readable verdict sentence from aggregated risk data.
166
+ */
167
+ function buildVerdict(safe, liveReferenceCount, isExported, isEntryPoint, risks) {
168
+ if (safe) {
169
+ const testCount = risks.filter((r) => r.kind === 'test-subject').length;
170
+ const testNote = testCount > 0 ? ` (${testCount} test reference${testCount > 1 ? 's' : ''} will also break).` : '.';
171
+ return `Safe to delete: no live references found${testNote}`;
172
+ }
173
+ const parts = [];
174
+ if (liveReferenceCount > 0) {
175
+ const fileSet = new Set(risks.filter((r) => r.kind === 'live-reference').map((r) => r.filePath));
176
+ parts.push(`${liveReferenceCount} live reference${liveReferenceCount > 1 ? 's' : ''} in ${fileSet.size} file${fileSet.size > 1 ? 's' : ''}`);
177
+ }
178
+ if (isExported) {
179
+ parts.push('symbol is exported (external consumers possible)');
180
+ }
181
+ if (isEntryPoint) {
182
+ parts.push('symbol is an entry point');
183
+ }
184
+ return `Unsafe to delete: ${parts.join('; ')}.`;
185
+ }
186
+ // ─── Handler ──────────────────────────────────────────────────────────────────
187
+ export async function handler(args) {
188
+ const t0 = Date.now();
189
+ const { repoId, symbolId, filePath, includeExternalRisk = true } = args;
190
+ if (!symbolId && !filePath) {
191
+ return {
192
+ content: [
193
+ {
194
+ type: 'text',
195
+ text: JSON.stringify({
196
+ error: 'Provide either symbolId or filePath.',
197
+ }),
198
+ },
199
+ ],
200
+ isError: true,
201
+ };
202
+ }
203
+ const db = openDatabase(repoId);
204
+ try {
205
+ const repo = getRepo(db, repoId);
206
+ if (!repo) {
207
+ return {
208
+ content: [
209
+ {
210
+ type: 'text',
211
+ text: JSON.stringify({
212
+ error: `Repo "${repoId}" not found. Run index_folder first.`,
213
+ }),
214
+ },
215
+ ],
216
+ isError: true,
217
+ };
218
+ }
219
+ const files = getAllFilesWithContent(db, repoId);
220
+ // ── symbolId mode ──────────────────────────────────────────────────────────
221
+ if (symbolId) {
222
+ const symbol = getSymbolById(db, repoId, symbolId);
223
+ if (!symbol) {
224
+ return {
225
+ content: [
226
+ {
227
+ type: 'text',
228
+ text: JSON.stringify({
229
+ error: `Symbol "${symbolId}" not found in repo "${repoId}".`,
230
+ }),
231
+ },
232
+ ],
233
+ isError: true,
234
+ };
235
+ }
236
+ const { risks, liveReferenceCount, isExported, isEntryPoint } = checkOneSymbol(symbol.name, symbol.filePath, symbol.signature, includeExternalRisk, files);
237
+ const safe = liveReferenceCount === 0 &&
238
+ (!isExported || !includeExternalRisk) &&
239
+ !isEntryPoint;
240
+ const verdict = buildVerdict(safe, liveReferenceCount, isExported, isEntryPoint, risks);
241
+ const responseText = JSON.stringify(risks);
242
+ const output = {
243
+ safe,
244
+ verdict,
245
+ risks,
246
+ liveReferenceCount,
247
+ isExported,
248
+ isEntryPoint,
249
+ _tokenEstimate: Math.ceil(responseText.length / 4),
250
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
251
+ };
252
+ return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
253
+ }
254
+ // ── filePath mode ──────────────────────────────────────────────────────────
255
+ const targetFilePath = filePath;
256
+ const symbolRows = db
257
+ .prepare('SELECT id, name, kind, file_path, signature FROM symbols WHERE repo_id = ? AND file_path = ?')
258
+ .all(repoId, targetFilePath);
259
+ if (symbolRows.length === 0) {
260
+ return {
261
+ content: [
262
+ {
263
+ type: 'text',
264
+ text: JSON.stringify({
265
+ error: `No symbols found for file "${targetFilePath}" in repo "${repoId}". ` +
266
+ 'Check the file path is relative to the repo root and the file is indexed.',
267
+ }),
268
+ },
269
+ ],
270
+ isError: true,
271
+ };
272
+ }
273
+ // Aggregate results across all symbols in the file
274
+ const allRisks = [];
275
+ let totalLiveRefCount = 0;
276
+ let anyExported = false;
277
+ let anyEntryPoint = false;
278
+ for (const row of symbolRows) {
279
+ const { risks, liveReferenceCount, isExported, isEntryPoint } = checkOneSymbol(row.name, row.file_path, row.signature, includeExternalRisk, files);
280
+ allRisks.push(...risks);
281
+ totalLiveRefCount += liveReferenceCount;
282
+ if (isExported)
283
+ anyExported = true;
284
+ if (isEntryPoint)
285
+ anyEntryPoint = true;
286
+ }
287
+ const safe = totalLiveRefCount === 0 &&
288
+ (!anyExported || !includeExternalRisk) &&
289
+ !anyEntryPoint;
290
+ const verdict = buildVerdict(safe, totalLiveRefCount, anyExported, anyEntryPoint, allRisks);
291
+ const responseText = JSON.stringify(allRisks);
292
+ const output = {
293
+ safe,
294
+ verdict,
295
+ risks: allRisks,
296
+ liveReferenceCount: totalLiveRefCount,
297
+ isExported: anyExported,
298
+ isEntryPoint: anyEntryPoint,
299
+ _tokenEstimate: Math.ceil(responseText.length / 4),
300
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
301
+ };
302
+ return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
303
+ }
304
+ finally {
305
+ db.close();
306
+ }
307
+ }
308
+ //# sourceMappingURL=check-delete-safe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-delete-safe.js","sourceRoot":"","sources":["../../../src/server/tools/check-delete-safe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * check-move-safe.ts
3
+ *
4
+ * MCP tool: check_move_safe
5
+ *
6
+ * Pre-flight check for moving a file to a new location. Returns:
7
+ * - All import statements that need updating (importUpdates), with exact
8
+ * current and new paths, plus the line number of each import.
9
+ * - Whether the move would introduce import cycles at the new location
10
+ * (wouldIntroduceCycles).
11
+ *
12
+ * Safety definition:
13
+ * safe: false — if the move would place the file in an existing import cycle
14
+ * (the cycle moves with the file to its new location).
15
+ * safe: true — if all affected imports can be updated mechanically and the
16
+ * new location has no cycle involvement.
17
+ *
18
+ * Note: all moves are mechanically doable — the only hard blocker is cycle
19
+ * risk. `importUpdates` is the primary output: an exact checklist of the
20
+ * import statements that must be updated after the move.
21
+ */
22
+ import { z } from 'zod';
23
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
24
+ export declare const name = "check_move_safe";
25
+ export declare const description: string;
26
+ export declare const inputSchema: {
27
+ repoId: z.ZodString;
28
+ filePath: z.ZodString;
29
+ newFilePath: z.ZodString;
30
+ checkCycles: z.ZodOptional<z.ZodBoolean>;
31
+ };
32
+ export interface ImportUpdate {
33
+ importerFilePath: string;
34
+ currentImportPath: string;
35
+ newImportPath: string;
36
+ line: number;
37
+ }
38
+ export declare function handler(args: {
39
+ repoId: string;
40
+ filePath: string;
41
+ newFilePath: string;
42
+ checkCycles?: boolean;
43
+ }): Promise<CallToolResult>;
44
+ //# sourceMappingURL=check-move-safe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-move-safe.d.ts","sourceRoot":"","sources":["../../../src/server/tools/check-move-safe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAOxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAGzE,eAAO,MAAM,IAAI,oBAAoB,CAAC;AAEtC,eAAO,MAAM,WAAW,QAM0D,CAAC;AAEnF,eAAO,MAAM,WAAW;;;;;CAevB,CAAC;AAIF,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAyJD,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,GAAG,OAAO,CAAC,cAAc,CAAC,CA2H1B"}
@@ -0,0 +1,266 @@
1
+ /**
2
+ * check-move-safe.ts
3
+ *
4
+ * MCP tool: check_move_safe
5
+ *
6
+ * Pre-flight check for moving a file to a new location. Returns:
7
+ * - All import statements that need updating (importUpdates), with exact
8
+ * current and new paths, plus the line number of each import.
9
+ * - Whether the move would introduce import cycles at the new location
10
+ * (wouldIntroduceCycles).
11
+ *
12
+ * Safety definition:
13
+ * safe: false — if the move would place the file in an existing import cycle
14
+ * (the cycle moves with the file to its new location).
15
+ * safe: true — if all affected imports can be updated mechanically and the
16
+ * new location has no cycle involvement.
17
+ *
18
+ * Note: all moves are mechanically doable — the only hard blocker is cycle
19
+ * risk. `importUpdates` is the primary output: an exact checklist of the
20
+ * import statements that must be updated after the move.
21
+ */
22
+ import { z } from 'zod';
23
+ import { dirname, extname, relative, sep } from 'path';
24
+ import { openDatabase, getRepo } from '../../core/db/schema.js';
25
+ import { getFileContent } from '../../core/db/file-store.js';
26
+ import { getImportersOf, getAllDepEdges } from '../../core/db/dep-store.js';
27
+ import { buildMeta } from './_meta.js';
28
+ export const name = 'check_move_safe';
29
+ export const description = 'Pre-flight check for moving a file to a new location. Returns a checklist of ' +
30
+ 'import statements that need updating (importUpdates) plus cycle-risk analysis ' +
31
+ '(wouldIntroduceCycles). ' +
32
+ 'safe: false only when the move would place the file inside an existing import cycle. ' +
33
+ 'All moves are mechanically doable — importUpdates gives you the exact edits needed. ' +
34
+ 'Use find_importers to preview which files depend on a module before moving it.';
35
+ export const inputSchema = {
36
+ repoId: z.string().describe('Repo ID from index_folder or resolve_repo'),
37
+ filePath: z
38
+ .string()
39
+ .describe('Current file path relative to the repo root (e.g. "src/utils/hash.ts")'),
40
+ newFilePath: z
41
+ .string()
42
+ .describe('Proposed new location relative to the repo root (e.g. "src/core/hash.ts")'),
43
+ checkCycles: z
44
+ .boolean()
45
+ .optional()
46
+ .describe('Simulate the move in the dependency graph and detect any import cycles ' +
47
+ 'that would involve the new location. Default true.'),
48
+ };
49
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
50
+ /** Normalize path separators to forward slashes. */
51
+ function normalizeSep(p) {
52
+ return p.split(sep).join('/');
53
+ }
54
+ /**
55
+ * Compute the new import specifier from `importerFilePath` to `newTargetPath`,
56
+ * preserving whether the original specifier had a file extension.
57
+ *
58
+ * Examples:
59
+ * importerFilePath = 'src/main.ts', newTargetPath = 'src/core/hash.ts',
60
+ * currentSpecifier = './utils/hash'
61
+ * → './core/hash' (no extension, matching original)
62
+ *
63
+ * importerFilePath = 'src/deep/nested/consumer.ts', newTargetPath = 'src/deep/parser.ts',
64
+ * currentSpecifier = '../../lib/parser'
65
+ * → '../parser'
66
+ */
67
+ function computeNewImportPath(importerFilePath, newTargetPath, currentSpecifier) {
68
+ const importerDir = dirname(importerFilePath);
69
+ const rawRelative = normalizeSep(relative(normalizeSep(importerDir), normalizeSep(newTargetPath)));
70
+ // Add './' prefix when the path doesn't start with '../'
71
+ const withPrefix = rawRelative.startsWith('../') ? rawRelative : `./${rawRelative}`;
72
+ // Match extension presence from the original specifier
73
+ if (!extname(currentSpecifier)) {
74
+ // Original had no extension → strip extension from computed path
75
+ const ext = extname(withPrefix);
76
+ return ext ? withPrefix.slice(0, -ext.length) : withPrefix;
77
+ }
78
+ return withPrefix;
79
+ }
80
+ /** Find the 1-based line number of the first import containing `specifier`. */
81
+ function findImportLine(content, specifier) {
82
+ if (!content)
83
+ return 0;
84
+ const text = content.toString('utf8');
85
+ const lines = text.split('\n');
86
+ // Match the raw specifier surrounded by any quote character
87
+ const escaped = specifier.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
88
+ const re = new RegExp(`['"\`]${escaped}['"\`]`);
89
+ for (let i = 0; i < lines.length; i++) {
90
+ if (re.test(lines[i]))
91
+ return i + 1;
92
+ }
93
+ return 0;
94
+ }
95
+ /**
96
+ * Get the import specifier used by `importerFile` when importing `targetFile`.
97
+ * Returns the first matching edge's specifier, or an empty string if not found.
98
+ */
99
+ function getSpecifier(db, repoId, importerFile, targetFile) {
100
+ const row = db
101
+ .prepare(`SELECT specifier FROM dep_edges
102
+ WHERE repo_id = ? AND source_file = ? AND target_file = ?
103
+ LIMIT 1`)
104
+ .get(repoId, importerFile, targetFile);
105
+ return row?.specifier ?? '';
106
+ }
107
+ /**
108
+ * Detect all import cycles in a modified dependency graph where `oldPath` has
109
+ * been renamed to `newPath`. Returns cycles that involve `newPath`.
110
+ *
111
+ * Uses the same DFS algorithm as findImportCycles: each cycle is reported
112
+ * exactly once, rooted at its lexicographically smallest file.
113
+ */
114
+ function detectCyclesAfterMove(edges, oldPath, newPath, maxCycles = 20) {
115
+ // Build adjacency list with oldPath renamed to newPath
116
+ const adj = new Map();
117
+ for (const edge of edges) {
118
+ if (edge.sourceFile === edge.targetFile)
119
+ continue;
120
+ const src = edge.sourceFile === oldPath ? newPath : edge.sourceFile;
121
+ const tgt = edge.targetFile === oldPath ? newPath : edge.targetFile;
122
+ if (src === tgt)
123
+ continue;
124
+ const srcList = adj.get(src) ?? [];
125
+ if (!srcList.includes(tgt))
126
+ srcList.push(tgt);
127
+ adj.set(src, srcList);
128
+ if (!adj.has(tgt))
129
+ adj.set(tgt, []);
130
+ }
131
+ for (const v of adj.values())
132
+ v.sort();
133
+ const found = [];
134
+ const cap = maxCycles + 1;
135
+ const nodes = [...adj.keys()].sort();
136
+ function dfs(start, path, pathSet) {
137
+ if (found.length >= cap)
138
+ return;
139
+ const cur = path[path.length - 1];
140
+ for (const next of adj.get(cur) ?? []) {
141
+ if (found.length >= cap)
142
+ return;
143
+ if (next === start && path.length >= 2) {
144
+ found.push([...path]);
145
+ }
146
+ else if (!pathSet.has(next) && next > start) {
147
+ pathSet.add(next);
148
+ path.push(next);
149
+ dfs(start, path, pathSet);
150
+ path.pop();
151
+ pathSet.delete(next);
152
+ }
153
+ }
154
+ }
155
+ for (const node of nodes) {
156
+ if (found.length >= cap)
157
+ break;
158
+ dfs(node, [node], new Set([node]));
159
+ }
160
+ // Return only cycles that involve the new (moved) path, capped at maxCycles
161
+ return found.filter((c) => c.includes(newPath)).slice(0, maxCycles);
162
+ }
163
+ // ─── Handler ──────────────────────────────────────────────────────────────────
164
+ export async function handler(args) {
165
+ const t0 = Date.now();
166
+ const { repoId, filePath, newFilePath, checkCycles = true } = args;
167
+ // Normalize separators so the paths match what's stored in the DB
168
+ const normalizedFilePath = normalizeSep(filePath);
169
+ const normalizedNewFilePath = normalizeSep(newFilePath);
170
+ if (normalizedFilePath === normalizedNewFilePath) {
171
+ const output = {
172
+ safe: true,
173
+ verdict: 'Safe to move: source and destination paths are the same (no-op).',
174
+ filePath: normalizedFilePath,
175
+ newFilePath: normalizedNewFilePath,
176
+ importUpdates: [],
177
+ importUpdateCount: 0,
178
+ newCycles: [],
179
+ wouldIntroduceCycles: false,
180
+ _tokenEstimate: 0,
181
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
182
+ };
183
+ return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
184
+ }
185
+ const db = openDatabase(repoId);
186
+ try {
187
+ const repo = getRepo(db, repoId);
188
+ if (!repo) {
189
+ return {
190
+ content: [
191
+ {
192
+ type: 'text',
193
+ text: JSON.stringify({
194
+ error: `Repo "${repoId}" not found. Run index_folder first.`,
195
+ }),
196
+ },
197
+ ],
198
+ isError: true,
199
+ };
200
+ }
201
+ // ── 1. Find all direct importers ──────────────────────────────────────────
202
+ const importerFiles = getImportersOf(db, repoId, normalizedFilePath);
203
+ // ── 2. Build ImportUpdate list ────────────────────────────────────────────
204
+ const importUpdates = [];
205
+ for (const importerFilePath of importerFiles) {
206
+ const specifier = getSpecifier(db, repoId, importerFilePath, normalizedFilePath);
207
+ if (!specifier)
208
+ continue; // edge without specifier — skip
209
+ const newImportPath = computeNewImportPath(importerFilePath, normalizedNewFilePath, specifier);
210
+ const content = getFileContent(db, repoId, importerFilePath);
211
+ const line = findImportLine(content, specifier);
212
+ importUpdates.push({
213
+ importerFilePath,
214
+ currentImportPath: specifier,
215
+ newImportPath,
216
+ line,
217
+ });
218
+ }
219
+ // Sort by importer path for deterministic output
220
+ importUpdates.sort((a, b) => a.importerFilePath.localeCompare(b.importerFilePath));
221
+ // ── 3. Cycle detection ────────────────────────────────────────────────────
222
+ let newCycles = [];
223
+ if (checkCycles) {
224
+ const allEdges = getAllDepEdges(db, repoId);
225
+ newCycles = detectCyclesAfterMove(allEdges, normalizedFilePath, normalizedNewFilePath);
226
+ }
227
+ const wouldIntroduceCycles = newCycles.length > 0;
228
+ // ── 4. Verdict ────────────────────────────────────────────────────────────
229
+ const safe = !wouldIntroduceCycles;
230
+ let verdict;
231
+ if (safe) {
232
+ const count = importUpdates.length;
233
+ if (count === 0) {
234
+ verdict = 'Safe to move: no importers found. No import statements need updating.';
235
+ }
236
+ else {
237
+ verdict =
238
+ `Safe to move: ${count} import statement${count !== 1 ? 's' : ''} will need updating across ` +
239
+ `${new Set(importUpdates.map((u) => u.importerFilePath)).size} file${importUpdates.length !== 1 ? 's' : ''}. No cycles.`;
240
+ }
241
+ }
242
+ else {
243
+ verdict =
244
+ `Move introduces ${newCycles.length} import cycle${newCycles.length !== 1 ? 's' : ''} at the new location. ` +
245
+ `${importUpdates.length} import statement${importUpdates.length !== 1 ? 's' : ''} also need updating.`;
246
+ }
247
+ const responseText = JSON.stringify({ importUpdates, newCycles });
248
+ const output = {
249
+ safe,
250
+ verdict,
251
+ filePath: normalizedFilePath,
252
+ newFilePath: normalizedNewFilePath,
253
+ importUpdates,
254
+ importUpdateCount: importUpdates.length,
255
+ newCycles,
256
+ wouldIntroduceCycles,
257
+ _tokenEstimate: Math.ceil(responseText.length / 4),
258
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
259
+ };
260
+ return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
261
+ }
262
+ finally {
263
+ db.close();
264
+ }
265
+ }
266
+ //# sourceMappingURL=check-move-safe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-move-safe.js","sourceRoot":"","sources":["../../../src/server/tools/check-move-safe.ts"],"names":[],"mappings":"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"}