mcp-code-context 3.9.1 → 7.0.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 (208) hide show
  1. package/CHANGELOG.md +288 -215
  2. package/INSTRUCTIONS.md +28 -11
  3. package/README.md +124 -11
  4. package/dist/src/core/engine.d.ts +1 -1
  5. package/dist/src/core/engine.js +1 -1
  6. package/dist/src/core/indexManager.d.ts +1 -1
  7. package/dist/src/core/indexManager.js +26 -26
  8. package/dist/src/core/sessionManager.d.ts +1 -1
  9. package/dist/src/core/sessionManager.js +1 -1
  10. package/dist/src/core/validator.d.ts +2 -2
  11. package/dist/src/core/validator.js +8 -2
  12. package/dist/src/core/validator.js.map +1 -1
  13. package/dist/src/index.d.ts +4 -2
  14. package/dist/src/index.js +119 -14
  15. package/dist/src/index.js.map +1 -1
  16. package/dist/src/operations/apiRoutes.d.ts +31 -0
  17. package/dist/src/operations/apiRoutes.js +170 -0
  18. package/dist/src/operations/apiRoutes.js.map +1 -0
  19. package/dist/src/operations/architectureLinter.d.ts +45 -0
  20. package/dist/src/operations/architectureLinter.js +223 -0
  21. package/dist/src/operations/architectureLinter.js.map +1 -0
  22. package/dist/src/operations/astComplexity.d.ts +38 -0
  23. package/dist/src/operations/astComplexity.js +243 -0
  24. package/dist/src/operations/astComplexity.js.map +1 -0
  25. package/dist/src/operations/astMockGenerator.d.ts +34 -0
  26. package/dist/src/operations/astMockGenerator.js +203 -0
  27. package/dist/src/operations/astMockGenerator.js.map +1 -0
  28. package/dist/src/operations/astQuery.d.ts +47 -0
  29. package/dist/src/operations/astQuery.js +169 -0
  30. package/dist/src/operations/astQuery.js.map +1 -0
  31. package/dist/src/operations/astTransform.d.ts +1 -1
  32. package/dist/src/operations/astTransform.js +11 -2
  33. package/dist/src/operations/astTransform.js.map +1 -1
  34. package/dist/src/operations/asyncBlockers.d.ts +33 -0
  35. package/dist/src/operations/asyncBlockers.js +162 -0
  36. package/dist/src/operations/asyncBlockers.js.map +1 -0
  37. package/dist/src/operations/blastRadiusReport.d.ts +43 -0
  38. package/dist/src/operations/blastRadiusReport.js +236 -0
  39. package/dist/src/operations/blastRadiusReport.js.map +1 -0
  40. package/dist/src/operations/callHierarchy.d.ts +28 -0
  41. package/dist/src/operations/callHierarchy.js +166 -0
  42. package/dist/src/operations/callHierarchy.js.map +1 -0
  43. package/dist/src/operations/circularDependencies.d.ts +28 -0
  44. package/dist/src/operations/circularDependencies.js +201 -0
  45. package/dist/src/operations/circularDependencies.js.map +1 -0
  46. package/dist/src/operations/classHierarchyFlattener.d.ts +35 -0
  47. package/dist/src/operations/classHierarchyFlattener.js +185 -0
  48. package/dist/src/operations/classHierarchyFlattener.js.map +1 -0
  49. package/dist/src/operations/compress.d.ts +2 -2
  50. package/dist/src/operations/compress.js +154 -20
  51. package/dist/src/operations/compress.js.map +1 -1
  52. package/dist/src/operations/conceptSearch.d.ts +19 -0
  53. package/dist/src/operations/conceptSearch.js +176 -0
  54. package/dist/src/operations/conceptSearch.js.map +1 -0
  55. package/dist/src/operations/confirmationStore.d.ts +1 -1
  56. package/dist/src/operations/confirmationStore.js +1 -1
  57. package/dist/src/operations/conflictPredictor.d.ts +21 -0
  58. package/dist/src/operations/conflictPredictor.js +139 -0
  59. package/dist/src/operations/conflictPredictor.js.map +1 -0
  60. package/dist/src/operations/contextCompactor.d.ts +38 -0
  61. package/dist/src/operations/contextCompactor.js +348 -0
  62. package/dist/src/operations/contextCompactor.js.map +1 -0
  63. package/dist/src/operations/cstCodemod.d.ts +34 -0
  64. package/dist/src/operations/cstCodemod.js +205 -0
  65. package/dist/src/operations/cstCodemod.js.map +1 -0
  66. package/dist/src/operations/deadSymbols.d.ts +32 -0
  67. package/dist/src/operations/deadSymbols.js +178 -0
  68. package/dist/src/operations/deadSymbols.js.map +1 -0
  69. package/dist/src/operations/envContract.d.ts +35 -0
  70. package/dist/src/operations/envContract.js +194 -0
  71. package/dist/src/operations/envContract.js.map +1 -0
  72. package/dist/src/operations/errorAudit.d.ts +36 -0
  73. package/dist/src/operations/errorAudit.js +201 -0
  74. package/dist/src/operations/errorAudit.js.map +1 -0
  75. package/dist/src/operations/importIntegrity.d.ts +48 -0
  76. package/dist/src/operations/importIntegrity.js +395 -0
  77. package/dist/src/operations/importIntegrity.js.map +1 -0
  78. package/dist/src/operations/incrementalDiff.d.ts +47 -0
  79. package/dist/src/operations/incrementalDiff.js +216 -0
  80. package/dist/src/operations/incrementalDiff.js.map +1 -0
  81. package/dist/src/operations/lexicalScope.d.ts +51 -0
  82. package/dist/src/operations/lexicalScope.js +212 -0
  83. package/dist/src/operations/lexicalScope.js.map +1 -0
  84. package/dist/src/operations/read.d.ts +21 -0
  85. package/dist/src/operations/read.js +21 -0
  86. package/dist/src/operations/read.js.map +1 -1
  87. package/dist/src/operations/readCore.js +37 -17
  88. package/dist/src/operations/readCore.js.map +1 -1
  89. package/dist/src/operations/rename.js +35 -24
  90. package/dist/src/operations/rename.js.map +1 -1
  91. package/dist/src/operations/sqlValidator.d.ts +36 -0
  92. package/dist/src/operations/sqlValidator.js +202 -0
  93. package/dist/src/operations/sqlValidator.js.map +1 -0
  94. package/dist/src/operations/symbolQuery.js +112 -23
  95. package/dist/src/operations/symbolQuery.js.map +1 -1
  96. package/dist/src/operations/taintAnalysis.d.ts +46 -0
  97. package/dist/src/operations/taintAnalysis.js +220 -0
  98. package/dist/src/operations/taintAnalysis.js.map +1 -0
  99. package/dist/src/operations/testImpact.d.ts +31 -0
  100. package/dist/src/operations/testImpact.js +179 -0
  101. package/dist/src/operations/testImpact.js.map +1 -0
  102. package/dist/src/operations/typeInference.d.ts +54 -0
  103. package/dist/src/operations/typeInference.js +565 -0
  104. package/dist/src/operations/typeInference.js.map +1 -0
  105. package/dist/src/operations/wireContract.d.ts +34 -0
  106. package/dist/src/operations/wireContract.js +185 -0
  107. package/dist/src/operations/wireContract.js.map +1 -0
  108. package/dist/src/operations/write.d.ts +2 -2
  109. package/dist/src/operations/write.js +151 -82
  110. package/dist/src/operations/write.js.map +1 -1
  111. package/dist/src/parsers/base.d.ts +9 -1
  112. package/dist/src/parsers/base.js +61 -1
  113. package/dist/src/parsers/base.js.map +1 -1
  114. package/dist/src/parsers/csharp.d.ts +1 -1
  115. package/dist/src/parsers/csharp.js +1 -1
  116. package/dist/src/parsers/dartTreeSitter.d.ts +1 -1
  117. package/dist/src/parsers/dartTreeSitter.js +1 -1
  118. package/dist/src/parsers/go.d.ts +1 -1
  119. package/dist/src/parsers/go.js +1 -1
  120. package/dist/src/parsers/java.d.ts +1 -1
  121. package/dist/src/parsers/java.js +1 -1
  122. package/dist/src/parsers/kotlin.d.ts +1 -1
  123. package/dist/src/parsers/kotlin.js +1 -1
  124. package/dist/src/parsers/php.d.ts +1 -1
  125. package/dist/src/parsers/php.js +1 -1
  126. package/dist/src/parsers/python.d.ts +1 -1
  127. package/dist/src/parsers/python.js +1 -1
  128. package/dist/src/parsers/registry.d.ts +1 -1
  129. package/dist/src/parsers/registry.js +1 -1
  130. package/dist/src/parsers/ruby.d.ts +1 -1
  131. package/dist/src/parsers/ruby.js +1 -1
  132. package/dist/src/parsers/rust.d.ts +1 -1
  133. package/dist/src/parsers/rust.js +1 -1
  134. package/dist/src/parsers/typescript.d.ts +1 -1
  135. package/dist/src/parsers/typescript.js +1 -1
  136. package/dist/src/tools/adminHandlers.js +8 -7
  137. package/dist/src/tools/adminHandlers.js.map +1 -1
  138. package/dist/src/tools/context.d.ts +4 -0
  139. package/dist/src/tools/context.js +14 -0
  140. package/dist/src/tools/context.js.map +1 -1
  141. package/dist/src/tools/pipeline.js +27 -1
  142. package/dist/src/tools/pipeline.js.map +1 -1
  143. package/dist/src/tools/readHandlers.d.ts +150 -0
  144. package/dist/src/tools/readHandlers.js +642 -35
  145. package/dist/src/tools/readHandlers.js.map +1 -1
  146. package/dist/src/tools/toolDefinitions.d.ts +2190 -1
  147. package/dist/src/tools/toolDefinitionsAdmin.d.ts +1 -1
  148. package/dist/src/tools/toolDefinitionsAdmin.js +12 -12
  149. package/dist/src/tools/toolDefinitionsAdmin.js.map +1 -1
  150. package/dist/src/tools/toolDefinitionsCore.d.ts +2189 -0
  151. package/dist/src/tools/toolDefinitionsCore.js +422 -42
  152. package/dist/src/tools/toolDefinitionsCore.js.map +1 -1
  153. package/dist/src/tools/writeHandlers.js +31 -17
  154. package/dist/src/tools/writeHandlers.js.map +1 -1
  155. package/dist/src/utils/appDir.d.ts +1 -1
  156. package/dist/src/utils/appDir.js +1 -1
  157. package/dist/src/utils/auditLogger.d.ts +1 -1
  158. package/dist/src/utils/auditLogger.js +1 -1
  159. package/dist/src/utils/backupManager.d.ts +1 -1
  160. package/dist/src/utils/backupManager.js +1 -1
  161. package/dist/src/utils/conceptEngine.d.ts +56 -0
  162. package/dist/src/utils/conceptEngine.js +234 -0
  163. package/dist/src/utils/conceptEngine.js.map +1 -0
  164. package/dist/src/utils/constants.d.ts +1 -1
  165. package/dist/src/utils/constants.js +2 -1
  166. package/dist/src/utils/constants.js.map +1 -1
  167. package/dist/src/utils/diff.d.ts +1 -1
  168. package/dist/src/utils/diff.js +1 -1
  169. package/dist/src/utils/fileLock.d.ts +1 -1
  170. package/dist/src/utils/fileLock.js +1 -1
  171. package/dist/src/utils/fileWalker.d.ts +1 -1
  172. package/dist/src/utils/fileWalker.js +1 -1
  173. package/dist/src/utils/fileWatcher.d.ts +1 -1
  174. package/dist/src/utils/fileWatcher.js +1 -1
  175. package/dist/src/utils/fuzzySearch.d.ts +1 -1
  176. package/dist/src/utils/fuzzySearch.js +1 -1
  177. package/dist/src/utils/gemfileParser.d.ts +1 -1
  178. package/dist/src/utils/gemfileParser.js +1 -1
  179. package/dist/src/utils/logger.d.ts +1 -1
  180. package/dist/src/utils/logger.js +1 -1
  181. package/dist/src/utils/metaprogramming.d.ts +1 -1
  182. package/dist/src/utils/metaprogramming.js +1 -1
  183. package/dist/src/utils/projectRoot.d.ts +9 -0
  184. package/dist/src/utils/projectRoot.js +94 -0
  185. package/dist/src/utils/projectRoot.js.map +1 -0
  186. package/dist/src/utils/railsRoutes.d.ts +1 -1
  187. package/dist/src/utils/railsRoutes.js +1 -1
  188. package/dist/src/utils/rateLimiter.d.ts +26 -1
  189. package/dist/src/utils/rateLimiter.js +26 -1
  190. package/dist/src/utils/rateLimiter.js.map +1 -1
  191. package/dist/src/utils/streaming.d.ts +1 -1
  192. package/dist/src/utils/streaming.js +1 -1
  193. package/dist/src/utils/telemetry.d.ts +1 -1
  194. package/dist/src/utils/telemetry.js +1 -1
  195. package/dist/src/utils/virtualSchema.d.ts +31 -0
  196. package/dist/src/utils/virtualSchema.js +367 -0
  197. package/dist/src/utils/virtualSchema.js.map +1 -0
  198. package/llms.txt +24 -6
  199. package/package.json +4 -2
  200. package/skills/code-context-logo.png +0 -0
  201. package/skills/code-context-pro/SKILL.md +149 -0
  202. package/skills/code-context-pro/references/benchmarks.md +25 -0
  203. package/skills/code-context-pro/references/decision-tree.md +32 -0
  204. package/skills/code-context-pro/references/multi-ide-setup.md +104 -0
  205. package/skills/code-context-pro.zip +0 -0
  206. package/HIRE_ME.md +0 -234
  207. package/SPONSORS.md +0 -104
  208. package/vitest.config.ts +0 -37
