gbos 1.1.2 → 1.1.4

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.
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gbos",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "description": "GBOS - Command line interface for GBOS services",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -38,6 +38,7 @@
38
38
  "images/**/*"
39
39
  ],
40
40
  "dependencies": {
41
- "commander": "^12.1.0"
41
+ "commander": "^12.1.0",
42
+ "pngjs": "^7.0.0"
42
43
  }
43
44
  }
@@ -1,223 +1,254 @@
1
- const { execSync, spawnSync } = require('child_process');
2
1
  const path = require('path');
3
2
  const fs = require('fs');
3
+ const { PNG } = require('pngjs');
4
4
 
5
5
  // ANSI color codes - Dark Purple Theme
6
6
  const colors = {
7
7
  reset: '\x1b[0m',
8
8
  bold: '\x1b[1m',
9
9
  dim: '\x1b[2m',
10
- // Dark purple shades (256 color mode)
11
- purple1: '\x1b[38;5;54m', // Darkest purple
12
- purple2: '\x1b[38;5;55m', // Dark purple
13
- purple3: '\x1b[38;5;56m', // Medium dark purple
14
- purple4: '\x1b[38;5;93m', // Medium purple
15
- purple5: '\x1b[38;5;99m', // Light purple
16
- purple6: '\x1b[38;5;141m', // Lighter purple
17
- purple7: '\x1b[38;5;183m', // Lightest purple
18
- // Fallback standard colors
19
- magenta: '\x1b[35m',
10
+ purple1: '\x1b[38;5;54m',
11
+ purple2: '\x1b[38;5;55m',
12
+ purple3: '\x1b[38;5;56m',
13
+ purple4: '\x1b[38;5;93m',
14
+ purple5: '\x1b[38;5;99m',
15
+ purple6: '\x1b[38;5;141m',
16
+ purple7: '\x1b[38;5;183m',
20
17
  white: '\x1b[37m',
21
18
  gray: '\x1b[90m',
22
19
  green: '\x1b[32m',
23
20
  yellow: '\x1b[33m',
21
+ red: '\x1b[31m',
24
22
  };
25
23
 
