@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
@@ -2,8 +2,8 @@
2
2
  * VibeCheck Entitlements
3
3
  *
4
4
  * Simple 2-tier model:
5
- * - FREE ($0): Inspect & Observe - No API key required
6
- * - PRO ($69/mo): Fix, Prove & Enforce - Requires API key
5
+ * - FREE ($0): Inspect & Observe
6
+ * - PRO ($69/mo): Fix, Prove & Enforce
7
7
  */
8
8
 
9
9
  "use strict";
@@ -17,7 +17,6 @@ const os = require("os");
17
17
  // ============================================================================
18
18
  const EXIT_SUCCESS = 0;
19
19
  const EXIT_FEATURE_NOT_ALLOWED = 3;
20
- const EXIT_AUTH_REQUIRED = 4;
21
20
 
22
21
  // ============================================================================
23
22
  // TIERS
@@ -34,7 +33,7 @@ const FREE_FEATURES = [
34
33
  // Setup & environment
35
34
  "init", "doctor", "install", "status", "watch", "preflight",
36
35
  // Scan & analysis
37
- "scan", "runtime", "vibe",
36
+ "scan", "runtime",
38
37
  // AI verification
39
38
  "ctx", "contracts", "verify",
40
39
  // Reports
@@ -44,37 +43,53 @@ const FREE_FEATURES = [
44
43
  // Preview modes
45
44
  "reality.preview", "firewall.observe",
46
45
  // Misc
47
- "labs", "mdc", "help", "version",
46
+ "labs", "mdc",
48
47
  ];
49
48
 
50
49
  const PRO_FEATURES = [
51
50
  // CI/CD & PR
52
51
  "gate", "pr", "badge", "ship",
53
52
  // Fixes
54
- "fix", "fix.apply", "scan.autofix",
53
+ "fix", "fix.apply", "fix.analyze", "fix.diff", "fix.rules", "scan.autofix",
55
54
  // Prove & verify
56
55
  "prove", "replay", "permissions", "graph", "ai-test", "share",
57
56
  // Advanced
58
57
  "checkpoint", "polish", "guard", "context",
59
58
  // Full modes
60
59
  "firewall.enforce", "reality.full", "mcp.full",
61
- // All FREE features included
60
+ // All FREE features
62
61
  ...FREE_FEATURES,
63
62
  ];
64
63
 
65
- function isPro(tier) {
66
- return tier === "pro";
67
- }
68
-
69
- function isFreeFeature(feature) {
70
- return FREE_FEATURES.includes(feature);
64
+ /**
65
+ * Check if developer mode bypass is allowed.
66
+ *
67
+ * SECURITY: VIBECHECK_DEV_PRO is ONLY allowed in non-production environments.
68
+ * This prevents environment variable injection from granting PRO access in production.
69
+ *
70
+ * @returns {boolean} True only if in development AND VIBECHECK_DEV_PRO=1
71
+ */
72
+ function isDevProBypassAllowed() {
73
+ // SECURITY: Never allow dev bypass in production
74
+ if (process.env.NODE_ENV === "production") {
75
+ return false;
76
+ }
77
+ // Also block in CI environments to prevent pipeline exploitation
78
+ if (process.env.CI === "true" || process.env.CI === "1") {
79
+ return false;
80
+ }
81
+ return process.env.VIBECHECK_DEV_PRO === "1";
71
82
  }
72
83
 
73
- function isProFeature(feature) {
74
- return !FREE_FEATURES.includes(feature);
84
+ function isPro(tier) {
85
+ // Developer mode bypass (blocked in production)
86
+ if (isDevProBypassAllowed()) return true;
87
+ return tier === "pro";
75
88
  }
76
89
 
77
90
  function tierHasFeature(tier, feature) {
91
+ // Developer mode bypass - grant all features (blocked in production)
92
+ if (isDevProBypassAllowed()) return true;
78
93
  if (tier === "pro") return true; // PRO has everything
79
94
  return FREE_FEATURES.includes(feature);
80
95
  }
@@ -90,6 +105,14 @@ let _cachedTierExpiry = 0;
90
105
  async function getTier(options = {}) {
91
106
  const { apiKey, forceRefresh = false } = options;
92
107
 
108
+ // Developer mode: VIBECHECK_DEV_PRO=1 grants pro tier for local development
109
+ // SECURITY: This bypass is blocked in production environments
110
+ if (isDevProBypassAllowed()) {
111
+ _cachedTier = "pro";
112
+ _cachedTierExpiry = Date.now() + 86400000; // 24 hours
113
+ return "pro";
114
+ }
115
+
93
116
  if (!forceRefresh && _cachedTier && Date.now() < _cachedTierExpiry) {
94
117
  return _cachedTier;
95
118
  }
@@ -127,36 +150,14 @@ async function getTier(options = {}) {
127
150
  // ============================================================================
128
151
  async function enforce(feature, options = {}) {
129
152
  const { apiKey, silent = false } = options;
130
-
131
- // FREE features work without any API key
132
- if (isFreeFeature(feature)) {
133
- return { allowed: true, tier: apiKey ? await getTier({ apiKey }) : "free" };
134
- }
135
-
136
- // PRO features require an API key
137
- if (!apiKey) {
138
- const message = formatApiKeyRequiredMessage(feature);
139
- if (!silent) {
140
- console.error(message);
141
- }
142
- return {
143
- allowed: false,
144
- tier: "free",
145
- exitCode: EXIT_AUTH_REQUIRED,
146
- message,
147
- reason: "api_key_required",
148
- };
149
- }
150
-
151
- // Validate API key and check tier
152
153
  const tier = await getTier({ apiKey });
154
+
153
155
  const hasAccess = tierHasFeature(tier, feature);
154
156
 
155
157
  if (hasAccess) {
156
158
  return { allowed: true, tier };
157
159
  }
158
160
 
159
- // User has API key but not on Pro plan
160
161
  const message = formatUpgradeMessage(feature);
161
162
  if (!silent) {
162
163
  console.error(message);
@@ -167,7 +168,6 @@ async function enforce(feature, options = {}) {
167
168
  tier,
168
169
  exitCode: EXIT_FEATURE_NOT_ALLOWED,
169
170
  message,
170
- reason: "upgrade_required",
171
171
  };
172
172
  }
173
173
 
@@ -189,72 +189,54 @@ async function checkCommand(command, options = {}) {
189
189
  const c = {
190
190
  reset: "\x1b[0m",
191
191
  bold: "\x1b[1m",
192
- dim: "\x1b[2m",
193
192
  cyan: "\x1b[36m",
194
193
  yellow: "\x1b[33m",
195
- magenta: "\x1b[35m",
196
- green: "\x1b[32m",
197
194
  };
198
195
 
199
- function formatApiKeyRequiredMessage(feature) {
200
- return `
201
- ${c.bold}${c.magenta}✦ PRO Feature${c.reset}
202
-
203
- ${c.yellow}${feature}${c.reset} requires an API key.
204
-
205
- ${c.dim}To use PRO features:${c.reset}
206
-
207
- ${c.cyan}1.${c.reset} Sign up at ${c.cyan}https://vibecheckai.dev${c.reset}
208
- ${c.cyan}2.${c.reset} Run ${c.green}vibecheck login${c.reset}
209
- ${c.cyan}3.${c.reset} Or set ${c.green}VIBECHECK_API_KEY${c.reset} environment variable
210
-
211
- ${c.dim}FREE features (scan, init, doctor, etc.) work without an API key.${c.reset}
212
- `;
213
- }
214
-
215
196
  function formatUpgradeMessage(feature) {
216
197
  return `
217
- ${c.bold}${c.magenta}✦ Upgrade Required${c.reset}
218
-
219
- ${c.yellow}${feature}${c.reset} requires a Pro subscription.
198
+ ${c.bold}This feature requires Pro.${c.reset}
220
199
 
221
- You're currently on the ${c.cyan}FREE${c.reset} plan.
200
+ ${c.yellow}${feature}${c.reset} is a Pro feature.
222
201
 
223
- ${c.bold}Pro ($69/mo)${c.reset} includes:
224
- ${c.green}✓${c.reset} AI-powered fixes
225
- ${c.green}✓${c.reset} Ship verdicts & badges
226
- ${c.green}✓${c.reset} Runtime proof generation
227
- ${c.green}✓${c.reset} CI/CD enforcement
228
- ${c.green}✓${c.reset} Full MCP integration
202
+ Upgrade to Pro ($69/mo) to unlock Fix, Prove & Enforce capabilities.
229
203
 
230
- ${c.cyan}vibecheck upgrade${c.reset}
231
- ${c.dim}https://vibecheckai.dev/pricing${c.reset}
204
+ vibecheck upgrade
205
+ https://vibecheckai.dev/pricing
232
206
  `;
233
207
  }
234
208
 
235
209
  // ============================================================================
236
- // BACKWARD COMPATIBILITY ALIASES (for migration from entitlements.js)
210
+ // TIER LIMITS
237
211
  // ============================================================================
212
+ const TIER_LIMITS = {
213
+ free: {
214
+ reportFormats: ["html", "md", "json"],
215
+ maxScansPerMonth: 100,
216
+ maxFilesPerScan: 1000,
217
+ },
218
+ pro: {
219
+ reportFormats: ["html", "md", "json", "sarif", "csv", "pdf"],
220
+ maxScansPerMonth: -1, // unlimited
221
+ maxFilesPerScan: -1, // unlimited
222
+ },
223
+ };
238
224
 
239
- /** @deprecated Use getTier() instead */
240
- async function getCurrentTier() {
241
- return getTier();
242
- }
243
-
244
- /** @deprecated Use enforce() instead */
245
- async function enforceFeature(feature, options = {}) {
246
- return enforce(feature, options);
247
- }
248
-
249
- /** @deprecated Use enforce() instead */
250
- async function enforceLimit(feature, options = {}) {
251
- return enforce(feature, options);
225
+ /**
226
+ * Get limits for a tier
227
+ */
228
+ function getLimits(tier) {
229
+ return TIER_LIMITS[tier] || TIER_LIMITS.free;
252
230
  }
253
231
 
254
- /** @deprecated No-op for compatibility - usage tracking removed */
255
- async function trackUsage(/* feature, amount = 1 */) {
256
- // No-op - usage tracking handled by API
257
- return;
232
+ /**
233
+ * Check if current tier meets minimum required tier
234
+ */
235
+ function tierMeetsMinimum(current, required) {
236
+ const tierOrder = ['free', 'pro'];
237
+ const currentIndex = tierOrder.indexOf(current);
238
+ const requiredIndex = tierOrder.indexOf(required);
239
+ return currentIndex >= requiredIndex;
258
240
  }
259
241
 
260
242
  // ============================================================================
@@ -269,21 +251,15 @@ module.exports = {
269
251
 
270
252
  // Helpers
271
253
  isPro,
272
- isFreeFeature,
273
- isProFeature,
274
254
  tierHasFeature,
255
+ getLimits,
256
+ tierMeetsMinimum,
275
257
 
276
258
  // Constants
277
259
  TIERS,
260
+ TIER_LIMITS,
278
261
  FREE_FEATURES,
279
262
  PRO_FEATURES,
280
263
  EXIT_SUCCESS,
281
264
  EXIT_FEATURE_NOT_ALLOWED,
282
- EXIT_AUTH_REQUIRED,
283
-
284
- // Backward compatibility (deprecated)
285
- getCurrentTier,
286
- enforceFeature,
287
- enforceLimit,
288
- trackUsage,
289
265
  };
@@ -160,8 +160,26 @@ function handleError(error, context = "", metadata = {}) {
160
160
  // Get specific guidance
161
161
  const guidance = getErrorGuidance(err);
162
162
 
163
+ // Check for JSON mode (via NO_COLOR env var or explicit check)
164
+ const isJsonMode = process.env.NO_COLOR === '1' || process.env.VIBECHECK_JSON === '1';
165
+
163
166
  // Print error header
164
167
  if (guidance) {
168
+ if (isJsonMode) {
169
+ // JSON error output
170
+ const errorOutput = {
171
+ success: false,
172
+ error: {
173
+ code: err.code || err.name || 'ERROR',
174
+ message: message,
175
+ type: guidance.title,
176
+ nextSteps: guidance.nextSteps,
177
+ },
178
+ exitCode: err.exitCode || 1
179
+ };
180
+ console.error(JSON.stringify(errorOutput, null, 2));
181
+ return;
182
+ }
165
183
  console.error(`\n${c.error("✗")} ${c.error(guidance.title)}`);
166
184
  console.error(` ${message}`);
167
185
 
@@ -171,8 +189,20 @@ function handleError(error, context = "", metadata = {}) {
171
189
  console.error(` ${c.dim("•")} ${step}`);
172
190
  }
173
191
  } else {
192
+ // Check for JSON mode
193
+ const isJsonMode = process.env.NO_COLOR === '1' || process.env.VIBECHECK_JSON === '1';
194
+
174
195
  // Generic error handling with specific type detection
175
196
  if (err.code === "ENOENT") {
197
+ if (isJsonMode) {
198
+ const errorOutput = {
199
+ success: false,
200
+ error: { code: 'ENOENT', message: err.path || message, receipt },
201
+ exitCode: 4
202
+ };
203
+ console.error(JSON.stringify(errorOutput, null, 2));
204
+ return;
205
+ }
176
206
  console.error(`\n${c.error("✗")} File or directory not found`);
177
207
  console.error(` ${err.path || message}`);
178
208
  // Print receipt if available
@@ -213,6 +243,15 @@ function handleError(error, context = "", metadata = {}) {
213
243
  console.error(` ${c.dim("•")} Verify VIBECHECK_API_URL is correct`);
214
244
  } else {
215
245
  // Generic error
246
+ if (isJsonMode) {
247
+ const errorOutput = {
248
+ success: false,
249
+ error: { code: err.code || err.name || 'ERROR', message, receipt },
250
+ exitCode: err.exitCode || 1
251
+ };
252
+ console.error(JSON.stringify(errorOutput, null, 2));
253
+ return;
254
+ }
216
255
  console.error(`\n${c.error("✗")} Error`);
217
256
  console.error(` ${message}`);
218
257
  // Print receipt if available
@@ -229,13 +268,15 @@ function handleError(error, context = "", metadata = {}) {
229
268
  }
230
269
  }
231
270
 
232
- // Show stack trace in debug mode
233
- if (process.env.DEBUG || process.env.VIBECHECK_DEBUG) {
271
+ // Show stack trace in debug mode (skip in JSON mode)
272
+ if (!isJsonMode && (process.env.DEBUG || process.env.VIBECHECK_DEBUG)) {
234
273
  console.error(`\n${c.dim("Stack trace:")}`);
235
274
  console.error(c.dim(err.stack));
236
275
  }
237
276
 
238
- console.error(""); // Empty line for readability
277
+ if (!isJsonMode) {
278
+ console.error(""); // Empty line for readability
279
+ }
239
280
  }
240
281
 
241
282
  /**
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Actionable Error Messages
3
+ *
4
+ * Provides standardized error messages with actionable next steps,
5
+ * documentation links, and clear guidance for users.
6
+ */
7
+
8
+ const { EXIT } = require('./exit-codes');
9
+
10
+ const DOCS_BASE_URL = 'https://docs.vibecheckai.dev';
11
+ const DASHBOARD_URL = 'https://app.vibecheckai.dev';
12
+
13
+ /**
14
+ * Format an actionable error message
15
+ */
16
+ function formatError(error, context = {}) {
17
+ const {
18
+ command = '',
19
+ suggestion = null,
20
+ docsLink = null,
21
+ nextSteps = [],
22
+ code = null,
23
+ } = context;
24
+
25
+ const lines = [];
26
+
27
+ // Main error message
28
+ lines.push(`\n ❌ ${error.message || error}`);
29
+
30
+ // Error code if provided
31
+ if (code) {
32
+ lines.push(`\n Code: ${code}`);
33
+ }
34
+
35
+ // Next steps
36
+ if (nextSteps.length > 0) {
37
+ lines.push(`\n Next steps:`);
38
+ nextSteps.forEach((step, i) => {
39
+ lines.push(` ${i + 1}. ${step}`);
40
+ });
41
+ } else if (suggestion) {
42
+ lines.push(`\n 💡 ${suggestion}`);
43
+ }
44
+
45
+ // Documentation link
46
+ if (docsLink) {
47
+ lines.push(`\n 📖 Docs: ${docsLink}`);
48
+ } else if (command) {
49
+ lines.push(`\n 📖 Docs: ${DOCS_BASE_URL}/commands/${command}`);
50
+ }
51
+
52
+ lines.push('');
53
+
54
+ return lines.join('\n');
55
+ }
56
+
57
+ /**
58
+ * Common error templates with actionable guidance
59
+ */
60
+ const ERROR_TEMPLATES = {
61
+ PROJECT_NOT_INITIALIZED: {
62
+ message: 'Project not initialized',
63
+ suggestion: 'Run `vibecheck init` to set up your project',
64
+ nextSteps: [
65
+ 'Run: vibecheck init',
66
+ 'This creates .vibecheckrc config file',
67
+ 'Then run: vibecheck scan',
68
+ ],
69
+ docsLink: `${DOCS_BASE_URL}/getting-started/init`,
70
+ },
71
+
72
+ NO_SCAN_RESULTS: {
73
+ message: 'No scan results found',
74
+ suggestion: 'Run `vibecheck scan` first to generate results',
75
+ nextSteps: [
76
+ 'Run: vibecheck scan',
77
+ 'This analyzes your codebase',
78
+ 'Then re-run this command',
79
+ ],
80
+ docsLink: `${DOCS_BASE_URL}/commands/scan`,
81
+ },
82
+
83
+ NO_TRUTHPACK: {
84
+ message: 'No truthpack found',
85
+ suggestion: 'Run `vibecheck context` to generate truthpack',
86
+ nextSteps: [
87
+ 'Run: vibecheck context',
88
+ 'This generates route/auth/env mapping',
89
+ 'Then re-run this command',
90
+ ],
91
+ docsLink: `${DOCS_BASE_URL}/commands/context`,
92
+ },
93
+
94
+ AUTH_REQUIRED: {
95
+ message: 'Authentication required',
96
+ suggestion: 'Run `vibecheck login` to authenticate',
97
+ nextSteps: [
98
+ 'Run: vibecheck login',
99
+ 'Enter your API key',
100
+ 'Get your key from: https://app.vibecheckai.dev/settings/api-keys',
101
+ ],
102
+ docsLink: `${DOCS_BASE_URL}/getting-started/authentication`,
103
+ },
104
+
105
+ INVALID_API_KEY: {
106
+ message: 'Invalid API key format',
107
+ suggestion: 'Check your API key format',
108
+ nextSteps: [
109
+ 'API keys should start with vc_',
110
+ 'Get a new key: https://app.vibecheckai.dev/settings/api-keys',
111
+ 'Run: vibecheck login --key YOUR_KEY',
112
+ ],
113
+ docsLink: `${DOCS_BASE_URL}/getting-started/authentication`,
114
+ },
115
+
116
+ TIER_REQUIRED: {
117
+ message: 'This feature requires PRO tier',
118
+ suggestion: 'Upgrade to PRO to access this feature',
119
+ nextSteps: [
120
+ 'Visit: https://app.vibecheckai.dev/pricing',
121
+ 'Upgrade your account',
122
+ 'Re-run this command',
123
+ ],
124
+ docsLink: `${DOCS_BASE_URL}/pricing`,
125
+ },
126
+
127
+ PROJECT_PATH_NOT_FOUND: {
128
+ message: 'Project path does not exist',
129
+ suggestion: 'Check the path and try again',
130
+ nextSteps: [
131
+ 'Verify the path exists: ls <path>',
132
+ 'Use absolute path if relative path fails',
133
+ 'Run: vibecheck init --path <path>',
134
+ ],
135
+ docsLink: `${DOCS_BASE_URL}/commands/init`,
136
+ },
137
+
138
+ CONFIG_INVALID: {
139
+ message: 'Invalid configuration file',
140
+ suggestion: 'Run `vibecheck doctor --fix` to repair config',
141
+ nextSteps: [
142
+ 'Run: vibecheck doctor --fix',
143
+ 'This auto-fixes common config issues',
144
+ 'Or manually edit .vibecheckrc',
145
+ ],
146
+ docsLink: `${DOCS_BASE_URL}/configuration`,
147
+ },
148
+
149
+ NETWORK_ERROR: {
150
+ message: 'Network connection failed',
151
+ suggestion: 'Check your internet connection or use --offline mode',
152
+ nextSteps: [
153
+ 'Check internet connection',
154
+ 'Or run with --offline flag for local-only mode',
155
+ 'Example: vibecheck scan --offline',
156
+ ],
157
+ docsLink: `${DOCS_BASE_URL}/commands/scan#offline-mode`,
158
+ },
159
+
160
+ MISSING_DEPENDENCY: {
161
+ message: 'Missing required dependency',
162
+ suggestion: 'Install missing dependencies',
163
+ nextSteps: [
164
+ 'Run: npm install',
165
+ 'Or: pnpm install',
166
+ 'Check package.json for required packages',
167
+ ],
168
+ docsLink: `${DOCS_BASE_URL}/troubleshooting/dependencies`,
169
+ },
170
+ };
171
+
172
+ /**
173
+ * Get error template by key
174
+ */
175
+ function getErrorTemplate(key, overrides = {}) {
176
+ const template = ERROR_TEMPLATES[key];
177
+ if (!template) {
178
+ return {
179
+ message: key,
180
+ suggestion: 'Check the documentation for help',
181
+ docsLink: DOCS_BASE_URL,
182
+ };
183
+ }
184
+
185
+ return { ...template, ...overrides };
186
+ }
187
+
188
+ /**
189
+ * Print actionable error and return exit code
190
+ */
191
+ function printActionableError(errorKey, context = {}) {
192
+ const template = getErrorTemplate(errorKey, context);
193
+ const error = {
194
+ message: template.message,
195
+ code: context.code || errorKey,
196
+ };
197
+
198
+ const formatted = formatError(error, {
199
+ ...context,
200
+ suggestion: template.suggestion,
201
+ nextSteps: template.nextSteps || [],
202
+ docsLink: template.docsLink,
203
+ });
204
+
205
+ console.error(formatted);
206
+
207
+ // Map error keys to exit codes
208
+ const exitCodeMap = {
209
+ AUTH_REQUIRED: EXIT.AUTH_REQUIRED,
210
+ INVALID_API_KEY: EXIT.AUTH_FAILED,
211
+ TIER_REQUIRED: EXIT.TIER_REQUIRED,
212
+ PROJECT_PATH_NOT_FOUND: EXIT.USER_ERROR,
213
+ CONFIG_INVALID: EXIT.USER_ERROR,
214
+ NETWORK_ERROR: EXIT.NETWORK_ERROR || 1,
215
+ MISSING_DEPENDENCY: EXIT.USER_ERROR,
216
+ PROJECT_NOT_INITIALIZED: EXIT.USER_ERROR,
217
+ NO_SCAN_RESULTS: EXIT.NOT_FOUND || 1,
218
+ NO_TRUTHPACK: EXIT.NOT_FOUND || 1,
219
+ };
220
+
221
+ return exitCodeMap[errorKey] || EXIT.USER_ERROR;
222
+ }
223
+
224
+ /**
225
+ * Enhance existing error with actionable guidance
226
+ */
227
+ function enhanceError(error, command = '', additionalContext = {}) {
228
+ const errorMessage = error.message || String(error);
229
+ const lowerMessage = errorMessage.toLowerCase();
230
+
231
+ // Detect error type from message
232
+ if (lowerMessage.includes('not initialized') || lowerMessage.includes('no config')) {
233
+ return printActionableError('PROJECT_NOT_INITIALIZED', { command, ...additionalContext });
234
+ }
235
+
236
+ if (lowerMessage.includes('scan result') || lowerMessage.includes('no results')) {
237
+ return printActionableError('NO_SCAN_RESULTS', { command, ...additionalContext });
238
+ }
239
+
240
+ if (lowerMessage.includes('truthpack') || lowerMessage.includes('context')) {
241
+ return printActionableError('NO_TRUTHPACK', { command, ...additionalContext });
242
+ }
243
+
244
+ if (lowerMessage.includes('auth') && (lowerMessage.includes('required') || lowerMessage.includes('unauthorized'))) {
245
+ return printActionableError('AUTH_REQUIRED', { command, ...additionalContext });
246
+ }
247
+
248
+ if (lowerMessage.includes('api key') && (lowerMessage.includes('invalid') || lowerMessage.includes('format'))) {
249
+ return printActionableError('INVALID_API_KEY', { command, ...additionalContext });
250
+ }
251
+
252
+ if (lowerMessage.includes('tier') || lowerMessage.includes('pro') || lowerMessage.includes('upgrade')) {
253
+ return printActionableError('TIER_REQUIRED', { command, ...additionalContext });
254
+ }
255
+
256
+ if (lowerMessage.includes('path') && (lowerMessage.includes('not found') || lowerMessage.includes('does not exist'))) {
257
+ return printActionableError('PROJECT_PATH_NOT_FOUND', { command, path: additionalContext.path });
258
+ }
259
+
260
+ if (lowerMessage.includes('config') && (lowerMessage.includes('invalid') || lowerMessage.includes('error'))) {
261
+ return printActionableError('CONFIG_INVALID', { command, ...additionalContext });
262
+ }
263
+
264
+ if (lowerMessage.includes('network') || lowerMessage.includes('connection') || lowerMessage.includes('fetch')) {
265
+ return printActionableError('NETWORK_ERROR', { command, ...additionalContext });
266
+ }
267
+
268
+ if (lowerMessage.includes('cannot find module') || lowerMessage.includes('missing')) {
269
+ return printActionableError('MISSING_DEPENDENCY', { command, dependency: additionalContext.dependency });
270
+ }
271
+
272
+ // Default: print enhanced error
273
+ console.error(formatError(error, {
274
+ command,
275
+ suggestion: additionalContext.suggestion || 'Check the documentation for help',
276
+ docsLink: additionalContext.docsLink || `${DOCS_BASE_URL}/commands/${command}`,
277
+ nextSteps: additionalContext.nextSteps || [],
278
+ }));
279
+
280
+ return EXIT.USER_ERROR;
281
+ }
282
+
283
+ module.exports = {
284
+ formatError,
285
+ getErrorTemplate,
286
+ printActionableError,
287
+ enhanceError,
288
+ ERROR_TEMPLATES,
289
+ };
@@ -14,7 +14,13 @@
14
14
  const fs = require("fs");
15
15
  const path = require("path");
16
16
  const crypto = require("crypto");
17
- const archiver = require("archiver");
17
+ // Make archiver optional - only required for zip creation
18
+ let archiver;
19
+ try {
20
+ archiver = require("archiver");
21
+ } catch {
22
+ archiver = null;
23
+ }
18
24
 
19
25
  // ═══════════════════════════════════════════════════════════════════════════════
20
26
  // EVIDENCE PACK SCHEMA