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,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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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * check-rename-safe.ts
3
+ *
4
+ * MCP tool: check_rename_safe
5
+ *
6
+ * Pre-flight check for renaming a symbol. Returns a binary verdict, all
7
+ * affected files, and the specific lines that will need updating — so an
8
+ * agent can decide whether to proceed without manually inspecting raw
9
+ * reference lists.
10
+ *
11
+ * Safety rules:
12
+ * safe: false — if conflicts exist (newName already present in the same file)
13
+ * safe: false — if any reference is a string-literal (runtime string that
14
+ * won't be fixed by a text rename, requires human judgment)
15
+ * safe: true — all other cases (comment references are included but not
16
+ * blockers)
17
+ *
18
+ * changeType detection (in priority order):
19
+ * 'comment' — line starts with // or * (JSDoc)
20
+ * 'import' — line contains the `import` keyword
21
+ * 'string-literal' — symbol name appears inside quote characters
22
+ * 'type-reference' — line contains `type` or `interface` keyword
23
+ * 'call' — default
24
+ */
25
+ import { z } from 'zod';
26
+ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
27
+ export declare const name = "check_rename_safe";
28
+ export declare const description: string;
29
+ export declare const inputSchema: {
30
+ repoId: z.ZodString;
31
+ symbolId: z.ZodString;
32
+ newName: z.ZodString;
33
+ checkConflicts: z.ZodOptional<z.ZodBoolean>;
34
+ };
35
+ export interface AffectedSite {
36
+ filePath: string;
37
+ line: number;
38
+ column: number;
39
+ context: string;
40
+ changeType: 'call' | 'import' | 'type-reference' | 'string-literal' | 'comment';
41
+ }
42
+ export declare function handler(args: {
43
+ repoId: string;
44
+ symbolId: string;
45
+ newName: string;
46
+ checkConflicts?: boolean;
47
+ }): Promise<CallToolResult>;
48
+ //# sourceMappingURL=check-rename-safe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-rename-safe.d.ts","sourceRoot":"","sources":["../../../src/server/tools/check-rename-safe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAEzE,eAAO,MAAM,IAAI,sBAAsB,CAAC;AAExC,eAAO,MAAM,WAAW,QAK0B,CAAC;AAEnD,eAAO,MAAM,WAAW;;;;;CAWvB,CAAC;AAIF,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,QAAQ,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,SAAS,CAAC;CACjF;AAyDD,wBAAsB,OAAO,CAAC,IAAI,EAAE;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC,cAAc,CAAC,CA6J1B"}
@@ -0,0 +1,218 @@
1
+ /**
2
+ * check-rename-safe.ts
3
+ *
4
+ * MCP tool: check_rename_safe
5
+ *
6
+ * Pre-flight check for renaming a symbol. Returns a binary verdict, all
7
+ * affected files, and the specific lines that will need updating — so an
8
+ * agent can decide whether to proceed without manually inspecting raw
9
+ * reference lists.
10
+ *
11
+ * Safety rules:
12
+ * safe: false — if conflicts exist (newName already present in the same file)
13
+ * safe: false — if any reference is a string-literal (runtime string that
14
+ * won't be fixed by a text rename, requires human judgment)
15
+ * safe: true — all other cases (comment references are included but not
16
+ * blockers)
17
+ *
18
+ * changeType detection (in priority order):
19
+ * 'comment' — line starts with // or * (JSDoc)
20
+ * 'import' — line contains the `import` keyword
21
+ * 'string-literal' — symbol name appears inside quote characters
22
+ * 'type-reference' — line contains `type` or `interface` keyword
23
+ * 'call' — default
24
+ */
25
+ import { z } from 'zod';
26
+ import { openDatabase, getRepo } from '../../core/db/schema.js';
27
+ import { getSymbolById } from '../../core/db/symbol-store.js';
28
+ import { getAllFilesWithContent } from '../../core/db/file-store.js';
29
+ import { buildMeta } from './_meta.js';
30
+ export const name = 'check_rename_safe';
31
+ export const description = 'Pre-flight check for renaming a symbol. Returns a verdict, all affected files, ' +
32
+ 'and the specific lines that will need updating. ' +
33
+ 'safe: false when the new name conflicts with an existing symbol or when string-literal ' +
34
+ 'references exist that require manual updates. ' +
35
+ 'Use search_symbols to find the symbolId first.';
36
+ export const inputSchema = {
37
+ repoId: z.string().describe('Repo ID from index_folder or resolve_repo'),
38
+ symbolId: z.string().describe('Symbol ID of the symbol to rename'),
39
+ newName: z.string().min(1).describe('Proposed new name for the symbol'),
40
+ checkConflicts: z
41
+ .boolean()
42
+ .optional()
43
+ .describe('Check if newName already exists in the same file (default true). ' +
44
+ 'Set false to skip conflict detection for speed.'),
45
+ };
46
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
47
+ function escapeRegex(str) {
48
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
49
+ }
50
+ /**
51
+ * Classify a reference line into a change type.
52
+ * Checked in priority order so that the most specific match wins.
53
+ */
54
+ function detectChangeType(lineContent, symbolName) {
55
+ const trimmed = lineContent.trim();
56
+ // Comment: line starts with // or * (JSDoc block) or /*
57
+ if (/^(\/\/|\*|\/\*)/.test(trimmed)) {
58
+ return 'comment';
59
+ }
60
+ // Import statement
61
+ if (/\bimport\b/.test(trimmed)) {
62
+ return 'import';
63
+ }
64
+ // String literal: symbol name appears inside quote characters
65
+ const escaped = escapeRegex(symbolName);
66
+ if (new RegExp(`['"\`][^'"\`]*\\b${escaped}\\b[^'"\`]*['"\`]`).test(trimmed)) {
67
+ return 'string-literal';
68
+ }
69
+ // Type reference: `type` or `interface` keyword on this line
70
+ if (/\btype\b/.test(trimmed) || /\binterface\b/.test(trimmed)) {
71
+ return 'type-reference';
72
+ }
73
+ // Default: call / variable usage
74
+ return 'call';
75
+ }
76
+ // ─── Handler ──────────────────────────────────────────────────────────────────
77
+ export async function handler(args) {
78
+ const t0 = Date.now();
79
+ const { repoId, symbolId, newName, checkConflicts = true } = args;
80
+ const db = openDatabase(repoId);
81
+ try {
82
+ const repo = getRepo(db, repoId);
83
+ if (!repo) {
84
+ return {
85
+ content: [
86
+ {
87
+ type: 'text',
88
+ text: JSON.stringify({
89
+ error: `Repo "${repoId}" not found. Run index_folder first.`,
90
+ }),
91
+ },
92
+ ],
93
+ isError: true,
94
+ };
95
+ }
96
+ const symbol = getSymbolById(db, repoId, symbolId);
97
+ if (!symbol) {
98
+ return {
99
+ content: [
100
+ {
101
+ type: 'text',
102
+ text: JSON.stringify({
103
+ error: `Symbol "${symbolId}" not found in repo "${repoId}".`,
104
+ }),
105
+ },
106
+ ],
107
+ isError: true,
108
+ };
109
+ }
110
+ // No-op: renaming to the same name is always safe
111
+ if (symbol.name === newName) {
112
+ const output = {
113
+ safe: true,
114
+ verdict: `Safe to rename: new name is the same as the current name (no-op).`,
115
+ symbolName: symbol.name,
116
+ newName,
117
+ conflicts: [],
118
+ affectedSites: [],
119
+ affectedFileCount: 0,
120
+ _tokenEstimate: 0,
121
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
122
+ };
123
+ return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
124
+ }
125
+ // ── 1. Find all references ────────────────────────────────────────────────
126
+ const affectedSites = [];
127
+ const pattern = new RegExp(`\\b${escapeRegex(symbol.name)}\\b`);
128
+ // Definition file is excluded from reference scan (we don't list the
129
+ // declaration itself as an affected site — only call/import sites)
130
+ const definitionFile = symbol.filePath;
131
+ const files = getAllFilesWithContent(db, repoId);
132
+ for (const { path, rawContent } of files) {
133
+ if (!rawContent)
134
+ continue;
135
+ if (path === definitionFile)
136
+ continue;
137
+ const text = rawContent.toString('utf8');
138
+ const lines = text.split('\n');
139
+ for (let i = 0; i < lines.length; i++) {
140
+ const line = lines[i];
141
+ if (!pattern.test(line))
142
+ continue;
143
+ const match = pattern.exec(line);
144
+ const column = match ? match.index + 1 : 1; // 1-based
145
+ affectedSites.push({
146
+ filePath: path,
147
+ line: i + 1,
148
+ column,
149
+ context: line.length > 120 ? line.slice(0, 120) : line,
150
+ changeType: detectChangeType(line, symbol.name),
151
+ });
152
+ }
153
+ }
154
+ // ── 2. Conflict detection ─────────────────────────────────────────────────
155
+ const conflicts = [];
156
+ if (checkConflicts) {
157
+ // Look for any symbol with newName in the same file as the declaration
158
+ const conflictRows = db
159
+ .prepare(`SELECT name, file_path, kind FROM symbols
160
+ WHERE repo_id = ? AND name = ? AND file_path = ?`)
161
+ .all(repoId, newName, definitionFile);
162
+ for (const row of conflictRows) {
163
+ conflicts.push(`${row.name} (${row.kind}) in ${row.file_path}`);
164
+ }
165
+ }
166
+ // ── 3. Compute verdict ────────────────────────────────────────────────────
167
+ const hasStringLiterals = affectedSites.some((s) => s.changeType === 'string-literal');
168
+ const safe = conflicts.length === 0 && !hasStringLiterals;
169
+ const uniqueFiles = new Set(affectedSites.map((s) => s.filePath));
170
+ const affectedFileCount = uniqueFiles.size;
171
+ const callCount = affectedSites.filter((s) => s.changeType === 'call').length;
172
+ const importCount = affectedSites.filter((s) => s.changeType === 'import').length;
173
+ const stringLitCount = affectedSites.filter((s) => s.changeType === 'string-literal').length;
174
+ const commentCount = affectedSites.filter((s) => s.changeType === 'comment').length;
175
+ const typeRefCount = affectedSites.filter((s) => s.changeType === 'type-reference').length;
176
+ let verdict;
177
+ if (!safe) {
178
+ const reasons = [];
179
+ if (conflicts.length > 0) {
180
+ reasons.push(`"${newName}" conflicts with an existing symbol`);
181
+ }
182
+ if (hasStringLiterals) {
183
+ reasons.push(`${stringLitCount} string-literal reference(s) require manual update`);
184
+ }
185
+ verdict = `Not safe to rename: ${reasons.join('; ')}. ${affectedFileCount} file(s) affected.`;
186
+ }
187
+ else {
188
+ const breakdown = [];
189
+ if (callCount > 0)
190
+ breakdown.push(`${callCount} call site${callCount > 1 ? 's' : ''}`);
191
+ if (importCount > 0)
192
+ breakdown.push(`${importCount} import${importCount > 1 ? 's' : ''}`);
193
+ if (typeRefCount > 0)
194
+ breakdown.push(`${typeRefCount} type reference${typeRefCount > 1 ? 's' : ''}`);
195
+ if (commentCount > 0)
196
+ breakdown.push(`${commentCount} comment${commentCount > 1 ? 's' : ''}`);
197
+ const detail = breakdown.length > 0 ? ` (${breakdown.join(', ')})` : '';
198
+ verdict = `Safe to rename: ${affectedFileCount} file${affectedFileCount !== 1 ? 's' : ''} affected${detail}. No conflicts.`;
199
+ }
200
+ const responseText = JSON.stringify(affectedSites);
201
+ const output = {
202
+ safe,
203
+ verdict,
204
+ symbolName: symbol.name,
205
+ newName,
206
+ conflicts,
207
+ affectedSites,
208
+ affectedFileCount,
209
+ _tokenEstimate: Math.ceil(responseText.length / 4),
210
+ _meta: buildMeta({ timingMs: Date.now() - t0 }),
211
+ };
212
+ return { content: [{ type: 'text', text: JSON.stringify(output, null, 2) }] };
213
+ }
214
+ finally {
215
+ db.close();
216
+ }
217
+ }
218
+ //# sourceMappingURL=check-rename-safe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-rename-safe.js","sourceRoot":"","sources":["../../../src/server/tools/check-rename-safe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
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 type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
30
+ export declare const name = "diff_health_radar";
31
+ export declare const description: string;
32
+ export declare const inputSchema: {
33
+ baseRepoId: z.ZodString;
34
+ headRepoId: z.ZodString;
35
+ scope: z.ZodOptional<z.ZodString>;
36
+ includeStability: z.ZodOptional<z.ZodBoolean>;
37
+ };
38
+ export declare function handler(args: {
39
+ baseRepoId: string;
40
+ headRepoId: string;
41
+ scope?: string;
42
+ includeStability?: boolean;
43
+ }): Promise<CallToolResult>;
44
+ //# sourceMappingURL=diff-health-radar.d.ts.map