@vibecheckai/cli 3.5.5 → 3.6.1
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 +1 -1
- 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/next-action.js +5 -5
- 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 +316 -271
- 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 +1 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enterprise Doctor Output - V5 "Mission Control" Format
|
|
3
|
+
* Features:
|
|
4
|
+
* - Dynamic "DOCTOR" ASCII Art
|
|
5
|
+
* - Health Check Status
|
|
6
|
+
* - System Diagnostics
|
|
7
|
+
* - Pixel-perfect 80-char alignment
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const path = require('path');
|
|
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
|
+
};
|
|
26
|
+
|
|
27
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
28
|
+
// CONFIGURATION
|
|
29
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
30
|
+
|
|
31
|
+
const WIDTH = 80;
|
|
32
|
+
|
|
33
|
+
const BOX = {
|
|
34
|
+
topLeft: '╔', topRight: '╗', bottomLeft: '╚', bottomRight: '╝',
|
|
35
|
+
horizontal: '═', vertical: '║',
|
|
36
|
+
teeRight: '╠', teeLeft: '╣', teeTop: '╤', teeBottom: '╧',
|
|
37
|
+
cross: '╪',
|
|
38
|
+
lightH: '─', lightV: '│',
|
|
39
|
+
lightTeeLeft: '├', lightTeeRight: '┤', lightCross: '┼'
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// EXTERNAL HEADER
|
|
43
|
+
const LOGO_VIBECHECK = `
|
|
44
|
+
██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗
|
|
45
|
+
██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝
|
|
46
|
+
██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝
|
|
47
|
+
╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗
|
|
48
|
+
╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗
|
|
49
|
+
╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
// HERO: DOCTOR (Cyan/Green)
|
|
53
|
+
const LOGO_DOCTOR = `
|
|
54
|
+
██████╗ ██████╗ ██████╗████████╗ ██████╗ ██████╗
|
|
55
|
+
██╔══██╗██╔═══██╗██╔════╝╚══██╔══╝██╔═══██╗██╔══██╗
|
|
56
|
+
██║ ██║██║ ██║██║ ██║ ██║ ██║██████╔╝
|
|
57
|
+
██║ ██║██║ ██║██║ ██║ ██║ ██║██╔══██╗
|
|
58
|
+
██████╔╝╚██████╔╝╚██████╗ ██║ ╚██████╔╝██║ ██║
|
|
59
|
+
╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
63
|
+
// UTILITIES
|
|
64
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
65
|
+
|
|
66
|
+
function stripAnsi(str) {
|
|
67
|
+
return str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function padCenter(str, width) {
|
|
71
|
+
const visibleLen = stripAnsi(str).length;
|
|
72
|
+
const padding = Math.max(0, width - visibleLen);
|
|
73
|
+
const left = Math.floor(padding / 2);
|
|
74
|
+
const right = padding - left;
|
|
75
|
+
return ' '.repeat(left) + str + ' '.repeat(right);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function padRight(str, len) {
|
|
79
|
+
const visibleLen = stripAnsi(str).length;
|
|
80
|
+
const truncated = visibleLen > len ? str.substring(0, len - 3) + '...' : str;
|
|
81
|
+
return truncated + ' '.repeat(Math.max(0, len - visibleLen));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
85
|
+
// MAIN FORMATTER
|
|
86
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
87
|
+
|
|
88
|
+
function formatDoctorOutput(result, options = {}) {
|
|
89
|
+
const {
|
|
90
|
+
checks = [],
|
|
91
|
+
summary = {},
|
|
92
|
+
healthy = true,
|
|
93
|
+
errors = [],
|
|
94
|
+
warnings = [],
|
|
95
|
+
} = result;
|
|
96
|
+
|
|
97
|
+
const { total = 0, passed = 0, failed = 0, warnings: warnCount = 0 } = summary;
|
|
98
|
+
|
|
99
|
+
const themeColor = healthy ? chalk.green : chalk.red;
|
|
100
|
+
const statusText = healthy ? 'SYSTEM HEALTHY' : 'ISSUES DETECTED';
|
|
101
|
+
|
|
102
|
+
const lines = [];
|
|
103
|
+
|
|
104
|
+
// 1. Render External Header
|
|
105
|
+
lines.push(chalk.cyan + LOGO_VIBECHECK.trim() + chalk.reset);
|
|
106
|
+
lines.push('');
|
|
107
|
+
|
|
108
|
+
// 2. Render Box Top
|
|
109
|
+
lines.push(`${chalk.gray}${BOX.topLeft}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.topRight}${chalk.reset}`);
|
|
110
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
111
|
+
|
|
112
|
+
// 3. Render Hero Logo (DOCTOR)
|
|
113
|
+
LOGO_DOCTOR.trim().split('\n').filter(l => l.trim().length > 0).forEach(l => {
|
|
114
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${themeColor}${padCenter(l.trim(), WIDTH - 2)}${chalk.reset}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
115
|
+
});
|
|
116
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
117
|
+
|
|
118
|
+
// 4. Info Row
|
|
119
|
+
const version = options.version || 'v3.5.5';
|
|
120
|
+
const infoText = `${chalk.bold}${version} DOCTOR${chalk.reset} :: STATUS: ${themeColor}${statusText}${chalk.reset}`;
|
|
121
|
+
const metaText = `Checks: ${total} | Passed: ${passed}`;
|
|
122
|
+
const infoLine = ` ${infoText}${' '.repeat(Math.max(1, WIDTH - 6 - stripAnsi(infoText).length - stripAnsi(metaText).length))}${chalk.dim}${metaText}${chalk.reset}`;
|
|
123
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${infoLine} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
124
|
+
|
|
125
|
+
const projectLine = ` Project: ${padRight(path.basename(options.projectPath || process.cwd()), 50)}`;
|
|
126
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${projectLine}${' '.repeat(WIDTH - 2 - stripAnsi(projectLine).length)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
127
|
+
|
|
128
|
+
// 5. Split Pane
|
|
129
|
+
lines.push(`${chalk.gray}${BOX.teeRight}${BOX.horizontal.repeat(44)}${BOX.teeTop}${BOX.horizontal.repeat(WIDTH - 47)}${BOX.teeLeft}${chalk.reset}`);
|
|
130
|
+
|
|
131
|
+
function printSplitRow(left, right) {
|
|
132
|
+
const leftContent = padRight(left || '', 42);
|
|
133
|
+
const rightContent = padRight(right || '', WIDTH - 48);
|
|
134
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${leftContent} ${chalk.gray}${BOX.lightV}${chalk.reset} ${rightContent} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Row 1: Headers
|
|
138
|
+
printSplitRow(`${chalk.bold}HEALTH CHECKS${chalk.reset}`, `${chalk.bold}ISSUES & WARNINGS${chalk.reset}`);
|
|
139
|
+
|
|
140
|
+
// Row 2: Divider
|
|
141
|
+
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}`);
|
|
142
|
+
|
|
143
|
+
// Prepare Left Column
|
|
144
|
+
const leftCol = [
|
|
145
|
+
'',
|
|
146
|
+
` TOTAL CHECKS [${total}]`,
|
|
147
|
+
` Passed: ${chalk.green}${passed}${chalk.reset}`,
|
|
148
|
+
` Failed: ${chalk.red}${failed}${chalk.reset}`,
|
|
149
|
+
` Warnings: ${chalk.yellow}${warnCount}${chalk.reset}`,
|
|
150
|
+
'',
|
|
151
|
+
`${chalk.gray}${BOX.lightH.repeat(42)}${chalk.reset}`,
|
|
152
|
+
`${chalk.bold} CHECK RESULTS${chalk.reset}`,
|
|
153
|
+
'',
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
// Add check results
|
|
157
|
+
checks.slice(0, 5).forEach((check, i) => {
|
|
158
|
+
const status = check.status === 'pass' ? chalk.green + '✓' : check.status === 'fail' ? chalk.red + '✖' : chalk.yellow + '⚠';
|
|
159
|
+
const name = (check.name || check.category || 'Check').substring(0, 25);
|
|
160
|
+
leftCol.push(` ${status}${chalk.reset} ${name}`);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (checks.length > 5) {
|
|
164
|
+
leftCol.push(` ${chalk.dim}... ${checks.length - 5} more${chalk.reset}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Prepare Right Column
|
|
168
|
+
const rightCol = [];
|
|
169
|
+
rightCol.push('');
|
|
170
|
+
|
|
171
|
+
if (errors.length > 0) {
|
|
172
|
+
rightCol.push(`${chalk.bold} ERRORS${chalk.reset}`);
|
|
173
|
+
errors.slice(0, 3).forEach((error, i) => {
|
|
174
|
+
const msg = (error.message || error).substring(0, 25);
|
|
175
|
+
rightCol.push(` ${chalk.red}✖${chalk.reset} ${msg}`);
|
|
176
|
+
});
|
|
177
|
+
if (errors.length > 3) {
|
|
178
|
+
rightCol.push(` ${chalk.dim}... ${errors.length - 3} more${chalk.reset}`);
|
|
179
|
+
}
|
|
180
|
+
rightCol.push('');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (warnings.length > 0) {
|
|
184
|
+
rightCol.push(`${chalk.bold} WARNINGS${chalk.reset}`);
|
|
185
|
+
warnings.slice(0, 3).forEach((warning, i) => {
|
|
186
|
+
const msg = (warning.message || warning).substring(0, 25);
|
|
187
|
+
rightCol.push(` ${chalk.yellow}⚠${chalk.reset} ${msg}`);
|
|
188
|
+
});
|
|
189
|
+
if (warnings.length > 3) {
|
|
190
|
+
rightCol.push(` ${chalk.dim}... ${warnings.length - 3} more${chalk.reset}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (errors.length === 0 && warnings.length === 0) {
|
|
195
|
+
rightCol.push(`${chalk.green} [✓] NO ISSUES${chalk.reset}`);
|
|
196
|
+
rightCol.push(` All checks passed.`);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Merge Columns
|
|
200
|
+
const maxRows = Math.max(leftCol.length, rightCol.length);
|
|
201
|
+
for (let i = 0; i < maxRows; i++) {
|
|
202
|
+
printSplitRow(leftCol[i] || '', rightCol[i] || '');
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// 6. Action Footer
|
|
206
|
+
lines.push(`${chalk.gray}${BOX.teeRight}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.teeLeft}${chalk.reset}`);
|
|
207
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${chalk.bold}DIAGNOSTIC CONTROL${chalk.reset}${' '.repeat(WIDTH - 20)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
208
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${BOX.lightH.repeat(WIDTH - 4)} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
209
|
+
|
|
210
|
+
if (healthy) {
|
|
211
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${chalk.green}[✓] SYSTEM HEALTHY. ALL CHECKS PASSED.${chalk.reset}${' '.repeat(WIDTH - 40)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
212
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
213
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}vibecheck scan${chalk.reset} [SCAN] Run codebase analysis ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
214
|
+
} else {
|
|
215
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${chalk.red}[!] ISSUES DETECTED. REVIEW REQUIRED.${chalk.reset}${' '.repeat(WIDTH - 40)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
216
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
217
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}vibecheck doctor --fix${chalk.reset} [AUTO-FIX] Attempt automatic fixes ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// 7. Box Bottom
|
|
221
|
+
lines.push(`${chalk.gray}${BOX.bottomLeft}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.bottomRight}${chalk.reset}`);
|
|
222
|
+
|
|
223
|
+
return lines.join('\n');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
module.exports = { formatDoctorOutput };
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enterprise Fix Output - V5 "Mission Control" Format
|
|
3
|
+
* Features:
|
|
4
|
+
* - Dynamic "FIX" ASCII Art
|
|
5
|
+
* - Mission Planning Status
|
|
6
|
+
* - Fix Progress Tracking
|
|
7
|
+
* - Pixel-perfect 80-char alignment
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const path = require('path');
|
|
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
|
+
};
|
|
26
|
+
|
|
27
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
28
|
+
// CONFIGURATION
|
|
29
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
30
|
+
|
|
31
|
+
const WIDTH = 80;
|
|
32
|
+
|
|
33
|
+
const BOX = {
|
|
34
|
+
topLeft: '╔', topRight: '╗', bottomLeft: '╚', bottomRight: '╝',
|
|
35
|
+
horizontal: '═', vertical: '║',
|
|
36
|
+
teeRight: '╠', teeLeft: '╣', teeTop: '╤', teeBottom: '╧',
|
|
37
|
+
cross: '╪',
|
|
38
|
+
lightH: '─', lightV: '│',
|
|
39
|
+
lightTeeLeft: '├', lightTeeRight: '┤', lightCross: '┼'
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// EXTERNAL HEADER
|
|
43
|
+
const LOGO_VIBECHECK = `
|
|
44
|
+
██╗ ██╗██╗██████╗ ███████╗ ██████╗██╗ ██╗███████╗ ██████╗██╗ ██╗
|
|
45
|
+
██║ ██║██║██╔══██╗██╔════╝██╔════╝██║ ██║██╔════╝██╔════╝██║ ██╔╝
|
|
46
|
+
██║ ██║██║██████╔╝█████╗ ██║ ███████║█████╗ ██║ █████╔╝
|
|
47
|
+
╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██║ ██╔══██║██╔══╝ ██║ ██╔═██╗
|
|
48
|
+
╚████╔╝ ██║██████╔╝███████╗╚██████╗██║ ██║███████╗╚██████╗██║ ██╗
|
|
49
|
+
╚═══╝ ╚═╝╚═════╝ ╚══════╝ ╚═════╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝
|
|
50
|
+
`;
|
|
51
|
+
|
|
52
|
+
// HERO: FIX (Magenta/Yellow)
|
|
53
|
+
const LOGO_FIX = `
|
|
54
|
+
███████╗██╗██╗ ██╗
|
|
55
|
+
██╔════╝██║╚██╗██╔╝
|
|
56
|
+
█████╗ ██║ ╚███╔╝
|
|
57
|
+
██╔══╝ ██║ ██╔██╗
|
|
58
|
+
██║ ██║██╔╝ ██╗
|
|
59
|
+
╚═╝ ╚═╝╚═╝ ╚═╝
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
63
|
+
// UTILITIES
|
|
64
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
65
|
+
|
|
66
|
+
function stripAnsi(str) {
|
|
67
|
+
return str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function padCenter(str, width) {
|
|
71
|
+
const visibleLen = stripAnsi(str).length;
|
|
72
|
+
const padding = Math.max(0, width - visibleLen);
|
|
73
|
+
const left = Math.floor(padding / 2);
|
|
74
|
+
const right = padding - left;
|
|
75
|
+
return ' '.repeat(left) + str + ' '.repeat(right);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function padRight(str, len) {
|
|
79
|
+
const visibleLen = stripAnsi(str).length;
|
|
80
|
+
const truncated = visibleLen > len ? str.substring(0, len - 3) + '...' : str;
|
|
81
|
+
return truncated + ' '.repeat(Math.max(0, len - visibleLen));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
85
|
+
// MAIN FORMATTER
|
|
86
|
+
// ═══════════════════════════════════════════════════════════════════════════════
|
|
87
|
+
|
|
88
|
+
function formatFixOutput(result, options = {}) {
|
|
89
|
+
const {
|
|
90
|
+
missions = [],
|
|
91
|
+
verdict = null,
|
|
92
|
+
beforeVerdict = null,
|
|
93
|
+
afterVerdict = null,
|
|
94
|
+
appliedMissions = 0,
|
|
95
|
+
totalMissions = 0,
|
|
96
|
+
duration = 0,
|
|
97
|
+
success = false,
|
|
98
|
+
error = null,
|
|
99
|
+
} = result;
|
|
100
|
+
|
|
101
|
+
const isSuccess = success || (afterVerdict === 'SHIP');
|
|
102
|
+
const themeColor = isSuccess ? chalk.green : error ? chalk.red : chalk.yellow;
|
|
103
|
+
const statusText = isSuccess ? 'MISSIONS COMPLETE' : error ? 'MISSION FAILED' : 'IN PROGRESS';
|
|
104
|
+
|
|
105
|
+
const lines = [];
|
|
106
|
+
|
|
107
|
+
// 1. Render External Header
|
|
108
|
+
lines.push(chalk.cyan + LOGO_VIBECHECK.trim() + chalk.reset);
|
|
109
|
+
lines.push('');
|
|
110
|
+
|
|
111
|
+
// 2. Render Box Top
|
|
112
|
+
lines.push(`${chalk.gray}${BOX.topLeft}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.topRight}${chalk.reset}`);
|
|
113
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
114
|
+
|
|
115
|
+
// 3. Render Hero Logo (FIX)
|
|
116
|
+
LOGO_FIX.trim().split('\n').filter(l => l.trim().length > 0).forEach(l => {
|
|
117
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${themeColor}${padCenter(l.trim(), WIDTH - 2)}${chalk.reset}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
118
|
+
});
|
|
119
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
120
|
+
|
|
121
|
+
// 4. Info Row
|
|
122
|
+
const version = options.version || 'v3.5.5';
|
|
123
|
+
const infoText = `${chalk.bold}${version} FIX${chalk.reset} :: STATUS: ${themeColor}${statusText}${chalk.reset}`;
|
|
124
|
+
const metaText = `Missions: ${appliedMissions}/${totalMissions} | Time: ${(duration / 1000).toFixed(1)}s`;
|
|
125
|
+
const infoLine = ` ${infoText}${' '.repeat(Math.max(1, WIDTH - 6 - stripAnsi(infoText).length - stripAnsi(metaText).length))}${chalk.dim}${metaText}${chalk.reset}`;
|
|
126
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${infoLine} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
127
|
+
|
|
128
|
+
const projectLine = ` Project: ${padRight(path.basename(process.cwd()), 50)}`;
|
|
129
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${projectLine}${' '.repeat(WIDTH - 2 - stripAnsi(projectLine).length)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
130
|
+
|
|
131
|
+
// 5. Split Pane
|
|
132
|
+
lines.push(`${chalk.gray}${BOX.teeRight}${BOX.horizontal.repeat(44)}${BOX.teeTop}${BOX.horizontal.repeat(WIDTH - 47)}${BOX.teeLeft}${chalk.reset}`);
|
|
133
|
+
|
|
134
|
+
function printSplitRow(left, right) {
|
|
135
|
+
const leftContent = padRight(left || '', 42);
|
|
136
|
+
const rightContent = padRight(right || '', WIDTH - 48);
|
|
137
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${leftContent} ${chalk.gray}${BOX.lightV}${chalk.reset} ${rightContent} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Row 1: Headers
|
|
141
|
+
printSplitRow(`${chalk.bold}MISSION STATUS${chalk.reset}`, `${chalk.bold}VERDICT PROGRESSION${chalk.reset}`);
|
|
142
|
+
|
|
143
|
+
// Row 2: Divider
|
|
144
|
+
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}`);
|
|
145
|
+
|
|
146
|
+
// Prepare Left Column
|
|
147
|
+
const progress = totalMissions > 0 ? Math.round((appliedMissions / totalMissions) * 100) : 0;
|
|
148
|
+
const leftCol = [
|
|
149
|
+
'',
|
|
150
|
+
` PROGRESS [${progress}%]`,
|
|
151
|
+
` Applied: ${chalk.cyan}${appliedMissions}${chalk.reset}`,
|
|
152
|
+
` Remaining: ${chalk.yellow}${totalMissions - appliedMissions}${chalk.reset}`,
|
|
153
|
+
'',
|
|
154
|
+
`${chalk.gray}${BOX.lightH.repeat(42)}${chalk.reset}`,
|
|
155
|
+
`${chalk.bold} MODE${chalk.reset}`,
|
|
156
|
+
'',
|
|
157
|
+
` ${options.apply ? chalk.green + '✓' : chalk.gray + '—'}${chalk.reset} Auto-Apply`,
|
|
158
|
+
` ${options.promptOnly ? chalk.green + '✓' : chalk.gray + '—'}${chalk.reset} Prompt-Only`,
|
|
159
|
+
` ${options.loop ? chalk.green + '✓' : chalk.gray + '—'}${chalk.reset} Loop Mode`,
|
|
160
|
+
'',
|
|
161
|
+
`${chalk.gray}${BOX.lightH.repeat(42)}${chalk.reset}`,
|
|
162
|
+
`${chalk.bold} MISSIONS${chalk.reset}`,
|
|
163
|
+
'',
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
// Add mission list
|
|
167
|
+
missions.slice(0, 5).forEach((mission, i) => {
|
|
168
|
+
const status = i < appliedMissions ? chalk.green + '✓' : chalk.yellow + '○';
|
|
169
|
+
const name = (mission.type || mission.category || 'Mission').substring(0, 25);
|
|
170
|
+
leftCol.push(` ${status}${chalk.reset} ${name}`);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
if (missions.length > 5) {
|
|
174
|
+
leftCol.push(` ${chalk.dim}... ${missions.length - 5} more${chalk.reset}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Prepare Right Column
|
|
178
|
+
const rightCol = [];
|
|
179
|
+
rightCol.push('');
|
|
180
|
+
|
|
181
|
+
if (isSuccess) {
|
|
182
|
+
rightCol.push(`${chalk.green} [✓] SHIP ACHIEVED${chalk.reset}`);
|
|
183
|
+
rightCol.push(` All missions complete.`);
|
|
184
|
+
rightCol.push('');
|
|
185
|
+
rightCol.push(` Before: ${beforeVerdict || 'N/A'}`);
|
|
186
|
+
rightCol.push(` After: ${chalk.green}${afterVerdict || 'SHIP'}${chalk.reset}`);
|
|
187
|
+
} else if (error) {
|
|
188
|
+
rightCol.push(`${chalk.red} [!] ERROR${chalk.reset}`);
|
|
189
|
+
rightCol.push(` Mission failed.`);
|
|
190
|
+
rightCol.push('');
|
|
191
|
+
let msg = error.message || 'Unknown error';
|
|
192
|
+
if (msg.length > 25) msg = msg.substring(0, 25) + '...';
|
|
193
|
+
rightCol.push(` ${chalk.red}${msg}${chalk.reset}`);
|
|
194
|
+
} else {
|
|
195
|
+
rightCol.push(`${chalk.yellow} [○] IN PROGRESS${chalk.reset}`);
|
|
196
|
+
rightCol.push(` Applying fixes...`);
|
|
197
|
+
rightCol.push('');
|
|
198
|
+
rightCol.push(` Before: ${beforeVerdict || 'N/A'}`);
|
|
199
|
+
rightCol.push(` Target: ${chalk.green}SHIP${chalk.reset}`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Merge Columns
|
|
203
|
+
const maxRows = Math.max(leftCol.length, rightCol.length);
|
|
204
|
+
for (let i = 0; i < maxRows; i++) {
|
|
205
|
+
printSplitRow(leftCol[i] || '', rightCol[i] || '');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 6. Action Footer
|
|
209
|
+
lines.push(`${chalk.gray}${BOX.teeRight}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.teeLeft}${chalk.reset}`);
|
|
210
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${chalk.bold}MISSION CONTROL${chalk.reset}${' '.repeat(WIDTH - 18)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
211
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${BOX.lightH.repeat(WIDTH - 4)} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
212
|
+
|
|
213
|
+
if (isSuccess) {
|
|
214
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${chalk.green}[✓] ALL SYSTEMS OPERATIONAL.${chalk.reset}${' '.repeat(WIDTH - 32)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
215
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
216
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}vibecheck ship${chalk.reset} [VERIFY] Confirm deployment readiness ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
217
|
+
} else {
|
|
218
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}vibecheck fix --apply${chalk.reset} [CONTINUE] Apply remaining missions ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
219
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}vibecheck fix --loop${chalk.reset} [AUTO] Loop until SHIP ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// 7. Box Bottom
|
|
223
|
+
lines.push(`${chalk.gray}${BOX.bottomLeft}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.bottomRight}${chalk.reset}`);
|
|
224
|
+
|
|
225
|
+
return lines.join('\n');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
module.exports = { formatFixOutput };
|
|
@@ -228,7 +228,7 @@ function computeNextAction(state) {
|
|
|
228
228
|
return {
|
|
229
229
|
action: "badge",
|
|
230
230
|
command: "vibecheck ship --badge",
|
|
231
|
-
dashboardLink: `${DASHBOARD_URL}/runs/${runId}
|
|
231
|
+
dashboardLink: runId ? `${DASHBOARD_URL}/runs/${runId}` : undefined,
|
|
232
232
|
why: "SHIP passed! Generate a verified badge for your README.",
|
|
233
233
|
timeEstimate: TIME_ESTIMATES.badge,
|
|
234
234
|
tier: "pro",
|
|
@@ -255,7 +255,7 @@ function computeNextAction(state) {
|
|
|
255
255
|
return {
|
|
256
256
|
action: "report",
|
|
257
257
|
command: "vibecheck report",
|
|
258
|
-
dashboardLink: `${DASHBOARD_URL}/runs/${runId}
|
|
258
|
+
dashboardLink: runId ? `${DASHBOARD_URL}/runs/${runId}` : undefined,
|
|
259
259
|
why: "Scan complete. Export report or upgrade to get verdict.",
|
|
260
260
|
timeEstimate: TIME_ESTIMATES.report,
|
|
261
261
|
tier: "free",
|
|
@@ -328,7 +328,7 @@ function getNextActionForCommand(completedCmd, result = {}, tier = "free") {
|
|
|
328
328
|
return {
|
|
329
329
|
action: "report",
|
|
330
330
|
command: "vibecheck report",
|
|
331
|
-
dashboardLink: `${DASHBOARD_URL}/runs/${runId}
|
|
331
|
+
dashboardLink: runId ? `${DASHBOARD_URL}/runs/${runId}` : undefined,
|
|
332
332
|
why: `Scan complete. Export report.`,
|
|
333
333
|
timeEstimate: TIME_ESTIMATES.report,
|
|
334
334
|
tier: "free",
|
|
@@ -344,7 +344,7 @@ function getNextActionForCommand(completedCmd, result = {}, tier = "free") {
|
|
|
344
344
|
return {
|
|
345
345
|
action: "badge",
|
|
346
346
|
command: "vibecheck ship --badge",
|
|
347
|
-
dashboardLink: `${DASHBOARD_URL}/runs/${runId}
|
|
347
|
+
dashboardLink: runId ? `${DASHBOARD_URL}/runs/${runId}` : undefined,
|
|
348
348
|
why: "SHIP passed! Generate a verified badge.",
|
|
349
349
|
timeEstimate: TIME_ESTIMATES.badge,
|
|
350
350
|
tier: "pro",
|
|
@@ -363,7 +363,7 @@ function getNextActionForCommand(completedCmd, result = {}, tier = "free") {
|
|
|
363
363
|
return {
|
|
364
364
|
action: "report",
|
|
365
365
|
command: "vibecheck report",
|
|
366
|
-
dashboardLink: `${DASHBOARD_URL}/runs/${runId}
|
|
366
|
+
dashboardLink: runId ? `${DASHBOARD_URL}/runs/${runId}` : undefined,
|
|
367
367
|
why: "Export detailed report.",
|
|
368
368
|
timeEstimate: TIME_ESTIMATES.report,
|
|
369
369
|
tier: "free",
|