@@ -2,22 +2,28 @@
2
2
  import * as path from "node:path";
3
3
  import * as fs from "node:fs/promises";
4
4
  import { SecurityValidator } from "../core/validator.js";
5
- import { extractSymbol, readLines, searchPattern, analyzeImpact, searchSymbols, explainSymbol, batchRead } from "../operations/read.js";
5
+ import { extractSymbol, readLines, searchPattern, analyzeImpact, searchSymbols, searchCodeConcept, verifyImportIntegrity, traceTaintFlow, backfillTypes, enforceArchitectureRules, compactContextLedger, generateAstImpactReport, queryCodeAst, incrementalAstDiff, getAstComplexityMatrix, generateAstMocks, detectDeadAstSymbols, resolveLexicalScope, validateSqlAst, astCodemodTranspile, detectAsyncEventloopBlockers, verifyEnvContractDrift, auditErrorHandlingContracts, extractApiRouteMatrix, flattenClassHierarchy, detectCircularDependencies, explainSymbol, batchRead } from "../operations/read.js";
6
6
  import { compressRepository } from "../operations/compress.js";
7
7
  import { streamFile } from "../utils/streaming.js";
8
8
  import { assertNoPendingWriteConflict } from "../utils/toctou.js";
9
9
  import { getSession, getCacheManager, getRegistry } from "./context.js";
