@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
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vibecheck CLI Help Formatter - World-Class Help System
|
|
3
|
+
*
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* Provides consistent, beautiful, and informative help text across all commands.
|
|
6
|
+
* Features:
|
|
7
|
+
* - Consistent visual formatting
|
|
8
|
+
* - Rich examples with explanations
|
|
9
|
+
* - Tier badges and upgrade hints
|
|
10
|
+
* - Related commands section
|
|
11
|
+
* - Shell completion hints
|
|
12
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
"use strict";
|
|
16
|
+
|
|
17
|
+
const { ansi, colors, icons, BOX, WIDTH } = require("./terminal-ui");
|
|
18
|
+
|
|
19
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
20
|
+
// CONSTANTS
|
|
21
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
22
|
+
|
|
23
|
+
const HELP_WIDTH = 76;
|
|
24
|
+
const INDENT = " ";
|
|
25
|
+
const SECTION_INDENT = " ";
|
|
26
|
+
|
|
27
|
+
// Tier badges
|
|
28
|
+
const TIER_BADGES = {
|
|
29
|
+
free: `${ansi.green}[FREE]${ansi.reset}`,
|
|
30
|
+
starter: `${ansi.cyan}[STARTER]${ansi.reset}`,
|
|
31
|
+
pro: `${ansi.magenta}[PRO]${ansi.reset}`,
|
|
32
|
+
enterprise: `${ansi.yellow}[ENTERPRISE]${ansi.reset}`,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
36
|
+
// HELP SECTION BUILDERS
|
|
37
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Format a section header
|
|
41
|
+
*/
|
|
42
|
+
function formatSectionHeader(title, icon = "") {
|
|
43
|
+
const iconStr = icon ? `${icon} ` : "";
|
|
44
|
+
return `\n${INDENT}${ansi.bold}${iconStr}${title}${ansi.reset}\n`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Format a description paragraph
|
|
49
|
+
*/
|
|
50
|
+
function formatDescription(text) {
|
|
51
|
+
if (!text) return "";
|
|
52
|
+
const lines = wrapText(text, HELP_WIDTH - 4);
|
|
53
|
+
return lines.map(line => `${INDENT}${ansi.dim}${line}${ansi.reset}`).join("\n") + "\n";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Format a usage line
|
|
58
|
+
*/
|
|
59
|
+
function formatUsage(command, args = "", options = "[options]") {
|
|
60
|
+
const parts = [`vibecheck ${command}`];
|
|
61
|
+
if (args) parts.push(args);
|
|
62
|
+
if (options) parts.push(options);
|
|
63
|
+
return `${INDENT}${ansi.cyan}${parts.join(" ")}${ansi.reset}`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Format aliases
|
|
68
|
+
*/
|
|
69
|
+
function formatAliases(aliases) {
|
|
70
|
+
if (!aliases || aliases.length === 0) return "";
|
|
71
|
+
return `${INDENT}${ansi.dim}Aliases: ${aliases.join(", ")}${ansi.reset}\n`;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Format an option/flag
|
|
76
|
+
*/
|
|
77
|
+
function formatOption(flag, description, meta = {}) {
|
|
78
|
+
const { tier, default: defaultVal, required, short } = meta;
|
|
79
|
+
|
|
80
|
+
let flagStr = `${colors.accent}${flag}${ansi.reset}`;
|
|
81
|
+
if (short) {
|
|
82
|
+
flagStr = `${colors.accent}${short}${ansi.reset}, ${flagStr}`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let line = `${SECTION_INDENT}${flagStr.padEnd(28)}`;
|
|
86
|
+
line += description;
|
|
87
|
+
|
|
88
|
+
if (tier && tier !== "free") {
|
|
89
|
+
line += ` ${TIER_BADGES[tier]}`;
|
|
90
|
+
}
|
|
91
|
+
if (defaultVal !== undefined) {
|
|
92
|
+
line += ` ${ansi.dim}(default: ${defaultVal})${ansi.reset}`;
|
|
93
|
+
}
|
|
94
|
+
if (required) {
|
|
95
|
+
line += ` ${ansi.yellow}(required)${ansi.reset}`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return line;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Format a group of options
|
|
103
|
+
*/
|
|
104
|
+
function formatOptionGroup(title, options) {
|
|
105
|
+
const lines = [formatSectionHeader(title)];
|
|
106
|
+
for (const opt of options) {
|
|
107
|
+
lines.push(formatOption(opt.flag, opt.description, opt));
|
|
108
|
+
}
|
|
109
|
+
return lines.join("\n");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Format an example
|
|
114
|
+
*/
|
|
115
|
+
function formatExample(command, description, explanation = "") {
|
|
116
|
+
let result = `${SECTION_INDENT}${ansi.dim}#${ansi.reset} ${description}\n`;
|
|
117
|
+
result += `${SECTION_INDENT}${ansi.cyan}${command}${ansi.reset}`;
|
|
118
|
+
if (explanation) {
|
|
119
|
+
result += `\n${SECTION_INDENT}${ansi.dim}${explanation}${ansi.reset}`;
|
|
120
|
+
}
|
|
121
|
+
return result;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Format examples section
|
|
126
|
+
*/
|
|
127
|
+
function formatExamples(examples) {
|
|
128
|
+
const lines = [formatSectionHeader("EXAMPLES", "💡")];
|
|
129
|
+
for (let i = 0; i < examples.length; i++) {
|
|
130
|
+
const ex = examples[i];
|
|
131
|
+
lines.push(formatExample(ex.command, ex.description, ex.explanation));
|
|
132
|
+
if (i < examples.length - 1) lines.push(""); // spacing between examples
|
|
133
|
+
}
|
|
134
|
+
return lines.join("\n");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Format related commands
|
|
139
|
+
*/
|
|
140
|
+
function formatRelated(commands) {
|
|
141
|
+
if (!commands || commands.length === 0) return "";
|
|
142
|
+
|
|
143
|
+
const lines = [formatSectionHeader("RELATED COMMANDS", "🔗")];
|
|
144
|
+
for (const cmd of commands) {
|
|
145
|
+
const tierBadge = cmd.tier && cmd.tier !== "free" ? ` ${TIER_BADGES[cmd.tier]}` : "";
|
|
146
|
+
lines.push(`${SECTION_INDENT}${ansi.cyan}vibecheck ${cmd.name}${ansi.reset}${tierBadge}`);
|
|
147
|
+
lines.push(`${SECTION_INDENT}${ansi.dim}${cmd.description}${ansi.reset}`);
|
|
148
|
+
lines.push("");
|
|
149
|
+
}
|
|
150
|
+
return lines.join("\n");
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Format workflow section (multi-step guide)
|
|
155
|
+
*/
|
|
156
|
+
function formatWorkflow(steps) {
|
|
157
|
+
if (!steps || steps.length === 0) return "";
|
|
158
|
+
|
|
159
|
+
const lines = [formatSectionHeader("WORKFLOW", "📋")];
|
|
160
|
+
for (let i = 0; i < steps.length; i++) {
|
|
161
|
+
const step = steps[i];
|
|
162
|
+
const num = `${i + 1}.`;
|
|
163
|
+
lines.push(`${SECTION_INDENT}${ansi.bold}${num}${ansi.reset} ${step.title}`);
|
|
164
|
+
lines.push(`${SECTION_INDENT} ${ansi.cyan}${step.command}${ansi.reset}`);
|
|
165
|
+
if (step.note) {
|
|
166
|
+
lines.push(`${SECTION_INDENT} ${ansi.dim}${step.note}${ansi.reset}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return lines.join("\n");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Format output section (what the command produces)
|
|
174
|
+
*/
|
|
175
|
+
function formatOutput(outputs) {
|
|
176
|
+
if (!outputs || outputs.length === 0) return "";
|
|
177
|
+
|
|
178
|
+
const lines = [formatSectionHeader("OUTPUT", "📄")];
|
|
179
|
+
for (const out of outputs) {
|
|
180
|
+
lines.push(`${SECTION_INDENT}${ansi.cyan}${out.path}${ansi.reset}`);
|
|
181
|
+
lines.push(`${SECTION_INDENT}${ansi.dim}${out.description}${ansi.reset}`);
|
|
182
|
+
lines.push("");
|
|
183
|
+
}
|
|
184
|
+
return lines.join("\n");
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Format environment variables section
|
|
189
|
+
*/
|
|
190
|
+
function formatEnvVars(vars) {
|
|
191
|
+
if (!vars || vars.length === 0) return "";
|
|
192
|
+
|
|
193
|
+
const lines = [formatSectionHeader("ENVIRONMENT VARIABLES", "🌍")];
|
|
194
|
+
for (const v of vars) {
|
|
195
|
+
lines.push(`${SECTION_INDENT}${ansi.yellow}${v.name}${ansi.reset}`);
|
|
196
|
+
lines.push(`${SECTION_INDENT}${ansi.dim}${v.description}${ansi.reset}`);
|
|
197
|
+
if (v.default) {
|
|
198
|
+
lines.push(`${SECTION_INDENT}${ansi.dim}Default: ${v.default}${ansi.reset}`);
|
|
199
|
+
}
|
|
200
|
+
lines.push("");
|
|
201
|
+
}
|
|
202
|
+
return lines.join("\n");
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Format footer with links and hints
|
|
207
|
+
*/
|
|
208
|
+
function formatFooter(command, options = {}) {
|
|
209
|
+
const { docsUrl, tier, upgradeHint } = options;
|
|
210
|
+
|
|
211
|
+
const lines = ["", `${INDENT}${ansi.dim}${"─".repeat(HELP_WIDTH - 4)}${ansi.reset}`];
|
|
212
|
+
|
|
213
|
+
// Tier info
|
|
214
|
+
if (tier && tier !== "free") {
|
|
215
|
+
lines.push(`${INDENT}${ansi.dim}This command requires ${TIER_BADGES[tier]} tier or higher.${ansi.reset}`);
|
|
216
|
+
if (upgradeHint) {
|
|
217
|
+
lines.push(`${INDENT}${ansi.dim}${upgradeHint}${ansi.reset}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Docs link
|
|
222
|
+
if (docsUrl) {
|
|
223
|
+
lines.push(`${INDENT}${ansi.dim}Documentation: ${ansi.underline}${docsUrl}${ansi.reset}`);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Global help hint
|
|
227
|
+
lines.push(`${INDENT}${ansi.dim}Run 'vibecheck --help' for all commands.${ansi.reset}`);
|
|
228
|
+
lines.push("");
|
|
229
|
+
|
|
230
|
+
return lines.join("\n");
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
234
|
+
// UTILITY FUNCTIONS
|
|
235
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Wrap text to fit within width
|
|
239
|
+
*/
|
|
240
|
+
function wrapText(text, width) {
|
|
241
|
+
const words = text.split(/\s+/);
|
|
242
|
+
const lines = [];
|
|
243
|
+
let currentLine = "";
|
|
244
|
+
|
|
245
|
+
for (const word of words) {
|
|
246
|
+
if (currentLine.length + word.length + 1 > width) {
|
|
247
|
+
if (currentLine) lines.push(currentLine);
|
|
248
|
+
currentLine = word;
|
|
249
|
+
} else {
|
|
250
|
+
currentLine = currentLine ? `${currentLine} ${word}` : word;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
if (currentLine) lines.push(currentLine);
|
|
254
|
+
|
|
255
|
+
return lines;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Strip ANSI codes for length calculation
|
|
260
|
+
*/
|
|
261
|
+
function stripAnsi(str) {
|
|
262
|
+
return str.replace(/\x1b\[\d+m/g, "").replace(/\x1b\[38;2;\d+;\d+;\d+m/g, "");
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
266
|
+
// MAIN HELP BUILDER
|
|
267
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Build complete help text for a command
|
|
271
|
+
*
|
|
272
|
+
* @param {object} config - Help configuration
|
|
273
|
+
* @param {string} config.name - Command name
|
|
274
|
+
* @param {string[]} config.aliases - Command aliases
|
|
275
|
+
* @param {string} config.description - Short description
|
|
276
|
+
* @param {string} config.longDescription - Detailed description
|
|
277
|
+
* @param {string} config.tier - Required tier (free, starter, pro)
|
|
278
|
+
* @param {string} config.usage - Usage pattern (e.g., "[path] [options]")
|
|
279
|
+
* @param {object[]} config.options - Array of option definitions
|
|
280
|
+
* @param {object[]} config.examples - Array of example definitions
|
|
281
|
+
* @param {object[]} config.related - Array of related command definitions
|
|
282
|
+
* @param {object[]} config.workflow - Array of workflow steps
|
|
283
|
+
* @param {object[]} config.outputs - Array of output file definitions
|
|
284
|
+
* @param {object[]} config.envVars - Array of environment variable definitions
|
|
285
|
+
* @param {string} config.docsUrl - Documentation URL
|
|
286
|
+
* @param {function} config.banner - Optional banner function
|
|
287
|
+
* @returns {string} Complete formatted help text
|
|
288
|
+
*/
|
|
289
|
+
function buildHelp(config) {
|
|
290
|
+
const parts = [];
|
|
291
|
+
|
|
292
|
+
// Banner (optional)
|
|
293
|
+
if (config.banner) {
|
|
294
|
+
parts.push(config.banner());
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Usage
|
|
298
|
+
parts.push(formatSectionHeader("USAGE"));
|
|
299
|
+
parts.push(formatUsage(config.name, config.usage || "[options]"));
|
|
300
|
+
parts.push("");
|
|
301
|
+
|
|
302
|
+
// Aliases
|
|
303
|
+
if (config.aliases && config.aliases.length > 0) {
|
|
304
|
+
parts.push(formatAliases(config.aliases));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Description
|
|
308
|
+
if (config.longDescription || config.description) {
|
|
309
|
+
parts.push(formatSectionHeader("DESCRIPTION"));
|
|
310
|
+
parts.push(formatDescription(config.longDescription || config.description));
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Options (grouped)
|
|
314
|
+
if (config.options && config.options.length > 0) {
|
|
315
|
+
// Group options by category
|
|
316
|
+
const groups = {};
|
|
317
|
+
for (const opt of config.options) {
|
|
318
|
+
const group = opt.group || "OPTIONS";
|
|
319
|
+
if (!groups[group]) groups[group] = [];
|
|
320
|
+
groups[group].push(opt);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
for (const [groupName, groupOpts] of Object.entries(groups)) {
|
|
324
|
+
parts.push(formatOptionGroup(groupName, groupOpts));
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Examples
|
|
329
|
+
if (config.examples && config.examples.length > 0) {
|
|
330
|
+
parts.push(formatExamples(config.examples));
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Workflow
|
|
334
|
+
if (config.workflow && config.workflow.length > 0) {
|
|
335
|
+
parts.push(formatWorkflow(config.workflow));
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Output
|
|
339
|
+
if (config.outputs && config.outputs.length > 0) {
|
|
340
|
+
parts.push(formatOutput(config.outputs));
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Environment variables
|
|
344
|
+
if (config.envVars && config.envVars.length > 0) {
|
|
345
|
+
parts.push(formatEnvVars(config.envVars));
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
// Related commands
|
|
349
|
+
if (config.related && config.related.length > 0) {
|
|
350
|
+
parts.push(formatRelated(config.related));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// Footer
|
|
354
|
+
parts.push(formatFooter(config.name, {
|
|
355
|
+
tier: config.tier,
|
|
356
|
+
docsUrl: config.docsUrl,
|
|
357
|
+
upgradeHint: config.tier !== "free" ? "Upgrade at: https://vibecheckai.dev/pricing" : null,
|
|
358
|
+
}));
|
|
359
|
+
|
|
360
|
+
return parts.join("\n");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
364
|
+
// QUICK HELPERS FOR COMMON PATTERNS
|
|
365
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Global options that apply to most commands
|
|
369
|
+
*/
|
|
370
|
+
const GLOBAL_OPTIONS = [
|
|
371
|
+
{ flag: "--help, -h", description: "Show this help", group: "GLOBAL OPTIONS" },
|
|
372
|
+
{ flag: "--json", description: "Output as JSON (machine-readable)", group: "GLOBAL OPTIONS" },
|
|
373
|
+
{ flag: "--quiet, -q", description: "Suppress non-essential output", group: "GLOBAL OPTIONS" },
|
|
374
|
+
{ flag: "--verbose", description: "Show detailed output", group: "GLOBAL OPTIONS" },
|
|
375
|
+
{ flag: "--no-banner", description: "Hide the banner", group: "GLOBAL OPTIONS" },
|
|
376
|
+
{ flag: "--ci", description: "CI mode (implies --quiet --no-banner)", group: "GLOBAL OPTIONS" },
|
|
377
|
+
{ flag: "--path, -p <dir>", description: "Run in specified directory", group: "GLOBAL OPTIONS" },
|
|
378
|
+
{ flag: "--offline", description: "Run in offline mode (no API)", group: "GLOBAL OPTIONS" },
|
|
379
|
+
];
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Add global options to a command's options array
|
|
383
|
+
*/
|
|
384
|
+
function withGlobalOptions(options) {
|
|
385
|
+
return [...options, ...GLOBAL_OPTIONS];
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
389
|
+
// EXPORTS
|
|
390
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
391
|
+
|
|
392
|
+
module.exports = {
|
|
393
|
+
buildHelp,
|
|
394
|
+
formatSectionHeader,
|
|
395
|
+
formatDescription,
|
|
396
|
+
formatUsage,
|
|
397
|
+
formatAliases,
|
|
398
|
+
formatOption,
|
|
399
|
+
formatOptionGroup,
|
|
400
|
+
formatExample,
|
|
401
|
+
formatExamples,
|
|
402
|
+
formatRelated,
|
|
403
|
+
formatWorkflow,
|
|
404
|
+
formatOutput,
|
|
405
|
+
formatEnvVars,
|
|
406
|
+
formatFooter,
|
|
407
|
+
wrapText,
|
|
408
|
+
stripAnsi,
|
|
409
|
+
withGlobalOptions,
|
|
410
|
+
GLOBAL_OPTIONS,
|
|
411
|
+
TIER_BADGES,
|
|
412
|
+
HELP_WIDTH,
|
|
413
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple Logger Stub
|
|
3
|
+
*
|
|
4
|
+
* Provides a minimal logger interface for modules that need it.
|
|
5
|
+
* Respects VIBECHECK_DEBUG and VIBECHECK_QUIET environment variables.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
"use strict";
|
|
9
|
+
|
|
10
|
+
const isDebug = process.env.VIBECHECK_DEBUG === "true" || process.env.DEBUG;
|
|
11
|
+
const isQuiet = process.env.VIBECHECK_QUIET === "true";
|
|
12
|
+
|
|
13
|
+
const logger = {
|
|
14
|
+
debug: (...args) => {
|
|
15
|
+
if (isDebug && !isQuiet) {
|
|
16
|
+
console.debug("[DEBUG]", ...args);
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
info: (...args) => {
|
|
20
|
+
if (!isQuiet) {
|
|
21
|
+
console.info("[INFO]", ...args);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
warn: (...args) => {
|
|
25
|
+
console.warn("[WARN]", ...args);
|
|
26
|
+
},
|
|
27
|
+
error: (...args) => {
|
|
28
|
+
console.error("[ERROR]", ...args);
|
|
29
|
+
},
|
|
30
|
+
// Alias for compatibility
|
|
31
|
+
log: (...args) => {
|
|
32
|
+
if (!isQuiet) {
|
|
33
|
+
console.log(...args);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
module.exports = { logger };
|
|
@@ -245,39 +245,38 @@ function formatScanOutput(result, options = {}) {
|
|
|
245
245
|
});
|
|
246
246
|
|
|
247
247
|
const categoryLabels = {
|
|
248
|
-
'EnvContract': '🔐 Env
|
|
248
|
+
'EnvContract': '🔐 Env',
|
|
249
249
|
'MissingRoute': '🔗 Routes',
|
|
250
|
-
'GhostAuth': '🛡️
|
|
251
|
-
'FakeSuccess': '⚠️
|
|
252
|
-
'MockData': '🎭
|
|
250
|
+
'GhostAuth': '🛡️ Auth',
|
|
251
|
+
'FakeSuccess': '⚠️ Fake',
|
|
252
|
+
'MockData': '🎭 Mocks',
|
|
253
253
|
'Secrets': '🔑 Secrets',
|
|
254
|
-
'ConsoleLog': '📝
|
|
254
|
+
'ConsoleLog': '📝 Logs',
|
|
255
255
|
'TodoFixme': '📋 TODOs',
|
|
256
|
+
'CodeQuality': '✨ Quality',
|
|
257
|
+
'Security': '⚡ Security',
|
|
258
|
+
'Performance': '⚡ Perf',
|
|
256
259
|
};
|
|
257
260
|
|
|
258
261
|
const summaryItems = Object.entries(categoryCounts)
|
|
259
262
|
.sort((a, b) => b[1] - a[1])
|
|
260
263
|
.slice(0, 6)
|
|
261
264
|
.map(([cat, count]) => {
|
|
262
|
-
const label = categoryLabels[cat] ||
|
|
265
|
+
const label = categoryLabels[cat] || cat;
|
|
263
266
|
return `${label}: ${chalk.bold}${count}${chalk.reset}`;
|
|
264
267
|
});
|
|
265
268
|
|
|
266
269
|
if (summaryItems.length > 0) {
|
|
267
|
-
//
|
|
268
|
-
const
|
|
269
|
-
const prefix = `${chalk.dim}Findings by Category:${chalk.reset} `;
|
|
270
|
-
const maxLineLength = WIDTH - 10; // Leave some margin
|
|
270
|
+
// Simple left-aligned format with consistent spacing
|
|
271
|
+
const indent = ' ';
|
|
271
272
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${
|
|
279
|
-
} else {
|
|
280
|
-
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${padCenter(`${prefix}${categoryText}`, WIDTH - 2)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
273
|
+
// Always split into 2 rows of 3 for clean alignment
|
|
274
|
+
const row1 = summaryItems.slice(0, 3).join(' ');
|
|
275
|
+
const row2 = summaryItems.slice(3, 6).join(' ');
|
|
276
|
+
|
|
277
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${indent}${chalk.dim}FINDINGS:${chalk.reset} ${row1}${' '.repeat(Math.max(0, WIDTH - row1.length - 14))}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
278
|
+
if (row2) {
|
|
279
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${indent}${' '.repeat(10)}${row2}${' '.repeat(Math.max(0, WIDTH - row2.length - 14))}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
281
280
|
}
|
|
282
281
|
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${' '.repeat(WIDTH - 2)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
283
282
|
}
|
|
@@ -322,8 +322,8 @@ function renderBlockerDetails(findings, maxShow = 8, options = {}) {
|
|
|
322
322
|
|
|
323
323
|
if (blockers.length === 0) return '';
|
|
324
324
|
|
|
325
|
-
// Fix hints are
|
|
326
|
-
const canShowFixHints = tier === '
|
|
325
|
+
// Fix hints are PRO only (2-tier model)
|
|
326
|
+
const canShowFixHints = tier === 'pro' || tier === 'compliance' || tier === 'starter'; // starter=legacy compatibility
|
|
327
327
|
|
|
328
328
|
const lines = [];
|
|
329
329
|
lines.push(renderSection(`BLOCKERS (${blockers.length})`, '🚨'));
|
|
@@ -373,7 +373,7 @@ function renderBlockerDetails(findings, maxShow = 8, options = {}) {
|
|
|
373
373
|
}
|
|
374
374
|
} else {
|
|
375
375
|
// Show locked fix hint for FREE tier
|
|
376
|
-
lines.push(` ${ansi.dim}🔒 Fix
|
|
376
|
+
lines.push(` ${ansi.dim}🔒 Fix hints available with PRO ($69/mo)${ansi.reset}`);
|
|
377
377
|
}
|
|
378
378
|
|
|
379
379
|
lines.push('');
|
|
@@ -388,9 +388,9 @@ function renderBlockerDetails(findings, maxShow = 8, options = {}) {
|
|
|
388
388
|
if (!canShowFixHints && blockers.length > 0) {
|
|
389
389
|
lines.push(` ${ansi.dim}─────────────────────────────────────────${ansi.reset}`);
|
|
390
390
|
lines.push(` ${colors.accent}💡${ansi.reset} ${ansi.bold}Unlock AI fix suggestions${ansi.reset}`);
|
|
391
|
-
lines.push(` ${ansi.dim}
|
|
391
|
+
lines.push(` ${ansi.dim}PRO users get specific fix hints and${ansi.reset}`);
|
|
392
392
|
lines.push(` ${ansi.dim}AI mission prompts for every issue.${ansi.reset}`);
|
|
393
|
-
lines.push(` ${colors.accent}
|
|
393
|
+
lines.push(` ${colors.accent}Upgrade to PRO ($69/mo)${ansi.reset} ${ansi.dim}→ vibecheckai.dev/pricing${ansi.reset}`);
|
|
394
394
|
lines.push('');
|
|
395
395
|
}
|
|
396
396
|
|
|
@@ -702,22 +702,15 @@ function renderUpgradePrompts(findings, verdict) {
|
|
|
702
702
|
lines.push(` ${colors.accent}⚡${ansi.reset} ${ansi.bold}Want to fix these automatically?${ansi.reset}`);
|
|
703
703
|
lines.push('');
|
|
704
704
|
|
|
705
|
-
//
|
|
706
|
-
lines.push(` ${colors.accent}
|
|
705
|
+
// PRO tier benefits (2-tier: FREE / PRO)
|
|
706
|
+
lines.push(` ${colors.accent}PRO${ansi.reset} ${ansi.dim}($69/mo)${ansi.reset}`);
|
|
707
707
|
lines.push(` ${colors.success}→${ansi.reset} ${ansi.bold}vibecheck fix${ansi.reset} - AI auto-fix for ${fixableCount} issues`);
|
|
708
|
-
lines.push(` ${colors.success}→${ansi.reset} ${ansi.bold}vibecheck
|
|
709
|
-
lines.push(` ${colors.success}→${ansi.reset} ${ansi.bold}vibecheck
|
|
708
|
+
lines.push(` ${colors.success}→${ansi.reset} ${ansi.bold}vibecheck ship${ansi.reset} - GO/NO-GO verdicts with proof`);
|
|
709
|
+
lines.push(` ${colors.success}→${ansi.reset} ${ansi.bold}vibecheck prove${ansi.reset} - Video proof your app actually works`);
|
|
710
|
+
lines.push(` ${colors.success}→${ansi.reset} ${ansi.bold}vibecheck reality --agent${ansi.reset} - AI tests your app autonomously`);
|
|
710
711
|
lines.push('');
|
|
711
712
|
|
|
712
|
-
|
|
713
|
-
if (blockers.length > 0 || verdict === 'BLOCK') {
|
|
714
|
-
lines.push(` ${colors.accent}PRO${ansi.reset} ${ansi.dim}($99/mo)${ansi.reset}`);
|
|
715
|
-
lines.push(` ${colors.success}→${ansi.reset} ${ansi.bold}vibecheck prove${ansi.reset} - Video proof your app actually works`);
|
|
716
|
-
lines.push(` ${colors.success}→${ansi.reset} ${ansi.bold}vibecheck reality --agent${ansi.reset} - AI tests your app autonomously`);
|
|
717
|
-
lines.push('');
|
|
718
|
-
}
|
|
719
|
-
|
|
720
|
-
lines.push(` ${ansi.dim}Try STARTER free for 14 days: ${colors.accent}vibecheck login${ansi.reset}`);
|
|
713
|
+
lines.push(` ${ansi.dim}Upgrade: ${colors.accent}vibecheckai.dev/pricing${ansi.reset}`);
|
|
721
714
|
lines.push('');
|
|
722
715
|
|
|
723
716
|
return lines.join('\n');
|
|
@@ -751,8 +744,8 @@ function formatShipOutput(result, options = {}) {
|
|
|
751
744
|
cached = false,
|
|
752
745
|
} = result;
|
|
753
746
|
|
|
754
|
-
const isPro = tier === 'pro' || tier === 'compliance';
|
|
755
|
-
const
|
|
747
|
+
const isPro = tier === 'pro' || tier === 'compliance' || tier === 'starter'; // starter=legacy compat
|
|
748
|
+
const isProTier = isPro; // 2-tier model: isPro covers all paid tiers
|
|
756
749
|
const canShip = verdict === 'SHIP';
|
|
757
750
|
|
|
758
751
|
const lines = [];
|
|
@@ -777,7 +770,7 @@ function formatShipOutput(result, options = {}) {
|
|
|
777
770
|
lines.push(renderBlockerDetails(findings, 8, { tier }));
|
|
778
771
|
|
|
779
772
|
// Upgrade prompts for FREE tier users (if there are fixable issues)
|
|
780
|
-
if (findings.length > 0 && !
|
|
773
|
+
if (findings.length > 0 && !isProTier) {
|
|
781
774
|
lines.push(renderUpgradePrompts(findings, verdict));
|
|
782
775
|
}
|
|
783
776
|
|
|
@@ -799,16 +792,16 @@ function formatShipOutput(result, options = {}) {
|
|
|
799
792
|
}
|
|
800
793
|
|
|
801
794
|
// Badge (if requested and tier allows)
|
|
802
|
-
if (showBadge &&
|
|
795
|
+
if (showBadge && isProTier) {
|
|
803
796
|
const badgeResult = renderBadgeOutput(projectPath, verdict, score, { tier, isVerified });
|
|
804
797
|
lines.push(badgeResult.output);
|
|
805
|
-
} else if (showBadge && !
|
|
798
|
+
} else if (showBadge && !isProTier) {
|
|
806
799
|
// Show badge upsell for FREE users
|
|
807
800
|
lines.push('');
|
|
808
801
|
lines.push(renderSection('BADGE', '📛'));
|
|
809
802
|
lines.push('');
|
|
810
|
-
lines.push(` ${ansi.dim}🔒 Ship badges require
|
|
811
|
-
lines.push(` ${colors.accent}
|
|
803
|
+
lines.push(` ${ansi.dim}🔒 Ship badges require PRO ($69/mo)${ansi.reset}`);
|
|
804
|
+
lines.push(` ${colors.accent}vibecheckai.dev/pricing${ansi.reset} ${ansi.dim}to upgrade${ansi.reset}`);
|
|
812
805
|
lines.push('');
|
|
813
806
|
}
|
|
814
807
|
|