@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.
@@ -1,6 +1,10 @@
1
1
  /**
2
2
  * vibecheck watch - Continuous Dev Mode
3
3
  *
4
+ * ═══════════════════════════════════════════════════════════════════════════════
5
+ * ENTERPRISE EDITION - World-Class Terminal Experience
6
+ * ═══════════════════════════════════════════════════════════════════════════════
7
+ *
4
8
  * Watches for file changes and re-runs ship automatically.
5
9
  * Shows a persistent status line with current verdict.
6
10
  * Perfect for development workflow.
@@ -12,16 +16,92 @@ const fs = require("fs");
12
16
  const path = require("path");
13
17
  const { shipCore } = require("./runShip");
14
18
 
19
+ // ═══════════════════════════════════════════════════════════════════════════════
20
+ // ADVANCED TERMINAL - ANSI CODES & UTILITIES
21
+ // ═══════════════════════════════════════════════════════════════════════════════
22
+
15
23
  const c = {
16
- reset: "\x1b[0m",
17
- bold: "\x1b[1m",
18
- dim: "\x1b[2m",
19
- red: "\x1b[31m",
20
- green: "\x1b[32m",
21
- yellow: "\x1b[33m",
22
- cyan: "\x1b[36m",
23
- blue: "\x1b[34m",
24
- clear: "\x1b[2J\x1b[H",
24
+ reset: '\x1b[0m',
25
+ bold: '\x1b[1m',
26
+ dim: '\x1b[2m',
27
+ italic: '\x1b[3m',
28
+ underline: '\x1b[4m',
29
+ red: '\x1b[31m',
30
+ green: '\x1b[32m',
31
+ yellow: '\x1b[33m',
32
+ blue: '\x1b[34m',
33
+ magenta: '\x1b[35m',
34
+ cyan: '\x1b[36m',
35
+ white: '\x1b[37m',
36
+ gray: '\x1b[90m',
37
+ clear: '\x1b[2J\x1b[H',
38
+ clearLine: '\x1b[2K',
39
+ hideCursor: '\x1b[?25l',
40
+ showCursor: '\x1b[?25h',
41
+ };
42
+
43
+ const rgb = (r, g, b) => `\x1b[38;2;${r};${g};${b}m`;
44
+ const bgRgb = (r, g, b) => `\x1b[48;2;${r};${g};${b}m`;
45
+
46
+ const colors = {
47
+ gradient1: rgb(150, 100, 255),
48
+ gradient2: rgb(130, 80, 255),
49
+ gradient3: rgb(110, 60, 255),
50
+ shipGreen: rgb(0, 255, 150),
51
+ warnAmber: rgb(255, 200, 0),
52
+ blockRed: rgb(255, 80, 80),
53
+ accent: rgb(150, 100, 255),
54
+ muted: rgb(120, 120, 140),
55
+ watching: rgb(100, 200, 255),
56
+ };
57
+
58
+ // ═══════════════════════════════════════════════════════════════════════════════
59
+ // PREMIUM BANNER
60
+ // ═══════════════════════════════════════════════════════════════════════════════
61
+
62
+ const WATCH_BANNER = `
63
+ ${rgb(150, 100, 255)} ██╗ ██╗ █████╗ ████████╗ ██████╗██╗ ██╗${c.reset}
64
+ ${rgb(130, 80, 255)} ██║ ██║██╔══██╗╚══██╔══╝██╔════╝██║ ██║${c.reset}
65
+ ${rgb(110, 60, 255)} ██║ █╗ ██║███████║ ██║ ██║ ███████║${c.reset}
66
+ ${rgb(90, 40, 255)} ██║███╗██║██╔══██║ ██║ ██║ ██╔══██║${c.reset}
67
+ ${rgb(70, 20, 255)} ╚███╔███╔╝██║ ██║ ██║ ╚██████╗██║ ██║${c.reset}
68
+ ${rgb(50, 0, 255)} ╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝${c.reset}
69
+ `;
70
+
71
+ const BANNER_FULL = `
72
+ ${rgb(150, 100, 255)} ██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗${c.reset}
73
+ ${rgb(140, 90, 255)} ██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝${c.reset}
74
+ ${rgb(130, 80, 255)} ██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝ ${c.reset}
75
+ ${rgb(110, 60, 255)} ╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗ ${c.reset}
76
+ ${rgb(90, 40, 255)} ╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗${c.reset}
77
+ ${rgb(70, 20, 255)} ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝${c.reset}
78
+
79
+ ${c.dim} ┌─────────────────────────────────────────────────────────────────────┐${c.reset}
80
+ ${c.dim} │${c.reset} ${rgb(150, 100, 255)}👁️${c.reset} ${c.bold}WATCH${c.reset} ${c.dim}•${c.reset} ${rgb(200, 200, 200)}Live Reload${c.reset} ${c.dim}•${c.reset} ${rgb(150, 150, 150)}Auto Analysis${c.reset} ${c.dim}•${c.reset} ${rgb(100, 100, 100)}Dev Mode${c.reset} ${c.dim}│${c.reset}
81
+ ${c.dim} └─────────────────────────────────────────────────────────────────────┘${c.reset}
82
+ `;
83
+
84
+ const BOX = {
85
+ topLeft: '╭', topRight: '╮', bottomLeft: '╰', bottomRight: '╯',
86
+ horizontal: '─', vertical: '│',
87
+ dTopLeft: '╔', dTopRight: '╗', dBottomLeft: '╚', dBottomRight: '╝',
88
+ dHorizontal: '═', dVertical: '║',
89
+ };
90
+
91
+ const ICONS = {
92
+ eye: '👁️',
93
+ check: '✓',
94
+ cross: '✗',
95
+ warning: '⚠',
96
+ arrow: '→',
97
+ bullet: '•',
98
+ ship: '🚀',
99
+ clock: '⏱',
100
+ file: '📄',
101
+ sparkle: '✨',
102
+ lightning: '⚡',
103
+ refresh: '🔄',
104
+ watching: '◉',
25
105
  };
26
106
 
27
107
  const IGNORE_PATTERNS = [
@@ -58,29 +138,63 @@ function formatDuration(ms) {
58
138
  return `${(ms / 1000).toFixed(1)}s`;
59
139
  }
60
140
 
141
+ function progressBar(percent, width = 20) {
142
+ const filled = Math.round((percent / 100) * width);
143
+ const empty = width - filled;
144
+ const color = percent >= 80 ? colors.shipGreen : percent >= 50 ? colors.warnAmber : colors.blockRed;
145
+ return `${color}${'█'.repeat(filled)}${c.dim}${'░'.repeat(empty)}${c.reset}`;
146
+ }
147
+
148
+ function printDivider(char = '─', width = 62) {
149
+ console.log(` ${c.dim}${char.repeat(width)}${c.reset}`);
150
+ }
151
+
61
152
  function printStatus({ verdict, findings, duration, lastFile, runCount }) {
62
- const verdictColor = verdict === "SHIP" ? c.green : verdict === "WARN" ? c.yellow : c.red;
153
+ const verdictColor = verdict === "SHIP" ? colors.shipGreen : verdict === "WARN" ? colors.warnAmber : colors.blockRed;
63
154
  const blocks = findings.filter(f => f.severity === "BLOCK").length;
64
155
  const warns = findings.filter(f => f.severity === "WARN").length;
65
-
66
- console.log(`
67
- ${c.cyan}${c.bold}╔════════════════════════════════════════════════════════════╗
68
- 👁️ vibecheck watch ║
69
- ╚════════════════════════════════════════════════════════════╝${c.reset}
70
-
71
- ${c.dim}Time:${c.reset} ${formatTime()}
72
- ${c.dim}Runs:${c.reset} ${runCount}
73
- ${c.dim}Duration:${c.reset} ${formatDuration(duration)}
74
- ${c.dim}Changed:${c.reset} ${lastFile || "(initial)"}
75
-
76
- ${c.bold} VERDICT: ${verdictColor}${verdict}${c.reset}
156
+ const total = blocks + warns;
157
+ const health = total === 0 ? 100 : Math.max(0, 100 - (blocks * 20) - (warns * 5));
158
+
159
+ console.log();
160
+ console.log(` ${c.dim}${BOX.dTopLeft}${BOX.dHorizontal.repeat(62)}${BOX.dTopRight}${c.reset}`);
161
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${colors.watching}${ICONS.eye}${c.reset} ${c.bold}VIBECHECK WATCH${c.reset} ${c.dim}${BOX.dVertical}${c.reset}`);
162
+ console.log(` ${c.dim}${BOX.dVertical}${BOX.dHorizontal.repeat(62)}${BOX.dVertical}${c.reset}`);
163
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.dim}${BOX.dVertical}${c.reset}`);
77
164
 
78
- ${c.dim}Findings:${c.reset} ${blocks} BLOCK, ${warns} WARN
79
-
80
- ${verdict === "SHIP" ? ` ${c.green}✓ Ready to ship${c.reset}` : ` ${c.yellow}⚠ Run "vibecheck fix" to resolve${c.reset}`}
81
-
82
- ${c.dim} Watching for changes... (Ctrl+C to stop)${c.reset}
83
- `);
165
+ // Stats row
166
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.dim}${ICONS.clock} Time:${c.reset} ${formatTime()} ${c.dim}${ICONS.refresh} Runs:${c.reset} ${runCount} ${c.dim}${ICONS.lightning} Duration:${c.reset} ${formatDuration(duration)} ${c.dim}${BOX.dVertical}${c.reset}`);
167
+
168
+ // Changed file
169
+ const changedDisplay = lastFile ? lastFile.slice(0, 40) : '(initial scan)';
170
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.dim}${ICONS.file} Changed:${c.reset} ${colors.accent}${changedDisplay}${c.reset}${' '.repeat(Math.max(0, 45 - changedDisplay.length))}${c.dim}${BOX.dVertical}${c.reset}`);
171
+
172
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.dim}${BOX.dVertical}${c.reset}`);
173
+ console.log(` ${c.dim}${BOX.dVertical}${BOX.dHorizontal.repeat(62)}${BOX.dVertical}${c.reset}`);
174
+
175
+ // Verdict
176
+ const verdictIcon = verdict === "SHIP" ? ICONS.ship : verdict === "WARN" ? ICONS.warning : ICONS.cross;
177
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.dim}${BOX.dVertical}${c.reset}`);
178
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.bold}VERDICT:${c.reset} ${verdictColor}${c.bold}${verdictIcon} ${verdict}${c.reset} ${c.dim}${BOX.dVertical}${c.reset}`);
179
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.dim}${BOX.dVertical}${c.reset}`);
180
+
181
+ // Health bar
182
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.dim}Health:${c.reset} ${progressBar(health)} ${health}% ${c.dim}${BOX.dVertical}${c.reset}`);
183
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.dim}Findings:${c.reset} ${colors.blockRed}${blocks}${c.reset} ${c.dim}BLOCK${c.reset} ${colors.warnAmber}${warns}${c.reset} ${c.dim}WARN${c.reset} ${c.dim}${BOX.dVertical}${c.reset}`);
184
+
185
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.dim}${BOX.dVertical}${c.reset}`);
186
+
187
+ // Status message
188
+ const statusMsg = verdict === "SHIP"
189
+ ? `${colors.shipGreen}${ICONS.check}${c.reset} Ready to ship`
190
+ : `${colors.warnAmber}${ICONS.arrow}${c.reset} Run ${colors.accent}vibecheck fix${c.reset} to resolve`;
191
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${statusMsg} ${c.dim}${BOX.dVertical}${c.reset}`);
192
+
193
+ console.log(` ${c.dim}${BOX.dVertical}${c.reset} ${c.dim}${BOX.dVertical}${c.reset}`);
194
+ console.log(` ${c.dim}${BOX.dBottomLeft}${BOX.dHorizontal.repeat(62)}${BOX.dBottomRight}${c.reset}`);
195
+ console.log();
196
+ console.log(` ${c.dim}${ICONS.watching} Watching for changes... (Ctrl+C to stop)${c.reset}`);
197
+ console.log();
84
198
  }
85
199
 
86
200
  function printTopFindings(findings, max = 5) {
@@ -90,12 +204,13 @@ function printTopFindings(findings, max = 5) {
90
204
 
91
205
  if (!top.length) return;
92
206
 
93
- console.log(`${c.dim} Top findings:${c.reset}`);
207
+ console.log(` ${c.bold}Top findings:${c.reset}`);
94
208
  for (const f of top) {
95
- const icon = f.severity === "BLOCK" ? c.red + "●" : c.yellow + "●";
96
- console.log(` ${icon}${c.reset} ${f.title}`);
209
+ const icon = f.severity === "BLOCK" ? `${colors.blockRed}●` : `${colors.warnAmber}●`;
210
+ const title = f.title?.length > 50 ? f.title.slice(0, 47) + '...' : f.title;
211
+ console.log(` ${icon}${c.reset} ${title}`);
97
212
  }
98
- console.log("");
213
+ console.log();
99
214
  }
100
215
 
101
216
  async function runShipQuiet(root, fastifyEntry) {
@@ -159,37 +274,42 @@ function watchDirectory(dir, callback) {
159
274
  }
160
275
 
161
276
  function printHelp() {
277
+ console.log(BANNER_FULL);
162
278
  console.log(`
163
- ${c.cyan}${c.bold}vibecheck watch${c.reset} - Continuous Dev Mode
279
+ ${c.bold}Usage:${c.reset} vibecheck watch [options]
280
+
281
+ ${c.bold}Continuous Dev Mode${c.reset} — Live reload with automatic ship analysis.
282
+
283
+ ${c.bold}Options:${c.reset}
284
+ ${colors.accent}--fastify-entry <path>${c.reset} Fastify entry file for route extraction
285
+ ${colors.accent}--debounce <ms>${c.reset} Debounce delay in ms ${c.dim}(default: 500)${c.reset}
286
+ ${colors.accent}--no-clear${c.reset} Don't clear screen between runs
287
+ ${colors.accent}--help, -h${c.reset} Show this help
164
288
 
165
- ${c.bold}USAGE${c.reset}
166
- vibecheck watch [options]
289
+ ${c.bold}What It Does:${c.reset}
290
+ ${colors.shipGreen}1.${c.reset} Runs initial ship analysis
291
+ ${colors.shipGreen}2.${c.reset} Watches for file changes in your project
292
+ ${colors.shipGreen}3.${c.reset} Re-runs analysis on each change
293
+ ${colors.shipGreen}4.${c.reset} Shows live verdict dashboard
167
294
 
168
- ${c.bold}OPTIONS${c.reset}
169
- --fastify-entry <path> Fastify entry file for route extraction
170
- --debounce <ms> Debounce delay in ms (default: 500)
171
- --no-clear Don't clear screen between runs
172
- --help, -h Show this help
295
+ ${c.bold}Watched Files:${c.reset}
296
+ ${colors.accent}.ts${c.reset} ${colors.accent}.tsx${c.reset} ${colors.accent}.js${c.reset} ${colors.accent}.jsx${c.reset} ${colors.accent}.json${c.reset} ${colors.accent}.env${c.reset} ${colors.accent}.md${c.reset} ${colors.accent}.yml${c.reset} ${colors.accent}.yaml${c.reset}
173
297
 
174
- ${c.bold}WHAT IT DOES${c.reset}
175
- 1. Runs initial ship analysis
176
- 2. Watches for file changes in your project
177
- 3. Re-runs analysis on each change
178
- 4. Shows live verdict dashboard
298
+ ${c.bold}Ignored:${c.reset}
299
+ ${c.dim}node_modules, .next, .vibecheck, dist, build, .git${c.reset}
179
300
 
180
- ${c.bold}WATCHED FILES${c.reset}
181
- .ts, .tsx, .js, .jsx, .json, .env, .md, .yml, .yaml
301
+ ${c.bold}Examples:${c.reset}
302
+ ${c.dim}# Start watching${c.reset}
303
+ vibecheck watch
182
304
 
183
- ${c.bold}IGNORED${c.reset}
184
- node_modules, .next, .vibecheck, dist, build, .git
305
+ ${c.dim}# 1 second debounce${c.reset}
306
+ vibecheck watch --debounce 1000
185
307
 
186
- ${c.bold}EXAMPLES${c.reset}
187
- vibecheck watch # Start watching
188
- vibecheck watch --debounce 1000 # 1s debounce
189
- vibecheck watch --no-clear # Keep history
308
+ ${c.dim}# Keep history (don't clear)${c.reset}
309
+ vibecheck watch --no-clear
190
310
 
191
- ${c.dim}Press Ctrl+C to stop watching${c.reset}
192
- `);
311
+ ${c.dim}Press Ctrl+C to stop watching${c.reset}
312
+ `);
193
313
  }
194
314
 
195
315
  async function runWatch(argsOrOpts = {}) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibecheck-mcp-server",
3
- "version": "2.1.0",
3
+ "version": "3.0.9",
4
4
  "description": "Professional MCP server for vibecheck - Intelligent development environment vibechecks",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibecheckai/cli",
3
- "version": "3.0.9",
3
+ "version": "3.0.10",
4
4
  "description": "Vibecheck CLI - Ship with confidence. One verdict: SHIP | WARN | BLOCK.",
5
5
  "main": "bin/vibecheck.js",
6
6
  "bin": {