@vibecheckai/cli 3.5.0 → 3.5.2

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.
Files changed (224) hide show
  1. package/bin/registry.js +214 -237
  2. package/bin/runners/cli-utils.js +33 -2
  3. package/bin/runners/context/analyzer.js +52 -1
  4. package/bin/runners/context/generators/cursor.js +2 -49
  5. package/bin/runners/context/git-context.js +3 -1
  6. package/bin/runners/context/team-conventions.js +33 -7
  7. package/bin/runners/lib/analysis-core.js +25 -5
  8. package/bin/runners/lib/analyzers.js +431 -481
  9. package/bin/runners/lib/default-config.js +127 -0
  10. package/bin/runners/lib/doctor/modules/security.js +3 -1
  11. package/bin/runners/lib/engine/ast-cache.js +210 -0
  12. package/bin/runners/lib/engine/auth-extractor.js +211 -0
  13. package/bin/runners/lib/engine/billing-extractor.js +112 -0
  14. package/bin/runners/lib/engine/enforcement-extractor.js +100 -0
  15. package/bin/runners/lib/engine/env-extractor.js +207 -0
  16. package/bin/runners/lib/engine/express-extractor.js +208 -0
  17. package/bin/runners/lib/engine/extractors.js +849 -0
  18. package/bin/runners/lib/engine/index.js +207 -0
  19. package/bin/runners/lib/engine/repo-index.js +514 -0
  20. package/bin/runners/lib/engine/types.js +124 -0
  21. package/bin/runners/lib/engines/accessibility-engine.js +18 -218
  22. package/bin/runners/lib/engines/api-consistency-engine.js +30 -335
  23. package/bin/runners/lib/engines/cross-file-analysis-engine.js +27 -292
  24. package/bin/runners/lib/engines/empty-catch-engine.js +17 -127
  25. package/bin/runners/lib/engines/mock-data-engine.js +10 -53
  26. package/bin/runners/lib/engines/performance-issues-engine.js +36 -176
  27. package/bin/runners/lib/engines/security-vulnerabilities-engine.js +54 -382
  28. package/bin/runners/lib/engines/type-aware-engine.js +39 -263
  29. package/bin/runners/lib/engines/vibecheck-engines/index.js +13 -122
  30. package/bin/runners/lib/engines/vibecheck-engines/lib/ast-cache.js +164 -0
  31. package/bin/runners/lib/engines/vibecheck-engines/lib/code-quality-engine.js +291 -0
  32. package/bin/runners/lib/engines/vibecheck-engines/lib/console-logs-engine.js +83 -0
  33. package/bin/runners/lib/engines/vibecheck-engines/lib/dead-code-engine.js +198 -0
  34. package/bin/runners/lib/engines/vibecheck-engines/lib/deprecated-api-engine.js +275 -0
  35. package/bin/runners/lib/engines/vibecheck-engines/lib/empty-catch-engine.js +167 -0
  36. package/bin/runners/lib/engines/vibecheck-engines/lib/file-filter.js +217 -0
  37. package/bin/runners/lib/engines/vibecheck-engines/lib/hardcoded-secrets-engine.js +73 -373
  38. package/bin/runners/lib/engines/vibecheck-engines/lib/mock-data-engine.js +140 -0
  39. package/bin/runners/lib/engines/vibecheck-engines/lib/parallel-processor.js +164 -0
  40. package/bin/runners/lib/engines/vibecheck-engines/lib/performance-issues-engine.js +234 -0
  41. package/bin/runners/lib/engines/vibecheck-engines/lib/type-aware-engine.js +217 -0
  42. package/bin/runners/lib/engines/vibecheck-engines/lib/unsafe-regex-engine.js +78 -0
  43. package/bin/runners/lib/entitlements-v2.js +73 -97
  44. package/bin/runners/lib/error-handler.js +44 -3
  45. package/bin/runners/lib/error-messages.js +289 -0
  46. package/bin/runners/lib/evidence-pack.js +7 -1
  47. package/bin/runners/lib/finding-id.js +69 -0
  48. package/bin/runners/lib/finding-sorter.js +89 -0
  49. package/bin/runners/lib/html-proof-report.js +700 -350
  50. package/bin/runners/lib/missions/plan.js +6 -46
  51. package/bin/runners/lib/missions/templates.js +0 -232
  52. package/bin/runners/lib/next-action.js +560 -0
  53. package/bin/runners/lib/prerequisites.js +149 -0
  54. package/bin/runners/lib/route-detection.js +137 -68
  55. package/bin/runners/lib/scan-output.js +91 -76
  56. package/bin/runners/lib/scan-runner.js +135 -0
  57. package/bin/runners/lib/schemas/ajv-validator.js +464 -0
  58. package/bin/runners/lib/schemas/error-envelope.schema.json +105 -0
  59. package/bin/runners/lib/schemas/finding-v3.schema.json +151 -0
  60. package/bin/runners/lib/schemas/report-artifact.schema.json +120 -0
  61. package/bin/runners/lib/schemas/run-request.schema.json +108 -0
  62. package/bin/runners/lib/schemas/validator.js +27 -0
  63. package/bin/runners/lib/schemas/verdict.schema.json +140 -0
  64. package/bin/runners/lib/ship-output-enterprise.js +23 -23
  65. package/bin/runners/lib/ship-output.js +75 -31
  66. package/bin/runners/lib/terminal-ui.js +6 -113
  67. package/bin/runners/lib/truth.js +351 -10
  68. package/bin/runners/lib/unified-cli-output.js +430 -603
  69. package/bin/runners/lib/unified-output.js +13 -9
  70. package/bin/runners/runAIAgent.js +10 -5
  71. package/bin/runners/runAgent.js +0 -3
  72. package/bin/runners/runAllowlist.js +389 -0
  73. package/bin/runners/runApprove.js +0 -33
  74. package/bin/runners/runAuth.js +73 -45
  75. package/bin/runners/runCheckpoint.js +51 -11
  76. package/bin/runners/runClassify.js +85 -21
  77. package/bin/runners/runContext.js +0 -3
  78. package/bin/runners/runDoctor.js +41 -28
  79. package/bin/runners/runEvidencePack.js +362 -0
  80. package/bin/runners/runFirewall.js +0 -3
  81. package/bin/runners/runFirewallHook.js +0 -3
  82. package/bin/runners/runFix.js +66 -76
  83. package/bin/runners/runGuard.js +18 -411
  84. package/bin/runners/runInit.js +113 -30
  85. package/bin/runners/runLabs.js +424 -0
  86. package/bin/runners/runMcp.js +19 -25
  87. package/bin/runners/runPolish.js +64 -240
  88. package/bin/runners/runPromptFirewall.js +12 -5
  89. package/bin/runners/runProve.js +57 -22
  90. package/bin/runners/runQuickstart.js +531 -0
  91. package/bin/runners/runReality.js +59 -68
  92. package/bin/runners/runReport.js +38 -33
  93. package/bin/runners/runRuntime.js +8 -5
  94. package/bin/runners/runScan.js +1413 -190
  95. package/bin/runners/runShip.js +113 -719
  96. package/bin/runners/runTruth.js +0 -3
  97. package/bin/runners/runValidate.js +13 -9
  98. package/bin/runners/runWatch.js +23 -14
  99. package/bin/scan.js +6 -1
  100. package/bin/vibecheck.js +204 -185
  101. package/mcp-server/deprecation-middleware.js +282 -0
  102. package/mcp-server/handlers/index.ts +15 -0
  103. package/mcp-server/handlers/tool-handler.ts +554 -0
  104. package/mcp-server/index-v1.js +698 -0
  105. package/mcp-server/index.js +210 -238
  106. package/mcp-server/lib/cache-wrapper.cjs +383 -0
  107. package/mcp-server/lib/error-envelope.js +138 -0
  108. package/mcp-server/lib/executor.ts +499 -0
  109. package/mcp-server/lib/index.ts +19 -0
  110. package/mcp-server/lib/rate-limiter.js +166 -0
  111. package/mcp-server/lib/sandbox.test.ts +519 -0
  112. package/mcp-server/lib/sandbox.ts +395 -0
  113. package/mcp-server/lib/types.ts +267 -0
  114. package/mcp-server/package.json +12 -3
  115. package/mcp-server/registry/tool-registry.js +794 -0
  116. package/mcp-server/registry/tools.json +605 -0
  117. package/mcp-server/registry.test.ts +334 -0
  118. package/mcp-server/tests/tier-gating.test.js +297 -0
  119. package/mcp-server/tier-auth.js +378 -45
  120. package/mcp-server/tools-v3.js +353 -442
  121. package/mcp-server/tsconfig.json +37 -0
  122. package/mcp-server/vibecheck-2.0-tools.js +14 -1
  123. package/package.json +1 -1
  124. package/bin/runners/lib/agent-firewall/learning/learning-engine.js +0 -849
  125. package/bin/runners/lib/audit-logger.js +0 -532
  126. package/bin/runners/lib/authority/authorities/architecture.js +0 -364
  127. package/bin/runners/lib/authority/authorities/compliance.js +0 -341
  128. package/bin/runners/lib/authority/authorities/human.js +0 -343
  129. package/bin/runners/lib/authority/authorities/quality.js +0 -420
  130. package/bin/runners/lib/authority/authorities/security.js +0 -228
  131. package/bin/runners/lib/authority/index.js +0 -293
  132. package/bin/runners/lib/bundle/bundle-intelligence.js +0 -846
  133. package/bin/runners/lib/cli-charts.js +0 -368
  134. package/bin/runners/lib/cli-config-display.js +0 -405
  135. package/bin/runners/lib/cli-demo.js +0 -275
  136. package/bin/runners/lib/cli-errors.js +0 -438
  137. package/bin/runners/lib/cli-help-formatter.js +0 -439
  138. package/bin/runners/lib/cli-interactive-menu.js +0 -509
  139. package/bin/runners/lib/cli-prompts.js +0 -441
  140. package/bin/runners/lib/cli-scan-cards.js +0 -362
  141. package/bin/runners/lib/compliance-reporter.js +0 -710
  142. package/bin/runners/lib/conductor/index.js +0 -671
  143. package/bin/runners/lib/easy/README.md +0 -123
  144. package/bin/runners/lib/easy/index.js +0 -140
  145. package/bin/runners/lib/easy/interactive-wizard.js +0 -788
  146. package/bin/runners/lib/easy/one-click-firewall.js +0 -564
  147. package/bin/runners/lib/easy/zero-config-reality.js +0 -714
  148. package/bin/runners/lib/engines/async-patterns-engine.js +0 -444
  149. package/bin/runners/lib/engines/bundle-size-engine.js +0 -433
  150. package/bin/runners/lib/engines/confidence-scoring.js +0 -276
  151. package/bin/runners/lib/engines/context-detection.js +0 -264
  152. package/bin/runners/lib/engines/database-patterns-engine.js +0 -429
  153. package/bin/runners/lib/engines/duplicate-code-engine.js +0 -354
  154. package/bin/runners/lib/engines/env-variables-engine.js +0 -458
  155. package/bin/runners/lib/engines/error-handling-engine.js +0 -437
  156. package/bin/runners/lib/engines/false-positive-prevention.js +0 -630
  157. package/bin/runners/lib/engines/framework-adapters/index.js +0 -607
  158. package/bin/runners/lib/engines/framework-detection.js +0 -508
  159. package/bin/runners/lib/engines/import-order-engine.js +0 -429
  160. package/bin/runners/lib/engines/naming-conventions-engine.js +0 -544
  161. package/bin/runners/lib/engines/noise-reduction-engine.js +0 -452
  162. package/bin/runners/lib/engines/orchestrator.js +0 -334
  163. package/bin/runners/lib/engines/react-patterns-engine.js +0 -457
  164. package/bin/runners/lib/engines/vibecheck-engines/lib/ai-hallucination-engine.js +0 -806
  165. package/bin/runners/lib/engines/vibecheck-engines/lib/smart-fix-engine.js +0 -577
  166. package/bin/runners/lib/engines/vibecheck-engines/lib/vibe-score-engine.js +0 -543
  167. package/bin/runners/lib/engines/vibecheck-engines.js +0 -514
  168. package/bin/runners/lib/enhanced-features/index.js +0 -305
  169. package/bin/runners/lib/enhanced-output.js +0 -631
  170. package/bin/runners/lib/enterprise.js +0 -300
  171. package/bin/runners/lib/firewall/command-validator.js +0 -351
  172. package/bin/runners/lib/firewall/config.js +0 -341
  173. package/bin/runners/lib/firewall/content-validator.js +0 -519
  174. package/bin/runners/lib/firewall/index.js +0 -101
  175. package/bin/runners/lib/firewall/path-validator.js +0 -256
  176. package/bin/runners/lib/intelligence/cross-repo-intelligence.js +0 -817
  177. package/bin/runners/lib/mcp-utils.js +0 -425
  178. package/bin/runners/lib/output/index.js +0 -1022
  179. package/bin/runners/lib/policy-engine.js +0 -652
  180. package/bin/runners/lib/polish/autofix/accessibility-fixes.js +0 -333
  181. package/bin/runners/lib/polish/autofix/async-handlers.js +0 -273
  182. package/bin/runners/lib/polish/autofix/dead-code.js +0 -280
  183. package/bin/runners/lib/polish/autofix/imports-optimizer.js +0 -344
  184. package/bin/runners/lib/polish/autofix/index.js +0 -200
  185. package/bin/runners/lib/polish/autofix/remove-consoles.js +0 -209
  186. package/bin/runners/lib/polish/autofix/strengthen-types.js +0 -245
  187. package/bin/runners/lib/polish/backend-checks.js +0 -148
  188. package/bin/runners/lib/polish/documentation-checks.js +0 -111
  189. package/bin/runners/lib/polish/frontend-checks.js +0 -168
  190. package/bin/runners/lib/polish/index.js +0 -71
  191. package/bin/runners/lib/polish/infrastructure-checks.js +0 -131
  192. package/bin/runners/lib/polish/library-detection.js +0 -175
  193. package/bin/runners/lib/polish/performance-checks.js +0 -100
  194. package/bin/runners/lib/polish/security-checks.js +0 -148
  195. package/bin/runners/lib/polish/utils.js +0 -203
  196. package/bin/runners/lib/prompt-builder.js +0 -540
  197. package/bin/runners/lib/proof-certificate.js +0 -634
  198. package/bin/runners/lib/reality/accessibility-audit.js +0 -946
  199. package/bin/runners/lib/reality/api-contract-validator.js +0 -1012
  200. package/bin/runners/lib/reality/chaos-engineering.js +0 -1084
  201. package/bin/runners/lib/reality/performance-tracker.js +0 -1077
  202. package/bin/runners/lib/reality/scenario-generator.js +0 -1404
  203. package/bin/runners/lib/reality/visual-regression.js +0 -852
  204. package/bin/runners/lib/reality-profiler.js +0 -717
  205. package/bin/runners/lib/replay/flight-recorder-viewer.js +0 -1160
  206. package/bin/runners/lib/review/ai-code-review.js +0 -832
  207. package/bin/runners/lib/rules/custom-rule-engine.js +0 -985
  208. package/bin/runners/lib/sbom-generator.js +0 -641
  209. package/bin/runners/lib/scan-output-enhanced.js +0 -512
  210. package/bin/runners/lib/security/owasp-scanner.js +0 -939
  211. package/bin/runners/lib/validators/contract-validator.js +0 -283
  212. package/bin/runners/lib/validators/dead-export-detector.js +0 -279
  213. package/bin/runners/lib/validators/dep-audit.js +0 -245
  214. package/bin/runners/lib/validators/env-validator.js +0 -319
  215. package/bin/runners/lib/validators/index.js +0 -120
  216. package/bin/runners/lib/validators/license-checker.js +0 -252
  217. package/bin/runners/lib/validators/route-validator.js +0 -290
  218. package/bin/runners/runAuthority.js +0 -528
  219. package/bin/runners/runConductor.js +0 -772
  220. package/bin/runners/runContainer.js +0 -366
  221. package/bin/runners/runEasy.js +0 -410
  222. package/bin/runners/runIaC.js +0 -372
  223. package/bin/runners/runVibe.js +0 -791
  224. package/mcp-server/tools.js +0 -495
