@vibecheckai/cli 3.0.9 → 3.0.10
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/runners/lib/report-html.js +378 -1
- package/bin/runners/runBadge.js +823 -116
- package/bin/runners/runCtx.js +602 -119
- package/bin/runners/runDoctor.js +329 -42
- package/bin/runners/runFix.js +544 -85
- package/bin/runners/runGraph.js +231 -74
- package/bin/runners/runInit.js +647 -88
- package/bin/runners/runInstall.js +207 -46
- package/bin/runners/runPR.js +123 -32
- package/bin/runners/runProve.js +818 -97
- package/bin/runners/runReality.js +812 -92
- package/bin/runners/runReport.js +68 -2
- package/bin/runners/runShare.js +156 -38
- package/bin/runners/runShip.js +920 -889
- package/bin/runners/runWatch.js +175 -55
- package/mcp-server/package.json +1 -1
- package/package.json +1 -1
package/bin/runners/runGraph.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* vibecheck graph - Reality Proof Graph
|
|
3
3
|
*
|
|
4
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
+
* ENTERPRISE EDITION - World-Class Terminal Experience
|
|
6
|
+
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
|
+
*
|
|
4
8
|
* Builds and visualizes the complete causal chain:
|
|
5
9
|
* UI action → client function → network call → server route → handler → DB/external
|
|
6
10
|
*
|
|
@@ -27,23 +31,143 @@ const {
|
|
|
27
31
|
mergeRuntimeResults
|
|
28
32
|
} = require("./lib/graph");
|
|
29
33
|
|
|
34
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
35
|
+
// ADVANCED TERMINAL - ANSI CODES & UTILITIES
|
|
36
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
37
|
+
|
|
30
38
|
const c = {
|
|
31
39
|
reset: '\x1b[0m',
|
|
32
40
|
bold: '\x1b[1m',
|
|
33
41
|
dim: '\x1b[2m',
|
|
42
|
+
italic: '\x1b[3m',
|
|
43
|
+
red: '\x1b[31m',
|
|
34
44
|
green: '\x1b[32m',
|
|
35
45
|
yellow: '\x1b[33m',
|
|
36
|
-
cyan: '\x1b[36m',
|
|
37
|
-
red: '\x1b[31m',
|
|
38
46
|
blue: '\x1b[34m',
|
|
47
|
+
magenta: '\x1b[35m',
|
|
48
|
+
cyan: '\x1b[36m',
|
|
49
|
+
white: '\x1b[37m',
|
|
50
|
+
gray: '\x1b[90m',
|
|
51
|
+
clearLine: '\x1b[2K',
|
|
52
|
+
hideCursor: '\x1b[?25l',
|
|
53
|
+
showCursor: '\x1b[?25h',
|
|
39
54
|
};
|
|
40
55
|
|
|
56
|
+
const rgb = (r, g, b) => `\x1b[38;2;${r};${g};${b}m`;
|
|
57
|
+
const bgRgb = (r, g, b) => `\x1b[48;2;${r};${g};${b}m`;
|
|
58
|
+
|
|
59
|
+
const colors = {
|
|
60
|
+
gradient1: rgb(255, 100, 150),
|
|
61
|
+
gradient2: rgb(255, 80, 170),
|
|
62
|
+
gradient3: rgb(255, 60, 190),
|
|
63
|
+
shipGreen: rgb(0, 255, 150),
|
|
64
|
+
warnAmber: rgb(255, 200, 0),
|
|
65
|
+
blockRed: rgb(255, 80, 80),
|
|
66
|
+
accent: rgb(255, 100, 150),
|
|
67
|
+
muted: rgb(120, 120, 140),
|
|
68
|
+
node: rgb(100, 200, 255),
|
|
69
|
+
edge: rgb(150, 255, 150),
|
|
70
|
+
broken: rgb(255, 100, 100),
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
74
|
+
// PREMIUM BANNER
|
|
75
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
76
|
+
|
|
77
|
+
const GRAPH_BANNER = `
|
|
78
|
+
${rgb(255, 100, 150)} ██████╗ ██████╗ █████╗ ██████╗ ██╗ ██╗${c.reset}
|
|
79
|
+
${rgb(255, 80, 170)} ██╔════╝ ██╔══██╗██╔══██╗██╔══██╗██║ ██║${c.reset}
|
|
80
|
+
${rgb(255, 60, 190)} ██║ ███╗██████╔╝███████║██████╔╝███████║${c.reset}
|
|
81
|
+
${rgb(255, 40, 210)} ██║ ██║██╔══██╗██╔══██║██╔═══╝ ██╔══██║${c.reset}
|
|
82
|
+
${rgb(255, 20, 230)} ╚██████╔╝██║ ██║██║ ██║██║ ██║ ██║${c.reset}
|
|
83
|
+
${rgb(255, 0, 255)} ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝${c.reset}
|
|
84
|
+
`;
|
|
85
|
+
|
|
86
|
+
const BANNER_FULL = `
|
|
87
|
+
${rgb(255, 100, 150)} ██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗${c.reset}
|
|
88
|
+
${rgb(255, 90, 160)} ██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝${c.reset}
|
|
89
|
+
${rgb(255, 80, 170)} ██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝ ${c.reset}
|
|
90
|
+
${rgb(255, 60, 190)} ╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗ ${c.reset}
|
|
91
|
+
${rgb(255, 40, 210)} ╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗${c.reset}
|
|
92
|
+
${rgb(255, 20, 230)} ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝${c.reset}
|
|
93
|
+
|
|
94
|
+
${c.dim} ┌─────────────────────────────────────────────────────────────────────┐${c.reset}
|
|
95
|
+
${c.dim} │${c.reset} ${rgb(255, 100, 150)}📊${c.reset} ${c.bold}GRAPH${c.reset} ${c.dim}•${c.reset} ${rgb(200, 200, 200)}Proof Visualization${c.reset} ${c.dim}•${c.reset} ${rgb(150, 150, 150)}Causal Chain${c.reset} ${c.dim}•${c.reset} ${rgb(100, 100, 100)}Edge Analysis${c.reset} ${c.dim}│${c.reset}
|
|
96
|
+
${c.dim} └─────────────────────────────────────────────────────────────────────┘${c.reset}
|
|
97
|
+
`;
|
|
98
|
+
|
|
99
|
+
const ICONS = {
|
|
100
|
+
graph: '📊',
|
|
101
|
+
check: '✓',
|
|
102
|
+
cross: '✗',
|
|
103
|
+
warning: '⚠',
|
|
104
|
+
arrow: '→',
|
|
105
|
+
bullet: '•',
|
|
106
|
+
node: '◉',
|
|
107
|
+
edge: '─',
|
|
108
|
+
broken: '╳',
|
|
109
|
+
sparkle: '✨',
|
|
110
|
+
file: '📄',
|
|
111
|
+
folder: '📁',
|
|
112
|
+
view: '👁️',
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const SPINNER_DOTS = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
|
|
116
|
+
let spinnerIndex = 0;
|
|
117
|
+
let spinnerInterval = null;
|
|
118
|
+
let spinnerStartTime = null;
|
|
119
|
+
|
|
120
|
+
function formatDuration(ms) {
|
|
121
|
+
if (ms < 1000) return `${ms}ms`;
|
|
122
|
+
return `${(ms / 1000).toFixed(1)}s`;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function startSpinner(message) {
|
|
126
|
+
spinnerStartTime = Date.now();
|
|
127
|
+
process.stdout.write(c.hideCursor);
|
|
128
|
+
spinnerInterval = setInterval(() => {
|
|
129
|
+
const elapsed = formatDuration(Date.now() - spinnerStartTime);
|
|
130
|
+
process.stdout.write(`\r${c.clearLine} ${colors.accent}${SPINNER_DOTS[spinnerIndex]}${c.reset} ${message} ${c.dim}${elapsed}${c.reset}`);
|
|
131
|
+
spinnerIndex = (spinnerIndex + 1) % SPINNER_DOTS.length;
|
|
132
|
+
}, 80);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function stopSpinner(message, success = true) {
|
|
136
|
+
if (spinnerInterval) {
|
|
137
|
+
clearInterval(spinnerInterval);
|
|
138
|
+
spinnerInterval = null;
|
|
139
|
+
}
|
|
140
|
+
const elapsed = spinnerStartTime ? formatDuration(Date.now() - spinnerStartTime) : '';
|
|
141
|
+
const icon = success ? `${colors.shipGreen}${ICONS.check}${c.reset}` : `${colors.blockRed}${ICONS.cross}${c.reset}`;
|
|
142
|
+
process.stdout.write(`\r${c.clearLine} ${icon} ${message} ${c.dim}${elapsed}${c.reset}\n`);
|
|
143
|
+
process.stdout.write(c.showCursor);
|
|
144
|
+
spinnerStartTime = null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function printDivider(char = '─', width = 69, color = c.dim) {
|
|
148
|
+
console.log(`${color} ${char.repeat(width)}${c.reset}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function printSection(title, icon = '◆') {
|
|
152
|
+
console.log();
|
|
153
|
+
console.log(` ${colors.accent}${icon}${c.reset} ${c.bold}${title}${c.reset}`);
|
|
154
|
+
printDivider();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function progressBar(percent, width = 25) {
|
|
158
|
+
const filled = Math.round((percent / 100) * width);
|
|
159
|
+
const empty = width - filled;
|
|
160
|
+
const color = percent >= 80 ? colors.shipGreen : percent >= 50 ? colors.warnAmber : colors.blockRed;
|
|
161
|
+
return `${color}${'█'.repeat(filled)}${c.dim}${'░'.repeat(empty)}${c.reset}`;
|
|
162
|
+
}
|
|
163
|
+
|
|
41
164
|
function ensureDir(p) {
|
|
42
165
|
fs.mkdirSync(p, { recursive: true });
|
|
43
166
|
}
|
|
44
167
|
|
|
45
168
|
async function runGraph(args) {
|
|
46
169
|
const opts = parseArgs(args);
|
|
170
|
+
const startTime = Date.now();
|
|
47
171
|
|
|
48
172
|
if (opts.help) {
|
|
49
173
|
printHelp();
|
|
@@ -51,39 +175,51 @@ async function runGraph(args) {
|
|
|
51
175
|
}
|
|
52
176
|
|
|
53
177
|
const root = path.resolve(opts.path || process.cwd());
|
|
178
|
+
const projectName = path.basename(root);
|
|
54
179
|
const outDir = path.join(root, ".vibecheck", "graph");
|
|
55
180
|
ensureDir(outDir);
|
|
56
181
|
|
|
57
|
-
|
|
58
|
-
console.log(
|
|
182
|
+
// Print banner
|
|
183
|
+
console.log(BANNER_FULL);
|
|
184
|
+
console.log(` ${c.dim}Project:${c.reset} ${c.bold}${projectName}${c.reset}`);
|
|
185
|
+
console.log(` ${c.dim}Path:${c.reset} ${root}`);
|
|
186
|
+
console.log();
|
|
59
187
|
|
|
60
188
|
// Load or build truthpack
|
|
189
|
+
startSpinner('Loading truthpack...');
|
|
61
190
|
let truthpack = loadTruthpack(root);
|
|
62
191
|
if (!truthpack) {
|
|
63
|
-
|
|
192
|
+
stopSpinner('Truthpack not found, building...', true);
|
|
193
|
+
startSpinner('Building truthpack...');
|
|
64
194
|
truthpack = await buildTruthpack({ repoRoot: root, fastifyEntry: opts.fastifyEntry });
|
|
65
195
|
}
|
|
196
|
+
stopSpinner('Truthpack loaded', true);
|
|
66
197
|
|
|
67
198
|
// Extract static graph
|
|
68
|
-
|
|
199
|
+
startSpinner('Extracting static edges...');
|
|
69
200
|
const staticData = await extractStaticGraph(root, truthpack);
|
|
201
|
+
stopSpinner(`Extracted ${staticData.edges?.length || 0} edges`, true);
|
|
70
202
|
|
|
71
203
|
// Build proof graph
|
|
204
|
+
startSpinner('Building proof graph...');
|
|
72
205
|
let graph = buildProofGraph({
|
|
73
206
|
nodes: staticData.nodes,
|
|
74
207
|
edges: staticData.edges,
|
|
75
208
|
meta: { repoRoot: root }
|
|
76
209
|
});
|
|
210
|
+
stopSpinner(`Built graph with ${graph.nodes?.length || 0} nodes`, true);
|
|
77
211
|
|
|
78
212
|
// Runtime verification (optional)
|
|
79
213
|
if (opts.runtime && opts.url) {
|
|
80
|
-
|
|
214
|
+
startSpinner(`Collecting runtime edges from ${opts.url}...`);
|
|
81
215
|
|
|
82
216
|
try {
|
|
83
217
|
const runtimeEdges = await collectRuntimeEdges(opts.url, graph, opts);
|
|
84
218
|
graph = mergeRuntimeResults(graph, runtimeEdges);
|
|
219
|
+
stopSpinner('Runtime edges collected', true);
|
|
85
220
|
} catch (e) {
|
|
86
|
-
|
|
221
|
+
stopSpinner('Runtime collection failed', false);
|
|
222
|
+
console.log(` ${c.dim}${e.message}${c.reset}`);
|
|
87
223
|
}
|
|
88
224
|
}
|
|
89
225
|
|
|
@@ -91,6 +227,7 @@ async function runGraph(args) {
|
|
|
91
227
|
const findings = getFindingsFromGraph(graph);
|
|
92
228
|
|
|
93
229
|
// Write outputs
|
|
230
|
+
startSpinner('Writing outputs...');
|
|
94
231
|
fs.writeFileSync(path.join(outDir, "graph.json"), JSON.stringify(graph, null, 2), "utf8");
|
|
95
232
|
|
|
96
233
|
if (!opts.jsonOnly) {
|
|
@@ -104,23 +241,31 @@ async function runGraph(args) {
|
|
|
104
241
|
if (findings.length > 0) {
|
|
105
242
|
fs.writeFileSync(path.join(outDir, "broken-edges.json"), JSON.stringify(findings, null, 2), "utf8");
|
|
106
243
|
}
|
|
244
|
+
stopSpinner('Outputs written', true);
|
|
107
245
|
|
|
108
246
|
// Print summary
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
console.log(
|
|
247
|
+
const duration = Date.now() - startTime;
|
|
248
|
+
const coverage = graph.coverage?.percent || 0;
|
|
249
|
+
|
|
250
|
+
printSection('GRAPH SUMMARY', ICONS.graph);
|
|
251
|
+
console.log();
|
|
252
|
+
console.log(` ${colors.node}${ICONS.node}${c.reset} ${c.bold}Nodes:${c.reset} ${graph.nodes?.length || 0}`);
|
|
253
|
+
console.log(` ${colors.edge}${ICONS.edge}${c.reset} ${c.bold}Valid edges:${c.reset} ${colors.shipGreen}${graph.edges?.length || 0}${c.reset}`);
|
|
254
|
+
console.log(` ${colors.broken}${ICONS.broken}${c.reset} ${c.bold}Broken edges:${c.reset} ${graph.brokenEdges?.length > 0 ? colors.blockRed : colors.shipGreen}${graph.brokenEdges?.length || 0}${c.reset}`);
|
|
255
|
+
console.log();
|
|
256
|
+
console.log(` ${c.bold}Coverage:${c.reset} ${progressBar(coverage)} ${coverage}%`);
|
|
257
|
+
console.log(` ${c.bold}Duration:${c.reset} ${formatDuration(duration)}`);
|
|
114
258
|
|
|
115
259
|
if (opts.broken || findings.length > 0) {
|
|
116
|
-
|
|
260
|
+
printSection('BROKEN EDGES', ICONS.broken);
|
|
261
|
+
console.log();
|
|
117
262
|
|
|
118
263
|
if (findings.length === 0) {
|
|
119
|
-
console.log(` ${c.
|
|
264
|
+
console.log(` ${colors.shipGreen}${ICONS.check}${c.reset} No broken edges found`);
|
|
120
265
|
} else {
|
|
121
266
|
for (const f of findings.slice(0, 10)) {
|
|
122
|
-
const icon = f.severity === "BLOCK" ? `${
|
|
123
|
-
console.log(` ${icon}
|
|
267
|
+
const icon = f.severity === "BLOCK" ? `${colors.blockRed}●` : `${colors.warnAmber}●`;
|
|
268
|
+
console.log(` ${icon}${c.reset} ${f.title}`);
|
|
124
269
|
}
|
|
125
270
|
if (findings.length > 10) {
|
|
126
271
|
console.log(` ${c.dim}... and ${findings.length - 10} more${c.reset}`);
|
|
@@ -128,21 +273,22 @@ async function runGraph(args) {
|
|
|
128
273
|
}
|
|
129
274
|
}
|
|
130
275
|
|
|
131
|
-
|
|
132
|
-
console.log(
|
|
276
|
+
printSection('OUTPUT', ICONS.folder);
|
|
277
|
+
console.log();
|
|
278
|
+
console.log(` ${ICONS.file} ${colors.accent}graph.json${c.reset} ${c.dim}Machine-readable graph${c.reset}`);
|
|
133
279
|
if (!opts.jsonOnly) {
|
|
134
|
-
console.log(` ${c.dim}
|
|
135
|
-
console.log(` ${c.dim}Mermaid
|
|
280
|
+
console.log(` ${ICONS.view} ${colors.accent}graph.html${c.reset} ${c.dim}Interactive visualization${c.reset}`);
|
|
281
|
+
console.log(` ${ICONS.file} ${colors.accent}graph.mmd${c.reset} ${c.dim}Mermaid diagram${c.reset}`);
|
|
136
282
|
}
|
|
137
283
|
if (findings.length > 0) {
|
|
138
|
-
console.log(` ${c.dim}Broken edges
|
|
284
|
+
console.log(` ${ICONS.warning} ${colors.accent}broken-edges.json${c.reset} ${c.dim}Broken edges as findings${c.reset}`);
|
|
139
285
|
}
|
|
140
286
|
|
|
141
287
|
if (opts.view && !opts.jsonOnly) {
|
|
142
288
|
const htmlPath = path.join(outDir, "graph.html");
|
|
143
|
-
console.log(
|
|
289
|
+
console.log();
|
|
290
|
+
console.log(` ${c.dim}Opening visualization...${c.reset}`);
|
|
144
291
|
|
|
145
|
-
// Cross-platform open
|
|
146
292
|
const { exec } = require("child_process");
|
|
147
293
|
const cmd = process.platform === "win32" ? `start "" "${htmlPath}"` :
|
|
148
294
|
process.platform === "darwin" ? `open "${htmlPath}"` :
|
|
@@ -153,7 +299,13 @@ async function runGraph(args) {
|
|
|
153
299
|
const blocks = findings.filter(f => f.severity === "BLOCK").length;
|
|
154
300
|
const warns = findings.filter(f => f.severity === "WARN").length;
|
|
155
301
|
|
|
156
|
-
|
|
302
|
+
// Verdict card
|
|
303
|
+
console.log();
|
|
304
|
+
const verdictColor = blocks ? colors.blockRed : warns ? colors.warnAmber : colors.shipGreen;
|
|
305
|
+
const verdictIcon = blocks ? '🛑' : warns ? '⚠️' : '✅';
|
|
306
|
+
const verdictText = blocks ? 'BLOCK' : warns ? 'WARN' : 'CLEAN';
|
|
307
|
+
console.log(` ${verdictColor}${c.bold}${verdictIcon} ${verdictText}${c.reset}`);
|
|
308
|
+
console.log();
|
|
157
309
|
|
|
158
310
|
return blocks ? 2 : warns ? 1 : 0;
|
|
159
311
|
}
|
|
@@ -228,56 +380,61 @@ function parseArgs(args) {
|
|
|
228
380
|
}
|
|
229
381
|
|
|
230
382
|
function printHelp() {
|
|
383
|
+
console.log(BANNER_FULL);
|
|
231
384
|
console.log(`
|
|
232
|
-
${c.
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
${c.
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
${c.
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
${c.
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
${c.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
${c.
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
${c.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
385
|
+
${c.bold}Usage:${c.reset} vibecheck graph [options]
|
|
386
|
+
|
|
387
|
+
${c.bold}Reality Proof Graph${c.reset} — Visualize the complete causal chain from UI to database.
|
|
388
|
+
|
|
389
|
+
${c.bold}Modes:${c.reset}
|
|
390
|
+
${colors.accent}vibecheck graph${c.reset} ${c.dim}Build static graph${c.reset}
|
|
391
|
+
${colors.accent}vibecheck graph --runtime --url http://...${c.reset} ${c.dim}Add runtime edges${c.reset}
|
|
392
|
+
${colors.accent}vibecheck graph --view${c.reset} ${c.dim}Open visualization${c.reset}
|
|
393
|
+
${colors.accent}vibecheck graph --broken${c.reset} ${c.dim}List broken edges${c.reset}
|
|
394
|
+
|
|
395
|
+
${c.bold}Options:${c.reset}
|
|
396
|
+
${colors.accent}--build${c.reset} Build static graph ${c.dim}(default)${c.reset}
|
|
397
|
+
${colors.accent}--runtime${c.reset} Collect runtime edges via Playwright
|
|
398
|
+
${colors.accent}--url <url>${c.reset} Target URL for runtime collection
|
|
399
|
+
${colors.accent}--view${c.reset} Open interactive HTML visualization
|
|
400
|
+
${colors.accent}--broken${c.reset} Show only broken edges
|
|
401
|
+
${colors.accent}--json${c.reset} Output JSON only ${c.dim}(no HTML/Mermaid)${c.reset}
|
|
402
|
+
${colors.accent}--headed${c.reset} Run browser in headed mode
|
|
403
|
+
${colors.accent}--fastify-entry${c.reset} Fastify entry file ${c.dim}(e.g. src/server.ts)${c.reset}
|
|
404
|
+
${colors.accent}--path, -p${c.reset} Project path ${c.dim}(default: current directory)${c.reset}
|
|
405
|
+
${colors.accent}--help, -h${c.reset} Show this help
|
|
406
|
+
|
|
407
|
+
${c.bold}Graph Nodes:${c.reset}
|
|
408
|
+
${colors.node}◉${c.reset} UI Action ${c.dim}onClick, onSubmit, etc.${c.reset}
|
|
409
|
+
${colors.node}◉${c.reset} Client Function ${c.dim}Functions that make network calls${c.reset}
|
|
410
|
+
${colors.node}◉${c.reset} Network Call ${c.dim}fetch(), axios.*()${c.reset}
|
|
411
|
+
${colors.node}◉${c.reset} Server Route ${c.dim}Next API routes, Fastify routes${c.reset}
|
|
412
|
+
${colors.node}◉${c.reset} Handler ${c.dim}Route handler functions${c.reset}
|
|
413
|
+
${colors.node}◉${c.reset} DB Call ${c.dim}Prisma, raw SQL${c.reset}
|
|
414
|
+
${colors.node}◉${c.reset} External Call ${c.dim}Stripe, GitHub, etc.${c.reset}
|
|
415
|
+
|
|
416
|
+
${c.bold}Broken Edge Types:${c.reset}
|
|
417
|
+
${colors.blockRed}╳${c.reset} MissingRoute ${c.dim}Route referenced but doesn't exist${c.reset}
|
|
418
|
+
${colors.blockRed}╳${c.reset} RuntimeFailure ${c.dim}Route returns 4xx/5xx at runtime${c.reset}
|
|
419
|
+
${colors.blockRed}╳${c.reset} CausalContradiction ${c.dim}UI shows success but server returned error${c.reset}
|
|
420
|
+
|
|
421
|
+
${c.bold}Output:${c.reset}
|
|
422
|
+
${c.dim}.vibecheck/graph/${c.reset}
|
|
423
|
+
${colors.accent}graph.json${c.reset} ${c.dim}Machine-readable graph${c.reset}
|
|
424
|
+
${colors.accent}graph.html${c.reset} ${c.dim}Interactive D3 visualization${c.reset}
|
|
425
|
+
${colors.accent}graph.mmd${c.reset} ${c.dim}Mermaid diagram${c.reset}
|
|
426
|
+
${colors.accent}broken-edges.json${c.reset} ${c.dim}Broken edges as findings${c.reset}
|
|
427
|
+
|
|
428
|
+
${c.bold}Examples:${c.reset}
|
|
429
|
+
${c.dim}# Build + open visualization${c.reset}
|
|
430
|
+
vibecheck graph --view
|
|
431
|
+
|
|
432
|
+
${c.dim}# Runtime verification with Playwright${c.reset}
|
|
433
|
+
vibecheck graph --runtime --url http://localhost:3000 --view
|
|
434
|
+
|
|
435
|
+
${c.dim}# CI mode: just broken edges as JSON${c.reset}
|
|
436
|
+
vibecheck graph --broken --json
|
|
437
|
+
`);
|
|
281
438
|
}
|
|
282
439
|
|
|
283
440
|
module.exports = { runGraph };
|