26
- // ASCII art horse head + GBOS logo combined
27
- const ASCII_LOGO = `
28
- ${colors.purple2}${colors.bold} ╱▔╲
29
- ${colors.purple3} ╱▔ ╲▁▁
30
- ${colors.purple3} ▕ ╲╲ ${colors.purple4}██████╗ ██████╗ ██████╗ ███████╗
31
- ${colors.purple4} ▕ ● ╲╲ ${colors.purple4}██╔════╝ ██╔══██╗██╔═══██╗██╔════╝
32
- ${colors.purple4} ╲ ╱╱ ${colors.purple5}██║ ███╗██████╔╝██║ ██║███████╗
33
- ${colors.purple5} ╲╲ ╱╱ ${colors.purple5}██║ ██║██╔══██╗██║ ██║╚════██║
34
- ${colors.purple5} ▁▁▁▁╱ ╲▁▁╱ ${colors.purple6}╚██████╔╝██████╔╝╚██████╔╝███████║
35
- ${colors.purple6} ╱ ${colors.purple6} ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
36
- ${colors.purple6} ╱ ╲
37
- ${colors.purple7} ▕ ▏
38
- ${colors.reset}`;
39
-
40
- // Simpler horse ASCII for smaller displays
41
- const ASCII_LOGO_SIMPLE = `
42
- ${colors.purple3}${colors.bold} ▄▀▀▀▄▄
43
- ${colors.purple3} ▄▀ ▀▄ ${colors.purple4}██████╗ ██████╗ ██████╗ ███████╗
44
- ${colors.purple4} █ ● █ ${colors.purple4}██╔════╝ ██╔══██╗██╔═══██╗██╔════╝
45
- ${colors.purple4} █ █ ${colors.purple5}██║ ███╗██████╔╝██║ ██║███████╗
46
- ${colors.purple5} ▀▄ ▄▀ ${colors.purple5}██║ ██║██╔══██╗██║ ██║╚════██║
47
- ${colors.purple5} ▄▀ ▀▀▀▀▀ ${colors.purple6}╚██████╔╝██████╔╝╚██████╔╝███████║
48
- ${colors.purple6} █ █ ${colors.purple6} ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝
49
- ${colors.purple6} █ █
50
- ${colors.reset}`;
51
-
52
- // Check if catimg is available
53
- function hasCatimg() {
24
+ // ASCII characters for density mapping
25
+ const ASCII_CHARS = ' .,:;i1tfLCG08@#';
26
+
27
+ // Get terminal width
28
+ function getTerminalWidth() {
29
+ return process.stdout.columns || 80;
30
+ }
31
+
32
+ // Convert PNG to ASCII art
33
+ function imageToAscii(imagePath, width = 20) {
54
34
  try {
55
- execSync('which catimg', { stdio: 'ignore' });
56
- return true;
35
+ const data = fs.readFileSync(imagePath);
36
+ const png = PNG.sync.read(data);
37
+
38
+ const aspectRatio = 0.5;
39
+ const height = Math.floor((png.height / png.width) * width * aspectRatio);
40
+
41
+ const cellWidth = png.width / width;
42
+ const cellHeight = png.height / height;
43
+
44
+ const lines = [];
45
+
46
+ for (let y = 0; y < height; y++) {
47
+ let row = '';
48
+ for (let x = 0; x < width; x++) {
49
+ const sampleX = Math.floor(x * cellWidth + cellWidth / 2);
50
+ const sampleY = Math.floor(y * cellHeight + cellHeight / 2);
51
+ const idx = (png.width * sampleY + sampleX) << 2;
52
+
53
+ const r = png.data[idx];
54
+ const g = png.data[idx + 1];
55
+ const b = png.data[idx + 2];
56
+ const a = png.data[idx + 3];
57
+
58
+ if (a < 50 || (r > 240 && g > 240 && b > 240)) {
59
+ row += ' ';
60
+ continue;
61
+ }
62
+
63
+ const brightness = (r + g + b) / 3;
64
+ const charIndex = Math.floor((1 - brightness / 255) * (ASCII_CHARS.length - 1));
65
+ row += ASCII_CHARS[Math.max(0, Math.min(charIndex, ASCII_CHARS.length - 1))];
66
+ }
67
+ lines.push(row);
68
+ }
69
+
70
+ return lines;
57
71
  } catch (e) {
58
- return false;
72
+ return null;
59
73
  }
60
74
  }
61
75
 
62
- // Display logo using catimg or ASCII fallback
63
- function displayLogo() {
64
- const logoPath = path.join(__dirname, '../../images/logo.png');
65
-
66
- if (hasCatimg() && fs.existsSync(logoPath)) {
67
- try {
68
- // Use catimg with width constraint for terminal
69
- const result = spawnSync('catimg', ['-w', '40', logoPath], {
70
- encoding: 'utf8',
71
- stdio: ['ignore', 'pipe', 'ignore'],
72
- });
73
- if (result.stdout) {
74
- console.log(result.stdout);
75
- // Print GBOS text next to it
76
- console.log(`${colors.purple4}${colors.bold} ██████╗ ██████╗ ██████╗ ███████╗`);
77
- console.log(`${colors.purple4} ██╔════╝ ██╔══██╗██╔═══██╗██╔════╝`);
78
- console.log(`${colors.purple5} ██║ ███╗██████╔╝██║ ██║███████╗`);
79
- console.log(`${colors.purple5} ██║ ██║██╔══██╗██║ ██║╚════██║`);
80
- console.log(`${colors.purple6} ╚██████╔╝██████╔╝╚██████╔╝███████║`);
81
- console.log(`${colors.purple6} ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝${colors.reset}`);
82
- return;
76
+ // Compact text-based logo with horse
77
+ const COMPACT_LOGO = [
78
+ `${colors.purple3} ▄▀▀▀▄▄`,
79
+ `${colors.purple3} ▄▀${colors.purple4}●${colors.purple3} ▀▄`,
80
+ `${colors.purple4} █ █ ${colors.purple5}${colors.bold}gbos.io${colors.reset}`,
81
+ `${colors.purple4} ▀▄ ▄▀`,
82
+ `${colors.purple5} ▀▀▀▀`,
83
+ ];
84
+
85
+ // Display logo with connection details
86
+ function displayLogoWithDetails(details = null) {
87
+ const logoPath = path.join(__dirname, '../../images/logo.png'); // Use horse-only logo
88
+ const termWidth = getTerminalWidth();
89
+ const logoWidth = 20;
90
+ const rightWidth = termWidth - logoWidth - 8;
91
+
92
+ let asciiLines = imageToAscii(logoPath, logoWidth);
93
+
94
+ // Color all ASCII lines purple and add "gbos.io" text
95
+ if (asciiLines && asciiLines.length > 0) {
96
+ asciiLines = asciiLines.map((line, idx) => {
97
+ const coloredLine = colors.purple3 + line + colors.reset;
98
+ const midPoint = Math.floor(asciiLines.length / 2);
99
+ if (idx === midPoint) {
100
+ return coloredLine + ` ${colors.purple5}${colors.bold}gbos.io${colors.reset}`;
83
101
  }
84
- } catch (e) {
85
- // Fall through to ASCII
102
+ return coloredLine;
103
+ });
104
+ }
105
+
106
+ if (!asciiLines) {
107
+ asciiLines = COMPACT_LOGO;
108
+ }
109
+
110
+ // Build right side (details box)
111
+ const rightLines = [];
112
+
113
+ if (details) {
114
+ rightLines.push(`${colors.purple4}┌${'─'.repeat(rightWidth - 2)}┐${colors.reset}`);
115
+ rightLines.push(`${colors.purple4}│${colors.reset} ${colors.bold}${colors.purple5}Connected${colors.reset}${' '.repeat(rightWidth - 12)}${colors.purple4}│${colors.reset}`);
116
+ rightLines.push(`${colors.purple4}├${'─'.repeat(rightWidth - 2)}┤${colors.reset}`);
117
+
118
+ const addField = (label, value, valueColor = colors.white) => {
119
+ const val = (value || 'N/A').toString().substring(0, rightWidth - label.length - 6);
120
+ const padding = ' '.repeat(Math.max(0, rightWidth - label.length - val.length - 5));
121
+ rightLines.push(`${colors.purple4}│${colors.reset} ${colors.purple7}${label}${colors.reset} ${valueColor}${val}${colors.reset}${padding}${colors.purple4}│${colors.reset}`);
122
+ };
123
+
124
+ addField('Account:', details.accountName, colors.white);
125
+ addField('App:', details.applicationName, colors.purple5);
126
+ addField('Node:', details.nodeName, colors.purple4);
127
+ addField('ID:', details.nodeId, colors.dim);
128
+ if (details.connectionId) {
129
+ addField('Conn:', details.connectionId.substring(0, 18) + '...', colors.dim);
86
130
  }
131
+
132
+ rightLines.push(`${colors.purple4}└${'─'.repeat(rightWidth - 2)}┘${colors.reset}`);
87
133
  }
88
134
 
89
- // ASCII fallback with horse icon
90
- console.log(ASCII_LOGO_SIMPLE);
135
+ // Print side by side
136
+ console.log('');
137
+ const maxLines = Math.max(asciiLines.length, rightLines.length);
138
+ const logoStart = Math.floor((maxLines - asciiLines.length) / 2);
139
+ const detailStart = Math.floor((maxLines - rightLines.length) / 2);
140
+
141
+ for (let i = 0; i < maxLines; i++) {
142
+ const left = asciiLines[i - logoStart] || '';
143
+ const right = rightLines[i - detailStart] || '';
144
+ const paddedLeft = left.padEnd(logoWidth + 30); // Account for color codes
145
+ console.log(` ${paddedLeft} ${right}`);
146
+ }
147
+ console.log('');
91
148
  }
92
149
 
93
- // Display styled session summary (Gemini design + Claude Code layout) - Purple theme
94
- function displaySessionSummary(data) {
95
- const {
96
- accountName,
97
- applicationName,
98
- nodeName,
99
- nodeId,
100
- connectionId,
101
- userId,
102
- accountId,
103
- } = data;
104
-
105
- const line = '─'.repeat(61);
106
- const doubleLine = '═'.repeat(61);
107
-
108
- console.log(`\n${colors.purple3}╔${doubleLine}╗${colors.reset}`);
109
- console.log(`${colors.purple3}║${colors.reset}${colors.bold}${colors.purple5} GBOS Connected ${colors.reset}${colors.purple3}║${colors.reset}`);
110
- console.log(`${colors.purple3}╠${doubleLine}╣${colors.reset}`);
111
-
112
- // Account section
113
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
114
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}Account${colors.reset} ${colors.purple3}║${colors.reset}`);
115
- console.log(`${colors.purple3}║${colors.reset} ${colors.bold}${colors.purple7}${(accountName || 'N/A').substring(0, 50).padEnd(55)}${colors.reset} ${colors.purple3}║${colors.reset}`);
116
- 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}`);
117
-
118
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
119
- console.log(`${colors.purple4}╟${line}╢${colors.reset}`);
120
-
121
- // Application section
122
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
123
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}Application${colors.reset} ${colors.purple3}║${colors.reset}`);
124
- console.log(`${colors.purple3}║${colors.reset} ${colors.bold}${colors.purple5}${(applicationName || 'N/A').substring(0, 50).padEnd(55)}${colors.reset} ${colors.purple3}║${colors.reset}`);
125
-
126
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
127
- console.log(`${colors.purple4}╟${line}╢${colors.reset}`);
128
-
129
- // Node section
130
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
131
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}Development Node${colors.reset} ${colors.purple3}║${colors.reset}`);
132
- console.log(`${colors.purple3}║${colors.reset} ${colors.bold}${colors.purple4}${(nodeName || 'N/A').substring(0, 50).padEnd(55)}${colors.reset} ${colors.purple3}║${colors.reset}`);
133
- 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}`);
134
-
135
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
136
- console.log(`${colors.purple4}╟${line}╢${colors.reset}`);
137
-
138
- // Connection section
139
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
140
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}Connection${colors.reset} ${colors.purple3}║${colors.reset}`);
141
- const connIdDisplay = connectionId ? connectionId.substring(0, 36) : 'N/A';
142
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple5}${connIdDisplay.padEnd(55)}${colors.reset} ${colors.purple3}║${colors.reset}`);
143
-
144
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
145
- console.log(`${colors.purple3}╚${doubleLine}╝${colors.reset}`);
146
-
147
- console.log(`\n${colors.purple5}✓${colors.reset} ${colors.bold}${colors.purple6}Ready to work!${colors.reset}`);
148
- console.log(`${colors.dim}${colors.purple7} Session stored at ~/.gbos/session.json${colors.reset}\n`);
150
+ function displayLogo() {
151
+ displayLogoWithDetails(null);
149
152
  }
150
153
 
151
- // Display auth success screen - Purple theme
152
154
  function displayAuthSuccess(data) {
153
- displayLogo();
154
-
155
- const line = '─'.repeat(61);
156
- const doubleLine = '═'.repeat(61);
157
-
158
- console.log(`${colors.purple3}╔${doubleLine}╗${colors.reset}`);
159
- console.log(`${colors.purple3}║${colors.reset}${colors.bold}${colors.purple5} Authentication Successful ${colors.reset}${colors.purple3}║${colors.reset}`);
160
- console.log(`${colors.purple3}╠${doubleLine}╣${colors.reset}`);
161
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
162
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}User ID${colors.reset} ${colors.purple7}${String(data.userId || 'N/A').padEnd(42)}${colors.reset}${colors.purple3}║${colors.reset}`);
163
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}Account ID${colors.reset} ${colors.purple7}${String(data.accountId || 'N/A').padEnd(42)}${colors.reset}${colors.purple3}║${colors.reset}`);
164
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple6}Session${colors.reset} ${colors.dim}${colors.purple5}${(data.sessionId || 'N/A').substring(0, 36).padEnd(42)}${colors.reset}${colors.purple3}║${colors.reset}`);
165
- console.log(`${colors.purple3}║${colors.reset} ${colors.purple3}║${colors.reset}`);
166
- console.log(`${colors.purple3}╚${doubleLine}╝${colors.reset}`);
167
-
168
- console.log(`\n${colors.purple5}✓${colors.reset} ${colors.bold}${colors.purple6}Authenticated!${colors.reset}`);
169
- console.log(`${colors.dim}${colors.purple7} Run "gbos connect" to connect to a development node.${colors.reset}\n`);
155
+ const termWidth = getTerminalWidth();
156
+ const logoWidth = 20;
157
+ const rightWidth = termWidth - logoWidth - 8;
158
+
159
+ const logoPath = path.join(__dirname, '../../images/logo.png');
160
+ let asciiLines = imageToAscii(logoPath, logoWidth);
161
+
162
+ // Color all ASCII lines purple and add "gbos.io" text
163
+ if (asciiLines && asciiLines.length > 0) {
164
+ const midPoint = Math.floor(asciiLines.length / 2);
165
+ asciiLines = asciiLines.map((line, idx) => {
166
+ const coloredLine = colors.purple3 + line + colors.reset;
167
+ if (idx === midPoint) {
168
+ return coloredLine + ` ${colors.purple5}${colors.bold}gbos.io${colors.reset}`;
169
+ }
170
+ return coloredLine;
171
+ });
172
+ }
173
+
174
+ if (!asciiLines) asciiLines = COMPACT_LOGO;
175
+
176
+ const rightLines = [];
177
+ rightLines.push(`${colors.purple4}┌${'─'.repeat(rightWidth - 2)}┐${colors.reset}`);
178
+ rightLines.push(`${colors.purple4}│${colors.reset} ${colors.bold}${colors.purple5}✓ Authenticated${colors.reset}${' '.repeat(rightWidth - 18)}${colors.purple4}│${colors.reset}`);
179
+ rightLines.push(`${colors.purple4}├${'─'.repeat(rightWidth - 2)}┤${colors.reset}`);
180
+
181
+ const addField = (label, value) => {
182
+ const val = (value || 'N/A').toString().substring(0, rightWidth - label.length - 6);
183
+ const padding = ' '.repeat(Math.max(0, rightWidth - label.length - val.length - 5));
184
+ rightLines.push(`${colors.purple4}│${colors.reset} ${colors.purple7}${label}${colors.reset} ${colors.white}${val}${colors.reset}${padding}${colors.purple4}│${colors.reset}`);
185
+ };
186
+
187
+ addField('User:', data.userId);
188
+ addField('Account:', data.accountId);
189
+ addField('Session:', (data.sessionId || '').substring(0, 24) + '...');
190
+
191
+ rightLines.push(`${colors.purple4}└${'─'.repeat(rightWidth - 2)}┘${colors.reset}`);
192
+ rightLines.push('');
193
+ rightLines.push(`${colors.purple7}${colors.dim}Run "gbos connect" to connect${colors.reset}`);
194
+
195
+ console.log('');
196
+ const maxLines = Math.max(asciiLines.length, rightLines.length);
197
+ const logoStart = Math.floor((maxLines - asciiLines.length) / 2);
198
+ const detailStart = Math.floor((maxLines - rightLines.length) / 2);
199
+
200
+ for (let i = 0; i < maxLines; i++) {
201
+ const left = asciiLines[i - logoStart] || '';
202
+ const right = rightLines[i - detailStart] || '';
203
+ console.log(` ${left.padEnd(logoWidth + 30)} ${right}`);
204
+ }
205
+ console.log('');
170
206
  }
