@vibecheckai/cli 3.2.6 → 3.4.0
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/bin/registry.js +306 -90
- package/bin/runners/lib/agent-firewall/change-packet/builder.js +280 -6
- package/bin/runners/lib/agent-firewall/critic/index.js +151 -0
- package/bin/runners/lib/agent-firewall/critic/judge.js +432 -0
- package/bin/runners/lib/agent-firewall/critic/prompts.js +305 -0
- package/bin/runners/lib/agent-firewall/lawbook/distributor.js +465 -0
- package/bin/runners/lib/agent-firewall/lawbook/evaluator.js +604 -0
- package/bin/runners/lib/agent-firewall/lawbook/index.js +304 -0
- package/bin/runners/lib/agent-firewall/lawbook/registry.js +514 -0
- package/bin/runners/lib/agent-firewall/lawbook/schema.js +420 -0
- package/bin/runners/lib/agent-firewall/logger.js +141 -0
- package/bin/runners/lib/agent-firewall/policy/loader.js +312 -4
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-env.js +113 -1
- package/bin/runners/lib/agent-firewall/policy/rules/ghost-route.js +133 -6
- package/bin/runners/lib/agent-firewall/proposal/extractor.js +394 -0
- package/bin/runners/lib/agent-firewall/proposal/index.js +212 -0
- package/bin/runners/lib/agent-firewall/proposal/schema.js +251 -0
- package/bin/runners/lib/agent-firewall/proposal/validator.js +386 -0
- package/bin/runners/lib/agent-firewall/reality/index.js +332 -0
- package/bin/runners/lib/agent-firewall/reality/state.js +625 -0
- package/bin/runners/lib/agent-firewall/reality/watcher.js +322 -0
- package/bin/runners/lib/agent-firewall/risk/index.js +173 -0
- package/bin/runners/lib/agent-firewall/risk/scorer.js +328 -0
- package/bin/runners/lib/agent-firewall/risk/thresholds.js +321 -0
- package/bin/runners/lib/agent-firewall/risk/vectors.js +421 -0
- package/bin/runners/lib/agent-firewall/simulator/diff-simulator.js +472 -0
- package/bin/runners/lib/agent-firewall/simulator/import-resolver.js +346 -0
- package/bin/runners/lib/agent-firewall/simulator/index.js +181 -0
- package/bin/runners/lib/agent-firewall/simulator/route-validator.js +380 -0
- package/bin/runners/lib/agent-firewall/time-machine/incident-correlator.js +661 -0
- package/bin/runners/lib/agent-firewall/time-machine/index.js +267 -0
- package/bin/runners/lib/agent-firewall/time-machine/replay-engine.js +436 -0
- package/bin/runners/lib/agent-firewall/time-machine/state-reconstructor.js +490 -0
- package/bin/runners/lib/agent-firewall/time-machine/timeline-builder.js +530 -0
- package/bin/runners/lib/analyzers.js +136 -141
- package/bin/runners/lib/authority-badge.js +425 -0
- package/bin/runners/lib/cli-output.js +7 -1
- package/bin/runners/lib/entitlements-v2.js +96 -505
- package/bin/runners/lib/error-handler.js +16 -9
- package/bin/runners/lib/exit-codes.js +275 -0
- package/bin/runners/lib/global-flags.js +37 -0
- package/bin/runners/lib/help-formatter.js +413 -0
- package/bin/runners/lib/logger.js +38 -0
- package/bin/runners/lib/scan-output.js +18 -19
- package/bin/runners/lib/ship-output.js +18 -25
- package/bin/runners/lib/unified-cli-output.js +604 -0
- package/bin/runners/lib/upsell.js +105 -205
- package/bin/runners/runApprove.js +1200 -0
- package/bin/runners/runAuth.js +324 -95
- package/bin/runners/runCheckpoint.js +39 -21
- package/bin/runners/runClassify.js +859 -0
- package/bin/runners/runContext.js +136 -24
- package/bin/runners/runDoctor.js +108 -68
- package/bin/runners/runFix.js +6 -5
- package/bin/runners/runGuard.js +212 -118
- package/bin/runners/runInit.js +3 -2
- package/bin/runners/runMcp.js +130 -52
- package/bin/runners/runPolish.js +43 -20
- package/bin/runners/runProve.js +1 -2
- package/bin/runners/runReport.js +3 -2
- package/bin/runners/runScan.js +77 -45
- package/bin/runners/runShip.js +3 -4
- package/bin/runners/runValidate.js +19 -2
- package/bin/runners/runWatch.js +104 -53
- package/bin/vibecheck.js +103 -21
- package/mcp-server/HARDENING_SUMMARY.md +299 -0
- package/mcp-server/agent-firewall-interceptor.js +367 -31
- package/mcp-server/authority-tools.js +569 -0
- package/mcp-server/conductor/conflict-resolver.js +588 -0
- package/mcp-server/conductor/execution-planner.js +544 -0
- package/mcp-server/conductor/index.js +377 -0
- package/mcp-server/conductor/lock-manager.js +615 -0
- package/mcp-server/conductor/request-queue.js +550 -0
- package/mcp-server/conductor/session-manager.js +500 -0
- package/mcp-server/conductor/tools.js +510 -0
- package/mcp-server/index.js +1152 -856
- package/mcp-server/lib/api-client.cjs +13 -0
- package/mcp-server/lib/logger.cjs +30 -0
- package/mcp-server/logger.js +173 -0
- package/mcp-server/package.json +2 -2
- package/mcp-server/premium-tools.js +2 -2
- package/mcp-server/tier-auth.js +194 -383
- package/mcp-server/tools-v3.js +495 -533
- package/mcp-server/truth-firewall-tools.js +145 -15
- package/mcp-server/vibecheck-tools.js +2 -2
- package/package.json +2 -3
- package/mcp-server/index.old.js +0 -4137
- package/mcp-server/lib/api-client.js +0 -269
- package/mcp-server/package-lock.json +0 -165
|
@@ -1,25 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Entitlements
|
|
2
|
+
* VibeCheck Entitlements
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* NO BYPASS ALLOWED:
|
|
8
|
-
* - No owner-mode env vars
|
|
9
|
-
* - No offline fallback that grants paid features
|
|
10
|
-
* - No silent feature access
|
|
11
|
-
*
|
|
12
|
-
* Exit Codes:
|
|
13
|
-
* - 0: Success
|
|
14
|
-
* - 2: BLOCK verdict (CI failure)
|
|
15
|
-
* - 3: Feature not allowed (upgrade required)
|
|
16
|
-
* - 4: Misconfiguration/env error
|
|
17
|
-
*
|
|
18
|
-
* Tiers:
|
|
19
|
-
* - FREE ($0): Basic scanning and validation
|
|
20
|
-
* - STARTER ($39/repo/mo): CI/CD gates, PR checks, badges, MCP
|
|
21
|
-
* - PRO ($99/repo/mo): Full fix, prove, ai-test, share, advanced reality, permissions, graph, patch apply
|
|
22
|
-
* - COMPLIANCE (Enterprise): Advanced compliance packs, audit trails
|
|
4
|
+
* Simple 2-tier model:
|
|
5
|
+
* - FREE ($0): Inspect & Observe
|
|
6
|
+
* - PRO ($69/mo): Fix, Prove & Enforce
|
|
23
7
|
*/
|
|
24
8
|
|
|
25
9
|
"use strict";
|
|
@@ -27,301 +11,88 @@
|
|
|
27
11
|
const fs = require("fs");
|
|
28
12
|
const path = require("path");
|
|
29
13
|
const os = require("os");
|
|
30
|
-
const crypto = require("crypto");
|
|
31
14
|
|
|
32
|
-
//
|
|
15
|
+
// ============================================================================
|
|
33
16
|
// EXIT CODES
|
|
34
|
-
//
|
|
17
|
+
// ============================================================================
|
|
35
18
|
const EXIT_SUCCESS = 0;
|
|
36
|
-
const EXIT_BLOCK_VERDICT = 2;
|
|
37
19
|
const EXIT_FEATURE_NOT_ALLOWED = 3;
|
|
38
|
-
const EXIT_MISCONFIG = 4;
|
|
39
20
|
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
//
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// TIERS
|
|
23
|
+
// ============================================================================
|
|
43
24
|
const TIERS = {
|
|
44
|
-
free: { name: "FREE", price: 0
|
|
45
|
-
|
|
46
|
-
pro: { name: "PRO", price: 99, order: 2 },
|
|
47
|
-
compliance: { name: "COMPLIANCE", price: 0, order: 3 }, // Enterprise/on-prem
|
|
25
|
+
free: { name: "FREE", price: 0 },
|
|
26
|
+
pro: { name: "PRO", price: 69 },
|
|
48
27
|
};
|
|
49
28
|
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
"
|
|
60
|
-
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
//
|
|
74
|
-
"
|
|
75
|
-
|
|
76
|
-
"
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
//
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
88
|
-
// PROVE COMMAND
|
|
89
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
90
|
-
"prove": { minTier: "pro" },
|
|
91
|
-
|
|
92
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
93
|
-
// FIX COMMAND
|
|
94
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
95
|
-
"fix": { minTier: "free", downgrade: "fix.plan_only" },
|
|
96
|
-
"fix.plan_only": { minTier: "free" }, // Generate missions, don't apply
|
|
97
|
-
"fix.apply_patches": { minTier: "pro" }, // Apply patches automatically
|
|
98
|
-
"fix.loop": { minTier: "pro" }, // Continuous fix loop
|
|
99
|
-
|
|
100
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
101
|
-
// REPORT FORMATS
|
|
102
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
103
|
-
"report": { minTier: "free", downgrade: "report.html_md" },
|
|
104
|
-
"report.html_md": { minTier: "free" },
|
|
105
|
-
"report.sarif_csv": { minTier: "starter" }, // SARIF/CSV at STARTER
|
|
106
|
-
"report.compliance_packs": { minTier: "compliance" },
|
|
107
|
-
|
|
108
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
109
|
-
// SETUP & DX
|
|
110
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
111
|
-
"install": { minTier: "free" },
|
|
112
|
-
"doctor": { minTier: "free" },
|
|
113
|
-
"status": { minTier: "free" },
|
|
114
|
-
"watch": { minTier: "free", downgrade: "watch.local" },
|
|
115
|
-
"watch.local": { minTier: "free" }, // Local-only file watching
|
|
116
|
-
"watch.pr": { minTier: "starter" }, // PR updates on changes
|
|
117
|
-
"preflight": { minTier: "free" },
|
|
118
|
-
"polish": { minTier: "free" },
|
|
119
|
-
|
|
120
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
121
|
-
// AI TRUTH
|
|
122
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
123
|
-
"ctx": { minTier: "free" },
|
|
124
|
-
"guard": { minTier: "free" },
|
|
125
|
-
"context": { minTier: "free" },
|
|
126
|
-
"mdc": { minTier: "free" },
|
|
127
|
-
"contracts": { minTier: "free" },
|
|
128
|
-
|
|
129
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
130
|
-
// EXPORT COMMAND (subcommands gate individually)
|
|
131
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
132
|
-
"export": { minTier: "free" }, // Base export command is free, subcommands gate themselves
|
|
133
|
-
|
|
134
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
135
|
-
// RUNTIME COMMAND (browser-based verification)
|
|
136
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
137
|
-
"runtime": { minTier: "free", downgrade: "reality.preview" }, // Same as reality
|
|
138
|
-
|
|
139
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
140
|
-
// SECURITY COMMAND (AuthZ & IDOR)
|
|
141
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
142
|
-
"security": { minTier: "pro" },
|
|
143
|
-
|
|
144
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
145
|
-
// AI FEATURES - Token/Cost Controls
|
|
146
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
147
|
-
"ai": { minTier: "starter", downgrade: "ai.none" },
|
|
148
|
-
"ai.none": { minTier: "free", caps: { free: "No AI features - upgrade for AI" } },
|
|
149
|
-
"ai.starter": {
|
|
150
|
-
minTier: "starter",
|
|
151
|
-
caps: {
|
|
152
|
-
starter: {
|
|
153
|
-
model: "gpt-3.5-turbo", // Cheaper model for Starter
|
|
154
|
-
maxCallsPerMonth: 10, // 10 AI calls/month
|
|
155
|
-
maxInputTokensPerRequest: 2000, // ~$0.002 max input cost
|
|
156
|
-
maxOutputTokensPerRequest: 1000, // ~$0.002 max output cost
|
|
157
|
-
maxCostPerMonth: 0.50, // $0.50 max AI spend/month
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
"ai.pro": {
|
|
162
|
-
minTier: "pro",
|
|
163
|
-
caps: {
|
|
164
|
-
pro: {
|
|
165
|
-
model: "gpt-4-turbo-preview", // Premium model for Pro
|
|
166
|
-
alternateModel: "claude-3-5-sonnet-20241022", // Fallback
|
|
167
|
-
maxCallsPerMonth: 50, // 50 AI calls/month
|
|
168
|
-
maxInputTokensPerRequest: 4000, // ~$0.04 max input cost
|
|
169
|
-
maxOutputTokensPerRequest: 2000, // ~$0.06 max output cost
|
|
170
|
-
maxCostPerMonth: 5.00, // $5.00 max AI spend/month
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
},
|
|
174
|
-
"ai.compliance": {
|
|
175
|
-
minTier: "compliance",
|
|
176
|
-
caps: {
|
|
177
|
-
compliance: {
|
|
178
|
-
model: "gpt-4-turbo-preview",
|
|
179
|
-
alternateModel: "claude-3-5-sonnet-20241022",
|
|
180
|
-
maxCallsPerMonth: 500, // 500 AI calls/month
|
|
181
|
-
maxInputTokensPerRequest: 8000,
|
|
182
|
-
maxOutputTokensPerRequest: 4000,
|
|
183
|
-
maxCostPerMonth: 50.00, // $50 max AI spend/month
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
},
|
|
187
|
-
|
|
188
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
189
|
-
// PRO ONLY
|
|
190
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
191
|
-
"replay": { minTier: "pro" },
|
|
192
|
-
"share": { minTier: "pro" },
|
|
193
|
-
"ai-test": { minTier: "pro" },
|
|
194
|
-
"permissions": { minTier: "pro" },
|
|
195
|
-
"graph": { minTier: "pro" },
|
|
196
|
-
|
|
197
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
198
|
-
// STARTER AND ABOVE
|
|
199
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
200
|
-
"gate": { minTier: "starter" },
|
|
201
|
-
"pr": { minTier: "starter" },
|
|
202
|
-
"badge": { minTier: "starter", downgrade: "badge.basic" },
|
|
203
|
-
"badge.basic": { minTier: "starter" }, // Basic badge (STARTER)
|
|
204
|
-
"badge.verified": { minTier: "pro" }, // Verified badge with seal (PRO)
|
|
205
|
-
"fix_hints": { minTier: "starter" }, // Fix hints/missions in output
|
|
206
|
-
"launch": { minTier: "starter" },
|
|
207
|
-
"dashboard_sync": { minTier: "starter" },
|
|
208
|
-
|
|
209
|
-
// MCP Server
|
|
210
|
-
"mcp": { minTier: "starter", downgrade: "mcp.help_only" },
|
|
211
|
-
"mcp.help_only": { minTier: "free", caps: { free: "help and print-config only" } },
|
|
212
|
-
"mcp.read_only": { minTier: "starter", caps: { starter: "read-only safe tools, rate limited" } },
|
|
213
|
-
"mcp.full": { minTier: "pro", caps: { pro: "full tools, audit logs, higher limits" } },
|
|
214
|
-
|
|
215
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
216
|
-
// ACCOUNT (ALWAYS FREE)
|
|
217
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
218
|
-
"login": { minTier: "free" },
|
|
219
|
-
"logout": { minTier: "free" },
|
|
220
|
-
"whoami": { minTier: "free" },
|
|
221
|
-
|
|
222
|
-
// Labs/experimental
|
|
223
|
-
"labs": { minTier: "free" },
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
227
|
-
// LIMITS BY TIER
|
|
228
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
229
|
-
const LIMITS = {
|
|
230
|
-
free: {
|
|
231
|
-
realityMaxPages: 5,
|
|
232
|
-
realityMaxClicks: 20,
|
|
233
|
-
realityAuthBoundary: false,
|
|
234
|
-
reportFormats: ["html", "md"],
|
|
235
|
-
fixApplyPatches: false,
|
|
236
|
-
scansPerMonth: 50,
|
|
237
|
-
shipChecksPerMonth: 20,
|
|
238
|
-
},
|
|
239
|
-
starter: {
|
|
240
|
-
realityMaxPages: 50,
|
|
241
|
-
realityMaxClicks: 200,
|
|
242
|
-
realityAuthBoundary: false,
|
|
243
|
-
realityAdvancedAuth: false,
|
|
244
|
-
reportFormats: ["html", "md", "sarif", "csv"],
|
|
245
|
-
fixApplyPatches: false,
|
|
246
|
-
scansPerMonth: 500,
|
|
247
|
-
shipChecksPerMonth: 200,
|
|
248
|
-
},
|
|
249
|
-
pro: {
|
|
250
|
-
realityMaxPages: -1, // unlimited
|
|
251
|
-
realityMaxClicks: -1,
|
|
252
|
-
realityAuthBoundary: true,
|
|
253
|
-
realityAdvancedAuth: true,
|
|
254
|
-
reportFormats: ["html", "md", "sarif", "csv"],
|
|
255
|
-
fixApplyPatches: true,
|
|
256
|
-
scansPerMonth: -1, // unlimited
|
|
257
|
-
shipChecksPerMonth: -1,
|
|
258
|
-
},
|
|
259
|
-
compliance: {
|
|
260
|
-
realityMaxPages: -1,
|
|
261
|
-
realityMaxClicks: -1,
|
|
262
|
-
realityAuthBoundary: true,
|
|
263
|
-
realityAdvancedAuth: true,
|
|
264
|
-
reportFormats: ["html", "md", "sarif", "csv", "compliance"],
|
|
265
|
-
fixApplyPatches: true,
|
|
266
|
-
scansPerMonth: -1,
|
|
267
|
-
shipChecksPerMonth: -1,
|
|
268
|
-
},
|
|
269
|
-
};
|
|
270
|
-
|
|
271
|
-
const API_BASE_URL = process.env.VIBECHECK_API_URL || "https://api.vibecheckai.dev";
|
|
272
|
-
|
|
273
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
274
|
-
// CACHE PATHS
|
|
275
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
276
|
-
function getEntitlementsCachePath(projectPath) {
|
|
277
|
-
return path.join(projectPath || process.cwd(), ".vibecheck", ".entitlements.json");
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// GATED FEATURES
|
|
31
|
+
// ============================================================================
|
|
32
|
+
const FREE_FEATURES = [
|
|
33
|
+
// Setup & environment
|
|
34
|
+
"init", "doctor", "install", "status", "watch", "preflight",
|
|
35
|
+
// Scan & analysis
|
|
36
|
+
"scan", "runtime",
|
|
37
|
+
// AI verification
|
|
38
|
+
"ctx", "contracts", "verify",
|
|
39
|
+
// Reports
|
|
40
|
+
"report", "export",
|
|
41
|
+
// Account
|
|
42
|
+
"login", "logout", "whoami",
|
|
43
|
+
// Preview modes
|
|
44
|
+
"reality.preview", "firewall.observe",
|
|
45
|
+
// Misc
|
|
46
|
+
"labs", "mdc",
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const PRO_FEATURES = [
|
|
50
|
+
// CI/CD & PR
|
|
51
|
+
"gate", "pr", "badge", "ship",
|
|
52
|
+
// Fixes
|
|
53
|
+
"fix", "fix.apply", "scan.autofix",
|
|
54
|
+
// Prove & verify
|
|
55
|
+
"prove", "replay", "permissions", "graph", "ai-test", "share",
|
|
56
|
+
// Advanced
|
|
57
|
+
"checkpoint", "polish", "guard", "context",
|
|
58
|
+
// Full modes
|
|
59
|
+
"firewall.enforce", "reality.full", "mcp.full",
|
|
60
|
+
// All FREE features
|
|
61
|
+
...FREE_FEATURES,
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
function isPro(tier) {
|
|
65
|
+
return tier === "pro";
|
|
278
66
|
}
|
|
279
67
|
|
|
280
|
-
function
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
return path.join(process.env.APPDATA || path.join(home, "AppData", "Roaming"), "vibecheck", "config.json");
|
|
284
|
-
}
|
|
285
|
-
return path.join(home, ".config", "vibecheck", "config.json");
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
289
|
-
// TIER COMPARISON
|
|
290
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
291
|
-
function tierMeetsMinimum(currentTier, requiredTier) {
|
|
292
|
-
const current = TIERS[currentTier]?.order ?? -1;
|
|
293
|
-
const required = TIERS[requiredTier]?.order ?? 999;
|
|
294
|
-
return current >= required;
|
|
68
|
+
function tierHasFeature(tier, feature) {
|
|
69
|
+
if (tier === "pro") return true; // PRO has everything
|
|
70
|
+
return FREE_FEATURES.includes(feature);
|
|
295
71
|
}
|
|
296
72
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
73
|
+
// ============================================================================
|
|
74
|
+
// API
|
|
75
|
+
// ============================================================================
|
|
76
|
+
const API_BASE_URL = process.env.VIBECHECK_API_URL || "https://api.vibecheckai.dev";
|
|
300
77
|
|
|
301
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
302
|
-
// CORE API: getTier()
|
|
303
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
304
78
|
let _cachedTier = null;
|
|
305
79
|
let _cachedTierExpiry = 0;
|
|
306
80
|
|
|
307
81
|
async function getTier(options = {}) {
|
|
308
|
-
const { apiKey,
|
|
82
|
+
const { apiKey, forceRefresh = false } = options;
|
|
309
83
|
|
|
310
|
-
// Check cache (5 minute TTL)
|
|
311
84
|
if (!forceRefresh && _cachedTier && Date.now() < _cachedTierExpiry) {
|
|
312
85
|
return _cachedTier;
|
|
313
86
|
}
|
|
314
87
|
|
|
315
|
-
// No API key = free tier
|
|
316
88
|
if (!apiKey) {
|
|
317
89
|
_cachedTier = "free";
|
|
318
90
|
_cachedTierExpiry = Date.now() + 300000;
|
|
319
91
|
return "free";
|
|
320
92
|
}
|
|
321
93
|
|
|
322
|
-
// Fetch from API
|
|
323
94
|
try {
|
|
324
|
-
const res = await fetch(`${API_BASE_URL}/v1/
|
|
95
|
+
const res = await fetch(`${API_BASE_URL}/v1/auth/whoami`, {
|
|
325
96
|
method: "GET",
|
|
326
97
|
headers: { "Authorization": `Bearer ${apiKey}` },
|
|
327
98
|
signal: AbortSignal.timeout(5000),
|
|
@@ -329,113 +100,33 @@ async function getTier(options = {}) {
|
|
|
329
100
|
|
|
330
101
|
if (res.ok) {
|
|
331
102
|
const data = await res.json();
|
|
332
|
-
|
|
103
|
+
// Map any paid tier to 'pro'
|
|
104
|
+
const plan = data.plan || data.tier || "free";
|
|
105
|
+
_cachedTier = (plan === "free") ? "free" : "pro";
|
|
333
106
|
_cachedTierExpiry = Date.now() + 300000;
|
|
334
|
-
|
|
335
|
-
// Cache locally
|
|
336
|
-
try {
|
|
337
|
-
const cachePath = getEntitlementsCachePath(projectPath);
|
|
338
|
-
const dir = path.dirname(cachePath);
|
|
339
|
-
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
340
|
-
fs.writeFileSync(cachePath, JSON.stringify({ tier: _cachedTier, fetchedAt: new Date().toISOString() }, null, 2));
|
|
341
|
-
} catch {}
|
|
342
|
-
|
|
343
107
|
return _cachedTier;
|
|
344
108
|
}
|
|
345
|
-
|
|
346
|
-
if (res.status === 401) {
|
|
347
|
-
return "free"; // Invalid key = free tier
|
|
348
|
-
}
|
|
349
109
|
} catch {
|
|
350
|
-
// Network error -
|
|
351
|
-
try {
|
|
352
|
-
const cachePath = getEntitlementsCachePath(projectPath);
|
|
353
|
-
if (fs.existsSync(cachePath)) {
|
|
354
|
-
const cached = JSON.parse(fs.readFileSync(cachePath, "utf8"));
|
|
355
|
-
// Only use cache if less than 24 hours old
|
|
356
|
-
const fetchedAt = new Date(cached.fetchedAt).getTime();
|
|
357
|
-
if (Date.now() - fetchedAt < 24 * 3600 * 1000) {
|
|
358
|
-
return cached.tier || "free";
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
} catch {}
|
|
110
|
+
// Network error - default to free
|
|
362
111
|
}
|
|
363
112
|
|
|
364
|
-
// Default to free (no offline bypass to paid features)
|
|
365
113
|
return "free";
|
|
366
114
|
}
|
|
367
115
|
|
|
368
|
-
//
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
function getLimits(tier) {
|
|
372
|
-
return LIMITS[tier] || LIMITS.free;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
376
|
-
// CORE API: enforce() - THE GATEKEEPER
|
|
377
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
378
|
-
/**
|
|
379
|
-
* Enforce feature access. Returns enforcement result.
|
|
380
|
-
*
|
|
381
|
-
* @param {string} feature - Feature key (e.g., "prove", "fix.apply_patches")
|
|
382
|
-
* @param {object} options - { apiKey?, projectPath?, silent? }
|
|
383
|
-
* @returns {object} - { allowed, tier, downgrade?, exitCode, message }
|
|
384
|
-
*/
|
|
116
|
+
// ============================================================================
|
|
117
|
+
// ENFORCE
|
|
118
|
+
// ============================================================================
|
|
385
119
|
async function enforce(feature, options = {}) {
|
|
386
|
-
const { apiKey,
|
|
387
|
-
|
|
388
|
-
const tier = await getTier({ apiKey, projectPath });
|
|
389
|
-
const entitlement = ENTITLEMENTS[feature];
|
|
120
|
+
const { apiKey, silent = false } = options;
|
|
121
|
+
const tier = await getTier({ apiKey });
|
|
390
122
|
|
|
391
|
-
|
|
392
|
-
// Unknown feature - block by default
|
|
393
|
-
return {
|
|
394
|
-
allowed: false,
|
|
395
|
-
tier,
|
|
396
|
-
exitCode: EXIT_MISCONFIG,
|
|
397
|
-
message: `Unknown feature: ${feature}`,
|
|
398
|
-
};
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
const hasAccess = tierMeetsMinimum(tier, entitlement.minTier);
|
|
123
|
+
const hasAccess = tierHasFeature(tier, feature);
|
|
402
124
|
|
|
403
125
|
if (hasAccess) {
|
|
404
|
-
|
|
405
|
-
return {
|
|
406
|
-
allowed: true,
|
|
407
|
-
tier,
|
|
408
|
-
limits: getLimits(tier),
|
|
409
|
-
caps: entitlement.caps?.[tier] || null,
|
|
410
|
-
};
|
|
126
|
+
return { allowed: true, tier };
|
|
411
127
|
}
|
|
412
128
|
|
|
413
|
-
|
|
414
|
-
if (entitlement.downgrade) {
|
|
415
|
-
const downgradeEntitlement = ENTITLEMENTS[entitlement.downgrade];
|
|
416
|
-
if (downgradeEntitlement && tierMeetsMinimum(tier, downgradeEntitlement.minTier)) {
|
|
417
|
-
// Downgrade allowed
|
|
418
|
-
const caps = downgradeEntitlement.caps?.[tier] || null;
|
|
419
|
-
const message = formatDowngradeMessage(feature, entitlement.downgrade, tier, entitlement.minTier, caps);
|
|
420
|
-
|
|
421
|
-
if (!silent) {
|
|
422
|
-
console.log(message);
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
return {
|
|
426
|
-
allowed: true,
|
|
427
|
-
tier,
|
|
428
|
-
downgrade: entitlement.downgrade,
|
|
429
|
-
limits: getLimits(tier),
|
|
430
|
-
caps,
|
|
431
|
-
message,
|
|
432
|
-
};
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// Not allowed - generate upgrade message
|
|
437
|
-
const message = formatUpgradeMessage(feature, tier, entitlement.minTier);
|
|
438
|
-
|
|
129
|
+
const message = formatUpgradeMessage(feature);
|
|
439
130
|
if (!silent) {
|
|
440
131
|
console.error(message);
|
|
441
132
|
}
|
|
@@ -443,80 +134,11 @@ async function enforce(feature, options = {}) {
|
|
|
443
134
|
return {
|
|
444
135
|
allowed: false,
|
|
445
136
|
tier,
|
|
446
|
-
requiredTier: entitlement.minTier,
|
|
447
137
|
exitCode: EXIT_FEATURE_NOT_ALLOWED,
|
|
448
138
|
message,
|
|
449
139
|
};
|
|
450
140
|
}
|
|
451
141
|
|
|
452
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
453
|
-
// MESSAGING
|
|
454
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
455
|
-
const c = {
|
|
456
|
-
reset: "\x1b[0m",
|
|
457
|
-
bold: "\x1b[1m",
|
|
458
|
-
dim: "\x1b[2m",
|
|
459
|
-
red: "\x1b[31m",
|
|
460
|
-
green: "\x1b[32m",
|
|
461
|
-
yellow: "\x1b[33m",
|
|
462
|
-
cyan: "\x1b[36m",
|
|
463
|
-
magenta: "\x1b[35m",
|
|
464
|
-
};
|
|
465
|
-
|
|
466
|
-
function formatUpgradeMessage(feature, currentTier, requiredTier) {
|
|
467
|
-
const tierColors = { starter: c.cyan, pro: c.magenta, enterprise: c.yellow };
|
|
468
|
-
const reqColor = tierColors[requiredTier] || c.yellow;
|
|
469
|
-
|
|
470
|
-
return `
|
|
471
|
-
${c.red}${c.bold}⛔ Feature Not Available${c.reset}
|
|
472
|
-
|
|
473
|
-
${c.yellow}${feature}${c.reset} requires ${reqColor}${getTierLabel(requiredTier)}${c.reset} plan.
|
|
474
|
-
Your current plan: ${c.dim}${getTierLabel(currentTier)}${c.reset}
|
|
475
|
-
|
|
476
|
-
${c.cyan}Upgrade at:${c.reset} https://vibecheckai.dev/pricing
|
|
477
|
-
|
|
478
|
-
${c.dim}Exit code: ${EXIT_FEATURE_NOT_ALLOWED}${c.reset}
|
|
479
|
-
`;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
function formatDowngradeMessage(feature, downgradeTo, currentTier, requiredTier, caps) {
|
|
483
|
-
const tierColors = { starter: c.cyan, pro: c.magenta, enterprise: c.yellow };
|
|
484
|
-
const reqColor = tierColors[requiredTier] || c.yellow;
|
|
485
|
-
|
|
486
|
-
let capsStr = "";
|
|
487
|
-
if (caps) {
|
|
488
|
-
if (typeof caps === "string") {
|
|
489
|
-
capsStr = ` ${c.dim}Mode: ${caps}${c.reset}\n`;
|
|
490
|
-
} else if (typeof caps === "object") {
|
|
491
|
-
const entries = Object.entries(caps).map(([k, v]) => `${k}: ${v}`).join(", ");
|
|
492
|
-
capsStr = ` ${c.dim}Limits: ${entries}${c.reset}\n`;
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
|
|
496
|
-
return `
|
|
497
|
-
${c.yellow}${c.bold}⚠ Running in Preview Mode${c.reset}
|
|
498
|
-
|
|
499
|
-
Full ${c.yellow}${feature}${c.reset} requires ${reqColor}${getTierLabel(requiredTier)}${c.reset} plan.
|
|
500
|
-
Running ${c.green}${downgradeTo}${c.reset} instead.
|
|
501
|
-
${capsStr}
|
|
502
|
-
${c.cyan}Upgrade for full access:${c.reset} https://vibecheckai.dev/pricing
|
|
503
|
-
`;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
507
|
-
// CONVENIENCE HELPERS
|
|
508
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* Check if a command is allowed (does not print messages)
|
|
512
|
-
*/
|
|
513
|
-
async function checkCommand(command, options = {}) {
|
|
514
|
-
return enforce(command, { ...options, silent: true });
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* Enforce and exit if not allowed
|
|
519
|
-
*/
|
|
520
142
|
async function enforceOrExit(feature, options = {}) {
|
|
521
143
|
const result = await enforce(feature, options);
|
|
522
144
|
if (!result.allowed) {
|
|
@@ -525,82 +147,51 @@ async function enforceOrExit(feature, options = {}) {
|
|
|
525
147
|
return result;
|
|
526
148
|
}
|
|
527
149
|
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
*/
|
|
531
|
-
function getMinTierForFeature(feature) {
|
|
532
|
-
return ENTITLEMENTS[feature]?.minTier || "enterprise";
|
|
150
|
+
async function checkCommand(command, options = {}) {
|
|
151
|
+
return enforce(command, { ...options, silent: true });
|
|
533
152
|
}
|
|
534
153
|
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
154
|
+
// ============================================================================
|
|
155
|
+
// MESSAGING
|
|
156
|
+
// ============================================================================
|
|
157
|
+
const c = {
|
|
158
|
+
reset: "\x1b[0m",
|
|
159
|
+
bold: "\x1b[1m",
|
|
160
|
+
cyan: "\x1b[36m",
|
|
161
|
+
yellow: "\x1b[33m",
|
|
162
|
+
};
|
|
543
163
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
function getFeaturesForTier(tier) {
|
|
548
|
-
const features = [];
|
|
549
|
-
for (const [feature, def] of Object.entries(ENTITLEMENTS)) {
|
|
550
|
-
if (tierMeetsMinimum(tier, def.minTier)) {
|
|
551
|
-
features.push(feature);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
return features;
|
|
555
|
-
}
|
|
164
|
+
function formatUpgradeMessage(feature) {
|
|
165
|
+
return `
|
|
166
|
+
${c.bold}This feature requires Pro.${c.reset}
|
|
556
167
|
|
|
557
|
-
|
|
558
|
-
// COMMAND GROUPING FOR HELP DISPLAY
|
|
559
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
560
|
-
const COMMAND_GROUPS = {
|
|
561
|
-
"Proof Loop": ["scan", "ship", "reality", "prove", "fix", "report"],
|
|
562
|
-
"Setup & DX": ["install", "init", "doctor", "status", "watch", "launch"],
|
|
563
|
-
"AI Truth": ["ctx", "guard", "context", "mdc"],
|
|
564
|
-
"CI & Collaboration": ["gate", "pr", "badge"],
|
|
565
|
-
"Reporting": ["report"],
|
|
566
|
-
"Automation": ["ai-test", "mcp", "share"],
|
|
567
|
-
};
|
|
168
|
+
${c.yellow}${feature}${c.reset} is a Pro feature.
|
|
568
169
|
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
170
|
+
Upgrade to Pro ($69/mo) to unlock Fix, Prove & Enforce capabilities.
|
|
171
|
+
|
|
172
|
+
vibecheck upgrade
|
|
173
|
+
https://vibecheckai.dev/pricing
|
|
174
|
+
`;
|
|
574
175
|
}
|
|
575
176
|
|
|
576
|
-
//
|
|
177
|
+
// ============================================================================
|
|
577
178
|
// EXPORTS
|
|
578
|
-
//
|
|
179
|
+
// ============================================================================
|
|
579
180
|
module.exports = {
|
|
580
|
-
// Core
|
|
181
|
+
// Core
|
|
581
182
|
getTier,
|
|
582
|
-
getLimits,
|
|
583
183
|
enforce,
|
|
584
184
|
enforceOrExit,
|
|
585
185
|
checkCommand,
|
|
586
186
|
|
|
587
|
-
//
|
|
588
|
-
|
|
589
|
-
getTierLabel,
|
|
590
|
-
getMinTierForFeature,
|
|
187
|
+
// Helpers
|
|
188
|
+
isPro,
|
|
591
189
|
tierHasFeature,
|
|
592
|
-
getFeaturesForTier,
|
|
593
|
-
|
|
594
|
-
// Command grouping
|
|
595
|
-
COMMAND_GROUPS,
|
|
596
|
-
getCommandGroup,
|
|
597
190
|
|
|
598
191
|
// Constants
|
|
599
192
|
TIERS,
|
|
600
|
-
|
|
601
|
-
|
|
193
|
+
FREE_FEATURES,
|
|
194
|
+
PRO_FEATURES,
|
|
602
195
|
EXIT_SUCCESS,
|
|
603
|
-
EXIT_BLOCK_VERDICT,
|
|
604
196
|
EXIT_FEATURE_NOT_ALLOWED,
|
|
605
|
-
EXIT_MISCONFIG,
|
|
606
197
|
};
|