10
- import { loadRailsSchema, modelToTable, formatSchemaAnnotation } from "../utils/railsSchema.js";
10
+ import { modelToTable } from "../utils/railsSchema.js";
11
+ import { loadUnifiedVirtualSchema, formatUnifiedSchemaAnnotation } from "../utils/virtualSchema.js";
11
12
  import { parseGemfile, formatGemAnnotation } from "../utils/gemfileParser.js";
12
13
  import { findMetaprogrammingEntryPoints, formatMetaprogrammingResults } from "../utils/metaprogramming.js";
13
14
  import { parseRailsRoutes } from "../utils/railsRoutes.js";
15
+ import { resolveProjectRoot } from "../utils/projectRoot.js";
16
+ import { getImpactedTests } from "../operations/testImpact.js";
17
+ import { getCallHierarchy } from "../operations/callHierarchy.js";
18
+ import { validateWireContract } from "../operations/wireContract.js";
19
+ import { predictSemanticConflicts } from "../operations/conflictPredictor.js";
14
20
  export async function handleGetSemanticRepoMap(args) {
15
- if (!args.directoryPath || !args.projectRoot) {
16
- throw new Error("directoryPath and projectRoot are required (e.g. projectRoot: C:\\code\\mcp-code-context)");
21
+ if (!args.directoryPath) {
22
+ throw new Error("directoryPath is required (e.g. C:\\code\\mcp-code-context)");
17
23
  }
18
24
  const directoryPath = String(args.directoryPath);
19
- const projectRoot = String(args.projectRoot);
20
- const format = args.format === "markdown" ? "markdown" : "xml";
25
+ const projectRoot = resolveProjectRoot(args, directoryPath);
26
+ const format = args.format === "markdown" ? "markdown" : args.format === "html" ? "html" : "xml";
21
27
  const validator = new SecurityValidator(projectRoot);
22
28
  const validation = await validator.validateFilePath(directoryPath);
23
29
  if (!validation.valid) {
@@ -37,7 +43,7 @@ export async function handleGetSemanticRepoMap(args) {
37
43
  }
38
44
  export async function handleReadFileSurgical(args) {
39
45
  const filePath = String(args.filePath);
40
- const projectRoot = String(args.projectRoot);
46
+ const projectRoot = resolveProjectRoot(args, filePath);
41
47
  const symbolName = args.symbolName ? String(args.symbolName) : undefined;
42
48
  const className = args.className ? String(args.className) : undefined;
43
49
  const validator = new SecurityValidator(projectRoot);
@@ -76,37 +82,81 @@ export async function handleReadFileSurgical(args) {
76
82
  content = await fs.readFile(validation.resolvedPath, "utf-8");
77
83
  }
78
84
  }
79
- // ActiveRecord Virtual Schema injection
80
- if (path.extname(filePath) === ".rb") {
81
- // When extracting a symbol, `content` is only the method body — no class declaration.
82
- // We need the full file to detect AR inheritance, but guard with stat first to
83
- // avoid allocating >5MB files without the streaming guard.
85
+ // Unified Virtual ORM Schema injection (ActiveRecord, Eloquent, Django, Prisma, Drizzle)
86
+ const fileExt = path.extname(filePath);
87
+ if (fileExt === ".rb" || fileExt === ".php" || fileExt === ".py" || fileExt === ".ts" || fileExt === ".tsx" || fileExt === ".js" || fileExt === ".prisma") {
84
88
  let sourceForDetection = content;
85
89
  if (symbolName) {
86
90
  const fileStat = await fs.stat(validation.resolvedPath);
87
91
  if (fileStat.size <= 5 * 1024 * 1024) {
88
92
  sourceForDetection = await fs.readFile(validation.resolvedPath, "utf-8");
89
93
  }
90
- // Files >5MB: skip schema injection for symbol extracts — not worth the memory cost
91
94
  }
92
- const arMatch = sourceForDetection.match(/class\s+(\w+)\s*<\s*(?:ApplicationRecord|ActiveRecord::Base)/);
93
- if (arMatch) {
94
- const schema = await loadRailsSchema(projectRoot);
95
- if (schema) {
96
- const tableName = modelToTable(arMatch[1]);
97
- const columns = schema[tableName];
95
+ let modelName = null;
96
+ if (fileExt === ".rb") {
97
+ const m = sourceForDetection.match(/class\s+(\w+)\s*<\s*(?:ApplicationRecord|ActiveRecord::Base)/);
98
+ if (m) {
99
+ modelName = m[1];
100
+ }
101
+ }
102
+ else if (fileExt === ".php") {
103
+ const m = sourceForDetection.match(/class\s+(\w+)\s+extends\s+(?:Model|Authenticatable)/);
104
+ if (m) {
105
+ modelName = m[1];
106
+ }
107
+ }
108
+ else if (fileExt === ".py") {
109
+ const m = sourceForDetection.match(/class\s+(\w+)\s*\([^)]*models\.Model[^)]*\):/);
110
+ if (m) {
111
+ modelName = m[1];
112
+ }
113
+ }
114
+ else if (fileExt === ".prisma") {
115
+ const m = sourceForDetection.match(/model\s+(\w+)\s*\{/);
116
+ if (m) {
117
+ modelName = m[1];
118
+ }
119
+ }
120
+ else if (fileExt === ".ts" || fileExt === ".tsx" || fileExt === ".js") {
121
+ const drizzleM = sourceForDetection.match(/(?:export\s+const\s+(\w+)\s*=\s*)?(?:pgTable|mysqlTable|sqliteTable)\s*\(\s*["']([^"']+)["']/);
122
+ const prismaM = sourceForDetection.match(/(?:interface|type|class)\s+(\w+)\b/);
123
+ if (drizzleM) {
124
+ modelName = drizzleM[2] || drizzleM[1];
125
+ }
126
+ else if (prismaM) {
127
+ modelName = prismaM[1];
128
+ }
129
+ }
130
+ if (modelName) {
131
+ const unified = await loadUnifiedVirtualSchema(projectRoot, fileExt).catch(() => null);
132
+ if (unified && unified.schema) {
133
+ const tableName = modelToTable(modelName);
134
+ const columns = unified.schema[tableName] || unified.schema[modelName.toLowerCase()] || unified.schema[modelName];
98
135
  if (columns && Object.keys(columns).length > 0) {
99
- content = formatSchemaAnnotation(tableName, columns) + "\n" + content;
136
+ content = formatUnifiedSchemaAnnotation(unified.framework, tableName, columns) + "\n" + content;
100
137
  }
101
138
  }
102
139
  }
103
140
  }
104
- return { content: [{ type: "text", text: content }] };
141
+ // Vector 5: Token Budget Efficiency Header
142
+ let efficiencyHeader = "";
143
+ try {
144
+ const stat = await fs.stat(validation.resolvedPath);
145
+ const rawTokens = Math.max(1, Math.ceil(stat.size / 4));
146
+ const deliveredTokens = Math.max(1, Math.ceil(content.length / 4));
147
+ const saved = Math.max(0, rawTokens - deliveredTokens);
148
+ const ratio = ((saved / rawTokens) * 100).toFixed(1);
149
+ efficiencyHeader = `<!-- [CodeContext Efficiency]: Raw: ~${rawTokens} tokens | Delivered: ~${deliveredTokens} tokens | Saved: ~${saved} tokens (${ratio}% compression) -->\n\n`;
150
+ }
151
+ catch {
152
+ // Non-blocking header computation
153
+ }
154
+ return { content: [{ type: "text", text: efficiencyHeader + content }] };
105
155
  }
106
156
  export async function handleAnalyzeImpact(args) {
107
157
  const filePath = String(args.filePath);
108
- const projectRoot = String(args.projectRoot);
109
- const rootDir = args.rootDir ? String(args.rootDir) : projectRoot;
158
+ const projectRoot = resolveProjectRoot(args, filePath);
159
+ const rootDir = (args.rootDir && args.rootDir !== "undefined") ? String(args.rootDir) : projectRoot;
110
160
  const validator = new SecurityValidator(projectRoot);
111
161
  const validation = await validator.validateFilePath(filePath);
112
162
  if (!validation.valid)
@@ -121,7 +171,7 @@ export async function handleAnalyzeImpact(args) {
121
171
  }
122
172
  export async function handleReadFileLines(args) {
123
173
  const filePath = String(args.filePath);
124
- const projectRoot = String(args.projectRoot);
174
+ const projectRoot = resolveProjectRoot(args, filePath);
125
175
  const validator = new SecurityValidator(projectRoot);
126
176
  const validation = await validator.validateFilePath(filePath);
127
177
  if (!validation.valid)
@@ -140,7 +190,7 @@ export async function handleReadFileLines(args) {
140
190
  }
141
191
  export async function handleSearchCodePattern(args) {
142
192
  const rootDir = String(args.rootDir);
143
- const projectRoot = String(args.projectRoot);
193
+ const projectRoot = resolveProjectRoot(args, rootDir);
144
194
  const validator = new SecurityValidator(projectRoot);
145
195
  const validation = await validator.validateFilePath(rootDir);
146
196
  if (!validation.valid)
@@ -161,7 +211,7 @@ export async function handleSearchCodePattern(args) {
161
211
  }
162
212
  export async function handleParseFile(args) {
163
213
  const filePath = String(args.filePath);
164
- const projectRoot = String(args.projectRoot);
214
+ const projectRoot = resolveProjectRoot(args, filePath);
165
215
  const validator = new SecurityValidator(projectRoot);
166
216
  const validation = await validator.validateFilePath(filePath);
167
217
  if (!validation.valid)
@@ -181,7 +231,7 @@ export async function handleParseFile(args) {
181
231
  // NEW-02: search_symbols
182
232
  export async function handleSearchSymbols(args) {
183
233
  const rootDir = String(args.rootDir);
184
- const projectRoot = String(args.projectRoot);
234
+ const projectRoot = resolveProjectRoot(args, rootDir);
185
235
  const validator = new SecurityValidator(projectRoot);
186
236
  const validation = await validator.validateFilePath(rootDir);
187
237
  if (!validation.valid)
@@ -200,11 +250,486 @@ export async function handleSearchSymbols(args) {
200
250
  throw new Error(result.error);
201
251
  return { content: [{ type: "text", text: result.content }] };
202
252
  }
253
+ // NEW-02b: search_code_concept (v5.0.0)
254
+ export async function handleSearchCodeConcept(args) {
255
+ const rootDir = (args.rootDir && args.rootDir !== "undefined") ? String(args.rootDir) : undefined;
256
+ const projectRoot = resolveProjectRoot(args, rootDir);
257
+ const targetDir = rootDir || projectRoot;
258
+ const validator = new SecurityValidator(projectRoot);
259
+ const validation = await validator.validateFilePath(targetDir);
260
+ if (!validation.valid)
261
+ throw new Error(validation.error);
262
+ const registry = getRegistry();
263
+ const result = await searchCodeConcept({
264
+ rootDir: validation.resolvedPath,
265
+ projectRoot,
266
+ query: String(args.query || ""),
267
+ threshold: args.threshold !== undefined ? Number(args.threshold) : undefined,
268
+ maxResults: args.maxResults !== undefined ? Number(args.maxResults) : undefined,
269
+ fileExtensions: args.fileExtensions,
270
+ excludeDirs: args.excludeDirs,
271
+ registry,
272
+ });
273
+ if (!result.success)
274
+ throw new Error(result.error);
275
+ return { content: [{ type: "text", text: result.content }] };
276
+ }
277
+ // NEW-02c: verify_import_integrity (v5.0.0)
278
+ export async function handleVerifyImportIntegrity(args) {
279
+ if (!args.filePath)
280
+ throw new Error("filePath is required for verify_import_integrity");
281
+ const filePath = String(args.filePath);
282
+ const projectRoot = resolveProjectRoot(args, filePath);
283
+ const validator = new SecurityValidator(projectRoot);
284
+ const validation = await validator.validateFilePath(filePath);
285
+ if (!validation.valid)
286
+ throw new Error(validation.error);
287
+ const registry = getRegistry();
288
+ const result = await verifyImportIntegrity({
289
+ filePath: validation.resolvedPath,
290
+ projectRoot,
291
+ content: args.content ? String(args.content) : undefined,
292
+ registry,
293
+ });
294
+ if (!result.success)
295
+ throw new Error(result.error);
296
+ return { content: [{ type: "text", text: result.content }] };
297
+ }
298
+ // NEW-02d: trace_taint_flow (v5.1.0)
299
+ export async function handleTraceTaintFlow(args) {
300
+ if (!args.filePath)
301
+ throw new Error("filePath is required for trace_taint_flow");
302
+ const filePath = String(args.filePath);
303
+ const projectRoot = resolveProjectRoot(args, filePath);
304
+ const validator = new SecurityValidator(projectRoot);
305
+ const validation = await validator.validateFilePath(filePath);
306
+ if (!validation.valid && !args.content)
307
+ throw new Error(validation.error);
308
+ const resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
309
+ const registry = getRegistry();
310
+ const result = await traceTaintFlow({
311
+ filePath: resolvedTarget,
312
+ projectRoot,
313
+ sourceParam: args.sourceParam ? String(args.sourceParam) : undefined,
314
+ dangerousSink: args.dangerousSink ? String(args.dangerousSink) : undefined,
315
+ content: args.content ? String(args.content) : undefined,
316
+ registry,
317
+ });
318
+ if (!result.success)
319
+ throw new Error(result.error);
320
+ return { content: [{ type: "text", text: result.content }] };
321
+ }
322
+ // NEW-02e: backfill_types (v4.5.0)
323
+ export async function handleBackfillTypes(args) {
324
+ if (!args.filePath)
325
+ throw new Error("filePath is required for backfill_types");
326
+ const filePath = String(args.filePath);
327
+ const projectRoot = resolveProjectRoot(args, filePath);
328
+ const validator = new SecurityValidator(projectRoot);
329
+ const validation = await validator.validateFilePath(filePath);
330
+ if (!validation.valid && !args.content)
331
+ throw new Error(validation.error);
332
+ const resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
333
+ const registry = getRegistry();
334
+ const result = await backfillTypes({
335
+ filePath: resolvedTarget,
336
+ projectRoot,
337
+ symbolName: args.symbolName ? String(args.symbolName) : undefined,
338
+ targetLanguage: args.targetLanguage,
339
+ content: args.content ? String(args.content) : undefined,
340
+ registry,
341
+ });
342
+ if (!result.success)
343
+ throw new Error(result.error);
344
+ return { content: [{ type: "text", text: result.content }] };
345
+ }
346
+ // NEW-02f: enforce_architecture_rules (v4.6.0)
347
+ export async function handleEnforceArchitectureRules(args) {
348
+ const filePath = args.filePath ? String(args.filePath) : undefined;
349
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
350
+ let resolvedTarget = filePath;
351
+ if (filePath) {
352
+ const validator = new SecurityValidator(projectRoot);
353
+ const validation = await validator.validateFilePath(filePath);
354
+ if (!validation.valid && !args.content)
355
+ throw new Error(validation.error);
356
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
357
+ }
358
+ const result = await enforceArchitectureRules({
359
+ filePath: resolvedTarget,
360
+ projectRoot,
361
+ rules: args.rules,
362
+ content: args.content ? String(args.content) : undefined,
363
+ });
364
+ if (!result.success)
365
+ throw new Error(result.error);
366
+ return { content: [{ type: "text", text: result.content }] };
367
+ }
368
+ // NEW-02g: compact_context_ledger (v4.7.0)
369
+ export async function handleCompactContextLedger(args) {
370
+ if (!args.filePaths)
371
+ throw new Error("filePaths is required for compact_context_ledger");
372
+ const projectRoot = resolveProjectRoot(args, ".");
373
+ const registry = getRegistry();
374
+ const result = await compactContextLedger({
375
+ filePaths: args.filePaths,
376
+ projectRoot,
377
+ dropPrivate: args.dropPrivate,
378
+ includeDocstrings: args.includeDocstrings,
379
+ content: args.content ? String(args.content) : undefined,
380
+ registry,
381
+ });
382
+ if (!result.success)
383
+ throw new Error(result.error);
384
+ return { content: [{ type: "text", text: result.content }] };
385
+ }
386
+ // NEW-02h: generate_ast_impact_report (v5.0.0)
387
+ export async function handleGenerateAstImpactReport(args) {
388
+ const projectRoot = resolveProjectRoot(args, ".");
389
+ const result = await generateAstImpactReport({
390
+ baseBranch: args.baseBranch ? String(args.baseBranch) : undefined,
391
+ targetBranch: args.targetBranch ? String(args.targetBranch) : undefined,
392
+ projectRoot,
393
+ includeTests: args.includeTests !== undefined ? Boolean(args.includeTests) : true,
394
+ includeArchitecture: args.includeArchitecture !== undefined ? Boolean(args.includeArchitecture) : true,
395
+ });
396
+ if (!result.success)
397
+ throw new Error(result.error);
398
+ return { content: [{ type: "text", text: result.content }] };
399
+ }
400
+ // NEW-02i: query_code_ast (v5.1.0)
401
+ export async function handleQueryCodeAst(args) {
402
+ const filePath = args.filePath ? String(args.filePath) : undefined;
403
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
404
+ let resolvedTarget = filePath;
405
+ if (filePath) {
406
+ const validator = new SecurityValidator(projectRoot);
407
+ const validation = await validator.validateFilePath(filePath);
408
+ if (!validation.valid && !args.code)
409
+ throw new Error(validation.error);
410
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
411
+ }
412
+ const registry = getRegistry();
413
+ const result = await queryCodeAst({
414
+ filePath: resolvedTarget,
415
+ projectRoot,
416
+ query: args.query ? String(args.query) : undefined,
417
+ template: args.template,
418
+ code: args.code ? String(args.code) : undefined,
419
+ limit: args.limit ? Number(args.limit) : undefined,
420
+ registry,
421
+ });
422
+ if (!result.success)
423
+ throw new Error(result.error);
424
+ return { content: [{ type: "text", text: result.content }] };
425
+ }
426
+ // NEW-02j: incremental_ast_diff (v5.1.0)
427
+ export async function handleIncrementalAstDiff(args) {
428
+ const filePath = args.filePath ? String(args.filePath) : undefined;
429
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
430
+ let resolvedTarget = filePath;
431
+ if (filePath) {
432
+ const validator = new SecurityValidator(projectRoot);
433
+ const validation = await validator.validateFilePath(filePath);
434
+ if (!validation.valid && !args.oldCode)
435
+ throw new Error(validation.error);
436
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
437
+ }
438
+ const registry = getRegistry();
439
+ const result = await incrementalAstDiff({
440
+ filePath: resolvedTarget,
441
+ projectRoot,
442
+ oldCode: args.oldCode ? String(args.oldCode) : undefined,
443
+ newCode: args.newCode ? String(args.newCode) : undefined,
444
+ registry,
445
+ });
446
+ if (!result.success)
447
+ throw new Error(result.error);
448
+ return { content: [{ type: "text", text: result.content }] };
449
+ }
450
+ // NEW-02k: get_ast_complexity_matrix (v5.6.0)
451
+ export async function handleGetAstComplexityMatrix(args) {
452
+ const filePath = args.filePath ? String(args.filePath) : undefined;
453
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
454
+ let resolvedTarget = filePath;
455
+ if (filePath) {
456
+ const validator = new SecurityValidator(projectRoot);
457
+ const validation = await validator.validateFilePath(filePath);
458
+ if (!validation.valid && !args.code)
459
+ throw new Error(validation.error);
460
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
461
+ }
462
+ const registry = getRegistry();
463
+ const result = await getAstComplexityMatrix({
464
+ filePath: resolvedTarget,
465
+ projectRoot,
466
+ code: args.code ? String(args.code) : undefined,
467
+ threshold: args.threshold ? Number(args.threshold) : undefined,
468
+ registry,
469
+ });
470
+ if (!result.success)
471
+ throw new Error(result.error);
472
+ return { content: [{ type: "text", text: result.content }] };
473
+ }
474
+ // NEW-02l: generate_ast_mocks (v5.6.0)
475
+ export async function handleGenerateAstMocks(args) {
476
+ if (!args.symbolName)
477
+ throw new Error("symbolName is required for generate_ast_mocks");
478
+ const filePath = args.filePath ? String(args.filePath) : undefined;
479
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
480
+ let resolvedTarget = filePath;
481
+ if (filePath) {
482
+ const validator = new SecurityValidator(projectRoot);
483
+ const validation = await validator.validateFilePath(filePath);
484
+ if (!validation.valid && !args.code)
485
+ throw new Error(validation.error);
486
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
487
+ }
488
+ const registry = getRegistry();
489
+ const result = await generateAstMocks({
490
+ filePath: resolvedTarget,
491
+ projectRoot,
492
+ symbolName: String(args.symbolName),
493
+ format: args.format,
494
+ code: args.code ? String(args.code) : undefined,
495
+ registry,
496
+ });
497
+ if (!result.success)
498
+ throw new Error(result.error);
499
+ return { content: [{ type: "text", text: result.content }] };
500
+ }
501
+ // NEW-02m: detect_dead_ast_symbols (v5.7.0)
502
+ export async function handleDetectDeadAstSymbols(args) {
503
+ const filePath = args.filePath ? String(args.filePath) : undefined;
504
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
505
+ let resolvedTarget = filePath;
506
+ if (filePath) {
507
+ const validator = new SecurityValidator(projectRoot);
508
+ const validation = await validator.validateFilePath(filePath);
509
+ if (!validation.valid && !args.code)
510
+ throw new Error(validation.error);
511
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
512
+ }
513
+ const registry = getRegistry();
514
+ const result = await detectDeadAstSymbols({
515
+ filePath: resolvedTarget,
516
+ projectRoot,
517
+ code: args.code ? String(args.code) : undefined,
518
+ registry,
519
+ });
520
+ if (!result.success)
521
+ throw new Error(result.error);
522
+ return { content: [{ type: "text", text: result.content }] };
523
+ }
524
+ // NEW-02n: resolve_lexical_scope (v5.7.0)
525
+ export async function handleResolveLexicalScope(args) {
526
+ const filePath = args.filePath ? String(args.filePath) : undefined;
527
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
528
+ let resolvedTarget = filePath;
529
+ if (filePath) {
530
+ const validator = new SecurityValidator(projectRoot);
531
+ const validation = await validator.validateFilePath(filePath);
532
+ if (!validation.valid && !args.code)
533
+ throw new Error(validation.error);
534
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
535
+ }
536
+ const registry = getRegistry();
537
+ const result = await resolveLexicalScope({
538
+ filePath: resolvedTarget,
539
+ projectRoot,
540
+ code: args.code ? String(args.code) : undefined,
541
+ proposedRename: args.proposedRename,
542
+ registry,
543
+ });
544
+ if (!result.success)
545
+ throw new Error(result.error);
546
+ return { content: [{ type: "text", text: result.content }] };
547
+ }
548
+ // NEW-02o: sql_ast_validator (v6.0.0)
549
+ export async function handleValidateSqlAst(args) {
550
+ const filePath = args.filePath ? String(args.filePath) : undefined;
551
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
552
+ let resolvedTarget = filePath;
553
+ if (filePath) {
554
+ const validator = new SecurityValidator(projectRoot);
555
+ const validation = await validator.validateFilePath(filePath);
556
+ if (!validation.valid && !args.code)
557
+ throw new Error(validation.error);
558
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
559
+ }
560
+ const registry = getRegistry();
561
+ const result = await validateSqlAst({
562
+ filePath: resolvedTarget,
563
+ projectRoot,
564
+ code: args.code ? String(args.code) : undefined,
565
+ registry,
566
+ });
567
+ if (!result.success)
568
+ throw new Error(result.error);
569
+ return { content: [{ type: "text", text: result.content }] };
570
+ }
571
+ // NEW-02p: ast_codemod_transpile (v6.0.0)
572
+ export async function handleAstCodemodTranspile(args) {
573
+ if (!args.rule)
574
+ throw new Error("rule is required for ast_codemod_transpile (e.g. 'cjs-to-esm', 'strip-console')");
575
+ const filePath = args.filePath ? String(args.filePath) : undefined;
576
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
577
+ let resolvedTarget = filePath;
578
+ if (filePath) {
579
+ const validator = new SecurityValidator(projectRoot);
580
+ const validation = await validator.validateFilePath(filePath);
581
+ if (!validation.valid && !args.code)
582
+ throw new Error(validation.error);
583
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
584
+ }
585
+ const registry = getRegistry();
586
+ const result = await astCodemodTranspile({
587
+ filePath: resolvedTarget,
588
+ projectRoot,
589
+ rule: args.rule,
590
+ code: args.code ? String(args.code) : undefined,
591
+ registry,
592
+ });
593
+ if (!result.success)
594
+ throw new Error(result.error);
595
+ return { content: [{ type: "text", text: result.content }] };
596
+ }
597
+ // NEW-02q: detect_async_eventloop_blockers (v7.0.0)
598
+ export async function handleDetectAsyncEventloopBlockers(args) {
599
+ const filePath = args.filePath ? String(args.filePath) : undefined;
600
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
601
+ let resolvedTarget = filePath;
602
+ if (filePath) {
603
+ const validator = new SecurityValidator(projectRoot);
604
+ const validation = await validator.validateFilePath(filePath);
605
+ if (!validation.valid && !args.code)
606
+ throw new Error(validation.error);
607
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
608
+ }
609
+ const registry = getRegistry();
610
+ const result = await detectAsyncEventloopBlockers({
611
+ filePath: resolvedTarget,
612
+ projectRoot,
613
+ code: args.code ? String(args.code) : undefined,
614
+ registry,
615
+ });
616
+ if (!result.success)
617
+ throw new Error(result.error);
618
+ return { content: [{ type: "text", text: result.content }] };
619
+ }
620
+ // NEW-02r: verify_env_contract_drift (v7.0.0)
621
+ export async function handleVerifyEnvContractDrift(args) {
622
+ const filePath = args.filePath ? String(args.filePath) : undefined;
623
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
624
+ let resolvedTarget = filePath;
625
+ if (filePath) {
626
+ const validator = new SecurityValidator(projectRoot);
627
+ const validation = await validator.validateFilePath(filePath);
628
+ if (!validation.valid && !args.code)
629
+ throw new Error(validation.error);
630
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
631
+ }
632
+ const registry = getRegistry();
633
+ const result = await verifyEnvContractDrift({
634
+ filePath: resolvedTarget,
635
+ projectRoot,
636
+ code: args.code ? String(args.code) : undefined,
637
+ envExampleContent: args.envExampleContent ? String(args.envExampleContent) : undefined,
638
+ registry,
639
+ });
640
+ if (!result.success)
641
+ throw new Error(result.error);
642
+ return { content: [{ type: "text", text: result.content }] };
643
+ }
644
+ // NEW-02s: audit_error_handling_contracts (v7.0.0)
645
+ export async function handleAuditErrorHandlingContracts(args) {
646
+ const filePath = args.filePath ? String(args.filePath) : undefined;
647
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
648
+ let resolvedTarget = filePath;
649
+ if (filePath) {
650
+ const validator = new SecurityValidator(projectRoot);
651
+ const validation = await validator.validateFilePath(filePath);
652
+ if (!validation.valid && !args.code)
653
+ throw new Error(validation.error);
654
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
655
+ }
656
+ const registry = getRegistry();
657
+ const result = await auditErrorHandlingContracts({
658
+ filePath: resolvedTarget,
659
+ projectRoot,
660
+ code: args.code ? String(args.code) : undefined,
661
+ registry,
662
+ });
663
+ if (!result.success)
664
+ throw new Error(result.error);
665
+ return { content: [{ type: "text", text: result.content }] };
666
+ }
667
+ // NEW-02t: extract_api_route_matrix (v7.0.0)
668
+ export async function handleExtractApiRouteMatrix(args) {
669
+ const filePath = args.filePath ? String(args.filePath) : undefined;
670
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
671
+ let resolvedTarget = filePath;
672
+ if (filePath) {
673
+ const validator = new SecurityValidator(projectRoot);
674
+ const validation = await validator.validateFilePath(filePath);
675
+ if (!validation.valid && !args.code)
676
+ throw new Error(validation.error);
677
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
678
+ }
679
+ const registry = getRegistry();
680
+ const result = await extractApiRouteMatrix({
681
+ filePath: resolvedTarget,
682
+ projectRoot,
683
+ code: args.code ? String(args.code) : undefined,
684
+ registry,
685
+ });
686
+ if (!result.success)
687
+ throw new Error(result.error);
688
+ return { content: [{ type: "text", text: result.content }] };
689
+ }
690
+ // NEW-02u: flatten_class_hierarchy (v7.0.0)
691
+ export async function handleFlattenClassHierarchy(args) {
692
+ const filePath = args.filePath ? String(args.filePath) : undefined;
693
+ const projectRoot = resolveProjectRoot(args, filePath || ".");
694
+ let resolvedTarget = filePath;
695
+ if (filePath) {
696
+ const validator = new SecurityValidator(projectRoot);
697
+ const validation = await validator.validateFilePath(filePath);
698
+ if (!validation.valid && !args.code)
699
+ throw new Error(validation.error);
700
+ resolvedTarget = validation.resolvedPath || path.resolve(projectRoot, filePath);
701
+ }
702
+ const registry = getRegistry();
703
+ const result = await flattenClassHierarchy({
704
+ filePath: resolvedTarget,
705
+ projectRoot,
706
+ className: args.className ? String(args.className) : undefined,
707
+ code: args.code ? String(args.code) : undefined,
708
+ registry,
709
+ });
710
+ if (!result.success)
711
+ throw new Error(result.error);
712
+ return { content: [{ type: "text", text: result.content }] };
713
+ }
714
+ // NEW-02v: detect_circular_dependencies (v7.0.0)
715
+ export async function handleDetectCircularDependencies(args) {
716
+ const projectRoot = resolveProjectRoot(args, ".");
717
+ const registry = getRegistry();
718
+ const result = await detectCircularDependencies({
719
+ projectRoot,
720
+ filesMap: args.filesMap,
721
+ filePaths: args.filePaths,
722
+ registry,
723
+ });
724
+ if (!result.success)
725
+ throw new Error(result.error);
726
+ return { content: [{ type: "text", text: result.content }] };
727
+ }
203
728
  // NEW-03: explain_symbol
204
729
  export async function handleExplainSymbol(args) {
205
730
  const filePath = String(args.filePath);
206
- const projectRoot = String(args.projectRoot);
207
- const rootDir = args.rootDir ? String(args.rootDir) : projectRoot;
731
+ const projectRoot = resolveProjectRoot(args, filePath);
732
+ const rootDir = (args.rootDir && args.rootDir !== "undefined") ? String(args.rootDir) : projectRoot;
208
733
  const validator = new SecurityValidator(projectRoot);
209
734
  const validation = await validator.validateFilePath(filePath);
210
735
  if (!validation.valid)
@@ -227,7 +752,7 @@ export async function handleExplainSymbol(args) {
227
752
  }
228
753
  // NEW-05: batch_read
229
754
  export async function handleBatchRead(args) {
230
- const projectRoot = String(args.projectRoot);
755
+ const projectRoot = resolveProjectRoot(args);
231
756
  const reads = args.reads;
232
757
  const validator = new SecurityValidator(projectRoot);
233
758
  // Validate all paths upfront
@@ -248,7 +773,7 @@ export async function handleBatchRead(args) {
248
773
  }
249
774
  // R7: get_gemfile_context — parse Gemfile and return known gem behaviors
250
775
  export async function handleGetGemfileContext(args) {
251
- const projectRoot = String(args.projectRoot);
776
+ const projectRoot = resolveProjectRoot(args);
252
777
  const validator = new SecurityValidator(projectRoot);
253
778
  const rootValidation = await validator.validateFilePath(projectRoot);
254
779
  if (!rootValidation.valid)
@@ -268,11 +793,12 @@ export async function handleGetGemfileContext(args) {
268
793
  }
269
794
  // R3: find_metaprogramming — scan for dynamic method generation entry points
270
795
  export async function handleFindMetaprogramming(args) {
271
- const projectRoot = String(args.projectRoot);
272
- const target = args.filePath ? String(args.filePath) : args.rootDir ? String(args.rootDir) : projectRoot;
796
+ const target = args.filePath ? String(args.filePath) : args.rootDir ? String(args.rootDir) : undefined;
797
+ const projectRoot = resolveProjectRoot(args, target);
798
+ const resolvedTarget = target ?? projectRoot;
273
799
  const isFile = Boolean(args.filePath);
274
800
  const validator = new SecurityValidator(projectRoot);
275
- const validation = await validator.validateFilePath(target);
801
+ const validation = await validator.validateFilePath(resolvedTarget);
276
802
  if (!validation.valid)
277
803
  throw new Error(validation.error);
278
804
  const matches = await findMetaprogrammingEntryPoints({
@@ -284,7 +810,7 @@ export async function handleFindMetaprogramming(args) {
284
810
  }
285
811
  // R2: get_rails_routes — parse config/routes.rb and return route map
286
812
  export async function handleGetRailsRoutes(args) {
287
- const projectRoot = String(args.projectRoot);
813
+ const projectRoot = resolveProjectRoot(args);
288
814
  const validator = new SecurityValidator(projectRoot);
289
815
  const rootValidation = await validator.validateFilePath(projectRoot);
290
816
  if (!rootValidation.valid)
@@ -295,4 +821,85 @@ export async function handleGetRailsRoutes(args) {
295
821
  }
296
822
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
297
823
  }
824
+ // TIA: get_impacted_tests — map modified AST symbols to target test suites
825
+ export async function handleGetImpactedTests(args) {
826
+ if (!args.filePath)
827
+ throw new Error("filePath is required");
828
+ const filePath = String(args.filePath);
829
+ const projectRoot = resolveProjectRoot(args, filePath);
830
+ const symbolName = args.symbolName ? String(args.symbolName) : undefined;
831
+ const validator = new SecurityValidator(projectRoot);
832
+ const validation = await validator.validateFilePath(filePath);
833
+ if (!validation.valid)
834
+ throw new Error(validation.error);
835
+ const result = await getImpactedTests({
836
+ filePath: validation.resolvedPath,
837
+ symbolName,
838
+ projectRoot,
839
+ });
840
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
841
+ }
842
+ // 3-Hop Call Hierarchy: get_call_hierarchy
843
+ export async function handleGetCallHierarchy(args) {
844
+ if (!args.filePath)
845
+ throw new Error("filePath is required");
846
+ if (!args.symbolName)
847
+ throw new Error("symbolName is required");
848
+ const filePath = String(args.filePath);
849
+ const symbolName = String(args.symbolName);
850
+ const projectRoot = resolveProjectRoot(args, filePath);
851
+ const direction = args.direction || "both";
852
+ const maxHops = args.maxHops ? Number(args.maxHops) : 3;
853
+ const validator = new SecurityValidator(projectRoot);
854
+ const validation = await validator.validateFilePath(filePath);
855
+ if (!validation.valid)
856
+ throw new Error(validation.error);
857
+ const result = await getCallHierarchy({
858
+ filePath: validation.resolvedPath,
859
+ symbolName,
860
+ direction,
861
+ maxHops,
862
+ projectRoot,
863
+ });
864
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
865
+ }
866
+ // Cross-Language Wire Contract: validate_wire_contract
867
+ export async function handleValidateWireContract(args) {
868
+ if (!args.frontendFile)
869
+ throw new Error("frontendFile is required");
870
+ const frontendFile = String(args.frontendFile);
871
+ const projectRoot = resolveProjectRoot(args, frontendFile);
872
+ const backendFile = args.backendFile ? String(args.backendFile) : undefined;
873
+ const endpoint = args.endpoint ? String(args.endpoint) : undefined;
874
+ const validator = new SecurityValidator(projectRoot);
875
+ const feVal = await validator.validateFilePath(frontendFile);
876
+ if (!feVal.valid)
877
+ throw new Error(feVal.error);
878
+ let bePath = undefined;
879
+ if (backendFile) {
880
+ const beVal = await validator.validateFilePath(backendFile);
881
+ if (!beVal.valid)
882
+ throw new Error(beVal.error);
883
+ bePath = beVal.resolvedPath;
884
+ }
885
+ const result = await validateWireContract({
886
+ frontendFile: feVal.resolvedPath,
887
+ backendFile: bePath,
888
+ endpoint,
889
+ projectRoot,
890
+ });
891
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
892
+ }
893
+ // Semantic Merge Conflict Predictor: predict_semantic_conflicts
894
+ export async function handlePredictSemanticConflicts(args) {
895
+ const projectRoot = resolveProjectRoot(args);
896
+ const baseBranch = args.baseBranch ? String(args.baseBranch) : undefined;
897
+ const targetBranch = args.targetBranch ? String(args.targetBranch) : undefined;
898
+ const result = await predictSemanticConflicts({
899
+ baseBranch,
900
+ targetBranch,
901
+ projectRoot,
902
+ });
903
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
904
+ }
298
905
  //# sourceMappingURL=readHandlers.js.map