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
package/index.js
ADDED
|
@@ -0,0 +1,1409 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* GUARDRAIL MCP Server v2.0 - Clean Product Surface
|
|
5
|
+
*
|
|
6
|
+
* 6 Public Tools (maps to CLI):
|
|
7
|
+
* guardrail.scan - Find truth
|
|
8
|
+
* guardrail.gate - Enforce truth in CI
|
|
9
|
+
* guardrail.fix - Apply safe patches
|
|
10
|
+
* guardrail.proof - Premium verification (mocks, reality)
|
|
11
|
+
* guardrail.report - Access artifacts
|
|
12
|
+
* guardrail.status - Health and config info
|
|
13
|
+
*
|
|
14
|
+
* Everything else is parameters on these tools.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
18
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
19
|
+
import {
|
|
20
|
+
CallToolRequestSchema,
|
|
21
|
+
ListToolsRequestSchema,
|
|
22
|
+
ListResourcesRequestSchema,
|
|
23
|
+
ReadResourceRequestSchema,
|
|
24
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
25
|
+
|
|
26
|
+
import fs from "fs/promises";
|
|
27
|
+
import path from "path";
|
|
28
|
+
import { fileURLToPath } from "url";
|
|
29
|
+
import { execSync } from "child_process";
|
|
30
|
+
|
|
31
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
32
|
+
const __dirname = path.dirname(__filename);
|
|
33
|
+
|
|
34
|
+
const VERSION = "2.1.0";
|
|
35
|
+
|
|
36
|
+
// Import intelligence tools
|
|
37
|
+
import {
|
|
38
|
+
INTELLIGENCE_TOOLS,
|
|
39
|
+
handleIntelligenceTool,
|
|
40
|
+
} from "./intelligence-tools.js";
|
|
41
|
+
|
|
42
|
+
// Import AI guardrail tools
|
|
43
|
+
import {
|
|
44
|
+
GUARDRAIL_TOOLS,
|
|
45
|
+
handleGuardrailTool,
|
|
46
|
+
} from "./guardrail-tools.js";
|
|
47
|
+
|
|
48
|
+
// Import agent checkpoint tools
|
|
49
|
+
import {
|
|
50
|
+
AGENT_CHECKPOINT_TOOLS,
|
|
51
|
+
handleCheckpointTool,
|
|
52
|
+
} from "./agent-checkpoint.js";
|
|
53
|
+
|
|
54
|
+
// Import architect tools
|
|
55
|
+
import {
|
|
56
|
+
ARCHITECT_TOOLS,
|
|
57
|
+
handleArchitectTool,
|
|
58
|
+
} from "./architect-tools.js";
|
|
59
|
+
|
|
60
|
+
// Import codebase architect tools
|
|
61
|
+
import {
|
|
62
|
+
CODEBASE_ARCHITECT_TOOLS,
|
|
63
|
+
handleCodebaseArchitectTool,
|
|
64
|
+
} from "./codebase-architect-tools.js";
|
|
65
|
+
|
|
66
|
+
// Import guardrail 2.0 tools
|
|
67
|
+
import {
|
|
68
|
+
GUARDRAIL_2_TOOLS,
|
|
69
|
+
handleGuardrail2Tool,
|
|
70
|
+
} from "./guardrail-2.0-tools.js";
|
|
71
|
+
|
|
72
|
+
// Import intent drift tools
|
|
73
|
+
import {
|
|
74
|
+
intentDriftTools,
|
|
75
|
+
} from "./intent-drift-tools.js";
|
|
76
|
+
|
|
77
|
+
// Import audit trail for MCP
|
|
78
|
+
import { emitToolInvoke, emitToolComplete } from "./audit-mcp.js";
|
|
79
|
+
|
|
80
|
+
// Import MDC generator
|
|
81
|
+
import { mdcGeneratorTool, handleMDCGeneration } from "./mdc-generator.js";
|
|
82
|
+
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// TOOL DEFINITIONS - Public Tools (Clean Product Surface)
|
|
85
|
+
// ============================================================================
|
|
86
|
+
|
|
87
|
+
const TOOLS = [
|
|
88
|
+
...INTELLIGENCE_TOOLS, // Add all intelligence suite tools
|
|
89
|
+
...GUARDRAIL_TOOLS, // Add AI guardrail tools (verify, quality, smells, etc.)
|
|
90
|
+
...AGENT_CHECKPOINT_TOOLS, // Add agent checkpoint tools
|
|
91
|
+
...ARCHITECT_TOOLS, // Add architect review/suggest tools
|
|
92
|
+
...CODEBASE_ARCHITECT_TOOLS, // Add codebase-aware architect tools
|
|
93
|
+
...GUARDRAIL_2_TOOLS, // Add guardrail 2.0 consolidated tools
|
|
94
|
+
...intentDriftTools, // Add intent drift guard tools
|
|
95
|
+
mdcGeneratorTool, // Add MDC generator tool
|
|
96
|
+
// 1. SHIP - Quick health check (vibe coder friendly)
|
|
97
|
+
{
|
|
98
|
+
name: "guardrail.ship",
|
|
99
|
+
description:
|
|
100
|
+
"š Quick health check ā 'Is my app ready?' Plain English, traffic light score",
|
|
101
|
+
inputSchema: {
|
|
102
|
+
type: "object",
|
|
103
|
+
properties: {
|
|
104
|
+
projectPath: {
|
|
105
|
+
type: "string",
|
|
106
|
+
description: "Path to project root",
|
|
107
|
+
default: ".",
|
|
108
|
+
},
|
|
109
|
+
fix: {
|
|
110
|
+
type: "boolean",
|
|
111
|
+
description: "Auto-fix problems where possible",
|
|
112
|
+
default: false,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
// 2. SCAN - Deep technical analysis
|
|
119
|
+
{
|
|
120
|
+
name: "guardrail.scan",
|
|
121
|
+
description:
|
|
122
|
+
"š Deep scan ā technical analysis of secrets, auth, mocks, routes (detailed output)",
|
|
123
|
+
inputSchema: {
|
|
124
|
+
type: "object",
|
|
125
|
+
properties: {
|
|
126
|
+
projectPath: {
|
|
127
|
+
type: "string",
|
|
128
|
+
description: "Path to project root",
|
|
129
|
+
default: ".",
|
|
130
|
+
},
|
|
131
|
+
profile: {
|
|
132
|
+
type: "string",
|
|
133
|
+
enum: ["quick", "full", "ship", "ci", "security", "compliance", "ai"],
|
|
134
|
+
description:
|
|
135
|
+
"Check profile: quick, full, ship, ci, security, compliance, ai",
|
|
136
|
+
default: "quick",
|
|
137
|
+
},
|
|
138
|
+
only: {
|
|
139
|
+
type: "array",
|
|
140
|
+
items: { type: "string" },
|
|
141
|
+
description:
|
|
142
|
+
"Run only specific checks: integrity, security, hygiene, contracts, auth, routes, mocks, compliance, ai",
|
|
143
|
+
},
|
|
144
|
+
format: {
|
|
145
|
+
type: "string",
|
|
146
|
+
enum: ["text", "json", "html", "sarif"],
|
|
147
|
+
description: "Output format",
|
|
148
|
+
default: "text",
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
|
|
154
|
+
// 3. REALITY - Browser testing
|
|
155
|
+
{
|
|
156
|
+
name: "guardrail.reality",
|
|
157
|
+
description:
|
|
158
|
+
"š§Ŗ Browser testing ā clicks buttons, fills forms, finds broken UI with Playwright",
|
|
159
|
+
inputSchema: {
|
|
160
|
+
type: "object",
|
|
161
|
+
properties: {
|
|
162
|
+
url: {
|
|
163
|
+
type: "string",
|
|
164
|
+
description: "Target URL to test (required)",
|
|
165
|
+
},
|
|
166
|
+
auth: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Auth credentials (email:password)",
|
|
169
|
+
},
|
|
170
|
+
flows: {
|
|
171
|
+
type: "array",
|
|
172
|
+
items: { type: "string" },
|
|
173
|
+
description: "Flow packs to test: auth, ui, forms, ecommerce",
|
|
174
|
+
},
|
|
175
|
+
headed: {
|
|
176
|
+
type: "boolean",
|
|
177
|
+
description: "Run browser in visible mode",
|
|
178
|
+
default: false,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
required: ["url"],
|
|
182
|
+
},
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
// 4. AI-TEST - AI Agent testing
|
|
186
|
+
{
|
|
187
|
+
name: "guardrail.ai-test",
|
|
188
|
+
description:
|
|
189
|
+
"š¤ AI Agent ā autonomous testing that explores your app and generates fix prompts",
|
|
190
|
+
inputSchema: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: {
|
|
193
|
+
url: {
|
|
194
|
+
type: "string",
|
|
195
|
+
description: "Target URL to test (required)",
|
|
196
|
+
},
|
|
197
|
+
goal: {
|
|
198
|
+
type: "string",
|
|
199
|
+
description: "Natural language goal for the AI agent",
|
|
200
|
+
default: "Test all features and find issues",
|
|
201
|
+
},
|
|
202
|
+
headed: {
|
|
203
|
+
type: "boolean",
|
|
204
|
+
description: "Run browser in visible mode",
|
|
205
|
+
default: false,
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
required: ["url"],
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
|
|
212
|
+
// 2. GATE - Enforce truth in CI
|
|
213
|
+
{
|
|
214
|
+
name: "guardrail.gate",
|
|
215
|
+
description: "š¦ Enforce truth in CI ā fail builds on policy violations",
|
|
216
|
+
inputSchema: {
|
|
217
|
+
type: "object",
|
|
218
|
+
properties: {
|
|
219
|
+
projectPath: {
|
|
220
|
+
type: "string",
|
|
221
|
+
default: ".",
|
|
222
|
+
},
|
|
223
|
+
policy: {
|
|
224
|
+
type: "string",
|
|
225
|
+
enum: ["default", "strict", "ci"],
|
|
226
|
+
description: "Policy strictness level",
|
|
227
|
+
default: "strict",
|
|
228
|
+
},
|
|
229
|
+
sarif: {
|
|
230
|
+
type: "boolean",
|
|
231
|
+
description: "Generate SARIF for GitHub Code Scanning",
|
|
232
|
+
default: true,
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
// 3. FIX - Apply safe patches
|
|
239
|
+
{
|
|
240
|
+
name: "guardrail.fix",
|
|
241
|
+
description: "š§ Apply safe patches ā preview plan then apply fixes",
|
|
242
|
+
inputSchema: {
|
|
243
|
+
type: "object",
|
|
244
|
+
properties: {
|
|
245
|
+
projectPath: {
|
|
246
|
+
type: "string",
|
|
247
|
+
default: ".",
|
|
248
|
+
},
|
|
249
|
+
plan: {
|
|
250
|
+
type: "boolean",
|
|
251
|
+
description: "Show fix plan without applying (dry run)",
|
|
252
|
+
default: true,
|
|
253
|
+
},
|
|
254
|
+
apply: {
|
|
255
|
+
type: "boolean",
|
|
256
|
+
description: "Apply fixes from plan",
|
|
257
|
+
default: false,
|
|
258
|
+
},
|
|
259
|
+
scope: {
|
|
260
|
+
type: "string",
|
|
261
|
+
enum: ["all", "secrets", "auth", "mocks", "routes"],
|
|
262
|
+
description: "Fix scope",
|
|
263
|
+
default: "all",
|
|
264
|
+
},
|
|
265
|
+
risk: {
|
|
266
|
+
type: "string",
|
|
267
|
+
enum: ["safe", "moderate", "aggressive"],
|
|
268
|
+
description: "Risk tolerance for auto-fixes",
|
|
269
|
+
default: "safe",
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
|
|
275
|
+
// 4. PROOF - Premium verification
|
|
276
|
+
{
|
|
277
|
+
name: "guardrail.proof",
|
|
278
|
+
description:
|
|
279
|
+
"š¬ Premium verification ā mocks (static) or reality (runtime with Playwright)",
|
|
280
|
+
inputSchema: {
|
|
281
|
+
type: "object",
|
|
282
|
+
properties: {
|
|
283
|
+
projectPath: {
|
|
284
|
+
type: "string",
|
|
285
|
+
default: ".",
|
|
286
|
+
},
|
|
287
|
+
mode: {
|
|
288
|
+
type: "string",
|
|
289
|
+
enum: ["mocks", "reality"],
|
|
290
|
+
description:
|
|
291
|
+
"Proof mode: mocks (import graph + fake domains) or reality (Playwright runtime)",
|
|
292
|
+
},
|
|
293
|
+
url: {
|
|
294
|
+
type: "string",
|
|
295
|
+
description: "Base URL for reality mode",
|
|
296
|
+
default: "http://localhost:3000",
|
|
297
|
+
},
|
|
298
|
+
flow: {
|
|
299
|
+
type: "string",
|
|
300
|
+
enum: ["auth", "checkout", "dashboard"],
|
|
301
|
+
description: "Flow to test in reality mode",
|
|
302
|
+
default: "auth",
|
|
303
|
+
},
|
|
304
|
+
},
|
|
305
|
+
required: ["mode"],
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
// 5. REPORT - Access artifacts
|
|
310
|
+
{
|
|
311
|
+
name: "guardrail.validate",
|
|
312
|
+
description:
|
|
313
|
+
"š¤ Validate AI-generated code. Checks for hallucinations, intent mismatch, and quality issues.",
|
|
314
|
+
inputSchema: {
|
|
315
|
+
type: "object",
|
|
316
|
+
properties: {
|
|
317
|
+
code: { type: "string", description: "The code content to validate" },
|
|
318
|
+
intent: {
|
|
319
|
+
type: "string",
|
|
320
|
+
description: "The user's original request/intent",
|
|
321
|
+
},
|
|
322
|
+
projectPath: { type: "string", default: "." },
|
|
323
|
+
},
|
|
324
|
+
required: ["code"],
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
name: "guardrail.report",
|
|
329
|
+
description:
|
|
330
|
+
"š Access scan artifacts ā summary, full report, SARIF export",
|
|
331
|
+
inputSchema: {
|
|
332
|
+
type: "object",
|
|
333
|
+
properties: {
|
|
334
|
+
projectPath: {
|
|
335
|
+
type: "string",
|
|
336
|
+
default: ".",
|
|
337
|
+
},
|
|
338
|
+
type: {
|
|
339
|
+
type: "string",
|
|
340
|
+
enum: ["summary", "full", "sarif", "html"],
|
|
341
|
+
description: "Report type to retrieve",
|
|
342
|
+
default: "summary",
|
|
343
|
+
},
|
|
344
|
+
runId: {
|
|
345
|
+
type: "string",
|
|
346
|
+
description: "Specific run ID (defaults to last run)",
|
|
347
|
+
},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
|
|
352
|
+
// 6. STATUS - Health and config
|
|
353
|
+
{
|
|
354
|
+
name: "guardrail.status",
|
|
355
|
+
description: "š Server status ā health, versions, config, last run info",
|
|
356
|
+
inputSchema: {
|
|
357
|
+
type: "object",
|
|
358
|
+
properties: {
|
|
359
|
+
projectPath: {
|
|
360
|
+
type: "string",
|
|
361
|
+
default: ".",
|
|
362
|
+
},
|
|
363
|
+
},
|
|
364
|
+
},
|
|
365
|
+
},
|
|
366
|
+
|
|
367
|
+
// 7. AUTOPILOT - Continuous protection
|
|
368
|
+
{
|
|
369
|
+
name: "guardrail.autopilot",
|
|
370
|
+
description:
|
|
371
|
+
"š¤ Autopilot ā continuous protection with weekly reports, auto-PRs, deploy blocking",
|
|
372
|
+
inputSchema: {
|
|
373
|
+
type: "object",
|
|
374
|
+
properties: {
|
|
375
|
+
projectPath: {
|
|
376
|
+
type: "string",
|
|
377
|
+
default: ".",
|
|
378
|
+
},
|
|
379
|
+
action: {
|
|
380
|
+
type: "string",
|
|
381
|
+
enum: ["status", "enable", "disable", "digest"],
|
|
382
|
+
description: "Autopilot action",
|
|
383
|
+
default: "status",
|
|
384
|
+
},
|
|
385
|
+
slack: {
|
|
386
|
+
type: "string",
|
|
387
|
+
description: "Slack webhook URL for notifications",
|
|
388
|
+
},
|
|
389
|
+
email: {
|
|
390
|
+
type: "string",
|
|
391
|
+
description: "Email for weekly digest",
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
// 8. AUTOPILOT PLAN - Generate fix plan (Pro/Compliance)
|
|
398
|
+
{
|
|
399
|
+
name: "guardrail.autopilot_plan",
|
|
400
|
+
description:
|
|
401
|
+
"š¤ Autopilot Plan ā scan codebase, group issues into fix packs, estimate risk (Pro/Compliance)",
|
|
402
|
+
inputSchema: {
|
|
403
|
+
type: "object",
|
|
404
|
+
properties: {
|
|
405
|
+
projectPath: {
|
|
406
|
+
type: "string",
|
|
407
|
+
default: ".",
|
|
408
|
+
},
|
|
409
|
+
profile: {
|
|
410
|
+
type: "string",
|
|
411
|
+
enum: ["quick", "full", "ship", "ci"],
|
|
412
|
+
description: "Scan profile",
|
|
413
|
+
default: "ship",
|
|
414
|
+
},
|
|
415
|
+
maxFixes: {
|
|
416
|
+
type: "number",
|
|
417
|
+
description: "Max fixes per category",
|
|
418
|
+
default: 10,
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
},
|
|
422
|
+
},
|
|
423
|
+
|
|
424
|
+
// 9. AUTOPILOT APPLY - Apply fixes (Pro/Compliance)
|
|
425
|
+
{
|
|
426
|
+
name: "guardrail.autopilot_apply",
|
|
427
|
+
description:
|
|
428
|
+
"š§ Autopilot Apply ā apply fix packs with verification, re-scan to confirm (Pro/Compliance)",
|
|
429
|
+
inputSchema: {
|
|
430
|
+
type: "object",
|
|
431
|
+
properties: {
|
|
432
|
+
projectPath: {
|
|
433
|
+
type: "string",
|
|
434
|
+
default: ".",
|
|
435
|
+
},
|
|
436
|
+
profile: {
|
|
437
|
+
type: "string",
|
|
438
|
+
enum: ["quick", "full", "ship", "ci"],
|
|
439
|
+
description: "Scan profile",
|
|
440
|
+
default: "ship",
|
|
441
|
+
},
|
|
442
|
+
maxFixes: {
|
|
443
|
+
type: "number",
|
|
444
|
+
description: "Max fixes per category",
|
|
445
|
+
default: 10,
|
|
446
|
+
},
|
|
447
|
+
verify: {
|
|
448
|
+
type: "boolean",
|
|
449
|
+
description: "Run verification after apply",
|
|
450
|
+
default: true,
|
|
451
|
+
},
|
|
452
|
+
dryRun: {
|
|
453
|
+
type: "boolean",
|
|
454
|
+
description: "Preview changes without applying",
|
|
455
|
+
default: false,
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
},
|
|
459
|
+
},
|
|
460
|
+
|
|
461
|
+
// 10. BADGE - Generate ship badge
|
|
462
|
+
{
|
|
463
|
+
name: "guardrail.badge",
|
|
464
|
+
description:
|
|
465
|
+
"š
Ship Badge ā generate a badge for README/PR showing scan status",
|
|
466
|
+
inputSchema: {
|
|
467
|
+
type: "object",
|
|
468
|
+
properties: {
|
|
469
|
+
projectPath: {
|
|
470
|
+
type: "string",
|
|
471
|
+
default: ".",
|
|
472
|
+
},
|
|
473
|
+
format: {
|
|
474
|
+
type: "string",
|
|
475
|
+
enum: ["svg", "md", "html"],
|
|
476
|
+
description: "Badge format",
|
|
477
|
+
default: "svg",
|
|
478
|
+
},
|
|
479
|
+
style: {
|
|
480
|
+
type: "string",
|
|
481
|
+
enum: ["flat", "flat-square"],
|
|
482
|
+
description: "Badge style",
|
|
483
|
+
default: "flat",
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
|
|
489
|
+
// 9. CONTEXT - AI Rules Generator
|
|
490
|
+
{
|
|
491
|
+
name: "guardrail.context",
|
|
492
|
+
description:
|
|
493
|
+
"š§ AI Context ā generate rules files for Cursor, Windsurf, Copilot to understand your codebase",
|
|
494
|
+
inputSchema: {
|
|
495
|
+
type: "object",
|
|
496
|
+
properties: {
|
|
497
|
+
projectPath: {
|
|
498
|
+
type: "string",
|
|
499
|
+
description: "Path to project root",
|
|
500
|
+
default: ".",
|
|
501
|
+
},
|
|
502
|
+
platform: {
|
|
503
|
+
type: "string",
|
|
504
|
+
enum: ["all", "cursor", "windsurf", "copilot", "claude"],
|
|
505
|
+
description: "Target platform (default: all)",
|
|
506
|
+
default: "all",
|
|
507
|
+
},
|
|
508
|
+
},
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
];
|
|
512
|
+
|
|
513
|
+
// ============================================================================
|
|
514
|
+
// SERVER IMPLEMENTATION
|
|
515
|
+
// ============================================================================
|
|
516
|
+
|
|
517
|
+
class GuardrailMCP {
|
|
518
|
+
constructor() {
|
|
519
|
+
this.server = new Server(
|
|
520
|
+
{ name: "guardrail", version: VERSION },
|
|
521
|
+
{ capabilities: { tools: {}, resources: {} } },
|
|
522
|
+
);
|
|
523
|
+
this.setupHandlers();
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
setupHandlers() {
|
|
527
|
+
// List tools
|
|
528
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
529
|
+
tools: TOOLS,
|
|
530
|
+
}));
|
|
531
|
+
|
|
532
|
+
// Call tool
|
|
533
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
534
|
+
const { name, arguments: args } = request.params;
|
|
535
|
+
const projectPath = path.resolve(args?.projectPath || ".");
|
|
536
|
+
const startTime = Date.now();
|
|
537
|
+
|
|
538
|
+
// Emit audit event for tool invocation start
|
|
539
|
+
emitToolInvoke(name, args, "success", { projectPath });
|
|
540
|
+
|
|
541
|
+
try {
|
|
542
|
+
// Handle intelligence tools first
|
|
543
|
+
if (name.startsWith("guardrail.intelligence.")) {
|
|
544
|
+
return await handleIntelligenceTool(name, args, __dirname);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Handle AI guardrail tools (verify, quality, smells, hallucination, breaking, mdc, coverage)
|
|
548
|
+
if (["guardrail.verify", "guardrail.quality", "guardrail.smells",
|
|
549
|
+
"guardrail.hallucination", "guardrail.breaking", "guardrail.mdc",
|
|
550
|
+
"guardrail.coverage"].includes(name)) {
|
|
551
|
+
const result = await handleGuardrailTool(name, args);
|
|
552
|
+
return {
|
|
553
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Handle agent checkpoint tools
|
|
558
|
+
if (["guardrail_checkpoint", "guardrail_set_strictness", "guardrail_checkpoint_status"].includes(name)) {
|
|
559
|
+
return await handleCheckpointTool(name, args);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Handle architect tools
|
|
563
|
+
if (["guardrail_architect_review", "guardrail_architect_suggest",
|
|
564
|
+
"guardrail_architect_patterns", "guardrail_architect_set_strictness"].includes(name)) {
|
|
565
|
+
return await handleArchitectTool(name, args);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Handle codebase architect tools
|
|
569
|
+
if (["guardrail_architect_context", "guardrail_architect_guide",
|
|
570
|
+
"guardrail_architect_validate", "guardrail_architect_patterns",
|
|
571
|
+
"guardrail_architect_dependencies"].includes(name)) {
|
|
572
|
+
return await handleCodebaseArchitectTool(name, args);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// Handle guardrail 2.0 tools
|
|
576
|
+
if (["checkpoint", "check", "ship", "fix", "status", "set_strictness"].includes(name)) {
|
|
577
|
+
return await handleGuardrail2Tool(name, args, __dirname);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Handle intent drift tools
|
|
581
|
+
if (name.startsWith("guardrail_intent_")) {
|
|
582
|
+
const tool = intentDriftTools.find(t => t.name === name);
|
|
583
|
+
if (tool && tool.handler) {
|
|
584
|
+
const result = await tool.handler(args);
|
|
585
|
+
return {
|
|
586
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
switch (name) {
|
|
592
|
+
case "guardrail.ship":
|
|
593
|
+
return await this.handleShip(projectPath, args);
|
|
594
|
+
case "guardrail.scan":
|
|
595
|
+
return await this.handleScan(projectPath, args);
|
|
596
|
+
case "guardrail.reality":
|
|
597
|
+
return await this.handleReality(projectPath, args);
|
|
598
|
+
case "guardrail.ai-test":
|
|
599
|
+
return await this.handleAITest(projectPath, args);
|
|
600
|
+
case "guardrail.gate":
|
|
601
|
+
return await this.handleGate(projectPath, args);
|
|
602
|
+
case "guardrail.fix":
|
|
603
|
+
return await this.handleFix(projectPath, args);
|
|
604
|
+
case "guardrail.proof":
|
|
605
|
+
return await this.handleProof(projectPath, args);
|
|
606
|
+
case "guardrail.validate":
|
|
607
|
+
return await this.handleValidate(projectPath, args);
|
|
608
|
+
case "guardrail.report":
|
|
609
|
+
return await this.handleReport(projectPath, args);
|
|
610
|
+
case "guardrail.status":
|
|
611
|
+
return await this.handleStatus(projectPath, args);
|
|
612
|
+
case "guardrail.autopilot":
|
|
613
|
+
return await this.handleAutopilot(projectPath, args);
|
|
614
|
+
case "guardrail.autopilot_plan":
|
|
615
|
+
return await this.handleAutopilotPlan(projectPath, args);
|
|
616
|
+
case "guardrail.autopilot_apply":
|
|
617
|
+
return await this.handleAutopilotApply(projectPath, args);
|
|
618
|
+
case "guardrail.badge":
|
|
619
|
+
return await this.handleBadge(projectPath, args);
|
|
620
|
+
case "guardrail.context":
|
|
621
|
+
return await this.handleContext(projectPath, args);
|
|
622
|
+
case "generate_mdc":
|
|
623
|
+
return await handleMDCGeneration(args);
|
|
624
|
+
default:
|
|
625
|
+
return this.error(`Unknown tool: ${name}`);
|
|
626
|
+
}
|
|
627
|
+
} catch (err) {
|
|
628
|
+
// Emit audit event for tool error
|
|
629
|
+
emitToolComplete(name, "error", {
|
|
630
|
+
errorMessage: err.message,
|
|
631
|
+
durationMs: Date.now() - startTime
|
|
632
|
+
});
|
|
633
|
+
return this.error(`${name} failed: ${err.message}`);
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
// Resources
|
|
638
|
+
this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
639
|
+
resources: [
|
|
640
|
+
{
|
|
641
|
+
uri: "guardrail://config",
|
|
642
|
+
name: "Guardrail Config",
|
|
643
|
+
mimeType: "application/json",
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
uri: "guardrail://summary",
|
|
647
|
+
name: "Last Scan Summary",
|
|
648
|
+
mimeType: "application/json",
|
|
649
|
+
},
|
|
650
|
+
],
|
|
651
|
+
}));
|
|
652
|
+
|
|
653
|
+
this.server.setRequestHandler(
|
|
654
|
+
ReadResourceRequestSchema,
|
|
655
|
+
async (request) => {
|
|
656
|
+
const { uri } = request.params;
|
|
657
|
+
const projectPath = process.cwd();
|
|
658
|
+
|
|
659
|
+
if (uri === "guardrail://config") {
|
|
660
|
+
const configPath = path.join(projectPath, "guardrail.config.json");
|
|
661
|
+
try {
|
|
662
|
+
const content = await fs.readFile(configPath, "utf-8");
|
|
663
|
+
return {
|
|
664
|
+
contents: [{ uri, mimeType: "application/json", text: content }],
|
|
665
|
+
};
|
|
666
|
+
} catch {
|
|
667
|
+
return {
|
|
668
|
+
contents: [{ uri, mimeType: "application/json", text: "{}" }],
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
if (uri === "guardrail://summary") {
|
|
674
|
+
const summaryPath = path.join(
|
|
675
|
+
projectPath,
|
|
676
|
+
".guardrail",
|
|
677
|
+
"summary.json",
|
|
678
|
+
);
|
|
679
|
+
try {
|
|
680
|
+
const content = await fs.readFile(summaryPath, "utf-8");
|
|
681
|
+
return {
|
|
682
|
+
contents: [{ uri, mimeType: "application/json", text: content }],
|
|
683
|
+
};
|
|
684
|
+
} catch {
|
|
685
|
+
return {
|
|
686
|
+
contents: [
|
|
687
|
+
{
|
|
688
|
+
uri,
|
|
689
|
+
mimeType: "application/json",
|
|
690
|
+
text: '{"message": "No scan found. Run guardrail.scan first."}',
|
|
691
|
+
},
|
|
692
|
+
],
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
return { contents: [] };
|
|
698
|
+
},
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
// Helpers
|
|
703
|
+
success(text) {
|
|
704
|
+
return { content: [{ type: "text", text }] };
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
error(text) {
|
|
708
|
+
return { content: [{ type: "text", text: `ā ${text}` }], isError: true };
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
// ============================================================================
|
|
712
|
+
// SCAN
|
|
713
|
+
// ============================================================================
|
|
714
|
+
async handleScan(projectPath, args) {
|
|
715
|
+
const profile = args?.profile || "quick";
|
|
716
|
+
const format = args?.format || "text";
|
|
717
|
+
const only = args?.only;
|
|
718
|
+
|
|
719
|
+
let output = "# š Guardrail Scan\n\n";
|
|
720
|
+
output += `**Profile:** ${profile}\n`;
|
|
721
|
+
output += `**Path:** ${projectPath}\n\n`;
|
|
722
|
+
|
|
723
|
+
try {
|
|
724
|
+
// Build CLI command
|
|
725
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" scan`;
|
|
726
|
+
cmd += ` --profile=${profile}`;
|
|
727
|
+
if (only?.length) cmd += ` --only=${only.join(",")}`;
|
|
728
|
+
cmd += ` --json`;
|
|
729
|
+
|
|
730
|
+
const result = execSync(cmd, {
|
|
731
|
+
cwd: projectPath,
|
|
732
|
+
encoding: "utf8",
|
|
733
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
// Read summary
|
|
737
|
+
const summaryPath = path.join(projectPath, ".guardrail", "summary.json");
|
|
738
|
+
const summary = JSON.parse(await fs.readFile(summaryPath, "utf-8"));
|
|
739
|
+
|
|
740
|
+
output += `## Score: ${summary.score}/100 (${summary.grade})\n\n`;
|
|
741
|
+
output += `**Verdict:** ${summary.canShip ? "ā
SHIP" : "š« NO-SHIP"}\n\n`;
|
|
742
|
+
|
|
743
|
+
if (summary.counts) {
|
|
744
|
+
output += "### Checks\n\n";
|
|
745
|
+
output += "| Category | Issues |\n|----------|--------|\n";
|
|
746
|
+
for (const [key, count] of Object.entries(summary.counts)) {
|
|
747
|
+
const icon = count === 0 ? "ā
" : "ā ļø";
|
|
748
|
+
output += `| ${icon} ${key} | ${count} |\n`;
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
output += `\nš **Report:** .guardrail/report.html\n`;
|
|
753
|
+
} catch (err) {
|
|
754
|
+
output += `\nā ļø Scan error: ${err.message}\n`;
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
output += "\n---\n_Context Enhanced by Guardrail AI_\n";
|
|
758
|
+
return this.success(output);
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// ============================================================================
|
|
762
|
+
// GATE
|
|
763
|
+
// ============================================================================
|
|
764
|
+
async handleGate(projectPath, args) {
|
|
765
|
+
const policy = args?.policy || "strict";
|
|
766
|
+
|
|
767
|
+
let output = "# š¦ Guardrail Gate\n\n";
|
|
768
|
+
output += `**Policy:** ${policy}\n\n`;
|
|
769
|
+
|
|
770
|
+
try {
|
|
771
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" gate`;
|
|
772
|
+
cmd += ` --policy=${policy}`;
|
|
773
|
+
if (args?.sarif) cmd += ` --sarif`;
|
|
774
|
+
|
|
775
|
+
execSync(cmd, {
|
|
776
|
+
cwd: projectPath,
|
|
777
|
+
encoding: "utf8",
|
|
778
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
output += "## ā
GATE PASSED\n\n";
|
|
782
|
+
output += "All checks passed. Clear to merge.\n";
|
|
783
|
+
} catch (err) {
|
|
784
|
+
output += "## š« GATE FAILED\n\n";
|
|
785
|
+
output += "Build blocked. Fix the issues and re-run.\n\n";
|
|
786
|
+
output += `Run \`guardrail fix --plan\` to see recommended fixes.\n`;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
return this.success(output);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// ============================================================================
|
|
793
|
+
// FIX
|
|
794
|
+
// ============================================================================
|
|
795
|
+
async handleFix(projectPath, args) {
|
|
796
|
+
const planOnly = args?.plan !== false && !args?.apply;
|
|
797
|
+
|
|
798
|
+
let output = "# š§ Guardrail Fix\n\n";
|
|
799
|
+
output += `**Mode:** ${planOnly ? "Plan (dry run)" : "Apply"}\n`;
|
|
800
|
+
output += `**Scope:** ${args?.scope || "all"}\n\n`;
|
|
801
|
+
|
|
802
|
+
try {
|
|
803
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" fix`;
|
|
804
|
+
if (planOnly) cmd += ` --plan`;
|
|
805
|
+
if (args?.apply) cmd += ` --apply`;
|
|
806
|
+
if (args?.scope) cmd += ` --scope=${args.scope}`;
|
|
807
|
+
if (args?.risk) cmd += ` --risk=${args.risk}`;
|
|
808
|
+
|
|
809
|
+
const result = execSync(cmd, {
|
|
810
|
+
cwd: projectPath,
|
|
811
|
+
encoding: "utf8",
|
|
812
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
output += result;
|
|
816
|
+
} catch (err) {
|
|
817
|
+
output += `\nā ļø Fix error: ${err.message}\n`;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
return this.success(output);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// ============================================================================
|
|
824
|
+
// PROOF
|
|
825
|
+
// ============================================================================
|
|
826
|
+
async handleProof(projectPath, args) {
|
|
827
|
+
const mode = args?.mode;
|
|
828
|
+
|
|
829
|
+
if (!mode) {
|
|
830
|
+
return this.error("Mode required: 'mocks' or 'reality'");
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
let output = `# š¬ Guardrail Proof: ${mode.toUpperCase()}\n\n`;
|
|
834
|
+
|
|
835
|
+
try {
|
|
836
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" proof ${mode}`;
|
|
837
|
+
if (mode === "reality" && args?.url) cmd += ` --url=${args.url}`;
|
|
838
|
+
if (mode === "reality" && args?.flow) cmd += ` --flow=${args.flow}`;
|
|
839
|
+
|
|
840
|
+
const result = execSync(cmd, {
|
|
841
|
+
cwd: projectPath,
|
|
842
|
+
encoding: "utf8",
|
|
843
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
844
|
+
timeout: 120000, // 2 min timeout for reality mode
|
|
845
|
+
});
|
|
846
|
+
|
|
847
|
+
output += result;
|
|
848
|
+
} catch (err) {
|
|
849
|
+
if (mode === "mocks") {
|
|
850
|
+
output += "## š« MOCKPROOF: FAIL\n\n";
|
|
851
|
+
output += "Mock/demo code detected in production paths.\n";
|
|
852
|
+
} else {
|
|
853
|
+
output += "## š« REALITY MODE: FAIL\n\n";
|
|
854
|
+
output += "Fake data or mock services detected at runtime.\n";
|
|
855
|
+
}
|
|
856
|
+
output += `\n${err.stdout || err.message}\n`;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
return this.success(output);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
// ============================================================================
|
|
863
|
+
// VALIDATE
|
|
864
|
+
// ============================================================================
|
|
865
|
+
async handleValidate(projectPath, args) {
|
|
866
|
+
const { code, intent } = args;
|
|
867
|
+
if (!code) return this.error("Code is required");
|
|
868
|
+
|
|
869
|
+
let output = "# š¤ AI Code Validation\n\n";
|
|
870
|
+
if (intent) output += `**Intent:** ${intent}\n\n`;
|
|
871
|
+
|
|
872
|
+
try {
|
|
873
|
+
const {
|
|
874
|
+
runHallucinationCheck,
|
|
875
|
+
validateIntent,
|
|
876
|
+
validateQuality,
|
|
877
|
+
} = require(
|
|
878
|
+
path.join(__dirname, "..", "bin", "runners", "lib", "ai-bridge.js"),
|
|
879
|
+
);
|
|
880
|
+
|
|
881
|
+
// 1. Hallucinations (checking against project deps + internal logic)
|
|
882
|
+
// Note: In MCP context, we might want to check the provided code specifically for imports.
|
|
883
|
+
// The bridge's runHallucinationCheck mostly checks package.json.
|
|
884
|
+
// But we can check imports in the 'code' snippet if we extract them.
|
|
885
|
+
// The bridge handles extractImports internally but runHallucinationCheck doesn't expose it directly for a string input.
|
|
886
|
+
// We will rely on package.json sanity check for now + static analysis of the snippet.
|
|
887
|
+
|
|
888
|
+
const hallResult = await runHallucinationCheck(projectPath);
|
|
889
|
+
|
|
890
|
+
// 2. Intent
|
|
891
|
+
let intentResult = { score: 100, issues: [] };
|
|
892
|
+
if (intent) {
|
|
893
|
+
intentResult = validateIntent(code, intent);
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
// 3. Quality
|
|
897
|
+
const qualityResult = validateQuality(code);
|
|
898
|
+
|
|
899
|
+
const allIssues = [
|
|
900
|
+
...hallResult.issues,
|
|
901
|
+
...intentResult.issues,
|
|
902
|
+
...qualityResult.issues,
|
|
903
|
+
];
|
|
904
|
+
|
|
905
|
+
const score = Math.round(
|
|
906
|
+
(hallResult.score + intentResult.score + qualityResult.score) / 3,
|
|
907
|
+
);
|
|
908
|
+
const status = score >= 80 ? "ā
PASSED" : "ā ļø ISSUES FOUND";
|
|
909
|
+
|
|
910
|
+
output += `**Status:** ${status} (${score}/100)\n\n`;
|
|
911
|
+
|
|
912
|
+
if (allIssues.length > 0) {
|
|
913
|
+
output += "### Issues\n";
|
|
914
|
+
for (const issue of allIssues) {
|
|
915
|
+
const icon =
|
|
916
|
+
issue.severity === "critical"
|
|
917
|
+
? "š“"
|
|
918
|
+
: issue.severity === "high"
|
|
919
|
+
? "š "
|
|
920
|
+
: "š”";
|
|
921
|
+
output += `- ${icon} **[${issue.type}]** ${issue.message}\n`;
|
|
922
|
+
}
|
|
923
|
+
} else {
|
|
924
|
+
output += "⨠Code looks valid and safe.\n";
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
return this.success(output);
|
|
928
|
+
} catch (err) {
|
|
929
|
+
return this.error(`Validation failed: ${err.message}`);
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
// ============================================================================
|
|
934
|
+
// REPORT
|
|
935
|
+
// ============================================================================
|
|
936
|
+
async handleReport(projectPath, args) {
|
|
937
|
+
const type = args?.type || "summary";
|
|
938
|
+
const outputDir = path.join(projectPath, ".guardrail");
|
|
939
|
+
|
|
940
|
+
let output = "# š Guardrail Report\n\n";
|
|
941
|
+
|
|
942
|
+
try {
|
|
943
|
+
if (type === "summary") {
|
|
944
|
+
const summaryPath = path.join(outputDir, "summary.json");
|
|
945
|
+
const summary = JSON.parse(await fs.readFile(summaryPath, "utf-8"));
|
|
946
|
+
|
|
947
|
+
output += `**Score:** ${summary.score}/100 (${summary.grade})\n`;
|
|
948
|
+
output += `**Verdict:** ${summary.canShip ? "ā
SHIP" : "š« NO-SHIP"}\n`;
|
|
949
|
+
output += `**Generated:** ${summary.timestamp}\n`;
|
|
950
|
+
} else if (type === "full") {
|
|
951
|
+
const reportPath = path.join(outputDir, "summary.md");
|
|
952
|
+
output += await fs.readFile(reportPath, "utf-8");
|
|
953
|
+
} else if (type === "sarif") {
|
|
954
|
+
const sarifPath = path.join(outputDir, "results.sarif");
|
|
955
|
+
const sarif = await fs.readFile(sarifPath, "utf-8");
|
|
956
|
+
output += "```json\n" + sarif.substring(0, 2000) + "\n```\n";
|
|
957
|
+
output += `\nš **Full SARIF:** ${sarifPath}\n`;
|
|
958
|
+
} else if (type === "html") {
|
|
959
|
+
output += `š **HTML Report:** ${path.join(outputDir, "report.html")}\n`;
|
|
960
|
+
output += "Open in browser to view the full report.\n";
|
|
961
|
+
}
|
|
962
|
+
} catch (err) {
|
|
963
|
+
output += `ā ļø No ${type} report found. Run \`guardrail.scan\` first.\n`;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
return this.success(output);
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
// ============================================================================
|
|
970
|
+
// SHIP - Quick health check
|
|
971
|
+
// ============================================================================
|
|
972
|
+
async handleShip(projectPath, args) {
|
|
973
|
+
let output = "# š Guardrail Ship\n\n";
|
|
974
|
+
output += `**Path:** ${projectPath}\n\n`;
|
|
975
|
+
|
|
976
|
+
try {
|
|
977
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" ship`;
|
|
978
|
+
if (args?.fix) cmd += ` --fix`;
|
|
979
|
+
|
|
980
|
+
const result = execSync(cmd, {
|
|
981
|
+
cwd: projectPath,
|
|
982
|
+
encoding: "utf8",
|
|
983
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
984
|
+
env: { ...process.env, GUARDRAIL_SKIP_AUTH: "1" },
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
// Parse the output for key information
|
|
988
|
+
output += result.replace(/\x1b\[[0-9;]*m/g, ""); // Strip ANSI codes
|
|
989
|
+
} catch (err) {
|
|
990
|
+
output += `\nā ļø Ship check failed: ${err.message}\n`;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
output += "\n---\n_Context Enhanced by Guardrail AI_\n";
|
|
994
|
+
return this.success(output);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// ============================================================================
|
|
998
|
+
// REALITY - Browser testing
|
|
999
|
+
// ============================================================================
|
|
1000
|
+
async handleReality(projectPath, args) {
|
|
1001
|
+
const url = args?.url;
|
|
1002
|
+
if (!url) return this.error("URL is required");
|
|
1003
|
+
|
|
1004
|
+
let output = "# š§Ŗ Guardrail Reality Mode\n\n";
|
|
1005
|
+
output += `**URL:** ${url}\n\n`;
|
|
1006
|
+
|
|
1007
|
+
try {
|
|
1008
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" reality --url "${url}"`;
|
|
1009
|
+
if (args?.auth) cmd += ` --auth "${args.auth}"`;
|
|
1010
|
+
if (args?.flows?.length) cmd += ` --flows ${args.flows.join(",")}`;
|
|
1011
|
+
if (args?.headed) cmd += ` --headed`;
|
|
1012
|
+
|
|
1013
|
+
const result = execSync(cmd, {
|
|
1014
|
+
cwd: projectPath,
|
|
1015
|
+
encoding: "utf8",
|
|
1016
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
1017
|
+
timeout: 120000,
|
|
1018
|
+
env: { ...process.env, GUARDRAIL_SKIP_AUTH: "1" },
|
|
1019
|
+
});
|
|
1020
|
+
|
|
1021
|
+
output += result.replace(/\x1b\[[0-9;]*m/g, "");
|
|
1022
|
+
} catch (err) {
|
|
1023
|
+
output += `\nā ļø Reality mode failed: ${err.message}\n`;
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
output += "\n---\n_Context Enhanced by Guardrail AI_\n";
|
|
1027
|
+
return this.success(output);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// ============================================================================
|
|
1031
|
+
// AI-TEST - AI Agent testing
|
|
1032
|
+
// ============================================================================
|
|
1033
|
+
async handleAITest(projectPath, args) {
|
|
1034
|
+
const url = args?.url;
|
|
1035
|
+
if (!url) return this.error("URL is required");
|
|
1036
|
+
|
|
1037
|
+
let output = "# š¤ Guardrail AI Agent\n\n";
|
|
1038
|
+
output += `**URL:** ${url}\n`;
|
|
1039
|
+
output += `**Goal:** ${args?.goal || "Test all features"}\n\n`;
|
|
1040
|
+
|
|
1041
|
+
try {
|
|
1042
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" ai-test --url "${url}"`;
|
|
1043
|
+
if (args?.goal) cmd += ` --goal "${args.goal}"`;
|
|
1044
|
+
if (args?.headed) cmd += ` --headed`;
|
|
1045
|
+
|
|
1046
|
+
const result = execSync(cmd, {
|
|
1047
|
+
cwd: projectPath,
|
|
1048
|
+
encoding: "utf8",
|
|
1049
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
1050
|
+
timeout: 180000,
|
|
1051
|
+
env: { ...process.env, GUARDRAIL_SKIP_AUTH: "1" },
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
output += result.replace(/\x1b\[[0-9;]*m/g, "");
|
|
1055
|
+
|
|
1056
|
+
// Try to read fix prompts
|
|
1057
|
+
const promptPath = path.join(
|
|
1058
|
+
projectPath,
|
|
1059
|
+
".guardrail",
|
|
1060
|
+
"ai-agent",
|
|
1061
|
+
"fix-prompt.md",
|
|
1062
|
+
);
|
|
1063
|
+
try {
|
|
1064
|
+
const prompts = await fs.readFile(promptPath, "utf-8");
|
|
1065
|
+
output += "\n## Fix Prompts Generated\n\n";
|
|
1066
|
+
output += prompts.substring(0, 2000);
|
|
1067
|
+
if (prompts.length > 2000) output += "\n\n... (truncated)";
|
|
1068
|
+
} catch {}
|
|
1069
|
+
} catch (err) {
|
|
1070
|
+
output += `\nā ļø AI Agent failed: ${err.message}\n`;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
output += "\n---\n_Context Enhanced by Guardrail AI_\n";
|
|
1074
|
+
return this.success(output);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
// ============================================================================
|
|
1078
|
+
// AUTOPILOT - Continuous protection
|
|
1079
|
+
// ============================================================================
|
|
1080
|
+
async handleAutopilot(projectPath, args) {
|
|
1081
|
+
const action = args?.action || "status";
|
|
1082
|
+
|
|
1083
|
+
let output = "# š¤ Guardrail Autopilot\n\n";
|
|
1084
|
+
output += `**Action:** ${action}\n\n`;
|
|
1085
|
+
|
|
1086
|
+
try {
|
|
1087
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" autopilot ${action}`;
|
|
1088
|
+
if (args?.slack) cmd += ` --slack="${args.slack}"`;
|
|
1089
|
+
if (args?.email) cmd += ` --email="${args.email}"`;
|
|
1090
|
+
|
|
1091
|
+
const result = execSync(cmd, {
|
|
1092
|
+
cwd: projectPath,
|
|
1093
|
+
encoding: "utf8",
|
|
1094
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
1095
|
+
env: { ...process.env, GUARDRAIL_SKIP_AUTH: "1" },
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
output += result.replace(/\x1b\[[0-9;]*m/g, "");
|
|
1099
|
+
} catch (err) {
|
|
1100
|
+
output += `\nā ļø Autopilot failed: ${err.message}\n`;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
return this.success(output);
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
// ============================================================================
|
|
1107
|
+
// AUTOPILOT PLAN - Generate fix plan (Pro/Compliance)
|
|
1108
|
+
// ============================================================================
|
|
1109
|
+
async handleAutopilotPlan(projectPath, args) {
|
|
1110
|
+
let output = "# š¤ Guardrail Autopilot Plan\n\n";
|
|
1111
|
+
output += `**Path:** ${projectPath}\n`;
|
|
1112
|
+
output += `**Profile:** ${args?.profile || "ship"}\n\n`;
|
|
1113
|
+
|
|
1114
|
+
try {
|
|
1115
|
+
// Use the core autopilot runner directly
|
|
1116
|
+
const corePath = path.join(__dirname, "..", "packages", "core", "dist", "index.js");
|
|
1117
|
+
let runAutopilot;
|
|
1118
|
+
|
|
1119
|
+
try {
|
|
1120
|
+
const core = await import(corePath);
|
|
1121
|
+
runAutopilot = core.runAutopilot;
|
|
1122
|
+
} catch {
|
|
1123
|
+
// Fallback to CLI
|
|
1124
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" autopilot plan`;
|
|
1125
|
+
cmd += ` --profile ${args?.profile || "ship"}`;
|
|
1126
|
+
cmd += ` --max-fixes ${args?.maxFixes || 10}`;
|
|
1127
|
+
cmd += ` --json`;
|
|
1128
|
+
|
|
1129
|
+
const result = execSync(cmd, {
|
|
1130
|
+
cwd: projectPath,
|
|
1131
|
+
encoding: "utf8",
|
|
1132
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
1133
|
+
env: { ...process.env, GUARDRAIL_SKIP_AUTH: "1" },
|
|
1134
|
+
});
|
|
1135
|
+
|
|
1136
|
+
const jsonResult = JSON.parse(result);
|
|
1137
|
+
output += `## Scan Results\n\n`;
|
|
1138
|
+
output += `- **Total findings:** ${jsonResult.totalFindings}\n`;
|
|
1139
|
+
output += `- **Fixable:** ${jsonResult.fixableFindings}\n`;
|
|
1140
|
+
output += `- **Estimated time:** ${jsonResult.estimatedDuration}\n\n`;
|
|
1141
|
+
|
|
1142
|
+
output += `## Fix Packs\n\n`;
|
|
1143
|
+
for (const pack of jsonResult.packs || []) {
|
|
1144
|
+
const risk = pack.estimatedRisk === "high" ? "š“" : pack.estimatedRisk === "medium" ? "š”" : "š¢";
|
|
1145
|
+
output += `### ${risk} ${pack.name}\n`;
|
|
1146
|
+
output += `- Issues: ${pack.findings.length}\n`;
|
|
1147
|
+
output += `- Files: ${pack.impactedFiles.join(", ")}\n\n`;
|
|
1148
|
+
}
|
|
1149
|
+
|
|
1150
|
+
output += `\nš” Run \`guardrail.autopilot_apply\` to apply these fixes.\n`;
|
|
1151
|
+
return this.success(output);
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
if (runAutopilot) {
|
|
1155
|
+
const result = await runAutopilot({
|
|
1156
|
+
projectPath,
|
|
1157
|
+
mode: "plan",
|
|
1158
|
+
profile: args?.profile || "ship",
|
|
1159
|
+
maxFixes: args?.maxFixes || 10,
|
|
1160
|
+
});
|
|
1161
|
+
|
|
1162
|
+
output += `## Scan Results\n\n`;
|
|
1163
|
+
output += `- **Total findings:** ${result.totalFindings}\n`;
|
|
1164
|
+
output += `- **Fixable:** ${result.fixableFindings}\n`;
|
|
1165
|
+
output += `- **Estimated time:** ${result.estimatedDuration}\n\n`;
|
|
1166
|
+
|
|
1167
|
+
output += `## Fix Packs\n\n`;
|
|
1168
|
+
for (const pack of result.packs) {
|
|
1169
|
+
const risk = pack.estimatedRisk === "high" ? "š“" : pack.estimatedRisk === "medium" ? "š”" : "š¢";
|
|
1170
|
+
output += `### ${risk} ${pack.name}\n`;
|
|
1171
|
+
output += `- Issues: ${pack.findings.length}\n`;
|
|
1172
|
+
output += `- Files: ${pack.impactedFiles.join(", ")}\n\n`;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
output += `\nš” Run \`guardrail.autopilot_apply\` to apply these fixes.\n`;
|
|
1176
|
+
}
|
|
1177
|
+
} catch (err) {
|
|
1178
|
+
output += `\nā Error: ${err.message}\n`;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
return this.success(output);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
// ============================================================================
|
|
1185
|
+
// AUTOPILOT APPLY - Apply fixes (Pro/Compliance)
|
|
1186
|
+
// ============================================================================
|
|
1187
|
+
async handleAutopilotApply(projectPath, args) {
|
|
1188
|
+
let output = "# š§ Guardrail Autopilot Apply\n\n";
|
|
1189
|
+
output += `**Path:** ${projectPath}\n`;
|
|
1190
|
+
output += `**Profile:** ${args?.profile || "ship"}\n`;
|
|
1191
|
+
output += `**Dry Run:** ${args?.dryRun ? "Yes" : "No"}\n\n`;
|
|
1192
|
+
|
|
1193
|
+
try {
|
|
1194
|
+
// Fallback to CLI
|
|
1195
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" autopilot apply`;
|
|
1196
|
+
cmd += ` --profile ${args?.profile || "ship"}`;
|
|
1197
|
+
cmd += ` --max-fixes ${args?.maxFixes || 10}`;
|
|
1198
|
+
if (args?.verify === false) cmd += ` --no-verify`;
|
|
1199
|
+
if (args?.dryRun) cmd += ` --dry-run`;
|
|
1200
|
+
cmd += ` --json`;
|
|
1201
|
+
|
|
1202
|
+
const result = execSync(cmd, {
|
|
1203
|
+
cwd: projectPath,
|
|
1204
|
+
encoding: "utf8",
|
|
1205
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
1206
|
+
timeout: 300000, // 5 min timeout
|
|
1207
|
+
env: { ...process.env, GUARDRAIL_SKIP_AUTH: "1" },
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
const jsonResult = JSON.parse(result);
|
|
1211
|
+
|
|
1212
|
+
output += `## Results\n\n`;
|
|
1213
|
+
output += `- **Packs attempted:** ${jsonResult.packsAttempted}\n`;
|
|
1214
|
+
output += `- **Packs succeeded:** ${jsonResult.packsSucceeded}\n`;
|
|
1215
|
+
output += `- **Packs failed:** ${jsonResult.packsFailed}\n`;
|
|
1216
|
+
output += `- **Fixes applied:** ${jsonResult.appliedFixes?.filter(f => f.success).length || 0}\n`;
|
|
1217
|
+
output += `- **Duration:** ${jsonResult.duration}ms\n\n`;
|
|
1218
|
+
|
|
1219
|
+
if (jsonResult.verification) {
|
|
1220
|
+
output += `## Verification\n\n`;
|
|
1221
|
+
output += `- TypeScript: ${jsonResult.verification.typecheck?.passed ? "ā
" : "ā"}\n`;
|
|
1222
|
+
output += `- Build: ${jsonResult.verification.build?.passed ? "ā
" : "āļø"}\n`;
|
|
1223
|
+
output += `- Overall: ${jsonResult.verification.passed ? "ā
PASSED" : "ā FAILED"}\n\n`;
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
output += `**Remaining findings:** ${jsonResult.remainingFindings}\n`;
|
|
1227
|
+
output += `**New scan verdict:** ${jsonResult.newScanVerdict}\n`;
|
|
1228
|
+
} catch (err) {
|
|
1229
|
+
output += `\nā Error: ${err.message}\n`;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
return this.success(output);
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// ============================================================================
|
|
1236
|
+
// BADGE - Generate ship badge
|
|
1237
|
+
// ============================================================================
|
|
1238
|
+
async handleBadge(projectPath, args) {
|
|
1239
|
+
const format = args?.format || "svg";
|
|
1240
|
+
|
|
1241
|
+
let output = "# š
Guardrail Badge\n\n";
|
|
1242
|
+
|
|
1243
|
+
try {
|
|
1244
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" badge --format ${format}`;
|
|
1245
|
+
if (args?.style) cmd += ` --style ${args.style}`;
|
|
1246
|
+
|
|
1247
|
+
const result = execSync(cmd, {
|
|
1248
|
+
cwd: projectPath,
|
|
1249
|
+
encoding: "utf8",
|
|
1250
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
1251
|
+
env: { ...process.env, GUARDRAIL_SKIP_AUTH: "1" },
|
|
1252
|
+
});
|
|
1253
|
+
|
|
1254
|
+
output += result.replace(/\x1b\[[0-9;]*m/g, "");
|
|
1255
|
+
|
|
1256
|
+
// Read the badge file
|
|
1257
|
+
const badgePath = path.join(
|
|
1258
|
+
projectPath,
|
|
1259
|
+
".guardrail",
|
|
1260
|
+
"badges",
|
|
1261
|
+
`badge.${format}`,
|
|
1262
|
+
);
|
|
1263
|
+
try {
|
|
1264
|
+
const badge = await fs.readFile(badgePath, "utf-8");
|
|
1265
|
+
if (format === "md") {
|
|
1266
|
+
output += "\n**Markdown:**\n```\n" + badge + "\n```\n";
|
|
1267
|
+
} else if (format === "html") {
|
|
1268
|
+
output += "\n**HTML:**\n```html\n" + badge + "\n```\n";
|
|
1269
|
+
} else {
|
|
1270
|
+
output += `\n**Badge saved to:** ${badgePath}\n`;
|
|
1271
|
+
}
|
|
1272
|
+
} catch {}
|
|
1273
|
+
} catch (err) {
|
|
1274
|
+
output += `\nā ļø Badge generation failed: ${err.message}\n`;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
return this.success(output);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// ============================================================================
|
|
1281
|
+
// CONTEXT - AI Rules Generator
|
|
1282
|
+
// ============================================================================
|
|
1283
|
+
async handleContext(projectPath, args) {
|
|
1284
|
+
const platform = args?.platform || "all";
|
|
1285
|
+
|
|
1286
|
+
let output = "# š§ Guardrail Context Generator\n\n";
|
|
1287
|
+
output += `**Project:** ${path.basename(projectPath)}\n`;
|
|
1288
|
+
output += `**Platform:** ${platform}\n\n`;
|
|
1289
|
+
|
|
1290
|
+
try {
|
|
1291
|
+
let cmd = `node "${path.join(__dirname, "..", "bin", "guardrail.js")}" context`;
|
|
1292
|
+
if (platform !== "all") cmd += ` --platform=${platform}`;
|
|
1293
|
+
|
|
1294
|
+
execSync(cmd, {
|
|
1295
|
+
cwd: projectPath,
|
|
1296
|
+
encoding: "utf8",
|
|
1297
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
1298
|
+
});
|
|
1299
|
+
|
|
1300
|
+
output += "## ā
Context Generated\n\n";
|
|
1301
|
+
output +=
|
|
1302
|
+
"Your AI coding assistants now have full project awareness.\n\n";
|
|
1303
|
+
|
|
1304
|
+
output += "### Generated Files\n\n";
|
|
1305
|
+
|
|
1306
|
+
if (platform === "all" || platform === "cursor") {
|
|
1307
|
+
output += "**Cursor:**\n";
|
|
1308
|
+
output += "- `.cursorrules` - Main rules file\n";
|
|
1309
|
+
output += "- `.cursor/rules/*.mdc` - Modular rules\n\n";
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
if (platform === "all" || platform === "windsurf") {
|
|
1313
|
+
output += "**Windsurf:**\n";
|
|
1314
|
+
output += "- `.windsurf/rules/*.md` - Cascade rules\n\n";
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
if (platform === "all" || platform === "copilot") {
|
|
1318
|
+
output += "**GitHub Copilot:**\n";
|
|
1319
|
+
output += "- `.github/copilot-instructions.md`\n\n";
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
output += "**Universal (MCP):**\n";
|
|
1323
|
+
output += "- `.guardrail/context.json` - Full context\n";
|
|
1324
|
+
output += "- `.guardrail/project-map.json` - Project analysis\n\n";
|
|
1325
|
+
|
|
1326
|
+
output += "### What Your AI Now Knows\n\n";
|
|
1327
|
+
output += "- Project architecture and structure\n";
|
|
1328
|
+
output += "- API routes and endpoints\n";
|
|
1329
|
+
output += "- Components and data models\n";
|
|
1330
|
+
output += "- Coding conventions and patterns\n";
|
|
1331
|
+
output += "- Dependencies and tech stack\n\n";
|
|
1332
|
+
|
|
1333
|
+
output +=
|
|
1334
|
+
"> **Tip:** Regenerate after major codebase changes with `guardrail context`\n";
|
|
1335
|
+
} catch (err) {
|
|
1336
|
+
output += `\nā ļø Context generation failed: ${err.message}\n`;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
output += "\n---\n_Context Enhanced by Guardrail AI_\n";
|
|
1340
|
+
return this.success(output);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
// ============================================================================
|
|
1344
|
+
// STATUS
|
|
1345
|
+
// ============================================================================
|
|
1346
|
+
async handleStatus(projectPath, args) {
|
|
1347
|
+
let output = "# š Guardrail Status\n\n";
|
|
1348
|
+
|
|
1349
|
+
output += "## Server\n\n";
|
|
1350
|
+
output += `- **Version:** ${VERSION}\n`;
|
|
1351
|
+
output += `- **Node:** ${process.version}\n`;
|
|
1352
|
+
output += `- **Platform:** ${process.platform}\n\n`;
|
|
1353
|
+
|
|
1354
|
+
output += "## Project\n\n";
|
|
1355
|
+
output += `- **Path:** ${projectPath}\n`;
|
|
1356
|
+
|
|
1357
|
+
// Config
|
|
1358
|
+
const configPaths = [
|
|
1359
|
+
path.join(projectPath, "guardrail.config.json"),
|
|
1360
|
+
path.join(projectPath, ".guardrailrc"),
|
|
1361
|
+
];
|
|
1362
|
+
let hasConfig = false;
|
|
1363
|
+
for (const p of configPaths) {
|
|
1364
|
+
try {
|
|
1365
|
+
await fs.access(p);
|
|
1366
|
+
hasConfig = true;
|
|
1367
|
+
output += `- **Config:** ā
Found (${path.basename(p)})\n`;
|
|
1368
|
+
break;
|
|
1369
|
+
} catch {}
|
|
1370
|
+
}
|
|
1371
|
+
if (!hasConfig) {
|
|
1372
|
+
output += "- **Config:** ā ļø Not found (run `guardrail init`)\n";
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// Last scan
|
|
1376
|
+
const summaryPath = path.join(projectPath, ".guardrail", "summary.json");
|
|
1377
|
+
try {
|
|
1378
|
+
const summary = JSON.parse(await fs.readFile(summaryPath, "utf-8"));
|
|
1379
|
+
output += `- **Last Scan:** ${summary.timestamp}\n`;
|
|
1380
|
+
output += `- **Last Score:** ${summary.score}/100 (${summary.grade})\n`;
|
|
1381
|
+
output += `- **Last Verdict:** ${summary.canShip ? "ā
SHIP" : "š« NO-SHIP"}\n`;
|
|
1382
|
+
} catch {
|
|
1383
|
+
output += "- **Last Scan:** None\n";
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
output += "\n## Available Tools\n\n";
|
|
1387
|
+
output += "| Tool | Description |\n|------|-------------|\n";
|
|
1388
|
+
for (const tool of TOOLS) {
|
|
1389
|
+
output += `| \`${tool.name}\` | ${tool.description.split("ā")[0].trim()} |\n`;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
output += "\n---\n_Guardrail v" + VERSION + " ā https://getguardrail.io_\n";
|
|
1393
|
+
|
|
1394
|
+
return this.success(output);
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
// ============================================================================
|
|
1398
|
+
// RUN
|
|
1399
|
+
// ============================================================================
|
|
1400
|
+
async run() {
|
|
1401
|
+
const transport = new StdioServerTransport();
|
|
1402
|
+
await this.server.connect(transport);
|
|
1403
|
+
console.error("Guardrail MCP Server v2.0 running on stdio");
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
// Main
|
|
1408
|
+
const server = new GuardrailMCP();
|
|
1409
|
+
server.run().catch(console.error);
|