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.old.js ADDED
@@ -0,0 +1,4137 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * AI Agent Guardrails - MCP Server
5
+ * Version: 1.0.0
6
+ *
7
+ * Professional Model Context Protocol server for AI development environments.
8
+ * Compatible with Cursor, Claude Desktop, VS Code, Windsurf, and other MCP-enabled editors.
9
+ *
10
+ * Features:
11
+ * - Project validation and architecture analysis
12
+ * - Design system enforcement
13
+ * - API endpoint registration
14
+ * - Knowledge base building
15
+ * - Semantic code search
16
+ * - Change impact analysis
17
+ */
18
+
19
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
20
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
21
+ import {
22
+ CallToolRequestSchema,
23
+ ListToolsRequestSchema,
24
+ ListResourcesRequestSchema,
25
+ ReadResourceRequestSchema,
26
+ } from "@modelcontextprotocol/sdk/types.js";
27
+ import fs from "fs/promises";
28
+ import path from "path";
29
+ import { fileURLToPath } from "url";
30
+ import { execSync } from "child_process";
31
+
32
+ // Import premium tools
33
+ import { PREMIUM_TOOLS, handlePremiumTool } from "./premium-tools.js";
34
+
35
+ // Import hygiene tools
36
+ import { createRequire } from "module";
37
+ const require = createRequire(import.meta.url);
38
+ const {
39
+ hygieneTools,
40
+ hygieneFullScan,
41
+ hygieneDuplicates,
42
+ hygieneUnused,
43
+ hygieneErrors,
44
+ hygieneRootCleanup,
45
+ hygieneDeletionPlan,
46
+ } = require("./hygiene-tools.js");
47
+
48
+ // Professional logging system
49
+ class Logger {
50
+ constructor(debug = false) {
51
+ this.debug = debug;
52
+ }
53
+
54
+ log(level, message, data = null) {
55
+ const timestamp = new Date().toISOString();
56
+ const logEntry = `[${timestamp}] [${level}] [GUARDRAIL MCP] ${message}`;
57
+
58
+ if (level === "ERROR") {
59
+ console.error(logEntry);
60
+ if (data) console.error(JSON.stringify(data, null, 2));
61
+ } else if (this.debug) {
62
+ console.error(logEntry);
63
+ if (data) console.error(JSON.stringify(data, null, 2));
64
+ }
65
+ }
66
+
67
+ info(message, data) {
68
+ this.log("INFO", message, data);
69
+ }
70
+ warn(message, data) {
71
+ this.log("WARN", message, data);
72
+ }
73
+ error(message, data) {
74
+ this.log("ERROR", message, data);
75
+ }
76
+ debug(message, data) {
77
+ this.log("DEBUG", message, data);
78
+ }
79
+ }
80
+
81
+ const __filename = fileURLToPath(import.meta.url);
82
+ const __dirname = path.dirname(__filename);
83
+
84
+ class GuardrailsMCPServer {
85
+ constructor() {
86
+ // Initialize logger
87
+ this.logger = new Logger(process.env.GUARDRAIL_DEBUG === "true");
88
+
89
+ this.server = new Server(
90
+ {
91
+ name: "GUARDRAIL-ai",
92
+ version: "1.0.0",
93
+ },
94
+ {
95
+ capabilities: {
96
+ tools: {},
97
+ resources: {},
98
+ },
99
+ },
100
+ );
101
+
102
+ this.setupHandlers();
103
+ this.setupErrorHandling();
104
+ this.logger.info("GUARDRAIL MCP Server initialized");
105
+ }
106
+
107
+ setupHandlers() {
108
+ // List available tools with professional descriptions and categorization
109
+ this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
110
+ tools: [
111
+ // 🏗️ Project Analysis & Validation
112
+ {
113
+ name: "validate_project",
114
+ description:
115
+ "🔍 Comprehensive project validation - checks structure, API endpoints, and identifies mock data usage",
116
+ inputSchema: {
117
+ type: "object",
118
+ properties: {
119
+ projectPath: {
120
+ type: "string",
121
+ description: "Path to project root directory",
122
+ default: ".",
123
+ },
124
+ },
125
+ },
126
+ },
127
+ {
128
+ name: "check_project_drift",
129
+ description:
130
+ "📊 Detect architectural drift - analyzes if project structure has deviated from intended patterns",
131
+ inputSchema: {
132
+ type: "object",
133
+ properties: {
134
+ projectPath: {
135
+ type: "string",
136
+ description: "Path to project root directory",
137
+ default: ".",
138
+ },
139
+ },
140
+ },
141
+ },
142
+ {
143
+ name: "get_project_health",
144
+ description:
145
+ "💯 Generate project health score with actionable recommendations (Professional feature)",
146
+ inputSchema: {
147
+ type: "object",
148
+ properties: {
149
+ projectPath: {
150
+ type: "string",
151
+ description: "Path to project root directory",
152
+ default: ".",
153
+ },
154
+ },
155
+ },
156
+ },
157
+ // 🎨 Design System Management
158
+ {
159
+ name: "check_design_system",
160
+ description:
161
+ "🎨 Validate components against locked design system - ensures visual consistency",
162
+ inputSchema: {
163
+ type: "object",
164
+ properties: {
165
+ projectPath: {
166
+ type: "string",
167
+ description: "Path to project root directory",
168
+ default: ".",
169
+ },
170
+ },
171
+ },
172
+ },
173
+ {
174
+ name: "setup_design_system",
175
+ description:
176
+ "🔧 Initialize and lock a professional design system for your project",
177
+ inputSchema: {
178
+ type: "object",
179
+ properties: {
180
+ projectPath: {
181
+ type: "string",
182
+ description: "Path to project root directory",
183
+ default: ".",
184
+ },
185
+ theme: {
186
+ type: "string",
187
+ enum: ["modern", "dark", "elegant", "minimal", "corporate"],
188
+ description: "Pre-built theme to apply",
189
+ default: "modern",
190
+ },
191
+ },
192
+ },
193
+ },
194
+ // 🔌 API Management
195
+ {
196
+ name: "register_api_endpoint",
197
+ description:
198
+ "📝 Register new API endpoints to prevent mock data usage and maintain API integrity",
199
+ inputSchema: {
200
+ type: "object",
201
+ properties: {
202
+ projectPath: {
203
+ type: "string",
204
+ description: "Path to project root directory",
205
+ default: ".",
206
+ },
207
+ path: {
208
+ type: "string",
209
+ description: "API endpoint path (e.g., /api/users)",
210
+ },
211
+ method: {
212
+ type: "string",
213
+ enum: ["GET", "POST", "PUT", "DELETE", "PATCH"],
214
+ description: "HTTP method",
215
+ },
216
+ description: {
217
+ type: "string",
218
+ description: "Detailed endpoint description",
219
+ },
220
+ },
221
+ required: ["path", "method"],
222
+ },
223
+ },
224
+ {
225
+ name: "get_guardrails_rules",
226
+ description:
227
+ "📋 Retrieve current guardrails rules and project constraints",
228
+ inputSchema: {
229
+ type: "object",
230
+ properties: {
231
+ projectPath: {
232
+ type: "string",
233
+ description: "Path to project root directory",
234
+ default: ".",
235
+ },
236
+ },
237
+ },
238
+ },
239
+ // 🧠 Intelligence & Knowledge
240
+ {
241
+ name: "architect_analyze",
242
+ description:
243
+ "🏗️ Intelligent project analysis - understands context and recommends optimal implementation order",
244
+ inputSchema: {
245
+ type: "object",
246
+ properties: {
247
+ projectPath: {
248
+ type: "string",
249
+ description: "Path to project root directory",
250
+ default: ".",
251
+ },
252
+ },
253
+ },
254
+ },
255
+ {
256
+ name: "architect_apply",
257
+ description:
258
+ "⚡ Automatically apply recommended templates with dependency resolution",
259
+ inputSchema: {
260
+ type: "object",
261
+ properties: {
262
+ projectPath: {
263
+ type: "string",
264
+ description: "Path to project root directory",
265
+ default: ".",
266
+ },
267
+ autoApply: {
268
+ type: "boolean",
269
+ description:
270
+ "Automatically apply critical templates without confirmation",
271
+ default: true,
272
+ },
273
+ },
274
+ },
275
+ },
276
+ {
277
+ name: "build_knowledge_base",
278
+ description:
279
+ "🧠 Build deep codebase knowledge - analyzes architecture, patterns, and relationships",
280
+ inputSchema: {
281
+ type: "object",
282
+ properties: {
283
+ projectPath: {
284
+ type: "string",
285
+ description: "Path to project root directory",
286
+ default: ".",
287
+ },
288
+ },
289
+ },
290
+ },
291
+ {
292
+ name: "get_deep_context",
293
+ description:
294
+ "💬 Get project-specific answers using knowledge base with customizable response styles",
295
+ inputSchema: {
296
+ type: "object",
297
+ properties: {
298
+ projectPath: {
299
+ type: "string",
300
+ description: "Path to project root directory",
301
+ default: ".",
302
+ },
303
+ query: {
304
+ type: "string",
305
+ description:
306
+ 'Question about your codebase (e.g., "How is authentication implemented?")',
307
+ },
308
+ style: {
309
+ type: "string",
310
+ enum: [
311
+ "blunt",
312
+ "excited",
313
+ "strict",
314
+ "friendly",
315
+ "professional",
316
+ "casual",
317
+ "technical",
318
+ "encouraging",
319
+ "concise",
320
+ "detailed",
321
+ ],
322
+ description:
323
+ "Response tone: blunt (direct), excited (energetic), strict (formal), friendly (warm), professional (business), casual (relaxed), technical (precise), encouraging (supportive), concise (brief), detailed (thorough)",
324
+ default: "professional",
325
+ },
326
+ useEmojis: {
327
+ type: "boolean",
328
+ description:
329
+ "Include emojis in responses for better engagement",
330
+ default: true,
331
+ },
332
+ includeExamples: {
333
+ type: "boolean",
334
+ description: "Include code examples in recommendations",
335
+ default: false,
336
+ },
337
+ },
338
+ required: ["query"],
339
+ },
340
+ },
341
+ // 🔍 Code Analysis & Search
342
+ {
343
+ name: "semantic_search",
344
+ description:
345
+ "🔍 Semantic code search - find code by meaning, not just text matching",
346
+ inputSchema: {
347
+ type: "object",
348
+ properties: {
349
+ projectPath: {
350
+ type: "string",
351
+ description: "Path to project root directory",
352
+ default: ".",
353
+ },
354
+ query: {
355
+ type: "string",
356
+ description:
357
+ 'Describe what you\'re looking for (e.g., "authentication middleware", "user validation logic")',
358
+ },
359
+ },
360
+ required: ["query"],
361
+ },
362
+ },
363
+ {
364
+ name: "analyze_change_impact",
365
+ description:
366
+ "💥 Analyze impact of changes - identifies dependencies and potential breaking changes",
367
+ inputSchema: {
368
+ type: "object",
369
+ properties: {
370
+ projectPath: {
371
+ type: "string",
372
+ description: "Path to project root directory",
373
+ default: ".",
374
+ },
375
+ file: {
376
+ type: "string",
377
+ description: "File path to analyze for impact",
378
+ },
379
+ },
380
+ required: ["file"],
381
+ },
382
+ },
383
+ {
384
+ name: "generate_code_context",
385
+ description:
386
+ "⚙️ Generate code prompts that follow your project's patterns and conventions",
387
+ inputSchema: {
388
+ type: "object",
389
+ properties: {
390
+ projectPath: {
391
+ type: "string",
392
+ description: "Path to project root directory",
393
+ default: ".",
394
+ },
395
+ task: {
396
+ type: "string",
397
+ description:
398
+ 'Describe what code to generate (e.g., "Create a user authentication hook with TypeScript")',
399
+ },
400
+ },
401
+ required: ["task"],
402
+ },
403
+ },
404
+ // 🛡️ Security Orchestrator
405
+ {
406
+ name: "security_scan",
407
+ description:
408
+ "🛡️ Full security scan - runs policy checks, SAST, supply chain analysis, and secret detection",
409
+ inputSchema: {
410
+ type: "object",
411
+ properties: {
412
+ projectPath: {
413
+ type: "string",
414
+ description: "Path to project root directory",
415
+ default: ".",
416
+ },
417
+ environment: {
418
+ type: "string",
419
+ enum: ["development", "staging", "production"],
420
+ description: "Target environment for security checks",
421
+ default: "production",
422
+ },
423
+ },
424
+ },
425
+ },
426
+ {
427
+ name: "policy_check",
428
+ description:
429
+ "📋 Run policy checks - validates banned patterns, mock data, localhost URLs, and env vars",
430
+ inputSchema: {
431
+ type: "object",
432
+ properties: {
433
+ projectPath: {
434
+ type: "string",
435
+ description: "Path to project root directory",
436
+ default: ".",
437
+ },
438
+ environment: {
439
+ type: "string",
440
+ enum: ["development", "staging", "production"],
441
+ description: "Target environment",
442
+ default: "production",
443
+ },
444
+ },
445
+ },
446
+ },
447
+ {
448
+ name: "secret_scan",
449
+ description:
450
+ "🔐 Scan for secrets - detects API keys, tokens, passwords, and credentials in code",
451
+ inputSchema: {
452
+ type: "object",
453
+ properties: {
454
+ projectPath: {
455
+ type: "string",
456
+ description: "Path to project root directory",
457
+ default: ".",
458
+ },
459
+ scanHistory: {
460
+ type: "boolean",
461
+ description: "Also scan git history for leaked secrets",
462
+ default: false,
463
+ },
464
+ },
465
+ },
466
+ },
467
+ {
468
+ name: "supply_chain_scan",
469
+ description:
470
+ "📦 Supply chain analysis - generates SBOM, scans vulnerabilities, checks licenses",
471
+ inputSchema: {
472
+ type: "object",
473
+ properties: {
474
+ projectPath: {
475
+ type: "string",
476
+ description: "Path to project root directory",
477
+ default: ".",
478
+ },
479
+ repoUrl: {
480
+ type: "string",
481
+ description: "GitHub repo URL for OpenSSF Scorecard (optional)",
482
+ },
483
+ },
484
+ },
485
+ },
486
+ {
487
+ name: "ship_check",
488
+ description:
489
+ "🚀 Ship readiness check - MockProof build gate to ensure no fakes in production",
490
+ inputSchema: {
491
+ type: "object",
492
+ properties: {
493
+ projectPath: {
494
+ type: "string",
495
+ description: "Path to project root directory",
496
+ default: ".",
497
+ },
498
+ },
499
+ },
500
+ },
501
+ // 🔗 API Endpoint Audit
502
+ {
503
+ name: "audit_api_endpoints",
504
+ description:
505
+ "🔗 Audit API endpoints - identifies disconnected endpoints, missing backend implementations, and unused routes",
506
+ inputSchema: {
507
+ type: "object",
508
+ properties: {
509
+ projectPath: {
510
+ type: "string",
511
+ description: "Path to project root directory",
512
+ default: ".",
513
+ },
514
+ showDetails: {
515
+ type: "boolean",
516
+ description: "Show detailed endpoint lists",
517
+ default: false,
518
+ },
519
+ },
520
+ },
521
+ },
522
+ {
523
+ name: "get_deploy_verdict",
524
+ description:
525
+ "🚦 Get deploy verdict - returns ship/no-ship decision with blockers and risk score",
526
+ inputSchema: {
527
+ type: "object",
528
+ properties: {
529
+ projectPath: {
530
+ type: "string",
531
+ description: "Path to project root directory",
532
+ default: ".",
533
+ },
534
+ },
535
+ },
536
+ },
537
+ // 🛡️ Production Integrity Suite
538
+ {
539
+ name: "production_integrity_check",
540
+ description:
541
+ "🛡️ Full production integrity audit - combines API wiring, auth coverage, secrets, routes, and mock detection into one comprehensive report with integrity score",
542
+ inputSchema: {
543
+ type: "object",
544
+ properties: {
545
+ projectPath: {
546
+ type: "string",
547
+ description: "Path to project root directory",
548
+ default: ".",
549
+ },
550
+ },
551
+ },
552
+ },
553
+ {
554
+ name: "audit_auth_coverage",
555
+ description:
556
+ "🔐 Auth/RBAC coverage scanner - detects unprotected endpoints, missing auth middleware, exposed admin routes, and missing role checks",
557
+ inputSchema: {
558
+ type: "object",
559
+ properties: {
560
+ projectPath: {
561
+ type: "string",
562
+ description: "Path to project root directory",
563
+ default: ".",
564
+ },
565
+ },
566
+ },
567
+ },
568
+ {
569
+ name: "audit_env_secrets",
570
+ description:
571
+ "🔑 Environment & secrets audit - detects hardcoded secrets, leaked NEXT_PUBLIC vars, missing env vars, and generates .env.example",
572
+ inputSchema: {
573
+ type: "object",
574
+ properties: {
575
+ projectPath: {
576
+ type: "string",
577
+ description: "Path to project root directory",
578
+ default: ".",
579
+ },
580
+ },
581
+ },
582
+ },
583
+ {
584
+ name: "audit_route_integrity",
585
+ description:
586
+ "🗺️ Route integrity scanner - finds dead links, unused pages, placeholder content, and feature flags that may hide sections",
587
+ inputSchema: {
588
+ type: "object",
589
+ properties: {
590
+ projectPath: {
591
+ type: "string",
592
+ description: "Path to project root directory",
593
+ default: ".",
594
+ },
595
+ },
596
+ },
597
+ },
598
+ {
599
+ name: "audit_mock_blocker",
600
+ description:
601
+ "🚫 Mock/stub ship blocker - detects test imports, mock code, debug statements, and test credentials that shouldn't ship to production",
602
+ inputSchema: {
603
+ type: "object",
604
+ properties: {
605
+ projectPath: {
606
+ type: "string",
607
+ description: "Path to project root directory",
608
+ default: ".",
609
+ },
610
+ },
611
+ },
612
+ },
613
+ // 🔮 Reality Check - The Ultimate Truth Detector
614
+ {
615
+ name: "reality_check",
616
+ description:
617
+ "🔮 Reality Check - The ultimate production truth detector. Runs comprehensive integrity audit: API wiring, auth coverage, secrets, routes, mock code detection, plus code-level self-deception analysis. Returns full report with integrity score and ship/no-ship verdict.",
618
+ inputSchema: {
619
+ type: "object",
620
+ properties: {
621
+ projectPath: {
622
+ type: "string",
623
+ description: "Path to project root directory",
624
+ default: ".",
625
+ },
626
+ mode: {
627
+ type: "string",
628
+ enum: ["full", "quick", "code-only"],
629
+ description:
630
+ "full = complete production audit (default), quick = summary only, code-only = just analyze specific file",
631
+ default: "full",
632
+ },
633
+ file: {
634
+ type: "string",
635
+ description: "Specific file to analyze (for code-only mode)",
636
+ },
637
+ },
638
+ },
639
+ },
640
+ {
641
+ name: "reality_check_deep",
642
+ description:
643
+ "🔮 Deep Reality Check (Pro) - Cross-file analysis, call graph tracing, async lifecycle analysis, and AI intent verification",
644
+ inputSchema: {
645
+ type: "object",
646
+ properties: {
647
+ projectPath: {
648
+ type: "string",
649
+ description: "Path to project root directory",
650
+ default: ".",
651
+ },
652
+ file: {
653
+ type: "string",
654
+ description: "File path to analyze",
655
+ },
656
+ includeCallGraph: {
657
+ type: "boolean",
658
+ description: "Include call graph analysis",
659
+ default: true,
660
+ },
661
+ includeAsyncAnalysis: {
662
+ type: "boolean",
663
+ description: "Include async/await lifecycle analysis",
664
+ default: true,
665
+ },
666
+ },
667
+ required: ["file"],
668
+ },
669
+ },
670
+ // 🤖 AI-Enhanced Production Integrity
671
+ {
672
+ name: "ai_production_integrity",
673
+ description:
674
+ "🤖 AI-Enhanced Production Integrity - Uses LLM to analyze findings, generate intelligent fix suggestions, explain security risks, and provide prioritized action items with business impact analysis",
675
+ inputSchema: {
676
+ type: "object",
677
+ properties: {
678
+ projectPath: {
679
+ type: "string",
680
+ description: "Path to project root directory",
681
+ default: ".",
682
+ },
683
+ enableAI: {
684
+ type: "boolean",
685
+ description:
686
+ "Enable AI-powered analysis (requires OPENAI_API_KEY)",
687
+ default: true,
688
+ },
689
+ },
690
+ },
691
+ },
692
+ {
693
+ name: "ai_explain_finding",
694
+ description:
695
+ "🧠 AI Explain Finding - Get detailed AI explanation of a security finding including attack scenarios, compliance impact, and step-by-step fix with code examples",
696
+ inputSchema: {
697
+ type: "object",
698
+ properties: {
699
+ finding: {
700
+ type: "object",
701
+ description: "The finding object to explain",
702
+ properties: {
703
+ category: { type: "string" },
704
+ severity: { type: "string" },
705
+ title: { type: "string" },
706
+ description: { type: "string" },
707
+ file: { type: "string" },
708
+ code: { type: "string" },
709
+ },
710
+ required: ["category", "title"],
711
+ },
712
+ context: {
713
+ type: "string",
714
+ description: "Additional context about the codebase",
715
+ },
716
+ },
717
+ required: ["finding"],
718
+ },
719
+ },
720
+ {
721
+ name: "ai_generate_fix",
722
+ description:
723
+ "🔧 AI Generate Fix - Generate AI-powered code fix for a specific finding with step-by-step instructions and working code example",
724
+ inputSchema: {
725
+ type: "object",
726
+ properties: {
727
+ finding: {
728
+ type: "object",
729
+ description: "The finding to fix",
730
+ properties: {
731
+ category: { type: "string" },
732
+ severity: { type: "string" },
733
+ title: { type: "string" },
734
+ description: { type: "string" },
735
+ file: { type: "string" },
736
+ code: { type: "string" },
737
+ },
738
+ required: ["category", "title"],
739
+ },
740
+ },
741
+ required: ["finding"],
742
+ },
743
+ },
744
+ {
745
+ name: "ai_security_assessment",
746
+ description:
747
+ "🛡️ AI Security Assessment - Get comprehensive AI-powered security posture assessment with risk matrix, compliance gaps, and remediation roadmap",
748
+ inputSchema: {
749
+ type: "object",
750
+ properties: {
751
+ projectPath: {
752
+ type: "string",
753
+ description: "Path to project root directory",
754
+ default: ".",
755
+ },
756
+ complianceFrameworks: {
757
+ type: "array",
758
+ items: { type: "string" },
759
+ description:
760
+ "Compliance frameworks to check (e.g., SOC2, GDPR, HIPAA)",
761
+ default: ["SOC2", "GDPR"],
762
+ },
763
+ },
764
+ },
765
+ },
766
+ // Premium Command Palette Tools
767
+ ...PREMIUM_TOOLS,
768
+ // 🧹 Repo Hygiene + Debt Radar
769
+ {
770
+ name: "repo_hygiene_scan",
771
+ description:
772
+ "🧹 Full repo hygiene scan - duplicates, unused files, lint/type errors, root cleanup. Generates deletion-safe plan.",
773
+ inputSchema: {
774
+ type: "object",
775
+ properties: {
776
+ projectPath: {
777
+ type: "string",
778
+ description: "Path to project root",
779
+ default: ".",
780
+ },
781
+ mode: {
782
+ type: "string",
783
+ enum: ["report", "safe-fix"],
784
+ default: "report",
785
+ },
786
+ saveArtifacts: { type: "boolean", default: true },
787
+ },
788
+ },
789
+ },
790
+ {
791
+ name: "repo_hygiene_duplicates",
792
+ description:
793
+ "📋 Find duplicate files - exact (same hash), near-duplicate (85%+ similar), and copy-paste blocks",
794
+ inputSchema: {
795
+ type: "object",
796
+ properties: {
797
+ projectPath: { type: "string", default: "." },
798
+ threshold: {
799
+ type: "number",
800
+ description: "Similarity threshold",
801
+ default: 0.85,
802
+ },
803
+ },
804
+ },
805
+ },
806
+ {
807
+ name: "repo_hygiene_unused",
808
+ description:
809
+ "📦 Find unused files via import graph analysis from entrypoints. Classifies by deletion safety.",
810
+ inputSchema: {
811
+ type: "object",
812
+ properties: {
813
+ projectPath: { type: "string", default: "." },
814
+ scope: {
815
+ type: "string",
816
+ enum: ["all", "prod", "test"],
817
+ default: "all",
818
+ },
819
+ },
820
+ },
821
+ },
822
+ {
823
+ name: "repo_hygiene_errors",
824
+ description:
825
+ "🔴 Unified lint/type/import/syntax error collection. CI-friendly with counts and top offenders.",
826
+ inputSchema: {
827
+ type: "object",
828
+ properties: {
829
+ projectPath: { type: "string", default: "." },
830
+ eslint: { type: "boolean", default: true },
831
+ tsc: { type: "boolean", default: true },
832
+ imports: { type: "boolean", default: true },
833
+ syntax: { type: "boolean", default: true },
834
+ },
835
+ },
836
+ },
837
+ {
838
+ name: "repo_hygiene_root_cleanup",
839
+ description:
840
+ "🏠 Root directory analyzer - junk files, missing standards, duplicate configs, misplaced files",
841
+ inputSchema: {
842
+ type: "object",
843
+ properties: {
844
+ projectPath: { type: "string", default: "." },
845
+ },
846
+ },
847
+ },
848
+ {
849
+ name: "repo_hygiene_deletion_plan",
850
+ description:
851
+ "🗑️ Generate safe deletion plan for duplicates and unused files. Never auto-deletes.",
852
+ inputSchema: {
853
+ type: "object",
854
+ properties: {
855
+ projectPath: { type: "string", default: "." },
856
+ includeReview: { type: "boolean", default: false },
857
+ },
858
+ },
859
+ },
860
+ ],
861
+ }));
862
+
863
+ // List available resources
864
+ this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
865
+ resources: [
866
+ {
867
+ uri: "guardrails://rules",
868
+ name: "Guardrails Rules",
869
+ description:
870
+ "Current guardrails rules and file organization constraints",
871
+ mimeType: "text/markdown",
872
+ },
873
+ {
874
+ uri: "guardrails://templates",
875
+ name: "Available Templates",
876
+ description: "List of available project templates",
877
+ mimeType: "application/json",
878
+ },
879
+ {
880
+ uri: "guardrails://design-tokens",
881
+ name: "Design Tokens",
882
+ description: "Current design system tokens (if locked)",
883
+ mimeType: "application/json",
884
+ },
885
+ ],
886
+ }));
887
+
888
+ // Read resources
889
+ this.server.setRequestHandler(
890
+ ReadResourceRequestSchema,
891
+ async (request) => {
892
+ const { uri } = request.params;
893
+
894
+ switch (uri) {
895
+ case "guardrails://rules":
896
+ return {
897
+ contents: [
898
+ {
899
+ uri,
900
+ mimeType: "text/markdown",
901
+ text: await this.getGuardrailsRules(),
902
+ },
903
+ ],
904
+ };
905
+
906
+ case "guardrails://templates":
907
+ return {
908
+ contents: [
909
+ {
910
+ uri,
911
+ mimeType: "application/json",
912
+ text: JSON.stringify(
913
+ await this.getAvailableTemplates(),
914
+ null,
915
+ 2,
916
+ ),
917
+ },
918
+ ],
919
+ };
920
+
921
+ case "guardrails://design-tokens":
922
+ return {
923
+ contents: [
924
+ {
925
+ uri,
926
+ mimeType: "application/json",
927
+ text: JSON.stringify(await this.getDesignTokens(), null, 2),
928
+ },
929
+ ],
930
+ };
931
+
932
+ default:
933
+ throw new Error(`Unknown resource: ${uri}`);
934
+ }
935
+ },
936
+ );
937
+
938
+ // Handle tool calls with enhanced error handling and progress feedback
939
+ this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
940
+ const { name, arguments: args } = request.params;
941
+ const projectPath = args?.projectPath || process.cwd();
942
+
943
+ // Log tool usage
944
+ this.logger.info(`Executing tool: ${name}`, { projectPath, args });
945
+
946
+ // Validate project path
947
+ if (!projectPath || typeof projectPath !== "string") {
948
+ const error = "Invalid project path provided";
949
+ this.logger.error(error, { projectPath });
950
+ return {
951
+ content: [{ type: "text", text: `❌ Error: ${error}` }],
952
+ isError: true,
953
+ };
954
+ }
955
+
956
+ try {
957
+ // Show progress for long-running operations
958
+ const startTime = Date.now();
959
+ let result;
960
+
961
+ switch (name) {
962
+ case "validate_project":
963
+ result = await this.validateProject(projectPath);
964
+ break;
965
+
966
+ case "check_design_system":
967
+ result = await this.checkDesignSystem(projectPath);
968
+ break;
969
+
970
+ case "check_project_drift":
971
+ result = await this.checkProjectDrift(projectPath);
972
+ break;
973
+
974
+ case "setup_design_system":
975
+ result = await this.setupDesignSystem(
976
+ projectPath,
977
+ args?.theme || "modern",
978
+ );
979
+ break;
980
+
981
+ case "get_project_health":
982
+ result = await this.getProjectHealth(projectPath);
983
+ break;
984
+
985
+ case "register_api_endpoint":
986
+ result = await this.registerApiEndpoint(
987
+ projectPath,
988
+ args.path,
989
+ args.method,
990
+ args.description,
991
+ );
992
+ break;
993
+
994
+ case "get_guardrails_rules":
995
+ result = await this.getGuardrailsRulesResponse(projectPath);
996
+ break;
997
+
998
+ case "architect_analyze":
999
+ result = await this.architectAnalyze(projectPath);
1000
+ break;
1001
+
1002
+ case "architect_apply":
1003
+ result = await this.architectApply(
1004
+ projectPath,
1005
+ args?.autoApply !== false,
1006
+ );
1007
+ break;
1008
+
1009
+ case "build_knowledge_base":
1010
+ result = await this.buildKnowledgeBase(projectPath);
1011
+ break;
1012
+
1013
+ case "get_deep_context":
1014
+ result = await this.getDeepContext(
1015
+ projectPath,
1016
+ args?.query,
1017
+ args?.style || "professional",
1018
+ args?.useEmojis !== undefined ? args.useEmojis : true,
1019
+ args?.includeExamples !== undefined
1020
+ ? args.includeExamples
1021
+ : false,
1022
+ );
1023
+ break;
1024
+
1025
+ case "semantic_search":
1026
+ result = await this.semanticSearch(projectPath, args?.query);
1027
+ break;
1028
+
1029
+ case "analyze_change_impact":
1030
+ result = await this.analyzeChangeImpact(projectPath, args?.file);
1031
+ break;
1032
+
1033
+ case "generate_code_context":
1034
+ result = await this.generateCodeContext(projectPath, args?.task);
1035
+ break;
1036
+
1037
+ // Security Orchestrator tools
1038
+ case "security_scan":
1039
+ result = await this.securityScan(
1040
+ projectPath,
1041
+ args?.environment || "production",
1042
+ );
1043
+ break;
1044
+
1045
+ case "policy_check":
1046
+ result = await this.policyCheck(
1047
+ projectPath,
1048
+ args?.environment || "production",
1049
+ );
1050
+ break;
1051
+
1052
+ case "secret_scan":
1053
+ result = await this.secretScan(
1054
+ projectPath,
1055
+ args?.scanHistory || false,
1056
+ );
1057
+ break;
1058
+
1059
+ case "supply_chain_scan":
1060
+ result = await this.supplyChainScan(projectPath, args?.repoUrl);
1061
+ break;
1062
+
1063
+ case "ship_check":
1064
+ result = await this.shipCheck(projectPath);
1065
+ break;
1066
+
1067
+ case "get_deploy_verdict":
1068
+ result = await this.getDeployVerdict(projectPath);
1069
+ break;
1070
+
1071
+ case "audit_api_endpoints":
1072
+ result = await this.auditApiEndpoints(
1073
+ projectPath,
1074
+ args?.showDetails || false,
1075
+ );
1076
+ break;
1077
+
1078
+ case "production_integrity_check":
1079
+ result = await this.productionIntegrityCheck(projectPath);
1080
+ break;
1081
+
1082
+ case "audit_auth_coverage":
1083
+ result = await this.auditAuthCoverage(projectPath);
1084
+ break;
1085
+
1086
+ case "audit_env_secrets":
1087
+ result = await this.auditEnvSecrets(projectPath);
1088
+ break;
1089
+
1090
+ case "audit_route_integrity":
1091
+ result = await this.auditRouteIntegrity(projectPath);
1092
+ break;
1093
+
1094
+ case "audit_mock_blocker":
1095
+ result = await this.auditMockBlocker(projectPath);
1096
+ break;
1097
+
1098
+ case "reality_check":
1099
+ result = await this.realityCheck(
1100
+ projectPath,
1101
+ args?.mode || "full",
1102
+ args?.file,
1103
+ );
1104
+ break;
1105
+
1106
+ case "reality_check_deep":
1107
+ result = await this.realityCheckDeep(
1108
+ projectPath,
1109
+ args?.file,
1110
+ args?.includeCallGraph,
1111
+ args?.includeAsyncAnalysis,
1112
+ );
1113
+ break;
1114
+
1115
+ // 🤖 AI-Enhanced Production Integrity Tools
1116
+ case "ai_production_integrity":
1117
+ result = await this.aiProductionIntegrity(
1118
+ projectPath,
1119
+ args?.enableAI !== false,
1120
+ );
1121
+ break;
1122
+
1123
+ case "ai_explain_finding":
1124
+ result = await this.aiExplainFinding(args?.finding, args?.context);
1125
+ break;
1126
+
1127
+ case "ai_generate_fix":
1128
+ result = await this.aiGenerateFix(args?.finding);
1129
+ break;
1130
+
1131
+ case "ai_security_assessment":
1132
+ result = await this.aiSecurityAssessment(
1133
+ projectPath,
1134
+ args?.complianceFrameworks || ["SOC2", "GDPR"],
1135
+ );
1136
+ break;
1137
+
1138
+ // Repo Hygiene + Debt Radar tools
1139
+ case "repo_hygiene_scan":
1140
+ result = await this.repoHygieneScan(
1141
+ projectPath,
1142
+ args?.mode,
1143
+ args?.saveArtifacts,
1144
+ );
1145
+ break;
1146
+
1147
+ case "repo_hygiene_duplicates":
1148
+ result = await this.repoHygieneDuplicates(
1149
+ projectPath,
1150
+ args?.threshold,
1151
+ );
1152
+ break;
1153
+
1154
+ case "repo_hygiene_unused":
1155
+ result = await this.repoHygieneUnused(projectPath, args?.scope);
1156
+ break;
1157
+
1158
+ case "repo_hygiene_errors":
1159
+ result = await this.repoHygieneErrors(projectPath, args);
1160
+ break;
1161
+
1162
+ case "repo_hygiene_root_cleanup":
1163
+ result = await this.repoHygieneRootCleanup(projectPath);
1164
+ break;
1165
+
1166
+ case "repo_hygiene_deletion_plan":
1167
+ result = await this.repoHygieneDeletionPlan(
1168
+ projectPath,
1169
+ args?.includeReview,
1170
+ );
1171
+ break;
1172
+
1173
+ default:
1174
+ // Try premium tools first
1175
+ const premiumResult = await handlePremiumTool(
1176
+ name,
1177
+ args,
1178
+ this.logger,
1179
+ );
1180
+ if (premiumResult) {
1181
+ result = premiumResult;
1182
+ break;
1183
+ }
1184
+
1185
+ const error = `Unknown tool: ${name}`;
1186
+ this.logger.error(error);
1187
+ return {
1188
+ content: [{ type: "text", text: `❌ Error: ${error}` }],
1189
+ isError: true,
1190
+ };
1191
+ }
1192
+
1193
+ // Log completion
1194
+ const duration = Date.now() - startTime;
1195
+ this.logger.info(`Tool completed: ${name}`, {
1196
+ duration: `${duration}ms`,
1197
+ });
1198
+
1199
+ return result;
1200
+ } catch (error) {
1201
+ // Enhanced error reporting
1202
+ const errorMessage = error.message || "Unknown error occurred";
1203
+ const errorDetails = {
1204
+ tool: name,
1205
+ error: errorMessage,
1206
+ stack: error.stack,
1207
+ projectPath,
1208
+ };
1209
+
1210
+ this.logger.error(`Tool failed: ${name}`, errorDetails);
1211
+
1212
+ return {
1213
+ content: [
1214
+ {
1215
+ type: "text",
1216
+ text: `❌ Error executing ${name}: ${errorMessage}\n\n💡 Tip: Check if you're in a valid project directory and all required files exist.`,
1217
+ },
1218
+ ],
1219
+ isError: true,
1220
+ };
1221
+ }
1222
+ });
1223
+ }
1224
+
1225
+ async validateProject(projectPath) {
1226
+ try {
1227
+ const scriptsPath = path.join(
1228
+ __dirname,
1229
+ "..",
1230
+ "scripts",
1231
+ "validate-api-endpoints.js",
1232
+ );
1233
+ const result = execSync(`node "${scriptsPath}"`, {
1234
+ cwd: projectPath,
1235
+ encoding: "utf8",
1236
+ stdio: "pipe",
1237
+ });
1238
+
1239
+ return {
1240
+ content: [
1241
+ {
1242
+ type: "text",
1243
+ text: result || "✅ Validation passed!",
1244
+ },
1245
+ ],
1246
+ };
1247
+ } catch (error) {
1248
+ return {
1249
+ content: [
1250
+ {
1251
+ type: "text",
1252
+ text: `Validation issues found:\n${error.stdout || error.message}`,
1253
+ },
1254
+ ],
1255
+ };
1256
+ }
1257
+ }
1258
+
1259
+ async checkDesignSystem(projectPath) {
1260
+ try {
1261
+ const scriptsPath = path.join(
1262
+ __dirname,
1263
+ "..",
1264
+ "scripts",
1265
+ "validate-design-system.js",
1266
+ );
1267
+ const result = execSync(`node "${scriptsPath}"`, {
1268
+ cwd: projectPath,
1269
+ encoding: "utf8",
1270
+ stdio: "pipe",
1271
+ });
1272
+
1273
+ return {
1274
+ content: [
1275
+ {
1276
+ type: "text",
1277
+ text: result || "✅ Design system is consistent!",
1278
+ },
1279
+ ],
1280
+ };
1281
+ } catch (error) {
1282
+ return {
1283
+ content: [
1284
+ {
1285
+ type: "text",
1286
+ text: `Design system issues:\n${error.stdout || error.message}`,
1287
+ },
1288
+ ],
1289
+ };
1290
+ }
1291
+ }
1292
+
1293
+ async checkProjectDrift(projectPath) {
1294
+ try {
1295
+ const scriptsPath = path.join(
1296
+ __dirname,
1297
+ "..",
1298
+ "scripts",
1299
+ "check-project-drift.js",
1300
+ );
1301
+ const result = execSync(`node "${scriptsPath}"`, {
1302
+ cwd: projectPath,
1303
+ encoding: "utf8",
1304
+ stdio: "pipe",
1305
+ });
1306
+
1307
+ return {
1308
+ content: [
1309
+ {
1310
+ type: "text",
1311
+ text: result || "✅ No drift detected!",
1312
+ },
1313
+ ],
1314
+ };
1315
+ } catch (error) {
1316
+ return {
1317
+ content: [
1318
+ {
1319
+ type: "text",
1320
+ text: `Drift detected:\n${error.stdout || error.message}`,
1321
+ },
1322
+ ],
1323
+ };
1324
+ }
1325
+ }
1326
+
1327
+ async setupDesignSystem(projectPath, theme) {
1328
+ try {
1329
+ // This would call the design system wizard
1330
+ // For now, return instructions
1331
+ return {
1332
+ content: [
1333
+ {
1334
+ type: "text",
1335
+ text: `To set up design system, run: npm run design-system\nOr use theme: ${theme}`,
1336
+ },
1337
+ ],
1338
+ };
1339
+ } catch (error) {
1340
+ return {
1341
+ content: [
1342
+ {
1343
+ type: "text",
1344
+ text: `Error: ${error.message}`,
1345
+ },
1346
+ ],
1347
+ isError: true,
1348
+ };
1349
+ }
1350
+ }
1351
+
1352
+ async getProjectHealth(projectPath) {
1353
+ // This would use the project health analyzer
1354
+ return {
1355
+ content: [
1356
+ {
1357
+ type: "text",
1358
+ text: "Project health scoring is a premium feature. Upgrade to Professional or Enterprise tier.",
1359
+ },
1360
+ ],
1361
+ };
1362
+ }
1363
+
1364
+ async registerApiEndpoint(projectPath, endpointPath, method, description) {
1365
+ try {
1366
+ const endpointsFile = path.join(
1367
+ projectPath,
1368
+ "src",
1369
+ "config",
1370
+ "api-endpoints.ts",
1371
+ );
1372
+
1373
+ // Read existing file or create new
1374
+ let content = "";
1375
+ try {
1376
+ content = await fs.readFile(endpointsFile, "utf8");
1377
+ } catch {
1378
+ // File doesn't exist, create it
1379
+ const dir = path.dirname(endpointsFile);
1380
+ await fs.mkdir(dir, { recursive: true });
1381
+ content = `import { apiValidator } from '@/lib/api-validator';
1382
+
1383
+ export function registerAllEndpoints() {
1384
+ `;
1385
+ }
1386
+
1387
+ // Add endpoint registration
1388
+ const registration = ` apiValidator.registerEndpoint({
1389
+ path: '${endpointPath}',
1390
+ method: '${method}',
1391
+ description: '${description || ""}',
1392
+ });
1393
+ `;
1394
+
1395
+ // Insert before the closing brace
1396
+ const updatedContent = content.replace(
1397
+ /(\s*)(\})/,
1398
+ `$1${registration}$1$2`,
1399
+ );
1400
+
1401
+ await fs.writeFile(endpointsFile, updatedContent);
1402
+
1403
+ return {
1404
+ content: [
1405
+ {
1406
+ type: "text",
1407
+ text: `✅ Registered endpoint: ${method} ${endpointPath}`,
1408
+ },
1409
+ ],
1410
+ };
1411
+ } catch (error) {
1412
+ return {
1413
+ content: [
1414
+ {
1415
+ type: "text",
1416
+ text: `Error: ${error.message}`,
1417
+ },
1418
+ ],
1419
+ isError: true,
1420
+ };
1421
+ }
1422
+ }
1423
+
1424
+ async getGuardrailsRulesResponse(projectPath) {
1425
+ const rulesPath = path.join(projectPath, ".cursorrules");
1426
+ try {
1427
+ const rules = await fs.readFile(rulesPath, "utf8");
1428
+ return {
1429
+ content: [
1430
+ {
1431
+ type: "text",
1432
+ text: rules,
1433
+ },
1434
+ ],
1435
+ };
1436
+ } catch {
1437
+ return {
1438
+ content: [
1439
+ {
1440
+ type: "text",
1441
+ text: "No .cursorrules file found. Run setup to create guardrails.",
1442
+ },
1443
+ ],
1444
+ };
1445
+ }
1446
+ }
1447
+
1448
+ async getGuardrailsRules() {
1449
+ return `# AI Agent Guardrails Rules
1450
+
1451
+ ## CRITICAL RULES
1452
+
1453
+ ### 1. FILE ORGANIZATION
1454
+ - NEVER create files in root directory (except allowed config files)
1455
+ - ALWAYS specify full file paths when creating files
1456
+ - Use feature-based organization: /src/features/[name]/
1457
+
1458
+ ### 2. NO MOCK DATA
1459
+ - NEVER use mock data, fake endpoints, or placeholder data
1460
+ - ALWAYS use real API endpoints that are registered
1461
+ - Register new endpoints using register_api_endpoint tool
1462
+
1463
+ ### 3. DESIGN SYSTEM
1464
+ - ALWAYS use design tokens from locked design system
1465
+ - NEVER use hardcoded colors, spacing, or values
1466
+ - Use validate_design_system tool to check consistency
1467
+
1468
+ ### 4. CODE QUALITY
1469
+ - All code must pass ESLint and TypeScript checks
1470
+ - Use proper TypeScript types (no 'any')
1471
+ - Follow the project's architecture patterns
1472
+ `;
1473
+ }
1474
+
1475
+ async getAvailableTemplates() {
1476
+ return {
1477
+ templates: [
1478
+ { id: "00", name: "Quick Start Guide" },
1479
+ { id: "01", name: "UI/UX System" },
1480
+ { id: "02", name: "Design System" },
1481
+ { id: "03", name: "Project Architecture" },
1482
+ { id: "04", name: "API Architecture" },
1483
+ { id: "05", name: "AI Agent File Rules" },
1484
+ { id: "06", name: "Testing Setup" },
1485
+ { id: "07", name: "State Management" },
1486
+ { id: "08", name: "Environment Config" },
1487
+ { id: "09", name: "Database & ORM" },
1488
+ { id: "10", name: "Authentication" },
1489
+ ],
1490
+ };
1491
+ }
1492
+
1493
+ async getDesignTokens() {
1494
+ const lockFile = path.join(process.cwd(), ".design-system-lock.json");
1495
+ try {
1496
+ const lock = JSON.parse(await fs.readFile(lockFile, "utf8"));
1497
+ return {
1498
+ locked: true,
1499
+ theme: lock.theme,
1500
+ message:
1501
+ "Design system is locked. Use design tokens for all components.",
1502
+ };
1503
+ } catch {
1504
+ return {
1505
+ locked: false,
1506
+ message:
1507
+ "No design system locked. Run setup_design_system tool to lock one.",
1508
+ };
1509
+ }
1510
+ }
1511
+
1512
+ async architectAnalyze(projectPath) {
1513
+ try {
1514
+ // Import architect agent (using dynamic import for ES modules)
1515
+ const { architectAgent } = await import("../src/lib/architect-agent.js");
1516
+ const analysis = await architectAgent.analyzeProject(projectPath);
1517
+
1518
+ const output = {
1519
+ context: analysis.context,
1520
+ recommendations: analysis.recommendations.map((rec) => ({
1521
+ action: rec.action,
1522
+ priority: rec.priority,
1523
+ description: rec.description,
1524
+ templates: rec.templates,
1525
+ autoApply: rec.autoApply,
1526
+ })),
1527
+ plan: {
1528
+ totalTemplates: analysis.plan.templates.length,
1529
+ estimatedTime: analysis.plan.estimatedTime,
1530
+ templates: analysis.plan.templates.map((t) => ({
1531
+ name: t.name,
1532
+ category: t.category,
1533
+ priority: t.priority,
1534
+ reason: t.reason,
1535
+ })),
1536
+ },
1537
+ };
1538
+
1539
+ return {
1540
+ content: [
1541
+ {
1542
+ type: "text",
1543
+ text:
1544
+ `🏗️ Architect Agent Analysis\n\n` +
1545
+ `Project Type: ${analysis.context.type}\n` +
1546
+ `Framework: ${analysis.context.framework.join(", ") || "None"}\n` +
1547
+ `Stage: ${analysis.context.stage}\n\n` +
1548
+ `Found ${analysis.recommendations.length} recommendations\n` +
1549
+ `Plan includes ${analysis.plan.templates.length} templates\n` +
1550
+ `Estimated time: ${analysis.plan.estimatedTime}\n\n` +
1551
+ `Use architect_apply tool to apply templates automatically.`,
1552
+ },
1553
+ {
1554
+ type: "text",
1555
+ text: JSON.stringify(output, null, 2),
1556
+ mimeType: "application/json",
1557
+ },
1558
+ ],
1559
+ };
1560
+ } catch (error) {
1561
+ return {
1562
+ content: [
1563
+ {
1564
+ type: "text",
1565
+ text: `Error analyzing project: ${error.message}\n\nMake sure you're in a valid project directory.`,
1566
+ },
1567
+ ],
1568
+ isError: true,
1569
+ };
1570
+ }
1571
+ }
1572
+
1573
+ async architectApply(projectPath, autoApply) {
1574
+ try {
1575
+ const { architectAgent } = await import("../src/lib/architect-agent.js");
1576
+ const analysis = await architectAgent.analyzeProject(projectPath);
1577
+ const result = await architectAgent.applyTemplates(
1578
+ projectPath,
1579
+ analysis.plan,
1580
+ autoApply,
1581
+ );
1582
+
1583
+ const summary =
1584
+ `✅ Applied: ${result.applied.length}\n` +
1585
+ `⏭️ Skipped: ${result.skipped.length}\n` +
1586
+ (result.errors.length > 0
1587
+ ? `❌ Errors: ${result.errors.length}\n`
1588
+ : "");
1589
+
1590
+ return {
1591
+ content: [
1592
+ {
1593
+ type: "text",
1594
+ text:
1595
+ `🏗️ Architect Agent - Template Application\n\n${summary}\n\n` +
1596
+ (result.applied.length > 0
1597
+ ? `Applied templates:\n${result.applied.map((id) => ` ✅ ${id}`).join("\n")}\n\n`
1598
+ : "") +
1599
+ (result.errors.length > 0
1600
+ ? `Errors:\n${result.errors.map((e) => ` ❌ ${e.template}: ${e.error}`).join("\n")}\n\n`
1601
+ : "") +
1602
+ `Review applied templates and customize as needed.`,
1603
+ },
1604
+ ],
1605
+ };
1606
+ } catch (error) {
1607
+ return {
1608
+ content: [
1609
+ {
1610
+ type: "text",
1611
+ text: `Error applying templates: ${error.message}`,
1612
+ },
1613
+ ],
1614
+ isError: true,
1615
+ };
1616
+ }
1617
+ }
1618
+
1619
+ async buildKnowledgeBase(projectPath) {
1620
+ try {
1621
+ const { codebaseKnowledgeBase } =
1622
+ await import("../src/lib/codebase-knowledge.js");
1623
+ const knowledge = await codebaseKnowledgeBase.buildKnowledge(projectPath);
1624
+
1625
+ return {
1626
+ content: [
1627
+ {
1628
+ type: "text",
1629
+ text:
1630
+ `🧠 Knowledge Base Built!\n\n` +
1631
+ `Architecture: ${knowledge.architecture.structure.type}\n` +
1632
+ `Patterns: ${knowledge.patterns.length}\n` +
1633
+ `Files analyzed: ${knowledge.relationships.imports.size}\n` +
1634
+ `Active features: ${knowledge.context.activeFeatures.length}\n\n` +
1635
+ `Knowledge saved to .codebase-knowledge.json\n` +
1636
+ `Use get_deep_context tool to query this knowledge.`,
1637
+ },
1638
+ ],
1639
+ };
1640
+ } catch (error) {
1641
+ return {
1642
+ content: [
1643
+ {
1644
+ type: "text",
1645
+ text: `Error building knowledge base: ${error.message}`,
1646
+ },
1647
+ ],
1648
+ isError: true,
1649
+ };
1650
+ }
1651
+ }
1652
+
1653
+ async getDeepContext(
1654
+ projectPath,
1655
+ query,
1656
+ style = "professional",
1657
+ useEmojis = true,
1658
+ includeExamples = false,
1659
+ ) {
1660
+ if (!query) {
1661
+ return {
1662
+ content: [
1663
+ {
1664
+ type: "text",
1665
+ text: "Error: query parameter is required",
1666
+ },
1667
+ ],
1668
+ isError: true,
1669
+ };
1670
+ }
1671
+
1672
+ try {
1673
+ const { deepContextAgent } =
1674
+ await import("../src/lib/deep-context-agent.js");
1675
+ const { responseStyleService } =
1676
+ await import("../src/lib/response-style-service.js");
1677
+
1678
+ // Validate style
1679
+ const availableStyles = responseStyleService.getAvailableStyles();
1680
+ const validStyle = availableStyles.includes(style)
1681
+ ? style
1682
+ : "professional";
1683
+
1684
+ await deepContextAgent.initialize(projectPath);
1685
+
1686
+ // Get formatted response with style
1687
+ const formattedResponse = await deepContextAgent.getFormattedContext(
1688
+ query,
1689
+ projectPath,
1690
+ validStyle,
1691
+ {
1692
+ useEmojis,
1693
+ includeExamples,
1694
+ },
1695
+ );
1696
+
1697
+ return {
1698
+ content: [
1699
+ {
1700
+ type: "text",
1701
+ text: formattedResponse,
1702
+ },
1703
+ ],
1704
+ };
1705
+ } catch (error) {
1706
+ const { responseStyleService } =
1707
+ await import("../src/lib/response-style-service.js");
1708
+ const errorMessage = responseStyleService.formatMessage(
1709
+ `Error getting context: ${error.message}\n\nTry running build_knowledge_base first.`,
1710
+ style || "professional",
1711
+ useEmojis,
1712
+ );
1713
+
1714
+ return {
1715
+ content: [
1716
+ {
1717
+ type: "text",
1718
+ text: errorMessage,
1719
+ },
1720
+ ],
1721
+ isError: true,
1722
+ };
1723
+ }
1724
+ }
1725
+
1726
+ async semanticSearch(projectPath, query) {
1727
+ try {
1728
+ // Import the semantic search service
1729
+ const { semanticSearchService } =
1730
+ await import("../src/lib/semantic-search-service.js");
1731
+
1732
+ // Perform semantic search
1733
+ const results = await semanticSearchService.search(
1734
+ query,
1735
+ projectPath,
1736
+ 10,
1737
+ );
1738
+
1739
+ if (results.length === 0) {
1740
+ return {
1741
+ content: [
1742
+ {
1743
+ type: "text",
1744
+ text: `🔍 No results found for "${query}"\n\nTry different keywords or check if the files are indexed.`,
1745
+ },
1746
+ ],
1747
+ };
1748
+ }
1749
+
1750
+ // Format results
1751
+ let response = `🔍 Semantic Search Results for "${query}"\n\nFound ${results.length} relevant results:\n\n`;
1752
+
1753
+ results.forEach((result, index) => {
1754
+ const relativePath = result.file
1755
+ .replace(projectPath, "")
1756
+ .replace(/^[\/\\]/, "");
1757
+ response += `${index + 1}. **${relativePath}:${result.line}**\n`;
1758
+ response += ` 📄 ${result.content.substring(0, 100)}${result.content.length > 100 ? "..." : ""}\n`;
1759
+ response += ` 💡 ${result.context}\n`;
1760
+ response += ` ⭐ Relevance: ${Math.round(result.score * 10)}/10\n\n`;
1761
+ });
1762
+
1763
+ return {
1764
+ content: [
1765
+ {
1766
+ type: "text",
1767
+ text: response,
1768
+ },
1769
+ ],
1770
+ };
1771
+ } catch (error) {
1772
+ this.logger.error("Semantic search failed", {
1773
+ error: error.message,
1774
+ projectPath,
1775
+ query,
1776
+ });
1777
+ return {
1778
+ content: [
1779
+ {
1780
+ type: "text",
1781
+ text: `❌ Error performing semantic search: ${error.message}\n\nTip: Ensure you're in a valid project directory with source files.`,
1782
+ },
1783
+ ],
1784
+ isError: true,
1785
+ };
1786
+ }
1787
+ }
1788
+
1789
+ async analyzeChangeImpact(projectPath, file) {
1790
+ try {
1791
+ // Import the change impact analyzer
1792
+ const { changeImpactAnalyzer } =
1793
+ await import("../src/lib/change-impact-analyzer.js");
1794
+
1795
+ // Analyze change impact
1796
+ const analysis = await changeImpactAnalyzer.analyzeImpact(
1797
+ projectPath,
1798
+ file,
1799
+ );
1800
+
1801
+ // Format results
1802
+ let response = `💥 Change Impact Analysis for "${file}"\n\n`;
1803
+ response += `📊 **Summary:**\n`;
1804
+ response += `- Total files affected: ${analysis.summary.totalAffected}\n`;
1805
+ response += `- Risk score: ${analysis.summary.riskScore}/100\n`;
1806
+ response += `- Estimated tests needed: ${analysis.summary.estimatedTests}\n\n`;
1807
+
1808
+ // Critical impact
1809
+ if (analysis.impact.critical.length > 0) {
1810
+ response += `🚨 **Critical Impact (${analysis.impact.critical.length} files):**\n`;
1811
+ analysis.impact.critical.forEach((dep) => {
1812
+ const relativePath = dep.file
1813
+ .replace(projectPath, "")
1814
+ .replace(/^[\/\\]/, "");
1815
+ response += ` - ${relativePath}: ${dep.description}\n`;
1816
+ });
1817
+ response += "\n";
1818
+ }
1819
+
1820
+ // High impact
1821
+ if (analysis.impact.high.length > 0) {
1822
+ response += `⚠️ **High Impact (${analysis.impact.high.length} files):**\n`;
1823
+ analysis.impact.high.forEach((dep) => {
1824
+ const relativePath = dep.file
1825
+ .replace(projectPath, "")
1826
+ .replace(/^[\/\\]/, "");
1827
+ response += ` - ${relativePath}: ${dep.description}\n`;
1828
+ });
1829
+ response += "\n";
1830
+ }
1831
+
1832
+ // Medium impact
1833
+ if (analysis.impact.medium.length > 0) {
1834
+ response += `📋 **Medium Impact (${analysis.impact.medium.length} files):**\n`;
1835
+ analysis.impact.medium.forEach((dep) => {
1836
+ const relativePath = dep.file
1837
+ .replace(projectPath, "")
1838
+ .replace(/^[\/\\]/, "");
1839
+ response += ` - ${relativePath}: ${dep.description}\n`;
1840
+ });
1841
+ response += "\n";
1842
+ }
1843
+
1844
+ // Low impact
1845
+ if (analysis.impact.low.length > 0) {
1846
+ response += `📝 **Low Impact (${analysis.impact.low.length} files):**\n`;
1847
+ analysis.impact.low.forEach((dep) => {
1848
+ const relativePath = dep.file
1849
+ .replace(projectPath, "")
1850
+ .replace(/^[\/\\]/, "");
1851
+ response += ` - ${relativePath}: ${dep.description}\n`;
1852
+ });
1853
+ response += "\n";
1854
+ }
1855
+
1856
+ // Recommendations
1857
+ response += `💡 **Recommendations:**\n`;
1858
+ analysis.recommendations.forEach((rec) => {
1859
+ response += `${rec}\n`;
1860
+ });
1861
+
1862
+ return {
1863
+ content: [
1864
+ {
1865
+ type: "text",
1866
+ text: response,
1867
+ },
1868
+ ],
1869
+ };
1870
+ } catch (error) {
1871
+ this.logger.error("Change impact analysis failed", {
1872
+ error: error.message,
1873
+ projectPath,
1874
+ file,
1875
+ });
1876
+ return {
1877
+ content: [
1878
+ {
1879
+ type: "text",
1880
+ text: `❌ Error analyzing change impact: ${error.message}\n\nTip: Ensure the file exists and is a valid source file.`,
1881
+ },
1882
+ ],
1883
+ isError: true,
1884
+ };
1885
+ }
1886
+ }
1887
+
1888
+ async generateCodeContext(projectPath, task) {
1889
+ try {
1890
+ // Import the code context generator
1891
+ const { codeContextGenerator } =
1892
+ await import("../src/lib/code-context-generator.js");
1893
+
1894
+ // Generate code context
1895
+ const context = await codeContextGenerator.generatePrompt(
1896
+ projectPath,
1897
+ task,
1898
+ );
1899
+
1900
+ // Format results
1901
+ let response = `⚙️ Code Generation Context for: "${task}"\n\n`;
1902
+ response += `📋 **Context:**\n${context.context}\n\n`;
1903
+
1904
+ // Show detected patterns
1905
+ if (context.patterns.length > 0) {
1906
+ response += `🎨 **Detected Patterns:**\n`;
1907
+ context.patterns.forEach((p) => {
1908
+ response += `- Type: ${p.type} (${p.framework})\n`;
1909
+ response += ` Naming: ${p.conventions.naming}\n`;
1910
+ response += ` Exports: ${p.conventions.exports.join(", ")}\n\n`;
1911
+ });
1912
+ }
1913
+
1914
+ // Show best practices
1915
+ if (context.bestPractices.length > 0) {
1916
+ response += `✨ **Best Practices:**\n`;
1917
+ context.bestPractices.forEach((practice) => {
1918
+ response += `- ${practice}\n`;
1919
+ });
1920
+ response += "\n";
1921
+ }
1922
+
1923
+ // Show examples
1924
+ if (context.examples.length > 0) {
1925
+ response += `📝 **Code Examples:**\n`;
1926
+ context.examples.slice(0, 2).forEach((example) => {
1927
+ response += `\n${example.description}:\n`;
1928
+ response += "```typescript\n";
1929
+ response += example.code;
1930
+ response += "\n```\n";
1931
+ });
1932
+ }
1933
+
1934
+ // Add the generated prompt
1935
+ response += `\n🚀 **Generated Prompt:**\n`;
1936
+ response += "```\n";
1937
+ response += context.prompt;
1938
+ response += "\n```\n";
1939
+
1940
+ return {
1941
+ content: [
1942
+ {
1943
+ type: "text",
1944
+ text: response,
1945
+ },
1946
+ ],
1947
+ };
1948
+ } catch (error) {
1949
+ this.logger.error("Code context generation failed", {
1950
+ error: error.message,
1951
+ projectPath,
1952
+ task,
1953
+ });
1954
+ return {
1955
+ content: [
1956
+ {
1957
+ type: "text",
1958
+ text: `❌ Error generating code context: ${error.message}\n\nTip: Ensure you're in a valid project directory with source files.`,
1959
+ },
1960
+ ],
1961
+ isError: true,
1962
+ };
1963
+ }
1964
+ }
1965
+
1966
+ // ============ Security Orchestrator Methods ============
1967
+
1968
+ async securityScan(projectPath, environment) {
1969
+ try {
1970
+ const scriptsPath = path.join(
1971
+ __dirname,
1972
+ "..",
1973
+ "scripts",
1974
+ "orchestrator.js",
1975
+ );
1976
+ const result = execSync(
1977
+ `node "${scriptsPath}" --path "${projectPath}" --env ${environment} --format json`,
1978
+ { cwd: projectPath, encoding: "utf8", maxBuffer: 10 * 1024 * 1024 },
1979
+ );
1980
+
1981
+ // Parse the JSON report
1982
+ const reportPath = path.join(
1983
+ projectPath,
1984
+ ".GUARDRAIL",
1985
+ "security-report.json",
1986
+ );
1987
+ let report;
1988
+ try {
1989
+ report = JSON.parse(await fs.readFile(reportPath, "utf8"));
1990
+ } catch {
1991
+ report = {
1992
+ verdict: { allowed: true },
1993
+ metrics: { riskScore: 0, totalFindings: 0 },
1994
+ };
1995
+ }
1996
+
1997
+ const icon = report.verdict.allowed ? "✅" : "🛑";
1998
+ let response = `${icon} **Security Scan Complete**\n\n`;
1999
+ response += `**Environment:** ${environment}\n`;
2000
+ response += `**Risk Score:** ${report.metrics.riskScore}/100\n`;
2001
+ response += `**Total Findings:** ${report.metrics.totalFindings}\n\n`;
2002
+
2003
+ if (report.metrics.findingsBySeverity) {
2004
+ response += `**Findings by Severity:**\n`;
2005
+ response += `- Critical: ${report.metrics.findingsBySeverity.critical || 0}\n`;
2006
+ response += `- High: ${report.metrics.findingsBySeverity.high || 0}\n`;
2007
+ response += `- Medium: ${report.metrics.findingsBySeverity.medium || 0}\n`;
2008
+ response += `- Low: ${report.metrics.findingsBySeverity.low || 0}\n\n`;
2009
+ }
2010
+
2011
+ if (!report.verdict.allowed && report.verdict.blockers?.length > 0) {
2012
+ response += `**Blockers:**\n`;
2013
+ report.verdict.blockers.forEach((b) => {
2014
+ response += `- ❌ ${b}\n`;
2015
+ });
2016
+ response += "\n";
2017
+ }
2018
+
2019
+ if (report.verdict.warnings?.length > 0) {
2020
+ response += `**Warnings:**\n`;
2021
+ report.verdict.warnings.forEach((w) => {
2022
+ response += `- ⚠️ ${w}\n`;
2023
+ });
2024
+ }
2025
+
2026
+ response += `\n📄 Full report: .GUARDRAIL/security-report.json`;
2027
+
2028
+ return {
2029
+ content: [{ type: "text", text: response }],
2030
+ };
2031
+ } catch (error) {
2032
+ return {
2033
+ content: [
2034
+ {
2035
+ type: "text",
2036
+ text: `❌ Security scan failed: ${error.message}\n\nTip: Run 'npm run ship' to see detailed output.`,
2037
+ },
2038
+ ],
2039
+ isError: true,
2040
+ };
2041
+ }
2042
+ }
2043
+
2044
+ async policyCheck(projectPath, environment) {
2045
+ try {
2046
+ // Run policy check using the orchestrator
2047
+ const BANNED_PATTERNS = [
2048
+ { pattern: "MockProvider", message: "MockProvider in production code" },
2049
+ { pattern: "useMock", message: "useMock hook in production code" },
2050
+ {
2051
+ pattern: "localhost:\\d+",
2052
+ isRegex: true,
2053
+ message: "Hardcoded localhost URLs",
2054
+ },
2055
+ {
2056
+ pattern: "demo_|inv_demo|fake_",
2057
+ isRegex: true,
2058
+ message: "Demo/fake identifiers",
2059
+ },
2060
+ { pattern: "sk_test_", message: "Stripe test keys" },
2061
+ ];
2062
+
2063
+ const findings = [];
2064
+ const excludeDirs = [
2065
+ "node_modules",
2066
+ "__tests__",
2067
+ "*.test.*",
2068
+ "*.spec.*",
2069
+ "docs",
2070
+ "landing",
2071
+ ];
2072
+ const excludeArgs = excludeDirs
2073
+ .map((d) => `--glob '!**/${d}/**'`)
2074
+ .join(" ");
2075
+
2076
+ for (const { pattern, message, isRegex } of BANNED_PATTERNS) {
2077
+ try {
2078
+ const searchPattern = isRegex
2079
+ ? pattern
2080
+ : pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2081
+ const cmd = `rg -n --hidden ${excludeArgs} "${searchPattern}" "${projectPath}"`;
2082
+ const output = execSync(cmd, {
2083
+ encoding: "utf-8",
2084
+ maxBuffer: 10 * 1024 * 1024,
2085
+ });
2086
+
2087
+ output
2088
+ .trim()
2089
+ .split("\n")
2090
+ .filter(Boolean)
2091
+ .forEach((line) => {
2092
+ const match = line.match(/^(.+?):(\d+):(.*)$/);
2093
+ if (match) {
2094
+ findings.push({
2095
+ pattern,
2096
+ message,
2097
+ file: path.relative(projectPath, match[1]),
2098
+ line: match[2],
2099
+ snippet: match[3].trim().substring(0, 60),
2100
+ });
2101
+ }
2102
+ });
2103
+ } catch {
2104
+ // No matches found - good!
2105
+ }
2106
+ }
2107
+
2108
+ const passed = findings.length === 0;
2109
+ let response = passed
2110
+ ? `✅ **Policy Check Passed**\n\nNo policy violations found in ${environment} configuration.\n`
2111
+ : `🛑 **Policy Check Failed**\n\nFound ${findings.length} policy violation(s):\n\n`;
2112
+
2113
+ if (!passed) {
2114
+ findings.slice(0, 10).forEach((f) => {
2115
+ response += `- **${f.message}**\n`;
2116
+ response += ` 📄 ${f.file}:${f.line}\n`;
2117
+ response += ` \`${f.snippet}...\`\n\n`;
2118
+ });
2119
+
2120
+ if (findings.length > 10) {
2121
+ response += `... and ${findings.length - 10} more violations\n`;
2122
+ }
2123
+ }
2124
+
2125
+ return {
2126
+ content: [{ type: "text", text: response }],
2127
+ };
2128
+ } catch (error) {
2129
+ return {
2130
+ content: [
2131
+ {
2132
+ type: "text",
2133
+ text: `❌ Policy check failed: ${error.message}`,
2134
+ },
2135
+ ],
2136
+ isError: true,
2137
+ };
2138
+ }
2139
+ }
2140
+
2141
+ async secretScan(projectPath, scanHistory) {
2142
+ try {
2143
+ const SECRET_PATTERNS = [
2144
+ { type: "AWS Access Key", pattern: /AKIA[0-9A-Z]{16}/g },
2145
+ { type: "GitHub Token", pattern: /ghp_[a-zA-Z0-9]{36}/g },
2146
+ { type: "Stripe Key", pattern: /sk_live_[a-zA-Z0-9]{24,}/g },
2147
+ {
2148
+ type: "JWT",
2149
+ pattern: /eyJ[a-zA-Z0-9\-_]+\.eyJ[a-zA-Z0-9\-_]+\.[a-zA-Z0-9\-_]+/g,
2150
+ },
2151
+ {
2152
+ type: "Private Key",
2153
+ pattern: /-----BEGIN (RSA |EC )?PRIVATE KEY-----/g,
2154
+ },
2155
+ {
2156
+ type: "Database URL",
2157
+ pattern: /(?:postgres|mysql|mongodb):\/\/[^\s"']+/gi,
2158
+ },
2159
+ ];
2160
+
2161
+ const secrets = [];
2162
+ const codeExtensions = [
2163
+ ".ts",
2164
+ ".tsx",
2165
+ ".js",
2166
+ ".jsx",
2167
+ ".json",
2168
+ ".env",
2169
+ ".yaml",
2170
+ ".yml",
2171
+ ];
2172
+
2173
+ // Walk directory
2174
+ const walkDir = async (dir) => {
2175
+ const files = [];
2176
+ try {
2177
+ const entries = await fs.readdir(dir, { withFileTypes: true });
2178
+ for (const entry of entries) {
2179
+ const fullPath = path.join(dir, entry.name);
2180
+ if (
2181
+ entry.isDirectory() &&
2182
+ !entry.name.startsWith(".") &&
2183
+ entry.name !== "node_modules"
2184
+ ) {
2185
+ files.push(...(await walkDir(fullPath)));
2186
+ } else if (
2187
+ entry.isFile() &&
2188
+ codeExtensions.some((ext) => entry.name.endsWith(ext))
2189
+ ) {
2190
+ files.push(fullPath);
2191
+ }
2192
+ }
2193
+ } catch {}
2194
+ return files;
2195
+ };
2196
+
2197
+ const files = await walkDir(projectPath);
2198
+
2199
+ for (const file of files) {
2200
+ if (
2201
+ file.includes("__tests__") ||
2202
+ file.includes(".test.") ||
2203
+ file.includes(".spec.")
2204
+ )
2205
+ continue;
2206
+
2207
+ try {
2208
+ const content = await fs.readFile(file, "utf-8");
2209
+ const lines = content.split("\n");
2210
+
2211
+ for (const { type, pattern } of SECRET_PATTERNS) {
2212
+ for (let i = 0; i < lines.length; i++) {
2213
+ const matches = lines[i].match(pattern);
2214
+ if (matches) {
2215
+ for (const match of matches) {
2216
+ if (lines[i].toLowerCase().includes("example")) continue;
2217
+ secrets.push({
2218
+ type,
2219
+ file: path.relative(projectPath, file),
2220
+ line: i + 1,
2221
+ redacted:
2222
+ match.substring(0, 4) +
2223
+ "..." +
2224
+ match.substring(match.length - 4),
2225
+ });
2226
+ }
2227
+ }
2228
+ }
2229
+ }
2230
+ } catch {}
2231
+ }
2232
+
2233
+ const passed = secrets.length === 0;
2234
+ let response = passed
2235
+ ? `✅ **Secret Scan Passed**\n\nNo secrets detected in codebase.\n`
2236
+ : `🛑 **Secrets Detected!**\n\nFound ${secrets.length} potential secret(s):\n\n`;
2237
+
2238
+ if (!passed) {
2239
+ secrets.slice(0, 10).forEach((s) => {
2240
+ response += `- **${s.type}**\n`;
2241
+ response += ` 📄 ${s.file}:${s.line}\n`;
2242
+ response += ` 🔑 \`${s.redacted}\`\n\n`;
2243
+ });
2244
+
2245
+ if (secrets.length > 10) {
2246
+ response += `... and ${secrets.length - 10} more secrets\n\n`;
2247
+ }
2248
+
2249
+ response += `⚠️ **Action Required:** Rotate these secrets immediately!\n`;
2250
+ }
2251
+
2252
+ return {
2253
+ content: [{ type: "text", text: response }],
2254
+ };
2255
+ } catch (error) {
2256
+ return {
2257
+ content: [
2258
+ {
2259
+ type: "text",
2260
+ text: `❌ Secret scan failed: ${error.message}`,
2261
+ },
2262
+ ],
2263
+ isError: true,
2264
+ };
2265
+ }
2266
+ }
2267
+
2268
+ async supplyChainScan(projectPath, repoUrl) {
2269
+ try {
2270
+ let response = `📦 **Supply Chain Analysis**\n\n`;
2271
+
2272
+ // Try npm audit
2273
+ try {
2274
+ execSync("npm audit --json", { cwd: projectPath, encoding: "utf-8" });
2275
+ response += `✅ **npm audit:** No vulnerabilities found\n\n`;
2276
+ } catch (error) {
2277
+ if (error.stdout) {
2278
+ try {
2279
+ const result = JSON.parse(error.stdout);
2280
+ const vulnCount = result.metadata?.vulnerabilities || {};
2281
+ const total =
2282
+ (vulnCount.critical || 0) +
2283
+ (vulnCount.high || 0) +
2284
+ (vulnCount.moderate || 0) +
2285
+ (vulnCount.low || 0);
2286
+
2287
+ if (total > 0) {
2288
+ response += `⚠️ **npm audit:** Found ${total} vulnerabilities\n`;
2289
+ response += `- Critical: ${vulnCount.critical || 0}\n`;
2290
+ response += `- High: ${vulnCount.high || 0}\n`;
2291
+ response += `- Moderate: ${vulnCount.moderate || 0}\n`;
2292
+ response += `- Low: ${vulnCount.low || 0}\n\n`;
2293
+ } else {
2294
+ response += `✅ **npm audit:** No vulnerabilities found\n\n`;
2295
+ }
2296
+ } catch {
2297
+ response += `⚠️ **npm audit:** Could not parse results\n\n`;
2298
+ }
2299
+ }
2300
+ }
2301
+
2302
+ // Count dependencies
2303
+ try {
2304
+ const pkgPath = path.join(projectPath, "package.json");
2305
+ const pkg = JSON.parse(await fs.readFile(pkgPath, "utf8"));
2306
+ const deps = Object.keys(pkg.dependencies || {}).length;
2307
+ const devDeps = Object.keys(pkg.devDependencies || {}).length;
2308
+
2309
+ response += `📊 **Dependencies:**\n`;
2310
+ response += `- Production: ${deps}\n`;
2311
+ response += `- Development: ${devDeps}\n`;
2312
+ response += `- Total: ${deps + devDeps}\n\n`;
2313
+ } catch {}
2314
+
2315
+ // License check (basic)
2316
+ response += `📜 **License compliance:** Run \`npm run ship:badge\` for full analysis\n`;
2317
+
2318
+ return {
2319
+ content: [{ type: "text", text: response }],
2320
+ };
2321
+ } catch (error) {
2322
+ return {
2323
+ content: [
2324
+ {
2325
+ type: "text",
2326
+ text: `❌ Supply chain scan failed: ${error.message}`,
2327
+ },
2328
+ ],
2329
+ isError: true,
2330
+ };
2331
+ }
2332
+ }
2333
+
2334
+ async shipCheck(projectPath) {
2335
+ try {
2336
+ // Run ship check with JSON output to get structured results
2337
+ let output;
2338
+ let exitCode = 0;
2339
+ try {
2340
+ output = execSync("npx ts-node src/bin/ship.ts check --json", {
2341
+ cwd: projectPath,
2342
+ encoding: "utf8",
2343
+ maxBuffer: 10 * 1024 * 1024,
2344
+ stdio: ["pipe", "pipe", "pipe"],
2345
+ });
2346
+ } catch (e) {
2347
+ output = e.stdout || "";
2348
+ exitCode = e.status || 1;
2349
+ }
2350
+
2351
+ // Find the latest run directory
2352
+ const runsDir = path.join(projectPath, ".GUARDRAIL", "runs");
2353
+ let runId = null;
2354
+ let summary = null;
2355
+ let artifacts = {};
2356
+
2357
+ try {
2358
+ const runs = await fs.readdir(runsDir);
2359
+ if (runs.length > 0) {
2360
+ runs.sort().reverse();
2361
+ runId = runs[0];
2362
+ const runDir = path.join(runsDir, runId);
2363
+
2364
+ // Read summary
2365
+ const summaryPath = path.join(runDir, "summary.json");
2366
+ if (
2367
+ await fs
2368
+ .access(summaryPath)
2369
+ .then(() => true)
2370
+ .catch(() => false)
2371
+ ) {
2372
+ summary = JSON.parse(await fs.readFile(summaryPath, "utf-8"));
2373
+ }
2374
+
2375
+ // Collect artifact paths
2376
+ artifacts = {
2377
+ runDir,
2378
+ report: path.join(runDir, "report.json"),
2379
+ reportTxt: path.join(runDir, "report.txt"),
2380
+ sarif: path.join(runDir, "sarif.json"),
2381
+ replay: path.join(runDir, "replay", "replay.json"),
2382
+ badges: path.join(runDir, "badges"),
2383
+ };
2384
+ }
2385
+ } catch (e) {
2386
+ // No runs yet
2387
+ }
2388
+
2389
+ const passed = summary?.verdict === "ship" || exitCode === 0;
2390
+ const icon = passed ? "✅" : "🛑";
2391
+
2392
+ let response = `${icon} **Ship Check: ${passed ? "SHIP" : "NO-SHIP"}**\n\n`;
2393
+
2394
+ if (summary) {
2395
+ response += `**Score:** ${summary.score}/100\n`;
2396
+ response += `**Exit Code:** ${summary.exitCode}\n\n`;
2397
+
2398
+ response += `**Gates:**\n`;
2399
+ response += `- MockProof: ${summary.gates.mockproof.verdict === "pass" ? "✅" : "❌"} (${summary.gates.mockproof.violations} violations)\n`;
2400
+ response += `- Badge: ${summary.gates.badge.verdict === "pass" ? "✅" : summary.gates.badge.verdict === "fail" ? "❌" : "⏭️"} (${summary.gates.badge.score}/100)\n`;
2401
+ response += `- Reality: ${summary.gates.reality.verdict}\n\n`;
2402
+
2403
+ if (summary.blockers?.length > 0) {
2404
+ response += `**Blockers:**\n`;
2405
+ summary.blockers.slice(0, 5).forEach((b) => {
2406
+ response += `- ❌ ${b}\n`;
2407
+ });
2408
+ response += "\n";
2409
+ }
2410
+ }
2411
+
2412
+ if (runId) {
2413
+ response += `**Run ID:** \`${runId}\`\n`;
2414
+ response += `**Artifacts:**\n`;
2415
+ response += `- Report: \`${path.relative(projectPath, artifacts.report)}\`\n`;
2416
+ response += `- SARIF: \`${path.relative(projectPath, artifacts.sarif)}\`\n`;
2417
+ response += `- Replay: \`${path.relative(projectPath, artifacts.replay)}\`\n`;
2418
+ }
2419
+
2420
+ // Return structured data for MCP clients
2421
+ return {
2422
+ content: [
2423
+ { type: "text", text: response },
2424
+ {
2425
+ type: "text",
2426
+ text: JSON.stringify(
2427
+ {
2428
+ verdict: passed ? "ship" : "no-ship",
2429
+ runId,
2430
+ score: summary?.score || 0,
2431
+ exitCode: summary?.exitCode || exitCode,
2432
+ blockers: summary?.blockers || [],
2433
+ artifacts: runId
2434
+ ? {
2435
+ runDir: artifacts.runDir,
2436
+ report: artifacts.report,
2437
+ sarif: artifacts.sarif,
2438
+ replay: artifacts.replay,
2439
+ }
2440
+ : null,
2441
+ },
2442
+ null,
2443
+ 2,
2444
+ ),
2445
+ mimeType: "application/json",
2446
+ },
2447
+ ],
2448
+ };
2449
+ } catch (error) {
2450
+ return {
2451
+ content: [
2452
+ {
2453
+ type: "text",
2454
+ text: `❌ Ship check failed: ${error.message}\n\nTip: Run \`GUARDRAIL ship\` to see detailed output.`,
2455
+ },
2456
+ ],
2457
+ isError: true,
2458
+ };
2459
+ }
2460
+ }
2461
+
2462
+ async getDeployVerdict(projectPath) {
2463
+ try {
2464
+ // Find the latest run
2465
+ const runsDir = path.join(projectPath, ".GUARDRAIL", "runs");
2466
+ let latestRun = null;
2467
+ let summary = null;
2468
+ let metadata = null;
2469
+
2470
+ try {
2471
+ const runs = await fs.readdir(runsDir);
2472
+ if (runs.length > 0) {
2473
+ runs.sort().reverse();
2474
+ latestRun = runs[0];
2475
+ const runDir = path.join(runsDir, latestRun);
2476
+
2477
+ const summaryPath = path.join(runDir, "summary.json");
2478
+ const metadataPath = path.join(runDir, "metadata.json");
2479
+
2480
+ if (
2481
+ await fs
2482
+ .access(summaryPath)
2483
+ .then(() => true)
2484
+ .catch(() => false)
2485
+ ) {
2486
+ summary = JSON.parse(await fs.readFile(summaryPath, "utf-8"));
2487
+ }
2488
+ if (
2489
+ await fs
2490
+ .access(metadataPath)
2491
+ .then(() => true)
2492
+ .catch(() => false)
2493
+ ) {
2494
+ metadata = JSON.parse(await fs.readFile(metadataPath, "utf-8"));
2495
+ }
2496
+ }
2497
+ } catch {
2498
+ // No runs available
2499
+ }
2500
+
2501
+ // If no runs, prompt user to run ship first
2502
+ if (!summary) {
2503
+ return {
2504
+ content: [
2505
+ {
2506
+ type: "text",
2507
+ text:
2508
+ `⚠️ **No Ship Run Found**\n\nRun \`GUARDRAIL ship\` first to generate a deploy verdict.\n\n` +
2509
+ `This will:\n` +
2510
+ `1. Scan for mock data (MockProof)\n` +
2511
+ `2. Generate ship badge\n` +
2512
+ `3. Create Reality Mode test\n` +
2513
+ `4. Produce a deploy verdict`,
2514
+ },
2515
+ ],
2516
+ };
2517
+ }
2518
+
2519
+ const allowed = summary.verdict === "ship";
2520
+ const icon = allowed ? "🚀" : "🛑";
2521
+
2522
+ let response = `${icon} **Deploy Verdict: ${allowed ? "SHIP" : "NO SHIP"}**\n\n`;
2523
+
2524
+ response += `**Run:** \`${latestRun}\`\n`;
2525
+ response += `**Score:** ${summary.score}/100\n`;
2526
+ response += `**Duration:** ${summary.duration}ms\n\n`;
2527
+
2528
+ if (metadata) {
2529
+ response += `**Context:**\n`;
2530
+ response += `- Commit: \`${metadata.commitSha?.substring(0, 8) || "N/A"}\`\n`;
2531
+ response += `- Branch: \`${metadata.branch || "N/A"}\`\n`;
2532
+ response += `- Policy: \`${metadata.policyHash}\`\n\n`;
2533
+ }
2534
+
2535
+ response += `**Gates:**\n`;
2536
+ response += `- MockProof: ${summary.gates.mockproof.verdict === "pass" ? "✅" : "❌"} (${summary.gates.mockproof.violations} violations)\n`;
2537
+ response += `- Badge: ${summary.gates.badge.verdict === "pass" ? "✅" : summary.gates.badge.verdict === "fail" ? "❌" : "⏭️"} (${summary.gates.badge.score}/100)\n`;
2538
+ response += `- Reality: ${summary.gates.reality.verdict}\n\n`;
2539
+
2540
+ if (!allowed && summary.blockers?.length > 0) {
2541
+ response += `**Blockers:**\n`;
2542
+ summary.blockers.forEach((b) => {
2543
+ response += `- ❌ ${b}\n`;
2544
+ });
2545
+ response += "\n";
2546
+ }
2547
+
2548
+ if (allowed) {
2549
+ response += `✅ **Ready to deploy!** All checks passed.\n\n`;
2550
+ response += `Add to README:\n\`\`\`markdown\n[![Ship Status](https://img.shields.io/badge/GUARDRAIL-SHIP-green)](https://GUARDRAIL.dev)\n\`\`\`\n`;
2551
+ } else {
2552
+ response += `⚠️ **Fix blockers before deploying.**\n\n`;
2553
+ response += `Run \`GUARDRAIL ship\` locally for detailed fix suggestions.\n`;
2554
+ }
2555
+
2556
+ // Return structured data
2557
+ return {
2558
+ content: [
2559
+ { type: "text", text: response },
2560
+ {
2561
+ type: "text",
2562
+ text: JSON.stringify(
2563
+ {
2564
+ verdict: summary.verdict,
2565
+ runId: latestRun,
2566
+ score: summary.score,
2567
+ exitCode: summary.exitCode,
2568
+ gates: summary.gates,
2569
+ blockers: summary.blockers,
2570
+ metadata: metadata
2571
+ ? {
2572
+ commitSha: metadata.commitSha,
2573
+ branch: metadata.branch,
2574
+ policyHash: metadata.policyHash,
2575
+ timestamp: metadata.timestamp,
2576
+ }
2577
+ : null,
2578
+ },
2579
+ null,
2580
+ 2,
2581
+ ),
2582
+ mimeType: "application/json",
2583
+ },
2584
+ ],
2585
+ };
2586
+ } catch (error) {
2587
+ return {
2588
+ content: [
2589
+ {
2590
+ type: "text",
2591
+ text: `❌ Could not get deploy verdict: ${error.message}\n\nTip: Run \`GUARDRAIL ship\` first.`,
2592
+ },
2593
+ ],
2594
+ isError: true,
2595
+ };
2596
+ }
2597
+ }
2598
+
2599
+ async realityCheck(projectPath, mode = "full", file = null) {
2600
+ try {
2601
+ this.logger.info(
2602
+ `🔮 Reality Check starting: mode=${mode}, path=${projectPath}`,
2603
+ );
2604
+
2605
+ // Code-only mode: analyze specific file for self-deception
2606
+ if (mode === "code-only" && file) {
2607
+ return await this.realityCheckCodeOnly(projectPath, file);
2608
+ }
2609
+
2610
+ // Full or Quick mode: run production integrity suite
2611
+ const { auditProductionIntegrity, formatProductionResults } = require(
2612
+ path.join(__dirname, "..", "scripts", "audit-production-integrity.js"),
2613
+ );
2614
+
2615
+ const { results, integrity } =
2616
+ await auditProductionIntegrity(projectPath);
2617
+
2618
+ // Build the Reality Check header
2619
+ let output = `# 🔮 REALITY CHECK\n`;
2620
+ output += `## "Where Your Code Lies To You"\n\n`;
2621
+ output += `**Project:** ${results.projectPath}\n`;
2622
+ output += `**Timestamp:** ${new Date().toISOString()}\n\n`;
2623
+
2624
+ // Big verdict box
2625
+ output += `\`\`\`\n`;
2626
+ output += `┌────────────────────────────────────────────┐\n`;
2627
+ output += `│ │\n`;
2628
+ output += `│ REALITY SCORE: ${String(integrity.score).padStart(3)} │\n`;
2629
+ output += `│ GRADE: ${integrity.grade.padStart(2)} │\n`;
2630
+ output += `│ │\n`;
2631
+ output += `│ ${integrity.canShip ? "✅ CLEAR TO SHIP " : "🚫 NOT READY TO SHIP "} │\n`;
2632
+ output += `│ │\n`;
2633
+ output += `└────────────────────────────────────────────┘\n`;
2634
+ output += `\`\`\`\n\n`;
2635
+
2636
+ // The Reality
2637
+ output += `## 🎭 The Reality\n\n`;
2638
+ output += `| What You Think | The Truth | Gap |\n`;
2639
+ output += `|----------------|-----------|-----|\n`;
2640
+
2641
+ const apiConnected = results.api?.summary?.connected || 0;
2642
+ const apiMissing = results.api?.summary?.missingBackend || 0;
2643
+ const apiTotal = apiConnected + apiMissing;
2644
+ if (apiTotal > 0) {
2645
+ output += `| "All APIs work" | ${apiMissing} endpoints don't exist | ${apiMissing > 0 ? "🔴" : "✅"} |\n`;
2646
+ }
2647
+
2648
+ const authProtected = results.auth?.analysis?.protected?.length || 0;
2649
+ const authExposed =
2650
+ (results.auth?.analysis?.adminExposed?.length || 0) +
2651
+ (results.auth?.analysis?.sensitiveUnprotected?.length || 0);
2652
+ if (authProtected > 0 || authExposed > 0) {
2653
+ output += `| "App is secure" | ${authExposed} sensitive endpoints exposed | ${authExposed > 0 ? "🔴" : "✅"} |\n`;
2654
+ }
2655
+
2656
+ const criticalSecrets =
2657
+ results.env?.secrets?.filter((s) => s.severity === "critical").length ||
2658
+ 0;
2659
+ output += `| "Secrets are safe" | ${criticalSecrets} hardcoded in code | ${criticalSecrets > 0 ? "🔴" : "✅"} |\n`;
2660
+
2661
+ const deadLinks = results.routes?.integrity?.deadLinks?.length || 0;
2662
+ output += `| "All pages work" | ${deadLinks} links go to 404 | ${deadLinks > 0 ? "🔴" : "✅"} |\n`;
2663
+
2664
+ const mockCritical = (results.mocks?.issues || []).filter(
2665
+ (i) => i.severity === "critical",
2666
+ ).length;
2667
+ const mockHigh = (results.mocks?.issues || []).filter(
2668
+ (i) => i.severity === "high",
2669
+ ).length;
2670
+ output += `| "No test code in prod" | ${mockCritical + mockHigh} mock/test issues | ${mockCritical + mockHigh > 0 ? "🔴" : "✅"} |\n`;
2671
+
2672
+ output += `\n`;
2673
+
2674
+ // Quick mode stops here with summary
2675
+ if (mode === "quick") {
2676
+ output += `## 📊 Quick Summary\n\n`;
2677
+ output += `- **API Wiring:** ${apiConnected} connected, ${apiMissing} missing\n`;
2678
+ output += `- **Auth:** ${authProtected} protected, ${authExposed} exposed\n`;
2679
+ output += `- **Secrets:** ${criticalSecrets} critical issues\n`;
2680
+ output += `- **Routes:** ${deadLinks} dead links\n`;
2681
+ output += `- **Mock Code:** ${mockCritical + mockHigh} blocking issues\n\n`;
2682
+ output += `_Run with mode="full" for complete details._\n`;
2683
+
2684
+ return {
2685
+ content: [{ type: "text", text: output }],
2686
+ };
2687
+ }
2688
+
2689
+ // Full mode: add complete production integrity report
2690
+ const fullReport = formatProductionResults({ results, integrity });
2691
+
2692
+ // Extract the detailed findings section from the full report
2693
+ const detailedStart = fullReport.indexOf("# 📋 Detailed Findings");
2694
+ if (detailedStart > 0) {
2695
+ output += fullReport.substring(detailedStart);
2696
+ } else {
2697
+ output += fullReport;
2698
+ }
2699
+
2700
+ // Add JSON summary at the end
2701
+ const summary = {
2702
+ score: integrity.score,
2703
+ grade: integrity.grade,
2704
+ canShip: integrity.canShip,
2705
+ verdict: integrity.canShip ? "SHIP" : "NO_SHIP",
2706
+ counts: {
2707
+ api: { connected: apiConnected, missing: apiMissing },
2708
+ auth: { protected: authProtected, exposed: authExposed },
2709
+ secrets: { critical: criticalSecrets },
2710
+ routes: { deadLinks },
2711
+ mocks: { critical: mockCritical, high: mockHigh },
2712
+ },
2713
+ timestamp: new Date().toISOString(),
2714
+ };
2715
+
2716
+ output += `\n---\n\n`;
2717
+ output += `## 📦 JSON Summary\n\n`;
2718
+ output += `\`\`\`json\n${JSON.stringify(summary, null, 2)}\n\`\`\`\n`;
2719
+
2720
+ // Context attribution
2721
+ output += `\n---\n_Context Enhanced by Guardrail AI_\n`;
2722
+
2723
+ this.logger.info(
2724
+ `Reality Check complete: Score ${integrity.score}, Grade ${integrity.grade}`,
2725
+ );
2726
+
2727
+ return {
2728
+ content: [{ type: "text", text: output }],
2729
+ };
2730
+ } catch (error) {
2731
+ this.logger.error("Reality check failed", {
2732
+ error: error.message,
2733
+ stack: error.stack,
2734
+ });
2735
+ return {
2736
+ content: [
2737
+ {
2738
+ type: "text",
2739
+ text:
2740
+ `❌ Reality Check failed: ${error.message}\n\n` +
2741
+ `**Troubleshooting:**\n` +
2742
+ `- Ensure the project path exists and is accessible\n` +
2743
+ `- For code-only mode, provide a valid file path\n` +
2744
+ `- Try: \`node scripts/audit-production-integrity.js "${projectPath}"\``,
2745
+ },
2746
+ ],
2747
+ isError: true,
2748
+ };
2749
+ }
2750
+ }
2751
+
2752
+ async realityCheckCodeOnly(projectPath, file) {
2753
+ try {
2754
+ const filePath = path.join(projectPath, file);
2755
+ const code = await fs.readFile(filePath, "utf8");
2756
+
2757
+ // Import and run the reality check service for code analysis
2758
+ const { realityCheck } =
2759
+ await import("../src/lib/reality-check-service.js");
2760
+ const result = await realityCheck.check(code, file);
2761
+
2762
+ // Format the output
2763
+ let output = `🔮 **Reality Check - Code Analysis**\n\n`;
2764
+ output += `📁 File: ${result.file}\n`;
2765
+ output += `📊 Reality Score: ${result.overallScore}/100\n`;
2766
+ output += `⏰ Analyzed: ${result.timestamp}\n\n`;
2767
+
2768
+ output += `## Summary\n`;
2769
+ output += `- 🔴 Critical: ${result.summary.critical}\n`;
2770
+ output += `- 🟡 Warnings: ${result.summary.warnings}\n`;
2771
+ output += `- 🔵 Suggestions: ${result.summary.suggestions}\n\n`;
2772
+
2773
+ if (result.findings.length === 0) {
2774
+ output += `✅ **No self-deception detected!** Your code does what you think it does.\n`;
2775
+ } else {
2776
+ output += `## Findings\n\n`;
2777
+ for (const finding of result.findings) {
2778
+ const icon =
2779
+ finding.type === "critical"
2780
+ ? "❌"
2781
+ : finding.type === "warning"
2782
+ ? "⚠️"
2783
+ : "💡";
2784
+ output += `### ${icon} ${finding.category.replace(/-/g, " ").toUpperCase()}\n`;
2785
+ if (finding.line) output += `📍 Line ${finding.line}\n`;
2786
+ output += `\`\`\`\n${finding.code}\n\`\`\`\n`;
2787
+ output += `**You think:** ${finding.intent}\n`;
2788
+ output += `**Reality:** ${finding.reality}\n`;
2789
+ output += `**Why it matters:** ${finding.explanation}\n`;
2790
+ output += `_Confidence: ${Math.round(finding.confidence * 100)}%_\n\n`;
2791
+ }
2792
+ }
2793
+
2794
+ output += `\n---\n_Context Enhanced by Guardrail AI_\n`;
2795
+
2796
+ return {
2797
+ content: [
2798
+ { type: "text", text: output },
2799
+ {
2800
+ type: "text",
2801
+ text: JSON.stringify(result, null, 2),
2802
+ mimeType: "application/json",
2803
+ },
2804
+ ],
2805
+ };
2806
+ } catch (error) {
2807
+ return {
2808
+ content: [
2809
+ {
2810
+ type: "text",
2811
+ text: `❌ Code analysis failed: ${error.message}\n\nMake sure the file exists and contains valid code.`,
2812
+ },
2813
+ ],
2814
+ isError: true,
2815
+ };
2816
+ }
2817
+ }
2818
+
2819
+ async realityCheckDeep(
2820
+ projectPath,
2821
+ file,
2822
+ includeCallGraph = true,
2823
+ includeAsyncAnalysis = true,
2824
+ ) {
2825
+ try {
2826
+ if (!file) {
2827
+ return {
2828
+ content: [
2829
+ {
2830
+ type: "text",
2831
+ text: "❌ Deep Reality Check requires a file path.",
2832
+ },
2833
+ ],
2834
+ isError: true,
2835
+ };
2836
+ }
2837
+
2838
+ const filePath = path.join(projectPath, file);
2839
+ const code = await fs.readFile(filePath, "utf8");
2840
+
2841
+ // Run basic reality check first
2842
+ const { realityCheck } =
2843
+ await import("../src/lib/reality-check-service.js");
2844
+ const basicResult = await realityCheck.check(code, file);
2845
+
2846
+ // Deep analysis additions
2847
+ let output = `🔮 **Deep Reality Check Results** (Pro)\n\n`;
2848
+ output += `📁 File: ${file}\n`;
2849
+ output += `📊 Reality Score: ${basicResult.overallScore}/100\n\n`;
2850
+
2851
+ output += `## Basic Analysis\n`;
2852
+ output += `- 🔴 Critical: ${basicResult.summary.critical}\n`;
2853
+ output += `- 🟡 Warnings: ${basicResult.summary.warnings}\n`;
2854
+ output += `- 🔵 Suggestions: ${basicResult.summary.suggestions}\n\n`;
2855
+
2856
+ if (includeCallGraph) {
2857
+ output += `## 📊 Call Graph Analysis\n`;
2858
+ output += `_Cross-file dependency tracking identifies assumptions about external code._\n\n`;
2859
+ // This would be enhanced with actual call graph analysis
2860
+ const imports = code.match(/import\s+.*from\s+['"]([^'"]+)['"]/g) || [];
2861
+ const calls = code.match(/\b(\w+)\s*\(/g) || [];
2862
+ output += `- Imports: ${imports.length}\n`;
2863
+ output += `- Function calls: ${[...new Set(calls)].length}\n\n`;
2864
+ }
2865
+
2866
+ if (includeAsyncAnalysis) {
2867
+ output += `## ⏳ Async Lifecycle Analysis\n`;
2868
+ output += `_Timing assumptions are a major source of bugs._\n\n`;
2869
+ const asyncFns = (code.match(/async\s+function|\basync\s*\(/g) || [])
2870
+ .length;
2871
+ const awaits = (code.match(/\bawait\s+/g) || []).length;
2872
+ const promises = (code.match(/new\s+Promise|\.then\(|\.catch\(/g) || [])
2873
+ .length;
2874
+ output += `- Async functions: ${asyncFns}\n`;
2875
+ output += `- Await expressions: ${awaits}\n`;
2876
+ output += `- Promise patterns: ${promises}\n`;
2877
+
2878
+ if (asyncFns > 0 && awaits === 0) {
2879
+ output += `\n⚠️ **Found async functions with no awaits** - these may not need to be async.\n`;
2880
+ }
2881
+ output += `\n`;
2882
+ }
2883
+
2884
+ output += `## All Findings\n\n`;
2885
+ for (const finding of basicResult.findings) {
2886
+ const icon =
2887
+ finding.type === "critical"
2888
+ ? "❌"
2889
+ : finding.type === "warning"
2890
+ ? "⚠️"
2891
+ : "💡";
2892
+ output += `### ${icon} ${finding.category.replace(/-/g, " ").toUpperCase()}\n`;
2893
+ if (finding.line) output += `📍 Line ${finding.line}\n`;
2894
+ output += `\`\`\`\n${finding.code}\n\`\`\`\n`;
2895
+ output += `**You think:** ${finding.intent}\n`;
2896
+ output += `**Reality:** ${finding.reality}\n`;
2897
+ output += `**Why it matters:** ${finding.explanation}\n\n`;
2898
+ }
2899
+
2900
+ return {
2901
+ content: [{ type: "text", text: output }],
2902
+ };
2903
+ } catch (error) {
2904
+ return {
2905
+ content: [
2906
+ {
2907
+ type: "text",
2908
+ text: `❌ Deep Reality Check failed: ${error.message}`,
2909
+ },
2910
+ ],
2911
+ isError: true,
2912
+ };
2913
+ }
2914
+ }
2915
+
2916
+ async auditApiEndpoints(projectPath, showDetails = false) {
2917
+ try {
2918
+ const {
2919
+ auditApiEndpoints,
2920
+ } = require("../scripts/audit-api-endpoints.js");
2921
+ const results = await auditApiEndpoints(projectPath);
2922
+
2923
+ // Format summary
2924
+ let response = `🔗 **API Endpoint Audit Report**\n\n`;
2925
+ response += `📊 **Summary:**\n`;
2926
+ response += `| Metric | Count |\n`;
2927
+ response += `|--------|-------|\n`;
2928
+ response += `| Backend Endpoints | ${results.summary.totalBackendEndpoints} |\n`;
2929
+ response += `| Frontend API Calls | ${results.summary.totalFrontendCalls} |\n`;
2930
+ response += `| ✅ Connected | ${results.summary.connectedEndpoints} |\n`;
2931
+ response += `| ⚠️ Unused Backend | ${results.summary.unusedBackendEndpoints} |\n`;
2932
+ response += `| ❌ Missing Backend | ${results.summary.missingBackendEndpoints} |\n\n`;
2933
+
2934
+ // Missing backend implementations (priority)
2935
+ if (results.missing.length > 0) {
2936
+ response += `## ❌ Missing Backend Implementations\n\n`;
2937
+ response += `These frontend API calls have **no backend endpoint**:\n\n`;
2938
+ results.missing.slice(0, 15).forEach((item) => {
2939
+ response += `- **${item.method} ${item.path}**\n`;
2940
+ response += ` - File: \`${item.file}\`\n`;
2941
+ response += ` - 💡 ${item.suggestion}\n\n`;
2942
+ });
2943
+ if (results.missing.length > 15) {
2944
+ response += `... and ${results.missing.length - 15} more\n\n`;
2945
+ }
2946
+ }
2947
+
2948
+ // Unused backend endpoints
2949
+ if (results.unused.length > 0) {
2950
+ response += `## ⚠️ Unused Backend Endpoints\n\n`;
2951
+ response += `These backend endpoints have **no frontend calls**:\n\n`;
2952
+ results.unused.slice(0, 15).forEach((item) => {
2953
+ response += `- **${item.method} ${item.path}** (\`${item.file}\`)\n`;
2954
+ });
2955
+ if (results.unused.length > 15) {
2956
+ response += `... and ${results.unused.length - 15} more\n\n`;
2957
+ }
2958
+ }
2959
+
2960
+ // Connected (if showDetails)
2961
+ if (showDetails && results.connected.length > 0) {
2962
+ response += `## ✅ Connected Endpoints\n\n`;
2963
+ results.connected.forEach((item) => {
2964
+ response += `- ${item.method} ${item.path}\n`;
2965
+ });
2966
+ response += "\n";
2967
+ } else if (results.connected.length > 0) {
2968
+ response += `✅ **${results.connected.length} endpoints properly connected**\n\n`;
2969
+ }
2970
+
2971
+ // Recommendations
2972
+ response += `## 💡 Recommendations\n\n`;
2973
+ if (results.missing.length > 0) {
2974
+ response += `1. **Implement missing backend routes** - ${results.missing.length} frontend calls need backend endpoints\n`;
2975
+ }
2976
+ if (results.unused.length > 0) {
2977
+ response += `2. **Review unused endpoints** - ${results.unused.length} backend routes may be dead code or need frontend integration\n`;
2978
+ }
2979
+ if (results.missing.length === 0 && results.unused.length === 0) {
2980
+ response += `🎉 All endpoints are properly connected!\n`;
2981
+ }
2982
+
2983
+ return {
2984
+ content: [
2985
+ { type: "text", text: response },
2986
+ {
2987
+ type: "text",
2988
+ text: JSON.stringify(
2989
+ {
2990
+ summary: results.summary,
2991
+ missing: results.missing,
2992
+ unused: results.unused,
2993
+ connected: results.connected.length,
2994
+ },
2995
+ null,
2996
+ 2,
2997
+ ),
2998
+ mimeType: "application/json",
2999
+ },
3000
+ ],
3001
+ };
3002
+ } catch (error) {
3003
+ this.logger.error("API audit failed", {
3004
+ error: error.message,
3005
+ projectPath,
3006
+ });
3007
+ return {
3008
+ content: [
3009
+ {
3010
+ type: "text",
3011
+ text:
3012
+ `❌ API endpoint audit failed: ${error.message}\n\n` +
3013
+ `Tip: Ensure you're in a project with:\n` +
3014
+ `- Backend routes in \`apps/api/src/routes/\` or \`server/routes/\`\n` +
3015
+ `- Frontend code in \`apps/web-ui/src/\` or \`src/\``,
3016
+ },
3017
+ ],
3018
+ isError: true,
3019
+ };
3020
+ }
3021
+ }
3022
+
3023
+ async productionIntegrityCheck(projectPath) {
3024
+ try {
3025
+ const { auditProductionIntegrity, formatProductionResults } = require(
3026
+ path.join(__dirname, "..", "scripts", "audit-production-integrity.js"),
3027
+ );
3028
+
3029
+ this.logger.info(
3030
+ `🛡️ Running Production Integrity Check on: ${projectPath}`,
3031
+ );
3032
+
3033
+ const { results, integrity } =
3034
+ await auditProductionIntegrity(projectPath);
3035
+ const report = formatProductionResults({ results, integrity });
3036
+
3037
+ // Build comprehensive JSON summary
3038
+ const summary = {
3039
+ score: integrity.score,
3040
+ grade: integrity.grade,
3041
+ canShip: integrity.canShip,
3042
+ verdict: integrity.canShip ? "SHIP" : "NO_SHIP",
3043
+ deductions: integrity.deductions,
3044
+ counts: {
3045
+ api: {
3046
+ connected: results.api?.summary?.connected || 0,
3047
+ missing: results.api?.summary?.missingBackend || 0,
3048
+ unused: results.api?.summary?.unusedBackend || 0,
3049
+ },
3050
+ auth: {
3051
+ protected: results.auth?.analysis?.protected?.length || 0,
3052
+ unprotected: results.auth?.analysis?.unprotected?.length || 0,
3053
+ adminExposed: results.auth?.analysis?.adminExposed?.length || 0,
3054
+ },
3055
+ secrets: {
3056
+ critical:
3057
+ results.env?.secrets?.filter((s) => s.severity === "critical")
3058
+ .length || 0,
3059
+ high:
3060
+ results.env?.secrets?.filter((s) => s.severity === "high")
3061
+ .length || 0,
3062
+ devUrls: results.env?.devUrls?.length || 0,
3063
+ envVars: results.env?.envExample?.variables?.length || 0,
3064
+ },
3065
+ routes: {
3066
+ pages: results.routes?.pages?.length || 0,
3067
+ deadLinks: results.routes?.integrity?.deadLinks?.length || 0,
3068
+ placeholders: results.routes?.placeholders?.length || 0,
3069
+ },
3070
+ mocks: {
3071
+ critical: (results.mocks?.issues || []).filter(
3072
+ (i) => i.severity === "critical",
3073
+ ).length,
3074
+ high: (results.mocks?.issues || []).filter(
3075
+ (i) => i.severity === "high",
3076
+ ).length,
3077
+ consoleLogs: (results.mocks?.issues || []).filter(
3078
+ (i) => i.name === "console.log",
3079
+ ).length,
3080
+ },
3081
+ },
3082
+ timestamp: new Date().toISOString(),
3083
+ projectPath: results.projectPath,
3084
+ };
3085
+
3086
+ this.logger.info(
3087
+ `Production integrity check complete: Score ${integrity.score}, Grade ${integrity.grade}`,
3088
+ );
3089
+
3090
+ return {
3091
+ content: [
3092
+ { type: "text", text: report },
3093
+ {
3094
+ type: "text",
3095
+ text: `\n---\n**JSON Summary:**\n\`\`\`json\n${JSON.stringify(summary, null, 2)}\n\`\`\``,
3096
+ },
3097
+ ],
3098
+ };
3099
+ } catch (error) {
3100
+ this.logger.error("Production integrity check failed", {
3101
+ error: error.message,
3102
+ stack: error.stack,
3103
+ });
3104
+ return {
3105
+ content: [
3106
+ {
3107
+ type: "text",
3108
+ text:
3109
+ `❌ Production integrity check failed: ${error.message}\n\n` +
3110
+ `**Troubleshooting:**\n` +
3111
+ `- Ensure the project path exists\n` +
3112
+ `- Check that Node.js can access the directory\n` +
3113
+ `- Try running: \`node scripts/audit-production-integrity.js "${projectPath}"\``,
3114
+ },
3115
+ ],
3116
+ isError: true,
3117
+ };
3118
+ }
3119
+ }
3120
+
3121
+ async auditAuthCoverage(projectPath) {
3122
+ try {
3123
+ const { auditAuthCoverage, formatAuthResults } = require(
3124
+ path.join(__dirname, "..", "scripts", "audit-auth-coverage.js"),
3125
+ );
3126
+
3127
+ const results = await auditAuthCoverage(projectPath);
3128
+ const report = formatAuthResults(results);
3129
+
3130
+ return {
3131
+ content: [{ type: "text", text: report }],
3132
+ };
3133
+ } catch (error) {
3134
+ this.logger.error("Auth coverage audit failed", { error: error.message });
3135
+ return {
3136
+ content: [
3137
+ {
3138
+ type: "text",
3139
+ text: `❌ Auth coverage audit failed: ${error.message}`,
3140
+ },
3141
+ ],
3142
+ isError: true,
3143
+ };
3144
+ }
3145
+ }
3146
+
3147
+ async auditEnvSecrets(projectPath) {
3148
+ try {
3149
+ const { auditEnvSecrets, formatEnvResults } = require(
3150
+ path.join(__dirname, "..", "scripts", "audit-env-secrets.js"),
3151
+ );
3152
+
3153
+ const results = await auditEnvSecrets(projectPath);
3154
+ const report = formatEnvResults(results);
3155
+
3156
+ return {
3157
+ content: [{ type: "text", text: report }],
3158
+ };
3159
+ } catch (error) {
3160
+ this.logger.error("Env secrets audit failed", { error: error.message });
3161
+ return {
3162
+ content: [
3163
+ {
3164
+ type: "text",
3165
+ text: `❌ Env secrets audit failed: ${error.message}`,
3166
+ },
3167
+ ],
3168
+ isError: true,
3169
+ };
3170
+ }
3171
+ }
3172
+
3173
+ async auditRouteIntegrity(projectPath) {
3174
+ try {
3175
+ const { auditRouteIntegrity, formatRouteResults } = require(
3176
+ path.join(__dirname, "..", "scripts", "audit-route-integrity.js"),
3177
+ );
3178
+
3179
+ const results = await auditRouteIntegrity(projectPath);
3180
+ const report = formatRouteResults(results);
3181
+
3182
+ return {
3183
+ content: [{ type: "text", text: report }],
3184
+ };
3185
+ } catch (error) {
3186
+ this.logger.error("Route integrity audit failed", {
3187
+ error: error.message,
3188
+ });
3189
+ return {
3190
+ content: [
3191
+ {
3192
+ type: "text",
3193
+ text: `❌ Route integrity audit failed: ${error.message}`,
3194
+ },
3195
+ ],
3196
+ isError: true,
3197
+ };
3198
+ }
3199
+ }
3200
+
3201
+ async auditMockBlocker(projectPath) {
3202
+ try {
3203
+ const { auditMockBlocker, formatMockResults } = require(
3204
+ path.join(__dirname, "..", "scripts", "audit-mock-blocker.js"),
3205
+ );
3206
+
3207
+ const results = await auditMockBlocker(projectPath);
3208
+ const report = formatMockResults(results);
3209
+
3210
+ return {
3211
+ content: [{ type: "text", text: report }],
3212
+ };
3213
+ } catch (error) {
3214
+ this.logger.error("Mock blocker audit failed", { error: error.message });
3215
+ return {
3216
+ content: [
3217
+ {
3218
+ type: "text",
3219
+ text: `❌ Mock blocker audit failed: ${error.message}`,
3220
+ },
3221
+ ],
3222
+ isError: true,
3223
+ };
3224
+ }
3225
+ }
3226
+
3227
+ // ==================== REPO HYGIENE + DEBT RADAR ====================
3228
+
3229
+ async repoHygieneScan(projectPath, mode = "report", saveArtifacts = true) {
3230
+ try {
3231
+ this.logger.info(`🧹 Running repo hygiene scan on: ${projectPath}`);
3232
+ const result = await hygieneFullScan({
3233
+ projectPath,
3234
+ mode,
3235
+ saveArtifacts,
3236
+ });
3237
+
3238
+ let response = `# 🧹 Repo Hygiene + Debt Radar\n\n`;
3239
+ response += `**Score:** ${result.score.score}/100 (Grade: ${result.score.grade})\n`;
3240
+ response += `**Status:** ${result.score.status}\n\n`;
3241
+
3242
+ response += `## Summary\n\n`;
3243
+ response += `| Category | Count |\n|----------|-------|\n`;
3244
+ response += `| Exact Duplicates | ${result.summary.duplicates.exact} |\n`;
3245
+ response += `| Near-Duplicates | ${result.summary.duplicates.near} |\n`;
3246
+ response += `| Copy-Paste Blocks | ${result.summary.duplicates.copyPaste} |\n`;
3247
+ response += `| Definitely Unused | ${result.summary.unused.definitelyUnused} |\n`;
3248
+ response += `| Probably Unused | ${result.summary.unused.probablyUnused} |\n`;
3249
+ response += `| Lint/Type Errors | ${result.summary.errors.total} |\n`;
3250
+ response += `| Junk Files | ${result.summary.rootCleanup.junkFiles} |\n\n`;
3251
+
3252
+ if (saveArtifacts) {
3253
+ response += `📄 **Reports saved to:** .guardrail/\n`;
3254
+ response += result.artifacts.map((a) => `- ${a}`).join("\n");
3255
+ }
3256
+
3257
+ return { content: [{ type: "text", text: response }] };
3258
+ } catch (error) {
3259
+ this.logger.error("Repo hygiene scan failed", { error: error.message });
3260
+ return {
3261
+ content: [
3262
+ {
3263
+ type: "text",
3264
+ text: `❌ Repo hygiene scan failed: ${error.message}`,
3265
+ },
3266
+ ],
3267
+ isError: true,
3268
+ };
3269
+ }
3270
+ }
3271
+
3272
+ async repoHygieneDuplicates(projectPath, threshold = 0.85) {
3273
+ try {
3274
+ const result = await hygieneDuplicates({ projectPath, threshold });
3275
+
3276
+ let response = `# 📋 Duplicate File Analysis\n\n`;
3277
+ response += `**Exact Duplicates:** ${result.summary.exactCount}\n`;
3278
+ response += `**Near-Duplicates:** ${result.summary.nearCount}\n`;
3279
+ response += `**Copy-Paste Blocks:** ${result.summary.copyPasteCount}\n`;
3280
+ response += `**Total Wasted Bytes:** ${result.summary.totalWastedBytes}\n\n`;
3281
+
3282
+ if (result.exact.length > 0) {
3283
+ response += `## Exact Duplicates\n\n`;
3284
+ for (const group of result.exact.slice(0, 10)) {
3285
+ response += `**Hash:** \`${group.hash}\`\n`;
3286
+ group.files.forEach((f) => (response += `- \`${f.path}\`\n`));
3287
+ response += `\n`;
3288
+ }
3289
+ }
3290
+
3291
+ if (result.near.length > 0) {
3292
+ response += `## Near-Duplicates (≥${threshold * 100}% similar)\n\n`;
3293
+ for (const group of result.near.slice(0, 10)) {
3294
+ response += `**Similarity:** ${group.similarity}%\n`;
3295
+ group.files.forEach((f) => (response += `- \`${f}\`\n`));
3296
+ response += `\n`;
3297
+ }
3298
+ }
3299
+
3300
+ return { content: [{ type: "text", text: response }] };
3301
+ } catch (error) {
3302
+ return {
3303
+ content: [
3304
+ { type: "text", text: `❌ Duplicate scan failed: ${error.message}` },
3305
+ ],
3306
+ isError: true,
3307
+ };
3308
+ }
3309
+ }
3310
+
3311
+ async repoHygieneUnused(projectPath, scope = "all") {
3312
+ try {
3313
+ const result = await hygieneUnused({ projectPath, scope });
3314
+
3315
+ let response = `# 📦 Unused File Analysis\n\n`;
3316
+ response += `**Total Files:** ${result.stats.totalFiles}\n`;
3317
+ response += `**Entrypoints:** ${result.stats.entrypoints}\n`;
3318
+ response += `**Reachable:** ${result.stats.reachable}\n`;
3319
+ response += `**Unreachable:** ${result.stats.unreachable}\n\n`;
3320
+
3321
+ if (result.safeToDelete.length > 0) {
3322
+ response += `## ✅ Safe to Delete (${result.safeToDelete.length} files)\n\n`;
3323
+ result.safeToDelete
3324
+ .slice(0, 20)
3325
+ .forEach((f) => (response += `- \`${f}\`\n`));
3326
+ if (result.safeToDelete.length > 20)
3327
+ response += `- ... and ${result.safeToDelete.length - 20} more\n`;
3328
+ response += `\n`;
3329
+ }
3330
+
3331
+ if (result.reviewFirst.length > 0) {
3332
+ response += `## 🟡 Review First (${result.reviewFirst.length} files)\n\n`;
3333
+ result.reviewFirst
3334
+ .slice(0, 10)
3335
+ .forEach((f) => (response += `- \`${f}\`\n`));
3336
+ response += `\n`;
3337
+ }
3338
+
3339
+ return { content: [{ type: "text", text: response }] };
3340
+ } catch (error) {
3341
+ return {
3342
+ content: [
3343
+ {
3344
+ type: "text",
3345
+ text: `❌ Unused file scan failed: ${error.message}`,
3346
+ },
3347
+ ],
3348
+ isError: true,
3349
+ };
3350
+ }
3351
+ }
3352
+
3353
+ async repoHygieneErrors(projectPath, options = {}) {
3354
+ try {
3355
+ const result = await hygieneErrors({ projectPath, ...options });
3356
+
3357
+ let response = `# 🔴 Lint/Type/Import Errors\n\n`;
3358
+ response += `**Total:** ${result.summary.total}\n`;
3359
+ response += `**Errors:** ${result.summary.bySeverity.error}\n`;
3360
+ response += `**Warnings:** ${result.summary.bySeverity.warning}\n`;
3361
+ response += `**Auto-fixable:** ${result.summary.autoFixable}\n\n`;
3362
+
3363
+ response += `## By Category\n\n`;
3364
+ response += `| Category | Count |\n|----------|-------|\n`;
3365
+ Object.entries(result.summary.byCategory).forEach(([cat, count]) => {
3366
+ if (count > 0) response += `| ${cat} | ${count} |\n`;
3367
+ });
3368
+ response += `\n`;
3369
+
3370
+ if (result.topOffenders.length > 0) {
3371
+ response += `## Top Offending Files\n\n`;
3372
+ result.topOffenders
3373
+ .slice(0, 15)
3374
+ .forEach((o) => (response += `- \`${o.file}\`: ${o.count} errors\n`));
3375
+ }
3376
+
3377
+ return { content: [{ type: "text", text: response }] };
3378
+ } catch (error) {
3379
+ return {
3380
+ content: [
3381
+ {
3382
+ type: "text",
3383
+ text: `❌ Error collection failed: ${error.message}`,
3384
+ },
3385
+ ],
3386
+ isError: true,
3387
+ };
3388
+ }
3389
+ }
3390
+
3391
+ async repoHygieneRootCleanup(projectPath) {
3392
+ try {
3393
+ const result = await hygieneRootCleanup({ projectPath });
3394
+
3395
+ let response = `# 🏠 Root Directory Cleanup\n\n`;
3396
+
3397
+ if (result.junkFiles.length > 0) {
3398
+ response += `## Junk Files (${result.junkFiles.length})\n\n`;
3399
+ result.junkFiles.forEach(
3400
+ (j) => (response += `- \`${j.file}\` - ${j.reason}\n`),
3401
+ );
3402
+ response += `\n`;
3403
+ }
3404
+
3405
+ if (result.missingStandards.length > 0) {
3406
+ response += `## Missing Standards\n\n`;
3407
+ result.missingStandards.forEach((s) => {
3408
+ const icon = s.importance === "required" ? "🔴" : "🟡";
3409
+ response += `- ${icon} ${s.suggestion}\n`;
3410
+ });
3411
+ response += `\n`;
3412
+ }
3413
+
3414
+ if (result.duplicateConfigs.length > 0) {
3415
+ response += `## Duplicate Configs\n\n`;
3416
+ result.duplicateConfigs.forEach(
3417
+ (d) => (response += `- **${d.type}:** ${d.files.join(", ")}\n`),
3418
+ );
3419
+ response += `\n`;
3420
+ }
3421
+
3422
+ response += `\n---\n${result.cleanupPlan}`;
3423
+
3424
+ return { content: [{ type: "text", text: response }] };
3425
+ } catch (error) {
3426
+ return {
3427
+ content: [
3428
+ {
3429
+ type: "text",
3430
+ text: `❌ Root cleanup analysis failed: ${error.message}`,
3431
+ },
3432
+ ],
3433
+ isError: true,
3434
+ };
3435
+ }
3436
+ }
3437
+
3438
+ async repoHygieneDeletionPlan(projectPath, includeReview = false) {
3439
+ try {
3440
+ const result = await hygieneDeletionPlan({ projectPath, includeReview });
3441
+
3442
+ let response = `# 🗑️ Safe Deletion Plan\n\n`;
3443
+ response += `**Safe to Delete:** ${result.summary.safeCount} files\n`;
3444
+ response += `**Needs Review:** ${result.summary.reviewCount} files\n\n`;
3445
+
3446
+ if (result.safeToDelete.length > 0) {
3447
+ response += `## ✅ Safe to Delete Now\n\n`;
3448
+ response += `| File | Reason | Category |\n|------|--------|----------|\n`;
3449
+ result.safeToDelete.slice(0, 30).forEach((f) => {
3450
+ response += `| \`${f.file}\` | ${f.reason} | ${f.category} |\n`;
3451
+ });
3452
+ if (result.safeToDelete.length > 30)
3453
+ response += `| ... | ${result.safeToDelete.length - 30} more | |\n`;
3454
+ response += `\n`;
3455
+ }
3456
+
3457
+ if (includeReview && result.reviewFirst.length > 0) {
3458
+ response += `## 🟡 Review Before Deleting\n\n`;
3459
+ result.reviewFirst
3460
+ .slice(0, 20)
3461
+ .forEach((f) => (response += `- \`${f.file}\` - ${f.reason}\n`));
3462
+ }
3463
+
3464
+ response += `\n⚠️ **Note:** This tool never auto-deletes. Review and delete manually.\n`;
3465
+
3466
+ return { content: [{ type: "text", text: response }] };
3467
+ } catch (error) {
3468
+ return {
3469
+ content: [
3470
+ { type: "text", text: `❌ Deletion plan failed: ${error.message}` },
3471
+ ],
3472
+ isError: true,
3473
+ };
3474
+ }
3475
+ }
3476
+
3477
+ // 🤖 AI-Enhanced Production Integrity Methods
3478
+ async aiProductionIntegrity(projectPath, enableAI = true) {
3479
+ try {
3480
+ const { auditProductionIntegrity } = require(
3481
+ path.join(__dirname, "..", "scripts", "audit-production-integrity.js"),
3482
+ );
3483
+
3484
+ this.logger.info(
3485
+ `🤖 Running AI-Enhanced Production Integrity on: ${projectPath}`,
3486
+ );
3487
+
3488
+ const { results, integrity } =
3489
+ await auditProductionIntegrity(projectPath);
3490
+
3491
+ // Convert to AI-friendly format
3492
+ const findings = this.convertToAIFindings(results);
3493
+
3494
+ // Generate AI insights if enabled
3495
+ let aiInsights;
3496
+ if (enableAI && process.env.OPENAI_API_KEY) {
3497
+ aiInsights = await this.generateAIInsights(findings);
3498
+ } else {
3499
+ aiInsights = this.generateLocalInsights(findings);
3500
+ }
3501
+
3502
+ const report = this.formatAIProductionReport(
3503
+ findings,
3504
+ integrity,
3505
+ aiInsights,
3506
+ );
3507
+
3508
+ return {
3509
+ content: [
3510
+ { type: "text", text: report },
3511
+ {
3512
+ type: "text",
3513
+ text: `\n---\n**AI Analysis JSON:**\n\`\`\`json\n${JSON.stringify(
3514
+ {
3515
+ score: integrity.score,
3516
+ grade: integrity.grade,
3517
+ canShip: integrity.canShip,
3518
+ aiInsights,
3519
+ findingsCount: findings.length,
3520
+ },
3521
+ null,
3522
+ 2,
3523
+ )}\n\`\`\``,
3524
+ },
3525
+ ],
3526
+ };
3527
+ } catch (error) {
3528
+ this.logger.error("AI Production integrity failed", {
3529
+ error: error.message,
3530
+ });
3531
+ return {
3532
+ content: [
3533
+ {
3534
+ type: "text",
3535
+ text: `❌ AI Production integrity failed: ${error.message}`,
3536
+ },
3537
+ ],
3538
+ isError: true,
3539
+ };
3540
+ }
3541
+ }
3542
+
3543
+ convertToAIFindings(results) {
3544
+ const findings = [];
3545
+ let id = 1;
3546
+
3547
+ // Auth findings
3548
+ if (results.auth?.analysis) {
3549
+ for (const e of results.auth.analysis.adminExposed || []) {
3550
+ findings.push({
3551
+ id: `auth-${id++}`,
3552
+ category: "auth",
3553
+ severity: "critical",
3554
+ title: "Admin Endpoint Exposed",
3555
+ description: `${e.method || "GET"} ${e.path} lacks authentication`,
3556
+ file: e.file,
3557
+ });
3558
+ }
3559
+ }
3560
+
3561
+ // Secret findings
3562
+ if (results.env?.secrets) {
3563
+ for (const s of results.env.secrets) {
3564
+ findings.push({
3565
+ id: `secret-${id++}`,
3566
+ category: "secrets",
3567
+ severity: s.severity,
3568
+ title: `Hardcoded ${s.type}`,
3569
+ description: `Found hardcoded ${s.type} in code`,
3570
+ file: s.file,
3571
+ line: s.line,
3572
+ });
3573
+ }
3574
+ }
3575
+
3576
+ // Mock findings
3577
+ if (results.mocks?.issues) {
3578
+ for (const m of results.mocks.issues) {
3579
+ findings.push({
3580
+ id: `mock-${id++}`,
3581
+ category: "mocks",
3582
+ severity: m.severity || "medium",
3583
+ title: `Mock Code: ${m.name}`,
3584
+ description: m.reason || `Found ${m.name} in production code`,
3585
+ file: m.file,
3586
+ });
3587
+ }
3588
+ }
3589
+
3590
+ return findings;
3591
+ }
3592
+
3593
+ async generateAIInsights(findings) {
3594
+ const apiKey = process.env.OPENAI_API_KEY;
3595
+ if (!apiKey) return this.generateLocalInsights(findings);
3596
+
3597
+ const summary = findings
3598
+ .slice(0, 15)
3599
+ .map((f) => `[${f.severity}] ${f.title}: ${f.description}`)
3600
+ .join("\n");
3601
+
3602
+ const prompt = `Analyze these security findings and provide insights:
3603
+
3604
+ ${summary}
3605
+
3606
+ Respond with JSON:
3607
+ {
3608
+ "overallAssessment": "1-2 sentence assessment",
3609
+ "topRisks": ["Top 3 risks"],
3610
+ "quickWins": ["3-5 easy fixes"],
3611
+ "securityPosture": "strong|moderate|weak|critical",
3612
+ "estimatedFixTime": "e.g. '2-4 hours'",
3613
+ "prioritizedActions": [{"priority": 1, "action": "...", "reason": "...", "effort": "low|medium|high", "impact": "low|medium|high"}]
3614
+ }`;
3615
+
3616
+ try {
3617
+ const response = await fetch(
3618
+ "https://api.openai.com/v1/chat/completions",
3619
+ {
3620
+ method: "POST",
3621
+ headers: {
3622
+ "Content-Type": "application/json",
3623
+ Authorization: `Bearer ${apiKey}`,
3624
+ },
3625
+ body: JSON.stringify({
3626
+ model: "gpt-4o-mini",
3627
+ messages: [
3628
+ {
3629
+ role: "system",
3630
+ content:
3631
+ "You are an expert security auditor. Respond only with valid JSON.",
3632
+ },
3633
+ { role: "user", content: prompt },
3634
+ ],
3635
+ temperature: 0.3,
3636
+ max_tokens: 2000,
3637
+ response_format: { type: "json_object" },
3638
+ }),
3639
+ },
3640
+ );
3641
+
3642
+ if (!response.ok) throw new Error("AI request failed");
3643
+ const data = await response.json();
3644
+ return JSON.parse(data.choices?.[0]?.message?.content || "{}");
3645
+ } catch (error) {
3646
+ this.logger.warn("AI insights generation failed, using local", {
3647
+ error: error.message,
3648
+ });
3649
+ return this.generateLocalInsights(findings);
3650
+ }
3651
+ }
3652
+
3653
+ generateLocalInsights(findings) {
3654
+ const critical = findings.filter((f) => f.severity === "critical");
3655
+ const high = findings.filter((f) => f.severity === "high");
3656
+
3657
+ return {
3658
+ overallAssessment:
3659
+ critical.length > 0
3660
+ ? `Found ${critical.length} critical issues requiring immediate attention.`
3661
+ : "No critical issues. Review high-priority items before shipping.",
3662
+ topRisks: [
3663
+ critical.length > 0
3664
+ ? "Unauthenticated endpoints may allow unauthorized access"
3665
+ : null,
3666
+ findings.some((f) => f.category === "secrets")
3667
+ ? "Hardcoded secrets risk credential exposure"
3668
+ : null,
3669
+ findings.some((f) => f.category === "mocks")
3670
+ ? "Mock code may bypass security controls"
3671
+ : null,
3672
+ ].filter(Boolean),
3673
+ quickWins: [
3674
+ findings.some((f) => f.title.includes("console"))
3675
+ ? "Remove console.log statements"
3676
+ : null,
3677
+ findings.some((f) => f.category === "secrets")
3678
+ ? "Move secrets to environment variables"
3679
+ : null,
3680
+ ].filter(Boolean),
3681
+ securityPosture:
3682
+ critical.length > 3
3683
+ ? "critical"
3684
+ : critical.length > 0
3685
+ ? "weak"
3686
+ : high.length > 5
3687
+ ? "moderate"
3688
+ : "strong",
3689
+ estimatedFixTime:
3690
+ critical.length > 5
3691
+ ? "4-8 hours"
3692
+ : critical.length > 0
3693
+ ? "1-2 hours"
3694
+ : "< 1 hour",
3695
+ prioritizedActions: [],
3696
+ };
3697
+ }
3698
+
3699
+ formatAIProductionReport(findings, integrity, aiInsights) {
3700
+ const lines = [];
3701
+ lines.push("# 🤖 AI-Enhanced Production Integrity Report\n");
3702
+ lines.push(`**Score:** ${integrity.score}/100 (${integrity.grade})`);
3703
+ lines.push(
3704
+ `**Ship Decision:** ${integrity.canShip ? "✅ APPROVED" : "🚫 BLOCKED"}\n`,
3705
+ );
3706
+
3707
+ lines.push("## 🧠 AI Assessment\n");
3708
+ lines.push(`${aiInsights.overallAssessment}\n`);
3709
+ lines.push(
3710
+ `**Security Posture:** ${aiInsights.securityPosture?.toUpperCase()}`,
3711
+ );
3712
+ lines.push(`**Estimated Fix Time:** ${aiInsights.estimatedFixTime}\n`);
3713
+
3714
+ if (aiInsights.topRisks?.length > 0) {
3715
+ lines.push("### 🚨 Top Risks\n");
3716
+ for (const risk of aiInsights.topRisks) {
3717
+ lines.push(`- ${risk}`);
3718
+ }
3719
+ lines.push("");
3720
+ }
3721
+
3722
+ if (aiInsights.quickWins?.length > 0) {
3723
+ lines.push("### ⚡ Quick Wins\n");
3724
+ for (const win of aiInsights.quickWins) {
3725
+ lines.push(`- ${win}`);
3726
+ }
3727
+ lines.push("");
3728
+ }
3729
+
3730
+ lines.push("## 📋 Findings Summary\n");
3731
+ lines.push(`| Severity | Count |`);
3732
+ lines.push(`|----------|-------|`);
3733
+ lines.push(
3734
+ `| Critical | ${findings.filter((f) => f.severity === "critical").length} |`,
3735
+ );
3736
+ lines.push(
3737
+ `| High | ${findings.filter((f) => f.severity === "high").length} |`,
3738
+ );
3739
+ lines.push(
3740
+ `| Medium | ${findings.filter((f) => f.severity === "medium").length} |`,
3741
+ );
3742
+ lines.push("");
3743
+
3744
+ lines.push("---\n_Context Enhanced by Guardrail AI_");
3745
+
3746
+ return lines.join("\n");
3747
+ }
3748
+
3749
+ async aiExplainFinding(finding, context) {
3750
+ if (!finding) {
3751
+ return {
3752
+ content: [{ type: "text", text: "❌ No finding provided to explain" }],
3753
+ isError: true,
3754
+ };
3755
+ }
3756
+
3757
+ const apiKey = process.env.OPENAI_API_KEY;
3758
+
3759
+ if (apiKey) {
3760
+ try {
3761
+ const prompt = `Explain this security finding for a developer:
3762
+
3763
+ Finding: ${finding.title}
3764
+ Category: ${finding.category}
3765
+ Severity: ${finding.severity}
3766
+ Description: ${finding.description}
3767
+ ${context ? `Context: ${context}` : ""}
3768
+
3769
+ Provide:
3770
+ 1. Plain English explanation of why this matters
3771
+ 2. A realistic attack scenario
3772
+ 3. Which compliance frameworks this affects (GDPR, SOC2, HIPAA, etc.)
3773
+ 4. Step-by-step fix instructions
3774
+ 5. Code example showing the fix
3775
+
3776
+ Be specific and actionable.`;
3777
+
3778
+ const response = await fetch(
3779
+ "https://api.openai.com/v1/chat/completions",
3780
+ {
3781
+ method: "POST",
3782
+ headers: {
3783
+ "Content-Type": "application/json",
3784
+ Authorization: `Bearer ${apiKey}`,
3785
+ },
3786
+ body: JSON.stringify({
3787
+ model: "gpt-4o-mini",
3788
+ messages: [{ role: "user", content: prompt }],
3789
+ temperature: 0.3,
3790
+ max_tokens: 1500,
3791
+ }),
3792
+ },
3793
+ );
3794
+
3795
+ if (response.ok) {
3796
+ const data = await response.json();
3797
+ const explanation =
3798
+ data.choices?.[0]?.message?.content ||
3799
+ "Unable to generate explanation";
3800
+
3801
+ return {
3802
+ content: [
3803
+ {
3804
+ type: "text",
3805
+ text: `# 🧠 AI Explanation: ${finding.title}\n\n${explanation}\n\n---\n_Context Enhanced by Guardrail AI_`,
3806
+ },
3807
+ ],
3808
+ };
3809
+ }
3810
+ } catch (error) {
3811
+ this.logger.warn("AI explanation failed", { error: error.message });
3812
+ }
3813
+ }
3814
+
3815
+ // Local fallback
3816
+ const localExplanation = this.getLocalExplanation(finding);
3817
+ return {
3818
+ content: [
3819
+ {
3820
+ type: "text",
3821
+ text: `# 🧠 Explanation: ${finding.title}\n\n${localExplanation}\n\n_Note: For detailed AI-powered explanations, set OPENAI_API_KEY_`,
3822
+ },
3823
+ ],
3824
+ };
3825
+ }
3826
+
3827
+ getLocalExplanation(finding) {
3828
+ const explanations = {
3829
+ auth: `**Why it matters:** This endpoint lacks authentication, allowing anyone to access it.\n\n**Risk:** Unauthorized users could access or modify sensitive data.\n\n**Fix:** Add authentication middleware to verify user identity before processing requests.`,
3830
+ secrets: `**Why it matters:** Hardcoded secrets in code can be exposed if the repository is leaked.\n\n**Risk:** Attackers could use these credentials to access external services.\n\n**Fix:** Move secrets to environment variables and rotate the exposed credential.`,
3831
+ mocks: `**Why it matters:** Test/mock code in production may bypass security controls.\n\n**Risk:** Users might see fake data or bypass authentication.\n\n**Fix:** Remove mock imports and ensure only production code is deployed.`,
3832
+ };
3833
+ return (
3834
+ explanations[finding.category] ||
3835
+ "This finding indicates a potential security or quality issue that should be reviewed."
3836
+ );
3837
+ }
3838
+
3839
+ async aiGenerateFix(finding) {
3840
+ if (!finding) {
3841
+ return {
3842
+ content: [{ type: "text", text: "❌ No finding provided" }],
3843
+ isError: true,
3844
+ };
3845
+ }
3846
+
3847
+ const apiKey = process.env.OPENAI_API_KEY;
3848
+
3849
+ if (apiKey) {
3850
+ try {
3851
+ const prompt = `Generate a specific fix for this security issue:
3852
+
3853
+ Category: ${finding.category}
3854
+ Severity: ${finding.severity}
3855
+ Title: ${finding.title}
3856
+ Description: ${finding.description}
3857
+ File: ${finding.file || "unknown"}
3858
+ Code: ${finding.code || "N/A"}
3859
+
3860
+ Provide:
3861
+ 1. Step-by-step instructions to fix this
3862
+ 2. A complete code example showing the fix
3863
+ 3. How to verify the fix works
3864
+
3865
+ Be specific and provide working code.`;
3866
+
3867
+ const response = await fetch(
3868
+ "https://api.openai.com/v1/chat/completions",
3869
+ {
3870
+ method: "POST",
3871
+ headers: {
3872
+ "Content-Type": "application/json",
3873
+ Authorization: `Bearer ${apiKey}`,
3874
+ },
3875
+ body: JSON.stringify({
3876
+ model: "gpt-4o-mini",
3877
+ messages: [{ role: "user", content: prompt }],
3878
+ temperature: 0.3,
3879
+ max_tokens: 1500,
3880
+ }),
3881
+ },
3882
+ );
3883
+
3884
+ if (response.ok) {
3885
+ const data = await response.json();
3886
+ const fix =
3887
+ data.choices?.[0]?.message?.content || "Unable to generate fix";
3888
+
3889
+ return {
3890
+ content: [
3891
+ {
3892
+ type: "text",
3893
+ text: `# 🔧 AI-Generated Fix: ${finding.title}\n\n${fix}\n\n---\n_Context Enhanced by Guardrail AI_`,
3894
+ },
3895
+ ],
3896
+ };
3897
+ }
3898
+ } catch (error) {
3899
+ this.logger.warn("AI fix generation failed", { error: error.message });
3900
+ }
3901
+ }
3902
+
3903
+ // Local fallback
3904
+ const localFix = this.getLocalFix(finding);
3905
+ return {
3906
+ content: [
3907
+ {
3908
+ type: "text",
3909
+ text: `# 🔧 Fix: ${finding.title}\n\n${localFix.fix}\n\n**Code Example:**\n\`\`\`javascript\n${localFix.code || "// No code example available"}\n\`\`\`\n\n_Note: For detailed AI-powered fixes, set OPENAI_API_KEY_`,
3910
+ },
3911
+ ],
3912
+ };
3913
+ }
3914
+
3915
+ getLocalFix(finding) {
3916
+ const fixes = {
3917
+ auth: {
3918
+ fix: "1. Add authentication middleware to the route\n2. Verify user session/token\n3. Check required permissions\n4. Return 401/403 for unauthorized access",
3919
+ code: `// Add auth middleware
3920
+ router.use(requireAuth);
3921
+
3922
+ router.get('/admin/users', async (req, res) => {
3923
+ if (!req.user?.isAdmin) {
3924
+ return res.status(403).json({ error: 'Forbidden' });
3925
+ }
3926
+ // ... handler
3927
+ });`,
3928
+ },
3929
+ secrets: {
3930
+ fix: "1. Remove the hardcoded secret\n2. Add to .env file\n3. Use process.env.VAR\n4. Rotate the exposed credential",
3931
+ code: `// Before (bad)
3932
+ const apiKey = 'sk-abc123...';
3933
+
3934
+ // After (good)
3935
+ const apiKey = process.env.API_KEY;
3936
+ if (!apiKey) {
3937
+ throw new Error('API_KEY required');
3938
+ }`,
3939
+ },
3940
+ mocks: {
3941
+ fix: "1. Remove mock/test imports\n2. Move test code to test directories\n3. Remove console.log statements",
3942
+ code: `// Remove these from production
3943
+ // import { mockData } from './test-utils';
3944
+ // console.log('debug:', data);`,
3945
+ },
3946
+ };
3947
+ return (
3948
+ fixes[finding.category] || {
3949
+ fix: "Review and apply appropriate fix.",
3950
+ code: null,
3951
+ }
3952
+ );
3953
+ }
3954
+
3955
+ async aiSecurityAssessment(
3956
+ projectPath,
3957
+ complianceFrameworks = ["SOC2", "GDPR"],
3958
+ ) {
3959
+ try {
3960
+ const { auditProductionIntegrity } = require(
3961
+ path.join(__dirname, "..", "scripts", "audit-production-integrity.js"),
3962
+ );
3963
+
3964
+ const { results, integrity } =
3965
+ await auditProductionIntegrity(projectPath);
3966
+ const findings = this.convertToAIFindings(results);
3967
+
3968
+ const apiKey = process.env.OPENAI_API_KEY;
3969
+
3970
+ let assessment;
3971
+ if (apiKey) {
3972
+ const prompt = `You are a security consultant. Assess this codebase for ${complianceFrameworks.join(", ")} compliance.
3973
+
3974
+ Findings Summary:
3975
+ - Critical: ${findings.filter((f) => f.severity === "critical").length}
3976
+ - High: ${findings.filter((f) => f.severity === "high").length}
3977
+ - Categories: auth (${findings.filter((f) => f.category === "auth").length}), secrets (${findings.filter((f) => f.category === "secrets").length}), mocks (${findings.filter((f) => f.category === "mocks").length})
3978
+
3979
+ Top Issues:
3980
+ ${findings
3981
+ .slice(0, 10)
3982
+ .map((f) => `- [${f.severity}] ${f.title}`)
3983
+ .join("\n")}
3984
+
3985
+ Provide a comprehensive security assessment including:
3986
+ 1. Overall security posture rating
3987
+ 2. Compliance gaps for each framework
3988
+ 3. Risk matrix (likelihood vs impact)
3989
+ 4. Remediation roadmap with timeline
3990
+ 5. Quick wins vs long-term improvements`;
3991
+
3992
+ try {
3993
+ const response = await fetch(
3994
+ "https://api.openai.com/v1/chat/completions",
3995
+ {
3996
+ method: "POST",
3997
+ headers: {
3998
+ "Content-Type": "application/json",
3999
+ Authorization: `Bearer ${apiKey}`,
4000
+ },
4001
+ body: JSON.stringify({
4002
+ model: "gpt-4o-mini",
4003
+ messages: [{ role: "user", content: prompt }],
4004
+ temperature: 0.3,
4005
+ max_tokens: 2500,
4006
+ }),
4007
+ },
4008
+ );
4009
+
4010
+ if (response.ok) {
4011
+ const data = await response.json();
4012
+ assessment = data.choices?.[0]?.message?.content;
4013
+ }
4014
+ } catch (error) {
4015
+ this.logger.warn("AI assessment failed", { error: error.message });
4016
+ }
4017
+ }
4018
+
4019
+ if (!assessment) {
4020
+ assessment = this.generateLocalAssessment(
4021
+ findings,
4022
+ integrity,
4023
+ complianceFrameworks,
4024
+ );
4025
+ }
4026
+
4027
+ return {
4028
+ content: [
4029
+ {
4030
+ type: "text",
4031
+ text: `# 🛡️ AI Security Assessment\n\n**Frameworks:** ${complianceFrameworks.join(", ")}\n**Score:** ${integrity.score}/100\n\n${assessment}\n\n---\n_Context Enhanced by Guardrail AI_`,
4032
+ },
4033
+ ],
4034
+ };
4035
+ } catch (error) {
4036
+ return {
4037
+ content: [
4038
+ {
4039
+ type: "text",
4040
+ text: `❌ Security assessment failed: ${error.message}`,
4041
+ },
4042
+ ],
4043
+ isError: true,
4044
+ };
4045
+ }
4046
+ }
4047
+
4048
+ generateLocalAssessment(findings, integrity, frameworks) {
4049
+ const critical = findings.filter((f) => f.severity === "critical").length;
4050
+ const high = findings.filter((f) => f.severity === "high").length;
4051
+
4052
+ let posture = "Moderate";
4053
+ if (critical > 3) posture = "Critical";
4054
+ else if (critical > 0) posture = "Weak";
4055
+ else if (high === 0) posture = "Strong";
4056
+
4057
+ return `## Security Posture: ${posture}
4058
+
4059
+ ### Findings Summary
4060
+ - Critical Issues: ${critical}
4061
+ - High Priority: ${high}
4062
+ - Total Findings: ${findings.length}
4063
+
4064
+ ### Compliance Gaps
4065
+ ${frameworks.map((f) => `- **${f}**: ${critical > 0 ? "Gaps detected - review required" : "No critical gaps"}`).join("\n")}
4066
+
4067
+ ### Recommendations
4068
+ 1. ${critical > 0 ? "Address critical authentication issues immediately" : "Continue monitoring security posture"}
4069
+ 2. ${findings.some((f) => f.category === "secrets") ? "Rotate exposed credentials and move to environment variables" : "Maintain secret management practices"}
4070
+ 3. Regular security audits recommended
4071
+
4072
+ _For detailed AI-powered assessment, set OPENAI_API_KEY_`;
4073
+ }
4074
+
4075
+ setupErrorHandling() {
4076
+ // Enhanced error handling with detailed logging
4077
+ this.server.onerror = (error) => {
4078
+ this.logger.error("MCP Server Error", {
4079
+ message: error.message,
4080
+ stack: error.stack,
4081
+ timestamp: new Date().toISOString(),
4082
+ });
4083
+ };
4084
+
4085
+ // Graceful shutdown
4086
+ process.on("SIGINT", async () => {
4087
+ this.logger.info("Received SIGINT, shutting down gracefully...");
4088
+ try {
4089
+ await this.server.close();
4090
+ this.logger.info("Server closed successfully");
4091
+ process.exit(0);
4092
+ } catch (error) {
4093
+ this.logger.error("Error during shutdown", error);
4094
+ process.exit(1);
4095
+ }
4096
+ });
4097
+
4098
+ process.on("SIGTERM", async () => {
4099
+ this.logger.info("Received SIGTERM, shutting down gracefully...");
4100
+ try {
4101
+ await this.server.close();
4102
+ this.logger.info("Server closed successfully");
4103
+ process.exit(0);
4104
+ } catch (error) {
4105
+ this.logger.error("Error during shutdown", error);
4106
+ process.exit(1);
4107
+ }
4108
+ });
4109
+
4110
+ // Unhandled promise rejections
4111
+ process.on("unhandledRejection", (reason, promise) => {
4112
+ this.logger.error("Unhandled Promise Rejection", {
4113
+ reason: reason.toString(),
4114
+ promise: promise.toString(),
4115
+ });
4116
+ });
4117
+
4118
+ // Uncaught exceptions
4119
+ process.on("uncaughtException", (error) => {
4120
+ this.logger.error("Uncaught Exception", {
4121
+ message: error.message,
4122
+ stack: error.stack,
4123
+ });
4124
+ process.exit(1);
4125
+ });
4126
+ }
4127
+
4128
+ async run() {
4129
+ const transport = new StdioServerTransport();
4130
+ await this.server.connect(transport);
4131
+ this.logger.info("GUARDRAIL AI MCP Server started successfully");
4132
+ console.error("GUARDRAIL AI MCP Server running on stdio");
4133
+ }
4134
+ }
4135
+
4136
+ const server = new GuardrailsMCPServer();
4137
+ server.run().catch(console.error);