@@ -63,7 +63,7 @@ const __dirname = path.dirname(__filename);
63
63
  // CENTRALIZED CONFIGURATION
64
64
  // ============================================================================
65
65
  const CONFIG = {
66
- VERSION: "2.2.0",
66
+ VERSION: "2.1.0",
67
67
  BIN_PATH: path.join(__dirname, "..", "bin", "vibecheck.js"),
68
68
  OUTPUT_DIR: ".vibecheck",
69
69
  ENV_DEFAULTS: { VIBECHECK_SKIP_AUTH: "1" },
@@ -526,11 +526,25 @@ const CONTEXT_ATTRIBUTION = "🧠 Context enhanced by vibecheck";
526
526
  // Import Consolidated Tools (15 focused tools - recommended surface)
527
527
  import { CONSOLIDATED_TOOLS, handleConsolidatedTool } from "./consolidated-tools.js";
528
528
 
529
- // Import v3 Tools (10 focused tools - STARTER+ only, no free tools)
529
+ // Import v3 Tools (2-tier model: FREE tools for inspect & observe, PRO for fix/prove/enforce)
530
530
  import { MCP_TOOLS_V3, handleToolV3, TOOL_TIERS as V3_TOOL_TIERS } from "./tools-v3.js";
531
531
 
532
532
  // Import tier auth for entitlement checking
533
- import { getFeatureAccessStatus } from "./tier-auth.js";
533
+ import { getFeatureAccessStatus, getTierFromApiKey } from "./tier-auth.js";
534
+
535
+ // Import new production modules
536
+ const {
537
+ validateToolInput,
538
+ validateToolOutput,
539
+ getToolTimeout,
540
+ getToolTier,
541
+ } = require('./registry/tool-registry.js');
542
+ const {
543
+ executeWithEnvelope,
544
+ createErrorEnvelope,
545
+ createSuccessEnvelope,
546
+ } = require('./lib/error-envelope.js');
547
+ const { rateLimiter } = require('./lib/rate-limiter.js');
534
548
 
535
549
  // Import Agent Firewall Interceptor - ENABLED BY DEFAULT
536
550
  // The Agent Firewall is the core gatekeeper that validates AI changes against reality
@@ -901,117 +915,29 @@ class VibecheckMCP {
901
915
  return '## Error: Invalid summary data\n';
902
916
  }
903
917
 
904
- // Safely extract values with defaults - handle different output structures
905
- const score = sanitizeNumber(
906
- summary.score?.overall || summary.score || summary.verdict?.score || 0,
907
- 0, 100, 0
908
- );
909
- const grade = sanitizeString(summary.grade || summary.verdict?.grade, 10) || 'N/A';
910
- const verdict = summary.verdict?.verdict || summary.verdict || (score >= 80 ? 'SHIP' : score >= 50 ? 'WARN' : 'BLOCK');
911
- const canShip = verdict === 'SHIP' || Boolean(summary.canShip);
912
- const findings = sanitizeArray(summary.findings || summary.report?.findings || [], 500);
913
-
914
- // Get severity counts
915
- const sevCounts = { critical: 0, high: 0, medium: 0, low: 0 };
916
- for (const f of findings) {
917
- const sev = (f.severity || 'medium').toLowerCase();
918
- if (sev === 'block' || sev === 'critical') sevCounts.critical++;
919
- else if (sev === 'high') sevCounts.high++;
920
- else if (sev === 'warn' || sev === 'warning' || sev === 'medium') sevCounts.medium++;
921
- else sevCounts.low++;
922
- }
923
-
924
- // Build structured output
925
- let output = '';
926
-
927
- // Header with verdict
928
- const verdictEmoji = verdict === 'SHIP' ? '✅' : verdict === 'WARN' ? '⚠️' : '🚫';
929
- output += `## ${verdictEmoji} VERDICT: ${verdict}\n\n`;
930
- output += `**Health Score:** ${score}/100 (${grade})\n\n`;
918
+ // Safely extract values with defaults
919
+ const score = sanitizeNumber(summary.score, 0, 100, 0);
920
+ const grade = sanitizeString(summary.grade, 10) || 'N/A';
921
+ const canShip = Boolean(summary.canShip);
931
922
 
932
- // Summary stats
933
- output += `### Summary\n`;
934
- output += `- **Total Issues:** ${findings.length}\n`;
935
- output += `- **Critical:** ${sevCounts.critical}\n`;
936
- output += `- **High:** ${sevCounts.high}\n`;
937
- output += `- **Medium:** ${sevCounts.medium}\n`;
938
- output += `- **Low:** ${sevCounts.low}\n\n`;
939
-
940
- // Category breakdown
923
+ let output = `## Score: ${score}/100 (${grade})\n\n`;
924
+ output += `**Verdict:** ${canShip ? "✅ SHIP" : "🚫 NO-SHIP"}\n\n`;
925
+
941
926
  if (summary.counts && typeof summary.counts === 'object') {
942
- output += "### Issue Categories\n\n";
943
- output += "| Category | Count | Status |\n|----------|-------|--------|\n";
927
+ output += "### Checks\n\n";
928
+ output += "| Category | Issues |\n|----------|--------|\n";
944
929
 
945
- const entries = Object.entries(summary.counts).slice(0, 20);
930
+ // Limit to 50 categories to prevent output bloat
931
+ const entries = Object.entries(summary.counts).slice(0, 50);
946
932
  for (const [key, count] of entries) {
947
933
  const safeKey = sanitizeString(key, 50);
948
934
  const safeCount = sanitizeNumber(count, 0, 999999, 0);
949
935
  const icon = safeCount === 0 ? "✅" : "⚠️";
950
- output += `| ${safeKey} | ${safeCount} | ${icon} |\n`;
936
+ output += `| ${icon} ${safeKey} | ${safeCount} |\n`;
951
937
  }
952
- output += '\n';
953
938
  }
954
939
 
955
- // Top findings with details (show up to 15)
956
- if (findings.length > 0) {
957
- output += "### Top Issues to Fix\n\n";
958
-
959
- // Sort by severity (critical first)
960
- const sortedFindings = findings
961
- .sort((a, b) => {
962
- const sevOrder = { critical: 0, block: 0, high: 1, warn: 2, warning: 2, medium: 2, low: 3, info: 4 };
963
- const aOrder = sevOrder[(a.severity || 'medium').toLowerCase()] || 2;
964
- const bOrder = sevOrder[(b.severity || 'medium').toLowerCase()] || 2;
965
- return aOrder - bOrder;
966
- })
967
- .slice(0, 15);
968
-
969
- for (let i = 0; i < sortedFindings.length; i++) {
970
- const f = sortedFindings[i];
971
- const sev = sanitizeString(f.severity || 'medium', 20).toUpperCase();
972
- const sevEmoji = sev === 'CRITICAL' || sev === 'BLOCK' ? '🔴' : sev === 'HIGH' ? '🟠' : '🟡';
973
- const title = sanitizeString(f.title || f.message || f.why || 'Unknown issue', 100);
974
- const category = sanitizeString(f.category || f.type || 'Other', 30);
975
- const file = sanitizeString(f.file || (f.evidence && f.evidence[0]?.file) || '', 150);
976
- const line = f.line || (f.evidence && f.evidence[0]?.lines) || '';
977
-
978
- output += `**${i + 1}. ${sevEmoji} [${sev}] ${title}**\n`;
979
- output += ` - Category: \`${category}\`\n`;
980
- if (file) {
981
- output += ` - File: \`${file}\`${line ? `:${line}` : ''}\n`;
982
- }
983
-
984
- // Include fix hints if available
985
- const fixHint = f.fixHints?.[0] || f.fixHint || f.fix;
986
- if (fixHint) {
987
- output += ` - **Fix:** ${sanitizeString(fixHint, 200)}\n`;
988
- }
989
- output += '\n';
990
- }
991
-
992
- if (findings.length > 15) {
993
- output += `_...and ${findings.length - 15} more issues. See full report for details._\n\n`;
994
- }
995
- }
996
-
997
- // Next steps based on verdict
998
- output += "### Recommended Actions\n\n";
999
- if (verdict === 'SHIP') {
1000
- output += "- ✅ Code is clean and ready to ship\n";
1001
- output += "- Consider running `vibecheck ship --badge` to generate a status badge\n";
1002
- } else if (verdict === 'WARN') {
1003
- output += "- Review the warnings above before shipping\n";
1004
- output += "- Run `vibecheck fix --plan` to see fix suggestions\n";
1005
- output += "- Consider using `vibecheck fix --apply` (PRO) to auto-fix issues\n";
1006
- } else {
1007
- output += "- 🚫 Critical issues must be fixed before shipping\n";
1008
- output += "- Run `vibecheck fix --plan` to see detailed fix suggestions\n";
1009
- output += "- Address critical issues first, then re-scan\n";
1010
- }
1011
-
1012
- output += `\n📄 **Full Report:** ${CONFIG.OUTPUT_DIR}/report.html\n`;
1013
- output += `📊 **JSON Results:** ${CONFIG.OUTPUT_DIR}/results/latest.json\n`;
1014
-
940
+ output += `\n📄 **Report:** ${CONFIG.OUTPUT_DIR}/report.html\n`;
1015
941
  return output;
1016
942
  }
