driftdetect-mcp 0.6.1 → 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,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_errors - Error Types Lookup
|
|
3
|
+
*
|
|
4
|
+
* Layer: Surgical
|
|
5
|
+
* Token Budget: 300 target, 800 max
|
|
6
|
+
*
|
|
7
|
+
* Returns custom error classes and error handling patterns.
|
|
8
|
+
* Solves: AI needs to know existing error types when adding error handling.
|
|
9
|
+
*/
|
|
10
|
+
import { createErrorHandlingAnalyzer } from 'driftdetect-core';
|
|
11
|
+
import { createResponseBuilder, Errors, metrics } from '../../infrastructure/index.js';
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Handler
|
|
14
|
+
// ============================================================================
|
|
15
|
+
export async function handleErrors(store, args, rootDir) {
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
const builder = createResponseBuilder();
|
|
18
|
+
const action = args.action ?? 'types';
|
|
19
|
+
const severityFilter = args.severity ?? 'medium';
|
|
20
|
+
const limit = args.limit ?? 20;
|
|
21
|
+
// Initialize call graph
|
|
22
|
+
await store.initialize();
|
|
23
|
+
const graph = store.getGraph();
|
|
24
|
+
if (!graph) {
|
|
25
|
+
throw Errors.custom('CALLGRAPH_NOT_BUILT', 'Call graph has not been built. Run "drift callgraph build" first.', ['drift_status']);
|
|
26
|
+
}
|
|
27
|
+
// Create error handling analyzer
|
|
28
|
+
const analyzer = createErrorHandlingAnalyzer({ rootDir });
|
|
29
|
+
analyzer.setCallGraph(graph);
|
|
30
|
+
let data;
|
|
31
|
+
switch (action) {
|
|
32
|
+
case 'types':
|
|
33
|
+
data = await getErrorTypes(graph, limit);
|
|
34
|
+
break;
|
|
35
|
+
case 'gaps':
|
|
36
|
+
data = getErrorGaps(analyzer, severityFilter, limit);
|
|
37
|
+
break;
|
|
38
|
+
case 'boundaries':
|
|
39
|
+
data = getErrorBoundaries(analyzer, limit);
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
throw Errors.invalidArgument('action', `Unknown action: ${action}`, 'Use: types, gaps, or boundaries');
|
|
43
|
+
}
|
|
44
|
+
// Build summary based on action
|
|
45
|
+
let summary;
|
|
46
|
+
switch (action) {
|
|
47
|
+
case 'types':
|
|
48
|
+
summary = data.errorTypes?.length
|
|
49
|
+
? `Found ${data.errorTypes.length} custom error types`
|
|
50
|
+
: 'No custom error types found';
|
|
51
|
+
break;
|
|
52
|
+
case 'gaps':
|
|
53
|
+
summary = data.gaps?.length
|
|
54
|
+
? `Found ${data.gaps.length} error handling gaps (${data.stats.criticalGaps ?? 0} critical)`
|
|
55
|
+
: 'No error handling gaps found';
|
|
56
|
+
break;
|
|
57
|
+
case 'boundaries':
|
|
58
|
+
summary = data.boundaries?.length
|
|
59
|
+
? `Found ${data.boundaries.length} error boundaries (avg coverage: ${data.stats.avgCoverage?.toFixed(0) ?? 0}%)`
|
|
60
|
+
: 'No error boundaries found';
|
|
61
|
+
break;
|
|
62
|
+
default:
|
|
63
|
+
summary = 'Error analysis complete';
|
|
64
|
+
}
|
|
65
|
+
// Record metrics
|
|
66
|
+
metrics.recordRequest('drift_errors', Date.now() - startTime, true, false);
|
|
67
|
+
return builder
|
|
68
|
+
.withSummary(summary)
|
|
69
|
+
.withData(data)
|
|
70
|
+
.withHints({
|
|
71
|
+
nextActions: getNextActions(action, data),
|
|
72
|
+
relatedTools: ['drift_error_handling', 'drift_signature', 'drift_imports'],
|
|
73
|
+
})
|
|
74
|
+
.buildContent();
|
|
75
|
+
}
|
|
76
|
+
// ============================================================================
|
|
77
|
+
// Action Handlers
|
|
78
|
+
// ============================================================================
|
|
79
|
+
async function getErrorTypes(graph, limit) {
|
|
80
|
+
const errorTypes = [];
|
|
81
|
+
// Find error classes from the call graph
|
|
82
|
+
// Look for classes that extend Error or have Error in name
|
|
83
|
+
for (const [, func] of graph.functions) {
|
|
84
|
+
// Check if this is a class constructor for an error
|
|
85
|
+
if (func.className && isErrorClass(func.className)) {
|
|
86
|
+
// Check if we already have this error type
|
|
87
|
+
if (!errorTypes.some(e => e.name === func.className)) {
|
|
88
|
+
errorTypes.push({
|
|
89
|
+
name: func.className,
|
|
90
|
+
file: func.file,
|
|
91
|
+
line: func.startLine,
|
|
92
|
+
extends: detectErrorBase(func),
|
|
93
|
+
properties: extractErrorProperties(func),
|
|
94
|
+
usages: countErrorUsages(graph, func.className),
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
// Also check for throw statements with custom errors
|
|
99
|
+
if (func.name === 'constructor' && func.className && isErrorClass(func.className)) {
|
|
100
|
+
if (!errorTypes.some(e => e.name === func.className)) {
|
|
101
|
+
errorTypes.push({
|
|
102
|
+
name: func.className,
|
|
103
|
+
file: func.file,
|
|
104
|
+
line: func.startLine,
|
|
105
|
+
extends: 'Error',
|
|
106
|
+
properties: extractErrorProperties(func),
|
|
107
|
+
usages: countErrorUsages(graph, func.className),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
// Sort by usages
|
|
113
|
+
errorTypes.sort((a, b) => b.usages - a.usages);
|
|
114
|
+
return {
|
|
115
|
+
action: 'types',
|
|
116
|
+
errorTypes: errorTypes.slice(0, limit),
|
|
117
|
+
stats: {
|
|
118
|
+
totalTypes: errorTypes.length,
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
function getErrorGaps(analyzer, severity, limit) {
|
|
123
|
+
// Build topology first
|
|
124
|
+
try {
|
|
125
|
+
analyzer.build();
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// Topology might already be built or graph issues
|
|
129
|
+
}
|
|
130
|
+
const gaps = analyzer.getGaps({
|
|
131
|
+
minSeverity: severity,
|
|
132
|
+
limit,
|
|
133
|
+
includeSuggestions: true,
|
|
134
|
+
});
|
|
135
|
+
const gapInfos = gaps.map((gap) => ({
|
|
136
|
+
function: gap.name,
|
|
137
|
+
file: gap.file,
|
|
138
|
+
line: gap.line,
|
|
139
|
+
gapType: gap.gapType,
|
|
140
|
+
severity: gap.severity,
|
|
141
|
+
suggestion: gap.suggestion,
|
|
142
|
+
}));
|
|
143
|
+
const criticalCount = gaps.filter((g) => g.severity === 'critical').length;
|
|
144
|
+
return {
|
|
145
|
+
action: 'gaps',
|
|
146
|
+
gaps: gapInfos,
|
|
147
|
+
stats: {
|
|
148
|
+
totalGaps: gaps.length,
|
|
149
|
+
criticalGaps: criticalCount,
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
function getErrorBoundaries(analyzer, limit) {
|
|
154
|
+
// Build topology first
|
|
155
|
+
try {
|
|
156
|
+
analyzer.build();
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// Topology might already be built or graph issues
|
|
160
|
+
}
|
|
161
|
+
const boundaries = analyzer.getBoundaries({ includeFramework: true });
|
|
162
|
+
const boundaryInfos = boundaries.slice(0, limit).map((b) => ({
|
|
163
|
+
function: b.name,
|
|
164
|
+
file: b.file,
|
|
165
|
+
line: b.line,
|
|
166
|
+
handledTypes: b.handledTypes,
|
|
167
|
+
coverage: b.coverage,
|
|
168
|
+
isFramework: b.isFrameworkBoundary,
|
|
169
|
+
}));
|
|
170
|
+
const avgCoverage = boundaries.length > 0
|
|
171
|
+
? boundaries.reduce((sum, b) => sum + b.coverage, 0) / boundaries.length
|
|
172
|
+
: 0;
|
|
173
|
+
return {
|
|
174
|
+
action: 'boundaries',
|
|
175
|
+
boundaries: boundaryInfos,
|
|
176
|
+
stats: {
|
|
177
|
+
totalBoundaries: boundaries.length,
|
|
178
|
+
avgCoverage,
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
// ============================================================================
|
|
183
|
+
// Helpers
|
|
184
|
+
// ============================================================================
|
|
185
|
+
function isErrorClass(name) {
|
|
186
|
+
const lower = name.toLowerCase();
|
|
187
|
+
return lower.includes('error') ||
|
|
188
|
+
lower.includes('exception') ||
|
|
189
|
+
lower.endsWith('err');
|
|
190
|
+
}
|
|
191
|
+
function detectErrorBase(func) {
|
|
192
|
+
// Try to detect what the error extends
|
|
193
|
+
if (func.extends)
|
|
194
|
+
return func.extends;
|
|
195
|
+
// Common patterns
|
|
196
|
+
const name = func.className?.toLowerCase() ?? '';
|
|
197
|
+
if (name.includes('http'))
|
|
198
|
+
return 'HttpError';
|
|
199
|
+
if (name.includes('validation'))
|
|
200
|
+
return 'ValidationError';
|
|
201
|
+
if (name.includes('auth'))
|
|
202
|
+
return 'AuthError';
|
|
203
|
+
if (name.includes('notfound'))
|
|
204
|
+
return 'NotFoundError';
|
|
205
|
+
return 'Error';
|
|
206
|
+
}
|
|
207
|
+
function extractErrorProperties(func) {
|
|
208
|
+
const props = [];
|
|
209
|
+
// Extract from parameters
|
|
210
|
+
if (func.parameters) {
|
|
211
|
+
for (const param of func.parameters) {
|
|
212
|
+
if (param !== 'message' && param !== 'options') {
|
|
213
|
+
props.push(param);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return props.slice(0, 5);
|
|
218
|
+
}
|
|
219
|
+
function countErrorUsages(graph, errorName) {
|
|
220
|
+
let count = 0;
|
|
221
|
+
for (const [, func] of graph.functions) {
|
|
222
|
+
// Check if function throws this error type
|
|
223
|
+
for (const call of func.calls ?? []) {
|
|
224
|
+
if (call.calleeName === errorName || call.calleeName?.includes(errorName)) {
|
|
225
|
+
count++;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return count;
|
|
230
|
+
}
|
|
231
|
+
function getNextActions(action, data) {
|
|
232
|
+
switch (action) {
|
|
233
|
+
case 'types':
|
|
234
|
+
return data.errorTypes?.length
|
|
235
|
+
? ['Use existing error types instead of creating new ones', 'Check error hierarchy for consistency']
|
|
236
|
+
: ['Consider creating custom error types for better error handling'];
|
|
237
|
+
case 'gaps':
|
|
238
|
+
return data.gaps?.length
|
|
239
|
+
? ['Address critical gaps first', 'Add try/catch blocks to unprotected functions']
|
|
240
|
+
: ['Error handling coverage looks good'];
|
|
241
|
+
case 'boundaries':
|
|
242
|
+
return data.boundaries?.length
|
|
243
|
+
? ['Review boundary coverage', 'Ensure all entry points have error boundaries']
|
|
244
|
+
: ['Consider adding error boundaries at API entry points'];
|
|
245
|
+
default:
|
|
246
|
+
return [];
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Tool definition for MCP registration
|
|
251
|
+
*/
|
|
252
|
+
export const errorsToolDefinition = {
|
|
253
|
+
name: 'drift_errors',
|
|
254
|
+
description: 'Find custom error types, error handling gaps, and error boundaries. Use action="types" for error classes, action="gaps" for missing error handling, action="boundaries" for catch locations.',
|
|
255
|
+
inputSchema: {
|
|
256
|
+
type: 'object',
|
|
257
|
+
properties: {
|
|
258
|
+
action: {
|
|
259
|
+
type: 'string',
|
|
260
|
+
enum: ['types', 'gaps', 'boundaries'],
|
|
261
|
+
description: 'What to look up: types (error classes), gaps (missing handling), boundaries (catch locations). Default: types',
|
|
262
|
+
},
|
|
263
|
+
severity: {
|
|
264
|
+
type: 'string',
|
|
265
|
+
enum: ['critical', 'high', 'medium', 'low'],
|
|
266
|
+
description: 'Minimum severity for gaps (default: medium)',
|
|
267
|
+
},
|
|
268
|
+
limit: {
|
|
269
|
+
type: 'number',
|
|
270
|
+
description: 'Max results to return (default: 20)',
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
};
|
|
275
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/tools/surgical/errors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_hooks - React/Vue Hooks Lookup
|
|
3
|
+
*
|
|
4
|
+
* Layer: Surgical
|
|
5
|
+
* Token Budget: 300 target, 800 max
|
|
6
|
+
*
|
|
7
|
+
* Returns custom hooks in the codebase.
|
|
8
|
+
* Solves: AI needs to know existing hooks before creating new ones.
|
|
9
|
+
*/
|
|
10
|
+
export interface HooksArgs {
|
|
11
|
+
/** Filter by category: state, fetch, effect, form, auth, all */
|
|
12
|
+
category?: 'state' | 'fetch' | 'effect' | 'form' | 'auth' | 'all';
|
|
13
|
+
/** Search by name pattern */
|
|
14
|
+
search?: string;
|
|
15
|
+
/** Max results */
|
|
16
|
+
limit?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface HookInfo {
|
|
19
|
+
name: string;
|
|
20
|
+
file: string;
|
|
21
|
+
line: number;
|
|
22
|
+
category: string;
|
|
23
|
+
usages: number;
|
|
24
|
+
dependencies: string[];
|
|
25
|
+
returnType?: string | undefined;
|
|
26
|
+
isAsync: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface HooksData {
|
|
29
|
+
hooks: HookInfo[];
|
|
30
|
+
byCategory: Record<string, number>;
|
|
31
|
+
stats: {
|
|
32
|
+
total: number;
|
|
33
|
+
customHooks: number;
|
|
34
|
+
mostUsed: string;
|
|
35
|
+
avgUsages: number;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export declare function handleHooks(args: HooksArgs, rootDir: string): Promise<{
|
|
39
|
+
content: Array<{
|
|
40
|
+
type: string;
|
|
41
|
+
text: string;
|
|
42
|
+
}>;
|
|
43
|
+
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Tool definition for MCP registration
|
|
46
|
+
*/
|
|
47
|
+
export declare const hooksToolDefinition: {
|
|
48
|
+
name: string;
|
|
49
|
+
description: string;
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: "object";
|
|
52
|
+
properties: {
|
|
53
|
+
category: {
|
|
54
|
+
type: string;
|
|
55
|
+
enum: string[];
|
|
56
|
+
description: string;
|
|
57
|
+
};
|
|
58
|
+
search: {
|
|
59
|
+
type: string;
|
|
60
|
+
description: string;
|
|
61
|
+
};
|
|
62
|
+
limit: {
|
|
63
|
+
type: string;
|
|
64
|
+
description: string;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/tools/surgical/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,WAAW,SAAS;IACxB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IAClE,6BAA6B;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kBAAkB;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAMD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;IAAE,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAiI7D;AAsHD;;GAEG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;CAqB/B,CAAC"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* drift_hooks - React/Vue Hooks Lookup
|
|
3
|
+
*
|
|
4
|
+
* Layer: Surgical
|
|
5
|
+
* Token Budget: 300 target, 800 max
|
|
6
|
+
*
|
|
7
|
+
* Returns custom hooks in the codebase.
|
|
8
|
+
* Solves: AI needs to know existing hooks before creating new ones.
|
|
9
|
+
*/
|
|
10
|
+
import { createWrapperScanner } from 'driftdetect-core/wrappers';
|
|
11
|
+
import { createResponseBuilder, metrics } from '../../infrastructure/index.js';
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Handler
|
|
14
|
+
// ============================================================================
|
|
15
|
+
export async function handleHooks(args, rootDir) {
|
|
16
|
+
const startTime = Date.now();
|
|
17
|
+
const builder = createResponseBuilder();
|
|
18
|
+
const categoryFilter = args.category ?? 'all';
|
|
19
|
+
const searchPattern = args.search?.toLowerCase();
|
|
20
|
+
const limit = args.limit ?? 20;
|
|
21
|
+
// Scan for wrappers
|
|
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
|
+
// Find hooks from wrappers
|
|
34
|
+
const hooksList = [];
|
|
35
|
+
// Check clusters for hook-related categories
|
|
36
|
+
const hookClusters = result.analysis.clusters.filter(c => c.category === 'state-management' ||
|
|
37
|
+
c.category === 'data-fetching' ||
|
|
38
|
+
c.category === 'side-effects' ||
|
|
39
|
+
c.category === 'form-handling' ||
|
|
40
|
+
c.category === 'authentication');
|
|
41
|
+
for (const cluster of hookClusters) {
|
|
42
|
+
for (const wrapper of cluster.wrappers) {
|
|
43
|
+
if (isHook(wrapper)) {
|
|
44
|
+
const hookCategory = categorizeHook(wrapper, cluster.category);
|
|
45
|
+
if (categoryFilter !== 'all' && hookCategory !== categoryFilter) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (searchPattern && !wrapper.name.toLowerCase().includes(searchPattern)) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
hooksList.push({
|
|
52
|
+
name: wrapper.name,
|
|
53
|
+
file: wrapper.file,
|
|
54
|
+
line: wrapper.line,
|
|
55
|
+
category: hookCategory,
|
|
56
|
+
usages: wrapper.calledBy.length,
|
|
57
|
+
dependencies: extractHookDependencies(wrapper),
|
|
58
|
+
returnType: wrapper.returnType,
|
|
59
|
+
isAsync: wrapper.isAsync,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Also scan all wrappers for hook patterns
|
|
65
|
+
for (const wrapper of result.analysis.wrappers) {
|
|
66
|
+
if (isHook(wrapper) && !hooksList.some(h => h.name === wrapper.name && h.file === wrapper.file)) {
|
|
67
|
+
const hookCategory = inferHookCategory(wrapper);
|
|
68
|
+
if (categoryFilter !== 'all' && hookCategory !== categoryFilter) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (searchPattern && !wrapper.name.toLowerCase().includes(searchPattern)) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
hooksList.push({
|
|
75
|
+
name: wrapper.name,
|
|
76
|
+
file: wrapper.file,
|
|
77
|
+
line: wrapper.line,
|
|
78
|
+
category: hookCategory,
|
|
79
|
+
usages: wrapper.calledBy.length,
|
|
80
|
+
dependencies: extractHookDependencies(wrapper),
|
|
81
|
+
returnType: wrapper.returnType,
|
|
82
|
+
isAsync: wrapper.isAsync,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Sort by usages and limit
|
|
87
|
+
hooksList.sort((a, b) => b.usages - a.usages);
|
|
88
|
+
const limited = hooksList.slice(0, limit);
|
|
89
|
+
// Calculate stats
|
|
90
|
+
const byCategory = {};
|
|
91
|
+
for (const hook of hooksList) {
|
|
92
|
+
byCategory[hook.category] = (byCategory[hook.category] ?? 0) + 1;
|
|
93
|
+
}
|
|
94
|
+
const totalUsages = hooksList.reduce((sum, h) => sum + h.usages, 0);
|
|
95
|
+
const mostUsed = hooksList[0]?.name ?? 'N/A';
|
|
96
|
+
const data = {
|
|
97
|
+
hooks: limited,
|
|
98
|
+
byCategory,
|
|
99
|
+
stats: {
|
|
100
|
+
total: hooksList.length,
|
|
101
|
+
customHooks: hooksList.filter(h => h.name.startsWith('use')).length,
|
|
102
|
+
mostUsed,
|
|
103
|
+
avgUsages: hooksList.length > 0 ? Math.round(totalUsages / hooksList.length) : 0,
|
|
104
|
+
},
|
|
105
|
+
};
|
|
106
|
+
// Build summary
|
|
107
|
+
const summary = hooksList.length > 0
|
|
108
|
+
? `Found ${hooksList.length} custom hooks. Most used: "${mostUsed}" (${hooksList[0]?.usages ?? 0} usages)`
|
|
109
|
+
: 'No custom hooks detected';
|
|
110
|
+
// Record metrics
|
|
111
|
+
metrics.recordRequest('drift_hooks', Date.now() - startTime, true, false);
|
|
112
|
+
return builder
|
|
113
|
+
.withSummary(summary)
|
|
114
|
+
.withData(data)
|
|
115
|
+
.withHints({
|
|
116
|
+
nextActions: hooksList.length > 0
|
|
117
|
+
? ['Check existing hooks before creating new ones', 'Consider composing existing hooks']
|
|
118
|
+
: ['No custom hooks found - consider extracting reusable logic into hooks'],
|
|
119
|
+
relatedTools: ['drift_wrappers', 'drift_signature', 'drift_imports'],
|
|
120
|
+
})
|
|
121
|
+
.buildContent();
|
|
122
|
+
}
|
|
123
|
+
// ============================================================================
|
|
124
|
+
// Helpers
|
|
125
|
+
// ============================================================================
|
|
126
|
+
function isHook(wrapper) {
|
|
127
|
+
// React/Vue hook naming convention
|
|
128
|
+
if (wrapper.name.startsWith('use') && wrapper.name.length > 3) {
|
|
129
|
+
const charAfterUse = wrapper.name[3];
|
|
130
|
+
// Must be followed by uppercase letter (useEffect, useState, etc.)
|
|
131
|
+
if (charAfterUse && charAfterUse === charAfterUse.toUpperCase()) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Check if it uses React hooks
|
|
136
|
+
const primitives = wrapper.primitiveSignature.join(' ').toLowerCase();
|
|
137
|
+
if (primitives.includes('usestate') ||
|
|
138
|
+
primitives.includes('useeffect') ||
|
|
139
|
+
primitives.includes('usecontext') ||
|
|
140
|
+
primitives.includes('usememo') ||
|
|
141
|
+
primitives.includes('usecallback') ||
|
|
142
|
+
primitives.includes('useref') ||
|
|
143
|
+
primitives.includes('usereducer')) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
// Vue composables
|
|
147
|
+
if (primitives.includes('ref(') ||
|
|
148
|
+
primitives.includes('reactive(') ||
|
|
149
|
+
primitives.includes('computed(') ||
|
|
150
|
+
primitives.includes('watch(') ||
|
|
151
|
+
primitives.includes('onmounted')) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
function categorizeHook(wrapper, clusterCategory) {
|
|
157
|
+
// Map cluster category to hook category
|
|
158
|
+
switch (clusterCategory) {
|
|
159
|
+
case 'state-management':
|
|
160
|
+
return 'state';
|
|
161
|
+
case 'data-fetching':
|
|
162
|
+
return 'fetch';
|
|
163
|
+
case 'side-effects':
|
|
164
|
+
return 'effect';
|
|
165
|
+
case 'form-handling':
|
|
166
|
+
return 'form';
|
|
167
|
+
case 'authentication':
|
|
168
|
+
return 'auth';
|
|
169
|
+
default:
|
|
170
|
+
return inferHookCategory(wrapper);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function inferHookCategory(wrapper) {
|
|
174
|
+
const name = wrapper.name.toLowerCase();
|
|
175
|
+
const primitives = wrapper.primitiveSignature.join(' ').toLowerCase();
|
|
176
|
+
// State management
|
|
177
|
+
if (name.includes('state') || name.includes('store') || name.includes('reducer') ||
|
|
178
|
+
primitives.includes('usestate') || primitives.includes('usereducer') ||
|
|
179
|
+
primitives.includes('zustand') || primitives.includes('redux') || primitives.includes('recoil')) {
|
|
180
|
+
return 'state';
|
|
181
|
+
}
|
|
182
|
+
// Data fetching
|
|
183
|
+
if (name.includes('fetch') || name.includes('query') || name.includes('data') ||
|
|
184
|
+
name.includes('api') || name.includes('request') ||
|
|
185
|
+
primitives.includes('fetch') || primitives.includes('axios') ||
|
|
186
|
+
primitives.includes('swr') || primitives.includes('react-query') || primitives.includes('tanstack')) {
|
|
187
|
+
return 'fetch';
|
|
188
|
+
}
|
|
189
|
+
// Side effects
|
|
190
|
+
if (name.includes('effect') || name.includes('subscription') || name.includes('listener') ||
|
|
191
|
+
primitives.includes('useeffect') || primitives.includes('uselayouteffect')) {
|
|
192
|
+
return 'effect';
|
|
193
|
+
}
|
|
194
|
+
// Form handling
|
|
195
|
+
if (name.includes('form') || name.includes('input') || name.includes('field') ||
|
|
196
|
+
primitives.includes('useform') || primitives.includes('formik') || primitives.includes('react-hook-form')) {
|
|
197
|
+
return 'form';
|
|
198
|
+
}
|
|
199
|
+
// Auth
|
|
200
|
+
if (name.includes('auth') || name.includes('user') || name.includes('session') ||
|
|
201
|
+
name.includes('login') || name.includes('permission')) {
|
|
202
|
+
return 'auth';
|
|
203
|
+
}
|
|
204
|
+
return 'other';
|
|
205
|
+
}
|
|
206
|
+
function extractHookDependencies(wrapper) {
|
|
207
|
+
const deps = [];
|
|
208
|
+
// Extract React hooks from primitives
|
|
209
|
+
for (const prim of wrapper.primitiveSignature) {
|
|
210
|
+
if (prim.startsWith('use') || prim.includes('use')) {
|
|
211
|
+
deps.push(prim);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// Also check direct primitives
|
|
215
|
+
for (const prim of wrapper.directPrimitives) {
|
|
216
|
+
if (prim.startsWith('use') && !deps.includes(prim)) {
|
|
217
|
+
deps.push(prim);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return deps.slice(0, 5); // Limit to 5 dependencies
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Tool definition for MCP registration
|
|
224
|
+
*/
|
|
225
|
+
export const hooksToolDefinition = {
|
|
226
|
+
name: 'drift_hooks',
|
|
227
|
+
description: 'Find custom React/Vue hooks in the codebase. Returns hook names, categories, usage counts, and dependencies.',
|
|
228
|
+
inputSchema: {
|
|
229
|
+
type: 'object',
|
|
230
|
+
properties: {
|
|
231
|
+
category: {
|
|
232
|
+
type: 'string',
|
|
233
|
+
enum: ['state', 'fetch', 'effect', 'form', 'auth', 'all'],
|
|
234
|
+
description: 'Filter by hook category (default: all)',
|
|
235
|
+
},
|
|
236
|
+
search: {
|
|
237
|
+
type: 'string',
|
|
238
|
+
description: 'Search hooks by name pattern',
|
|
239
|
+
},
|
|
240
|
+
limit: {
|
|
241
|
+
type: 'number',
|
|
242
|
+
description: 'Max results to return (default: 20)',
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../../src/tools/surgical/hooks.ts"],"names":[],"mappings":"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"}
|