vibecheck-mcp-server 3.1.3 ā 3.1.6
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/index.js +150 -18
- package/package.json +2 -2
- package/premium-tools.js +13 -13
- package/tier-auth.js +292 -27
- package/vibecheck-tools.js +9 -9
package/index.js
CHANGED
|
@@ -89,6 +89,9 @@ import { TRUTH_FIREWALL_TOOLS, handleTruthFirewallTool } from "./truth-firewall-
|
|
|
89
89
|
// Import Consolidated Tools (15 focused tools - recommended surface)
|
|
90
90
|
import { CONSOLIDATED_TOOLS, handleConsolidatedTool } from "./consolidated-tools.js";
|
|
91
91
|
|
|
92
|
+
// Import tier auth for entitlement checking
|
|
93
|
+
import { checkFeatureAccess } from "./tier-auth.js";
|
|
94
|
+
|
|
92
95
|
// ============================================================================
|
|
93
96
|
// TOOL DEFINITIONS - Public Tools (Clean Product Surface)
|
|
94
97
|
// ============================================================================
|
|
@@ -300,7 +303,7 @@ const TOOLS = USE_CONSOLIDATED_TOOLS ? [
|
|
|
300
303
|
// 3. GATE - Enforce truth in CI
|
|
301
304
|
{
|
|
302
305
|
name: "vibecheck.gate",
|
|
303
|
-
description: "š¦ Enforce truth in CI ā fail builds on policy violations",
|
|
306
|
+
description: "š¦ Enforce truth in CI ā fail builds on policy violations (STARTER tier)",
|
|
304
307
|
inputSchema: {
|
|
305
308
|
type: "object",
|
|
306
309
|
properties: {
|
|
@@ -327,7 +330,7 @@ const TOOLS = USE_CONSOLIDATED_TOOLS ? [
|
|
|
327
330
|
{
|
|
328
331
|
name: "vibecheck.fix",
|
|
329
332
|
description:
|
|
330
|
-
"š§ Fix Missions v1 ā AI-powered surgical fixes with proof verification loop",
|
|
333
|
+
"š§ Fix Missions v1 ā AI-powered surgical fixes with proof verification loop. --apply and --autopilot require PRO tier ($99/mo).",
|
|
331
334
|
inputSchema: {
|
|
332
335
|
type: "object",
|
|
333
336
|
properties: {
|
|
@@ -396,7 +399,7 @@ const TOOLS = USE_CONSOLIDATED_TOOLS ? [
|
|
|
396
399
|
// 7. PROVE - One Command Reality Proof (orchestrates ctx ā reality ā ship ā fix)
|
|
397
400
|
{
|
|
398
401
|
name: "vibecheck.prove",
|
|
399
|
-
description: "š¬ One Command Reality Proof ā orchestrates ctx ā reality ā ship ā fix loop until SHIP or stuck",
|
|
402
|
+
description: "š¬ One Command Reality Proof ā orchestrates ctx ā reality ā ship ā fix loop until SHIP or stuck (PRO tier)",
|
|
400
403
|
inputSchema: {
|
|
401
404
|
type: "object",
|
|
402
405
|
properties: {
|
|
@@ -593,11 +596,11 @@ const TOOLS = USE_CONSOLIDATED_TOOLS ? [
|
|
|
593
596
|
},
|
|
594
597
|
},
|
|
595
598
|
|
|
596
|
-
// 13. AUTOPILOT PLAN - Generate fix plan (
|
|
599
|
+
// 13. AUTOPILOT PLAN - Generate fix plan (PRO tier)
|
|
597
600
|
{
|
|
598
601
|
name: "vibecheck.autopilot_plan",
|
|
599
602
|
description:
|
|
600
|
-
"š¤ Autopilot Plan ā scan codebase, group issues into fix packs, estimate risk (
|
|
603
|
+
"š¤ Autopilot Plan ā scan codebase, group issues into fix packs, estimate risk (PRO tier)",
|
|
601
604
|
inputSchema: {
|
|
602
605
|
type: "object",
|
|
603
606
|
properties: {
|
|
@@ -620,11 +623,11 @@ const TOOLS = USE_CONSOLIDATED_TOOLS ? [
|
|
|
620
623
|
},
|
|
621
624
|
},
|
|
622
625
|
|
|
623
|
-
// 14. AUTOPILOT APPLY - Apply fixes (
|
|
626
|
+
// 14. AUTOPILOT APPLY - Apply fixes (PRO tier)
|
|
624
627
|
{
|
|
625
628
|
name: "vibecheck.autopilot_apply",
|
|
626
629
|
description:
|
|
627
|
-
"š§ Autopilot Apply ā apply fix packs with verification, re-scan to confirm (
|
|
630
|
+
"š§ Autopilot Apply ā apply fix packs with verification, re-scan to confirm (PRO tier)",
|
|
628
631
|
inputSchema: {
|
|
629
632
|
type: "object",
|
|
630
633
|
properties: {
|
|
@@ -661,7 +664,7 @@ const TOOLS = USE_CONSOLIDATED_TOOLS ? [
|
|
|
661
664
|
{
|
|
662
665
|
name: "vibecheck.badge",
|
|
663
666
|
description:
|
|
664
|
-
"š
Ship Badge ā generate a badge for README/PR showing scan status",
|
|
667
|
+
"š
Ship Badge ā generate a badge for README/PR showing scan status (STARTER tier)",
|
|
665
668
|
inputSchema: {
|
|
666
669
|
type: "object",
|
|
667
670
|
properties: {
|
|
@@ -1046,8 +1049,27 @@ class VibecheckMCP {
|
|
|
1046
1049
|
return { content: [{ type: "text", text }] };
|
|
1047
1050
|
}
|
|
1048
1051
|
|
|
1049
|
-
error(text) {
|
|
1050
|
-
|
|
1052
|
+
error(text, options = {}) {
|
|
1053
|
+
const { code, suggestion, nextSteps = [] } = options;
|
|
1054
|
+
|
|
1055
|
+
let errorText = `ā ${text}`;
|
|
1056
|
+
|
|
1057
|
+
if (code) {
|
|
1058
|
+
errorText += `\n\n**Error Code:** \`${code}\``;
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
if (suggestion) {
|
|
1062
|
+
errorText += `\n\nš” **Suggestion:** ${suggestion}`;
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
if (nextSteps.length > 0) {
|
|
1066
|
+
errorText += `\n\n**Next Steps:**\n`;
|
|
1067
|
+
nextSteps.forEach((step, i) => {
|
|
1068
|
+
errorText += `${i + 1}. ${step}\n`;
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
return { content: [{ type: "text", text: errorText }], isError: true };
|
|
1051
1073
|
}
|
|
1052
1074
|
|
|
1053
1075
|
// Validate project path exists and is accessible
|
|
@@ -1055,11 +1077,29 @@ class VibecheckMCP {
|
|
|
1055
1077
|
try {
|
|
1056
1078
|
const stats = require("fs").statSync(projectPath);
|
|
1057
1079
|
if (!stats.isDirectory()) {
|
|
1058
|
-
return {
|
|
1080
|
+
return {
|
|
1081
|
+
valid: false,
|
|
1082
|
+
error: `Path is not a directory: ${projectPath}`,
|
|
1083
|
+
suggestion: "Provide a directory path, not a file",
|
|
1084
|
+
nextSteps: [
|
|
1085
|
+
"Check the path you provided",
|
|
1086
|
+
"Ensure it points to a project directory",
|
|
1087
|
+
],
|
|
1088
|
+
};
|
|
1059
1089
|
}
|
|
1060
1090
|
return { valid: true };
|
|
1061
1091
|
} catch (e) {
|
|
1062
|
-
return {
|
|
1092
|
+
return {
|
|
1093
|
+
valid: false,
|
|
1094
|
+
error: `Cannot access path: ${projectPath}`,
|
|
1095
|
+
code: e.code || "PATH_ACCESS_ERROR",
|
|
1096
|
+
suggestion: "Check that the path exists and you have read permissions",
|
|
1097
|
+
nextSteps: [
|
|
1098
|
+
"Verify the path is correct",
|
|
1099
|
+
"Check file permissions",
|
|
1100
|
+
"Ensure the directory exists",
|
|
1101
|
+
],
|
|
1102
|
+
};
|
|
1063
1103
|
}
|
|
1064
1104
|
}
|
|
1065
1105
|
|
|
@@ -1067,6 +1107,16 @@ class VibecheckMCP {
|
|
|
1067
1107
|
// SCAN
|
|
1068
1108
|
// ============================================================================
|
|
1069
1109
|
async handleScan(projectPath, args) {
|
|
1110
|
+
// Validate project path first
|
|
1111
|
+
const validation = this.validateProjectPath(projectPath);
|
|
1112
|
+
if (!validation.valid) {
|
|
1113
|
+
return this.error(validation.error, {
|
|
1114
|
+
code: validation.code || "INVALID_PATH",
|
|
1115
|
+
suggestion: validation.suggestion,
|
|
1116
|
+
nextSteps: validation.nextSteps || [],
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1070
1120
|
const profile = args?.profile || "quick";
|
|
1071
1121
|
const format = args?.format || "text";
|
|
1072
1122
|
const only = args?.only;
|
|
@@ -1105,18 +1155,38 @@ class VibecheckMCP {
|
|
|
1105
1155
|
}
|
|
1106
1156
|
|
|
1107
1157
|
output += `\nš **Report:** .vibecheck/report.html\n`;
|
|
1158
|
+
output += "\n---\n_Context Enhanced by vibecheck AI_\n";
|
|
1159
|
+
return this.success(output);
|
|
1108
1160
|
} catch (err) {
|
|
1109
|
-
|
|
1161
|
+
return this.error(`Scan failed: ${err.message}`, {
|
|
1162
|
+
code: "SCAN_ERROR",
|
|
1163
|
+
suggestion: "Check that the project path is valid and contains scanable code",
|
|
1164
|
+
nextSteps: [
|
|
1165
|
+
"Verify the project path is correct",
|
|
1166
|
+
"Ensure you have read permissions",
|
|
1167
|
+
"Check that required dependencies are installed",
|
|
1168
|
+
"Try running: vibecheck scan --help",
|
|
1169
|
+
],
|
|
1170
|
+
});
|
|
1110
1171
|
}
|
|
1111
|
-
|
|
1112
|
-
output += "\n---\n_Context Enhanced by vibecheck AI_\n";
|
|
1113
|
-
return this.success(output);
|
|
1114
1172
|
}
|
|
1115
1173
|
|
|
1116
1174
|
// ============================================================================
|
|
1117
1175
|
// GATE
|
|
1118
1176
|
// ============================================================================
|
|
1119
1177
|
async handleGate(projectPath, args) {
|
|
1178
|
+
// Check tier access (STARTER tier required)
|
|
1179
|
+
const access = await checkFeatureAccess("gate", args?.apiKey);
|
|
1180
|
+
if (!access.hasAccess) {
|
|
1181
|
+
return {
|
|
1182
|
+
content: [{
|
|
1183
|
+
type: "text",
|
|
1184
|
+
text: `š« UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}`
|
|
1185
|
+
}],
|
|
1186
|
+
isError: true
|
|
1187
|
+
};
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1120
1190
|
const policy = args?.policy || "strict";
|
|
1121
1191
|
|
|
1122
1192
|
let output = "# š¦ vibecheck Gate\n\n";
|
|
@@ -1148,6 +1218,20 @@ class VibecheckMCP {
|
|
|
1148
1218
|
// FIX MISSIONS v1
|
|
1149
1219
|
// ============================================================================
|
|
1150
1220
|
async handleFix(projectPath, args) {
|
|
1221
|
+
// Check tier access for --apply and --autopilot (PRO tier required)
|
|
1222
|
+
if (args?.apply || args?.autopilot) {
|
|
1223
|
+
const access = await checkFeatureAccess("fix.apply_patches", args?.apiKey);
|
|
1224
|
+
if (!access.hasAccess) {
|
|
1225
|
+
return {
|
|
1226
|
+
content: [{
|
|
1227
|
+
type: "text",
|
|
1228
|
+
text: `š« UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}\n\nNote: --prompt-only mode is available for FREE tier.`
|
|
1229
|
+
}],
|
|
1230
|
+
isError: true
|
|
1231
|
+
};
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1151
1235
|
const mode = args?.autopilot ? "Autopilot" :
|
|
1152
1236
|
args?.apply ? "Apply" :
|
|
1153
1237
|
args?.promptOnly ? "Prompt Only" : "Plan";
|
|
@@ -1319,6 +1403,18 @@ class VibecheckMCP {
|
|
|
1319
1403
|
// PROVE - One Command Reality Proof
|
|
1320
1404
|
// ============================================================================
|
|
1321
1405
|
async handleProve(projectPath, args) {
|
|
1406
|
+
// Check tier access (PRO tier required)
|
|
1407
|
+
const access = await checkFeatureAccess("prove", args?.apiKey);
|
|
1408
|
+
if (!access.hasAccess) {
|
|
1409
|
+
return {
|
|
1410
|
+
content: [{
|
|
1411
|
+
type: "text",
|
|
1412
|
+
text: `š« UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}`
|
|
1413
|
+
}],
|
|
1414
|
+
isError: true
|
|
1415
|
+
};
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1322
1418
|
let output = "# š¬ vibecheck prove\n\n";
|
|
1323
1419
|
output += `**URL:** ${args?.url || "(static only)"}\n`;
|
|
1324
1420
|
output += `**Max Fix Rounds:** ${args?.maxFixRounds || 3}\n\n`;
|
|
@@ -1787,9 +1883,21 @@ class VibecheckMCP {
|
|
|
1787
1883
|
}
|
|
1788
1884
|
|
|
1789
1885
|
// ============================================================================
|
|
1790
|
-
// AUTOPILOT PLAN - Generate fix plan (
|
|
1886
|
+
// AUTOPILOT PLAN - Generate fix plan (PRO tier)
|
|
1791
1887
|
// ============================================================================
|
|
1792
1888
|
async handleAutopilotPlan(projectPath, args) {
|
|
1889
|
+
// Check tier access (PRO tier required)
|
|
1890
|
+
const access = await checkFeatureAccess("fix.apply_patches", args?.apiKey);
|
|
1891
|
+
if (!access.hasAccess) {
|
|
1892
|
+
return {
|
|
1893
|
+
content: [{
|
|
1894
|
+
type: "text",
|
|
1895
|
+
text: `š« UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}`
|
|
1896
|
+
}],
|
|
1897
|
+
isError: true
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1793
1901
|
let output = "# š¤ vibecheck Autopilot Plan\n\n";
|
|
1794
1902
|
output += `**Path:** ${projectPath}\n`;
|
|
1795
1903
|
output += `**Profile:** ${args?.profile || "ship"}\n\n`;
|
|
@@ -1865,9 +1973,21 @@ class VibecheckMCP {
|
|
|
1865
1973
|
}
|
|
1866
1974
|
|
|
1867
1975
|
// ============================================================================
|
|
1868
|
-
// AUTOPILOT APPLY - Apply fixes (
|
|
1976
|
+
// AUTOPILOT APPLY - Apply fixes (PRO tier)
|
|
1869
1977
|
// ============================================================================
|
|
1870
1978
|
async handleAutopilotApply(projectPath, args) {
|
|
1979
|
+
// Check tier access (PRO tier required)
|
|
1980
|
+
const access = await checkFeatureAccess("fix.apply_patches", args?.apiKey);
|
|
1981
|
+
if (!access.hasAccess) {
|
|
1982
|
+
return {
|
|
1983
|
+
content: [{
|
|
1984
|
+
type: "text",
|
|
1985
|
+
text: `š« UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}`
|
|
1986
|
+
}],
|
|
1987
|
+
isError: true
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1871
1991
|
let output = "# š§ vibecheck Autopilot Apply\n\n";
|
|
1872
1992
|
output += `**Path:** ${projectPath}\n`;
|
|
1873
1993
|
output += `**Profile:** ${args?.profile || "ship"}\n`;
|
|
@@ -1919,6 +2039,18 @@ class VibecheckMCP {
|
|
|
1919
2039
|
// BADGE - Generate ship badge
|
|
1920
2040
|
// ============================================================================
|
|
1921
2041
|
async handleBadge(projectPath, args) {
|
|
2042
|
+
// Check tier access (STARTER tier required)
|
|
2043
|
+
const access = await checkFeatureAccess("badge", args?.apiKey);
|
|
2044
|
+
if (!access.hasAccess) {
|
|
2045
|
+
return {
|
|
2046
|
+
content: [{
|
|
2047
|
+
type: "text",
|
|
2048
|
+
text: `š« UPGRADE REQUIRED\n\n${access.reason}\n\nCurrent tier: ${access.tier}\nUpgrade at: ${access.upgradeUrl}`
|
|
2049
|
+
}],
|
|
2050
|
+
isError: true
|
|
2051
|
+
};
|
|
2052
|
+
}
|
|
2053
|
+
|
|
1922
2054
|
const format = args?.format || "svg";
|
|
1923
2055
|
|
|
1924
2056
|
let output = "# š
vibecheck Badge\n\n";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibecheck-mcp-server",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.6",
|
|
4
4
|
"description": "Professional MCP server for vibecheck - Intelligent development environment vibechecks",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"architecture"
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@modelcontextprotocol/sdk": "^0.
|
|
24
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
25
25
|
},
|
|
26
26
|
"engines": {
|
|
27
27
|
"node": ">=18.0.0"
|
package/premium-tools.js
CHANGED
|
@@ -417,19 +417,19 @@ export async function handlePremiumTool(name, args, logger) {
|
|
|
417
417
|
|
|
418
418
|
// Map premium tools to required features (all require starter+)
|
|
419
419
|
const featureMap = {
|
|
420
|
-
'run_ship': '
|
|
421
|
-
'run_reality': '
|
|
422
|
-
'run_mockproof': '
|
|
423
|
-
'run_airlock': '
|
|
424
|
-
'get_last_run': '
|
|
425
|
-
'open_artifact': '
|
|
426
|
-
'rerun_last_check': '
|
|
427
|
-
'run_doctor': '
|
|
428
|
-
'edit_policies': '
|
|
429
|
-
'explain_finding': '
|
|
430
|
-
'policy_patch': '
|
|
431
|
-
'enter_fix_mode': '
|
|
432
|
-
'get_status': '
|
|
420
|
+
'run_ship': 'ship', // ship check is FREE (static-only)
|
|
421
|
+
'run_reality': 'reality.preview', // reality preview is FREE, full requires STARTER+
|
|
422
|
+
'run_mockproof': 'reality.full', // mockproof requires STARTER+
|
|
423
|
+
'run_airlock': 'prove', // supply chain analysis requires PRO
|
|
424
|
+
'get_last_run': 'scan', // basic access - FREE
|
|
425
|
+
'open_artifact': 'scan', // basic access - FREE
|
|
426
|
+
'rerun_last_check': 'scan', // basic access - FREE
|
|
427
|
+
'run_doctor': 'doctor', // doctor is FREE
|
|
428
|
+
'edit_policies': 'gate', // policy editing requires STARTER
|
|
429
|
+
'explain_finding': 'scan', // explanations are FREE
|
|
430
|
+
'policy_patch': 'gate', // patching requires STARTER
|
|
431
|
+
'enter_fix_mode': 'fix.plan_only', // fix mode planning is FREE, apply requires PRO
|
|
432
|
+
'get_status': 'status' // status check is FREE
|
|
433
433
|
};
|
|
434
434
|
|
|
435
435
|
const requiredFeature = featureMap[name];
|
package/tier-auth.js
CHANGED
|
@@ -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: '
|
|
15
|
-
|
|
16
|
-
|
|
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: '
|
|
20
|
-
|
|
21
|
-
|
|
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: '
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
29
|
-
name: '
|
|
30
|
-
|
|
31
|
-
|
|
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 '
|
|
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
|
|
80
|
-
const
|
|
201
|
+
const currentTier = getTierFromApiKey(apiKey);
|
|
202
|
+
const currentTierConfig = TIERS[currentTier];
|
|
81
203
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
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}
|
|
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:
|
|
145
|
-
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
|
}
|
package/vibecheck-tools.js
CHANGED
|
@@ -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", //
|
|
290
|
-
"vibecheck.autofix": "
|
|
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];
|