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/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);