@vibecheckai/cli 3.1.2 → 3.1.4

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 (47) hide show
  1. package/README.md +60 -33
  2. package/bin/registry.js +319 -34
  3. package/bin/runners/CLI_REFACTOR_SUMMARY.md +229 -0
  4. package/bin/runners/REPORT_AUDIT.md +64 -0
  5. package/bin/runners/lib/entitlements-v2.js +97 -28
  6. package/bin/runners/lib/entitlements.js +3 -6
  7. package/bin/runners/lib/init-wizard.js +1 -1
  8. package/bin/runners/lib/report-engine.js +459 -280
  9. package/bin/runners/lib/report-html.js +1154 -1423
  10. package/bin/runners/lib/report-output.js +187 -0
  11. package/bin/runners/lib/report-templates.js +848 -850
  12. package/bin/runners/lib/scan-output.js +545 -0
  13. package/bin/runners/lib/server-usage.js +0 -12
  14. package/bin/runners/lib/ship-output.js +641 -0
  15. package/bin/runners/lib/status-output.js +253 -0
  16. package/bin/runners/lib/terminal-ui.js +853 -0
  17. package/bin/runners/runCheckpoint.js +502 -0
  18. package/bin/runners/runContracts.js +105 -0
  19. package/bin/runners/runExport.js +93 -0
  20. package/bin/runners/runFix.js +31 -24
  21. package/bin/runners/runInit.js +377 -112
  22. package/bin/runners/runInstall.js +1 -5
  23. package/bin/runners/runLabs.js +3 -3
  24. package/bin/runners/runPolish.js +2452 -0
  25. package/bin/runners/runProve.js +2 -2
  26. package/bin/runners/runReport.js +251 -200
  27. package/bin/runners/runRuntime.js +110 -0
  28. package/bin/runners/runScan.js +477 -379
  29. package/bin/runners/runSecurity.js +92 -0
  30. package/bin/runners/runShip.js +137 -207
  31. package/bin/runners/runStatus.js +16 -68
  32. package/bin/runners/utils.js +5 -5
  33. package/bin/vibecheck.js +25 -11
  34. package/mcp-server/index.js +150 -18
  35. package/mcp-server/package.json +2 -2
  36. package/mcp-server/premium-tools.js +13 -13
  37. package/mcp-server/tier-auth.js +292 -27
  38. package/mcp-server/vibecheck-tools.js +9 -9
  39. package/package.json +1 -1
  40. package/bin/runners/runClaimVerifier.js +0 -483
  41. package/bin/runners/runContextCompiler.js +0 -385
  42. package/bin/runners/runGate.js +0 -17
  43. package/bin/runners/runInitGha.js +0 -164
  44. package/bin/runners/runInteractive.js +0 -388
  45. package/bin/runners/runMdc.js +0 -204
  46. package/bin/runners/runMissionGenerator.js +0 -282
  47. package/bin/runners/runTruthpack.js +0 -636
@@ -8,27 +8,144 @@ import fs from "fs/promises";
8
8
  import path from "path";
9
9
  import os from "os";
10
10
 
