@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
package/mcp-server/tier-auth.js
CHANGED
|
@@ -1,475 +1,286 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MCP Server Tier Authentication
|
|
2
|
+
* MCP Server Tier Authentication
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Simple 2-tier model:
|
|
5
|
+
* - FREE ($0): Inspect & Observe
|
|
6
|
+
* - PRO ($69/mo): Fix, Prove & Enforce
|
|
5
7
|
*
|
|
6
|
-
*
|
|
7
|
-
* -
|
|
8
|
-
* -
|
|
9
|
-
* -
|
|
10
|
-
* - ENTERPRISE: All features + compliance tools.
|
|
11
|
-
*
|
|
12
|
-
* Verdict authority is paid. Evidence beats explanations.
|
|
8
|
+
* PRO includes:
|
|
9
|
+
* - Authority System (verdicts, approvals)
|
|
10
|
+
* - Agent Conductor (multi-agent coordination)
|
|
11
|
+
* - Agent Firewall (enforce mode)
|
|
13
12
|
*/
|
|
14
13
|
|
|
15
14
|
import fs from "fs/promises";
|
|
16
15
|
import path from "path";
|
|
17
16
|
import os from "os";
|
|
18
17
|
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
//
|
|
22
|
-
//
|
|
23
|
-
// Authority Rules:
|
|
24
|
-
// - FREE: May see problems, never resolve certainty
|
|
25
|
-
// - STARTER: May fix, but not prove (Advisory verdicts only)
|
|
26
|
-
// - PRO: May enforce reality (Full verdict authority)
|
|
27
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// TIERS
|
|
20
|
+
// ============================================================================
|
|
28
21
|
export const TIERS = {
|
|
29
|
-
free: {
|
|
30
|
-
|
|
31
|
-
price: 0,
|
|
32
|
-
order: 0,
|
|
33
|
-
// Verdict authority
|
|
34
|
-
verdictAuthority: 'NONE',
|
|
35
|
-
canIssueVerdicts: false,
|
|
36
|
-
canEnforceCI: false,
|
|
37
|
-
canGenerateProof: false,
|
|
38
|
-
// Limits
|
|
39
|
-
limits: {
|
|
40
|
-
scans: -1, // Unlimited scans
|
|
41
|
-
realityMaxPages: 5,
|
|
42
|
-
realityMaxClicks: 20,
|
|
43
|
-
mcpRateLimit: 10,
|
|
44
|
-
},
|
|
45
|
-
// MCP tools allowed on FREE (read-only context only)
|
|
46
|
-
mcpTools: [
|
|
47
|
-
'vibecheck.get_truthpack',
|
|
48
|
-
'vibecheck.compile_context',
|
|
49
|
-
'vibecheck.search_evidence',
|
|
50
|
-
],
|
|
51
|
-
},
|
|
52
|
-
starter: {
|
|
53
|
-
name: 'STARTER',
|
|
54
|
-
price: 39,
|
|
55
|
-
order: 1,
|
|
56
|
-
// Verdict authority - ADVISORY (verdicts not enforced)
|
|
57
|
-
verdictAuthority: 'ADVISORY',
|
|
58
|
-
canIssueVerdicts: true, // SHIP, WARN only
|
|
59
|
-
canEnforceCI: false, // Cannot block builds
|
|
60
|
-
canGenerateProof: false, // Cannot generate proof
|
|
61
|
-
// Limits
|
|
62
|
-
limits: {
|
|
63
|
-
scans: -1, // Unlimited scans
|
|
64
|
-
realityMaxPages: -1, // Unlimited browser testing
|
|
65
|
-
realityMaxClicks: -1,
|
|
66
|
-
mcpRateLimit: 60,
|
|
67
|
-
},
|
|
68
|
-
// MCP tools allowed on STARTER (read + advisory actions)
|
|
69
|
-
mcpTools: [
|
|
70
|
-
'vibecheck.ctx',
|
|
71
|
-
'vibecheck.scan',
|
|
72
|
-
'vibecheck.ship', // Advisory verdicts only
|
|
73
|
-
'vibecheck.get_truthpack',
|
|
74
|
-
'vibecheck.validate_claim',
|
|
75
|
-
'vibecheck.compile_context',
|
|
76
|
-
'vibecheck.search_evidence',
|
|
77
|
-
'vibecheck.find_counterexamples',
|
|
78
|
-
'vibecheck.check_invariants',
|
|
79
|
-
'vibecheck.fix', // Plan mode only
|
|
80
|
-
],
|
|
81
|
-
},
|
|
82
|
-
pro: {
|
|
83
|
-
name: 'PRO',
|
|
84
|
-
price: 99,
|
|
85
|
-
order: 2,
|
|
86
|
-
// Verdict authority - ENFORCED (verdicts block CI/PRs)
|
|
87
|
-
verdictAuthority: 'ENFORCED',
|
|
88
|
-
canIssueVerdicts: true, // SHIP, WARN, BLOCK
|
|
89
|
-
canEnforceCI: true, // Can block builds
|
|
90
|
-
canGenerateProof: true, // Can generate cryptographic proof
|
|
91
|
-
// Limits
|
|
92
|
-
limits: {
|
|
93
|
-
scans: -1,
|
|
94
|
-
realityMaxPages: -1,
|
|
95
|
-
realityMaxClicks: -1,
|
|
96
|
-
mcpRateLimit: -1, // Unlimited
|
|
97
|
-
},
|
|
98
|
-
// MCP tools - FULL ACCESS
|
|
99
|
-
mcpTools: ['*'], // All tools unlocked
|
|
100
|
-
},
|
|
101
|
-
enterprise: {
|
|
102
|
-
name: 'ENTERPRISE',
|
|
103
|
-
price: 0, // Custom pricing
|
|
104
|
-
order: 3,
|
|
105
|
-
// Verdict authority - ENFORCED + Compliance
|
|
106
|
-
verdictAuthority: 'ENFORCED',
|
|
107
|
-
canIssueVerdicts: true,
|
|
108
|
-
canEnforceCI: true,
|
|
109
|
-
canGenerateProof: true,
|
|
110
|
-
// Limits
|
|
111
|
-
limits: {
|
|
112
|
-
scans: -1,
|
|
113
|
-
realityMaxPages: -1,
|
|
114
|
-
realityMaxClicks: -1,
|
|
115
|
-
mcpRateLimit: -1,
|
|
116
|
-
},
|
|
117
|
-
// MCP tools - FULL ACCESS + Compliance
|
|
118
|
-
mcpTools: ['*'],
|
|
119
|
-
}
|
|
22
|
+
free: { name: 'FREE', price: 0 },
|
|
23
|
+
pro: { name: 'PRO', price: 69 },
|
|
120
24
|
};
|
|
121
25
|
|
|
122
|
-
//
|
|
123
|
-
// MCP
|
|
124
|
-
//
|
|
125
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
126
|
-
export const MCP_TOOL_TIERS = {
|
|
127
|
-
// FREE - Read-only context tools ONLY
|
|
128
|
-
// Free users may see problems, never resolve certainty
|
|
129
|
-
'vibecheck.get_truthpack': 'free',
|
|
130
|
-
'vibecheck.compile_context': 'free',
|
|
131
|
-
'vibecheck.search_evidence': 'free',
|
|
132
|
-
|
|
133
|
-
// STARTER - Advisory verdict authority
|
|
134
|
-
// Starter users may fix, but not prove
|
|
135
|
-
'vibecheck.ctx': 'starter',
|
|
136
|
-
'vibecheck.scan': 'starter',
|
|
137
|
-
'vibecheck.ship': 'starter', // SHIP/WARN (advisory, not enforced)
|
|
138
|
-
'vibecheck.fix': 'starter', // Plan mode only (no apply)
|
|
139
|
-
'vibecheck.validate_claim': 'starter',
|
|
140
|
-
'vibecheck.find_counterexamples': 'starter',
|
|
141
|
-
'vibecheck.check_invariants': 'starter',
|
|
142
|
-
'vibecheck.gate': 'starter', // Advisory gates
|
|
143
|
-
'vibecheck.badge': 'starter', // Unverified badges
|
|
144
|
-
|
|
145
|
-
// PRO - Full verdict authority & enforcement
|
|
146
|
-
// Pro users may enforce reality
|
|
147
|
-
'vibecheck.prove': 'pro', // Cryptographic proof generation
|
|
148
|
-
'vibecheck.fix.apply': 'pro', // Apply fixes
|
|
149
|
-
'vibecheck.fix.verify': 'pro', // Verify fixes with proof
|
|
150
|
-
'vibecheck.reality': 'pro', // Full browser testing
|
|
151
|
-
'vibecheck.reality.prove': 'pro', // Prove runtime behavior
|
|
152
|
-
'vibecheck.enforce': 'pro', // Enforce verdicts in CI
|
|
153
|
-
'vibecheck.ai_test': 'pro', // AI agent testing
|
|
154
|
-
'vibecheck.autopilot': 'pro', // Autonomous protection
|
|
155
|
-
'vibecheck.report': 'pro', // Advanced reporting
|
|
156
|
-
'vibecheck.allowlist': 'pro', // Manage allowlists
|
|
157
|
-
'vibecheck.status': 'pro', // Advanced status
|
|
158
|
-
};
|
|
26
|
+
// ============================================================================
|
|
27
|
+
// MCP TOOLS - 15 Core + PRO Features
|
|
28
|
+
// ============================================================================
|
|
159
29
|
|
|
160
30
|
/**
|
|
161
|
-
*
|
|
31
|
+
* FREE TOOLS (7) - Inspect & Observe
|
|
162
32
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
33
|
+
export const FREE_TOOLS = [
|
|
34
|
+
// Core FREE tools
|
|
35
|
+
'vibecheck.scan',
|
|
36
|
+
'vibecheck.ctx',
|
|
37
|
+
'vibecheck.verify',
|
|
38
|
+
'vibecheck.report',
|
|
39
|
+
'vibecheck.status',
|
|
40
|
+
'vibecheck.doctor',
|
|
41
|
+
'vibecheck.firewall', // Observe mode only
|
|
42
|
+
// Authority (read-only)
|
|
43
|
+
'authority.list',
|
|
44
|
+
'authority.classify',
|
|
45
|
+
// Conductor (status only)
|
|
46
|
+
'vibecheck_conductor_status',
|
|
47
|
+
];
|
|
172
48
|
|
|
173
49
|
/**
|
|
174
|
-
*
|
|
175
|
-
* Matches CLI entitlements-v2.js logic
|
|
50
|
+
* PRO TOOLS (8 Core + Authority + Conductor + Firewall) - Fix, Prove & Enforce
|
|
176
51
|
*/
|
|
177
|
-
|
|
178
|
-
|
|
52
|
+
export const PRO_TOOLS = [
|
|
53
|
+
// Core PRO tools
|
|
54
|
+
'vibecheck.ship',
|
|
55
|
+
'vibecheck.fix',
|
|
56
|
+
'vibecheck.prove',
|
|
57
|
+
'vibecheck.gate',
|
|
58
|
+
'vibecheck.badge',
|
|
59
|
+
'vibecheck.reality',
|
|
60
|
+
'vibecheck.ai_test',
|
|
61
|
+
'vibecheck.share',
|
|
179
62
|
|
|
180
|
-
//
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (apiKey.startsWith('gr_enterprise_') || apiKey.startsWith('gr_ent_')) return 'enterprise';
|
|
184
|
-
if (apiKey.startsWith('gr_free_')) return 'free';
|
|
63
|
+
// Authority System (full)
|
|
64
|
+
'authority.approve',
|
|
65
|
+
'authority.enforce',
|
|
185
66
|
|
|
186
|
-
//
|
|
67
|
+
// Agent Conductor (full multi-agent coordination)
|
|
68
|
+
'vibecheck_conductor_register',
|
|
69
|
+
'vibecheck_conductor_acquire_lock',
|
|
70
|
+
'vibecheck_conductor_release_lock',
|
|
71
|
+
'vibecheck_conductor_propose',
|
|
72
|
+
'vibecheck_conductor_terminate',
|
|
73
|
+
|
|
74
|
+
// Agent Firewall (enforce mode)
|
|
75
|
+
'vibecheck_agent_firewall_intercept',
|
|
76
|
+
'vibecheck.firewall.enforce',
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
export const ALL_TOOLS = [...FREE_TOOLS, ...PRO_TOOLS];
|
|
80
|
+
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// TIER CACHE
|
|
83
|
+
// ============================================================================
|
|
84
|
+
const tierCache = new Map();
|
|
85
|
+
const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
|
|
86
|
+
|
|
87
|
+
function hashKey(apiKey) {
|
|
88
|
+
const crypto = require('crypto');
|
|
89
|
+
return crypto.createHash('sha256').update(apiKey).digest('hex').slice(0, 16);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ============================================================================
|
|
93
|
+
// TIER VALIDATION
|
|
94
|
+
// ============================================================================
|
|
95
|
+
|
|
96
|
+
export async function getTierFromApiKey(apiKey) {
|
|
97
|
+
if (!apiKey || typeof apiKey !== 'string' || apiKey.length < 10) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const keyHash = hashKey(apiKey);
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
|
|
104
|
+
// Check cache
|
|
105
|
+
const cached = tierCache.get(keyHash);
|
|
106
|
+
if (cached && cached.expiresAt > now) {
|
|
107
|
+
return cached.tier;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Validate with API
|
|
187
111
|
try {
|
|
188
112
|
const response = await fetch('https://api.vibecheckai.dev/whoami', {
|
|
189
|
-
headers: {
|
|
190
|
-
|
|
191
|
-
'Content-Type': 'application/json',
|
|
192
|
-
},
|
|
113
|
+
headers: { 'Authorization': `Bearer ${apiKey}` },
|
|
114
|
+
signal: AbortSignal.timeout(10000),
|
|
193
115
|
});
|
|
194
116
|
|
|
195
117
|
if (!response.ok) {
|
|
196
|
-
return null;
|
|
118
|
+
return null;
|
|
197
119
|
}
|
|
198
120
|
|
|
199
121
|
const data = await response.json();
|
|
122
|
+
const plan = data.plan?.toLowerCase() || 'free';
|
|
200
123
|
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
} catch (error) {
|
|
213
|
-
console.error('API validation failed:', error);
|
|
214
|
-
return null; // On error, deny access
|
|
124
|
+
// Any paid plan = pro
|
|
125
|
+
const tier = (plan === 'free') ? 'free' : 'pro';
|
|
126
|
+
|
|
127
|
+
tierCache.set(keyHash, { tier, expiresAt: now + CACHE_TTL });
|
|
128
|
+
return tier;
|
|
129
|
+
|
|
130
|
+
} catch {
|
|
131
|
+
// Network error - check stale cache
|
|
132
|
+
if (cached) return cached.tier;
|
|
133
|
+
return null;
|
|
215
134
|
}
|
|
216
|
-
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ============================================================================
|
|
138
|
+
// ACCESS CONTROL
|
|
139
|
+
// ============================================================================
|
|
140
|
+
|
|
141
|
+
export function isPro(tier) {
|
|
142
|
+
return tier === 'pro';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function canAccessTool(tier, toolName) {
|
|
146
|
+
// PRO gets everything
|
|
147
|
+
if (tier === 'pro') return true;
|
|
148
|
+
|
|
149
|
+
// FREE can access FREE tools
|
|
150
|
+
return FREE_TOOLS.includes(toolName);
|
|
151
|
+
}
|
|
217
152
|
|
|
218
153
|
/**
|
|
219
|
-
*
|
|
220
|
-
*
|
|
154
|
+
* Get firewall mode based on tier
|
|
155
|
+
* - FREE: observe (log only)
|
|
156
|
+
* - PRO: enforce (block violations)
|
|
221
157
|
*/
|
|
222
|
-
export
|
|
223
|
-
|
|
224
|
-
const userConfig = await loadUserConfig();
|
|
225
|
-
const apiKey = providedApiKey || userConfig?.apiKey;
|
|
226
|
-
|
|
227
|
-
if (!apiKey) {
|
|
228
|
-
return {
|
|
229
|
-
hasAccess: false,
|
|
230
|
-
tier: null,
|
|
231
|
-
reason: 'No API key provided. Please set your API key with `vibecheck login`.',
|
|
232
|
-
upgradeUrl: 'https://vibecheckai.dev'
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
const currentTier = await getTierFromApiKey(apiKey);
|
|
237
|
-
|
|
238
|
-
if (!currentTier) {
|
|
239
|
-
return {
|
|
240
|
-
hasAccess: false,
|
|
241
|
-
tier: null,
|
|
242
|
-
reason: 'Invalid API key. Please check your API key or get a new one at https://vibecheckai.dev',
|
|
243
|
-
upgradeUrl: 'https://vibecheckai.dev'
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
|
-
const currentTierConfig = TIERS[currentTier];
|
|
247
|
-
|
|
248
|
-
// Find which tier has this feature
|
|
249
|
-
let requiredTier = null;
|
|
250
|
-
let requiredTierConfig = null;
|
|
251
|
-
|
|
252
|
-
for (const [tierName, tierConfig] of Object.entries(TIERS)) {
|
|
253
|
-
if (tierConfig.features.includes(featureName)) {
|
|
254
|
-
requiredTier = tierName;
|
|
255
|
-
requiredTierConfig = tierConfig;
|
|
256
|
-
break;
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// If feature not found in any tier, deny access
|
|
261
|
-
if (!requiredTier) {
|
|
262
|
-
return {
|
|
263
|
-
hasAccess: false,
|
|
264
|
-
tier: currentTier,
|
|
265
|
-
reason: `${featureName} is not available in any tier`,
|
|
266
|
-
upgradeUrl: 'https://vibecheckai.dev'
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
// Check if current tier meets minimum requirement (using order)
|
|
271
|
-
const hasAccess = currentTierConfig.order >= requiredTierConfig.order;
|
|
272
|
-
|
|
273
|
-
if (!hasAccess) {
|
|
274
|
-
return {
|
|
275
|
-
hasAccess: false,
|
|
276
|
-
tier: currentTier,
|
|
277
|
-
requiredTier,
|
|
278
|
-
reason: `${featureName} requires ${requiredTierConfig.name} tier ($${requiredTierConfig.price}/mo) or higher. Current tier: ${currentTierConfig.name}`,
|
|
279
|
-
upgradeUrl: 'https://vibecheckai.dev'
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
return {
|
|
284
|
-
hasAccess: true,
|
|
285
|
-
tier: currentTier,
|
|
286
|
-
reason: 'Access granted'
|
|
287
|
-
};
|
|
158
|
+
export function getFirewallMode(tier) {
|
|
159
|
+
return tier === 'pro' ? 'enforce' : 'observe';
|
|
288
160
|
}
|
|
289
161
|
|
|
290
162
|
/**
|
|
291
|
-
*
|
|
163
|
+
* Check if user can use full conductor features
|
|
292
164
|
*/
|
|
293
|
-
export function
|
|
294
|
-
return
|
|
295
|
-
const access = await checkFeatureAccess(featureName, args?.apiKey);
|
|
296
|
-
|
|
297
|
-
if (!access.hasAccess) {
|
|
298
|
-
return {
|
|
299
|
-
content: [{
|
|
300
|
-
type: "text",
|
|
301
|
-
text: `🚫 UPGRADE REQUIRED\n\n${access.reason}\n\nUpgrade at: ${access.upgradeUrl}`
|
|
302
|
-
}],
|
|
303
|
-
isError: true
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Add tier info to args for the handler
|
|
308
|
-
args._tier = access.tier;
|
|
309
|
-
return handler(args);
|
|
310
|
-
};
|
|
165
|
+
export function canUseCondcutor(tier) {
|
|
166
|
+
return tier === 'pro';
|
|
311
167
|
}
|
|
312
168
|
|
|
313
169
|
/**
|
|
314
|
-
* Check if user
|
|
315
|
-
* MCP tools have specific tier requirements separate from CLI features
|
|
170
|
+
* Check if user can approve authorities
|
|
316
171
|
*/
|
|
317
|
-
export
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
172
|
+
export function canApproveAuthority(tier) {
|
|
173
|
+
return tier === 'pro';
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export async function getMcpToolAccess(toolName, apiKey) {
|
|
321
177
|
if (!apiKey) {
|
|
322
178
|
return {
|
|
323
|
-
hasAccess:
|
|
324
|
-
tier:
|
|
325
|
-
reason:
|
|
326
|
-
|
|
179
|
+
hasAccess: FREE_TOOLS.includes(toolName),
|
|
180
|
+
tier: 'free',
|
|
181
|
+
reason: FREE_TOOLS.includes(toolName)
|
|
182
|
+
? 'Access granted (free tool)'
|
|
183
|
+
: 'This tool requires Pro. Set API key with `vibecheck login`.',
|
|
327
184
|
};
|
|
328
185
|
}
|
|
329
186
|
|
|
330
|
-
const
|
|
187
|
+
const tier = await getTierFromApiKey(apiKey);
|
|
331
188
|
|
|
332
|
-
if (!
|
|
189
|
+
if (!tier) {
|
|
333
190
|
return {
|
|
334
191
|
hasAccess: false,
|
|
335
192
|
tier: null,
|
|
336
|
-
reason: 'Invalid API key.
|
|
337
|
-
upgradeUrl: 'https://vibecheckai.dev'
|
|
193
|
+
reason: 'Invalid API key.',
|
|
338
194
|
};
|
|
339
195
|
}
|
|
340
196
|
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
// Check if tool is allowed for current tier
|
|
344
|
-
const allowedTools = [];
|
|
345
|
-
|
|
346
|
-
// Accumulate tools from current tier and all lower tiers
|
|
347
|
-
for (const [tierName, tierConfig] of Object.entries(TIERS)) {
|
|
348
|
-
if (tierConfig.order <= currentTierConfig.order) {
|
|
349
|
-
if (tierConfig.mcpTools) {
|
|
350
|
-
if (tierConfig.mcpTools.includes('*')) {
|
|
351
|
-
// Compliance tier - all tools allowed
|
|
352
|
-
return {
|
|
353
|
-
hasAccess: true,
|
|
354
|
-
tier: currentTier,
|
|
355
|
-
reason: 'Full MCP access'
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
allowedTools.push(...tierConfig.mcpTools);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// Check if tool is in allowed list
|
|
364
|
-
const hasAccess = allowedTools.includes(toolName);
|
|
365
|
-
|
|
366
|
-
if (!hasAccess) {
|
|
367
|
-
// Find which tier has this tool
|
|
368
|
-
let requiredTier = null;
|
|
369
|
-
for (const [tierName, tierConfig] of Object.entries(TIERS)) {
|
|
370
|
-
if (tierConfig.mcpTools?.includes(toolName) || tierConfig.mcpTools?.includes('*')) {
|
|
371
|
-
requiredTier = tierName;
|
|
372
|
-
break;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
const requiredTierConfig = requiredTier ? TIERS[requiredTier] : null;
|
|
377
|
-
|
|
378
|
-
return {
|
|
379
|
-
hasAccess: false,
|
|
380
|
-
tier: currentTier,
|
|
381
|
-
requiredTier,
|
|
382
|
-
reason: requiredTierConfig
|
|
383
|
-
? `${toolName} requires ${requiredTierConfig.name} tier ($${requiredTierConfig.price}/mo). Current: ${currentTierConfig.name}`
|
|
384
|
-
: `${toolName} is not available`,
|
|
385
|
-
upgradeUrl: 'https://vibecheckai.dev'
|
|
386
|
-
};
|
|
387
|
-
}
|
|
197
|
+
const hasAccess = canAccessTool(tier, toolName);
|
|
388
198
|
|
|
389
199
|
return {
|
|
390
|
-
hasAccess
|
|
391
|
-
tier
|
|
392
|
-
|
|
200
|
+
hasAccess,
|
|
201
|
+
tier,
|
|
202
|
+
firewallMode: getFirewallMode(tier),
|
|
203
|
+
reason: hasAccess
|
|
204
|
+
? 'Access granted'
|
|
205
|
+
: `${toolName} requires Pro ($69/mo). Upgrade at https://vibecheckai.dev/pricing`,
|
|
393
206
|
};
|
|
394
207
|
}
|
|
395
208
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
209
|
+
// ============================================================================
|
|
210
|
+
// MIDDLEWARE
|
|
211
|
+
// ============================================================================
|
|
212
|
+
|
|
213
|
+
export function withTierCheck(toolName, handler) {
|
|
400
214
|
return async (args) => {
|
|
401
|
-
const access = await
|
|
215
|
+
const access = await getMcpToolAccess(toolName, args?.apiKey);
|
|
402
216
|
|
|
403
217
|
if (!access.hasAccess) {
|
|
404
218
|
return {
|
|
405
219
|
content: [{
|
|
406
220
|
type: "text",
|
|
407
|
-
text:
|
|
221
|
+
text: `This tool requires Pro.\n\n${toolName} is a Pro feature.\n\nUpgrade to Pro ($69/mo) to unlock:\n- Authority System (verdicts & approvals)\n- Agent Conductor (multi-agent coordination)\n- Agent Firewall (enforce mode)\n\nhttps://vibecheckai.dev/pricing`
|
|
408
222
|
}],
|
|
409
223
|
isError: true
|
|
410
224
|
};
|
|
411
225
|
}
|
|
412
226
|
|
|
413
|
-
// Add tier info to args for the handler
|
|
414
227
|
args._tier = access.tier;
|
|
228
|
+
args._firewallMode = access.firewallMode;
|
|
415
229
|
return handler(args);
|
|
416
230
|
};
|
|
417
231
|
}
|
|
418
232
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
233
|
+
// ============================================================================
|
|
234
|
+
// USER INFO
|
|
235
|
+
// ============================================================================
|
|
236
|
+
|
|
237
|
+
async function loadUserConfig() {
|
|
238
|
+
try {
|
|
239
|
+
const configPath = path.join(os.homedir(), '.vibecheck', 'credentials.json');
|
|
240
|
+
const data = await fs.readFile(configPath, 'utf-8');
|
|
241
|
+
return JSON.parse(data);
|
|
242
|
+
} catch {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
422
247
|
export async function getUserInfo() {
|
|
423
248
|
const config = await loadUserConfig();
|
|
424
|
-
|
|
249
|
+
|
|
250
|
+
if (!config?.apiKey) {
|
|
425
251
|
return {
|
|
426
252
|
authenticated: false,
|
|
427
253
|
tier: 'free',
|
|
428
|
-
|
|
254
|
+
tools: FREE_TOOLS,
|
|
255
|
+
firewallMode: 'observe',
|
|
429
256
|
};
|
|
430
257
|
}
|
|
431
258
|
|
|
432
|
-
const tier = getTierFromApiKey(config.apiKey);
|
|
433
|
-
const tierConfig = TIERS[tier];
|
|
259
|
+
const tier = await getTierFromApiKey(config.apiKey);
|
|
434
260
|
|
|
435
261
|
return {
|
|
436
262
|
authenticated: true,
|
|
437
|
-
tier,
|
|
263
|
+
tier: tier || 'free',
|
|
438
264
|
email: config.email,
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
limits: tierConfig.limits,
|
|
442
|
-
mcpTools: tierConfig.mcpTools,
|
|
265
|
+
tools: tier === 'pro' ? ALL_TOOLS : FREE_TOOLS,
|
|
266
|
+
firewallMode: getFirewallMode(tier || 'free'),
|
|
443
267
|
};
|
|
444
268
|
}
|
|
445
269
|
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
*/
|
|
449
|
-
export async function getAvailableMcpTools(providedApiKey = null) {
|
|
450
|
-
const userConfig = await loadUserConfig();
|
|
451
|
-
const apiKey = providedApiKey || userConfig?.apiKey;
|
|
452
|
-
|
|
453
|
-
const currentTier = getTierFromApiKey(apiKey);
|
|
454
|
-
const currentTierConfig = TIERS[currentTier];
|
|
455
|
-
|
|
456
|
-
const allowedTools = new Set();
|
|
457
|
-
|
|
458
|
-
// Accumulate tools from current tier and all lower tiers
|
|
459
|
-
for (const [tierName, tierConfig] of Object.entries(TIERS)) {
|
|
460
|
-
if (tierConfig.order <= currentTierConfig.order) {
|
|
461
|
-
if (tierConfig.mcpTools) {
|
|
462
|
-
if (tierConfig.mcpTools.includes('*')) {
|
|
463
|
-
return { tier: currentTier, tools: ['*'], unlimited: true };
|
|
464
|
-
}
|
|
465
|
-
tierConfig.mcpTools.forEach(t => allowedTools.add(t));
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
|
|
270
|
+
export async function getAvailableMcpTools(apiKey) {
|
|
271
|
+
const tier = apiKey ? await getTierFromApiKey(apiKey) : 'free';
|
|
470
272
|
return {
|
|
471
|
-
tier:
|
|
472
|
-
tools:
|
|
473
|
-
|
|
273
|
+
tier: tier || 'free',
|
|
274
|
+
tools: (tier === 'pro') ? ALL_TOOLS : FREE_TOOLS,
|
|
275
|
+
firewallMode: getFirewallMode(tier || 'free'),
|
|
474
276
|
};
|
|
475
277
|
}
|
|
278
|
+
|
|
279
|
+
// Legacy exports for backward compatibility
|
|
280
|
+
export async function getFeatureAccessStatus(featureName, apiKey) {
|
|
281
|
+
return getMcpToolAccess(featureName, apiKey);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function withMcpToolCheck(toolName, handler) {
|
|
285
|
+
return withTierCheck(toolName, handler);
|
|
286
|
+
}
|