vibecheck-mcp-server 2.0.1
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/README.md +191 -0
- package/agent-checkpoint.js +364 -0
- package/architect-tools.js +707 -0
- package/audit-mcp.js +206 -0
- package/codebase-architect-tools.js +838 -0
- package/guardrail-2.0-tools.js +748 -0
- package/guardrail-tools.js +1075 -0
- package/hygiene-tools.js +428 -0
- package/index-v1.js +698 -0
- package/index.js +1409 -0
- package/index.old.js +4137 -0
- package/intelligence-tools.js +664 -0
- package/intent-drift-tools.js +873 -0
- package/mdc-generator.js +298 -0
- package/package.json +47 -0
- package/premium-tools.js +1275 -0
- package/test-mcp.js +108 -0
- package/test-tools.js +36 -0
- package/tier-auth.js +147 -0
|
@@ -0,0 +1,707 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architect Agent MCP Tools
|
|
3
|
+
*
|
|
4
|
+
* Tools that let AI agents consult the Architect before writing code:
|
|
5
|
+
*
|
|
6
|
+
* 1. guardrail_architect_review - Review code against architecture patterns
|
|
7
|
+
* 2. guardrail_architect_suggest - Get suggestions before writing code
|
|
8
|
+
* 3. guardrail_architect_learn - Learn patterns from existing code
|
|
9
|
+
* 4. guardrail_architect_patterns - List active patterns
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from "fs";
|
|
13
|
+
import path from "path";
|
|
14
|
+
|
|
15
|
+
// Pattern types and their validation rules
|
|
16
|
+
const ARCHITECTURE_PATTERNS = {
|
|
17
|
+
// React patterns
|
|
18
|
+
react_import_order: {
|
|
19
|
+
name: "React Import Order",
|
|
20
|
+
description: "React imports first, then external, then internal",
|
|
21
|
+
check: (code) => {
|
|
22
|
+
const imports = code.match(/^import .+ from ['"][^'"]+['"];?$/gm) || [];
|
|
23
|
+
if (imports.length < 2) return { pass: true };
|
|
24
|
+
|
|
25
|
+
const reactIndex = imports.findIndex(
|
|
26
|
+
(i) => i.includes("'react'") || i.includes('"react"'),
|
|
27
|
+
);
|
|
28
|
+
if (reactIndex > 0) {
|
|
29
|
+
return {
|
|
30
|
+
pass: false,
|
|
31
|
+
message: "React imports should be at the top",
|
|
32
|
+
fix: "Move React imports to the beginning of the import block",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return { pass: true };
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
component_pascal_case: {
|
|
40
|
+
name: "PascalCase Components",
|
|
41
|
+
description: "React components must use PascalCase naming",
|
|
42
|
+
check: (code, filePath) => {
|
|
43
|
+
if (!filePath.match(/\.(jsx|tsx)$/)) return { pass: true };
|
|
44
|
+
|
|
45
|
+
const match = code.match(
|
|
46
|
+
/(?:function|const)\s+([a-z][a-zA-Z]*)\s*(?:=\s*\(|:\s*(?:React\.)?FC|\()/,
|
|
47
|
+
);
|
|
48
|
+
if (match && /^[a-z]/.test(match[1])) {
|
|
49
|
+
if (code.includes("return") && code.includes("<")) {
|
|
50
|
+
return {
|
|
51
|
+
pass: false,
|
|
52
|
+
message: `Component "${match[1]}" should use PascalCase`,
|
|
53
|
+
fix: `Rename to "${match[1].charAt(0).toUpperCase() + match[1].slice(1)}"`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return { pass: true };
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
hook_use_prefix: {
|
|
62
|
+
name: "Hook Naming",
|
|
63
|
+
description: 'Custom hooks must start with "use"',
|
|
64
|
+
check: (code, filePath) => {
|
|
65
|
+
if (!filePath.includes("hook") && !filePath.includes("use"))
|
|
66
|
+
return { pass: true };
|
|
67
|
+
|
|
68
|
+
const funcMatch = code.match(
|
|
69
|
+
/(?:function|const)\s+([a-zA-Z]+)\s*(?:=\s*\(|\()/,
|
|
70
|
+
);
|
|
71
|
+
if (funcMatch && !funcMatch[1].startsWith("use")) {
|
|
72
|
+
if (code.includes("useState") || code.includes("useEffect")) {
|
|
73
|
+
return {
|
|
74
|
+
pass: false,
|
|
75
|
+
message: `Custom hook "${funcMatch[1]}" must start with "use"`,
|
|
76
|
+
fix: `Rename to "use${funcMatch[1].charAt(0).toUpperCase() + funcMatch[1].slice(1)}"`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return { pass: true };
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
// TypeScript patterns
|
|
85
|
+
no_any_type: {
|
|
86
|
+
name: "No Any Type",
|
|
87
|
+
description: 'Avoid using "any" type',
|
|
88
|
+
check: (code) => {
|
|
89
|
+
if (code.match(/:\s*any\b/) && !code.includes("@ts-")) {
|
|
90
|
+
return {
|
|
91
|
+
pass: false,
|
|
92
|
+
message: 'Avoid using "any" type - use specific types',
|
|
93
|
+
fix: 'Replace "any" with a specific type or "unknown" for truly unknown types',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return { pass: true };
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
explicit_return_types: {
|
|
101
|
+
name: "Explicit Return Types",
|
|
102
|
+
description: "Functions should have explicit return types",
|
|
103
|
+
check: (code) => {
|
|
104
|
+
const asyncFuncs =
|
|
105
|
+
code.match(/(?:async\s+)?function\s+\w+\s*\([^)]*\)\s*\{/g) || [];
|
|
106
|
+
for (const func of asyncFuncs) {
|
|
107
|
+
if (!func.includes(":") && !func.includes("constructor")) {
|
|
108
|
+
return {
|
|
109
|
+
pass: false,
|
|
110
|
+
message: "Function missing return type annotation",
|
|
111
|
+
fix: "Add return type: function name(): ReturnType { ... }",
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return { pass: true };
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
// API patterns
|
|
120
|
+
api_error_handling: {
|
|
121
|
+
name: "API Error Handling",
|
|
122
|
+
description: "API routes must have try/catch",
|
|
123
|
+
check: (code, filePath) => {
|
|
124
|
+
if (!filePath.includes("api") && !filePath.includes("route"))
|
|
125
|
+
return { pass: true };
|
|
126
|
+
|
|
127
|
+
if (
|
|
128
|
+
code.includes("async") &&
|
|
129
|
+
(code.includes("req") || code.includes("request"))
|
|
130
|
+
) {
|
|
131
|
+
if (!code.includes("try") || !code.includes("catch")) {
|
|
132
|
+
return {
|
|
133
|
+
pass: false,
|
|
134
|
+
message: "API handler missing error handling",
|
|
135
|
+
fix: "Wrap handler logic in try/catch block",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return { pass: true };
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
// General patterns
|
|
144
|
+
no_console_in_production: {
|
|
145
|
+
name: "No Console Logs",
|
|
146
|
+
description: "Remove console.log from production code",
|
|
147
|
+
check: (code, filePath) => {
|
|
148
|
+
if (filePath.includes("test") || filePath.includes("spec"))
|
|
149
|
+
return { pass: true };
|
|
150
|
+
|
|
151
|
+
if (code.includes("console.log")) {
|
|
152
|
+
return {
|
|
153
|
+
pass: false,
|
|
154
|
+
message: "console.log found in production code",
|
|
155
|
+
fix: "Remove console.log or use a proper logging service",
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return { pass: true };
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
no_hardcoded_secrets: {
|
|
163
|
+
name: "No Hardcoded Secrets",
|
|
164
|
+
description: "API keys and secrets should use env vars",
|
|
165
|
+
check: (code) => {
|
|
166
|
+
const patterns = [
|
|
167
|
+
/['"]sk-[a-zA-Z0-9]{20,}['"]/, // OpenAI
|
|
168
|
+
/['"]ghp_[a-zA-Z0-9]{20,}['"]/, // GitHub
|
|
169
|
+
/['"]AKIA[A-Z0-9]{16}['"]/, // AWS
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
for (const pattern of patterns) {
|
|
173
|
+
if (pattern.test(code)) {
|
|
174
|
+
return {
|
|
175
|
+
pass: false,
|
|
176
|
+
message: "Hardcoded secret/API key detected",
|
|
177
|
+
fix: "Move secret to environment variable: process.env.SECRET_NAME",
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return { pass: true };
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
service_singleton: {
|
|
186
|
+
name: "Service Singleton",
|
|
187
|
+
description: "Services should export singleton instances",
|
|
188
|
+
check: (code, filePath) => {
|
|
189
|
+
if (!filePath.includes("service")) return { pass: true };
|
|
190
|
+
|
|
191
|
+
if (code.includes("class") && code.includes("Service")) {
|
|
192
|
+
if (!code.match(/export\s+(?:const|let)\s+\w+\s*=\s*new/)) {
|
|
193
|
+
return {
|
|
194
|
+
pass: false,
|
|
195
|
+
message: "Service should export a singleton instance",
|
|
196
|
+
fix: "Add: export const serviceName = new ServiceClass();",
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return { pass: true };
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// File type detection
|
|
206
|
+
function detectFileType(filePath, content) {
|
|
207
|
+
const fileName = path.basename(filePath);
|
|
208
|
+
const dirName = path.dirname(filePath);
|
|
209
|
+
|
|
210
|
+
if (fileName.includes(".test.") || fileName.includes(".spec.")) return "test";
|
|
211
|
+
if (fileName.includes("hook") || fileName.startsWith("use")) return "hook";
|
|
212
|
+
if (
|
|
213
|
+
dirName.includes("components") ||
|
|
214
|
+
(content.includes("return") && content.includes("<"))
|
|
215
|
+
)
|
|
216
|
+
return "component";
|
|
217
|
+
if (dirName.includes("api") || dirName.includes("routes")) return "api";
|
|
218
|
+
if (dirName.includes("services") || fileName.includes("service"))
|
|
219
|
+
return "service";
|
|
220
|
+
if (dirName.includes("utils") || dirName.includes("lib")) return "util";
|
|
221
|
+
if (fileName.includes(".d.ts") || dirName.includes("types")) return "type";
|
|
222
|
+
|
|
223
|
+
return "unknown";
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Framework detection
|
|
227
|
+
function detectFramework(content) {
|
|
228
|
+
if (content.includes("from 'react'") || content.includes('from "react"'))
|
|
229
|
+
return "react";
|
|
230
|
+
if (content.includes("from 'vue'")) return "vue";
|
|
231
|
+
if (content.includes("from 'svelte'")) return "svelte";
|
|
232
|
+
if (content.includes("from 'express'")) return "express";
|
|
233
|
+
if (content.includes("from 'next'")) return "next";
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Current project state
|
|
238
|
+
let projectPatterns = {};
|
|
239
|
+
let learnedPatterns = [];
|
|
240
|
+
let strictnessLevel = "standard"; // relaxed, standard, strict
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Review code against architecture patterns
|
|
244
|
+
*/
|
|
245
|
+
function reviewCode(filePath, content) {
|
|
246
|
+
const fileType = detectFileType(filePath, content);
|
|
247
|
+
const framework = detectFramework(content);
|
|
248
|
+
const violations = [];
|
|
249
|
+
const suggestions = [];
|
|
250
|
+
|
|
251
|
+
// Check all patterns
|
|
252
|
+
for (const [id, pattern] of Object.entries(ARCHITECTURE_PATTERNS)) {
|
|
253
|
+
const result = pattern.check(content, filePath);
|
|
254
|
+
if (!result.pass) {
|
|
255
|
+
violations.push({
|
|
256
|
+
pattern: id,
|
|
257
|
+
name: pattern.name,
|
|
258
|
+
message: result.message,
|
|
259
|
+
fix: result.fix,
|
|
260
|
+
severity:
|
|
261
|
+
id.includes("secret") || id.includes("error") ? "error" : "warning",
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Generate suggestions based on file type
|
|
267
|
+
if (fileType === "component" && framework === "react") {
|
|
268
|
+
if (
|
|
269
|
+
!content.includes("memo") &&
|
|
270
|
+
content.includes(".map(") &&
|
|
271
|
+
content.includes(".filter(")
|
|
272
|
+
) {
|
|
273
|
+
suggestions.push({
|
|
274
|
+
type: "performance",
|
|
275
|
+
title: "Consider useMemo",
|
|
276
|
+
description: "Complex computations could benefit from memoization",
|
|
277
|
+
code: "const processed = useMemo(() => data.filter(...).map(...), [data]);",
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (
|
|
282
|
+
content.includes("await") &&
|
|
283
|
+
!content.includes("loading") &&
|
|
284
|
+
!content.includes("isLoading")
|
|
285
|
+
) {
|
|
286
|
+
suggestions.push({
|
|
287
|
+
type: "ux",
|
|
288
|
+
title: "Add Loading State",
|
|
289
|
+
description: "Async operations should show loading state",
|
|
290
|
+
code: "const [isLoading, setIsLoading] = useState(false);",
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (fileType === "api") {
|
|
296
|
+
if (
|
|
297
|
+
!content.includes("validate") &&
|
|
298
|
+
!content.includes("zod") &&
|
|
299
|
+
!content.includes("yup")
|
|
300
|
+
) {
|
|
301
|
+
suggestions.push({
|
|
302
|
+
type: "security",
|
|
303
|
+
title: "Add Input Validation",
|
|
304
|
+
description: "API routes should validate input data",
|
|
305
|
+
code: "import { z } from 'zod';\nconst schema = z.object({ ... });",
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// Calculate score
|
|
311
|
+
let score = 100;
|
|
312
|
+
for (const v of violations) {
|
|
313
|
+
score -= v.severity === "error" ? 20 : 10;
|
|
314
|
+
}
|
|
315
|
+
score -= suggestions.length * 2;
|
|
316
|
+
score = Math.max(0, Math.min(100, score));
|
|
317
|
+
|
|
318
|
+
const approved =
|
|
319
|
+
strictnessLevel === "strict"
|
|
320
|
+
? violations.length === 0
|
|
321
|
+
: violations.filter((v) => v.severity === "error").length === 0;
|
|
322
|
+
|
|
323
|
+
return {
|
|
324
|
+
approved,
|
|
325
|
+
fileType,
|
|
326
|
+
framework,
|
|
327
|
+
score,
|
|
328
|
+
violations,
|
|
329
|
+
suggestions,
|
|
330
|
+
summary: approved
|
|
331
|
+
? `ā
Approved (${score}/100) - ${violations.length} warnings, ${suggestions.length} suggestions`
|
|
332
|
+
: `š BLOCKED (${score}/100) - ${violations.filter((v) => v.severity === "error").length} errors must be fixed`,
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Get suggestions before writing code
|
|
338
|
+
*/
|
|
339
|
+
function getSuggestions(intent, context) {
|
|
340
|
+
const suggestions = [];
|
|
341
|
+
|
|
342
|
+
// Based on intent (what they want to create)
|
|
343
|
+
if (intent.includes("component") || intent.includes("ui")) {
|
|
344
|
+
suggestions.push({
|
|
345
|
+
pattern: "React Component",
|
|
346
|
+
template: `interface Props {
|
|
347
|
+
// Define props here
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export function ComponentName({ prop }: Props) {
|
|
351
|
+
// 1. Hooks first
|
|
352
|
+
const [state, setState] = useState();
|
|
353
|
+
|
|
354
|
+
// 2. Event handlers
|
|
355
|
+
const handleClick = () => {};
|
|
356
|
+
|
|
357
|
+
// 3. Render
|
|
358
|
+
return (
|
|
359
|
+
<div>
|
|
360
|
+
{/* JSX */}
|
|
361
|
+
</div>
|
|
362
|
+
);
|
|
363
|
+
}`,
|
|
364
|
+
rules: [
|
|
365
|
+
"Use PascalCase for component name",
|
|
366
|
+
"Define Props interface",
|
|
367
|
+
"Hooks before handlers before return",
|
|
368
|
+
"Use named export for components",
|
|
369
|
+
],
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
if (intent.includes("hook") || intent.includes("use")) {
|
|
374
|
+
suggestions.push({
|
|
375
|
+
pattern: "Custom Hook",
|
|
376
|
+
template: `export function useHookName(param: Type) {
|
|
377
|
+
// 1. Internal state
|
|
378
|
+
const [state, setState] = useState();
|
|
379
|
+
|
|
380
|
+
// 2. Effects
|
|
381
|
+
useEffect(() => {
|
|
382
|
+
// Effect logic
|
|
383
|
+
}, [dependencies]);
|
|
384
|
+
|
|
385
|
+
// 3. Return value
|
|
386
|
+
return { state, actions };
|
|
387
|
+
}`,
|
|
388
|
+
rules: [
|
|
389
|
+
'Name must start with "use"',
|
|
390
|
+
"Return object or tuple",
|
|
391
|
+
"Document dependencies clearly",
|
|
392
|
+
],
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
if (
|
|
397
|
+
intent.includes("api") ||
|
|
398
|
+
intent.includes("endpoint") ||
|
|
399
|
+
intent.includes("route")
|
|
400
|
+
) {
|
|
401
|
+
suggestions.push({
|
|
402
|
+
pattern: "API Route",
|
|
403
|
+
template: `export async function handler(req: Request, res: Response) {
|
|
404
|
+
try {
|
|
405
|
+
// 1. Validate input
|
|
406
|
+
const data = schema.parse(req.body);
|
|
407
|
+
|
|
408
|
+
// 2. Business logic
|
|
409
|
+
const result = await service.process(data);
|
|
410
|
+
|
|
411
|
+
// 3. Return response
|
|
412
|
+
return res.json({ success: true, data: result });
|
|
413
|
+
|
|
414
|
+
} catch (error) {
|
|
415
|
+
console.error('API Error:', error);
|
|
416
|
+
return res.status(500).json({ error: 'Internal server error' });
|
|
417
|
+
}
|
|
418
|
+
}`,
|
|
419
|
+
rules: [
|
|
420
|
+
"Always wrap in try/catch",
|
|
421
|
+
"Validate input data",
|
|
422
|
+
"Return consistent response shape",
|
|
423
|
+
"Log errors properly",
|
|
424
|
+
],
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (intent.includes("service") || intent.includes("class")) {
|
|
429
|
+
suggestions.push({
|
|
430
|
+
pattern: "Service Class",
|
|
431
|
+
template: `class ServiceName {
|
|
432
|
+
private dependency: Dependency;
|
|
433
|
+
|
|
434
|
+
constructor(dependency: Dependency) {
|
|
435
|
+
this.dependency = dependency;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
async method(param: Type): Promise<Result> {
|
|
439
|
+
// Implementation
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// Export singleton
|
|
444
|
+
export const serviceName = new ServiceName(dependency);`,
|
|
445
|
+
rules: [
|
|
446
|
+
"Use dependency injection",
|
|
447
|
+
"Export singleton instance",
|
|
448
|
+
"Add explicit return types",
|
|
449
|
+
"Keep methods focused",
|
|
450
|
+
],
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
return suggestions;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* MCP Tool Definitions
|
|
459
|
+
*/
|
|
460
|
+
const ARCHITECT_TOOLS = [
|
|
461
|
+
{
|
|
462
|
+
name: "guardrail_architect_review",
|
|
463
|
+
description: `šļø ARCHITECT REVIEW - Review code against architecture patterns BEFORE committing.
|
|
464
|
+
|
|
465
|
+
Call this tool to check if code follows project architecture:
|
|
466
|
+
- Import ordering and structure
|
|
467
|
+
- Naming conventions (PascalCase, camelCase, use*)
|
|
468
|
+
- Error handling patterns
|
|
469
|
+
- TypeScript best practices
|
|
470
|
+
- Security patterns (no secrets, validation)
|
|
471
|
+
|
|
472
|
+
Returns: approval status, score, violations, and suggestions.
|
|
473
|
+
If blocked, you MUST fix the violations before proceeding.`,
|
|
474
|
+
inputSchema: {
|
|
475
|
+
type: "object",
|
|
476
|
+
properties: {
|
|
477
|
+
file_path: {
|
|
478
|
+
type: "string",
|
|
479
|
+
description: "Path to the file being reviewed",
|
|
480
|
+
},
|
|
481
|
+
content: {
|
|
482
|
+
type: "string",
|
|
483
|
+
description: "The code content to review",
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
required: ["file_path", "content"],
|
|
487
|
+
},
|
|
488
|
+
},
|
|
489
|
+
|
|
490
|
+
{
|
|
491
|
+
name: "guardrail_architect_suggest",
|
|
492
|
+
description: `š” ARCHITECT SUGGEST - Get architectural guidance BEFORE writing code.
|
|
493
|
+
|
|
494
|
+
Call this FIRST when you're about to create:
|
|
495
|
+
- A new component
|
|
496
|
+
- A new hook
|
|
497
|
+
- An API route
|
|
498
|
+
- A service class
|
|
499
|
+
- Any significant new code
|
|
500
|
+
|
|
501
|
+
Returns: recommended patterns, templates, and rules to follow.`,
|
|
502
|
+
inputSchema: {
|
|
503
|
+
type: "object",
|
|
504
|
+
properties: {
|
|
505
|
+
intent: {
|
|
506
|
+
type: "string",
|
|
507
|
+
description:
|
|
508
|
+
'What you want to create (e.g., "user profile component", "authentication hook", "payment API endpoint")',
|
|
509
|
+
},
|
|
510
|
+
context: {
|
|
511
|
+
type: "string",
|
|
512
|
+
description: "Additional context about the feature",
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
required: ["intent"],
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
|
|
519
|
+
{
|
|
520
|
+
name: "guardrail_architect_patterns",
|
|
521
|
+
description: `š List all active architecture patterns and their rules.`,
|
|
522
|
+
inputSchema: {
|
|
523
|
+
type: "object",
|
|
524
|
+
properties: {
|
|
525
|
+
category: {
|
|
526
|
+
type: "string",
|
|
527
|
+
enum: ["all", "react", "typescript", "api", "security"],
|
|
528
|
+
description: "Filter patterns by category",
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
|
|
534
|
+
{
|
|
535
|
+
name: "guardrail_architect_set_strictness",
|
|
536
|
+
description: `āļø Set architect strictness level:
|
|
537
|
+
- relaxed: Only block on critical issues
|
|
538
|
+
- standard: Block on errors, warn on issues
|
|
539
|
+
- strict: Block on any violation`,
|
|
540
|
+
inputSchema: {
|
|
541
|
+
type: "object",
|
|
542
|
+
properties: {
|
|
543
|
+
level: {
|
|
544
|
+
type: "string",
|
|
545
|
+
enum: ["relaxed", "standard", "strict"],
|
|
546
|
+
},
|
|
547
|
+
},
|
|
548
|
+
required: ["level"],
|
|
549
|
+
},
|
|
550
|
+
},
|
|
551
|
+
];
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Handle MCP tool calls
|
|
555
|
+
*/
|
|
556
|
+
async function handleArchitectTool(name, args) {
|
|
557
|
+
switch (name) {
|
|
558
|
+
case "guardrail_architect_review": {
|
|
559
|
+
const { file_path, content } = args;
|
|
560
|
+
const result = reviewCode(file_path, content);
|
|
561
|
+
|
|
562
|
+
let output = "\nšļø ARCHITECT REVIEW\n";
|
|
563
|
+
output += "ā".repeat(50) + "\n";
|
|
564
|
+
output += `File: ${file_path}\n`;
|
|
565
|
+
output += `Type: ${result.fileType} | Framework: ${result.framework || "none"}\n`;
|
|
566
|
+
output += `Score: ${result.score}/100\n\n`;
|
|
567
|
+
|
|
568
|
+
if (result.violations.length > 0) {
|
|
569
|
+
output += "ā VIOLATIONS:\n";
|
|
570
|
+
for (const v of result.violations) {
|
|
571
|
+
const icon = v.severity === "error" ? "š«" : "ā ļø";
|
|
572
|
+
output += `${icon} [${v.name}] ${v.message}\n`;
|
|
573
|
+
output += ` Fix: ${v.fix}\n\n`;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (result.suggestions.length > 0) {
|
|
578
|
+
output += "š” SUGGESTIONS:\n";
|
|
579
|
+
for (const s of result.suggestions) {
|
|
580
|
+
output += `⢠[${s.type}] ${s.title}\n`;
|
|
581
|
+
output += ` ${s.description}\n`;
|
|
582
|
+
if (s.code) {
|
|
583
|
+
output += ` Example: ${s.code}\n`;
|
|
584
|
+
}
|
|
585
|
+
output += "\n";
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
output += "ā".repeat(50) + "\n";
|
|
590
|
+
output += result.summary + "\n";
|
|
591
|
+
|
|
592
|
+
return {
|
|
593
|
+
content: [{ type: "text", text: output }],
|
|
594
|
+
isError: !result.approved,
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
case "guardrail_architect_suggest": {
|
|
599
|
+
const { intent, context } = args;
|
|
600
|
+
const suggestions = getSuggestions(intent, context || "");
|
|
601
|
+
|
|
602
|
+
let output = "\nš” ARCHITECT SUGGESTIONS\n";
|
|
603
|
+
output += "ā".repeat(50) + "\n";
|
|
604
|
+
output += `For: "${intent}"\n\n`;
|
|
605
|
+
|
|
606
|
+
for (const s of suggestions) {
|
|
607
|
+
output += `š ${s.pattern}\n\n`;
|
|
608
|
+
output += `Template:\n\`\`\`typescript\n${s.template}\n\`\`\`\n\n`;
|
|
609
|
+
output += `Rules to follow:\n`;
|
|
610
|
+
for (const rule of s.rules) {
|
|
611
|
+
output += ` ā ${rule}\n`;
|
|
612
|
+
}
|
|
613
|
+
output += "\n";
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
if (suggestions.length === 0) {
|
|
617
|
+
output += "No specific pattern suggestions for this intent.\n";
|
|
618
|
+
output += "General rules:\n";
|
|
619
|
+
output += " ā Use TypeScript with explicit types\n";
|
|
620
|
+
output += " ā Handle errors properly\n";
|
|
621
|
+
output += " ā Follow project naming conventions\n";
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
output += "ā".repeat(50) + "\n";
|
|
625
|
+
|
|
626
|
+
return {
|
|
627
|
+
content: [{ type: "text", text: output }],
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
case "guardrail_architect_patterns": {
|
|
632
|
+
const { category } = args;
|
|
633
|
+
|
|
634
|
+
let output = "\nš ARCHITECTURE PATTERNS\n";
|
|
635
|
+
output += "ā".repeat(50) + "\n";
|
|
636
|
+
output += `Strictness: ${strictnessLevel.toUpperCase()}\n\n`;
|
|
637
|
+
|
|
638
|
+
for (const [id, pattern] of Object.entries(ARCHITECTURE_PATTERNS)) {
|
|
639
|
+
if (category && category !== "all") {
|
|
640
|
+
if (
|
|
641
|
+
category === "react" &&
|
|
642
|
+
!id.includes("react") &&
|
|
643
|
+
!id.includes("component") &&
|
|
644
|
+
!id.includes("hook")
|
|
645
|
+
)
|
|
646
|
+
continue;
|
|
647
|
+
if (
|
|
648
|
+
category === "typescript" &&
|
|
649
|
+
!id.includes("type") &&
|
|
650
|
+
!id.includes("any")
|
|
651
|
+
)
|
|
652
|
+
continue;
|
|
653
|
+
if (category === "api" && !id.includes("api")) continue;
|
|
654
|
+
if (
|
|
655
|
+
category === "security" &&
|
|
656
|
+
!id.includes("secret") &&
|
|
657
|
+
!id.includes("console")
|
|
658
|
+
)
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
output += `⢠${pattern.name}\n`;
|
|
663
|
+
output += ` ${pattern.description}\n\n`;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
output += "ā".repeat(50) + "\n";
|
|
667
|
+
|
|
668
|
+
return {
|
|
669
|
+
content: [{ type: "text", text: output }],
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
case "guardrail_architect_set_strictness": {
|
|
674
|
+
const { level } = args;
|
|
675
|
+
strictnessLevel = level;
|
|
676
|
+
|
|
677
|
+
return {
|
|
678
|
+
content: [
|
|
679
|
+
{
|
|
680
|
+
type: "text",
|
|
681
|
+
text:
|
|
682
|
+
`šļø Architect strictness set to: ${level.toUpperCase()}\n\n` +
|
|
683
|
+
(level === "relaxed"
|
|
684
|
+
? "Only critical issues will block."
|
|
685
|
+
: level === "standard"
|
|
686
|
+
? "Errors block, warnings are reported."
|
|
687
|
+
: "All violations will block."),
|
|
688
|
+
},
|
|
689
|
+
],
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
default:
|
|
694
|
+
return {
|
|
695
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
696
|
+
isError: true,
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
export {
|
|
702
|
+
ARCHITECT_TOOLS,
|
|
703
|
+
handleArchitectTool,
|
|
704
|
+
reviewCode,
|
|
705
|
+
getSuggestions,
|
|
706
|
+
ARCHITECTURE_PATTERNS,
|
|
707
|
+
};
|