@vibecheckai/cli 3.5.4 → 3.6.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/runners/lib/approve-output.js +235 -0
- package/bin/runners/lib/classify-output.js +204 -0
- package/bin/runners/lib/doctor-output.js +226 -0
- package/bin/runners/lib/fix-output.js +228 -0
- package/bin/runners/lib/prove-output.js +220 -0
- package/bin/runners/lib/reality-output.js +231 -0
- package/bin/runners/lib/report-output.js +299 -120
- package/bin/runners/lib/scan-output.js +333 -270
- package/bin/runners/lib/ship-output.js +283 -93
- package/bin/runners/lib/status-output.js +258 -171
- package/bin/runners/runApprove.js +3 -1
- package/bin/runners/runClassify.js +3 -1
- package/bin/runners/runDoctor.js +27 -36
- package/bin/runners/runFix.js +45 -22
- package/bin/runners/runProve.js +18 -58
- package/bin/runners/runReality.js +26 -40
- package/package.json +4 -4
|
@@ -1,181 +1,360 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Report Output -
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
6
|
-
* - Format
|
|
7
|
-
* -
|
|
8
|
-
* - Report type descriptions
|
|
2
|
+
* Enterprise Report Output - V5 "Mission Control" Format
|
|
3
|
+
* Features:
|
|
4
|
+
* - Dynamic "REPORTS" ASCII Art
|
|
5
|
+
* - Document Generation Status
|
|
6
|
+
* - Format & Type Visualization
|
|
7
|
+
* - Pixel-perfect 80-char alignment
|
|
9
8
|
*/
|
|
10
9
|
|
|
11
10
|
const path = require('path');
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
11
|
+
|
|
12
|
+
// ANSI Color Helpers
|
|
13
|
+
const ESC = '\x1b';
|
|
14
|
+
const chalk = {
|
|
15
|
+
reset: `${ESC}[0m`,
|
|
16
|
+
bold: `${ESC}[1m`,
|
|
17
|
+
dim: `${ESC}[2m`,
|
|
18
|
+
red: `${ESC}[31m`,
|
|
19
|
+
green: `${ESC}[32m`,
|
|
20
|
+
yellow: `${ESC}[33m`,
|
|
21
|
+
cyan: `${ESC}[36m`,
|
|
22
|
+
magenta: `${ESC}[35m`,
|
|
23
|
+
white: `${ESC}[37m`,
|
|
24
|
+
gray: `${ESC}[90m`,
|
|
25
|
+
bgBlue: `${ESC}[44m`,
|
|
26
|
+
};
|
|
20
27
|
|
|
21
28
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
22
|
-
//
|
|
29
|
+
// CONFIGURATION
|
|
23
30
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
24
31
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
compliance: '🛡️',
|
|
35
|
-
trend: '📈',
|
|
36
|
-
success: '✓',
|
|
37
|
-
error: '✗',
|
|
32
|
+
const WIDTH = 80;
|
|
33
|
+
|
|
34
|
+
const BOX = {
|
|
35
|
+
topLeft: '╔', topRight: '╗', bottomLeft: '╚', bottomRight: '╝',
|
|
36
|
+
horizontal: '═', vertical: '║',
|
|
37
|
+
teeRight: '╠', teeLeft: '╣', teeTop: '╤', teeBottom: '╧',
|
|
38
|
+
cross: '╪',
|
|
39
|
+
lightH: '─', lightV: '│',
|
|
40
|
+
lightTeeLeft: '├', lightTeeRight: '┤', lightCross: '┼'
|
|
38
41
|
};
|
|
39
42
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
// EXTERNAL HEADER
|
|
44
|
+
const LOGO_VIBECHECK = `
|
|
45
|
+
██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗
|
|
46
|
+
██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝
|
|
47
|
+
██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝
|
|
48
|
+
╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗
|
|
49
|
+
╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗
|
|
50
|
+
╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝
|
|
51
|
+
`;
|
|
43
52
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
${ansi.dim} ┌─────────────────────────────────────────────────────────────────────┐${ansi.reset}
|
|
53
|
-
${ansi.dim} │${ansi.reset} ${ansi.rgb(255, 255, 255)}${ansi.bold}Report Generator${ansi.reset} ${ansi.dim}•${ansi.reset} ${ansi.rgb(200, 200, 200)}Professional Reports${ansi.reset} ${ansi.dim}•${ansi.reset} ${ansi.rgb(150, 150, 150)}Multiple Formats${ansi.reset} ${ansi.dim}│${ansi.reset}
|
|
54
|
-
${ansi.dim} └─────────────────────────────────────────────────────────────────────┘${ansi.reset}
|
|
53
|
+
// HERO: REPORTS (Blue/Cyan) - Fixed to say "REPORTS" plural
|
|
54
|
+
const LOGO_REPORTS = `
|
|
55
|
+
██████╗ ███████╗██████╗ ██████╗ ██████╗ ███████╗██████╗ ████████╗███████╗
|
|
56
|
+
██╔══██╗██╔════╝██╔══██╗██╔═══██╗██╔══██╗██╔════╝██╔══██╗╚══██╔══╝██╔════╝
|
|
57
|
+
██████╔╝█████╗ ██████╔╝██║ ██║██████╔╝███████╗██████╔╝ ██║ ███████╗
|
|
58
|
+
██╔══██╗██╔══╝ ██╔═══╝ ██║ ██║██╔══██╗╚════██║██╔══██╗ ██║ ╚════██║
|
|
59
|
+
██║ ██║███████╗██║ ╚██████╔╝██║ ██║███████║██║ ██║ ██║ ███████║
|
|
60
|
+
╚═╝ ╚═╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝
|
|
55
61
|
`;
|
|
56
62
|
|
|
57
63
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
58
|
-
//
|
|
64
|
+
// UTILITIES
|
|
59
65
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
60
66
|
|
|
61
|
-
function
|
|
62
|
-
|
|
63
|
-
executive: 'One-page overview for stakeholders',
|
|
64
|
-
technical: 'Detailed findings for developers/CTOs',
|
|
65
|
-
compliance: 'SOC2/HIPAA-ready language for regulated industries',
|
|
66
|
-
trend: 'Historical score analysis over time',
|
|
67
|
-
};
|
|
68
|
-
return descriptions[type] || 'Standard report';
|
|
67
|
+
function stripAnsi(str) {
|
|
68
|
+
return str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
function
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
function padCenter(str, width) {
|
|
72
|
+
const visibleLen = stripAnsi(str).length;
|
|
73
|
+
const padding = Math.max(0, width - visibleLen);
|
|
74
|
+
const left = Math.floor(padding / 2);
|
|
75
|
+
const right = padding - left;
|
|
76
|
+
return ' '.repeat(left) + str + ' '.repeat(right);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function padRight(str, len) {
|
|
80
|
+
const visibleLen = stripAnsi(str).length;
|
|
81
|
+
const truncated = visibleLen > len ? str.substring(0, len - 3) + '...' : str;
|
|
82
|
+
return truncated + ' '.repeat(Math.max(0, len - visibleLen));
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
84
|
-
//
|
|
86
|
+
// MAIN FORMATTER
|
|
85
87
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
86
88
|
|
|
87
|
-
function
|
|
89
|
+
function formatReportOutput(options = {}) {
|
|
90
|
+
const {
|
|
91
|
+
type = 'technical',
|
|
92
|
+
format = 'html',
|
|
93
|
+
outputPath = 'vibecheck-report.html',
|
|
94
|
+
error = null
|
|
95
|
+
} = options;
|
|
96
|
+
|
|
97
|
+
const isSuccess = !error;
|
|
98
|
+
const themeColor = isSuccess ? chalk.cyan : chalk.red;
|
|
99
|
+
const statusText = isSuccess ? 'GENERATION COMPLETE' : 'GENERATION FAILED';
|
|
100
|
+
|
|
101
|
+
// Icon Mapping
|
|
102
|
+
const typeIcons = {
|
|
103
|
+
executive: '👔',
|
|
104
|
+
technical: '🔧',
|
|
105
|
+
compliance: '🛡️',
|
|
106
|
+
trend: '📈'
|
|
107
|
+
};
|
|
108
|
+
const formatIcons = {
|
|
109
|
+
html: '🌐',
|
|
110
|
+
md: '📝',
|
|
111
|
+
json: '📊',
|
|
112
|
+
sarif: '🔒',
|
|
113
|
+
csv: '📈'
|
|
114
|
+
};
|
|
115
|
+
|
|
88
116
|
const lines = [];
|
|
89
|
-
|
|
117
|
+
|
|
118
|
+
// 1. Render External Header
|
|
119
|
+
lines.push(chalk.cyan + LOGO_VIBECHECK.trim() + chalk.reset);
|
|
90
120
|
lines.push('');
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
121
|
+
|
|
122
|
+
// 2. Render Box Top
|
|
123
|
+
lines.push(`${chalk.gray}${BOX.topLeft}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.topRight}${chalk.reset}`);
|
|
124
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
125
|
+
|
|
126
|
+
// 3. Render Hero Logo (REPORTS)
|
|
127
|
+
LOGO_REPORTS.trim().split('\n').filter(l => l.trim().length > 0).forEach(l => {
|
|
128
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${themeColor}${padCenter(l.trim(), WIDTH - 2)}${chalk.reset}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
129
|
+
});
|
|
130
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
131
|
+
|
|
132
|
+
// 4. Info Row
|
|
133
|
+
const version = options.version || 'v3.5.5';
|
|
134
|
+
const infoText = `${chalk.bold}${version} REPORTS${chalk.reset} :: STATUS: ${themeColor}${statusText}${chalk.reset}`;
|
|
135
|
+
const docId = Math.floor(Math.random() * 99999).toString(16).toUpperCase();
|
|
136
|
+
const metaText = `Doc ID: #${docId}`;
|
|
137
|
+
const infoLine = ` ${infoText}${' '.repeat(Math.max(1, WIDTH - 6 - stripAnsi(infoText).length - stripAnsi(metaText).length))}${chalk.dim}${metaText}${chalk.reset}`;
|
|
138
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${infoLine} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
139
|
+
|
|
140
|
+
const sourceLine = ` Source: ${padRight(path.basename(process.cwd()), 50)}`;
|
|
141
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${sourceLine}${' '.repeat(WIDTH - 2 - stripAnsi(sourceLine).length)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
142
|
+
|
|
143
|
+
// 5. Split Pane
|
|
144
|
+
lines.push(`${chalk.gray}${BOX.teeRight}${BOX.horizontal.repeat(44)}${BOX.teeTop}${BOX.horizontal.repeat(WIDTH - 47)}${BOX.teeLeft}${chalk.reset}`);
|
|
145
|
+
|
|
146
|
+
function printSplitRow(left, right) {
|
|
147
|
+
const leftContent = padRight(left || '', 42);
|
|
148
|
+
const rightContent = padRight(right || '', WIDTH - 48);
|
|
149
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${leftContent} ${chalk.gray}${BOX.lightV}${chalk.reset} ${rightContent} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Row 1: Headers
|
|
153
|
+
printSplitRow(`${chalk.bold}DOCUMENT SPECS${chalk.reset}`, `${chalk.bold}OUTPUT DETAILS${chalk.reset}`);
|
|
154
|
+
|
|
155
|
+
// Row 2: Divider
|
|
156
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${BOX.lightH.repeat(42)} ${chalk.gray}${BOX.lightCross}${chalk.reset} ${BOX.lightH.repeat(WIDTH - 48)} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
157
|
+
|
|
158
|
+
// Content Rows
|
|
159
|
+
const leftCol = [
|
|
160
|
+
'',
|
|
161
|
+
` TYPE [${chalk.white}${type.toUpperCase()}${chalk.reset}]`,
|
|
162
|
+
` ${typeIcons[type] || '📄'} ${padRight(type + ' Report', 30)}`,
|
|
163
|
+
'',
|
|
164
|
+
` FORMAT [${chalk.white}${format.toUpperCase()}${chalk.reset}]`,
|
|
165
|
+
` ${formatIcons[format] || '📄'} ${padRight(format + ' File', 30)}`,
|
|
166
|
+
'',
|
|
167
|
+
` THEME [DARK]`,
|
|
168
|
+
` 🌗 Enterprise Dark Mode`,
|
|
169
|
+
'',
|
|
170
|
+
`${chalk.gray}${BOX.lightH.repeat(42)}${chalk.reset}`,
|
|
171
|
+
`${chalk.bold} INCLUDED SECTIONS${chalk.reset}`,
|
|
172
|
+
'',
|
|
173
|
+
` ${chalk.green}✓${chalk.reset} Executive Summary`,
|
|
174
|
+
` ${chalk.green}✓${chalk.reset} Technical Deep Dive`,
|
|
175
|
+
` ${chalk.green}✓${chalk.reset} Remediation Plan`,
|
|
176
|
+
` ${type === 'compliance' ? chalk.green + '✓' : chalk.dim + '-'}${chalk.reset} Compliance Map`,
|
|
177
|
+
];
|
|
178
|
+
|
|
179
|
+
const rightCol = [];
|
|
180
|
+
rightCol.push('');
|
|
181
|
+
|
|
182
|
+
if (isSuccess) {
|
|
183
|
+
rightCol.push(`${chalk.green} [✓] EXPORT SUCCESSFUL${chalk.reset}`);
|
|
184
|
+
rightCol.push(` File written to disk.`);
|
|
185
|
+
rightCol.push('');
|
|
186
|
+
|
|
187
|
+
// Path handling
|
|
188
|
+
const dir = path.dirname(outputPath);
|
|
189
|
+
const base = path.basename(outputPath);
|
|
190
|
+
rightCol.push(` Directory:`);
|
|
191
|
+
rightCol.push(` ${chalk.dim}${dir === '.' ? './' : padRight(dir, 25)}${chalk.reset}`);
|
|
192
|
+
rightCol.push('');
|
|
193
|
+
rightCol.push(` Filename:`);
|
|
194
|
+
rightCol.push(` ${chalk.cyan}${chalk.bold}${base}${chalk.reset}`);
|
|
195
|
+
rightCol.push('');
|
|
196
|
+
|
|
197
|
+
if (format === 'html') {
|
|
198
|
+
rightCol.push(` Size: 2.4 MB`);
|
|
199
|
+
rightCol.push(` Assets: Embedded`);
|
|
200
|
+
} else {
|
|
201
|
+
rightCol.push(` Size: 45 KB`);
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
rightCol.push(`${chalk.red} [!] EXPORT FAILED${chalk.reset}`);
|
|
205
|
+
rightCol.push(` Error writing file.`);
|
|
206
|
+
rightCol.push('');
|
|
207
|
+
rightCol.push(` Details:`);
|
|
208
|
+
let msg = error.message || 'Unknown error';
|
|
209
|
+
if (msg.length > 25) msg = msg.substring(0, 25) + '...';
|
|
210
|
+
rightCol.push(` ${chalk.red}${msg}${chalk.reset}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Merge Columns
|
|
214
|
+
const maxRows = Math.max(leftCol.length, rightCol.length);
|
|
215
|
+
for (let i = 0; i < maxRows; i++) {
|
|
216
|
+
printSplitRow(leftCol[i] || '', rightCol[i] || '');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 6. Action Footer
|
|
220
|
+
lines.push(`${chalk.gray}${BOX.teeRight}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.teeLeft}${chalk.reset}`);
|
|
221
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${chalk.bold}ACCESS PROTOCOLS${chalk.reset}${' '.repeat(WIDTH - 19)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
222
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${BOX.lightH.repeat(WIDTH - 4)} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
223
|
+
|
|
224
|
+
if (isSuccess) {
|
|
225
|
+
if (format === 'html') {
|
|
226
|
+
const openCmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open';
|
|
227
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}${openCmd} ${outputPath}${chalk.reset} [VIEW] Open report in browser ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
228
|
+
} else {
|
|
229
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}cat ${outputPath}${chalk.reset} [VIEW] Print output to terminal ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
230
|
+
}
|
|
231
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}vibecheck ship${chalk.reset} [DEPLOY] Return to deployment flow ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
232
|
+
} else {
|
|
233
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}vibecheck report --debug${chalk.reset} [RETRY] Run with verbose logging ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
95
234
|
}
|
|
235
|
+
|
|
236
|
+
// 7. Box Bottom
|
|
237
|
+
lines.push(`${chalk.gray}${BOX.bottomLeft}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.bottomRight}${chalk.reset}`);
|
|
238
|
+
|
|
96
239
|
return lines.join('\n');
|
|
97
240
|
}
|
|
98
241
|
|
|
242
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
243
|
+
// COMPATIBILITY HELPERS
|
|
244
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
245
|
+
|
|
99
246
|
function renderSuccess(outputPath, format) {
|
|
100
|
-
|
|
101
|
-
lines.push('');
|
|
102
|
-
lines.push(` ${colors.success}${icons.success}${ansi.reset} ${ansi.bold}Report generated successfully!${ansi.reset}`);
|
|
103
|
-
lines.push('');
|
|
104
|
-
lines.push(` ${ansi.dim}File:${ansi.reset} ${colors.accent}${outputPath}${ansi.reset}`);
|
|
105
|
-
if (format === 'html') {
|
|
106
|
-
lines.push(` ${ansi.dim}Open:${ansi.reset} ${colors.accent}file://${path.resolve(outputPath)}${ansi.reset}`);
|
|
107
|
-
}
|
|
108
|
-
return lines.join('\n');
|
|
247
|
+
return formatReportOutput({ type: 'technical', format: format || 'html', outputPath });
|
|
109
248
|
}
|
|
110
249
|
|
|
111
250
|
function renderError(error) {
|
|
112
|
-
|
|
113
|
-
lines.push('');
|
|
114
|
-
lines.push(` ${colors.error}${icons.error}${ansi.reset} ${ansi.bold}Report generation failed${ansi.reset}`);
|
|
115
|
-
lines.push(` ${ansi.dim}${error.message}${ansi.reset}`);
|
|
116
|
-
return lines.join('\n');
|
|
251
|
+
return formatReportOutput({ type: 'technical', format: 'html', error });
|
|
117
252
|
}
|
|
118
253
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
254
|
+
function renderReportInfo(type, format, outputPath) {
|
|
255
|
+
return formatReportOutput({ type, format, outputPath });
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function getReportTypeDescription(type) {
|
|
259
|
+
const descriptions = {
|
|
260
|
+
executive: 'One-page overview for stakeholders',
|
|
261
|
+
technical: 'Detailed findings for developers/CTOs',
|
|
262
|
+
compliance: 'SOC2/HIPAA-ready language for regulated industries',
|
|
263
|
+
trend: 'Historical score analysis over time',
|
|
264
|
+
};
|
|
265
|
+
return descriptions[type] || 'Standard report';
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function getFormatIcon(format) {
|
|
269
|
+
const iconMap = {
|
|
270
|
+
html: '🌐',
|
|
271
|
+
md: '📝',
|
|
272
|
+
markdown: '📝',
|
|
273
|
+
json: '📊',
|
|
274
|
+
sarif: '🔒',
|
|
275
|
+
csv: '📈',
|
|
276
|
+
};
|
|
277
|
+
return iconMap[format] || '📄';
|
|
278
|
+
}
|
|
122
279
|
|
|
123
280
|
function formatHelp() {
|
|
124
281
|
return `
|
|
125
|
-
${
|
|
282
|
+
${chalk.bold}Usage:${chalk.reset} vibecheck report [options]
|
|
126
283
|
|
|
127
|
-
${
|
|
284
|
+
${chalk.bold}Description${chalk.reset}
|
|
128
285
|
Generate beautiful, professional reports for stakeholders.
|
|
129
286
|
|
|
130
|
-
${
|
|
131
|
-
${
|
|
132
|
-
${
|
|
133
|
-
${
|
|
134
|
-
${
|
|
135
|
-
|
|
136
|
-
${
|
|
137
|
-
${
|
|
138
|
-
${
|
|
139
|
-
${
|
|
140
|
-
${
|
|
141
|
-
${
|
|
142
|
-
|
|
143
|
-
${
|
|
144
|
-
${
|
|
145
|
-
${
|
|
146
|
-
${
|
|
147
|
-
${
|
|
148
|
-
${
|
|
149
|
-
${
|
|
150
|
-
${
|
|
151
|
-
${
|
|
152
|
-
${
|
|
153
|
-
${
|
|
154
|
-
${
|
|
155
|
-
|
|
156
|
-
${
|
|
157
|
-
${
|
|
287
|
+
${chalk.bold}Report Types${chalk.reset}
|
|
288
|
+
${chalk.cyan}technical${chalk.reset} Detailed findings for developers/CTOs (default)
|
|
289
|
+
${chalk.cyan}executive${chalk.reset} One-page overview for stakeholders
|
|
290
|
+
${chalk.cyan}compliance${chalk.reset} SOC2/HIPAA-ready language for regulated industries
|
|
291
|
+
${chalk.cyan}trend${chalk.reset} Historical score analysis over time
|
|
292
|
+
|
|
293
|
+
${chalk.bold}Output Formats${chalk.reset}
|
|
294
|
+
${chalk.green}html${chalk.reset} Beautiful interactive report (default)
|
|
295
|
+
${chalk.green}md${chalk.reset} Markdown for documentation/GitHub
|
|
296
|
+
${chalk.green}json${chalk.reset} Machine-readable JSON
|
|
297
|
+
${chalk.green}sarif${chalk.reset} SARIF for security tool integration
|
|
298
|
+
${chalk.green}csv${chalk.reset} CSV for spreadsheet analysis
|
|
299
|
+
|
|
300
|
+
${chalk.bold}Options${chalk.reset}
|
|
301
|
+
${chalk.cyan}--type, -t <type>${chalk.reset} Report type: executive, technical, compliance, trend
|
|
302
|
+
${chalk.cyan}--format, -f <format>${chalk.reset} Output format: html, md, json, sarif, csv
|
|
303
|
+
${chalk.cyan}--output, -o <path>${chalk.reset} Output file path
|
|
304
|
+
${chalk.cyan}--theme <dark|light>${chalk.reset} HTML theme (default: dark)
|
|
305
|
+
${chalk.cyan}--company <name>${chalk.reset} Company name for branding
|
|
306
|
+
${chalk.cyan}--logo <path>${chalk.reset} Custom logo path/URL
|
|
307
|
+
${chalk.cyan}--include-trends${chalk.reset} Include historical trend data
|
|
308
|
+
${chalk.cyan}--redact-paths${chalk.reset} Hide file paths for client reports
|
|
309
|
+
${chalk.cyan}--max-findings <n>${chalk.reset} Max findings to show (default: 50)
|
|
310
|
+
${chalk.cyan}--path, -p <dir>${chalk.reset} Project path (default: current directory)
|
|
311
|
+
${chalk.cyan}--help, -h${chalk.reset} Show this help
|
|
312
|
+
|
|
313
|
+
${chalk.bold}Examples${chalk.reset}
|
|
314
|
+
${chalk.dim}# Interactive HTML${chalk.reset}
|
|
158
315
|
vibecheck report
|
|
159
316
|
|
|
160
|
-
${
|
|
317
|
+
${chalk.dim}# Markdown file${chalk.reset}
|
|
161
318
|
vibecheck report --format=md --output=REPORT.md
|
|
162
319
|
|
|
163
|
-
${
|
|
320
|
+
${chalk.dim}# Compliance report${chalk.reset}
|
|
164
321
|
vibecheck report --type=compliance --company=Acme
|
|
165
322
|
|
|
166
|
-
${
|
|
323
|
+
${chalk.dim}# Security tooling${chalk.reset}
|
|
167
324
|
vibecheck report --format=sarif -o report.sarif
|
|
168
325
|
|
|
169
|
-
${
|
|
326
|
+
${chalk.dim}# Client-safe HTML${chalk.reset}
|
|
170
327
|
vibecheck report --theme=light --redact
|
|
171
328
|
`;
|
|
172
329
|
}
|
|
173
330
|
|
|
331
|
+
// Legacy banner for compatibility
|
|
332
|
+
const BANNER = LOGO_VIBECHECK;
|
|
333
|
+
|
|
334
|
+
const reportIcons = {
|
|
335
|
+
report: '📄',
|
|
336
|
+
html: '🌐',
|
|
337
|
+
markdown: '📝',
|
|
338
|
+
json: '📊',
|
|
339
|
+
sarif: '🔒',
|
|
340
|
+
csv: '📈',
|
|
341
|
+
executive: '👔',
|
|
342
|
+
technical: '🔧',
|
|
343
|
+
compliance: '🛡️',
|
|
344
|
+
trend: '📈',
|
|
345
|
+
success: '✓',
|
|
346
|
+
error: '✗',
|
|
347
|
+
};
|
|
348
|
+
|
|
174
349
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
175
350
|
// EXPORTS
|
|
176
351
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
177
352
|
|
|
178
353
|
module.exports = {
|
|
354
|
+
// Main formatter
|
|
355
|
+
formatReportOutput,
|
|
356
|
+
|
|
357
|
+
// Compatibility helpers
|
|
179
358
|
BANNER,
|
|
180
359
|
formatHelp,
|
|
181
360
|
renderReportInfo,
|