11
- // Tier definitions
11
+ // Tier definitions - MUST MATCH CLI entitlements-v2.js
12
12
  export const TIERS = {
13
13
  free: {
14
- name: 'Free',
15
- features: ['verify', 'quality', 'hallucination'],
16
- limits: { scans: 10, projects: 1 }
14
+ name: 'FREE',
15
+ price: 0,
16
+ order: 0,
17
+ features: [
18
+ // Core commands
19
+ 'scan', 'ship', 'ship.static',
20
+ // Setup
21
+ 'init', 'init.local', 'doctor', 'status', 'install', 'preflight', 'watch', 'watch.local',
22
+ // AI Truth
23
+ 'ctx', 'guard', 'context', 'mdc', 'contracts',
24
+ // Quality
25
+ 'verify', 'quality', 'polish', 'checkpoint', 'checkpoint.basic',
26
+ // Fix (plan only)
27
+ 'fix', 'fix.plan_only',
28
+ // Reality (preview)
29
+ 'reality', 'reality.preview',
30
+ // MCP (help only)
31
+ 'mcp.help_only',
32
+ // Report (html/md only)
33
+ 'report', 'report.html_md',
34
+ ],
35
+ limits: {
36
+ scans: 50,
37
+ shipChecks: 20,
38
+ realityMaxPages: 5,
39
+ realityMaxClicks: 20,
40
+ fixApplyPatches: false,
41
+ mcpRateLimit: 10, // requests per minute
42
+ },
43
+ // MCP tools allowed on FREE
44
+ mcpTools: ['vibecheck.status', 'vibecheck.get_truthpack'],
17
45
  },
18
46
  starter: {
19
- name: 'Starter',
20
- features: ['verify', 'quality', 'hallucination', 'smells', 'breaking'],
21
- limits: { scans: 100, projects: 3 }
47
+ name: 'STARTER',
48
+ price: 39, // Updated pricing
49
+ order: 1,
50
+ features: [
51
+ // All FREE features plus...
52
+ // Init connect
53
+ 'init.connect',
54
+ // Scan autofix
55
+ 'scan.autofix',
56
+ // CI/CD
57
+ 'gate', 'pr', 'badge', 'launch', 'dashboard_sync',
58
+ // Watch PR
59
+ 'watch.pr',
60
+ // Report formats
61
+ 'report.sarif_csv',
62
+ // Reality basic
63
+ 'reality.basic',
64
+ // MCP read-only
65
+ 'mcp', 'mcp.read_only',
66
+ // Ship full
67
+ 'ship.full',
68
+ ],
69
+ limits: {
70
+ scans: -1,
71
+ shipChecks: -1,
72
+ realityMaxPages: 50,
73
+ realityMaxClicks: 200,
74
+ fixApplyPatches: false,
75
+ mcpRateLimit: 60, // requests per minute
76
+ },
77
+ // MCP tools allowed on STARTER (read-only safe tools)
78
+ mcpTools: [
79
+ 'vibecheck.status',
80
+ 'vibecheck.get_truthpack',
81
+ 'vibecheck.scan',
82
+ 'vibecheck.list_routes',
83
+ 'vibecheck.list_env',
84
+ 'vibecheck.get_findings',
85
+ 'vibecheck.contracts_diff',
86
+ 'vibecheck.validate_claim',
87
+ 'vibecheck.compile_context',
88
+ ],
22
89
  },
23
90
  pro: {
24
- name: 'Professional',
25
- features: ['verify', 'quality', 'hallucination', 'smells', 'breaking', 'mdc'],
26
- limits: { scans: 1000, projects: 10 }
91
+ name: 'PRO',
92
+ price: 99,
93
+ order: 2,
94
+ features: [
95
+ // All STARTER features plus...
96
+ // Prove
97
+ 'prove',
98
+ // Fix apply
99
+ 'fix.apply_patches', 'fix.loop',
100
+ // Checkpoint advanced
101
+ 'checkpoint.hallucination',
102
+ // Reality advanced
103
+ 'reality.full', 'reality.advanced_auth_boundary',
104
+ // Premium
105
+ 'replay', 'share', 'ai-test', 'permissions', 'graph',
106
+ // MCP full
107
+ 'mcp.full',
108
+ ],
109
+ limits: {
110
+ scans: -1,
111
+ shipChecks: -1,
112
+ realityMaxPages: -1,
113
+ realityMaxClicks: -1,
114
+ fixApplyPatches: true,
115
+ mcpRateLimit: -1, // unlimited
116
+ },
117
+ // MCP tools allowed on PRO (full suite)
118
+ mcpTools: [
119
+ // All STARTER tools plus...
120
+ 'vibecheck.generate_mission',
121
+ 'vibecheck.verify_patch',
122
+ 'vibecheck.explain_evidence',
123
+ 'vibecheck.fix',
124
+ 'vibecheck.proof',
125
+ 'vibecheck.prove',
126
+ 'vibecheck.ship',
127
+ 'vibecheck.reality',
128
+ 'vibecheck.permissions',
129
+ 'vibecheck.graph',
130
+ ],
27
131
  },
28
- enterprise: {
29
- name: 'Enterprise',
30
- features: ['verify', 'quality', 'hallucination', 'smells', 'breaking', 'mdc'],
31
- limits: { scans: -1, projects: -1 } // unlimited
132
+ compliance: {
133
+ name: 'COMPLIANCE',
134
+ price: 0, // Enterprise/on-prem
135
+ order: 3,
136
+ features: [
137
+ // All PRO features plus...
138
+ 'report.compliance_packs',
139
+ ],
140
+ limits: {
141
+ scans: -1,
142
+ shipChecks: -1,
143
+ realityMaxPages: -1,
144
+ realityMaxClicks: -1,
145
+ fixApplyPatches: true,
146
+ mcpRateLimit: -1,
147
+ },
148
+ mcpTools: ['*'], // All tools
32
149
  }
33
150
  };
34
151
 
@@ -47,20 +164,25 @@ async function loadUserConfig() {
47
164
 
48
165
  /**
49
166
  * Determine tier from API key
167
+ * Matches CLI entitlements-v2.js logic
50
168
  */
51
169
  function getTierFromApiKey(apiKey) {
52
170
  if (!apiKey) return 'free';
53
171
 
172
+ // Check API key prefix patterns (matches CLI)
54
173
  if (apiKey.startsWith('gr_starter_')) return 'starter';
55
174
  if (apiKey.startsWith('gr_pro_')) return 'pro';
56
- if (apiKey.startsWith('gr_ent_')) return 'enterprise';
175
+ if (apiKey.startsWith('gr_compliance_') || apiKey.startsWith('gr_ent_')) return 'compliance';
57
176
  if (apiKey.startsWith('gr_free_')) return 'free';
58
177
 
178
+ // Try to fetch from API (same as CLI)
179
+ // For now, default to free - API lookup would happen in production
59
180
  return 'free'; // default for unknown keys
60
181
  }
61
182
 
62
183
  /**
63
184
  * Check if user has access to a specific feature
185
+ * Matches CLI entitlements-v2.js logic
64
186
  */
65
187
  export async function checkFeatureAccess(featureName, providedApiKey = null) {
66
188
  // Try to load user config
@@ -76,25 +198,47 @@ export async function checkFeatureAccess(featureName, providedApiKey = null) {
76
198
  };
77
199
  }
78
200
 
79
- const tier = getTierFromApiKey(apiKey);
80
- const tierConfig = TIERS[tier];
201
+ const currentTier = getTierFromApiKey(apiKey);
202
+ const currentTierConfig = TIERS[currentTier];
81
203
 
82
- if (!tierConfig.features.includes(featureName)) {
83
- const requiredTier = Object.entries(TIERS).find(([_, config]) =>
84
- config.features.includes(featureName)
85
- )?.[0];
86
-
204
+ // Find which tier has this feature
205
+ let requiredTier = null;
206
+ let requiredTierConfig = null;
207
+
208
+ for (const [tierName, tierConfig] of Object.entries(TIERS)) {
209
+ if (tierConfig.features.includes(featureName)) {
210
+ requiredTier = tierName;
211
+ requiredTierConfig = tierConfig;
212
+ break;
213
+ }
214
+ }
215
+
216
+ // If feature not found in any tier, deny access
217
+ if (!requiredTier) {
87
218
  return {
88
219
  hasAccess: false,
89
- tier,
90
- reason: `${featureName} requires ${requiredTier} tier or higher`,
220
+ tier: currentTier,
221
+ reason: `${featureName} is not available in any tier`,
222
+ upgradeUrl: 'https://vibecheckai.dev/pricing'
223
+ };
224
+ }
225
+
226
+ // Check if current tier meets minimum requirement (using order)
227
+ const hasAccess = currentTierConfig.order >= requiredTierConfig.order;
228
+
229
+ if (!hasAccess) {
230
+ return {
231
+ hasAccess: false,
232
+ tier: currentTier,
233
+ requiredTier,
234
+ reason: `${featureName} requires ${requiredTierConfig.name} tier ($${requiredTierConfig.price}/mo) or higher. Current tier: ${currentTierConfig.name}`,
91
235
  upgradeUrl: 'https://vibecheckai.dev/pricing'
92
236
  };
93
237
  }
94
238
 
95
239
  return {
96
240
  hasAccess: true,
97
- tier,
241
+ tier: currentTier,
98
242
  reason: 'Access granted'
99
243
  };
100
244
  }
@@ -122,6 +266,93 @@ export function withTierCheck(featureName, handler) {
122
266
  };
123
267
  }
124
268
 
269
+ /**
270
+ * Check if user has access to a specific MCP tool
271
+ * MCP tools have specific tier requirements separate from CLI features
272
+ */
273
+ export async function checkMcpToolAccess(toolName, providedApiKey = null) {
274
+ const userConfig = await loadUserConfig();
275
+ const apiKey = providedApiKey || userConfig?.apiKey;
276
+
277
+ const currentTier = getTierFromApiKey(apiKey);
278
+ const currentTierConfig = TIERS[currentTier];
279
+
280
+ // Check if tool is allowed for current tier
281
+ const allowedTools = [];
282
+
283
+ // Accumulate tools from current tier and all lower tiers
284
+ for (const [tierName, tierConfig] of Object.entries(TIERS)) {
285
+ if (tierConfig.order <= currentTierConfig.order) {
286
+ if (tierConfig.mcpTools) {
287
+ if (tierConfig.mcpTools.includes('*')) {
288
+ // Compliance tier - all tools allowed
289
+ return {
290
+ hasAccess: true,
291
+ tier: currentTier,
292
+ reason: 'Full MCP access'
293
+ };
294
+ }
295
+ allowedTools.push(...tierConfig.mcpTools);
296
+ }
297
+ }
298
+ }
299
+
300
+ // Check if tool is in allowed list
301
+ const hasAccess = allowedTools.includes(toolName);
302
+
303
+ if (!hasAccess) {
304
+ // Find which tier has this tool
305
+ let requiredTier = null;
306
+ for (const [tierName, tierConfig] of Object.entries(TIERS)) {
307
+ if (tierConfig.mcpTools?.includes(toolName) || tierConfig.mcpTools?.includes('*')) {
308
+ requiredTier = tierName;
309
+ break;
310
+ }
311
+ }
312
+
313
+ const requiredTierConfig = requiredTier ? TIERS[requiredTier] : null;
314
+
315
+ return {
316
+ hasAccess: false,
317
+ tier: currentTier,
318
+ requiredTier,
319
+ reason: requiredTierConfig
320
+ ? `${toolName} requires ${requiredTierConfig.name} tier ($${requiredTierConfig.price}/mo). Current: ${currentTierConfig.name}`
321
+ : `${toolName} is not available`,
322
+ upgradeUrl: 'https://vibecheckai.dev/pricing'
323
+ };
324
+ }
325
+
326
+ return {
327
+ hasAccess: true,
328
+ tier: currentTier,
329
+ reason: 'Access granted'
330
+ };
331
+ }
332
+
333
+ /**
334
+ * Middleware for MCP tool handlers with tool-specific checking
335
+ */
336
+ export function withMcpToolCheck(toolName, handler) {
337
+ return async (args) => {
338
+ const access = await checkMcpToolAccess(toolName, args?.apiKey);
339
+
340
+ if (!access.hasAccess) {
341
+ return {
342
+ content: [{
343
+ type: "text",
344
+ text: `🚫 UPGRADE REQUIRED\n\n${access.reason}\n\nUpgrade at: ${access.upgradeUrl}`
345
+ }],
346
+ isError: true
347
+ };
348
+ }
349
+
350
+ // Add tier info to args for the handler
351
+ args._tier = access.tier;
352
+ return handler(args);
353
+ };
354
+ }
355
+
125
356
  /**
126
357
  * Get current user info
127
358
  */
@@ -136,12 +367,46 @@ export async function getUserInfo() {
136
367
  }
137
368
 
138
369
  const tier = getTierFromApiKey(config.apiKey);
370
+ const tierConfig = TIERS[tier];
371
+
139
372
  return {
140
373
  authenticated: true,
141
374
  tier,
142
375
  email: config.email,
143
376
  authenticatedAt: config.authenticatedAt,
144
- features: TIERS[tier].features,
145
- limits: TIERS[tier].limits
377
+ features: tierConfig.features,
378
+ limits: tierConfig.limits,
379
+ mcpTools: tierConfig.mcpTools,
380
+ };
381
+ }
382
+
383
+ /**
384
+ * Get list of MCP tools available for current tier
385
+ */
386
+ export async function getAvailableMcpTools(providedApiKey = null) {
387
+ const userConfig = await loadUserConfig();
388
+ const apiKey = providedApiKey || userConfig?.apiKey;
389
+
390
+ const currentTier = getTierFromApiKey(apiKey);
391
+ const currentTierConfig = TIERS[currentTier];
392
+
393
+ const allowedTools = new Set();
394
+
395
+ // Accumulate tools from current tier and all lower tiers
396
+ for (const [tierName, tierConfig] of Object.entries(TIERS)) {
397
+ if (tierConfig.order <= currentTierConfig.order) {
398
+ if (tierConfig.mcpTools) {
399
+ if (tierConfig.mcpTools.includes('*')) {
400
+ return { tier: currentTier, tools: ['*'], unlimited: true };
401
+ }
402
+ tierConfig.mcpTools.forEach(t => allowedTools.add(t));
403
+ }
404
+ }
405
+ }
406
+
407
+ return {
408
+ tier: currentTier,
409
+ tools: Array.from(allowedTools),
410
+ unlimited: false
146
411
  };
147
412
  }
