@vibecheckai/cli 3.7.0 → 3.8.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/README.md +135 -63
- package/bin/_deprecations.js +447 -19
- package/bin/_router.js +1 -1
- package/bin/registry.js +347 -280
- package/bin/runners/context/generators/cursor-enhanced.js +2439 -0
- package/bin/runners/lib/agent-firewall/enforcement/gateway.js +1059 -0
- package/bin/runners/lib/agent-firewall/enforcement/index.js +98 -0
- package/bin/runners/lib/agent-firewall/enforcement/mode.js +318 -0
- package/bin/runners/lib/agent-firewall/enforcement/orchestrator.js +484 -0
- package/bin/runners/lib/agent-firewall/enforcement/proof-artifact.js +418 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/change-event.schema.json +173 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/intent.schema.json +181 -0
- package/bin/runners/lib/agent-firewall/enforcement/schemas/verdict.schema.json +222 -0
- package/bin/runners/lib/agent-firewall/enforcement/verdict-v2.js +333 -0
- package/bin/runners/lib/agent-firewall/index.js +200 -0
- package/bin/runners/lib/agent-firewall/integration/index.js +20 -0
- package/bin/runners/lib/agent-firewall/integration/ship-gate.js +437 -0
- package/bin/runners/lib/agent-firewall/intent/alignment-engine.js +622 -0
- package/bin/runners/lib/agent-firewall/intent/auto-detect.js +426 -0
- package/bin/runners/lib/agent-firewall/intent/index.js +102 -0
- package/bin/runners/lib/agent-firewall/intent/schema.js +352 -0
- package/bin/runners/lib/agent-firewall/intent/store.js +283 -0
- package/bin/runners/lib/agent-firewall/interception/fs-interceptor.js +502 -0
- package/bin/runners/lib/agent-firewall/interception/index.js +23 -0
- package/bin/runners/lib/agent-firewall/session/collector.js +451 -0
- package/bin/runners/lib/agent-firewall/session/index.js +26 -0
- package/bin/runners/lib/artifact-envelope.js +540 -0
- package/bin/runners/lib/auth-shared.js +977 -0
- package/bin/runners/lib/checkpoint.js +941 -0
- package/bin/runners/lib/cleanup/engine.js +571 -0
- package/bin/runners/lib/cleanup/index.js +53 -0
- package/bin/runners/lib/cleanup/output.js +375 -0
- package/bin/runners/lib/cleanup/rules.js +1060 -0
- package/bin/runners/lib/doctor/diagnosis-receipt.js +454 -0
- package/bin/runners/lib/doctor/failure-signatures.js +526 -0
- package/bin/runners/lib/doctor/fix-script.js +336 -0
- package/bin/runners/lib/doctor/modules/build-tools.js +453 -0
- package/bin/runners/lib/doctor/modules/index.js +62 -3
- package/bin/runners/lib/doctor/modules/os-quirks.js +706 -0
- package/bin/runners/lib/doctor/modules/repo-integrity.js +485 -0
- package/bin/runners/lib/doctor/safe-repair.js +384 -0
- package/bin/runners/lib/engines/attack-detector.js +1192 -0
- package/bin/runners/lib/entitlements-v2.js +2 -2
- package/bin/runners/lib/missions/briefing.js +427 -0
- package/bin/runners/lib/missions/checkpoint.js +753 -0
- package/bin/runners/lib/missions/hardening.js +851 -0
- package/bin/runners/lib/missions/plan.js +421 -32
- package/bin/runners/lib/missions/safety-gates.js +645 -0
- package/bin/runners/lib/missions/schema.js +478 -0
- package/bin/runners/lib/packs/bundle.js +675 -0
- package/bin/runners/lib/packs/evidence-pack.js +671 -0
- package/bin/runners/lib/packs/pack-factory.js +837 -0
- package/bin/runners/lib/packs/permissions-pack.js +686 -0
- package/bin/runners/lib/packs/proof-graph-pack.js +779 -0
- package/bin/runners/lib/safelist/index.js +96 -0
- package/bin/runners/lib/safelist/integration.js +334 -0
- package/bin/runners/lib/safelist/matcher.js +696 -0
- package/bin/runners/lib/safelist/schema.js +948 -0
- package/bin/runners/lib/safelist/store.js +438 -0
- package/bin/runners/lib/schemas/ship-manifest.schema.json +251 -0
- package/bin/runners/lib/ship-gate.js +832 -0
- package/bin/runners/lib/ship-manifest.js +1153 -0
- package/bin/runners/lib/ship-output.js +1 -1
- package/bin/runners/lib/unified-cli-output.js +710 -383
- package/bin/runners/lib/upsell.js +3 -3
- package/bin/runners/lib/why-tree.js +650 -0
- package/bin/runners/runAllowlist.js +33 -4
- package/bin/runners/runApprove.js +240 -1122
- package/bin/runners/runAudit.js +692 -0
- package/bin/runners/runAuth.js +325 -29
- package/bin/runners/runCheckpoint.js +442 -494
- package/bin/runners/runCleanup.js +343 -0
- package/bin/runners/runDoctor.js +269 -19
- package/bin/runners/runFix.js +411 -32
- package/bin/runners/runForge.js +411 -0
- package/bin/runners/runIntent.js +906 -0
- package/bin/runners/runKickoff.js +878 -0
- package/bin/runners/runLaunch.js +2000 -0
- package/bin/runners/runLink.js +785 -0
- package/bin/runners/runMcp.js +1741 -837
- package/bin/runners/runPacks.js +2089 -0
- package/bin/runners/runPolish.js +41 -0
- package/bin/runners/runSafelist.js +1190 -0
- package/bin/runners/runScan.js +21 -9
- package/bin/runners/runShield.js +1282 -0
- package/bin/runners/runShip.js +395 -16
- package/bin/vibecheck.js +34 -6
- package/mcp-server/README.md +117 -158
- package/mcp-server/handlers/tool-handler.ts +3 -3
- package/mcp-server/index.js +16 -0
- package/mcp-server/intent-firewall-interceptor.js +529 -0
- package/mcp-server/manifest.json +473 -0
- package/mcp-server/package.json +1 -1
- package/mcp-server/registry/tool-registry.js +315 -523
- package/mcp-server/registry/tools.json +442 -428
- package/mcp-server/tier-auth.js +68 -11
- package/mcp-server/tools-v3.js +70 -16
- package/package.json +1 -1
- package/bin/runners/runProof.zip +0 -0
|
@@ -1,37 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Unified CLI Output -
|
|
2
|
+
* Unified CLI Output - World-Class Terminal Experience
|
|
3
3
|
*
|
|
4
4
|
* ═══════════════════════════════════════════════════════════════════════════════
|
|
5
|
-
* VIBECHECK DESIGN SYSTEM
|
|
5
|
+
* THE VIBECHECK DESIGN SYSTEM v2.0
|
|
6
6
|
* ═══════════════════════════════════════════════════════════════════════════════
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Provides consistent, professional terminal UI across all CLI commands:
|
|
9
|
+
* • ASCII art banners (main + command-specific)
|
|
10
|
+
* • Box-drawing layouts with split columns
|
|
11
|
+
* • Progress bars and status indicators
|
|
12
|
+
* • Verdicts and action sections
|
|
13
|
+
*
|
|
14
|
+
* @version 2.0.0
|
|
10
15
|
*/
|
|
11
16
|
|
|
12
17
|
"use strict";
|
|
13
18
|
|
|
14
|
-
const { getApiKey } = require("./auth");
|
|
15
|
-
|
|
16
19
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
17
20
|
// CONSTANTS
|
|
18
21
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
19
22
|
|
|
20
|
-
const WIDTH =
|
|
21
|
-
const
|
|
22
|
-
const SUPPORTS_UNICODE = !process.env.NO_UNICODE && process.platform !== "win32" || process.env.WT_SESSION;
|
|
23
|
+
const WIDTH = 80; // Standard terminal width
|
|
24
|
+
const INNER_WIDTH = WIDTH - 4; // Inside borders
|
|
23
25
|
|
|
24
26
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
25
27
|
// ANSI CODES
|
|
26
28
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
27
29
|
|
|
28
30
|
const ESC = "\x1b";
|
|
31
|
+
const SUPPORTS_COLOR = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
32
|
+
const SUPPORTS_TRUECOLOR = process.env.COLORTERM === "truecolor" ||
|
|
33
|
+
process.env.TERM_PROGRAM === "iTerm.app" ||
|
|
34
|
+
process.env.WT_SESSION;
|
|
35
|
+
|
|
29
36
|
const ansi = SUPPORTS_COLOR ? {
|
|
30
37
|
reset: `${ESC}[0m`,
|
|
31
38
|
bold: `${ESC}[1m`,
|
|
32
39
|
dim: `${ESC}[2m`,
|
|
33
40
|
italic: `${ESC}[3m`,
|
|
34
41
|
underline: `${ESC}[4m`,
|
|
42
|
+
// Standard colors
|
|
35
43
|
red: `${ESC}[31m`,
|
|
36
44
|
green: `${ESC}[32m`,
|
|
37
45
|
yellow: `${ESC}[33m`,
|
|
@@ -40,514 +48,830 @@ const ansi = SUPPORTS_COLOR ? {
|
|
|
40
48
|
cyan: `${ESC}[36m`,
|
|
41
49
|
white: `${ESC}[37m`,
|
|
42
50
|
gray: `${ESC}[90m`,
|
|
43
|
-
|
|
51
|
+
// Bright colors
|
|
52
|
+
brightRed: `${ESC}[91m`,
|
|
53
|
+
brightGreen: `${ESC}[92m`,
|
|
54
|
+
brightYellow: `${ESC}[93m`,
|
|
55
|
+
brightCyan: `${ESC}[96m`,
|
|
56
|
+
// Backgrounds
|
|
44
57
|
bgRed: `${ESC}[41m`,
|
|
58
|
+
bgGreen: `${ESC}[42m`,
|
|
45
59
|
bgYellow: `${ESC}[43m`,
|
|
46
|
-
|
|
60
|
+
bgBlue: `${ESC}[44m`,
|
|
47
61
|
bgMagenta: `${ESC}[45m`,
|
|
62
|
+
bgCyan: `${ESC}[46m`,
|
|
63
|
+
// RGB (truecolor)
|
|
64
|
+
rgb: (r, g, b) => SUPPORTS_TRUECOLOR ? `${ESC}[38;2;${r};${g};${b}m` : "",
|
|
65
|
+
bgRgb: (r, g, b) => SUPPORTS_TRUECOLOR ? `${ESC}[48;2;${r};${g};${b}m` : "",
|
|
66
|
+
// Cursor control
|
|
67
|
+
hideCursor: `${ESC}[?25l`,
|
|
68
|
+
showCursor: `${ESC}[?25h`,
|
|
69
|
+
clearLine: `${ESC}[2K`,
|
|
70
|
+
cursorUp: (n = 1) => `${ESC}[${n}A`,
|
|
48
71
|
} : Object.fromEntries([
|
|
49
72
|
"reset", "bold", "dim", "italic", "underline",
|
|
50
73
|
"red", "green", "yellow", "blue", "magenta", "cyan", "white", "gray",
|
|
51
|
-
"
|
|
74
|
+
"brightRed", "brightGreen", "brightYellow", "brightCyan",
|
|
75
|
+
"bgRed", "bgGreen", "bgYellow", "bgBlue", "bgMagenta", "bgCyan",
|
|
76
|
+
"hideCursor", "showCursor", "clearLine"
|
|
52
77
|
].map(k => [k, ""]));
|
|
53
78
|
|
|
79
|
+
// Add stub functions if colors disabled
|
|
80
|
+
if (!SUPPORTS_COLOR) {
|
|
81
|
+
ansi.rgb = () => "";
|
|
82
|
+
ansi.bgRgb = () => "";
|
|
83
|
+
ansi.cursorUp = () => "";
|
|
84
|
+
}
|
|
85
|
+
|
|
54
86
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
55
87
|
// SYMBOLS
|
|
56
88
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
57
89
|
|
|
58
|
-
const sym =
|
|
90
|
+
const sym = {
|
|
91
|
+
// Status
|
|
59
92
|
check: "✓",
|
|
60
93
|
cross: "✗",
|
|
61
94
|
warning: "⚠",
|
|
62
95
|
info: "ℹ",
|
|
63
|
-
arrow: "→",
|
|
64
96
|
bullet: "•",
|
|
97
|
+
arrow: "→",
|
|
98
|
+
arrowRight: "▸",
|
|
65
99
|
star: "★",
|
|
100
|
+
// Progress
|
|
101
|
+
blockFull: "█",
|
|
102
|
+
blockMed: "▓",
|
|
103
|
+
blockLight: "▒",
|
|
104
|
+
blockEmpty: "░",
|
|
105
|
+
// Box drawing (double)
|
|
106
|
+
boxTL: "╔",
|
|
107
|
+
boxTR: "╗",
|
|
108
|
+
boxBL: "╚",
|
|
109
|
+
boxBR: "╝",
|
|
110
|
+
boxH: "═",
|
|
111
|
+
boxV: "║",
|
|
112
|
+
boxTeeR: "╠",
|
|
113
|
+
boxTeeL: "╣",
|
|
114
|
+
boxTeeD: "╦",
|
|
115
|
+
boxTeeU: "╩",
|
|
116
|
+
boxCross: "╬",
|
|
117
|
+
// Box drawing (single)
|
|
118
|
+
lineTL: "┌",
|
|
119
|
+
lineTR: "┐",
|
|
120
|
+
lineBL: "└",
|
|
121
|
+
lineBR: "┘",
|
|
122
|
+
lineH: "─",
|
|
123
|
+
lineV: "│",
|
|
124
|
+
lineTeeR: "├",
|
|
125
|
+
lineTeeL: "┤",
|
|
126
|
+
lineTeeD: "┬",
|
|
127
|
+
lineTeeU: "┴",
|
|
128
|
+
lineCross: "┼",
|
|
129
|
+
// Emoji
|
|
66
130
|
rocket: "🚀",
|
|
131
|
+
fire: "🔥",
|
|
132
|
+
brain: "🧠",
|
|
67
133
|
shield: "🛡️",
|
|
68
|
-
lock: "🔒",
|
|
69
|
-
key: "🔑",
|
|
70
|
-
gear: "⚙",
|
|
71
134
|
search: "🔍",
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
135
|
+
lock: "🔐",
|
|
136
|
+
unlock: "🔓",
|
|
137
|
+
link: "🔗",
|
|
75
138
|
clock: "⏱",
|
|
76
|
-
lightning: "⚡",
|
|
77
|
-
sparkle: "✨",
|
|
78
|
-
fire: "🔥",
|
|
79
139
|
target: "🎯",
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
warning: "!",
|
|
90
|
-
info: "i",
|
|
91
|
-
arrow: "->",
|
|
92
|
-
bullet: "*",
|
|
93
|
-
star: "*",
|
|
94
|
-
rocket: ">",
|
|
95
|
-
shield: "[S]",
|
|
96
|
-
lock: "[L]",
|
|
97
|
-
key: "[K]",
|
|
98
|
-
gear: "[G]",
|
|
99
|
-
search: "[?]",
|
|
100
|
-
chart: "[C]",
|
|
101
|
-
file: "[F]",
|
|
102
|
-
folder: "[D]",
|
|
103
|
-
clock: "[T]",
|
|
104
|
-
lightning: "[!]",
|
|
105
|
-
sparkle: "*",
|
|
106
|
-
fire: "(!)",
|
|
107
|
-
target: "(>)",
|
|
108
|
-
trophy: "[W]",
|
|
109
|
-
box: {
|
|
110
|
-
tl: "+", tr: "+", bl: "+", br: "+", h: "-", v: "|",
|
|
111
|
-
ltl: "+", ltr: "+", lbl: "+", lbr: "+", lh: "-", lv: "|",
|
|
112
|
-
lt: "+", lb: "+", lx: "+", ltrT: "+", ltlT: "+",
|
|
113
|
-
},
|
|
140
|
+
party: "🎉",
|
|
141
|
+
skull: "💀",
|
|
142
|
+
bomb: "💣",
|
|
143
|
+
ghost: "👻",
|
|
144
|
+
money: "💰",
|
|
145
|
+
doc: "📄",
|
|
146
|
+
box: "📦",
|
|
147
|
+
sparkle: "✨",
|
|
148
|
+
lightning: "⚡",
|
|
114
149
|
};
|
|
115
150
|
|
|
116
151
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
117
|
-
//
|
|
118
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
152
|
+
// ASCII ART BANNERS
|
|
153
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
154
|
+
|
|
155
|
+
const VIBECHECK_BANNER = `
|
|
156
|
+
██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗
|
|
157
|
+
██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝
|
|
158
|
+
██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝
|
|
159
|
+
╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗
|
|
160
|
+
╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗
|
|
161
|
+
╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝`.trim();
|
|
162
|
+
|
|
163
|
+
const COMMAND_BANNERS = {
|
|
164
|
+
launch: `
|
|
165
|
+
██╗ █████╗ ██╗ ██╗███╗ ██╗ ██████╗██╗ ██╗
|
|
166
|
+
██║ ██╔══██╗██║ ██║████╗ ██║██╔════╝██║ ██║
|
|
167
|
+
██║ ███████║██║ ██║██╔██╗ ██║██║ ███████║
|
|
168
|
+
██║ ██╔══██║██║ ██║██║╚██╗██║██║ ██╔══██║
|
|
169
|
+
███████╗██║ ██║╚██████╔╝██║ ╚████║╚██████╗██║ ██║
|
|
170
|
+
╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝╚═╝ ╚═╝`.trim(),
|
|
171
|
+
|
|
172
|
+
kickoff: `
|
|
173
|
+
██╗ ██╗██╗ ██████╗██╗ ██╗ ██████╗ ███████╗███████╗
|
|
174
|
+
██║ ██╔╝██║██╔════╝██║ ██╔╝██╔═══██╗██╔════╝██╔════╝
|
|
175
|
+
█████╔╝ ██║██║ █████╔╝ ██║ ██║█████╗ █████╗
|
|
176
|
+
██╔═██╗ ██║██║ ██╔═██╗ ██║ ██║██╔══╝ ██╔══╝
|
|
177
|
+
██║ ██╗██║╚██████╗██║ ██╗╚██████╔╝██║ ██║
|
|
178
|
+
╚═╝ ╚═╝╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝`.trim(),
|
|
179
|
+
|
|
180
|
+
scan: `
|
|
181
|
+
███████╗ ██████╗ █████╗ ███╗ ██╗
|
|
182
|
+
██╔════╝██╔════╝██╔══██╗████╗ ██║
|
|
183
|
+
███████╗██║ ███████║██╔██╗ ██║
|
|
184
|
+
╚════██║██║ ██╔══██║██║╚██╗██║
|
|
185
|
+
███████║╚██████╗██║ ██║██║ ╚████║
|
|
186
|
+
╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝`.trim(),
|
|
187
|
+
|
|
188
|
+
audit: `
|
|
189
|
+
█████╗ ██╗ ██╗██████╗ ██╗████████╗
|
|
190
|
+
██╔══██╗██║ ██║██╔══██╗██║╚══██╔══╝
|
|
191
|
+
███████║██║ ██║██║ ██║██║ ██║
|
|
192
|
+
██╔══██║██║ ██║██║ ██║██║ ██║
|
|
193
|
+
██║ ██║╚██████╔╝██████╔╝██║ ██║
|
|
194
|
+
╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝`.trim(),
|
|
195
|
+
|
|
196
|
+
packs: `
|
|
197
|
+
██████╗ █████╗ ██████╗██╗ ██╗███████╗
|
|
198
|
+
██╔══██╗██╔══██╗██╔════╝██║ ██╔╝██╔════╝
|
|
199
|
+
██████╔╝███████║██║ █████╔╝ ███████╗
|
|
200
|
+
██╔═══╝ ██╔══██║██║ ██╔═██╗ ╚════██║
|
|
201
|
+
██║ ██║ ██║╚██████╗██║ ██╗███████║
|
|
202
|
+
╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝╚══════╝`.trim(),
|
|
203
|
+
|
|
204
|
+
safelist: `
|
|
205
|
+
███████╗ █████╗ ███████╗███████╗██╗ ██╗███████╗████████╗
|
|
206
|
+
██╔════╝██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝╚══██╔══╝
|
|
207
|
+
███████╗███████║█████╗ █████╗ ██║ ██║███████╗ ██║
|
|
208
|
+
╚════██║██╔══██║██╔══╝ ██╔══╝ ██║ ██║╚════██║ ██║
|
|
209
|
+
███████║██║ ██║██║ ███████╗███████╗██║███████║ ██║
|
|
210
|
+
╚══════╝╚═╝ ╚═╝╚═╝ ╚══════╝╚══════╝╚═╝╚══════╝ ╚═╝`.trim(),
|
|
211
|
+
|
|
212
|
+
doctor: `
|
|
213
|
+
██████╗ ██████╗ ██████╗████████╗ ██████╗ ██████╗
|
|
214
|
+
██╔══██╗██╔═══██╗██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗
|
|
215
|
+
██║ ██║██║ ██║██║ ██║ ██║ ██║██████╔╝
|
|
216
|
+
██║ ██║██║ ██║██║ ██║ ██║ ██║██╔══██╗
|
|
217
|
+
██████╔╝╚██████╔╝╚██████╗ ██║ ╚██████╔╝██║ ██║
|
|
218
|
+
╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝`.trim(),
|
|
219
|
+
|
|
220
|
+
watch: `
|
|
221
|
+
██╗ ██╗ █████╗ ████████╗ ██████╗██╗ ██╗
|
|
222
|
+
██║ ██║██╔══██╗╚══██╔══╝██╔════╝██║ ██║
|
|
223
|
+
██║ █╗ ██║███████║ ██║ ██║ ███████║
|
|
224
|
+
██║███╗██║██╔══██║ ██║ ██║ ██╔══██║
|
|
225
|
+
╚███╔███╔╝██║ ██║ ██║ ╚██████╗██║ ██║
|
|
226
|
+
╚══╝╚══╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝`.trim(),
|
|
227
|
+
|
|
228
|
+
init: `
|
|
229
|
+
██╗███╗ ██╗██╗████████╗
|
|
230
|
+
██║████╗ ██║██║╚══██╔══╝
|
|
231
|
+
██║██╔██╗ ██║██║ ██║
|
|
232
|
+
██║██║╚██╗██║██║ ██║
|
|
233
|
+
██║██║ ╚████║██║ ██║
|
|
234
|
+
╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝`.trim(),
|
|
235
|
+
|
|
236
|
+
ship: `
|
|
237
|
+
███████╗██╗ ██╗██╗██████╗
|
|
238
|
+
██╔════╝██║ ██║██║██╔══██╗
|
|
239
|
+
███████╗███████║██║██████╔╝
|
|
240
|
+
╚════██║██╔══██║██║██╔═══╝
|
|
241
|
+
███████║██║ ██║██║██║
|
|
242
|
+
╚══════╝╚═╝ ╚═╝╚═╝╚═╝`.trim(),
|
|
243
|
+
|
|
244
|
+
forge: `
|
|
245
|
+
███████╗ ██████╗ ██████╗ ██████╗ ███████╗
|
|
246
|
+
██╔════╝██╔═══██╗██╔══██╗██╔════╝ ██╔════╝
|
|
247
|
+
█████╗ ██║ ██║██████╔╝██║ ███╗█████╗
|
|
248
|
+
██╔══╝ ██║ ██║██╔══██╗██║ ██║██╔══╝
|
|
249
|
+
██║ ╚██████╔╝██║ ██║╚██████╔╝███████╗
|
|
250
|
+
╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝`.trim(),
|
|
251
|
+
|
|
252
|
+
shield: `
|
|
253
|
+
███████╗██╗ ██╗██╗███████╗██╗ ██████╗
|
|
254
|
+
██╔════╝██║ ██║██║██╔════╝██║ ██╔══██╗
|
|
255
|
+
███████╗███████║██║█████╗ ██║ ██║ ██║
|
|
256
|
+
╚════██║██╔══██║██║██╔══╝ ██║ ██║ ██║
|
|
257
|
+
███████║██║ ██║██║███████╗███████╗██████╔╝
|
|
258
|
+
╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚═════╝`.trim(),
|
|
259
|
+
|
|
260
|
+
fix: `
|
|
261
|
+
███████╗██╗██╗ ██╗
|
|
262
|
+
██╔════╝██║╚██╗██╔╝
|
|
263
|
+
█████╗ ██║ ╚███╔╝
|
|
264
|
+
██╔══╝ ██║ ██╔██╗
|
|
265
|
+
██║ ██║██╔╝ ██╗
|
|
266
|
+
╚═╝ ╚═╝╚═╝ ╚═╝`.trim(),
|
|
267
|
+
|
|
268
|
+
link: `
|
|
269
|
+
██╗ ██╗███╗ ██╗██╗ ██╗
|
|
270
|
+
██║ ██║████╗ ██║██║ ██╔╝
|
|
271
|
+
██║ ██║██╔██╗ ██║█████╔╝
|
|
272
|
+
██║ ██║██║╚██╗██║██╔═██╗
|
|
273
|
+
███████╗██║██║ ╚████║██║ ██╗
|
|
274
|
+
╚══════╝╚═╝╚═╝ ╚═══╝╚═╝ ╚═╝`.trim(),
|
|
275
|
+
|
|
276
|
+
prove: `
|
|
277
|
+
██████╗ ██████╗ ██████╗ ██╗ ██╗███████╗
|
|
278
|
+
██╔══██╗██╔══██╗██╔═══██╗██║ ██║██╔════╝
|
|
279
|
+
██████╔╝██████╔╝██║ ██║██║ ██║█████╗
|
|
280
|
+
██╔═══╝ ██╔══██╗██║ ██║╚██╗ ██╔╝██╔══╝
|
|
281
|
+
██║ ██║ ██║╚██████╔╝ ╚████╔╝ ███████╗
|
|
282
|
+
╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═══╝ ╚══════╝`.trim(),
|
|
283
|
+
|
|
284
|
+
reality: `
|
|
285
|
+
██████╗ ███████╗ █████╗ ██╗ ██╗████████╗██╗ ██╗
|
|
286
|
+
██╔══██╗██╔════╝██╔══██╗██║ ██║╚══██╔══╝╚██╗ ██╔╝
|
|
287
|
+
██████╔╝█████╗ ███████║██║ ██║ ██║ ╚████╔╝
|
|
288
|
+
██╔══██╗██╔══╝ ██╔══██║██║ ██║ ██║ ╚██╔╝
|
|
289
|
+
██║ ██║███████╗██║ ██║███████╗██║ ██║ ██║
|
|
290
|
+
╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝`.trim(),
|
|
125
291
|
};
|
|
126
292
|
|
|
127
|
-
function getTierBadge(tier) {
|
|
128
|
-
const t = TIER[tier] || TIER.free;
|
|
129
|
-
return `${t.color}[${t.label}]${ansi.reset}`;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function getTierFromKey() {
|
|
133
|
-
const { key } = getApiKey();
|
|
134
|
-
if (!key) return "free";
|
|
135
|
-
// Simplified tier detection - in real app would check entitlements
|
|
136
|
-
return "starter";
|
|
137
|
-
}
|
|
138
|
-
|
|
139
293
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
140
294
|
// UTILITY FUNCTIONS
|
|
141
295
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
142
296
|
|
|
297
|
+
/**
|
|
298
|
+
* Strip ANSI codes for length calculation
|
|
299
|
+
*/
|
|
143
300
|
function stripAnsi(str) {
|
|
144
|
-
return str.replace(/\
|
|
301
|
+
return str.replace(/\u001b\[[0-9;]*m/g, "");
|
|
145
302
|
}
|
|
146
303
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return
|
|
304
|
+
/**
|
|
305
|
+
* Get visible length of string (excluding ANSI codes)
|
|
306
|
+
*/
|
|
307
|
+
function visibleLength(str) {
|
|
308
|
+
return stripAnsi(str).length;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Pad string to right with spaces
|
|
313
|
+
*/
|
|
314
|
+
function padRight(str, len) {
|
|
315
|
+
const visible = visibleLength(str);
|
|
316
|
+
if (visible >= len) return str;
|
|
317
|
+
return str + " ".repeat(len - visible);
|
|
152
318
|
}
|
|
153
319
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
320
|
+
/**
|
|
321
|
+
* Pad string to left with spaces
|
|
322
|
+
*/
|
|
323
|
+
function padLeft(str, len) {
|
|
324
|
+
const visible = visibleLength(str);
|
|
325
|
+
if (visible >= len) return str;
|
|
326
|
+
return " ".repeat(len - visible) + str;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Center string within given width
|
|
331
|
+
*/
|
|
332
|
+
function padCenter(str, width) {
|
|
333
|
+
const visible = visibleLength(str);
|
|
334
|
+
if (visible >= width) return str;
|
|
335
|
+
const padding = width - visible;
|
|
336
|
+
const left = Math.floor(padding / 2);
|
|
337
|
+
return " ".repeat(left) + str + " ".repeat(padding - left);
|
|
157
338
|
}
|
|
158
339
|
|
|
340
|
+
/**
|
|
341
|
+
* Truncate string with ellipsis
|
|
342
|
+
*/
|
|
159
343
|
function truncate(str, maxLen) {
|
|
160
|
-
const
|
|
161
|
-
if (
|
|
162
|
-
return
|
|
344
|
+
const visible = visibleLength(str);
|
|
345
|
+
if (visible <= maxLen) return str;
|
|
346
|
+
return stripAnsi(str).substring(0, maxLen - 3) + "...";
|
|
163
347
|
}
|
|
164
348
|
|
|
349
|
+
/**
|
|
350
|
+
* Format duration
|
|
351
|
+
*/
|
|
165
352
|
function formatDuration(ms) {
|
|
166
353
|
if (ms < 1000) return `${ms}ms`;
|
|
167
354
|
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
|
|
168
|
-
|
|
355
|
+
const minutes = Math.floor(ms / 60000);
|
|
356
|
+
const seconds = Math.floor((ms % 60000) / 1000);
|
|
357
|
+
return `${minutes}m ${seconds}s`;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* Format number with commas
|
|
362
|
+
*/
|
|
363
|
+
function formatNumber(num) {
|
|
364
|
+
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
169
365
|
}
|
|
170
366
|
|
|
171
367
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
172
|
-
//
|
|
368
|
+
// PROGRESS BAR
|
|
173
369
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
174
370
|
|
|
175
371
|
/**
|
|
176
|
-
* Render a
|
|
177
|
-
* @param {
|
|
178
|
-
* @param {
|
|
179
|
-
* @param {
|
|
180
|
-
* @param {string} opts.tier - Tier requirement (free, starter, pro)
|
|
181
|
-
* @param {string} [opts.subtitle] - Optional subtitle
|
|
372
|
+
* Render a progress bar
|
|
373
|
+
* @param {number} percent - 0-100
|
|
374
|
+
* @param {number} width - Character width
|
|
375
|
+
* @param {object} opts - Options { color, showPercent, label }
|
|
182
376
|
*/
|
|
183
|
-
function
|
|
184
|
-
const {
|
|
185
|
-
const
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
const lines = [];
|
|
189
|
-
|
|
190
|
-
// Top border
|
|
191
|
-
lines.push(`${ansi.gray}${b.tl}${b.h.repeat(WIDTH - 2)}${b.tr}${ansi.reset}`);
|
|
377
|
+
function renderProgressBar(percent, width = 25, opts = {}) {
|
|
378
|
+
const { color = ansi.green, bgColor = ansi.gray, showPercent = false, label = "" } = opts;
|
|
379
|
+
const filled = Math.round((percent / 100) * width);
|
|
380
|
+
const empty = width - filled;
|
|
192
381
|
|
|
193
|
-
|
|
194
|
-
const titleStr = `${ansi.bold}${title}${ansi.reset} ${tierBadge}`;
|
|
195
|
-
lines.push(`${ansi.gray}${b.v}${ansi.reset}${padCenter(titleStr, WIDTH - 2)}${ansi.gray}${b.v}${ansi.reset}`);
|
|
382
|
+
let bar = `${color}${sym.blockFull.repeat(filled)}${bgColor}${sym.blockEmpty.repeat(empty)}${ansi.reset}`;
|
|
196
383
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
const subStr = `${ansi.dim}${subtitle}${ansi.reset}`;
|
|
200
|
-
lines.push(`${ansi.gray}${b.v}${ansi.reset}${padCenter(subStr, WIDTH - 2)}${ansi.gray}${b.v}${ansi.reset}`);
|
|
384
|
+
if (showPercent) {
|
|
385
|
+
bar += ` ${percent}%`;
|
|
201
386
|
}
|
|
202
387
|
|
|
203
|
-
|
|
204
|
-
|
|
388
|
+
if (label) {
|
|
389
|
+
return `${label} [${bar}]`;
|
|
390
|
+
}
|
|
205
391
|
|
|
206
|
-
|
|
392
|
+
return `[${bar}]`;
|
|
207
393
|
}
|
|
208
394
|
|
|
209
395
|
/**
|
|
210
|
-
* Render a
|
|
396
|
+
* Render a status indicator with label
|
|
211
397
|
*/
|
|
212
|
-
function
|
|
213
|
-
const
|
|
214
|
-
|
|
398
|
+
function renderStatus(label, status, width = 20) {
|
|
399
|
+
const colors = {
|
|
400
|
+
OPTIMAL: ansi.green,
|
|
401
|
+
STABLE: ansi.green,
|
|
402
|
+
GOOD: ansi.green,
|
|
403
|
+
OK: ansi.green,
|
|
404
|
+
PASS: ansi.green,
|
|
405
|
+
WARNING: ansi.yellow,
|
|
406
|
+
WARN: ansi.yellow,
|
|
407
|
+
HEAVY: ansi.yellow,
|
|
408
|
+
DEGRADED: ansi.yellow,
|
|
409
|
+
CRITICAL: ansi.red,
|
|
410
|
+
FAIL: ansi.red,
|
|
411
|
+
ERROR: ansi.red,
|
|
412
|
+
LOW: ansi.red,
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
const color = colors[status.toUpperCase()] || ansi.gray;
|
|
416
|
+
return `${padRight(label, width)} ${color}[${status}]${ansi.reset}`;
|
|
215
417
|
}
|
|
216
418
|
|
|
217
419
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
218
|
-
//
|
|
420
|
+
// HEADER RENDERING
|
|
219
421
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
220
422
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
423
|
+
/**
|
|
424
|
+
* Render the full header with VIBECHECK banner and command banner
|
|
425
|
+
*/
|
|
426
|
+
function renderFullHeader(command, opts = {}) {
|
|
427
|
+
const {
|
|
428
|
+
version = "4.0.0",
|
|
429
|
+
tier = "FREE",
|
|
430
|
+
integrity = null,
|
|
431
|
+
target = process.cwd(),
|
|
432
|
+
sessionId = generateSessionId(),
|
|
433
|
+
duration = null,
|
|
434
|
+
} = opts;
|
|
435
|
+
|
|
436
|
+
const lines = [];
|
|
437
|
+
|
|
438
|
+
// Main VIBECHECK banner with gradient colors
|
|
439
|
+
const vibeLines = VIBECHECK_BANNER.split("\n");
|
|
440
|
+
const gradientColors = [
|
|
441
|
+
ansi.rgb(0, 255, 200),
|
|
442
|
+
ansi.rgb(0, 230, 220),
|
|
443
|
+
ansi.rgb(0, 200, 255),
|
|
444
|
+
ansi.rgb(50, 150, 255),
|
|
445
|
+
ansi.rgb(100, 100, 255),
|
|
446
|
+
ansi.rgb(150, 50, 255),
|
|
447
|
+
];
|
|
448
|
+
|
|
449
|
+
lines.push("");
|
|
450
|
+
vibeLines.forEach((line, i) => {
|
|
451
|
+
const color = gradientColors[i % gradientColors.length] || ansi.cyan;
|
|
452
|
+
lines.push(` ${color}${line}${ansi.reset}`);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
// Main box
|
|
456
|
+
lines.push("");
|
|
457
|
+
lines.push(`${ansi.cyan}${sym.boxTL}${sym.boxH.repeat(WIDTH - 2)}${sym.boxTR}${ansi.reset}`);
|
|
458
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset}${" ".repeat(WIDTH - 2)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
459
|
+
|
|
460
|
+
// Command banner
|
|
461
|
+
const cmdBanner = COMMAND_BANNERS[command];
|
|
462
|
+
if (cmdBanner) {
|
|
463
|
+
const cmdLines = cmdBanner.split("\n");
|
|
464
|
+
cmdLines.forEach(line => {
|
|
465
|
+
const centered = padCenter(line, WIDTH - 4);
|
|
466
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${ansi.bold}${ansi.white}${centered}${ansi.reset} ${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset}${" ".repeat(WIDTH - 2)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
471
|
+
|
|
472
|
+
// Info bar
|
|
473
|
+
const tierBadge = tier === "PRO" ? `${ansi.magenta}PRO${ansi.reset}` : `${ansi.gray}FREE${ansi.reset}`;
|
|
474
|
+
const integrityStr = integrity ? ` :: SYSTEM INTEGRITY: ${getIntegrityColor(integrity)}${integrity}${ansi.reset}` : "";
|
|
475
|
+
const infoLine = `v${version} ${tierBadge}${integrityStr}`;
|
|
476
|
+
|
|
477
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${infoLine}${" ".repeat(Math.max(0, WIDTH - 4 - visibleLength(infoLine)))}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
478
|
+
|
|
479
|
+
// Target and session line
|
|
480
|
+
const shortTarget = truncate(target, 40);
|
|
481
|
+
const durationStr = duration ? ` | Time: ${formatDuration(duration)}` : "";
|
|
482
|
+
const targetLine = `Target: ${shortTarget}${" ".repeat(6)}Session: #${sessionId}${durationStr}`;
|
|
483
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${ansi.dim}${truncate(targetLine, WIDTH - 6)}${ansi.reset}${" ".repeat(Math.max(0, WIDTH - 4 - visibleLength(targetLine)))}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
484
|
+
|
|
485
|
+
// Separator
|
|
486
|
+
lines.push(`${ansi.cyan}${sym.boxTeeR}${sym.boxH.repeat(WIDTH - 2)}${sym.boxTeeL}${ansi.reset}`);
|
|
487
|
+
|
|
488
|
+
return lines.join("\n");
|
|
229
489
|
}
|
|
230
490
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
491
|
+
/**
|
|
492
|
+
* Get color for integrity level
|
|
493
|
+
*/
|
|
494
|
+
function getIntegrityColor(integrity) {
|
|
495
|
+
const upper = integrity.toUpperCase();
|
|
496
|
+
if (upper === "HIGH" || upper === "OPTIMAL") return ansi.green;
|
|
497
|
+
if (upper === "MEDIUM" || upper === "STABLE") return ansi.yellow;
|
|
498
|
+
return ansi.red;
|
|
237
499
|
}
|
|
238
500
|
|
|
239
|
-
|
|
240
|
-
|
|
501
|
+
/**
|
|
502
|
+
* Generate a short session ID
|
|
503
|
+
*/
|
|
504
|
+
function generateSessionId() {
|
|
505
|
+
const chars = "0123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
|
|
506
|
+
let id = "";
|
|
507
|
+
for (let i = 0; i < 6; i++) {
|
|
508
|
+
id += chars[Math.floor(Math.random() * chars.length)];
|
|
509
|
+
}
|
|
510
|
+
return id;
|
|
241
511
|
}
|
|
242
512
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
513
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
514
|
+
// MINIMAL HEADER (for simpler commands)
|
|
515
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
246
516
|
|
|
247
|
-
|
|
248
|
-
|
|
517
|
+
/**
|
|
518
|
+
* Render a minimal header (no full banner, just command name)
|
|
519
|
+
*/
|
|
520
|
+
function renderMinimalHeader(command, tier = "free") {
|
|
521
|
+
const tierBadge = tier === "pro" ? `${ansi.magenta}PRO${ansi.reset}` : `${ansi.dim}free${ansi.reset}`;
|
|
522
|
+
console.log();
|
|
523
|
+
console.log(` ${ansi.cyan}${sym.boxTL}${sym.boxH.repeat(60)}${sym.boxTR}${ansi.reset}`);
|
|
524
|
+
console.log(` ${ansi.cyan}${sym.boxV}${ansi.reset} ${ansi.bold}vibecheck ${command}${ansi.reset} ${tierBadge}${" ".repeat(60 - 15 - command.length - (tier === "pro" ? 3 : 4))}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
525
|
+
console.log(` ${ansi.cyan}${sym.boxBL}${sym.boxH.repeat(60)}${sym.boxBR}${ansi.reset}`);
|
|
526
|
+
console.log();
|
|
249
527
|
}
|
|
250
528
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
529
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
530
|
+
// SPLIT COLUMN LAYOUT
|
|
531
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
254
532
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
533
|
+
/**
|
|
534
|
+
* Render a split-column section
|
|
535
|
+
*/
|
|
536
|
+
function renderSplitColumns(leftTitle, rightTitle, leftContent, rightContent, opts = {}) {
|
|
537
|
+
const { leftWidth = 44, rightWidth = 33 } = opts;
|
|
538
|
+
const lines = [];
|
|
539
|
+
|
|
540
|
+
// Header row
|
|
541
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${ansi.bold}${padRight(leftTitle, leftWidth)}${ansi.reset}${ansi.dim}│${ansi.reset} ${ansi.bold}${padRight(rightTitle, rightWidth)}${ansi.reset}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
542
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${sym.lineH.repeat(leftWidth)}${ansi.dim}┼${ansi.reset}${sym.lineH.repeat(rightWidth + 1)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
543
|
+
|
|
544
|
+
// Content rows
|
|
545
|
+
const maxRows = Math.max(leftContent.length, rightContent.length);
|
|
546
|
+
for (let i = 0; i < maxRows; i++) {
|
|
547
|
+
const left = leftContent[i] || "";
|
|
548
|
+
const right = rightContent[i] || "";
|
|
549
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${padRight(left, leftWidth)}${ansi.dim}│${ansi.reset} ${padRight(right, rightWidth)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
return lines.join("\n");
|
|
261
553
|
}
|
|
262
554
|
|
|
263
555
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
264
|
-
//
|
|
556
|
+
// VITALS SECTION
|
|
265
557
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
266
558
|
|
|
267
559
|
/**
|
|
268
|
-
* Render
|
|
269
|
-
* @param {string} verdict - SHIP, WARN, or BLOCK
|
|
270
|
-
* @param {object} [stats] - Optional statistics
|
|
560
|
+
* Render system vitals with progress bars
|
|
271
561
|
*/
|
|
272
|
-
function
|
|
273
|
-
const
|
|
274
|
-
const v = String(verdict).toUpperCase();
|
|
275
|
-
|
|
276
|
-
let bg, icon, label;
|
|
277
|
-
switch (v) {
|
|
278
|
-
case "SHIP":
|
|
279
|
-
case "PASS":
|
|
280
|
-
case "SUCCESS":
|
|
281
|
-
bg = ansi.bgGreen;
|
|
282
|
-
icon = sym.rocket;
|
|
283
|
-
label = "SHIP";
|
|
284
|
-
break;
|
|
285
|
-
case "WARN":
|
|
286
|
-
case "WARNING":
|
|
287
|
-
bg = ansi.bgYellow;
|
|
288
|
-
icon = sym.warning;
|
|
289
|
-
label = "WARN";
|
|
290
|
-
break;
|
|
291
|
-
case "BLOCK":
|
|
292
|
-
case "FAIL":
|
|
293
|
-
case "ERROR":
|
|
294
|
-
bg = ansi.bgRed;
|
|
295
|
-
icon = sym.cross;
|
|
296
|
-
label = "BLOCK";
|
|
297
|
-
break;
|
|
298
|
-
default:
|
|
299
|
-
bg = ansi.bgCyan;
|
|
300
|
-
icon = sym.info;
|
|
301
|
-
label = v;
|
|
302
|
-
}
|
|
562
|
+
function renderVitals(vitals) {
|
|
563
|
+
const lines = [];
|
|
303
564
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
if (
|
|
317
|
-
|
|
565
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${ansi.bold}SYSTEM VITALS${ansi.reset}${" ".repeat(WIDTH - 17)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
566
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${sym.lineH.repeat(WIDTH - 4)} ${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
567
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset}${" ".repeat(WIDTH - 2)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
568
|
+
|
|
569
|
+
for (const vital of vitals) {
|
|
570
|
+
const { label, value, status, percent } = vital;
|
|
571
|
+
const statusColor = getStatusColor(status);
|
|
572
|
+
|
|
573
|
+
let line = ` ${padRight(label, 18)} ${statusColor}[${status}]${ansi.reset}`;
|
|
574
|
+
if (percent !== undefined) {
|
|
575
|
+
const bar = renderProgressBar(percent, 25);
|
|
576
|
+
line += `\n${ansi.cyan}${sym.boxV}${ansi.reset} ${bar} ${percent}%`;
|
|
577
|
+
} else if (value) {
|
|
578
|
+
line += ` ${ansi.dim}${value}${ansi.reset}`;
|
|
579
|
+
}
|
|
318
580
|
|
|
319
|
-
|
|
320
|
-
console.log(` ${ansi.gray}${b.v}${ansi.reset}${padCenter(statsStr, WIDTH - 4)}${ansi.gray}${b.v}${ansi.reset}`);
|
|
581
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset}${line}${" ".repeat(Math.max(0, WIDTH - 4 - visibleLength(line)))}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
321
582
|
}
|
|
322
583
|
|
|
323
|
-
|
|
324
|
-
|
|
584
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset}${" ".repeat(WIDTH - 2)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
585
|
+
|
|
586
|
+
return lines.join("\n");
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Get color for status
|
|
591
|
+
*/
|
|
592
|
+
function getStatusColor(status) {
|
|
593
|
+
const upper = String(status).toUpperCase();
|
|
594
|
+
if (["OPTIMAL", "STABLE", "GOOD", "PASS", "HIGH", "SHIP", "LAUNCH"].includes(upper)) return ansi.green;
|
|
595
|
+
if (["WARNING", "WARN", "HEAVY", "DEGRADED", "MEDIUM"].includes(upper)) return ansi.yellow;
|
|
596
|
+
return ansi.red;
|
|
325
597
|
}
|
|
326
598
|
|
|
327
599
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
328
|
-
// FINDINGS
|
|
600
|
+
// FINDINGS/DIAGNOSTIC SECTION
|
|
329
601
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
330
602
|
|
|
331
603
|
/**
|
|
332
|
-
* Render
|
|
333
|
-
* @param {Array} findings - Array of finding objects
|
|
334
|
-
* @param {object} opts - Options
|
|
335
|
-
* @param {number} [opts.limit=5] - Max findings to show
|
|
604
|
+
* Render diagnostic log / findings
|
|
336
605
|
*/
|
|
337
|
-
function
|
|
338
|
-
const {
|
|
339
|
-
const
|
|
606
|
+
function renderDiagnostics(findings, opts = {}) {
|
|
607
|
+
const { maxItems = 5, title = "DIAGNOSTIC LOG" } = opts;
|
|
608
|
+
const lines = [];
|
|
609
|
+
|
|
610
|
+
lines.push(`${ansi.bold}${title}${ansi.reset}`);
|
|
611
|
+
lines.push(`${sym.lineH.repeat(30)}`);
|
|
340
612
|
|
|
341
|
-
if (
|
|
342
|
-
|
|
343
|
-
|
|
613
|
+
if (findings.length === 0) {
|
|
614
|
+
lines.push("");
|
|
615
|
+
lines.push(`${ansi.green}${sym.check} No issues found${ansi.reset}`);
|
|
616
|
+
return lines;
|
|
344
617
|
}
|
|
345
618
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
// Header
|
|
351
|
-
console.log(` ${ansi.gray}${b.ltl}${b.lh.repeat(COL1)}${b.lt}${b.lh.repeat(COL2)}${b.lt}${b.lh.repeat(COL3)}${b.ltr}${ansi.reset}`);
|
|
352
|
-
console.log(` ${ansi.gray}${b.lv}${ansi.reset}${ansi.bold}${padRight(" SEVERITY", COL1)}${ansi.reset}${ansi.gray}${b.lv}${ansi.reset}${ansi.bold}${padRight(" CATEGORY", COL2)}${ansi.reset}${ansi.gray}${b.lv}${ansi.reset}${ansi.bold}${padRight(" MESSAGE", COL3)}${ansi.reset}${ansi.gray}${b.lv}${ansi.reset}`);
|
|
353
|
-
console.log(` ${ansi.gray}${b.ltrT}${b.lh.repeat(COL1)}${b.lx}${b.lh.repeat(COL2)}${b.lx}${b.lh.repeat(COL3)}${b.ltlT}${ansi.reset}`);
|
|
354
|
-
|
|
355
|
-
// Rows
|
|
356
|
-
const shown = findings.slice(0, limit);
|
|
357
|
-
for (const f of shown) {
|
|
358
|
-
const sev = f.severity?.toUpperCase() || "INFO";
|
|
359
|
-
let sevStr;
|
|
360
|
-
switch (sev) {
|
|
361
|
-
case "BLOCK":
|
|
362
|
-
case "CRITICAL":
|
|
363
|
-
sevStr = `${ansi.red} ${sym.cross} BLOCK${ansi.reset}`;
|
|
364
|
-
break;
|
|
365
|
-
case "WARN":
|
|
366
|
-
case "WARNING":
|
|
367
|
-
case "HIGH":
|
|
368
|
-
sevStr = `${ansi.yellow} ${sym.warning} WARN${ansi.reset}`;
|
|
369
|
-
break;
|
|
370
|
-
default:
|
|
371
|
-
sevStr = `${ansi.gray} ${sym.info} INFO${ansi.reset}`;
|
|
372
|
-
}
|
|
619
|
+
findings.slice(0, maxItems).forEach((f, i) => {
|
|
620
|
+
const severityIcon = getSeverityIcon(f.severity);
|
|
621
|
+
const type = f.type || f.rule || "ISSUE";
|
|
373
622
|
|
|
374
|
-
|
|
375
|
-
|
|
623
|
+
lines.push("");
|
|
624
|
+
lines.push(`${severityIcon} ${type}${f.count ? ` (x${f.count})` : ""}`);
|
|
625
|
+
lines.push(`${sym.lineH.repeat(30)}`);
|
|
626
|
+
lines.push(`Severity: ${getSeverityLabel(f.severity)}`);
|
|
627
|
+
if (f.impact) lines.push(`Impact: ${f.impact}`);
|
|
376
628
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
629
|
+
if (f.instances && f.instances.length > 0) {
|
|
630
|
+
lines.push("");
|
|
631
|
+
lines.push("DETECTED INSTANCES:");
|
|
632
|
+
lines.push("");
|
|
633
|
+
f.instances.slice(0, 3).forEach((inst, j) => {
|
|
634
|
+
const file = inst.file ? truncate(inst.file, 28) : "Unknown";
|
|
635
|
+
lines.push(`${j + 1}. ${file}`);
|
|
636
|
+
if (inst.message) lines.push(` ${ansi.dim}> ${truncate(inst.message, 25)}${ansi.reset}`);
|
|
637
|
+
});
|
|
638
|
+
} else if (f.file) {
|
|
639
|
+
lines.push("");
|
|
640
|
+
lines.push(`File: ${truncate(f.file, 25)}`);
|
|
641
|
+
if (f.message) lines.push(`${ansi.dim}> ${truncate(f.message, 25)}${ansi.reset}`);
|
|
642
|
+
}
|
|
643
|
+
});
|
|
382
644
|
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
645
|
+
if (findings.length > maxItems) {
|
|
646
|
+
lines.push("");
|
|
647
|
+
lines.push(`${ansi.dim}... and ${findings.length - maxItems} more${ansi.reset}`);
|
|
386
648
|
}
|
|
649
|
+
|
|
650
|
+
return lines;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
/**
|
|
654
|
+
* Get icon for severity
|
|
655
|
+
*/
|
|
656
|
+
function getSeverityIcon(severity) {
|
|
657
|
+
const upper = String(severity).toUpperCase();
|
|
658
|
+
if (["CRITICAL", "BLOCK", "HIGH"].includes(upper)) return `${ansi.red}[FAIL]${ansi.reset}`;
|
|
659
|
+
if (["WARNING", "WARN", "MEDIUM"].includes(upper)) return `${ansi.yellow}[WARN]${ansi.reset}`;
|
|
660
|
+
return `${ansi.blue}[INFO]${ansi.reset}`;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/**
|
|
664
|
+
* Get label for severity
|
|
665
|
+
*/
|
|
666
|
+
function getSeverityLabel(severity) {
|
|
667
|
+
const upper = String(severity).toUpperCase();
|
|
668
|
+
if (["CRITICAL", "BLOCK"].includes(upper)) return `${ansi.red}CRITICAL${ansi.reset}`;
|
|
669
|
+
if (upper === "HIGH") return `${ansi.red}HIGH${ansi.reset}`;
|
|
670
|
+
if (["WARNING", "WARN", "MEDIUM"].includes(upper)) return `${ansi.yellow}MEDIUM${ansi.reset}`;
|
|
671
|
+
return `${ansi.blue}LOW${ansi.reset}`;
|
|
387
672
|
}
|
|
388
673
|
|
|
389
674
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
390
|
-
//
|
|
675
|
+
// SECURITY AUDIT SECTION
|
|
391
676
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
392
677
|
|
|
393
678
|
/**
|
|
394
|
-
* Render
|
|
395
|
-
* @param {Array<{label: string, value: string}>} items
|
|
679
|
+
* Render security audit checklist
|
|
396
680
|
*/
|
|
397
|
-
function
|
|
398
|
-
const
|
|
681
|
+
function renderSecurityAudit(checks) {
|
|
682
|
+
const lines = [];
|
|
399
683
|
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
684
|
+
lines.push(`${ansi.bold}SECURITY AUDIT${ansi.reset}`);
|
|
685
|
+
lines.push("");
|
|
686
|
+
|
|
687
|
+
for (const check of checks) {
|
|
688
|
+
const icon = check.pass ? `${ansi.green}${sym.check}${ansi.reset}` : `${ansi.red}${sym.cross}${ansi.reset}`;
|
|
689
|
+
const status = check.pass ? `${ansi.green}PASS${ansi.reset}` : `${ansi.red}FAIL${ansi.reset}`;
|
|
690
|
+
const dots = ".".repeat(Math.max(0, 20 - check.name.length));
|
|
691
|
+
lines.push(` ${icon} ${check.name}${ansi.dim}${dots}${ansi.reset}${status}`);
|
|
403
692
|
}
|
|
693
|
+
|
|
694
|
+
return lines;
|
|
404
695
|
}
|
|
405
696
|
|
|
406
697
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
407
|
-
//
|
|
698
|
+
// ACTION REQUIRED SECTION
|
|
408
699
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
409
700
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
701
|
+
/**
|
|
702
|
+
* Render action required section
|
|
703
|
+
*/
|
|
704
|
+
function renderActionRequired(actions, opts = {}) {
|
|
705
|
+
const { blocking = false, title = "ACTION REQUIRED" } = opts;
|
|
706
|
+
const lines = [];
|
|
707
|
+
|
|
708
|
+
lines.push(`${ansi.cyan}${sym.boxTeeR}${sym.boxH.repeat(WIDTH - 2)}${sym.boxTeeL}${ansi.reset}`);
|
|
709
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${ansi.bold}${title}${ansi.reset}${" ".repeat(WIDTH - 4 - title.length)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
710
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${sym.lineH.repeat(WIDTH - 4)} ${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
711
|
+
|
|
712
|
+
if (blocking) {
|
|
713
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${ansi.red}[!] BLOCKING ISSUES DETECTED. DEPLOYMENT HALTED.${ansi.reset}${" ".repeat(WIDTH - 54)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
714
|
+
}
|
|
413
715
|
|
|
414
|
-
|
|
415
|
-
if (percent < 50) color = ansi.red;
|
|
416
|
-
else if (percent < 80) color = ansi.yellow;
|
|
716
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset}${" ".repeat(WIDTH - 2)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
417
717
|
|
|
418
|
-
|
|
718
|
+
for (const action of actions) {
|
|
719
|
+
const cmd = `${ansi.cyan}> ${action.command}${ansi.reset}`;
|
|
720
|
+
const label = action.label ? `${ansi.dim}[${action.label}]${ansi.reset}` : "";
|
|
721
|
+
const desc = action.description || "";
|
|
722
|
+
|
|
723
|
+
const line = ` ${cmd}${" ".repeat(Math.max(2, 26 - action.command.length))}${label} ${desc}`;
|
|
724
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset}${padRight(line, WIDTH - 2)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
return lines.join("\n");
|
|
419
728
|
}
|
|
420
729
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
730
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
731
|
+
// FOOTER
|
|
732
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* Render standard footer
|
|
736
|
+
*/
|
|
737
|
+
function renderFooter() {
|
|
738
|
+
return `${ansi.cyan}${sym.boxBL}${sym.boxH.repeat(WIDTH - 2)}${sym.boxBR}${ansi.reset}`;
|
|
424
739
|
}
|
|
425
740
|
|
|
426
741
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
427
|
-
//
|
|
742
|
+
// VERDICT BOX
|
|
428
743
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
429
744
|
|
|
430
745
|
/**
|
|
431
|
-
* Render
|
|
432
|
-
* @param {object} opts
|
|
433
|
-
* @param {Array<{cmd: string, desc: string}>} [opts.nextSteps]
|
|
434
|
-
* @param {string} [opts.docsUrl]
|
|
435
|
-
* @param {boolean} [opts.showUpsell]
|
|
746
|
+
* Render a verdict box
|
|
436
747
|
*/
|
|
437
|
-
function
|
|
438
|
-
const {
|
|
439
|
-
|
|
748
|
+
function renderVerdict(verdict, score, stats = {}) {
|
|
749
|
+
const { blockers = 0, warnings = 0, passed = 0, duration = 0 } = stats;
|
|
750
|
+
|
|
751
|
+
const verdictColors = {
|
|
752
|
+
SHIP: ansi.green,
|
|
753
|
+
LAUNCH: ansi.green,
|
|
754
|
+
PASS: ansi.green,
|
|
755
|
+
WARN: ansi.yellow,
|
|
756
|
+
WARNING: ansi.yellow,
|
|
757
|
+
BLOCK: ansi.red,
|
|
758
|
+
FAIL: ansi.red,
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
const verdictIcons = {
|
|
762
|
+
SHIP: sym.rocket,
|
|
763
|
+
LAUNCH: sym.rocket,
|
|
764
|
+
PASS: sym.check,
|
|
765
|
+
WARN: sym.warning,
|
|
766
|
+
WARNING: sym.warning,
|
|
767
|
+
BLOCK: sym.cross,
|
|
768
|
+
FAIL: sym.cross,
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
const color = verdictColors[verdict.toUpperCase()] || ansi.gray;
|
|
772
|
+
const icon = verdictIcons[verdict.toUpperCase()] || sym.bullet;
|
|
440
773
|
|
|
441
|
-
|
|
442
|
-
renderDivider();
|
|
774
|
+
const lines = [];
|
|
443
775
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
console.log(` ${ansi.cyan}${step.cmd}${ansi.reset} ${ansi.dim}${step.desc}${ansi.reset}`);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
776
|
+
lines.push(`${ansi.cyan}${sym.boxTeeR}${sym.boxH.repeat(WIDTH - 2)}${sym.boxTeeL}${ansi.reset}`);
|
|
777
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset}${" ".repeat(WIDTH - 2)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
778
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${icon} ${ansi.bold}VERDICT: ${color}${verdict}${ansi.reset}${" ".repeat(WIDTH - 16 - verdict.length)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
779
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset}${" ".repeat(WIDTH - 2)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
451
780
|
|
|
452
|
-
//
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
console.log(` ${ansi.dim}${sym.star}${ansi.reset} ${ansi.cyan}STARTER${ansi.reset}${ansi.dim}: dashboard sync + auto-fix + team features${ansi.reset}`);
|
|
456
|
-
console.log(` ${ansi.dim} Upgrade ${sym.arrow} https://vibecheckai.dev${ansi.reset}`);
|
|
457
|
-
}
|
|
781
|
+
// Score bar
|
|
782
|
+
const bar = renderProgressBar(score, 30, { color });
|
|
783
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} Score: ${bar} ${score}/100${" ".repeat(WIDTH - 54)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
458
784
|
|
|
459
|
-
//
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
785
|
+
// Stats
|
|
786
|
+
const statsLine = `Blockers: ${blockers} Warnings: ${warnings} Passed: ${passed}`;
|
|
787
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${statsLine}${" ".repeat(WIDTH - 4 - statsLine.length)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
788
|
+
|
|
789
|
+
if (duration) {
|
|
790
|
+
const durationLine = `Duration: ${formatDuration(duration)}`;
|
|
791
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset} ${ansi.dim}${durationLine}${ansi.reset}${" ".repeat(WIDTH - 4 - durationLine.length)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
463
792
|
}
|
|
464
793
|
|
|
465
|
-
|
|
794
|
+
lines.push(`${ansi.cyan}${sym.boxV}${ansi.reset}${" ".repeat(WIDTH - 2)}${ansi.cyan}${sym.boxV}${ansi.reset}`);
|
|
795
|
+
|
|
796
|
+
return lines.join("\n");
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
800
|
+
// SECTION HEADER
|
|
801
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
802
|
+
|
|
803
|
+
/**
|
|
804
|
+
* Render a section header within the box
|
|
805
|
+
*/
|
|
806
|
+
function renderSectionHeader(title, icon = sym.bullet) {
|
|
807
|
+
console.log(` ${ansi.cyan}${icon}${ansi.reset} ${ansi.bold}${title}${ansi.reset}`);
|
|
808
|
+
console.log(` ${ansi.dim}${sym.lineH.repeat(60)}${ansi.reset}`);
|
|
466
809
|
}
|
|
467
810
|
|
|
468
811
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
469
|
-
//
|
|
812
|
+
// SUCCESS/ERROR/WARNING MESSAGES
|
|
813
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
814
|
+
|
|
815
|
+
function renderSuccess(message) {
|
|
816
|
+
console.log(` ${ansi.green}${sym.check}${ansi.reset} ${message}`);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
function renderError(message) {
|
|
820
|
+
console.log(` ${ansi.red}${sym.cross}${ansi.reset} ${message}`);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
function renderWarning(message) {
|
|
824
|
+
console.log(` ${ansi.yellow}${sym.warning}${ansi.reset} ${message}`);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
function renderInfo(message) {
|
|
828
|
+
console.log(` ${ansi.cyan}${sym.info}${ansi.reset} ${message}`);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
832
|
+
// SPINNER CLASS
|
|
470
833
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
471
834
|
|
|
472
835
|
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
473
836
|
|
|
474
837
|
class Spinner {
|
|
475
|
-
constructor(text = "") {
|
|
838
|
+
constructor(text = "", color = ansi.cyan) {
|
|
476
839
|
this.text = text;
|
|
840
|
+
this.color = color;
|
|
477
841
|
this.timer = null;
|
|
478
|
-
this.
|
|
842
|
+
this.frameIndex = 0;
|
|
479
843
|
}
|
|
480
844
|
|
|
481
845
|
start(text) {
|
|
482
846
|
if (text) this.text = text;
|
|
483
|
-
|
|
484
|
-
console.log(` ${ansi.cyan}${sym.gear}${ansi.reset} ${this.text}...`);
|
|
485
|
-
return this;
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
process.stdout.write("\x1b[?25l"); // Hide cursor
|
|
847
|
+
process.stdout.write(ansi.hideCursor);
|
|
489
848
|
this.timer = setInterval(() => {
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
this.frame
|
|
849
|
+
const frame = SPINNER_FRAMES[this.frameIndex];
|
|
850
|
+
this.frameIndex = (this.frameIndex + 1) % SPINNER_FRAMES.length;
|
|
851
|
+
process.stdout.write(`\r ${this.color}${frame}${ansi.reset} ${this.text}`);
|
|
493
852
|
}, 80);
|
|
494
853
|
return this;
|
|
495
854
|
}
|
|
496
855
|
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
if (
|
|
504
|
-
|
|
505
|
-
process.stdout.write("\x1b[?25h"); // Show cursor
|
|
506
|
-
}
|
|
507
|
-
|
|
856
|
+
update(text) {
|
|
857
|
+
this.text = text;
|
|
858
|
+
return this;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
stop(icon = sym.check, color = ansi.green, finalText) {
|
|
862
|
+
if (this.timer) clearInterval(this.timer);
|
|
863
|
+
process.stdout.write(`\r${ansi.clearLine}`);
|
|
508
864
|
if (finalText !== null) {
|
|
509
|
-
const
|
|
510
|
-
|
|
511
|
-
console.log(` ${color}${icon}${ansi.reset} ${finalText || this.text}`);
|
|
865
|
+
const msg = finalText || this.text;
|
|
866
|
+
console.log(` ${color}${icon}${ansi.reset} ${msg}`);
|
|
512
867
|
}
|
|
868
|
+
process.stdout.write(ansi.showCursor);
|
|
513
869
|
return this;
|
|
514
870
|
}
|
|
515
871
|
|
|
516
872
|
succeed(text) { return this.stop(sym.check, ansi.green, text); }
|
|
517
873
|
fail(text) { return this.stop(sym.cross, ansi.red, text); }
|
|
518
874
|
warn(text) { return this.stop(sym.warning, ansi.yellow, text); }
|
|
519
|
-
info(text) { return this.stop(sym.info, ansi.cyan, text); }
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
523
|
-
// COMMAND TEMPLATES
|
|
524
|
-
// ═══════════════════════════════════════════════════════════════════════════════
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* Standard command wrapper for consistent output
|
|
528
|
-
* @param {object} opts
|
|
529
|
-
* @param {string} opts.command - Command name
|
|
530
|
-
* @param {string} opts.title - Title for header
|
|
531
|
-
* @param {string} [opts.tier] - Required tier
|
|
532
|
-
* @param {boolean} [opts.quiet] - Suppress non-essential output
|
|
533
|
-
* @param {boolean} [opts.json] - JSON output mode
|
|
534
|
-
* @param {Function} opts.run - The command's main logic
|
|
535
|
-
*/
|
|
536
|
-
async function runCommand(opts) {
|
|
537
|
-
const { command, title, tier = "free", quiet = false, json = false, run } = opts;
|
|
538
|
-
|
|
539
|
-
if (json) {
|
|
540
|
-
// JSON mode - run silently, output only JSON
|
|
541
|
-
return await run();
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
if (!quiet) {
|
|
545
|
-
renderMinimalHeader(command, tier);
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
const result = await run();
|
|
549
|
-
|
|
550
|
-
return result;
|
|
551
875
|
}
|
|
552
876
|
|
|
553
877
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
@@ -557,48 +881,51 @@ async function runCommand(opts) {
|
|
|
557
881
|
module.exports = {
|
|
558
882
|
// Constants
|
|
559
883
|
WIDTH,
|
|
884
|
+
INNER_WIDTH,
|
|
885
|
+
|
|
886
|
+
// ANSI & Symbols
|
|
560
887
|
ansi,
|
|
561
888
|
sym,
|
|
562
|
-
|
|
889
|
+
|
|
890
|
+
// Banners
|
|
891
|
+
VIBECHECK_BANNER,
|
|
892
|
+
COMMAND_BANNERS,
|
|
563
893
|
|
|
564
894
|
// Utilities
|
|
565
895
|
stripAnsi,
|
|
566
|
-
|
|
896
|
+
visibleLength,
|
|
567
897
|
padRight,
|
|
898
|
+
padLeft,
|
|
899
|
+
padCenter,
|
|
568
900
|
truncate,
|
|
569
901
|
formatDuration,
|
|
570
|
-
|
|
571
|
-
|
|
902
|
+
formatNumber,
|
|
903
|
+
|
|
904
|
+
// Progress & Status
|
|
905
|
+
renderProgressBar,
|
|
906
|
+
renderStatus,
|
|
572
907
|
|
|
573
908
|
// Headers
|
|
574
|
-
|
|
909
|
+
renderFullHeader,
|
|
575
910
|
renderMinimalHeader,
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
911
|
+
generateSessionId,
|
|
912
|
+
|
|
913
|
+
// Layouts
|
|
914
|
+
renderSplitColumns,
|
|
915
|
+
renderVitals,
|
|
916
|
+
renderDiagnostics,
|
|
917
|
+
renderSecurityAudit,
|
|
918
|
+
renderActionRequired,
|
|
919
|
+
renderVerdict,
|
|
920
|
+
renderFooter,
|
|
579
921
|
renderSectionHeader,
|
|
580
922
|
|
|
581
|
-
//
|
|
923
|
+
// Messages
|
|
582
924
|
renderSuccess,
|
|
583
925
|
renderError,
|
|
584
926
|
renderWarning,
|
|
585
927
|
renderInfo,
|
|
586
|
-
renderBullet,
|
|
587
|
-
renderStep,
|
|
588
|
-
|
|
589
|
-
// Results
|
|
590
|
-
renderVerdict,
|
|
591
|
-
renderFindingsTable,
|
|
592
|
-
renderKeyValue,
|
|
593
|
-
renderProgressBar,
|
|
594
|
-
renderScore,
|
|
595
928
|
|
|
596
|
-
//
|
|
597
|
-
renderFooter,
|
|
598
|
-
|
|
599
|
-
// Components
|
|
929
|
+
// Spinner
|
|
600
930
|
Spinner,
|
|
601
|
-
|
|
602
|
-
// Templates
|
|
603
|
-
runCommand,
|
|
604
931
|
};
|