@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.
@@ -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 };