vibecodingmachine-cli 1.0.3 → 1.0.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/.allnightai/REQUIREMENTS.md +11 -11
- package/.eslintrc.js +16 -16
- package/README.md +85 -85
- package/bin/vibecodingmachine.js +274 -274
- package/jest.config.js +8 -8
- package/logs/audit/2025-11-07.jsonl +2 -2
- package/package.json +62 -66
- package/scripts/README.md +128 -128
- package/scripts/auto-start-wrapper.sh +92 -92
- package/scripts/postinstall.js +81 -81
- package/src/commands/auth.js +96 -96
- package/src/commands/auto-direct.js +1748 -1748
- package/src/commands/auto.js +4692 -4692
- package/src/commands/auto.js.bak +710 -710
- package/src/commands/ide.js +70 -70
- package/src/commands/repo.js +159 -159
- package/src/commands/requirements.js +161 -161
- package/src/commands/setup.js +91 -91
- package/src/commands/status.js +88 -88
- package/src/index.js +5 -5
- package/src/utils/auth.js +577 -577
- package/src/utils/auto-mode-ansi-ui.js +238 -238
- package/src/utils/auto-mode-simple-ui.js +161 -161
- package/src/utils/auto-mode-ui.js.bak.blessed +207 -207
- package/src/utils/auto-mode.js +65 -65
- package/src/utils/config.js +64 -64
- package/src/utils/interactive.js +3616 -3616
- package/src/utils/keyboard-handler.js +152 -152
- package/src/utils/logger.js +4 -4
- package/src/utils/persistent-header.js +116 -116
- package/src/utils/provider-registry.js +128 -128
- package/src/utils/status-card.js +120 -120
- package/src/utils/stdout-interceptor.js +127 -127
- package/tests/auto-mode.test.js +37 -37
- package/tests/config.test.js +34 -34
- package/.allnightai/temp/auto-status.json +0 -6
- package/.env +0 -7
|
@@ -1,238 +1,238 @@
|
|
|
1
|
-
const chalk = require('chalk');
|
|
2
|
-
const ansiEscapes = require('ansi-escapes');
|
|
3
|
-
const stripAnsi = require('strip-ansi');
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* ANSI-based UI for Auto Mode
|
|
7
|
-
* Simple, reliable, no module system issues
|
|
8
|
-
*/
|
|
9
|
-
class AutoModeANSIUI {
|
|
10
|
-
constructor(options = {}) {
|
|
11
|
-
this.menuContent = options.menuContent || '';
|
|
12
|
-
this.onExit = options.onExit;
|
|
13
|
-
this.requirement = 'Loading...';
|
|
14
|
-
this.step = 'PREPARE';
|
|
15
|
-
this.chatCount = 0;
|
|
16
|
-
this.maxChats = null;
|
|
17
|
-
this.progress = 0;
|
|
18
|
-
this.outputLines = [];
|
|
19
|
-
this.maxOutputLines = 15;
|
|
20
|
-
|
|
21
|
-
// Hide cursor for cleaner output
|
|
22
|
-
process.stdout.write(ansiEscapes.cursorHide);
|
|
23
|
-
|
|
24
|
-
// Handle exit - just use SIGINT, don't try to capture keys
|
|
25
|
-
// (stdin might be used by child process like Aider)
|
|
26
|
-
this.handleExit = () => {
|
|
27
|
-
this.destroy();
|
|
28
|
-
if (this.onExit) {
|
|
29
|
-
this.onExit();
|
|
30
|
-
}
|
|
31
|
-
process.exit(0);
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
process.on('SIGINT', this.handleExit);
|
|
35
|
-
process.on('SIGTERM', this.handleExit);
|
|
36
|
-
|
|
37
|
-
// Initial render
|
|
38
|
-
this.render();
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
updateStatus(status) {
|
|
42
|
-
if (status.requirement !== undefined) this.requirement = status.requirement;
|
|
43
|
-
if (status.step !== undefined) this.step = status.step;
|
|
44
|
-
if (status.chatCount !== undefined) this.chatCount = status.chatCount;
|
|
45
|
-
if (status.maxChats !== undefined) this.maxChats = status.maxChats;
|
|
46
|
-
if (status.progress !== undefined) this.progress = status.progress;
|
|
47
|
-
this.render();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
appendOutput(line) {
|
|
51
|
-
// Safety: truncate very long lines to prevent memory issues
|
|
52
|
-
const maxLineLength = 500;
|
|
53
|
-
const safeLine = line.length > maxLineLength ? line.substring(0, maxLineLength) + '...' : line;
|
|
54
|
-
|
|
55
|
-
this.outputLines.push(safeLine);
|
|
56
|
-
// Keep only last N lines
|
|
57
|
-
if (this.outputLines.length > this.maxOutputLines) {
|
|
58
|
-
this.outputLines = this.outputLines.slice(-this.maxOutputLines);
|
|
59
|
-
}
|
|
60
|
-
this.render();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
clearOutput() {
|
|
64
|
-
this.outputLines = [];
|
|
65
|
-
this.render();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
render() {
|
|
69
|
-
// Clear screen and move cursor to top
|
|
70
|
-
process.stdout.write(ansiEscapes.clearScreen);
|
|
71
|
-
process.stdout.write(ansiEscapes.cursorTo(0, 0));
|
|
72
|
-
|
|
73
|
-
let output = '';
|
|
74
|
-
|
|
75
|
-
// Header box
|
|
76
|
-
output += this.drawBox(this.menuContent, { color: 'cyan', style: 'round' });
|
|
77
|
-
output += '\n';
|
|
78
|
-
|
|
79
|
-
// Status card
|
|
80
|
-
const statusContent = this.buildStatusContent();
|
|
81
|
-
output += this.drawBox(statusContent, { color: 'magenta', style: 'round', title: ' Auto Mode Status ' });
|
|
82
|
-
output += '\n';
|
|
83
|
-
|
|
84
|
-
// Output log
|
|
85
|
-
const outputContent = this.buildOutputContent();
|
|
86
|
-
output += this.drawBox(outputContent, { color: 'green', style: 'single', title: ' Aider Output ' });
|
|
87
|
-
|
|
88
|
-
process.stdout.write(output);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
buildStatusContent() {
|
|
92
|
-
const stepColors = {
|
|
93
|
-
'PREPARE': chalk.cyan,
|
|
94
|
-
'ACT': chalk.yellow,
|
|
95
|
-
'CLEAN UP': chalk.magenta,
|
|
96
|
-
'VERIFY': chalk.blue,
|
|
97
|
-
'DONE': chalk.green,
|
|
98
|
-
'UNKNOWN': chalk.gray
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const stepColor = stepColors[this.step] || chalk.gray;
|
|
102
|
-
|
|
103
|
-
// Progress bar
|
|
104
|
-
const barWidth = 40;
|
|
105
|
-
const filledWidth = Math.round((this.progress / 100) * barWidth);
|
|
106
|
-
const emptyWidth = barWidth - filledWidth;
|
|
107
|
-
const progressBar = chalk.green('█'.repeat(filledWidth)) + chalk.gray('░'.repeat(emptyWidth));
|
|
108
|
-
|
|
109
|
-
// Chat counter
|
|
110
|
-
const chatDisplay = this.maxChats
|
|
111
|
-
? `Chat ${this.chatCount}/${this.maxChats}`
|
|
112
|
-
: `Chat ${this.chatCount} (unlimited)`;
|
|
113
|
-
|
|
114
|
-
// Truncate requirement if too long
|
|
115
|
-
const displayReq = this.requirement.length > 70
|
|
116
|
-
? this.requirement.substring(0, 67) + '...'
|
|
117
|
-
: this.requirement;
|
|
118
|
-
|
|
119
|
-
return `
|
|
120
|
-
${chalk.bold('📋 Current Requirement')}
|
|
121
|
-
|
|
122
|
-
${displayReq}
|
|
123
|
-
|
|
124
|
-
${chalk.bold('🚦 Status:')} ${stepColor.bold(this.step)}
|
|
125
|
-
|
|
126
|
-
${progressBar} ${this.progress}%
|
|
127
|
-
|
|
128
|
-
${chalk.gray(chatDisplay)}
|
|
129
|
-
`.trim();
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
buildOutputContent() {
|
|
133
|
-
if (this.outputLines.length === 0) {
|
|
134
|
-
return chalk.gray('No output yet...');
|
|
135
|
-
}
|
|
136
|
-
return this.outputLines.join('\n');
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
drawBox(content, options = {}) {
|
|
140
|
-
const { color = 'white', style = 'single', title = '' } = options;
|
|
141
|
-
const colorFn = chalk[color] || chalk.white;
|
|
142
|
-
|
|
143
|
-
// Box drawing characters
|
|
144
|
-
const chars = {
|
|
145
|
-
single: {
|
|
146
|
-
topLeft: '┌',
|
|
147
|
-
topRight: '┐',
|
|
148
|
-
bottomLeft: '└',
|
|
149
|
-
bottomRight: '┘',
|
|
150
|
-
horizontal: '─',
|
|
151
|
-
vertical: '│'
|
|
152
|
-
},
|
|
153
|
-
round: {
|
|
154
|
-
topLeft: '╭',
|
|
155
|
-
topRight: '╮',
|
|
156
|
-
bottomLeft: '╰',
|
|
157
|
-
bottomRight: '╯',
|
|
158
|
-
horizontal: '─',
|
|
159
|
-
vertical: '│'
|
|
160
|
-
},
|
|
161
|
-
double: {
|
|
162
|
-
topLeft: '╔',
|
|
163
|
-
topRight: '╗',
|
|
164
|
-
bottomLeft: '╚',
|
|
165
|
-
bottomRight: '╝',
|
|
166
|
-
horizontal: '═',
|
|
167
|
-
vertical: '║'
|
|
168
|
-
}
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
const boxChars = chars[style] || chars.single;
|
|
172
|
-
const lines = content.split('\n');
|
|
173
|
-
|
|
174
|
-
// Use fixed width to avoid any width calculation issues
|
|
175
|
-
const terminalWidth = process.stdout.columns || 80;
|
|
176
|
-
const width = Math.min(terminalWidth - 4, 60);
|
|
177
|
-
|
|
178
|
-
// Top border
|
|
179
|
-
let box = colorFn(boxChars.topLeft);
|
|
180
|
-
if (title) {
|
|
181
|
-
const titleLen = title.length;
|
|
182
|
-
const leftPad = Math.floor((width - titleLen - 2) / 2);
|
|
183
|
-
box += colorFn(boxChars.horizontal.repeat(leftPad));
|
|
184
|
-
box += colorFn(title);
|
|
185
|
-
box += colorFn(boxChars.horizontal.repeat(width - leftPad - titleLen));
|
|
186
|
-
} else {
|
|
187
|
-
box += colorFn(boxChars.horizontal.repeat(width));
|
|
188
|
-
}
|
|
189
|
-
box += colorFn(boxChars.topRight) + '\n';
|
|
190
|
-
|
|
191
|
-
// Content lines - use fixed padding to avoid width calculations
|
|
192
|
-
lines.forEach(line => {
|
|
193
|
-
// Truncate long lines
|
|
194
|
-
const maxLen = width - 4;
|
|
195
|
-
const displayLine = line.length > maxLen ? line.substring(0, maxLen - 3) + '...' : line;
|
|
196
|
-
const padding = Math.max(0, width - displayLine.length - 2);
|
|
197
|
-
box += colorFn(boxChars.vertical) + ' ' + displayLine + ' '.repeat(padding) + ' ' + colorFn(boxChars.vertical) + '\n';
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
// Bottom border
|
|
201
|
-
box += colorFn(boxChars.bottomLeft) + colorFn(boxChars.horizontal.repeat(width)) + colorFn(boxChars.bottomRight);
|
|
202
|
-
|
|
203
|
-
return box;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
getStringWidth(str) {
|
|
207
|
-
// Simple character count - don't try to strip ANSI
|
|
208
|
-
// This avoids any regex issues entirely
|
|
209
|
-
return str.length;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
destroy() {
|
|
213
|
-
// Clean up listeners
|
|
214
|
-
if (this.handleExit) {
|
|
215
|
-
process.removeListener('SIGINT', this.handleExit);
|
|
216
|
-
process.removeListener('SIGTERM', this.handleExit);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Show cursor again
|
|
220
|
-
process.stdout.write(ansiEscapes.cursorShow);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Create and display an ANSI-based UI for Auto Mode
|
|
226
|
-
* @param {object} options - UI configuration
|
|
227
|
-
* @param {string} options.menuContent - Menu content to display in header
|
|
228
|
-
* @param {function} options.onExit - Callback when user presses Ctrl+C
|
|
229
|
-
* @returns {AutoModeANSIUI} UI instance
|
|
230
|
-
*/
|
|
231
|
-
function createAutoModeUI(options = {}) {
|
|
232
|
-
return new AutoModeANSIUI(options);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
module.exports = {
|
|
236
|
-
createAutoModeUI,
|
|
237
|
-
AutoModeANSIUI
|
|
238
|
-
};
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const ansiEscapes = require('ansi-escapes');
|
|
3
|
+
const stripAnsi = require('strip-ansi');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* ANSI-based UI for Auto Mode
|
|
7
|
+
* Simple, reliable, no module system issues
|
|
8
|
+
*/
|
|
9
|
+
class AutoModeANSIUI {
|
|
10
|
+
constructor(options = {}) {
|
|
11
|
+
this.menuContent = options.menuContent || '';
|
|
12
|
+
this.onExit = options.onExit;
|
|
13
|
+
this.requirement = 'Loading...';
|
|
14
|
+
this.step = 'PREPARE';
|
|
15
|
+
this.chatCount = 0;
|
|
16
|
+
this.maxChats = null;
|
|
17
|
+
this.progress = 0;
|
|
18
|
+
this.outputLines = [];
|
|
19
|
+
this.maxOutputLines = 15;
|
|
20
|
+
|
|
21
|
+
// Hide cursor for cleaner output
|
|
22
|
+
process.stdout.write(ansiEscapes.cursorHide);
|
|
23
|
+
|
|
24
|
+
// Handle exit - just use SIGINT, don't try to capture keys
|
|
25
|
+
// (stdin might be used by child process like Aider)
|
|
26
|
+
this.handleExit = () => {
|
|
27
|
+
this.destroy();
|
|
28
|
+
if (this.onExit) {
|
|
29
|
+
this.onExit();
|
|
30
|
+
}
|
|
31
|
+
process.exit(0);
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
process.on('SIGINT', this.handleExit);
|
|
35
|
+
process.on('SIGTERM', this.handleExit);
|
|
36
|
+
|
|
37
|
+
// Initial render
|
|
38
|
+
this.render();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
updateStatus(status) {
|
|
42
|
+
if (status.requirement !== undefined) this.requirement = status.requirement;
|
|
43
|
+
if (status.step !== undefined) this.step = status.step;
|
|
44
|
+
if (status.chatCount !== undefined) this.chatCount = status.chatCount;
|
|
45
|
+
if (status.maxChats !== undefined) this.maxChats = status.maxChats;
|
|
46
|
+
if (status.progress !== undefined) this.progress = status.progress;
|
|
47
|
+
this.render();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
appendOutput(line) {
|
|
51
|
+
// Safety: truncate very long lines to prevent memory issues
|
|
52
|
+
const maxLineLength = 500;
|
|
53
|
+
const safeLine = line.length > maxLineLength ? line.substring(0, maxLineLength) + '...' : line;
|
|
54
|
+
|
|
55
|
+
this.outputLines.push(safeLine);
|
|
56
|
+
// Keep only last N lines
|
|
57
|
+
if (this.outputLines.length > this.maxOutputLines) {
|
|
58
|
+
this.outputLines = this.outputLines.slice(-this.maxOutputLines);
|
|
59
|
+
}
|
|
60
|
+
this.render();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
clearOutput() {
|
|
64
|
+
this.outputLines = [];
|
|
65
|
+
this.render();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
render() {
|
|
69
|
+
// Clear screen and move cursor to top
|
|
70
|
+
process.stdout.write(ansiEscapes.clearScreen);
|
|
71
|
+
process.stdout.write(ansiEscapes.cursorTo(0, 0));
|
|
72
|
+
|
|
73
|
+
let output = '';
|
|
74
|
+
|
|
75
|
+
// Header box
|
|
76
|
+
output += this.drawBox(this.menuContent, { color: 'cyan', style: 'round' });
|
|
77
|
+
output += '\n';
|
|
78
|
+
|
|
79
|
+
// Status card
|
|
80
|
+
const statusContent = this.buildStatusContent();
|
|
81
|
+
output += this.drawBox(statusContent, { color: 'magenta', style: 'round', title: ' Auto Mode Status ' });
|
|
82
|
+
output += '\n';
|
|
83
|
+
|
|
84
|
+
// Output log
|
|
85
|
+
const outputContent = this.buildOutputContent();
|
|
86
|
+
output += this.drawBox(outputContent, { color: 'green', style: 'single', title: ' Aider Output ' });
|
|
87
|
+
|
|
88
|
+
process.stdout.write(output);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
buildStatusContent() {
|
|
92
|
+
const stepColors = {
|
|
93
|
+
'PREPARE': chalk.cyan,
|
|
94
|
+
'ACT': chalk.yellow,
|
|
95
|
+
'CLEAN UP': chalk.magenta,
|
|
96
|
+
'VERIFY': chalk.blue,
|
|
97
|
+
'DONE': chalk.green,
|
|
98
|
+
'UNKNOWN': chalk.gray
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const stepColor = stepColors[this.step] || chalk.gray;
|
|
102
|
+
|
|
103
|
+
// Progress bar
|
|
104
|
+
const barWidth = 40;
|
|
105
|
+
const filledWidth = Math.round((this.progress / 100) * barWidth);
|
|
106
|
+
const emptyWidth = barWidth - filledWidth;
|
|
107
|
+
const progressBar = chalk.green('█'.repeat(filledWidth)) + chalk.gray('░'.repeat(emptyWidth));
|
|
108
|
+
|
|
109
|
+
// Chat counter
|
|
110
|
+
const chatDisplay = this.maxChats
|
|
111
|
+
? `Chat ${this.chatCount}/${this.maxChats}`
|
|
112
|
+
: `Chat ${this.chatCount} (unlimited)`;
|
|
113
|
+
|
|
114
|
+
// Truncate requirement if too long
|
|
115
|
+
const displayReq = this.requirement.length > 70
|
|
116
|
+
? this.requirement.substring(0, 67) + '...'
|
|
117
|
+
: this.requirement;
|
|
118
|
+
|
|
119
|
+
return `
|
|
120
|
+
${chalk.bold('📋 Current Requirement')}
|
|
121
|
+
|
|
122
|
+
${displayReq}
|
|
123
|
+
|
|
124
|
+
${chalk.bold('🚦 Status:')} ${stepColor.bold(this.step)}
|
|
125
|
+
|
|
126
|
+
${progressBar} ${this.progress}%
|
|
127
|
+
|
|
128
|
+
${chalk.gray(chatDisplay)}
|
|
129
|
+
`.trim();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
buildOutputContent() {
|
|
133
|
+
if (this.outputLines.length === 0) {
|
|
134
|
+
return chalk.gray('No output yet...');
|
|
135
|
+
}
|
|
136
|
+
return this.outputLines.join('\n');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
drawBox(content, options = {}) {
|
|
140
|
+
const { color = 'white', style = 'single', title = '' } = options;
|
|
141
|
+
const colorFn = chalk[color] || chalk.white;
|
|
142
|
+
|
|
143
|
+
// Box drawing characters
|
|
144
|
+
const chars = {
|
|
145
|
+
single: {
|
|
146
|
+
topLeft: '┌',
|
|
147
|
+
topRight: '┐',
|
|
148
|
+
bottomLeft: '└',
|
|
149
|
+
bottomRight: '┘',
|
|
150
|
+
horizontal: '─',
|
|
151
|
+
vertical: '│'
|
|
152
|
+
},
|
|
153
|
+
round: {
|
|
154
|
+
topLeft: '╭',
|
|
155
|
+
topRight: '╮',
|
|
156
|
+
bottomLeft: '╰',
|
|
157
|
+
bottomRight: '╯',
|
|
158
|
+
horizontal: '─',
|
|
159
|
+
vertical: '│'
|
|
160
|
+
},
|
|
161
|
+
double: {
|
|
162
|
+
topLeft: '╔',
|
|
163
|
+
topRight: '╗',
|
|
164
|
+
bottomLeft: '╚',
|
|
165
|
+
bottomRight: '╝',
|
|
166
|
+
horizontal: '═',
|
|
167
|
+
vertical: '║'
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
const boxChars = chars[style] || chars.single;
|
|
172
|
+
const lines = content.split('\n');
|
|
173
|
+
|
|
174
|
+
// Use fixed width to avoid any width calculation issues
|
|
175
|
+
const terminalWidth = process.stdout.columns || 80;
|
|
176
|
+
const width = Math.min(terminalWidth - 4, 60);
|
|
177
|
+
|
|
178
|
+
// Top border
|
|
179
|
+
let box = colorFn(boxChars.topLeft);
|
|
180
|
+
if (title) {
|
|
181
|
+
const titleLen = title.length;
|
|
182
|
+
const leftPad = Math.floor((width - titleLen - 2) / 2);
|
|
183
|
+
box += colorFn(boxChars.horizontal.repeat(leftPad));
|
|
184
|
+
box += colorFn(title);
|
|
185
|
+
box += colorFn(boxChars.horizontal.repeat(width - leftPad - titleLen));
|
|
186
|
+
} else {
|
|
187
|
+
box += colorFn(boxChars.horizontal.repeat(width));
|
|
188
|
+
}
|
|
189
|
+
box += colorFn(boxChars.topRight) + '\n';
|
|
190
|
+
|
|
191
|
+
// Content lines - use fixed padding to avoid width calculations
|
|
192
|
+
lines.forEach(line => {
|
|
193
|
+
// Truncate long lines
|
|
194
|
+
const maxLen = width - 4;
|
|
195
|
+
const displayLine = line.length > maxLen ? line.substring(0, maxLen - 3) + '...' : line;
|
|
196
|
+
const padding = Math.max(0, width - displayLine.length - 2);
|
|
197
|
+
box += colorFn(boxChars.vertical) + ' ' + displayLine + ' '.repeat(padding) + ' ' + colorFn(boxChars.vertical) + '\n';
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// Bottom border
|
|
201
|
+
box += colorFn(boxChars.bottomLeft) + colorFn(boxChars.horizontal.repeat(width)) + colorFn(boxChars.bottomRight);
|
|
202
|
+
|
|
203
|
+
return box;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
getStringWidth(str) {
|
|
207
|
+
// Simple character count - don't try to strip ANSI
|
|
208
|
+
// This avoids any regex issues entirely
|
|
209
|
+
return str.length;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
destroy() {
|
|
213
|
+
// Clean up listeners
|
|
214
|
+
if (this.handleExit) {
|
|
215
|
+
process.removeListener('SIGINT', this.handleExit);
|
|
216
|
+
process.removeListener('SIGTERM', this.handleExit);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Show cursor again
|
|
220
|
+
process.stdout.write(ansiEscapes.cursorShow);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Create and display an ANSI-based UI for Auto Mode
|
|
226
|
+
* @param {object} options - UI configuration
|
|
227
|
+
* @param {string} options.menuContent - Menu content to display in header
|
|
228
|
+
* @param {function} options.onExit - Callback when user presses Ctrl+C
|
|
229
|
+
* @returns {AutoModeANSIUI} UI instance
|
|
230
|
+
*/
|
|
231
|
+
function createAutoModeUI(options = {}) {
|
|
232
|
+
return new AutoModeANSIUI(options);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
module.exports = {
|
|
236
|
+
createAutoModeUI,
|
|
237
|
+
AutoModeANSIUI
|
|
238
|
+
};
|