@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,8 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Upsell Copy Module - Central copy generator for tier upgrades
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* All upgrade nudges flow through these functions.
|
|
4
|
+
* Simple 2-tier model: FREE and PRO ($69/mo)
|
|
6
5
|
*
|
|
7
6
|
* Rules:
|
|
8
7
|
* - Blunt, confident, minimal tone
|
|
@@ -49,163 +48,86 @@ const sym = {
|
|
|
49
48
|
};
|
|
50
49
|
|
|
51
50
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
52
|
-
// TIER
|
|
51
|
+
// SIMPLE 2-TIER CONFIG: FREE and PRO ($69/mo)
|
|
53
52
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
54
53
|
const TIER_LABELS = {
|
|
55
54
|
free: "FREE",
|
|
56
|
-
starter: "STARTER",
|
|
57
55
|
pro: "PRO",
|
|
58
|
-
complete: "COMPLETE",
|
|
59
56
|
};
|
|
60
57
|
|
|
61
58
|
const TIER_COLORS = {
|
|
62
59
|
free: c.green,
|
|
63
|
-
starter: c.cyan,
|
|
64
60
|
pro: c.magenta,
|
|
65
|
-
complete: c.yellow,
|
|
66
61
|
};
|
|
67
62
|
|
|
68
|
-
const PRICING_URL = "https://vibecheckai.dev";
|
|
63
|
+
const PRICING_URL = "https://vibecheckai.dev/pricing";
|
|
64
|
+
const PRO_PRICE = "$69/mo";
|
|
69
65
|
|
|
70
66
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
71
67
|
// DENIAL COPY - Command-specific reasons and alternatives
|
|
72
68
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
73
69
|
const DENIAL_COPY = {
|
|
74
70
|
ship: {
|
|
75
|
-
feature: "release
|
|
76
|
-
why: "
|
|
71
|
+
feature: "release verdict",
|
|
72
|
+
why: "SHIP/WARN/BLOCK verdict with evidence",
|
|
77
73
|
freeAlt: "vibecheck scan",
|
|
78
|
-
freeAltDesc: "static analysis",
|
|
74
|
+
freeAltDesc: "static analysis without verdict",
|
|
79
75
|
},
|
|
80
76
|
prove: {
|
|
81
|
-
feature: "proof
|
|
82
|
-
why: "
|
|
83
|
-
freeAlt: "vibecheck
|
|
84
|
-
freeAltDesc: "static
|
|
85
|
-
},
|
|
86
|
-
permissions: {
|
|
87
|
-
feature: "auth boundary / IDOR detection",
|
|
88
|
-
why: "Deep authorization matrix and IDOR analysis",
|
|
89
|
-
freeAlt: "vibecheck reality --verify-auth",
|
|
90
|
-
freeAltDesc: "basic auth boundary check",
|
|
91
|
-
},
|
|
92
|
-
"fix.apply_patches": {
|
|
93
|
-
feature: "patch generator / PR-ready diff",
|
|
94
|
-
why: "Apply LLM-generated patches automatically",
|
|
95
|
-
freeAlt: "vibecheck fix",
|
|
96
|
-
freeAltDesc: "plan-only mode",
|
|
77
|
+
feature: "runtime proof",
|
|
78
|
+
why: "Full runtime verification with evidence",
|
|
79
|
+
freeAlt: "vibecheck scan",
|
|
80
|
+
freeAltDesc: "static analysis",
|
|
97
81
|
},
|
|
98
82
|
fix: {
|
|
99
|
-
feature: "auto-fix
|
|
100
|
-
why: "
|
|
101
|
-
freeAlt: "vibecheck
|
|
102
|
-
freeAltDesc: "view
|
|
103
|
-
},
|
|
104
|
-
badge: {
|
|
105
|
-
feature: "status artifact",
|
|
106
|
-
why: "Verified ship badge for README",
|
|
107
|
-
freeAlt: "vibecheck report",
|
|
108
|
-
freeAltDesc: "HTML/MD report",
|
|
83
|
+
feature: "auto-fix",
|
|
84
|
+
why: "AI-powered fixes with --apply",
|
|
85
|
+
freeAlt: "vibecheck scan",
|
|
86
|
+
freeAltDesc: "view issues only",
|
|
109
87
|
},
|
|
110
88
|
gate: {
|
|
111
89
|
feature: "CI/CD gate",
|
|
112
90
|
why: "Block deploys on verification failures",
|
|
113
|
-
freeAlt: "vibecheck
|
|
114
|
-
freeAltDesc: "
|
|
115
|
-
},
|
|
116
|
-
pr: {
|
|
117
|
-
feature: "PR comment generator",
|
|
118
|
-
why: "Auto-generated PR comments with findings",
|
|
119
|
-
freeAlt: "vibecheck report --format md",
|
|
120
|
-
freeAltDesc: "markdown report",
|
|
91
|
+
freeAlt: "vibecheck scan",
|
|
92
|
+
freeAltDesc: "check before deploy",
|
|
121
93
|
},
|
|
122
|
-
|
|
123
|
-
feature: "
|
|
124
|
-
why: "
|
|
125
|
-
freeAlt: "vibecheck
|
|
126
|
-
freeAltDesc: "
|
|
94
|
+
badge: {
|
|
95
|
+
feature: "ship badge",
|
|
96
|
+
why: "Verified ship badge for README",
|
|
97
|
+
freeAlt: "vibecheck report",
|
|
98
|
+
freeAltDesc: "HTML/MD report",
|
|
127
99
|
},
|
|
128
|
-
|
|
129
|
-
feature: "
|
|
130
|
-
why: "
|
|
131
|
-
freeAlt: "vibecheck
|
|
132
|
-
freeAltDesc: "
|
|
100
|
+
reality: {
|
|
101
|
+
feature: "full runtime verification",
|
|
102
|
+
why: "Unlimited pages + auth boundary testing",
|
|
103
|
+
freeAlt: "vibecheck scan",
|
|
104
|
+
freeAltDesc: "static analysis",
|
|
133
105
|
},
|
|
134
106
|
share: {
|
|
135
|
-
feature: "share pack
|
|
107
|
+
feature: "share pack",
|
|
136
108
|
why: "Shareable proof bundle for PRs/docs",
|
|
137
109
|
freeAlt: "vibecheck report",
|
|
138
110
|
freeAltDesc: "local report",
|
|
139
111
|
},
|
|
140
112
|
"ai-test": {
|
|
141
|
-
feature: "
|
|
113
|
+
feature: "AI testing",
|
|
142
114
|
why: "AI-generated test coverage",
|
|
143
115
|
freeAlt: "vibecheck scan",
|
|
144
116
|
freeAltDesc: "static analysis",
|
|
145
117
|
},
|
|
146
|
-
replay: {
|
|
147
|
-
feature: "session replay",
|
|
148
|
-
why: "Record and replay user sessions",
|
|
149
|
-
freeAlt: "vibecheck reality",
|
|
150
|
-
freeAltDesc: "one-time runtime proof",
|
|
151
|
-
},
|
|
152
|
-
graph: {
|
|
153
|
-
feature: "reality proof graph",
|
|
154
|
-
why: "Visual dependency and proof graph",
|
|
155
|
-
freeAlt: "vibecheck ctx",
|
|
156
|
-
freeAltDesc: "truthpack",
|
|
157
|
-
},
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
161
|
-
// CAPS COPY - Downgrade mode descriptions
|
|
162
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
163
|
-
const CAPS_COPY = {
|
|
164
|
-
"reality.preview": {
|
|
165
|
-
short: "5 pages, no auth boundary",
|
|
166
|
-
full: "Preview mode: 5 pages max, 20 clicks, no auth boundary verification",
|
|
167
|
-
upgradeBenefit: "Unlimited pages + full auth boundary testing",
|
|
168
|
-
},
|
|
169
|
-
"fix.plan_only": {
|
|
170
|
-
short: "plan-only, no apply",
|
|
171
|
-
full: "Plan mode: generates fix missions but cannot apply patches",
|
|
172
|
-
upgradeBenefit: "Apply patches automatically with --apply",
|
|
173
|
-
},
|
|
174
|
-
"report.html_md": {
|
|
175
|
-
short: "HTML/MD only",
|
|
176
|
-
full: "Basic formats: HTML and Markdown reports only",
|
|
177
|
-
upgradeBenefit: "SARIF, CSV, and compliance pack exports",
|
|
178
|
-
},
|
|
179
|
-
"ship.static": {
|
|
180
|
-
short: "static-only",
|
|
181
|
-
full: "Static analysis only, no runtime verification",
|
|
182
|
-
upgradeBenefit: "Full runtime + static verification",
|
|
183
|
-
},
|
|
184
|
-
"mcp.help_only": {
|
|
185
|
-
short: "help and print-config only",
|
|
186
|
-
full: "MCP server limited to help and config commands",
|
|
187
|
-
upgradeBenefit: "Full MCP server with all tools",
|
|
188
|
-
},
|
|
189
118
|
};
|
|
190
119
|
|
|
191
120
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
192
121
|
// formatDenied() - Hard denial message
|
|
193
122
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
194
123
|
/**
|
|
195
|
-
* Format a denial message for a command that requires
|
|
124
|
+
* Format a denial message for a command that requires PRO.
|
|
196
125
|
*
|
|
197
126
|
* @param {string} cmd - The command that was denied
|
|
198
127
|
* @param {object} opts - Options
|
|
199
|
-
* @param {string} opts.currentTier - User's current tier
|
|
200
|
-
* @param {string} opts.requiredTier - Required tier for the command
|
|
201
|
-
* @param {string} [opts.reason] - Additional context
|
|
202
|
-
* @param {string} [opts.suggestedNext] - Suggested next command
|
|
203
|
-
* @param {string} [opts.freeAlternative] - Free alternative command
|
|
204
128
|
* @returns {string} Formatted denial message
|
|
205
129
|
*/
|
|
206
130
|
function formatDenied(cmd, opts = {}) {
|
|
207
|
-
const { currentTier = "free", requiredTier = "pro" } = opts;
|
|
208
|
-
|
|
209
131
|
const copy = DENIAL_COPY[cmd] || {
|
|
210
132
|
feature: cmd,
|
|
211
133
|
why: `${cmd} command`,
|
|
@@ -213,80 +135,42 @@ function formatDenied(cmd, opts = {}) {
|
|
|
213
135
|
freeAltDesc: null,
|
|
214
136
|
};
|
|
215
137
|
|
|
216
|
-
const reqColor = TIER_COLORS[requiredTier] || c.yellow;
|
|
217
|
-
const reqLabel = TIER_LABELS[requiredTier] || requiredTier.toUpperCase();
|
|
218
|
-
const curLabel = TIER_LABELS[currentTier] || currentTier.toUpperCase();
|
|
219
|
-
|
|
220
138
|
let msg = `
|
|
221
|
-
${c.red}${c.bold}${sym.lock}
|
|
139
|
+
${c.red}${c.bold}${sym.lock} PRO FEATURE${c.reset}
|
|
222
140
|
|
|
223
|
-
${c.bold}
|
|
224
|
-
${c.bold}
|
|
225
|
-
${c.bold}
|
|
226
|
-
${c.bold}You have:${c.reset} ${c.dim}${curLabel}${c.reset}
|
|
141
|
+
${c.bold}Command:${c.reset} ${c.yellow}${cmd}${c.reset}
|
|
142
|
+
${c.bold}Feature:${c.reset} ${copy.feature}
|
|
143
|
+
${c.bold}Why:${c.reset} ${copy.why}
|
|
227
144
|
`;
|
|
228
145
|
|
|
229
146
|
// Free alternative
|
|
230
147
|
if (copy.freeAlt) {
|
|
231
148
|
msg += `
|
|
232
|
-
${c.green}${sym.arrow} Free
|
|
149
|
+
${c.green}${sym.arrow} Free:${c.reset} ${c.cyan}${copy.freeAlt}${c.reset} ${c.dim}(${copy.freeAltDesc})${c.reset}`;
|
|
233
150
|
}
|
|
234
151
|
|
|
235
152
|
// Upgrade CTA
|
|
236
153
|
msg += `
|
|
237
|
-
${c.bold}${sym.arrow} Upgrade:${c.reset}
|
|
154
|
+
${c.bold}${sym.arrow} Upgrade:${c.reset} PRO ${PRO_PRICE} ${sym.arrow} ${PRICING_URL}
|
|
238
155
|
`;
|
|
239
156
|
|
|
240
157
|
return msg;
|
|
241
158
|
}
|
|
242
159
|
|
|
243
160
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
244
|
-
//
|
|
161
|
+
// formatCapHit() - Limit reached notice
|
|
245
162
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
246
163
|
/**
|
|
247
|
-
* Format a
|
|
164
|
+
* Format a cap-hit notice when user reaches a limit.
|
|
248
165
|
*
|
|
249
166
|
* @param {string} cmd - The command being run
|
|
250
167
|
* @param {object} opts - Options
|
|
251
|
-
* @param {string} opts.currentTier - User's current tier
|
|
252
|
-
* @param {string} opts.effectiveMode - The downgraded mode being used
|
|
253
|
-
* @param {object} [opts.caps] - Specific caps applied
|
|
254
|
-
* @returns {string} Formatted downgrade notice
|
|
255
|
-
*/
|
|
256
|
-
function formatDowngrade(cmd, opts = {}) {
|
|
257
|
-
const { currentTier = "free", effectiveMode, caps } = opts;
|
|
258
|
-
|
|
259
|
-
const copy = CAPS_COPY[effectiveMode] || {
|
|
260
|
-
short: effectiveMode || "limited mode",
|
|
261
|
-
full: `Running in ${effectiveMode || "limited"} mode`,
|
|
262
|
-
upgradeBenefit: "Full access",
|
|
263
|
-
};
|
|
264
|
-
|
|
265
|
-
const curLabel = TIER_LABELS[currentTier] || currentTier.toUpperCase();
|
|
266
|
-
|
|
267
|
-
// Single line notice for start of run
|
|
268
|
-
let shortNotice = `${c.yellow}${sym.warning}${c.reset} Running in ${c.yellow}${curLabel}${c.reset} mode: ${c.dim}${copy.short}${c.reset}`;
|
|
269
|
-
|
|
270
|
-
return shortNotice;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* Format a cap-hit notice when user reaches a limit during execution.
|
|
275
|
-
*
|
|
276
|
-
* @param {string} cmd - The command being run
|
|
277
|
-
* @param {object} opts - Options
|
|
278
|
-
* @param {string} opts.limitType - Type of limit hit (e.g., "pages", "clicks")
|
|
279
|
-
* @param {number} opts.limitValue - The limit value
|
|
280
|
-
* @param {string} opts.upgradeTier - Tier to upgrade to
|
|
281
168
|
* @returns {string} Formatted cap-hit message
|
|
282
169
|
*/
|
|
283
170
|
function formatCapHit(cmd, opts = {}) {
|
|
284
|
-
const { limitType = "limit", limitValue
|
|
285
|
-
|
|
286
|
-
const tierColor = TIER_COLORS[upgradeTier] || c.magenta;
|
|
287
|
-
const tierLabel = TIER_LABELS[upgradeTier] || upgradeTier.toUpperCase();
|
|
171
|
+
const { limitType = "limit", limitValue } = opts;
|
|
288
172
|
|
|
289
|
-
return `${c.yellow}${sym.warning}${c.reset}
|
|
173
|
+
return `${c.yellow}${sym.warning}${c.reset} FREE ${limitType} cap (${limitValue}). Upgrade to ${c.magenta}PRO${c.reset} (${PRO_PRICE}) ${sym.arrow} ${PRICING_URL}`;
|
|
290
174
|
}
|
|
291
175
|
|
|
292
176
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -296,12 +180,6 @@ function formatCapHit(cmd, opts = {}) {
|
|
|
296
180
|
* Format an earned upsell shown at end of run.
|
|
297
181
|
*
|
|
298
182
|
* @param {object} opts - Options
|
|
299
|
-
* @param {string} opts.cmd - The command that was run
|
|
300
|
-
* @param {string} opts.verdict - The verdict (SHIP/WARN/BLOCK)
|
|
301
|
-
* @param {Array} [opts.topIssues] - Top 3 issues to show
|
|
302
|
-
* @param {string} [opts.withheldArtifact] - Artifact that was withheld (e.g., "badge")
|
|
303
|
-
* @param {string} [opts.upgradeTier] - Tier to suggest upgrading to
|
|
304
|
-
* @param {string} [opts.why] - Why this upsell is relevant
|
|
305
183
|
* @returns {string} Formatted earned upsell message
|
|
306
184
|
*/
|
|
307
185
|
function formatEarnedUpsell(opts = {}) {
|
|
@@ -310,15 +188,11 @@ function formatEarnedUpsell(opts = {}) {
|
|
|
310
188
|
verdict,
|
|
311
189
|
topIssues = [],
|
|
312
190
|
withheldArtifact,
|
|
313
|
-
upgradeTier = "pro",
|
|
314
191
|
why,
|
|
315
192
|
currentTier = "free",
|
|
316
193
|
suggestedCmd,
|
|
317
194
|
} = opts;
|
|
318
195
|
|
|
319
|
-
const tierColor = TIER_COLORS[upgradeTier] || c.magenta;
|
|
320
|
-
const tierLabel = TIER_LABELS[upgradeTier] || upgradeTier.toUpperCase();
|
|
321
|
-
|
|
322
196
|
let msg = "";
|
|
323
197
|
|
|
324
198
|
// Badge withheld case
|
|
@@ -344,16 +218,16 @@ ${c.yellow}${sym.badge} Badge withheld${c.reset} ${c.dim}(verdict: ${verdict})${
|
|
|
344
218
|
return msg;
|
|
345
219
|
}
|
|
346
220
|
|
|
347
|
-
// Fix
|
|
221
|
+
// Fix withheld case
|
|
348
222
|
if (cmd === "fix" && withheldArtifact === "apply") {
|
|
349
223
|
msg += `
|
|
350
224
|
${c.dim}─────────────────────────────────────────────────────────────${c.reset}
|
|
351
225
|
${c.yellow}${sym.lightning} Fix plan generated${c.reset}
|
|
352
226
|
|
|
353
|
-
Patches ready but ${c.yellow}--apply${c.reset} requires ${
|
|
227
|
+
Patches ready but ${c.yellow}--apply${c.reset} requires ${c.magenta}PRO${c.reset}.
|
|
354
228
|
|
|
355
229
|
${c.green}${sym.arrow} Review:${c.reset} .vibecheck/missions/
|
|
356
|
-
${c.bold}${sym.arrow} Apply:${c.reset} Upgrade ${sym.arrow} ${PRICING_URL}
|
|
230
|
+
${c.bold}${sym.arrow} Apply:${c.reset} Upgrade to PRO ${sym.arrow} ${PRICING_URL}
|
|
357
231
|
`;
|
|
358
232
|
return msg;
|
|
359
233
|
}
|
|
@@ -365,7 +239,7 @@ ${c.dim}────────────────────────
|
|
|
365
239
|
${c.yellow}${sym.warning} Preview complete${c.reset}
|
|
366
240
|
|
|
367
241
|
Crawled ${topIssues.length || 5} pages (FREE limit).
|
|
368
|
-
${
|
|
242
|
+
${c.magenta}PRO${c.reset} unlocks unlimited pages + auth boundary testing.
|
|
369
243
|
|
|
370
244
|
${c.bold}${sym.arrow} Upgrade:${c.reset} ${PRICING_URL}
|
|
371
245
|
`;
|
|
@@ -378,7 +252,7 @@ ${c.yellow}${sym.warning} Preview complete${c.reset}
|
|
|
378
252
|
${c.dim}─────────────────────────────────────────────────────────────${c.reset}
|
|
379
253
|
${c.cyan}${sym.star} ${why}${c.reset}
|
|
380
254
|
|
|
381
|
-
${
|
|
255
|
+
${c.magenta}PRO${c.reset} (${PRO_PRICE}) unlocks this feature.
|
|
382
256
|
${c.bold}${sym.arrow} Upgrade:${c.reset} ${PRICING_URL}
|
|
383
257
|
`;
|
|
384
258
|
}
|
|
@@ -391,11 +265,6 @@ ${c.cyan}${sym.star} ${why}${c.reset}
|
|
|
391
265
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
392
266
|
/**
|
|
393
267
|
* Format badge withheld message with top issues.
|
|
394
|
-
*
|
|
395
|
-
* @param {string} verdict - Current verdict
|
|
396
|
-
* @param {Array} findings - All findings
|
|
397
|
-
* @param {string} currentTier - User's tier
|
|
398
|
-
* @returns {string} Formatted message
|
|
399
268
|
*/
|
|
400
269
|
function formatBadgeWithheld(verdict, findings = [], currentTier = "free") {
|
|
401
270
|
const blockers = findings.filter(f => f.severity === "BLOCK").slice(0, 3);
|
|
@@ -418,12 +287,11 @@ ${c.yellow}${sym.badge} Badge withheld${c.reset}
|
|
|
418
287
|
});
|
|
419
288
|
}
|
|
420
289
|
|
|
421
|
-
// Suggest fix command
|
|
422
|
-
|
|
423
|
-
if (canFix) {
|
|
290
|
+
// Suggest fix command
|
|
291
|
+
if (currentTier === "pro") {
|
|
424
292
|
msg += `\n ${c.green}${sym.arrow} Run:${c.reset} ${c.cyan}vibecheck fix${c.reset}\n`;
|
|
425
293
|
} else {
|
|
426
|
-
msg += `\n ${c.
|
|
294
|
+
msg += `\n ${c.dim}Upgrade to PRO for auto-fix ${sym.arrow} ${PRICING_URL}${c.reset}\n`;
|
|
427
295
|
}
|
|
428
296
|
|
|
429
297
|
return msg;
|
|
@@ -434,46 +302,34 @@ ${c.yellow}${sym.badge} Badge withheld${c.reset}
|
|
|
434
302
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
435
303
|
/**
|
|
436
304
|
* Format next step suggestions based on current command and result.
|
|
437
|
-
*
|
|
438
|
-
* @param {string} cmd - Command just run
|
|
439
|
-
* @param {string} verdict - Result/verdict
|
|
440
|
-
* @param {string} currentTier - User's tier
|
|
441
|
-
* @returns {string} Next step suggestion
|
|
442
305
|
*/
|
|
443
306
|
function formatNextSteps(cmd, verdict, currentTier = "free") {
|
|
444
307
|
const steps = [];
|
|
308
|
+
const isPro = currentTier === "pro";
|
|
445
309
|
|
|
446
310
|
switch (cmd) {
|
|
447
311
|
case "scan":
|
|
448
|
-
if (
|
|
312
|
+
if (isPro) {
|
|
449
313
|
steps.push({ cmd: "vibecheck ship", desc: "get verdict" });
|
|
314
|
+
steps.push({ cmd: "vibecheck fix", desc: "auto-fix issues" });
|
|
450
315
|
} else {
|
|
451
|
-
steps.push({ cmd: "vibecheck
|
|
452
|
-
steps.push({ cmd: "vibecheck prove --url <url>", desc: "full proof loop" });
|
|
316
|
+
steps.push({ cmd: "vibecheck report", desc: "export report" });
|
|
453
317
|
}
|
|
454
318
|
break;
|
|
455
319
|
|
|
456
320
|
case "ship":
|
|
457
|
-
if (verdict === "SHIP") {
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
}
|
|
461
|
-
steps.push({ cmd: "vibecheck report", desc: "export report" });
|
|
462
|
-
} else {
|
|
463
|
-
if (currentTier === "free") {
|
|
464
|
-
steps.push({ cmd: "vibecheck fix --plan-only", desc: "view fix plan" });
|
|
465
|
-
} else {
|
|
466
|
-
steps.push({ cmd: "vibecheck fix", desc: "auto-fix issues" });
|
|
467
|
-
}
|
|
321
|
+
if (verdict === "SHIP" && isPro) {
|
|
322
|
+
steps.push({ cmd: "vibecheck badge", desc: "generate badge" });
|
|
323
|
+
} else if (isPro) {
|
|
324
|
+
steps.push({ cmd: "vibecheck fix", desc: "auto-fix issues" });
|
|
468
325
|
}
|
|
326
|
+
steps.push({ cmd: "vibecheck report", desc: "export report" });
|
|
469
327
|
break;
|
|
470
328
|
|
|
471
329
|
case "fix":
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
case "reality":
|
|
476
|
-
steps.push({ cmd: "vibecheck ship", desc: "get verdict with runtime proof" });
|
|
330
|
+
if (isPro) {
|
|
331
|
+
steps.push({ cmd: "vibecheck ship", desc: "verify fixes" });
|
|
332
|
+
}
|
|
477
333
|
break;
|
|
478
334
|
}
|
|
479
335
|
|
|
@@ -485,6 +341,48 @@ function formatNextSteps(cmd, verdict, currentTier = "free") {
|
|
|
485
341
|
return msg;
|
|
486
342
|
}
|
|
487
343
|
|
|
344
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
345
|
+
// formatDowngrade() - Caps/downgrade notice (for free tier)
|
|
346
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
347
|
+
function formatDowngrade(cmd, opts = {}) {
|
|
348
|
+
const { currentTier = "free" } = opts;
|
|
349
|
+
|
|
350
|
+
if (currentTier === "pro") return "";
|
|
351
|
+
|
|
352
|
+
return `${c.yellow}${sym.warning}${c.reset} Running in ${c.yellow}FREE${c.reset} mode ${c.dim}(limited features)${c.reset}`;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
356
|
+
// formatSoftUpsell() - Non-intrusive end-of-run upsell
|
|
357
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
358
|
+
function formatSoftUpsell(cmd, opts = {}) {
|
|
359
|
+
const { currentTier = "free" } = opts;
|
|
360
|
+
|
|
361
|
+
if (currentTier === "pro") return "";
|
|
362
|
+
|
|
363
|
+
return `${c.dim}${sym.star} ${c.magenta}PRO${c.reset}${c.dim} (${PRO_PRICE}): Fix, Prove & Enforce ${sym.arrow} ${PRICING_URL}${c.reset}`;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
367
|
+
// formatWorkflowUpsell() - Workflow suggestion with upsell
|
|
368
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
369
|
+
function formatWorkflowUpsell(completedCmd, currentTier = "free") {
|
|
370
|
+
if (currentTier === "pro") {
|
|
371
|
+
// PRO users get next command suggestion without upsell
|
|
372
|
+
const NEXT_CMDS = {
|
|
373
|
+
scan: "vibecheck ship",
|
|
374
|
+
ship: "vibecheck badge",
|
|
375
|
+
fix: "vibecheck ship",
|
|
376
|
+
reality: "vibecheck prove",
|
|
377
|
+
};
|
|
378
|
+
const next = NEXT_CMDS[completedCmd];
|
|
379
|
+
return next ? `${c.dim}Next:${c.reset} ${c.cyan}${next}${c.reset}` : "";
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// FREE users get upsell
|
|
383
|
+
return `${c.dim}Next:${c.reset} ${c.cyan}vibecheck report${c.reset} ${c.dim}or${c.reset} ${c.magenta}PRO${c.reset}${c.dim}: ship, fix, prove, gate, badge${c.reset}`;
|
|
384
|
+
}
|
|
385
|
+
|
|
488
386
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
489
387
|
// EXPORTS
|
|
490
388
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -496,13 +394,15 @@ module.exports = {
|
|
|
496
394
|
formatEarnedUpsell,
|
|
497
395
|
formatBadgeWithheld,
|
|
498
396
|
formatNextSteps,
|
|
397
|
+
formatSoftUpsell,
|
|
398
|
+
formatWorkflowUpsell,
|
|
499
399
|
|
|
500
400
|
// Copy data (for testing/docs)
|
|
501
401
|
DENIAL_COPY,
|
|
502
|
-
CAPS_COPY,
|
|
503
402
|
TIER_LABELS,
|
|
504
403
|
TIER_COLORS,
|
|
505
404
|
PRICING_URL,
|
|
405
|
+
PRO_PRICE,
|
|
506
406
|
|
|
507
407
|
// Styling (for consistent use)
|
|
508
408
|
c,
|