gbos 1.1.3 → 1.1.5
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/images/logo-2.png +0 -0
- package/package.json +1 -1
- package/src/lib/display.js +291 -217
|
Binary file
|
package/package.json
CHANGED
package/src/lib/display.js
CHANGED
|
@@ -1,283 +1,357 @@
|
|
|
1
|
-
const { execSync, spawnSync } = require('child_process');
|
|
2
1
|
const path = require('path');
|
|
3
2
|
const fs = require('fs');
|
|
4
3
|
const { PNG } = require('pngjs');
|
|
5
4
|
|
|
6
|
-
// ANSI
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
green: '\x1b[32m',
|
|
24
|
-
yellow: '\x1b[33m',
|
|
5
|
+
// ANSI escape codes
|
|
6
|
+
const ESC = '\x1b';
|
|
7
|
+
const RESET = `${ESC}[0m`;
|
|
8
|
+
const BOLD = `${ESC}[1m`;
|
|
9
|
+
const DIM = `${ESC}[2m`;
|
|
10
|
+
|
|
11
|
+
// True color ANSI helpers
|
|
12
|
+
const fg = (r, g, b) => `${ESC}[38;2;${r};${g};${b}m`;
|
|
13
|
+
const bg = (r, g, b) => `${ESC}[48;2;${r};${g};${b}m`;
|
|
14
|
+
|
|
15
|
+
// Purple theme RGB values
|
|
16
|
+
const PURPLE = {
|
|
17
|
+
dark: [75, 0, 130], // Deep purple
|
|
18
|
+
medium: [128, 0, 128], // Purple
|
|
19
|
+
light: [147, 112, 219], // Medium purple
|
|
20
|
+
bright: [186, 85, 211], // Medium orchid
|
|
21
|
+
pale: [216, 191, 216], // Thistle
|
|
25
22
|
};
|
|
26
23
|
|
|
27
|
-
//
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
24
|
+
// 256-color fallback codes
|
|
25
|
+
const colors = {
|
|
26
|
+
reset: RESET,
|
|
27
|
+
bold: BOLD,
|
|
28
|
+
dim: DIM,
|
|
29
|
+
purple4: `${ESC}[38;5;93m`,
|
|
30
|
+
purple5: `${ESC}[38;5;99m`,
|
|
31
|
+
purple6: `${ESC}[38;5;141m`,
|
|
32
|
+
purple7: `${ESC}[38;5;183m`,
|
|
33
|
+
white: `${ESC}[37m`,
|
|
34
|
+
};
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
// Unicode half-block characters
|
|
37
|
+
const UPPER_HALF = '▀';
|
|
38
|
+
const LOWER_HALF = '▄';
|
|
39
|
+
const FULL_BLOCK = '█';
|
|
38
40
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
// Get terminal width
|
|
42
|
+
function getTerminalWidth() {
|
|
43
|
+
return process.stdout.columns || 80;
|
|
44
|
+
}
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
// Sample pixel from PNG at given coordinates
|
|
47
|
+
function samplePixel(png, x, y) {
|
|
48
|
+
const clampedX = Math.max(0, Math.min(Math.floor(x), png.width - 1));
|
|
49
|
+
const clampedY = Math.max(0, Math.min(Math.floor(y), png.height - 1));
|
|
50
|
+
const idx = (png.width * clampedY + clampedX) << 2;
|
|
51
|
+
return {
|
|
52
|
+
r: png.data[idx],
|
|
53
|
+
g: png.data[idx + 1],
|
|
54
|
+
b: png.data[idx + 2],
|
|
55
|
+
a: png.data[idx + 3],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
43
58
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const sampleX = Math.floor(x * cellWidth + cellWidth / 2);
|
|
49
|
-
const sampleY = Math.floor(y * cellHeight + cellHeight / 2);
|
|
50
|
-
const idx = (png.width * sampleY + sampleX) << 2;
|
|
59
|
+
// Check if pixel is transparent or white (background)
|
|
60
|
+
function isBackground(pixel) {
|
|
61
|
+
return pixel.a < 50 || (pixel.r > 240 && pixel.g > 240 && pixel.b > 240);
|
|
62
|
+
}
|
|
51
63
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
64
|
+
// Convert PNG to true-color pixel art using half-blocks
|
|
65
|
+
// Each character cell represents 2 vertical pixels
|
|
66
|
+
function imageToPixels(imagePath, targetWidth = 24, targetHeight = 12) {
|
|
67
|
+
try {
|
|
68
|
+
const data = fs.readFileSync(imagePath);
|
|
69
|
+
const png = PNG.sync.read(data);
|
|
56
70
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
// Each row of output = 2 rows of pixels (using half-blocks)
|
|
72
|
+
const pixelRows = targetHeight * 2;
|
|
73
|
+
const cellWidth = png.width / targetWidth;
|
|
74
|
+
const cellHeight = png.height / pixelRows;
|
|
75
|
+
|
|
76
|
+
const lines = [];
|
|
77
|
+
|
|
78
|
+
for (let row = 0; row < targetHeight; row++) {
|
|
79
|
+
let line = '';
|
|
80
|
+
for (let col = 0; col < targetWidth; col++) {
|
|
81
|
+
// Sample top and bottom pixels for this cell
|
|
82
|
+
const topY = row * 2 * cellHeight + cellHeight / 2;
|
|
83
|
+
const bottomY = (row * 2 + 1) * cellHeight + cellHeight / 2;
|
|
84
|
+
const x = col * cellWidth + cellWidth / 2;
|
|
85
|
+
|
|
86
|
+
const topPixel = samplePixel(png, x, topY);
|
|
87
|
+
const bottomPixel = samplePixel(png, x, bottomY);
|
|
88
|
+
|
|
89
|
+
const topBg = isBackground(topPixel);
|
|
90
|
+
const bottomBg = isBackground(bottomPixel);
|
|
91
|
+
|
|
92
|
+
if (topBg && bottomBg) {
|
|
93
|
+
// Both transparent - just a space
|
|
94
|
+
line += ' ';
|
|
95
|
+
} else if (topBg && !bottomBg) {
|
|
96
|
+
// Only bottom has color - use lower half block with fg color
|
|
97
|
+
line += fg(bottomPixel.r, bottomPixel.g, bottomPixel.b) + LOWER_HALF + RESET;
|
|
98
|
+
} else if (!topBg && bottomBg) {
|
|
99
|
+
// Only top has color - use upper half block with fg color
|
|
100
|
+
line += fg(topPixel.r, topPixel.g, topPixel.b) + UPPER_HALF + RESET;
|
|
101
|
+
} else {
|
|
102
|
+
// Both have color - use upper half with fg=top, bg=bottom
|
|
103
|
+
line += fg(topPixel.r, topPixel.g, topPixel.b) + bg(bottomPixel.r, bottomPixel.g, bottomPixel.b) + UPPER_HALF + RESET;
|
|
61
104
|
}
|
|
62
|
-
|
|
63
|
-
// Calculate brightness (0-255)
|
|
64
|
-
const brightness = (r + g + b) / 3;
|
|
65
|
-
// Map to ASCII character (inverted - darker pixels = denser characters)
|
|
66
|
-
const charIndex = Math.floor((1 - brightness / 255) * (ASCII_CHARS.length - 1));
|
|
67
|
-
row += ASCII_CHARS[charIndex];
|
|
68
105
|
}
|
|
69
|
-
|
|
106
|
+
lines.push(line);
|
|
70
107
|
}
|
|
71
108
|
|
|
72
|
-
return
|
|
109
|
+
return lines;
|
|
73
110
|
} catch (e) {
|
|
74
111
|
return null;
|
|
75
112
|
}
|
|
76
113
|
}
|
|
77
114
|
|
|
78
|
-
//
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
115
|
+
// "gbos.io" pixel art (8 rows tall to match logo height)
|
|
116
|
+
// Each character is approximately 5 wide, total ~35 wide
|
|
117
|
+
function getGbosTextPixels() {
|
|
118
|
+
// 8-row pixel art for "gbos.io"
|
|
119
|
+
// Using purple gradient colors
|
|
120
|
+
const p1 = PURPLE.dark;
|
|
121
|
+
const p2 = PURPLE.medium;
|
|
122
|
+
const p3 = PURPLE.light;
|
|
123
|
+
const p4 = PURPLE.bright;
|
|
124
|
+
|
|
125
|
+
// Pixel art bitmap for "gbos.io" - 8 rows, each row is pairs of pixels
|
|
126
|
+
// 0 = transparent, 1-4 = purple shades
|
|
127
|
+
const bitmap = [
|
|
128
|
+
' 222 2222 222 2222 22 222 ',
|
|
129
|
+
' 2 2 2 2 2 2 2 2 2 2 2 ',
|
|
130
|
+
' 2 2 2 2 2 2 2 2 2 ',
|
|
131
|
+
' 2 222 2222 2 2 222 2 2 2 ',
|
|
132
|
+
' 2 2 2 2 2 2 2 2 2 2 ',
|
|
133
|
+
' 2 2 2 2 2 2 2 22 2 2 2 2 ',
|
|
134
|
+
' 222 2222 222 2222 22 22 222 ',
|
|
135
|
+
' ',
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
const lines = [];
|
|
139
|
+
const colorMap = {
|
|
140
|
+
' ': null,
|
|
141
|
+
'1': p1,
|
|
142
|
+
'2': p2,
|
|
143
|
+
'3': p3,
|
|
144
|
+
'4': p4,
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// Process 2 bitmap rows at a time into 1 output row (half-block technique)
|
|
148
|
+
for (let row = 0; row < bitmap.length; row += 2) {
|
|
149
|
+
let line = '';
|
|
150
|
+
const topRow = bitmap[row] || '';
|
|
151
|
+
const bottomRow = bitmap[row + 1] || '';
|
|
152
|
+
const width = Math.max(topRow.length, bottomRow.length);
|
|
153
|
+
|
|
154
|
+
for (let col = 0; col < width; col++) {
|
|
155
|
+
const topChar = topRow[col] || ' ';
|
|
156
|
+
const bottomChar = bottomRow[col] || ' ';
|
|
157
|
+
const topColor = colorMap[topChar];
|
|
158
|
+
const bottomColor = colorMap[bottomChar];
|
|
159
|
+
|
|
160
|
+
if (!topColor && !bottomColor) {
|
|
161
|
+
line += ' ';
|
|
162
|
+
} else if (!topColor && bottomColor) {
|
|
163
|
+
line += fg(bottomColor[0], bottomColor[1], bottomColor[2]) + LOWER_HALF + RESET;
|
|
164
|
+
} else if (topColor && !bottomColor) {
|
|
165
|
+
line += fg(topColor[0], topColor[1], topColor[2]) + UPPER_HALF + RESET;
|
|
166
|
+
} else {
|
|
167
|
+
line += fg(topColor[0], topColor[1], topColor[2]) + bg(bottomColor[0], bottomColor[1], bottomColor[2]) + UPPER_HALF + RESET;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
lines.push(line);
|
|
171
|
+
}
|
|
82
172
|
|
|
83
|
-
return lines
|
|
84
|
-
const colorIndex = Math.floor((i / lines.length) * purpleGradient.length);
|
|
85
|
-
const color = purpleGradient[Math.min(colorIndex, purpleGradient.length - 1)];
|
|
86
|
-
return color + line + colors.reset;
|
|
87
|
-
}).join('\n');
|
|
173
|
+
return lines;
|
|
88
174
|
}
|
|
89
175
|
|
|
90
|
-
//
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// Check if catimg is available
|
|
111
|
-
function hasCatimg() {
|
|
112
|
-
try {
|
|
113
|
-
execSync('which catimg', { stdio: 'ignore' });
|
|
114
|
-
return true;
|
|
115
|
-
} catch (e) {
|
|
116
|
-
return false;
|
|
176
|
+
// Fallback compact logo
|
|
177
|
+
const COMPACT_LOGO = [
|
|
178
|
+
`${fg(...PURPLE.medium)} ▄▀▀▀▄▄${RESET}`,
|
|
179
|
+
`${fg(...PURPLE.medium)}▄▀${fg(...PURPLE.bright)}●${fg(...PURPLE.medium)} ▀▄${RESET}`,
|
|
180
|
+
`${fg(...PURPLE.light)}█ █${RESET}`,
|
|
181
|
+
`${fg(...PURPLE.light)} ▀▄ ▄▀${RESET}`,
|
|
182
|
+
`${fg(...PURPLE.bright)} ▀▀▀▀${RESET}`,
|
|
183
|
+
];
|
|
184
|
+
|
|
185
|
+
// Combine logo and text side by side
|
|
186
|
+
function combineLogoAndText(logoLines, textLines) {
|
|
187
|
+
const combined = [];
|
|
188
|
+
const maxLines = Math.max(logoLines.length, textLines.length);
|
|
189
|
+
const logoStart = Math.floor((maxLines - logoLines.length) / 2);
|
|
190
|
+
const textStart = Math.floor((maxLines - textLines.length) / 2);
|
|
191
|
+
|
|
192
|
+
for (let i = 0; i < maxLines; i++) {
|
|
193
|
+
const logo = logoLines[i - logoStart] || '';
|
|
194
|
+
const text = textLines[i - textStart] || '';
|
|
195
|
+
combined.push(logo + ' ' + text);
|
|
117
196
|
}
|
|
197
|
+
|
|
198
|
+
return combined;
|
|
118
199
|
}
|
|
119
200
|
|
|
120
|
-
// Display logo
|
|
121
|
-
function
|
|
201
|
+
// Display logo with connection details
|
|
202
|
+
function displayLogoWithDetails(details = null) {
|
|
122
203
|
const logoPath = path.join(__dirname, '../../images/logo.png');
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
204
|
+
const termWidth = getTerminalWidth();
|
|
205
|
+
|
|
206
|
+
// Render logo at ~24 chars wide, 6 rows tall (12 pixel rows with half-blocks)
|
|
207
|
+
let logoLines = imageToPixels(logoPath, 24, 6);
|
|
208
|
+
if (!logoLines) logoLines = COMPACT_LOGO;
|
|
209
|
+
|
|
210
|
+
// Get pixel art text
|
|
211
|
+
const textLines = getGbosTextPixels();
|
|
212
|
+
|
|
213
|
+
// Combine logo and text
|
|
214
|
+
const leftSide = combineLogoAndText(logoLines, textLines);
|
|
215
|
+
const leftWidth = 70; // Account for escape codes
|
|
216
|
+
|
|
217
|
+
// Build right side (details box)
|
|
218
|
+
const rightWidth = Math.max(30, termWidth - 75);
|
|
219
|
+
const rightLines = [];
|
|
220
|
+
|
|
221
|
+
if (details) {
|
|
222
|
+
rightLines.push(`${colors.purple4}┌${'─'.repeat(rightWidth - 2)}┐${RESET}`);
|
|
223
|
+
rightLines.push(`${colors.purple4}│${RESET} ${BOLD}${colors.purple5}Connected${RESET}${' '.repeat(rightWidth - 12)}${colors.purple4}│${RESET}`);
|
|
224
|
+
rightLines.push(`${colors.purple4}├${'─'.repeat(rightWidth - 2)}┤${RESET}`);
|
|
225
|
+
|
|
226
|
+
const addField = (label, value, valueColor = colors.white) => {
|
|
227
|
+
const val = (value || 'N/A').toString().substring(0, rightWidth - label.length - 6);
|
|
228
|
+
const padding = ' '.repeat(Math.max(0, rightWidth - label.length - val.length - 5));
|
|
229
|
+
rightLines.push(`${colors.purple4}│${RESET} ${colors.purple7}${label}${RESET} ${valueColor}${val}${RESET}${padding}${colors.purple4}│${RESET}`);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
addField('Account:', details.accountName, colors.white);
|
|
233
|
+
addField('App:', details.applicationName, colors.purple5);
|
|
234
|
+
addField('Node:', details.nodeName, colors.purple4);
|
|
235
|
+
addField('ID:', details.nodeId, colors.dim);
|
|
236
|
+
if (details.connectionId) {
|
|
237
|
+
addField('Conn:', details.connectionId.substring(0, 18) + '...', colors.dim);
|
|
145
238
|
}
|
|
239
|
+
|
|
240
|
+
rightLines.push(`${colors.purple4}└${'─'.repeat(rightWidth - 2)}┘${RESET}`);
|
|
146
241
|
}
|
|
147
242
|
|
|
148
|
-
//
|
|
149
|
-
console.log(
|
|
243
|
+
// Print side by side
|
|
244
|
+
console.log('');
|
|
245
|
+
const maxLines = Math.max(leftSide.length, rightLines.length);
|
|
246
|
+
const leftStart = Math.floor((maxLines - leftSide.length) / 2);
|
|
247
|
+
const rightStart = Math.floor((maxLines - rightLines.length) / 2);
|
|
248
|
+
|
|
249
|
+
for (let i = 0; i < maxLines; i++) {
|
|
250
|
+
const left = leftSide[i - leftStart] || '';
|
|
251
|
+
const right = rightLines[i - rightStart] || '';
|
|
252
|
+
// Pad left side accounting for ANSI codes (rough estimate)
|
|
253
|
+
const visibleLen = left.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
254
|
+
const padding = ' '.repeat(Math.max(0, leftWidth - visibleLen));
|
|
255
|
+
console.log(` ${left}${padding}${right}`);
|
|
256
|
+
}
|
|
257
|
+
console.log('');
|
|
150
258
|
}
|
|
151
259
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const {
|
|
155
|
-
accountName,
|
|
156
|
-
applicationName,
|
|
157
|
-
nodeName,
|
|
158
|
-
nodeId,
|
|
159
|
-
connectionId,
|
|
160
|
-
userId,
|
|
161
|
-
accountId,
|
|
162
|
-
} = data;
|
|
163
|
-
|
|
164
|
-
const line = '─'.repeat(61);
|
|
165
|
-
const doubleLine = '═'.repeat(61);
|
|
166
|
-
|
|
167
|
-
console.log(`\n${colors.purple3}╔${doubleLine}╗${colors.reset}`);
|
|
168
|
-
console.log(`${colors.purple3}║${colors.reset}${colors.bold}${colors.purple5} GBOS Connected ${colors.reset}${colors.purple3}║${colors.reset}`);
|
|
169
|
-
console.log(`${colors.purple3}╠${doubleLine}╣${colors.reset}`);
|
|
170
|
-
|
|
171
|
-
// Account section
|
|
172
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
173
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}Account${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
174
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.bold}${colors.purple7}${(accountName || 'N/A').substring(0, 50).padEnd(55)}${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
175
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.dim}${colors.purple6}ID: ${accountId || 'N/A'}${colors.reset}${' '.repeat(Math.max(0, 53 - String(accountId || 'N/A').length))}${colors.purple3}║${colors.reset}`);
|
|
176
|
-
|
|
177
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
178
|
-
console.log(`${colors.purple4}╟${line}╢${colors.reset}`);
|
|
179
|
-
|
|
180
|
-
// Application section
|
|
181
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
182
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}Application${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
183
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.bold}${colors.purple5}${(applicationName || 'N/A').substring(0, 50).padEnd(55)}${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
184
|
-
|
|
185
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
186
|
-
console.log(`${colors.purple4}╟${line}╢${colors.reset}`);
|
|
187
|
-
|
|
188
|
-
// Node section
|
|
189
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
190
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}Development Node${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
191
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.bold}${colors.purple4}${(nodeName || 'N/A').substring(0, 50).padEnd(55)}${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
192
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.dim}${colors.purple6}Node ID: ${nodeId || 'N/A'}${colors.reset}${' '.repeat(Math.max(0, 48 - String(nodeId || 'N/A').length))}${colors.purple3}║${colors.reset}`);
|
|
193
|
-
|
|
194
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
195
|
-
console.log(`${colors.purple4}╟${line}╢${colors.reset}`);
|
|
196
|
-
|
|
197
|
-
// Connection section
|
|
198
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
199
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}Connection${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
200
|
-
const connIdDisplay = connectionId ? connectionId.substring(0, 36) : 'N/A';
|
|
201
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple5}${connIdDisplay.padEnd(55)}${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
202
|
-
|
|
203
|
-
console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
|
|
204
|
-
console.log(`${colors.purple3}╚${doubleLine}╝${colors.reset}`);
|
|
205
|
-
|
|
206
|
-
console.log(`\n${colors.purple5}✓${colors.reset} ${colors.bold}${colors.purple6}Ready to work!${colors.reset}`);
|
|
207
|
-
console.log(`${colors.dim}${colors.purple7} Session stored at ~/.gbos/session.json${colors.reset}\n`);
|
|
260
|
+
function displayLogo() {
|
|
261
|
+
displayLogoWithDetails(null);
|
|
208
262
|
}
|
|
209
263
|
|
|
210
|
-
// Display auth success screen - Purple theme
|
|
211
264
|
function displayAuthSuccess(data) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
265
|
+
const logoPath = path.join(__dirname, '../../images/logo.png');
|
|
266
|
+
const termWidth = getTerminalWidth();
|
|
267
|
+
|
|
268
|
+
let logoLines = imageToPixels(logoPath, 24, 6);
|
|
269
|
+
if (!logoLines) logoLines = COMPACT_LOGO;
|
|
270
|
+
|
|
271
|
+
const textLines = getGbosTextPixels();
|
|
272
|
+
const leftSide = combineLogoAndText(logoLines, textLines);
|
|
273
|
+
const leftWidth = 70;
|
|
274
|
+
|
|
275
|
+
const rightWidth = Math.max(30, termWidth - 75);
|
|
276
|
+
const rightLines = [];
|
|
277
|
+
|
|
278
|
+
rightLines.push(`${colors.purple4}┌${'─'.repeat(rightWidth - 2)}┐${RESET}`);
|
|
279
|
+
rightLines.push(`${colors.purple4}│${RESET} ${BOLD}${colors.purple5}✓ Authenticated${RESET}${' '.repeat(rightWidth - 18)}${colors.purple4}│${RESET}`);
|
|
280
|
+
rightLines.push(`${colors.purple4}├${'─'.repeat(rightWidth - 2)}┤${RESET}`);
|
|
281
|
+
|
|
282
|
+
const addField = (label, value) => {
|
|
283
|
+
const val = (value || 'N/A').toString().substring(0, rightWidth - label.length - 6);
|
|
284
|
+
const padding = ' '.repeat(Math.max(0, rightWidth - label.length - val.length - 5));
|
|
285
|
+
rightLines.push(`${colors.purple4}│${RESET} ${colors.purple7}${label}${RESET} ${colors.white}${val}${RESET}${padding}${colors.purple4}│${RESET}`);
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
addField('User:', data.userId);
|
|
289
|
+
addField('Account:', data.accountId);
|
|
290
|
+
addField('Session:', (data.sessionId || '').substring(0, 24) + '...');
|
|
291
|
+
|
|
292
|
+
rightLines.push(`${colors.purple4}└${'─'.repeat(rightWidth - 2)}┘${RESET}`);
|
|
293
|
+
rightLines.push('');
|
|
294
|
+
rightLines.push(`${colors.purple7}${DIM}Run "gbos connect" to connect${RESET}`);
|
|
295
|
+
|
|
296
|
+
console.log('');
|
|
297
|
+
const maxLines = Math.max(leftSide.length, rightLines.length);
|
|
298
|
+
const leftStart = Math.floor((maxLines - leftSide.length) / 2);
|
|
299
|
+
const rightStart = Math.floor((maxLines - rightLines.length) / 2);
|
|
300
|
+
|
|
301
|
+
for (let i = 0; i < maxLines; i++) {
|
|
302
|
+
const left = leftSide[i - leftStart] || '';
|
|
303
|
+
const right = rightLines[i - rightStart] || '';
|
|
304
|
+
const visibleLen = left.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
305
|
+
const padding = ' '.repeat(Math.max(0, leftWidth - visibleLen));
|
|
306
|
+
console.log(` ${left}${padding}${right}`);
|
|
307
|
+
}
|
|
308
|
+
console.log('');
|
|
229
309
|
}
|
|
230
310
|
|
|
231
|
-
// Display connect success screen
|
|
232
311
|
function displayConnectSuccess(data) {
|
|
233
|
-
|
|
234
|
-
|
|
312
|
+
displayLogoWithDetails(data);
|
|
313
|
+
console.log(` ${colors.purple5}✓${RESET} ${BOLD}${colors.purple6}Ready to work!${RESET}`);
|
|
314
|
+
console.log(` ${DIM}${colors.purple7}Session: ~/.gbos/session.json${RESET}\n`);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function displaySessionSummary(data) {
|
|
318
|
+
displayLogoWithDetails(data);
|
|
235
319
|
}
|
|
236
320
|
|
|
237
|
-
// Display simple message box - Purple theme
|
|
238
321
|
function displayMessageBox(title, message, type = 'info') {
|
|
239
|
-
const colorMap = {
|
|
240
|
-
info: colors.purple4,
|
|
241
|
-
success: colors.purple5,
|
|
242
|
-
warning: colors.yellow,
|
|
243
|
-
error: '\x1b[31m',
|
|
244
|
-
};
|
|
322
|
+
const colorMap = { info: colors.purple4, success: colors.purple5, warning: `${ESC}[33m`, error: `${ESC}[31m` };
|
|
245
323
|
const color = colorMap[type] || colors.purple4;
|
|
246
324
|
const icon = type === 'success' ? '✓' : type === 'warning' ? '⚠' : type === 'error' ? '✗' : 'ℹ';
|
|
325
|
+
const width = Math.min(55, getTerminalWidth() - 4);
|
|
247
326
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
console.log(
|
|
251
|
-
console.log(`${color}│${colors.reset} ${icon} ${colors.bold}${colors.purple6}${title.padEnd(56)}${colors.reset}${color}│${colors.reset}`);
|
|
252
|
-
console.log(`${color}├${line}┤${colors.reset}`);
|
|
327
|
+
console.log(`\n${color}┌${'─'.repeat(width)}┐${RESET}`);
|
|
328
|
+
console.log(`${color}│${RESET} ${icon} ${BOLD}${colors.purple6}${title.substring(0, width - 5).padEnd(width - 4)}${RESET}${color}│${RESET}`);
|
|
329
|
+
console.log(`${color}├${'─'.repeat(width)}┤${RESET}`);
|
|
253
330
|
|
|
254
|
-
// Word wrap message
|
|
255
331
|
const words = message.split(' ');
|
|
256
332
|
let currentLine = '';
|
|
257
|
-
|
|
258
333
|
for (const word of words) {
|
|
259
|
-
if ((currentLine + ' ' + word).trim().length >
|
|
260
|
-
console.log(`${color}│${
|
|
334
|
+
if ((currentLine + ' ' + word).trim().length > width - 4) {
|
|
335
|
+
console.log(`${color}│${RESET} ${colors.purple7}${currentLine.trim().padEnd(width - 2)}${RESET}${color}│${RESET}`);
|
|
261
336
|
currentLine = word;
|
|
262
337
|
} else {
|
|
263
338
|
currentLine = currentLine ? currentLine + ' ' + word : word;
|
|
264
339
|
}
|
|
265
340
|
}
|
|
266
|
-
|
|
267
341
|
if (currentLine) {
|
|
268
|
-
console.log(`${color}│${
|
|
342
|
+
console.log(`${color}│${RESET} ${colors.purple7}${currentLine.trim().padEnd(width - 2)}${RESET}${color}│${RESET}`);
|
|
269
343
|
}
|
|
270
|
-
|
|
271
|
-
console.log(`${color}└${line}┘${colors.reset}\n`);
|
|
344
|
+
console.log(`${color}└${'─'.repeat(width)}┘${RESET}\n`);
|
|
272
345
|
}
|
|
273
346
|
|
|
274
347
|
module.exports = {
|
|
275
348
|
colors,
|
|
276
349
|
displayLogo,
|
|
350
|
+
displayLogoWithDetails,
|
|
277
351
|
displaySessionSummary,
|
|
278
352
|
displayAuthSuccess,
|
|
279
353
|
displayConnectSuccess,
|
|
280
354
|
displayMessageBox,
|
|
281
|
-
|
|
282
|
-
|
|
355
|
+
imageToPixels,
|
|
356
|
+
getTerminalWidth,
|
|
283
357
|
};
|