driftdetect-mcp 0.6.0 → 0.7.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/LICENSE +21 -0
- package/dist/bin/server.js +0 -0
- package/dist/enterprise-server.d.ts +1 -0
- package/dist/enterprise-server.d.ts.map +1 -1
- package/dist/enterprise-server.js +8 -1
- package/dist/enterprise-server.js.map +1 -1
- package/dist/tools/analysis/constants.d.ts +99 -0
- package/dist/tools/analysis/constants.d.ts.map +1 -0
- package/dist/tools/analysis/constants.js +421 -0
- package/dist/tools/analysis/constants.js.map +1 -0
- package/dist/tools/analysis/index.d.ts +1 -0
- package/dist/tools/analysis/index.d.ts.map +1 -1
- package/dist/tools/analysis/index.js +70 -0
- package/dist/tools/analysis/index.js.map +1 -1
- package/dist/tools/exploration/env.d.ts +53 -0
- package/dist/tools/exploration/env.d.ts.map +1 -0
- package/dist/tools/exploration/env.js +283 -0
- package/dist/tools/exploration/env.js.map +1 -0
- package/dist/tools/exploration/index.d.ts +2 -0
- package/dist/tools/exploration/index.d.ts.map +1 -1
- package/dist/tools/exploration/index.js +32 -0
- package/dist/tools/exploration/index.js.map +1 -1
- package/dist/tools/index.d.ts +6 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +6 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/registry.d.ts +7 -5
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +10 -4
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/surgical/callers.d.ts +85 -0
- package/dist/tools/surgical/callers.d.ts.map +1 -0
- package/dist/tools/surgical/callers.js +239 -0
- package/dist/tools/surgical/callers.js.map +1 -0
- package/dist/tools/surgical/dependencies.d.ts +96 -0
- package/dist/tools/surgical/dependencies.d.ts.map +1 -0
- package/dist/tools/surgical/dependencies.js +433 -0
- package/dist/tools/surgical/dependencies.js.map +1 -0
- package/dist/tools/surgical/errors.d.ts +88 -0
- package/dist/tools/surgical/errors.d.ts.map +1 -0
- package/dist/tools/surgical/errors.js +275 -0
- package/dist/tools/surgical/errors.js.map +1 -0
- package/dist/tools/surgical/hooks.d.ts +69 -0
- package/dist/tools/surgical/hooks.d.ts.map +1 -0
- package/dist/tools/surgical/hooks.js +247 -0
- package/dist/tools/surgical/hooks.js.map +1 -0
- package/dist/tools/surgical/imports.d.ts +61 -0
- package/dist/tools/surgical/imports.d.ts.map +1 -0
- package/dist/tools/surgical/imports.js +211 -0
- package/dist/tools/surgical/imports.js.map +1 -0
- package/dist/tools/surgical/index.d.ts +42 -0
- package/dist/tools/surgical/index.d.ts.map +1 -0
- package/dist/tools/surgical/index.js +66 -0
- package/dist/tools/surgical/index.js.map +1 -0
- package/dist/tools/surgical/middleware.d.ts +69 -0
- package/dist/tools/surgical/middleware.d.ts.map +1 -0
- package/dist/tools/surgical/middleware.js +237 -0
- package/dist/tools/surgical/middleware.js.map +1 -0
- package/dist/tools/surgical/prevalidate.d.ts +76 -0
- package/dist/tools/surgical/prevalidate.d.ts.map +1 -0
- package/dist/tools/surgical/prevalidate.js +303 -0
- package/dist/tools/surgical/prevalidate.js.map +1 -0
- package/dist/tools/surgical/recent.d.ts +66 -0
- package/dist/tools/surgical/recent.d.ts.map +1 -0
- package/dist/tools/surgical/recent.js +238 -0
- package/dist/tools/surgical/recent.js.map +1 -0
- package/dist/tools/surgical/signature.d.ts +73 -0
- package/dist/tools/surgical/signature.d.ts.map +1 -0
- package/dist/tools/surgical/signature.js +190 -0
- package/dist/tools/surgical/signature.js.map +1 -0
- package/dist/tools/surgical/similar.d.ts +77 -0
- package/dist/tools/surgical/similar.d.ts.map +1 -0
- package/dist/tools/surgical/similar.js +285 -0
- package/dist/tools/surgical/similar.js.map +1 -0
- package/dist/tools/surgical/test-template.d.ts +70 -0
- package/dist/tools/surgical/test-template.d.ts.map +1 -0
- package/dist/tools/surgical/test-template.js +298 -0
- package/dist/tools/surgical/test-template.js.map +1 -0
- package/dist/tools/surgical/type.d.ts +69 -0
- package/dist/tools/surgical/type.d.ts.map +1 -0
- package/dist/tools/surgical/type.js +289 -0
- package/dist/tools/surgical/type.js.map +1 -0
- package/package.json +11 -11
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_middleware - Middleware Pattern Lookup
|
|
3
|
+
*
|
|
4
|
+
* Layer: Surgical
|
|
5
|
+
* Token Budget: 300 target, 800 max
|
|
6
|
+
*
|
|
7
|
+
* Returns middleware patterns in the codebase.
|
|
8
|
+
* Solves: AI needs to know existing middleware when adding auth/logging/etc.
|
|
9
|
+
*/
|
|
10
|
+
import { createWrapperScanner, } from 'driftdetect-core/wrappers';
|
|
11
|
+
import { createResponseBuilder, metrics } from '../../infrastructure/index.js';
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Handler
|
|
14
|
+
// ============================================================================
|
|
15
|
+
export async function handleMiddleware(args, rootDir) {
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
const builder = createResponseBuilder();
|
|
18
|
+
const typeFilter = args.type ?? 'all';
|
|
19
|
+
const frameworkFilter = args.framework?.toLowerCase();
|
|
20
|
+
const limit = args.limit ?? 20;
|
|
21
|
+
// Scan for wrappers with middleware category
|
|
22
|
+
const scanner = createWrapperScanner({
|
|
23
|
+
rootDir,
|
|
24
|
+
includeTestFiles: false,
|
|
25
|
+
verbose: false,
|
|
26
|
+
});
|
|
27
|
+
const result = await scanner.scan({
|
|
28
|
+
minConfidence: 0.3,
|
|
29
|
+
minClusterSize: 1,
|
|
30
|
+
maxDepth: 5,
|
|
31
|
+
includeTestFiles: false,
|
|
32
|
+
});
|
|
33
|
+
// Filter to middleware-related clusters
|
|
34
|
+
const middlewareClusters = result.analysis.clusters.filter(c => c.category === 'middleware' ||
|
|
35
|
+
c.category === 'authentication' ||
|
|
36
|
+
c.category === 'authorization' ||
|
|
37
|
+
c.category === 'validation' ||
|
|
38
|
+
c.category === 'logging' ||
|
|
39
|
+
c.category === 'error-handling');
|
|
40
|
+
// Extract middleware functions
|
|
41
|
+
const middlewareList = [];
|
|
42
|
+
for (const cluster of middlewareClusters) {
|
|
43
|
+
const middlewareType = categorizeMiddleware(cluster);
|
|
44
|
+
// Apply type filter
|
|
45
|
+
if (typeFilter !== 'all' && middlewareType !== typeFilter) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
for (const wrapper of cluster.wrappers) {
|
|
49
|
+
// Apply framework filter
|
|
50
|
+
const detectedFramework = detectFramework(wrapper);
|
|
51
|
+
if (frameworkFilter && detectedFramework?.toLowerCase() !== frameworkFilter) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
middlewareList.push({
|
|
55
|
+
name: wrapper.name,
|
|
56
|
+
file: wrapper.file,
|
|
57
|
+
line: wrapper.line,
|
|
58
|
+
type: middlewareType,
|
|
59
|
+
framework: detectedFramework,
|
|
60
|
+
usages: wrapper.calledBy.length,
|
|
61
|
+
parameters: wrapper.parameterSignature,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Also check for common middleware patterns in wrappers
|
|
66
|
+
for (const wrapper of result.analysis.wrappers) {
|
|
67
|
+
if (isMiddlewarePattern(wrapper) && !middlewareList.some(m => m.name === wrapper.name)) {
|
|
68
|
+
const middlewareType = inferMiddlewareType(wrapper);
|
|
69
|
+
if (typeFilter !== 'all' && middlewareType !== typeFilter) {
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const detectedFramework = detectFramework(wrapper);
|
|
73
|
+
if (frameworkFilter && detectedFramework?.toLowerCase() !== frameworkFilter) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
middlewareList.push({
|
|
77
|
+
name: wrapper.name,
|
|
78
|
+
file: wrapper.file,
|
|
79
|
+
line: wrapper.line,
|
|
80
|
+
type: middlewareType,
|
|
81
|
+
framework: detectedFramework,
|
|
82
|
+
usages: wrapper.calledBy.length,
|
|
83
|
+
parameters: wrapper.parameterSignature,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Sort by usages and limit
|
|
88
|
+
middlewareList.sort((a, b) => b.usages - a.usages);
|
|
89
|
+
const limited = middlewareList.slice(0, limit);
|
|
90
|
+
// Calculate stats
|
|
91
|
+
const byType = {};
|
|
92
|
+
let authCount = 0;
|
|
93
|
+
let loggingCount = 0;
|
|
94
|
+
let validationCount = 0;
|
|
95
|
+
let errorCount = 0;
|
|
96
|
+
for (const mw of middlewareList) {
|
|
97
|
+
byType[mw.type] = (byType[mw.type] ?? 0) + 1;
|
|
98
|
+
if (mw.type === 'auth')
|
|
99
|
+
authCount++;
|
|
100
|
+
if (mw.type === 'logging')
|
|
101
|
+
loggingCount++;
|
|
102
|
+
if (mw.type === 'validation')
|
|
103
|
+
validationCount++;
|
|
104
|
+
if (mw.type === 'error')
|
|
105
|
+
errorCount++;
|
|
106
|
+
}
|
|
107
|
+
const data = {
|
|
108
|
+
middleware: limited,
|
|
109
|
+
byType,
|
|
110
|
+
stats: {
|
|
111
|
+
total: middlewareList.length,
|
|
112
|
+
authCount,
|
|
113
|
+
loggingCount,
|
|
114
|
+
validationCount,
|
|
115
|
+
errorCount,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
// Build summary
|
|
119
|
+
const summary = middlewareList.length > 0
|
|
120
|
+
? `Found ${middlewareList.length} middleware: ${authCount} auth, ${loggingCount} logging, ${validationCount} validation, ${errorCount} error handling`
|
|
121
|
+
: 'No middleware patterns detected';
|
|
122
|
+
// Record metrics
|
|
123
|
+
metrics.recordRequest('drift_middleware', Date.now() - startTime, true, false);
|
|
124
|
+
return builder
|
|
125
|
+
.withSummary(summary)
|
|
126
|
+
.withData(data)
|
|
127
|
+
.withHints({
|
|
128
|
+
nextActions: middlewareList.length > 0
|
|
129
|
+
? ['Review existing middleware before adding new ones', 'Check middleware order in routes']
|
|
130
|
+
: ['Consider adding middleware for cross-cutting concerns'],
|
|
131
|
+
relatedTools: ['drift_wrappers', 'drift_signature', 'drift_imports'],
|
|
132
|
+
})
|
|
133
|
+
.buildContent();
|
|
134
|
+
}
|
|
135
|
+
// ============================================================================
|
|
136
|
+
// Helpers
|
|
137
|
+
// ============================================================================
|
|
138
|
+
function categorizeMiddleware(cluster) {
|
|
139
|
+
switch (cluster.category) {
|
|
140
|
+
case 'authentication':
|
|
141
|
+
case 'authorization':
|
|
142
|
+
return 'auth';
|
|
143
|
+
case 'logging':
|
|
144
|
+
return 'logging';
|
|
145
|
+
case 'validation':
|
|
146
|
+
return 'validation';
|
|
147
|
+
case 'error-handling':
|
|
148
|
+
return 'error';
|
|
149
|
+
default:
|
|
150
|
+
return 'other';
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
function detectFramework(wrapper) {
|
|
154
|
+
const primitives = wrapper.primitiveSignature.join(' ').toLowerCase();
|
|
155
|
+
const name = wrapper.name.toLowerCase();
|
|
156
|
+
if (primitives.includes('express') || name.includes('express'))
|
|
157
|
+
return 'express';
|
|
158
|
+
if (primitives.includes('koa'))
|
|
159
|
+
return 'koa';
|
|
160
|
+
if (primitives.includes('fastify'))
|
|
161
|
+
return 'fastify';
|
|
162
|
+
if (primitives.includes('nestjs') || primitives.includes('@nestjs'))
|
|
163
|
+
return 'nestjs';
|
|
164
|
+
if (primitives.includes('laravel') || primitives.includes('illuminate'))
|
|
165
|
+
return 'laravel';
|
|
166
|
+
if (primitives.includes('spring') || primitives.includes('@controller'))
|
|
167
|
+
return 'spring';
|
|
168
|
+
if (primitives.includes('gin') || primitives.includes('echo') || primitives.includes('fiber'))
|
|
169
|
+
return 'go';
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
function isMiddlewarePattern(wrapper) {
|
|
173
|
+
const name = wrapper.name.toLowerCase();
|
|
174
|
+
const params = wrapper.parameterSignature?.join(' ').toLowerCase() ?? '';
|
|
175
|
+
// Common middleware naming patterns
|
|
176
|
+
if (name.includes('middleware'))
|
|
177
|
+
return true;
|
|
178
|
+
if (name.includes('interceptor'))
|
|
179
|
+
return true;
|
|
180
|
+
if (name.includes('guard'))
|
|
181
|
+
return true;
|
|
182
|
+
if (name.includes('filter'))
|
|
183
|
+
return true;
|
|
184
|
+
// Express-style (req, res, next)
|
|
185
|
+
if (params.includes('req') && params.includes('res') && params.includes('next'))
|
|
186
|
+
return true;
|
|
187
|
+
// Koa-style (ctx, next)
|
|
188
|
+
if (params.includes('ctx') && params.includes('next'))
|
|
189
|
+
return true;
|
|
190
|
+
return false;
|
|
191
|
+
}
|
|
192
|
+
function inferMiddlewareType(wrapper) {
|
|
193
|
+
const name = wrapper.name.toLowerCase();
|
|
194
|
+
const primitives = wrapper.primitiveSignature.join(' ').toLowerCase();
|
|
195
|
+
if (name.includes('auth') || name.includes('jwt') || name.includes('session') ||
|
|
196
|
+
primitives.includes('auth') || primitives.includes('jwt')) {
|
|
197
|
+
return 'auth';
|
|
198
|
+
}
|
|
199
|
+
if (name.includes('log') || name.includes('morgan') || name.includes('winston') ||
|
|
200
|
+
primitives.includes('log')) {
|
|
201
|
+
return 'logging';
|
|
202
|
+
}
|
|
203
|
+
if (name.includes('valid') || name.includes('sanitize') || name.includes('schema') ||
|
|
204
|
+
primitives.includes('joi') || primitives.includes('zod') || primitives.includes('yup')) {
|
|
205
|
+
return 'validation';
|
|
206
|
+
}
|
|
207
|
+
if (name.includes('error') || name.includes('exception') || name.includes('catch')) {
|
|
208
|
+
return 'error';
|
|
209
|
+
}
|
|
210
|
+
return 'other';
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Tool definition for MCP registration
|
|
214
|
+
*/
|
|
215
|
+
export const middlewareToolDefinition = {
|
|
216
|
+
name: 'drift_middleware',
|
|
217
|
+
description: 'Find middleware patterns in the codebase. Returns auth, logging, validation, and error handling middleware with their locations and usage counts.',
|
|
218
|
+
inputSchema: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
properties: {
|
|
221
|
+
type: {
|
|
222
|
+
type: 'string',
|
|
223
|
+
enum: ['auth', 'logging', 'validation', 'error', 'all'],
|
|
224
|
+
description: 'Filter by middleware type (default: all)',
|
|
225
|
+
},
|
|
226
|
+
framework: {
|
|
227
|
+
type: 'string',
|
|
228
|
+
description: 'Filter by framework: express, koa, fastify, nestjs, laravel, spring',
|
|
229
|
+
},
|
|
230
|
+
limit: {
|
|
231
|
+
type: 'number',
|
|
232
|
+
description: 'Max results to return (default: 20)',
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/tools/surgical/middleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_prevalidate - Validate Code Before Writing
|
|
3
|
+
*
|
|
4
|
+
* Layer: Surgical
|
|
5
|
+
* Token Budget: 400 target, 1000 max
|
|
6
|
+
* Cache TTL: 1 minute (short - code changes frequently)
|
|
7
|
+
* Invalidation Keys: patterns, category:{cat}
|
|
8
|
+
*
|
|
9
|
+
* Validates proposed code BEFORE writing it to disk.
|
|
10
|
+
* Solves: AI writes code, saves it, THEN finds out it violates patterns.
|
|
11
|
+
*/
|
|
12
|
+
import type { PatternStore, IPatternService } from 'driftdetect-core';
|
|
13
|
+
export interface PrevalidateArgs {
|
|
14
|
+
/** The code to validate */
|
|
15
|
+
code: string;
|
|
16
|
+
/** Where it will be written */
|
|
17
|
+
targetFile: string;
|
|
18
|
+
/** What kind of code is this? */
|
|
19
|
+
kind?: 'function' | 'class' | 'component' | 'test' | 'full-file';
|
|
20
|
+
}
|
|
21
|
+
export interface Violation {
|
|
22
|
+
rule: string;
|
|
23
|
+
severity: 'error' | 'warning' | 'info';
|
|
24
|
+
message: string;
|
|
25
|
+
suggestion?: string;
|
|
26
|
+
line?: number;
|
|
27
|
+
}
|
|
28
|
+
export interface PrevalidateData {
|
|
29
|
+
valid: boolean;
|
|
30
|
+
score: number;
|
|
31
|
+
violations: Violation[];
|
|
32
|
+
expectedPatterns: string[];
|
|
33
|
+
suggestions: string[];
|
|
34
|
+
}
|
|
35
|
+
export declare function handlePrevalidate(store: PatternStore, args: PrevalidateArgs): Promise<{
|
|
36
|
+
content: Array<{
|
|
37
|
+
type: string;
|
|
38
|
+
text: string;
|
|
39
|
+
}>;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Handler using IPatternService (preferred)
|
|
43
|
+
*/
|
|
44
|
+
export declare function handlePrevalidateWithService(service: IPatternService, args: PrevalidateArgs): Promise<{
|
|
45
|
+
content: Array<{
|
|
46
|
+
type: string;
|
|
47
|
+
text: string;
|
|
48
|
+
}>;
|
|
49
|
+
}>;
|
|
50
|
+
/**
|
|
51
|
+
* Tool definition for MCP registration
|
|
52
|
+
*/
|
|
53
|
+
export declare const prevalidateToolDefinition: {
|
|
54
|
+
name: string;
|
|
55
|
+
description: string;
|
|
56
|
+
inputSchema: {
|
|
57
|
+
type: "object";
|
|
58
|
+
properties: {
|
|
59
|
+
code: {
|
|
60
|
+
type: string;
|
|
61
|
+
description: string;
|
|
62
|
+
};
|
|
63
|
+
targetFile: {
|
|
64
|
+
type: string;
|
|
65
|
+
description: string;
|
|
66
|
+
};
|
|
67
|
+
kind: {
|
|
68
|
+
type: string;
|
|
69
|
+
enum: string[];
|
|
70
|
+
description: string;
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
required: string[];
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=prevalidate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prevalidate.d.ts","sourceRoot":"","sources":["../../../src/tools/surgical/prevalidate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAOtE,MAAM,WAAW,eAAe;IAC9B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,iCAAiC;IACjC,IAAI,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,WAAW,GAAG,MAAM,GAAG,WAAW,CAAC;CAClE;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAMD,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,YAAY,EACnB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CA6E7D;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,EAAE,eAAe,EACxB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CA8F7D;AAiJD;;GAEG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;CAsBrC,CAAC"}
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_prevalidate - Validate Code Before Writing
|
|
3
|
+
*
|
|
4
|
+
* Layer: Surgical
|
|
5
|
+
* Token Budget: 400 target, 1000 max
|
|
6
|
+
* Cache TTL: 1 minute (short - code changes frequently)
|
|
7
|
+
* Invalidation Keys: patterns, category:{cat}
|
|
8
|
+
*
|
|
9
|
+
* Validates proposed code BEFORE writing it to disk.
|
|
10
|
+
* Solves: AI writes code, saves it, THEN finds out it violates patterns.
|
|
11
|
+
*/
|
|
12
|
+
import { createResponseBuilder, Errors, metrics } from '../../infrastructure/index.js';
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Handler
|
|
15
|
+
// ============================================================================
|
|
16
|
+
export async function handlePrevalidate(store, args) {
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
const builder = createResponseBuilder();
|
|
19
|
+
// Validate input
|
|
20
|
+
if (!args.code || args.code.trim() === '') {
|
|
21
|
+
throw Errors.missingParameter('code');
|
|
22
|
+
}
|
|
23
|
+
if (!args.targetFile) {
|
|
24
|
+
throw Errors.missingParameter('targetFile');
|
|
25
|
+
}
|
|
26
|
+
const code = args.code;
|
|
27
|
+
const targetFile = args.targetFile;
|
|
28
|
+
const kind = args.kind ?? 'function';
|
|
29
|
+
// Initialize pattern store
|
|
30
|
+
await store.initialize();
|
|
31
|
+
// Get patterns for the target directory
|
|
32
|
+
const targetDir = targetFile.substring(0, targetFile.lastIndexOf('/'));
|
|
33
|
+
const relevantPatterns = findRelevantPatterns(store, targetDir, kind);
|
|
34
|
+
// Analyze the proposed code
|
|
35
|
+
const violations = [];
|
|
36
|
+
const suggestions = [];
|
|
37
|
+
// Check for common issues based on patterns
|
|
38
|
+
analyzeCode(code, relevantPatterns, violations, suggestions);
|
|
39
|
+
// Calculate score (100 - penalties)
|
|
40
|
+
let score = 100;
|
|
41
|
+
for (const v of violations) {
|
|
42
|
+
if (v.severity === 'error')
|
|
43
|
+
score -= 20;
|
|
44
|
+
else if (v.severity === 'warning')
|
|
45
|
+
score -= 10;
|
|
46
|
+
else
|
|
47
|
+
score -= 5;
|
|
48
|
+
}
|
|
49
|
+
score = Math.max(0, score);
|
|
50
|
+
const data = {
|
|
51
|
+
valid: violations.filter(v => v.severity === 'error').length === 0,
|
|
52
|
+
score,
|
|
53
|
+
violations,
|
|
54
|
+
expectedPatterns: relevantPatterns.map(p => p.name),
|
|
55
|
+
suggestions,
|
|
56
|
+
};
|
|
57
|
+
// Build summary
|
|
58
|
+
let summary;
|
|
59
|
+
if (violations.length === 0) {
|
|
60
|
+
summary = `Code looks good! Score: ${score}/100. Matches expected patterns.`;
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const errorCount = violations.filter(v => v.severity === 'error').length;
|
|
64
|
+
const warningCount = violations.filter(v => v.severity === 'warning').length;
|
|
65
|
+
summary = `Score: ${score}/100. Found ${errorCount} error${errorCount !== 1 ? 's' : ''}, ${warningCount} warning${warningCount !== 1 ? 's' : ''}.`;
|
|
66
|
+
}
|
|
67
|
+
// Build hints
|
|
68
|
+
const hints = {
|
|
69
|
+
nextActions: violations.length > 0
|
|
70
|
+
? ['Fix violations before writing code', 'Use drift_code_examples to see correct patterns']
|
|
71
|
+
: ['Code is ready to write', 'Use drift_imports to add correct imports'],
|
|
72
|
+
relatedTools: ['drift_code_examples', 'drift_imports', 'drift_similar'],
|
|
73
|
+
};
|
|
74
|
+
if (violations.some(v => v.severity === 'error')) {
|
|
75
|
+
hints.warnings = ['Code has errors that should be fixed before writing'];
|
|
76
|
+
}
|
|
77
|
+
// Record metrics
|
|
78
|
+
metrics.recordRequest('drift_prevalidate', Date.now() - startTime, true, false);
|
|
79
|
+
return builder
|
|
80
|
+
.withSummary(summary)
|
|
81
|
+
.withData(data)
|
|
82
|
+
.withHints(hints)
|
|
83
|
+
.buildContent();
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Handler using IPatternService (preferred)
|
|
87
|
+
*/
|
|
88
|
+
export async function handlePrevalidateWithService(service, args) {
|
|
89
|
+
const startTime = Date.now();
|
|
90
|
+
const builder = createResponseBuilder();
|
|
91
|
+
// Validate input
|
|
92
|
+
if (!args.code || args.code.trim() === '') {
|
|
93
|
+
throw Errors.missingParameter('code');
|
|
94
|
+
}
|
|
95
|
+
if (!args.targetFile) {
|
|
96
|
+
throw Errors.missingParameter('targetFile');
|
|
97
|
+
}
|
|
98
|
+
const code = args.code;
|
|
99
|
+
const targetFile = args.targetFile;
|
|
100
|
+
// kind reserved for future use
|
|
101
|
+
// const kind = args.kind ?? 'function';
|
|
102
|
+
// Get patterns - for prevalidation we use all patterns since PatternSummary
|
|
103
|
+
// doesn't include location data. The validation logic checks code content.
|
|
104
|
+
const patternsResult = await service.listPatterns();
|
|
105
|
+
const allPatterns = patternsResult.items ?? [];
|
|
106
|
+
// Map to pattern-like objects for analysis
|
|
107
|
+
const relevantPatterns = allPatterns.map(p => ({
|
|
108
|
+
name: p.name,
|
|
109
|
+
category: p.category,
|
|
110
|
+
subcategory: p.subcategory,
|
|
111
|
+
}));
|
|
112
|
+
// Analyze the proposed code
|
|
113
|
+
const violations = [];
|
|
114
|
+
const suggestions = [];
|
|
115
|
+
// Check for common issues
|
|
116
|
+
analyzeCodeWithPatterns(code, relevantPatterns, violations, suggestions);
|
|
117
|
+
// Calculate score
|
|
118
|
+
let score = 100;
|
|
119
|
+
for (const v of violations) {
|
|
120
|
+
if (v.severity === 'error')
|
|
121
|
+
score -= 20;
|
|
122
|
+
else if (v.severity === 'warning')
|
|
123
|
+
score -= 10;
|
|
124
|
+
else
|
|
125
|
+
score -= 5;
|
|
126
|
+
}
|
|
127
|
+
score = Math.max(0, score);
|
|
128
|
+
// Filter to patterns that might be relevant based on target file path
|
|
129
|
+
const targetDir = targetFile.substring(0, targetFile.lastIndexOf('/'));
|
|
130
|
+
const expectedPatterns = relevantPatterns
|
|
131
|
+
.filter(p => {
|
|
132
|
+
// Include patterns that match common directory conventions
|
|
133
|
+
if (targetDir.includes('api') && p.category === 'api')
|
|
134
|
+
return true;
|
|
135
|
+
if (targetDir.includes('auth') && p.category === 'auth')
|
|
136
|
+
return true;
|
|
137
|
+
if (targetDir.includes('test') && p.category === 'testing')
|
|
138
|
+
return true;
|
|
139
|
+
if (targetDir.includes('component') && p.category === 'components')
|
|
140
|
+
return true;
|
|
141
|
+
return false;
|
|
142
|
+
})
|
|
143
|
+
.map(p => p.name);
|
|
144
|
+
const data = {
|
|
145
|
+
valid: violations.filter(v => v.severity === 'error').length === 0,
|
|
146
|
+
score,
|
|
147
|
+
violations,
|
|
148
|
+
expectedPatterns: expectedPatterns.length > 0 ? expectedPatterns : relevantPatterns.slice(0, 5).map(p => p.name),
|
|
149
|
+
suggestions,
|
|
150
|
+
};
|
|
151
|
+
// Build summary
|
|
152
|
+
let summary;
|
|
153
|
+
if (violations.length === 0) {
|
|
154
|
+
summary = `Code looks good! Score: ${score}/100. Matches expected patterns.`;
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
const errorCount = violations.filter(v => v.severity === 'error').length;
|
|
158
|
+
const warningCount = violations.filter(v => v.severity === 'warning').length;
|
|
159
|
+
summary = `Score: ${score}/100. Found ${errorCount} error${errorCount !== 1 ? 's' : ''}, ${warningCount} warning${warningCount !== 1 ? 's' : ''}.`;
|
|
160
|
+
}
|
|
161
|
+
const hints = {
|
|
162
|
+
nextActions: violations.length > 0
|
|
163
|
+
? ['Fix violations before writing code', 'Use drift_code_examples to see correct patterns']
|
|
164
|
+
: ['Code is ready to write', 'Use drift_imports to add correct imports'],
|
|
165
|
+
relatedTools: ['drift_code_examples', 'drift_imports', 'drift_similar'],
|
|
166
|
+
};
|
|
167
|
+
if (violations.some(v => v.severity === 'error')) {
|
|
168
|
+
hints.warnings = ['Code has errors that should be fixed before writing'];
|
|
169
|
+
}
|
|
170
|
+
metrics.recordRequest('drift_prevalidate', Date.now() - startTime, true, false);
|
|
171
|
+
return builder
|
|
172
|
+
.withSummary(summary)
|
|
173
|
+
.withData(data)
|
|
174
|
+
.withHints(hints)
|
|
175
|
+
.buildContent();
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Find patterns relevant to a directory
|
|
179
|
+
*/
|
|
180
|
+
function findRelevantPatterns(store, targetDir, kind) {
|
|
181
|
+
const patterns = [];
|
|
182
|
+
// Get all patterns
|
|
183
|
+
const allPatterns = store.getAll();
|
|
184
|
+
for (const pattern of allPatterns) {
|
|
185
|
+
// Check if pattern has locations in target directory
|
|
186
|
+
const hasLocation = pattern.locations.some(loc => loc.file.startsWith(targetDir) || loc.file.includes(targetDir));
|
|
187
|
+
if (hasLocation) {
|
|
188
|
+
patterns.push({
|
|
189
|
+
name: pattern.name,
|
|
190
|
+
category: pattern.category,
|
|
191
|
+
subcategory: pattern.subcategory,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Also add patterns based on kind
|
|
196
|
+
if (kind === 'test') {
|
|
197
|
+
patterns.push({ name: 'testing-pattern', category: 'testing', subcategory: 'unit' });
|
|
198
|
+
}
|
|
199
|
+
else if (kind === 'component') {
|
|
200
|
+
patterns.push({ name: 'component-pattern', category: 'components', subcategory: 'react' });
|
|
201
|
+
}
|
|
202
|
+
return patterns;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Analyze code for common issues
|
|
206
|
+
*/
|
|
207
|
+
function analyzeCode(code, patterns, violations, suggestions) {
|
|
208
|
+
// Check for error handling patterns
|
|
209
|
+
const hasErrorPattern = patterns.some(p => p.category === 'errors' || p.name.includes('error') || p.name.includes('result'));
|
|
210
|
+
if (hasErrorPattern) {
|
|
211
|
+
// Check if code has try/catch or Result pattern
|
|
212
|
+
if (!code.includes('try') && !code.includes('catch') &&
|
|
213
|
+
!code.includes('Result') && !code.includes('.ok(') && !code.includes('.err(')) {
|
|
214
|
+
if (code.includes('async') || code.includes('await') || code.includes('Promise')) {
|
|
215
|
+
violations.push({
|
|
216
|
+
rule: 'error-handling',
|
|
217
|
+
severity: 'warning',
|
|
218
|
+
message: 'Async code without error handling - this codebase uses structured error handling',
|
|
219
|
+
suggestion: 'Add try/catch or use Result<T> pattern',
|
|
220
|
+
});
|
|
221
|
+
suggestions.push('Wrap async operations in try/catch');
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
// Check for raw SQL (if data-access patterns exist)
|
|
226
|
+
const hasDataPattern = patterns.some(p => p.category === 'data-access' || p.name.includes('prisma') || p.name.includes('orm'));
|
|
227
|
+
if (hasDataPattern) {
|
|
228
|
+
if (code.includes('SELECT') || code.includes('INSERT') ||
|
|
229
|
+
code.includes('UPDATE') || code.includes('DELETE')) {
|
|
230
|
+
violations.push({
|
|
231
|
+
rule: 'data-access',
|
|
232
|
+
severity: 'warning',
|
|
233
|
+
message: 'Raw SQL detected - this codebase uses an ORM',
|
|
234
|
+
suggestion: 'Use the ORM methods instead of raw SQL',
|
|
235
|
+
});
|
|
236
|
+
suggestions.push('Replace raw SQL with ORM calls');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Check for console.log in non-test code
|
|
240
|
+
if (code.includes('console.log') && !patterns.some(p => p.category === 'testing')) {
|
|
241
|
+
violations.push({
|
|
242
|
+
rule: 'logging',
|
|
243
|
+
severity: 'info',
|
|
244
|
+
message: 'console.log detected - consider using structured logging',
|
|
245
|
+
suggestion: 'Use logger.info() or similar',
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
// Check for any type
|
|
249
|
+
if (code.includes(': any') || code.includes('<any>')) {
|
|
250
|
+
violations.push({
|
|
251
|
+
rule: 'typing',
|
|
252
|
+
severity: 'warning',
|
|
253
|
+
message: 'Using "any" type reduces type safety',
|
|
254
|
+
suggestion: 'Use a specific type or "unknown"',
|
|
255
|
+
});
|
|
256
|
+
suggestions.push('Replace "any" with specific types');
|
|
257
|
+
}
|
|
258
|
+
// Check for hardcoded strings that look like config
|
|
259
|
+
const configPatterns = /['"](?:http|https):\/\/|['"](?:localhost|127\.0\.0\.1)|['"](?:api|secret|key|token)/i;
|
|
260
|
+
if (configPatterns.test(code)) {
|
|
261
|
+
violations.push({
|
|
262
|
+
rule: 'config',
|
|
263
|
+
severity: 'warning',
|
|
264
|
+
message: 'Hardcoded configuration detected',
|
|
265
|
+
suggestion: 'Use environment variables or config files',
|
|
266
|
+
});
|
|
267
|
+
suggestions.push('Move hardcoded values to configuration');
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Analyze code with IPatternService patterns
|
|
272
|
+
*/
|
|
273
|
+
function analyzeCodeWithPatterns(code, patterns, violations, suggestions) {
|
|
274
|
+
// Reuse the same analysis logic
|
|
275
|
+
analyzeCode(code, patterns, violations, suggestions);
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Tool definition for MCP registration
|
|
279
|
+
*/
|
|
280
|
+
export const prevalidateToolDefinition = {
|
|
281
|
+
name: 'drift_prevalidate',
|
|
282
|
+
description: 'Validate proposed code BEFORE writing it. Returns violations, score, and suggestions. Use to catch pattern violations before they happen.',
|
|
283
|
+
inputSchema: {
|
|
284
|
+
type: 'object',
|
|
285
|
+
properties: {
|
|
286
|
+
code: {
|
|
287
|
+
type: 'string',
|
|
288
|
+
description: 'The code to validate',
|
|
289
|
+
},
|
|
290
|
+
targetFile: {
|
|
291
|
+
type: 'string',
|
|
292
|
+
description: 'Where the code will be written (relative path)',
|
|
293
|
+
},
|
|
294
|
+
kind: {
|
|
295
|
+
type: 'string',
|
|
296
|
+
enum: ['function', 'class', 'component', 'test', 'full-file'],
|
|
297
|
+
description: 'What kind of code is this (default: function)',
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
required: ['code', 'targetFile'],
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
//# sourceMappingURL=prevalidate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prevalidate.js","sourceRoot":"","sources":["../../../src/tools/surgical/prevalidate.ts"],"names":[],"mappings":"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"}
|