171
207
 
172
- // Display connect success screen
173
208
  function displayConnectSuccess(data) {
174
- displayLogo();
175
- displaySessionSummary(data);
209
+ displayLogoWithDetails(data);
210
+ console.log(` ${colors.purple5}✓${colors.reset} ${colors.bold}${colors.purple6}Ready to work!${colors.reset}`);
211
+ console.log(` ${colors.dim}${colors.purple7}Session: ~/.gbos/session.json${colors.reset}\n`);
212
+ }
213
+
214
+ function displaySessionSummary(data) {
215
+ displayLogoWithDetails(data);
176
216
  }
177
217
 
178
- // Display simple message box - Purple theme
179
218
  function displayMessageBox(title, message, type = 'info') {
180
- const colorMap = {
181
- info: colors.purple4,
182
- success: colors.purple5,
183
- warning: colors.yellow,
184
- error: '\x1b[31m',
185
- };
219
+ const colorMap = { info: colors.purple4, success: colors.purple5, warning: colors.yellow, error: colors.red };
186
220
  const color = colorMap[type] || colors.purple4;
187
221
  const icon = type === 'success' ? '✓' : type === 'warning' ? '⚠' : type === 'error' ? '✗' : 'ℹ';
222
+ const width = Math.min(55, getTerminalWidth() - 4);
188
223
 
189
- const line = '─'.repeat(61);
190
-
191
- console.log(`\n${color}┌${line}┐${colors.reset}`);
192
- console.log(`${color}│${colors.reset} ${icon} ${colors.bold}${colors.purple6}${title.padEnd(56)}${colors.reset}${color}│${colors.reset}`);
193
- console.log(`${color}├${line}┤${colors.reset}`);
224
+ console.log(`\n${color}┌${'─'.repeat(width)}┐${colors.reset}`);
225
+ console.log(`${color}│${colors.reset} ${icon} ${colors.bold}${colors.purple6}${title.substring(0, width - 5).padEnd(width - 4)}${colors.reset}${color}│${colors.reset}`);
226
+ console.log(`${color}├${'─'.repeat(width)}┤${colors.reset}`);
194
227
 
195
- // Word wrap message
196
228
  const words = message.split(' ');
197
229
  let currentLine = '';
198
-
199
230
  for (const word of words) {
200
- if ((currentLine + ' ' + word).trim().length > 57) {
201
- console.log(`${color}│${colors.reset} ${colors.purple7}${currentLine.trim().padEnd(57)}${colors.reset}${color}│${colors.reset}`);
231
+ if ((currentLine + ' ' + word).trim().length > width - 4) {
232
+ console.log(`${color}│${colors.reset} ${colors.purple7}${currentLine.trim().padEnd(width - 2)}${colors.reset}${color}│${colors.reset}`);
202
233
  currentLine = word;
203
234
  } else {
204
235
  currentLine = currentLine ? currentLine + ' ' + word : word;
205
236
  }
206
237
  }
207
-
208
238
  if (currentLine) {
209
- console.log(`${color}│${colors.reset} ${colors.purple7}${currentLine.trim().padEnd(57)}${colors.reset}${color}│${colors.reset}`);
239
+ console.log(`${color}│${colors.reset} ${colors.purple7}${currentLine.trim().padEnd(width - 2)}${colors.reset}${color}│${colors.reset}`);
210
240
  }
211
-
212
- console.log(`${color}└${line}┘${colors.reset}\n`);
241
+ console.log(`${color}└${'─'.repeat(width)}┘${colors.reset}\n`);
213
242
  }
214
243
 
215
244
  module.exports = {
216
245
  colors,
217
246
  displayLogo,
247
+ displayLogoWithDetails,
218
248
  displaySessionSummary,
219
249
  displayAuthSuccess,
220
250
  displayConnectSuccess,
221
251
  displayMessageBox,
222
- hasCatimg,
252
+ imageToAscii,
253
+ getTerminalWidth,
223
254
  };