@@ -278,16 +278,16 @@ export const VIBECHECK_TOOLS = [
278
278
  export async function handleVibecheckTool(toolName, args) {
279
279
  const projectPath = path.resolve(args.projectPath || ".");
280
280
 
281
- // Map tools to required features
281
+ // Map tools to required features (matches CLI entitlements-v2.js)
282
282
  const featureMap = {
283
- "vibecheck.verify": "verify",
284
- "vibecheck.quality": "quality",
285
- "vibecheck.smells": "smells",
286
- "vibecheck.hallucination": "hallucination",
287
- "vibecheck.breaking": "breaking",
288
- "vibecheck.mdc": "mdc",
289
- "vibecheck.coverage": "quality", // map to quality tier
290
- "vibecheck.autofix": "smells" // map to smells tier (fix requires starter+)
283
+ "vibecheck.verify": "verify", // FREE
284
+ "vibecheck.quality": "quality", // FREE
285
+ "vibecheck.smells": "smells", // STARTER
286
+ "vibecheck.hallucination": "hallucination", // FREE
287
+ "vibecheck.breaking": "breaking", // STARTER
288
+ "vibecheck.mdc": "mdc", // FREE
289
+ "vibecheck.coverage": "quality", // FREE
290
+ "vibecheck.autofix": "fix.apply_patches" // PRO (auto-apply requires PRO)
291
291
  };
292
292
 
293
293
  const requiredFeature = featureMap[toolName];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecheckai/cli",
3
- "version": "3.1.2",
3
+ "version": "3.1.4",
4
4
  "description": "Vibecheck CLI - Ship with confidence. One verdict: SHIP | WARN | BLOCK.",
5
5
  "main": "bin/vibecheck.js",
6
6
  "bin": {