@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.
@@ -1,181 +1,360 @@
1
1
  /**
2
- * Report Output - Report Generation Display
3
- *
4
- * Handles all report command output formatting:
5
- * - Report generation progress
6
- * - Format selection display
7
- * - Output file information
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
- const {
13
- ansi,
14
- colors,
15
- icons,
16
- Spinner,
17
- renderSection,
18
- formatDuration,
19
- } = require('./terminal-ui');
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
- // REPORT-SPECIFIC ICONS
29
+ // CONFIGURATION
23
30
  // ═══════════════════════════════════════════════════════════════════════════════
24
31
 
25
- const reportIcons = {
26
- report: '📄',
27
- html: '🌐',
28
- markdown: '📝',
29
- json: '📊',
30
- sarif: '🔒',
31
- csv: '📈',
32
- executive: '👔',
33
- technical: '🔧',
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
- // BANNER
42
- // ═══════════════════════════════════════════════════════════════════════════════
43
+ // EXTERNAL HEADER
44
+ const LOGO_VIBECHECK = `
45
+ ██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗
46
+ ██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝
47
+ ██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝
48
+ ╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗
49
+ ╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗
50
+ ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝
51
+ `;
43
52
 
44
- const BANNER = `
45
- ${ansi.rgb(0, 200, 255)} ██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗${ansi.reset}
46
- ${ansi.rgb(30, 180, 255)} ██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝${ansi.reset}
47
- ${ansi.rgb(60, 160, 255)} ██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝ ${ansi.reset}
48
- ${ansi.rgb(90, 140, 255)} ╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗ ${ansi.reset}
49
- ${ansi.rgb(120, 120, 255)} ╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗${ansi.reset}
50
- ${ansi.rgb(150, 100, 255)} ╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝${ansi.reset}
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
- // REPORT TYPE DESCRIPTIONS
64
+ // UTILITIES
59
65
  // ═══════════════════════════════════════════════════════════════════════════════
60
66
 
61
- function getReportTypeDescription(type) {
62
- const descriptions = {
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 getFormatIcon(format) {
72
- const iconMap = {
73
- html: reportIcons.html,
74
- md: reportIcons.markdown,
75
- markdown: reportIcons.markdown,
76
- json: reportIcons.json,
77
- sarif: reportIcons.sarif,
78
- csv: reportIcons.csv,
79
- };
80
- return iconMap[format] || reportIcons.report;
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
- // REPORT GENERATION DISPLAY
86
+ // MAIN FORMATTER
85
87
  // ═══════════════════════════════════════════════════════════════════════════════
86
88
 
87
- function renderReportInfo(type, format, outputPath) {
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
- lines.push(renderSection('REPORT INFO', reportIcons.report));
117
+
118
+ // 1. Render External Header
119
+ lines.push(chalk.cyan + LOGO_VIBECHECK.trim() + chalk.reset);
90
120
  lines.push('');
91
- lines.push(` Type: ${colors.accent}${type}${ansi.reset} ${ansi.dim}(${getReportTypeDescription(type)})${ansi.reset}`);
92
- lines.push(` Format: ${getFormatIcon(format)} ${colors.accent}${format.toUpperCase()}${ansi.reset}`);
93
- if (outputPath) {
94
- lines.push(` Output: ${colors.accent}${outputPath}${ansi.reset}`);
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
- const lines = [];
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
- const lines = [];
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
- // HELP TEXT
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
- ${ansi.bold}Usage:${ansi.reset} vibecheck report [options]
282
+ ${chalk.bold}Usage:${chalk.reset} vibecheck report [options]
126
283
 
127
- ${ansi.bold}Description${ansi.reset}
284
+ ${chalk.bold}Description${chalk.reset}
128
285
  Generate beautiful, professional reports for stakeholders.
129
286
 
130
- ${ansi.bold}Report Types${ansi.reset}
131
- ${colors.accent}technical${ansi.reset} Detailed findings for developers/CTOs (default)
132
- ${colors.accent}executive${ansi.reset} One-page overview for stakeholders
133
- ${colors.accent}compliance${ansi.reset} SOC2/HIPAA-ready language for regulated industries
134
- ${colors.accent}trend${ansi.reset} Historical score analysis over time
135
-
136
- ${ansi.bold}Output Formats${ansi.reset}
137
- ${colors.success}html${ansi.reset} Beautiful interactive report (default)
138
- ${colors.success}md${ansi.reset} Markdown for documentation/GitHub
139
- ${colors.success}json${ansi.reset} Machine-readable JSON
140
- ${colors.success}sarif${ansi.reset} SARIF for security tool integration
141
- ${colors.success}csv${ansi.reset} CSV for spreadsheet analysis
142
-
143
- ${ansi.bold}Options${ansi.reset}
144
- ${colors.accent}--type, -t <type>${ansi.reset} Report type: executive, technical, compliance, trend
145
- ${colors.accent}--format, -f <format>${ansi.reset} Output format: html, md, json, sarif, csv
146
- ${colors.accent}--output, -o <path>${ansi.reset} Output file path
147
- ${colors.accent}--theme <dark|light>${ansi.reset} HTML theme (default: dark)
148
- ${colors.accent}--company <name>${ansi.reset} Company name for branding
149
- ${colors.accent}--logo <path>${ansi.reset} Custom logo path/URL
150
- ${colors.accent}--include-trends${ansi.reset} Include historical trend data
151
- ${colors.accent}--redact-paths${ansi.reset} Hide file paths for client reports
152
- ${colors.accent}--max-findings <n>${ansi.reset} Max findings to show (default: 50)
153
- ${colors.accent}--path, -p <dir>${ansi.reset} Project path (default: current directory)
154
- ${colors.accent}--help, -h${ansi.reset} Show this help
155
-
156
- ${ansi.bold}Examples${ansi.reset}
157
- ${ansi.dim}# Interactive HTML${ansi.reset}
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
- ${ansi.dim}# Markdown file${ansi.reset}
317
+ ${chalk.dim}# Markdown file${chalk.reset}
161
318
  vibecheck report --format=md --output=REPORT.md
162
319
 
163
- ${ansi.dim}# Compliance report${ansi.reset}
320
+ ${chalk.dim}# Compliance report${chalk.reset}
164
321
  vibecheck report --type=compliance --company=Acme
165
322
 
166
- ${ansi.dim}# Security tooling${ansi.reset}
323
+ ${chalk.dim}# Security tooling${chalk.reset}
167
324
  vibecheck report --format=sarif -o report.sarif
168
325
 
169
- ${ansi.dim}# Client-safe HTML${ansi.reset}
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,