@vibecheckai/cli 3.5.5 → 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 +1 -1
|
@@ -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 };
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enterprise Prove Output - V5 "Mission Control" Format
|
|
3
|
+
* Features:
|
|
4
|
+
* - Dynamic "PROVE" ASCII Art
|
|
5
|
+
* - Proof Loop Status
|
|
6
|
+
* - Runtime Verification Results
|
|
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: PROVE (Green/Cyan)
|
|
53
|
+
const LOGO_PROVE = `
|
|
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 formatProveOutput(result, options = {}) {
|
|
89
|
+
const {
|
|
90
|
+
verdict = null,
|
|
91
|
+
finalVerdict = null,
|
|
92
|
+
steps = [],
|
|
93
|
+
runtimeTests = 0,
|
|
94
|
+
runtimePassed = 0,
|
|
95
|
+
duration = 0,
|
|
96
|
+
success = false,
|
|
97
|
+
error = null,
|
|
98
|
+
} = result;
|
|
99
|
+
|
|
100
|
+
const isSuccess = success || (finalVerdict === 'SHIP');
|
|
101
|
+
const themeColor = isSuccess ? chalk.green : error ? chalk.red : chalk.yellow;
|
|
102
|
+
const statusText = isSuccess ? 'PROOF VERIFIED' : error ? 'PROOF FAILED' : 'PROOF IN PROGRESS';
|
|
103
|
+
|
|
104
|
+
const lines = [];
|
|
105
|
+
|
|
106
|
+
// 1. Render External Header
|
|
107
|
+
lines.push(chalk.cyan + LOGO_VIBECHECK.trim() + chalk.reset);
|
|
108
|
+
lines.push('');
|
|
109
|
+
|
|
110
|
+
// 2. Render Box Top
|
|
111
|
+
lines.push(`${chalk.gray}${BOX.topLeft}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.topRight}${chalk.reset}`);
|
|
112
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
113
|
+
|
|
114
|
+
// 3. Render Hero Logo (PROVE)
|
|
115
|
+
LOGO_PROVE.trim().split('\n').filter(l => l.trim().length > 0).forEach(l => {
|
|
116
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${themeColor}${padCenter(l.trim(), WIDTH - 2)}${chalk.reset}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
117
|
+
});
|
|
118
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
119
|
+
|
|
120
|
+
// 4. Info Row
|
|
121
|
+
const version = options.version || 'v3.5.5';
|
|
122
|
+
const infoText = `${chalk.bold}${version} PROVE${chalk.reset} :: STATUS: ${themeColor}${statusText}${chalk.reset}`;
|
|
123
|
+
const metaText = `Steps: ${steps.length} | Time: ${(duration / 1000).toFixed(1)}s`;
|
|
124
|
+
const infoLine = ` ${infoText}${' '.repeat(Math.max(1, WIDTH - 6 - stripAnsi(infoText).length - stripAnsi(metaText).length))}${chalk.dim}${metaText}${chalk.reset}`;
|
|
125
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${infoLine} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
126
|
+
|
|
127
|
+
const projectLine = ` Project: ${padRight(path.basename(process.cwd()), 50)}`;
|
|
128
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset}${projectLine}${' '.repeat(WIDTH - 2 - stripAnsi(projectLine).length)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
129
|
+
|
|
130
|
+
// 5. Split Pane
|
|
131
|
+
lines.push(`${chalk.gray}${BOX.teeRight}${BOX.horizontal.repeat(44)}${BOX.teeTop}${BOX.horizontal.repeat(WIDTH - 47)}${BOX.teeLeft}${chalk.reset}`);
|
|
132
|
+
|
|
133
|
+
function printSplitRow(left, right) {
|
|
134
|
+
const leftContent = padRight(left || '', 42);
|
|
135
|
+
const rightContent = padRight(right || '', WIDTH - 48);
|
|
136
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${leftContent} ${chalk.gray}${BOX.lightV}${chalk.reset} ${rightContent} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Row 1: Headers
|
|
140
|
+
printSplitRow(`${chalk.bold}PROOF LOOP${chalk.reset}`, `${chalk.bold}RUNTIME VERIFICATION${chalk.reset}`);
|
|
141
|
+
|
|
142
|
+
// Row 2: Divider
|
|
143
|
+
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}`);
|
|
144
|
+
|
|
145
|
+
// Prepare Left Column
|
|
146
|
+
const leftCol = [
|
|
147
|
+
'',
|
|
148
|
+
` VERDICT [${finalVerdict === 'SHIP' ? chalk.green + 'SHIP' : finalVerdict === 'BLOCK' ? chalk.red + 'BLOCK' : chalk.yellow + 'WARN'}${chalk.reset}]`,
|
|
149
|
+
` Final: ${finalVerdict || 'N/A'}`,
|
|
150
|
+
'',
|
|
151
|
+
`${chalk.gray}${BOX.lightH.repeat(42)}${chalk.reset}`,
|
|
152
|
+
`${chalk.bold} PROOF STEPS${chalk.reset}`,
|
|
153
|
+
'',
|
|
154
|
+
];
|
|
155
|
+
|
|
156
|
+
// Add step list
|
|
157
|
+
steps.slice(0, 5).forEach((step, i) => {
|
|
158
|
+
const status = step.success ? chalk.green + '✓' : step.error ? chalk.red + '✖' : chalk.yellow + '○';
|
|
159
|
+
const name = (step.name || step.type || 'Step').substring(0, 25);
|
|
160
|
+
leftCol.push(` ${status}${chalk.reset} ${name}`);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
if (steps.length > 5) {
|
|
164
|
+
leftCol.push(` ${chalk.dim}... ${steps.length - 5} more${chalk.reset}`);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Prepare Right Column
|
|
168
|
+
const rightCol = [];
|
|
169
|
+
rightCol.push('');
|
|
170
|
+
|
|
171
|
+
if (runtimeTests > 0) {
|
|
172
|
+
const passRate = Math.round((runtimePassed / runtimeTests) * 100);
|
|
173
|
+
rightCol.push(` TESTS RUN [${passRate}%]`);
|
|
174
|
+
rightCol.push(` Passed: ${chalk.green}${runtimePassed}${chalk.reset}`);
|
|
175
|
+
rightCol.push(` Failed: ${chalk.red}${runtimeTests - runtimePassed}${chalk.reset}`);
|
|
176
|
+
rightCol.push('');
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (isSuccess) {
|
|
180
|
+
rightCol.push(`${chalk.green} [✓] PROOF VERIFIED${chalk.reset}`);
|
|
181
|
+
rightCol.push(` Runtime tests passed.`);
|
|
182
|
+
} else if (error) {
|
|
183
|
+
rightCol.push(`${chalk.red} [!] PROOF FAILED${chalk.reset}`);
|
|
184
|
+
rightCol.push(` Verification error.`);
|
|
185
|
+
rightCol.push('');
|
|
186
|
+
let msg = error.message || 'Unknown error';
|
|
187
|
+
if (msg.length > 25) msg = msg.substring(0, 25) + '...';
|
|
188
|
+
rightCol.push(` ${chalk.red}${msg}${chalk.reset}`);
|
|
189
|
+
} else {
|
|
190
|
+
rightCol.push(`${chalk.yellow} [○] IN PROGRESS${chalk.reset}`);
|
|
191
|
+
rightCol.push(` Running proof loop...`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Merge Columns
|
|
195
|
+
const maxRows = Math.max(leftCol.length, rightCol.length);
|
|
196
|
+
for (let i = 0; i < maxRows; i++) {
|
|
197
|
+
printSplitRow(leftCol[i] || '', rightCol[i] || '');
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// 6. Action Footer
|
|
201
|
+
lines.push(`${chalk.gray}${BOX.teeRight}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.teeLeft}${chalk.reset}`);
|
|
202
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${chalk.bold}PROOF PROTOCOLS${chalk.reset}${' '.repeat(WIDTH - 17)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
203
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${BOX.lightH.repeat(WIDTH - 4)} ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
204
|
+
|
|
205
|
+
if (isSuccess) {
|
|
206
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} ${chalk.green}[✓] PROOF VERIFIED. READY FOR PRODUCTION.${chalk.reset}${' '.repeat(WIDTH - 42)}${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
207
|
+
lines.push(`${chalk.gray}${BOX.vertical}${' '.repeat(WIDTH - 2)}${BOX.vertical}${chalk.reset}`);
|
|
208
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}vibecheck ship${chalk.reset} [DEPLOY] Proceed with deployment ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
209
|
+
} else {
|
|
210
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}vibecheck prove --retry${chalk.reset} [RETRY] Re-run proof loop ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
211
|
+
lines.push(`${chalk.gray}${BOX.vertical}${chalk.reset} > ${chalk.cyan}vibecheck fix --apply${chalk.reset} [FIX] Apply fixes before retry ${chalk.gray}${BOX.vertical}${chalk.reset}`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 7. Box Bottom
|
|
215
|
+
lines.push(`${chalk.gray}${BOX.bottomLeft}${BOX.horizontal.repeat(WIDTH - 2)}${BOX.bottomRight}${chalk.reset}`);
|
|
216
|
+
|
|
217
|
+
return lines.join('\n');
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
module.exports = { formatProveOutput };
|