1017
943
 
@@ -1141,25 +1067,101 @@ class VibecheckMCP {
1141
1067
  });
1142
1068
  }
1143
1069
 
1144
- // Handle v3 tools (10 consolidated tools, STARTER+ only)
1070
+ // Handle v3 tools (2-tier: FREE/PRO aligned with CLI entitlements)
1145
1071
  if (USE_V3_TOOLS && V3_TOOL_TIERS[toolName]) {
1146
- // SECURITY FIX: Never trust client-provided tier - validate from API key
1147
- // Previous: const userTier = sanitizeString(args?.tier, 20) || ...
1148
- // This allowed privilege escalation via args.tier = "pro"
1072
+ // ================================================================
1073
+ // PRODUCTION HARDENING: Integrated validation, rate limiting, timeout
1074
+ // ================================================================
1075
+
1076
+ // 1. Get user tier from API key (never trust client-provided tier)
1149
1077
  const { getMcpToolAccess } = await import('./tier-auth.js');
1150
- const access = await getMcpToolAccess(toolName, apiKey);
1078
+ const access = await getMcpToolAccess(toolName, apiKey, args);
1151
1079
  const userTier = access.tier || 'free';
1152
- const result = await handleToolV3(toolName, args, { tier: userTier });
1153
1080
 
1154
- if (result.error) {
1155
- return this.error(result.error, { tier: result.tier, required: result.required });
1081
+ // 2. Check per-user rate limit
1082
+ const userId = apiKey ? hashKeyForRateLimit(apiKey) : '__anonymous__';
1083
+ const rateCheck = rateLimiter.check(userId, userTier);
1084
+ if (!rateCheck.allowed) {
1085
+ const errorEnvelope = createErrorEnvelope(
1086
+ 'RATE_LIMITED',
1087
+ `Rate limit exceeded. Try again in ${rateCheck.retryAfter} seconds`,
1088
+ { retryAfter: rateCheck.retryAfter, limit: rateCheck.limit }
1089
+ );
1090
+ return this.error(errorEnvelope.error.message, {
1091
+ code: errorEnvelope.error.code,
1092
+ retryAfter: rateCheck.retryAfter,
1093
+ });
1156
1094
  }
1157
1095
 
1158
- // Sanitize and truncate output
1159
- const outputText = truncateOutput(redactSensitive(JSON.stringify(result, null, 2)));
1160
- return {
1161
- content: [{ type: "text", text: outputText }],
1162
- };
1096
+ // 3. Validate input schema
1097
+ const validation = validateToolInput(toolName, args);
1098
+ if (!validation.valid) {
1099
+ const errorEnvelope = createErrorEnvelope(
1100
+ 'VALIDATION_ERROR',
1101
+ 'Invalid tool input',
1102
+ { errors: validation.errors }
1103
+ );
1104
+ return this.error(errorEnvelope.error.message, {
1105
+ code: errorEnvelope.error.code,
1106
+ errors: validation.errors,
1107
+ });
1108
+ }
1109
+
1110
+ // 4. Check tier access (already done above, but ensure it's checked)
1111
+ if (!access.hasAccess) {
1112
+ return this.error(access.error?.message || 'Access denied', {
1113
+ code: access.error?.code || 'TIER_REQUIRED',
1114
+ tier: access.tier,
1115
+ required: access.error?.required,
1116
+ });
1117
+ }
1118
+
1119
+ // 5. Execute with timeout and cancellation support
1120
+ const timeout = getToolTimeout(toolName);
1121
+ const controller = new AbortController();
1122
+
1123
+ // Register job for cancellation (if needed)
1124
+ const jobId = `${toolName}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
1125
+ if (typeof global !== 'undefined') {
1126
+ if (!global.activeJobs) global.activeJobs = new Map();
1127
+ global.activeJobs.set(jobId, controller);
1128
+ }
1129
+
1130
+ try {
1131
+ const result = await executeWithEnvelope(
1132
+ toolName,
1133
+ async (signal) => {
1134
+ return await handleToolV3(toolName, args, {
1135
+ tier: userTier,
1136
+ signal, // Pass abort signal to tool handler
1137
+ });
1138
+ },
1139
+ { timeout }
1140
+ );
1141
+
1142
+ // Cleanup job registration
1143
+ if (typeof global !== 'undefined' && global.activeJobs) {
1144
+ global.activeJobs.delete(jobId);
1145
+ }
1146
+
1147
+ // 6. Validate output schema (warn on mismatch, don't fail)
1148
+ const outputValidation = validateToolOutput(toolName, result.data || result);
1149
+ if (!outputValidation.valid) {
1150
+ console.warn(`[MCP] Tool ${toolName} output validation warnings:`, outputValidation.errors);
1151
+ }
1152
+
1153
+ // 7. Return sanitized output
1154
+ const outputText = truncateOutput(redactSensitive(JSON.stringify(result, null, 2)));
1155
+ return {
1156
+ content: [{ type: "text", text: outputText }],
1157
+ };
1158
+ } catch (error) {
1159
+ // Cleanup on error
1160
+ if (typeof global !== 'undefined' && global.activeJobs) {
1161
+ global.activeJobs.delete(jobId);
1162
+ }
1163
+ throw error;
1164
+ }
1163
1165
  }
1164
1166
 
1165
1167
  // 1. Check tool registry first (local CLI handlers)
@@ -1284,12 +1286,6 @@ class VibecheckMCP {
1284
1286
  // Resources
1285
1287
  this.server.setRequestHandler(ListResourcesRequestSchema, async () => ({
1286
1288
  resources: [
1287
- {
1288
- uri: "vibecheck://status",
1289
- name: "Server Status",
1290
- description: "Current MCP server health, version, and rate limits",
1291
- mimeType: "application/json",
1292
- },
1293
1289
  {
1294
1290
  uri: "vibecheck://config",
1295
1291
  name: "vibecheck Config",
@@ -1338,12 +1334,6 @@ class VibecheckMCP {
1338
1334
  description: "Last prove loop results (ctx → reality → ship → fix)",
1339
1335
  mimeType: "application/json",
1340
1336
  },
1341
- {
1342
- uri: "vibecheck://registry",
1343
- name: "Command Registry",
1344
- description: "Available commands and their tiers",
1345
- mimeType: "application/json",
1346
- },
1347
1337
  ],
1348
1338
  }));
1349
1339
 
@@ -1490,82 +1480,6 @@ class VibecheckMCP {
1490
1480
  return await safeReadResource(provePath, "No prove results. Run vibecheck.prove first.");
1491
1481
  }
1492
1482
 
1493
- // Server status resource - live health check
1494
- if (uri === "vibecheck://status") {
1495
- const rateCheck = checkRateLimit(null);
1496
- const circuitCheck = checkCircuitBreaker();
1497
-
1498
- const status = {
1499
- server: {
1500
- version: CONFIG.VERSION,
1501
- uptime: Math.floor(process.uptime()),
1502
- transport: 'stdio',
1503
- nodeVersion: process.version,
1504
- },
1505
- health: {
1506
- status: circuitCheck.allowed ? 'healthy' : 'degraded',
1507
- circuitBreaker: circuitBreakerState.state,
1508
- failureCount: circuitBreakerState.failures,
1509
- },
1510
- rateLimit: {
1511
- remaining: rateCheck.remaining,
1512
- resetIn: rateCheck.resetIn || 0,
1513
- limit: CONFIG.LIMITS.RATE_LIMIT_MAX_CALLS,
1514
- window: CONFIG.LIMITS.RATE_LIMIT_WINDOW_MS,
1515
- },
1516
- features: {
1517
- hardening: true,
1518
- auditLogging: true,
1519
- secretRedaction: true,
1520
- pathSecurity: true,
1521
- },
1522
- timestamp: new Date().toISOString(),
1523
- };
1524
-
1525
- return {
1526
- contents: [{ uri, mimeType: "application/json", text: JSON.stringify(status, null, 2) }],
1527
- };
1528
- }
1529
-
1530
- // Registry resource - available commands and tiers
1531
- if (uri === "vibecheck://registry") {
1532
- const registry = {
1533
- version: CONFIG.VERSION,
1534
- tiers: {
1535
- free: {
1536
- name: 'FREE',
1537
- price: '$0',
1538
- description: 'Inspect & Observe',
1539
- },
1540
- pro: {
1541
- name: 'PRO',
1542
- price: '$69/mo',
1543
- description: 'Fix, Prove & Enforce',
1544
- },
1545
- },
1546
- tools: Object.entries(V3_TOOL_TIERS).map(([name, tier]) => ({
1547
- name,
1548
- tier,
1549
- })),
1550
- resources: [
1551
- 'vibecheck://status',
1552
- 'vibecheck://config',
1553
- 'vibecheck://summary',
1554
- 'vibecheck://truthpack',
1555
- 'vibecheck://missions',
1556
- 'vibecheck://reality',
1557
- 'vibecheck://findings',
1558
- 'vibecheck://share',
1559
- 'vibecheck://prove',
1560
- 'vibecheck://registry',
1561
- ],
1562
- };
1563
-
1564
- return {
1565
- contents: [{ uri, mimeType: "application/json", text: JSON.stringify(registry, null, 2) }],
1566
- };
1567
- }
1568
-
1569
1483
  return {
1570
1484
  contents: [{
1571
1485
  uri,
@@ -1842,16 +1756,24 @@ class VibecheckMCP {
1842
1756
  }
1843
1757
 
1844
1758
  // ============================================================================
1845
- // GATE
1759
+ // GATE - PRO tier required (CI/CD enforcement)
1846
1760
  // ============================================================================
1847
1761
  async handleGate(projectPath, args) {
1848
- // Check tier access (STARTER tier required)
1849
- const access = await getFeatureAccessStatus("gate", args?.apiKey);
1762
+ // Check tier access (PRO tier required - aligned with CLI entitlements-v2.js)
1763
+ const access = await getFeatureAccessStatus("vibecheck.gate", args?.apiKey, args);
1850
1764
  if (!access.hasAccess) {
1851
1765
  return {
1852
1766
  content: [{
1853
1767
  type: "text",
1854
- text: `🚫 UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}`
1768
+ text: JSON.stringify({
1769
+ ok: false,
1770
+ error: access.error || {
1771
+ code: 'NOT_ENTITLED',
1772
+ message: 'Requires PRO',
1773
+ userAction: 'Open billing',
1774
+ retryable: false,
1775
+ },
1776
+ }, null, 2)
1855
1777
  }],
1856
1778
  isError: true
1857
1779
  };
@@ -1881,21 +1803,27 @@ class VibecheckMCP {
1881
1803
  }
1882
1804
 
1883
1805
  // ============================================================================
1884
- // FIX MISSIONS v1
1806
+ // FIX MISSIONS v1 - PRO tier required (aligned with CLI entitlements-v2.js)
1885
1807
  // ============================================================================
1886
1808
  async handleFix(projectPath, args) {
1887
- // Check tier access for --apply and --autopilot (PRO tier required)
1888
- if (args?.apply || args?.autopilot) {
1889
- const access = await getFeatureAccessStatus("fix.apply_patches", args?.apiKey);
1890
- if (!access.hasAccess) {
1891
- return {
1892
- content: [{
1893
- type: "text",
1894
- text: `🚫 UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}\n\nNote: --prompt-only mode is available for FREE tier.`
1895
- }],
1896
- isError: true
1897
- };
1898
- }
1809
+ // Check tier access - vibecheck.fix is PRO (all modes: plan, apply, autopilot)
1810
+ const access = await getFeatureAccessStatus("vibecheck.fix", args?.apiKey, args);
1811
+ if (!access.hasAccess) {
1812
+ return {
1813
+ content: [{
1814
+ type: "text",
1815
+ text: JSON.stringify({
1816
+ ok: false,
1817
+ error: access.error || {
1818
+ code: 'NOT_ENTITLED',
1819
+ message: 'Requires PRO',
1820
+ userAction: 'Open billing',
1821
+ retryable: false,
1822
+ },
1823
+ }, null, 2)
1824
+ }],
1825
+ isError: true
1826
+ };
1899
1827
  }
1900
1828
 
1901
1829
  const mode = args?.autopilot ? "Autopilot" :
@@ -2057,16 +1985,24 @@ class VibecheckMCP {
2057
1985
  }
2058
1986
 
2059
1987
  // ============================================================================
2060
- // PROVE - One Command Reality Proof
1988
+ // PROVE - One Command Reality Proof (PRO tier required)
2061
1989
  // ============================================================================
2062
1990
  async handleProve(projectPath, args) {
2063
- // Check tier access (PRO tier required)
2064
- const access = await getFeatureAccessStatus("prove", args?.apiKey);
1991
+ // Check tier access (PRO tier required - aligned with CLI entitlements-v2.js)
1992
+ const access = await getFeatureAccessStatus("vibecheck.prove", args?.apiKey, args);
2065
1993
  if (!access.hasAccess) {
2066
1994
  return {
2067
1995
  content: [{
2068
1996
  type: "text",
2069
- text: `🚫 UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}`
1997
+ text: JSON.stringify({
1998
+ ok: false,
1999
+ error: access.error || {
2000
+ code: 'NOT_ENTITLED',
2001
+ message: 'Requires PRO',
2002
+ userAction: 'Open billing',
2003
+ retryable: false,
2004
+ },
2005
+ }, null, 2)
2070
2006
  }],
2071
2007
  isError: true
2072
2008
  };
@@ -2261,9 +2197,29 @@ class VibecheckMCP {
2261
2197
  }
2262
2198
 
2263
2199
  // ============================================================================
2264
- // SHIP - Quick health check
2200
+ // SHIP - Verdict engine (PRO tier required - aligned with CLI entitlements-v2.js)
2265
2201
  // ============================================================================
2266
2202
  async handleShip(projectPath, args) {
2203
+ // Check tier access (PRO tier required)
2204
+ const access = await getFeatureAccessStatus("vibecheck.ship", args?.apiKey, args);
2205
+ if (!access.hasAccess) {
2206
+ return {
2207
+ content: [{
2208
+ type: "text",
2209
+ text: JSON.stringify({
2210
+ ok: false,
2211
+ error: access.error || {
2212
+ code: 'NOT_ENTITLED',
2213
+ message: 'Requires PRO',
2214
+ userAction: 'Open billing',
2215
+ retryable: false,
2216
+ },
2217
+ }, null, 2)
2218
+ }],
2219
+ isError: true
2220
+ };
2221
+ }
2222
+
2267
2223
  // HARDENING: Validate project path
2268
2224
  const validation = this.validateProjectPath(projectPath);
2269
2225
  if (!validation.valid) {
@@ -2588,16 +2544,24 @@ class VibecheckMCP {
2588
2544
  }
2589
2545
 
2590
2546
  // ============================================================================
2591
- // AUTOPILOT PLAN - Generate fix plan (PRO tier)
2547
+ // AUTOPILOT PLAN - Generate fix plan (PRO tier required)
2592
2548
  // ============================================================================
2593
2549
  async handleAutopilotPlan(projectPath, args) {
2594
- // Check tier access (PRO tier required)
2595
- const access = await getFeatureAccessStatus("fix.apply_patches", args?.apiKey);
2550
+ // Check tier access (PRO tier required - aligned with CLI entitlements-v2.js)
2551
+ const access = await getFeatureAccessStatus("vibecheck.fix", args?.apiKey, args);
2596
2552
  if (!access.hasAccess) {
2597
2553
  return {
2598
2554
  content: [{
2599
2555
  type: "text",
2600
- text: `🚫 UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}`
2556
+ text: JSON.stringify({
2557
+ ok: false,
2558
+ error: access.error || {
2559
+ code: 'NOT_ENTITLED',
2560
+ message: 'Requires PRO',
2561
+ userAction: 'Open billing',
2562
+ retryable: false,
2563
+ },
2564
+ }, null, 2)
2601
2565
  }],
2602
2566
  isError: true
2603
2567
  };
@@ -2675,11 +2639,11 @@ class VibecheckMCP {
2675
2639
  }
2676
2640
 
2677
2641
  // ============================================================================
2678
- // AUTOPILOT APPLY - Apply fixes (PRO tier)
2642
+ // AUTOPILOT APPLY - Apply fixes (PRO tier required)
2679
2643
  // ============================================================================
2680
2644
  async handleAutopilotApply(projectPath, args) {
2681
- // Check tier access (PRO tier required)
2682
- const access = await getFeatureAccessStatus("fix.apply_patches", args?.apiKey);
2645
+ // Check tier access (PRO tier required - aligned with CLI entitlements-v2.js)
2646
+ const access = await getFeatureAccessStatus("vibecheck.fix", args?.apiKey, args);
2683
2647
  if (!access.hasAccess) {
2684
2648
  return {
2685
2649
  content: [{
@@ -2736,16 +2700,24 @@ class VibecheckMCP {
2736
2700
  }
2737
2701
 
2738
2702
  // ============================================================================
2739
- // BADGE - Generate ship badge
2703
+ // BADGE - Generate ship badge (PRO tier required)
2740
2704
  // ============================================================================
2741
2705
  async handleBadge(projectPath, args) {
2742
- // Check tier access (STARTER tier required)
2743
- const access = await getFeatureAccessStatus("badge", args?.apiKey);
2706
+ // Check tier access (PRO tier required - aligned with CLI entitlements-v2.js)
2707
+ const access = await getFeatureAccessStatus("vibecheck.badge", args?.apiKey, args);
2744
2708
  if (!access.hasAccess) {
2745
2709
  return {
2746
2710
  content: [{
2747
2711
  type: "text",
2748
- text: `🚫 UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}`
2712
+ text: JSON.stringify({
2713
+ ok: false,
2714
+ error: access.error || {
2715
+ code: 'NOT_ENTITLED',
2716
+ message: 'Requires PRO',
2717
+ userAction: 'Open billing',
2718
+ retryable: false,
2719
+ },
2720
+ }, null, 2)
2749
2721
  }],
2750
2722
  isError: true
2751
2723
  };