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.
- package/CHANGELOG.md +288 -215
- package/INSTRUCTIONS.md +28 -11
- package/README.md +124 -11
- package/dist/src/core/engine.d.ts +1 -1
- package/dist/src/core/engine.js +1 -1
- package/dist/src/core/indexManager.d.ts +1 -1
- package/dist/src/core/indexManager.js +26 -26
- package/dist/src/core/sessionManager.d.ts +1 -1
- package/dist/src/core/sessionManager.js +1 -1
- package/dist/src/core/validator.d.ts +2 -2
- package/dist/src/core/validator.js +8 -2
- package/dist/src/core/validator.js.map +1 -1
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.js +119 -14
- package/dist/src/index.js.map +1 -1
- package/dist/src/operations/apiRoutes.d.ts +31 -0
- package/dist/src/operations/apiRoutes.js +170 -0
- package/dist/src/operations/apiRoutes.js.map +1 -0
- package/dist/src/operations/architectureLinter.d.ts +45 -0
- package/dist/src/operations/architectureLinter.js +223 -0
- package/dist/src/operations/architectureLinter.js.map +1 -0
- package/dist/src/operations/astComplexity.d.ts +38 -0
- package/dist/src/operations/astComplexity.js +243 -0
- package/dist/src/operations/astComplexity.js.map +1 -0
- package/dist/src/operations/astMockGenerator.d.ts +34 -0
- package/dist/src/operations/astMockGenerator.js +203 -0
- package/dist/src/operations/astMockGenerator.js.map +1 -0
- package/dist/src/operations/astQuery.d.ts +47 -0
- package/dist/src/operations/astQuery.js +169 -0
- package/dist/src/operations/astQuery.js.map +1 -0
- package/dist/src/operations/astTransform.d.ts +1 -1
- package/dist/src/operations/astTransform.js +11 -2
- package/dist/src/operations/astTransform.js.map +1 -1
- package/dist/src/operations/asyncBlockers.d.ts +33 -0
- package/dist/src/operations/asyncBlockers.js +162 -0
- package/dist/src/operations/asyncBlockers.js.map +1 -0
- package/dist/src/operations/blastRadiusReport.d.ts +43 -0
- package/dist/src/operations/blastRadiusReport.js +236 -0
- package/dist/src/operations/blastRadiusReport.js.map +1 -0
- package/dist/src/operations/callHierarchy.d.ts +28 -0
- package/dist/src/operations/callHierarchy.js +166 -0
- package/dist/src/operations/callHierarchy.js.map +1 -0
- package/dist/src/operations/circularDependencies.d.ts +28 -0
- package/dist/src/operations/circularDependencies.js +201 -0
- package/dist/src/operations/circularDependencies.js.map +1 -0
- package/dist/src/operations/classHierarchyFlattener.d.ts +35 -0
- package/dist/src/operations/classHierarchyFlattener.js +185 -0
- package/dist/src/operations/classHierarchyFlattener.js.map +1 -0
- package/dist/src/operations/compress.d.ts +2 -2
- package/dist/src/operations/compress.js +154 -20
- package/dist/src/operations/compress.js.map +1 -1
- package/dist/src/operations/conceptSearch.d.ts +19 -0
- package/dist/src/operations/conceptSearch.js +176 -0
- package/dist/src/operations/conceptSearch.js.map +1 -0
- package/dist/src/operations/confirmationStore.d.ts +1 -1
- package/dist/src/operations/confirmationStore.js +1 -1
- package/dist/src/operations/conflictPredictor.d.ts +21 -0
- package/dist/src/operations/conflictPredictor.js +139 -0
- package/dist/src/operations/conflictPredictor.js.map +1 -0
- package/dist/src/operations/contextCompactor.d.ts +38 -0
- package/dist/src/operations/contextCompactor.js +348 -0
- package/dist/src/operations/contextCompactor.js.map +1 -0
- package/dist/src/operations/cstCodemod.d.ts +34 -0
- package/dist/src/operations/cstCodemod.js +205 -0
- package/dist/src/operations/cstCodemod.js.map +1 -0
- package/dist/src/operations/deadSymbols.d.ts +32 -0
- package/dist/src/operations/deadSymbols.js +178 -0
- package/dist/src/operations/deadSymbols.js.map +1 -0
- package/dist/src/operations/envContract.d.ts +35 -0
- package/dist/src/operations/envContract.js +194 -0
- package/dist/src/operations/envContract.js.map +1 -0
- package/dist/src/operations/errorAudit.d.ts +36 -0
- package/dist/src/operations/errorAudit.js +201 -0
- package/dist/src/operations/errorAudit.js.map +1 -0
- package/dist/src/operations/importIntegrity.d.ts +48 -0
- package/dist/src/operations/importIntegrity.js +395 -0
- package/dist/src/operations/importIntegrity.js.map +1 -0
- package/dist/src/operations/incrementalDiff.d.ts +47 -0
- package/dist/src/operations/incrementalDiff.js +216 -0
- package/dist/src/operations/incrementalDiff.js.map +1 -0
- package/dist/src/operations/lexicalScope.d.ts +51 -0
- package/dist/src/operations/lexicalScope.js +212 -0
- package/dist/src/operations/lexicalScope.js.map +1 -0
- package/dist/src/operations/read.d.ts +21 -0
- package/dist/src/operations/read.js +21 -0
- package/dist/src/operations/read.js.map +1 -1
- package/dist/src/operations/readCore.js +37 -17
- package/dist/src/operations/readCore.js.map +1 -1
- package/dist/src/operations/rename.js +35 -24
- package/dist/src/operations/rename.js.map +1 -1
- package/dist/src/operations/sqlValidator.d.ts +36 -0
- package/dist/src/operations/sqlValidator.js +202 -0
- package/dist/src/operations/sqlValidator.js.map +1 -0
- package/dist/src/operations/symbolQuery.js +112 -23
- package/dist/src/operations/symbolQuery.js.map +1 -1
- package/dist/src/operations/taintAnalysis.d.ts +46 -0
- package/dist/src/operations/taintAnalysis.js +220 -0
- package/dist/src/operations/taintAnalysis.js.map +1 -0
- package/dist/src/operations/testImpact.d.ts +31 -0
- package/dist/src/operations/testImpact.js +179 -0
- package/dist/src/operations/testImpact.js.map +1 -0
- package/dist/src/operations/typeInference.d.ts +54 -0
- package/dist/src/operations/typeInference.js +565 -0
- package/dist/src/operations/typeInference.js.map +1 -0
- package/dist/src/operations/wireContract.d.ts +34 -0
- package/dist/src/operations/wireContract.js +185 -0
- package/dist/src/operations/wireContract.js.map +1 -0
- package/dist/src/operations/write.d.ts +2 -2
- package/dist/src/operations/write.js +151 -82
- package/dist/src/operations/write.js.map +1 -1
- package/dist/src/parsers/base.d.ts +9 -1
- package/dist/src/parsers/base.js +61 -1
- package/dist/src/parsers/base.js.map +1 -1
- package/dist/src/parsers/csharp.d.ts +1 -1
- package/dist/src/parsers/csharp.js +1 -1
- package/dist/src/parsers/dartTreeSitter.d.ts +1 -1
- package/dist/src/parsers/dartTreeSitter.js +1 -1
- package/dist/src/parsers/go.d.ts +1 -1
- package/dist/src/parsers/go.js +1 -1
- package/dist/src/parsers/java.d.ts +1 -1
- package/dist/src/parsers/java.js +1 -1
- package/dist/src/parsers/kotlin.d.ts +1 -1
- package/dist/src/parsers/kotlin.js +1 -1
- package/dist/src/parsers/php.d.ts +1 -1
- package/dist/src/parsers/php.js +1 -1
- package/dist/src/parsers/python.d.ts +1 -1
- package/dist/src/parsers/python.js +1 -1
- package/dist/src/parsers/registry.d.ts +1 -1
- package/dist/src/parsers/registry.js +1 -1
- package/dist/src/parsers/ruby.d.ts +1 -1
- package/dist/src/parsers/ruby.js +1 -1
- package/dist/src/parsers/rust.d.ts +1 -1
- package/dist/src/parsers/rust.js +1 -1
- package/dist/src/parsers/typescript.d.ts +1 -1
- package/dist/src/parsers/typescript.js +1 -1
- package/dist/src/tools/adminHandlers.js +8 -7
- package/dist/src/tools/adminHandlers.js.map +1 -1
- package/dist/src/tools/context.d.ts +4 -0
- package/dist/src/tools/context.js +14 -0
- package/dist/src/tools/context.js.map +1 -1
- package/dist/src/tools/pipeline.js +27 -1
- package/dist/src/tools/pipeline.js.map +1 -1
- package/dist/src/tools/readHandlers.d.ts +150 -0
- package/dist/src/tools/readHandlers.js +642 -35
- package/dist/src/tools/readHandlers.js.map +1 -1
- package/dist/src/tools/toolDefinitions.d.ts +2190 -1
- package/dist/src/tools/toolDefinitionsAdmin.d.ts +1 -1
- package/dist/src/tools/toolDefinitionsAdmin.js +12 -12
- package/dist/src/tools/toolDefinitionsAdmin.js.map +1 -1
- package/dist/src/tools/toolDefinitionsCore.d.ts +2189 -0
- package/dist/src/tools/toolDefinitionsCore.js +422 -42
- package/dist/src/tools/toolDefinitionsCore.js.map +1 -1
- package/dist/src/tools/writeHandlers.js +31 -17
- package/dist/src/tools/writeHandlers.js.map +1 -1
- package/dist/src/utils/appDir.d.ts +1 -1
- package/dist/src/utils/appDir.js +1 -1
- package/dist/src/utils/auditLogger.d.ts +1 -1
- package/dist/src/utils/auditLogger.js +1 -1
- package/dist/src/utils/backupManager.d.ts +1 -1
- package/dist/src/utils/backupManager.js +1 -1
- package/dist/src/utils/conceptEngine.d.ts +56 -0
- package/dist/src/utils/conceptEngine.js +234 -0
- package/dist/src/utils/conceptEngine.js.map +1 -0
- package/dist/src/utils/constants.d.ts +1 -1
- package/dist/src/utils/constants.js +2 -1
- package/dist/src/utils/constants.js.map +1 -1
- package/dist/src/utils/diff.d.ts +1 -1
- package/dist/src/utils/diff.js +1 -1
- package/dist/src/utils/fileLock.d.ts +1 -1
- package/dist/src/utils/fileLock.js +1 -1
- package/dist/src/utils/fileWalker.d.ts +1 -1
- package/dist/src/utils/fileWalker.js +1 -1
- package/dist/src/utils/fileWatcher.d.ts +1 -1
- package/dist/src/utils/fileWatcher.js +1 -1
- package/dist/src/utils/fuzzySearch.d.ts +1 -1
- package/dist/src/utils/fuzzySearch.js +1 -1
- package/dist/src/utils/gemfileParser.d.ts +1 -1
- package/dist/src/utils/gemfileParser.js +1 -1
- package/dist/src/utils/logger.d.ts +1 -1
- package/dist/src/utils/logger.js +1 -1
- package/dist/src/utils/metaprogramming.d.ts +1 -1
- package/dist/src/utils/metaprogramming.js +1 -1
- package/dist/src/utils/projectRoot.d.ts +9 -0
- package/dist/src/utils/projectRoot.js +94 -0
- package/dist/src/utils/projectRoot.js.map +1 -0
- package/dist/src/utils/railsRoutes.d.ts +1 -1
- package/dist/src/utils/railsRoutes.js +1 -1
- package/dist/src/utils/rateLimiter.d.ts +26 -1
- package/dist/src/utils/rateLimiter.js +26 -1
- package/dist/src/utils/rateLimiter.js.map +1 -1
- package/dist/src/utils/streaming.d.ts +1 -1
- package/dist/src/utils/streaming.js +1 -1
- package/dist/src/utils/telemetry.d.ts +1 -1
- package/dist/src/utils/telemetry.js +1 -1
- package/dist/src/utils/virtualSchema.d.ts +31 -0
- package/dist/src/utils/virtualSchema.js +367 -0
- package/dist/src/utils/virtualSchema.js.map +1 -0
- package/llms.txt +24 -6
- package/package.json +4 -2
- package/skills/code-context-logo.png +0 -0
- package/skills/code-context-pro/SKILL.md +149 -0
- package/skills/code-context-pro/references/benchmarks.md +25 -0
- package/skills/code-context-pro/references/decision-tree.md +32 -0
- package/skills/code-context-pro/references/multi-ide-setup.md +104 -0
- package/skills/code-context-pro.zip +0 -0
- package/HIRE_ME.md +0 -234
- package/SPONSORS.md +0 -104
- 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 {
|
|
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
|
|
16
|
-
throw new Error("directoryPath
|
|
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 =
|
|
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 =
|
|
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
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
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
|
-
|
|
93
|
-
if (
|
|
94
|
-
const
|
|
95
|
-
if (
|
|
96
|
-
|
|
97
|
-
|
|
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 =
|
|
136
|
+
content = formatUnifiedSchemaAnnotation(unified.framework, tableName, columns) + "\n" + content;
|
|
100
137
|
}
|
|
101
138
|
}
|
|
102
139
|
}
|
|
103
140
|
}
|
|
104
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
272
|
-
const
|
|
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(
|
|
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 =
|
|
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
|