vibecodingmachine-cli 2026.3.9-907 → 2026.3.10-1547
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/README.md +85 -85
- package/bin/commands/agent-commands.js +295 -28
- package/bin/vibecodingmachine.js +0 -0
- package/package.json +2 -2
- package/scripts/postinstall.js +161 -161
- package/src/commands/auth.js +100 -100
- package/src/commands/auto-execution.js +120 -32
- package/src/commands/auto-requirement-management.js +9 -9
- package/src/commands/auto-status-helpers.js +6 -12
- package/src/commands/computers.js +318 -318
- package/src/commands/feature.js +123 -123
- package/src/commands/locale.js +72 -72
- package/src/commands/repo.js +163 -163
- package/src/commands/setup.js +93 -93
- package/src/commands/sync.js +287 -287
- package/src/index.js +5 -5
- package/src/utils/agent-selector.js +50 -50
- package/src/utils/asset-cleanup.js +60 -60
- package/src/utils/auth.js +6 -0
- package/src/utils/auto-mode-ansi-ui.js +237 -237
- package/src/utils/auto-mode-simple-ui.js +141 -141
- package/src/utils/copy-with-progress.js +167 -167
- package/src/utils/download-with-progress.js +84 -84
- package/src/utils/keyboard-handler.js +153 -153
- package/src/utils/kiro-installer.js +178 -178
- package/src/utils/logger.js +4 -4
- package/src/utils/persistent-header.js +114 -114
- package/src/utils/prompt-helper.js +63 -63
- package/src/utils/provider-checker/agent-runner.js +110 -31
- package/src/utils/provider-checker/ide-manager.js +37 -8
- package/src/utils/provider-checker/provider-validator.js +50 -0
- package/src/utils/provider-checker/requirements-manager.js +21 -6
- package/src/utils/status-card.js +121 -121
- package/src/utils/stdout-interceptor.js +127 -127
- package/src/utils/trui-main-handlers.js +41 -8
- package/src/utils/trui-main-menu.js +10 -3
- package/src/utils/trui-nav-agents.js +23 -33
- package/src/utils/trui-navigation.js +2 -2
- package/src/utils/user-tracking.js +299 -299
|
@@ -1,84 +1,84 @@
|
|
|
1
|
-
const fs = require('fs');
|
|
2
|
-
const ora = require('ora');
|
|
3
|
-
|
|
4
|
-
async function downloadWithProgress(url, dest, opts = {}) {
|
|
5
|
-
const fetch = require('node-fetch');
|
|
6
|
-
const spinner = opts.spinner || ora();
|
|
7
|
-
const label = opts.label || 'Downloading...';
|
|
8
|
-
|
|
9
|
-
spinner.start(label);
|
|
10
|
-
|
|
11
|
-
const res = await fetch(url);
|
|
12
|
-
if (!res.ok) {
|
|
13
|
-
spinner.fail(`Download failed: ${res.status} ${res.statusText}`);
|
|
14
|
-
throw new Error(`Failed to download ${url}: ${res.status}`);
|
|
15
|
-
}
|
|
16
|
-
// Stop the ora spinner so we can write an in-place progress line without conflicts
|
|
17
|
-
try { spinner.stop(); } catch (e) { /* ignore */ }
|
|
18
|
-
// Print initial progress line so user sees immediate feedback
|
|
19
|
-
try { process.stdout.write('\r\x1b[2KDownloading: 0.0 MB'); } catch (e) { /* ignore */ }
|
|
20
|
-
|
|
21
|
-
const total = Number(res.headers.get('content-length')) || 0;
|
|
22
|
-
const fileStream = fs.createWriteStream(dest);
|
|
23
|
-
|
|
24
|
-
return await new Promise((resolve, reject) => {
|
|
25
|
-
let downloaded = 0;
|
|
26
|
-
const start = Date.now();
|
|
27
|
-
let lastPercent = -1;
|
|
28
|
-
|
|
29
|
-
res.body.on('data', (chunk) => {
|
|
30
|
-
downloaded += chunk.length;
|
|
31
|
-
if (total) {
|
|
32
|
-
const percent = Math.round((downloaded / total) * 100);
|
|
33
|
-
if (percent !== lastPercent) {
|
|
34
|
-
lastPercent = percent;
|
|
35
|
-
const mbDownloaded = (downloaded / (1024 * 1024)).toFixed(1);
|
|
36
|
-
const mbTotal = (total / (1024 * 1024)).toFixed(1);
|
|
37
|
-
const elapsed = Math.max(0.001, (Date.now() - start) / 1000);
|
|
38
|
-
const speed = downloaded / elapsed; // bytes/sec
|
|
39
|
-
const etaSec = (total - downloaded) / (speed || 1);
|
|
40
|
-
const eta = formatEta(etaSec);
|
|
41
|
-
const bar = progressBar(percent, 30);
|
|
42
|
-
process.stdout.write(`\r\x1b[2K[${bar}] ${percent}% ${mbDownloaded}MB / ${mbTotal}MB ETA: ${eta}`);
|
|
43
|
-
}
|
|
44
|
-
} else {
|
|
45
|
-
const mbDownloaded = (downloaded / (1024 * 1024)).toFixed(1);
|
|
46
|
-
process.stdout.write(`\r\x1b[2K${label} ${mbDownloaded} MB`);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
res.body.on('error', (err) => {
|
|
51
|
-
spinner.fail('Download error');
|
|
52
|
-
reject(err);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
fileStream.on('error', (err) => {
|
|
56
|
-
spinner.fail('File write error');
|
|
57
|
-
reject(err);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
fileStream.on('finish', () => {
|
|
61
|
-
process.stdout.write('\n');
|
|
62
|
-
spinner.succeed('Download complete');
|
|
63
|
-
resolve();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// Pipe the response body to file
|
|
67
|
-
res.body.pipe(fileStream);
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function progressBar(percent, width) {
|
|
72
|
-
const fill = Math.round((percent / 100) * width);
|
|
73
|
-
return '█'.repeat(fill) + '-'.repeat(Math.max(0, width - fill));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function formatEta(sec) {
|
|
77
|
-
if (!isFinite(sec) || sec === null) return '--:--';
|
|
78
|
-
const s = Math.max(0, Math.round(sec));
|
|
79
|
-
const m = Math.floor(s / 60);
|
|
80
|
-
const ss = s % 60;
|
|
81
|
-
return `${m}:${ss.toString().padStart(2, '0')}`;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
module.exports = { downloadWithProgress };
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const ora = require('ora');
|
|
3
|
+
|
|
4
|
+
async function downloadWithProgress(url, dest, opts = {}) {
|
|
5
|
+
const fetch = require('node-fetch');
|
|
6
|
+
const spinner = opts.spinner || ora();
|
|
7
|
+
const label = opts.label || 'Downloading...';
|
|
8
|
+
|
|
9
|
+
spinner.start(label);
|
|
10
|
+
|
|
11
|
+
const res = await fetch(url);
|
|
12
|
+
if (!res.ok) {
|
|
13
|
+
spinner.fail(`Download failed: ${res.status} ${res.statusText}`);
|
|
14
|
+
throw new Error(`Failed to download ${url}: ${res.status}`);
|
|
15
|
+
}
|
|
16
|
+
// Stop the ora spinner so we can write an in-place progress line without conflicts
|
|
17
|
+
try { spinner.stop(); } catch (e) { /* ignore */ }
|
|
18
|
+
// Print initial progress line so user sees immediate feedback
|
|
19
|
+
try { process.stdout.write('\r\x1b[2KDownloading: 0.0 MB'); } catch (e) { /* ignore */ }
|
|
20
|
+
|
|
21
|
+
const total = Number(res.headers.get('content-length')) || 0;
|
|
22
|
+
const fileStream = fs.createWriteStream(dest);
|
|
23
|
+
|
|
24
|
+
return await new Promise((resolve, reject) => {
|
|
25
|
+
let downloaded = 0;
|
|
26
|
+
const start = Date.now();
|
|
27
|
+
let lastPercent = -1;
|
|
28
|
+
|
|
29
|
+
res.body.on('data', (chunk) => {
|
|
30
|
+
downloaded += chunk.length;
|
|
31
|
+
if (total) {
|
|
32
|
+
const percent = Math.round((downloaded / total) * 100);
|
|
33
|
+
if (percent !== lastPercent) {
|
|
34
|
+
lastPercent = percent;
|
|
35
|
+
const mbDownloaded = (downloaded / (1024 * 1024)).toFixed(1);
|
|
36
|
+
const mbTotal = (total / (1024 * 1024)).toFixed(1);
|
|
37
|
+
const elapsed = Math.max(0.001, (Date.now() - start) / 1000);
|
|
38
|
+
const speed = downloaded / elapsed; // bytes/sec
|
|
39
|
+
const etaSec = (total - downloaded) / (speed || 1);
|
|
40
|
+
const eta = formatEta(etaSec);
|
|
41
|
+
const bar = progressBar(percent, 30);
|
|
42
|
+
process.stdout.write(`\r\x1b[2K[${bar}] ${percent}% ${mbDownloaded}MB / ${mbTotal}MB ETA: ${eta}`);
|
|
43
|
+
}
|
|
44
|
+
} else {
|
|
45
|
+
const mbDownloaded = (downloaded / (1024 * 1024)).toFixed(1);
|
|
46
|
+
process.stdout.write(`\r\x1b[2K${label} ${mbDownloaded} MB`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
res.body.on('error', (err) => {
|
|
51
|
+
spinner.fail('Download error');
|
|
52
|
+
reject(err);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
fileStream.on('error', (err) => {
|
|
56
|
+
spinner.fail('File write error');
|
|
57
|
+
reject(err);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
fileStream.on('finish', () => {
|
|
61
|
+
process.stdout.write('\n');
|
|
62
|
+
spinner.succeed('Download complete');
|
|
63
|
+
resolve();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Pipe the response body to file
|
|
67
|
+
res.body.pipe(fileStream);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function progressBar(percent, width) {
|
|
72
|
+
const fill = Math.round((percent / 100) * width);
|
|
73
|
+
return '█'.repeat(fill) + '-'.repeat(Math.max(0, width - fill));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function formatEta(sec) {
|
|
77
|
+
if (!isFinite(sec) || sec === null) return '--:--';
|
|
78
|
+
const s = Math.max(0, Math.round(sec));
|
|
79
|
+
const m = Math.floor(s / 60);
|
|
80
|
+
const ss = s % 60;
|
|
81
|
+
return `${m}:${ss.toString().padStart(2, '0')}`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
module.exports = { downloadWithProgress };
|
|
@@ -1,153 +1,153 @@
|
|
|
1
|
-
const readline = require('readline');
|
|
2
|
-
const chalk = require('chalk');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Lightweight keyboard handler for Auto Mode
|
|
6
|
-
* Listens for 'x' key and Ctrl+C without interfering with child process stdin
|
|
7
|
-
*/
|
|
8
|
-
class KeyboardHandler {
|
|
9
|
-
constructor(options = {}) {
|
|
10
|
-
this.onExit = options.onExit;
|
|
11
|
-
this.isActive = false;
|
|
12
|
-
this.exitConfirmMode = false;
|
|
13
|
-
this.keypressHandler = null;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Start listening for keyboard input
|
|
18
|
-
*/
|
|
19
|
-
start() {
|
|
20
|
-
if (this.isActive) return;
|
|
21
|
-
|
|
22
|
-
this.isActive = true;
|
|
23
|
-
|
|
24
|
-
// Set up keypress events on stdin
|
|
25
|
-
readline.emitKeypressEvents(process.stdin);
|
|
26
|
-
|
|
27
|
-
// Only set raw mode if stdin is a TTY
|
|
28
|
-
if (process.stdin.isTTY && !process.stdin.isRaw) {
|
|
29
|
-
process.stdin.setRawMode(true);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// Create keypress handler
|
|
33
|
-
this.keypressHandler = (str, key) => {
|
|
34
|
-
if (!key) return;
|
|
35
|
-
|
|
36
|
-
// Handle Ctrl+C - immediate exit
|
|
37
|
-
if (key.ctrl && key.name === 'c') {
|
|
38
|
-
this.handleImmediateExit();
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Handle 'x' key - show confirmation
|
|
43
|
-
if (key.name === 'x' && !this.exitConfirmMode) {
|
|
44
|
-
this.showExitConfirmation();
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// In confirmation mode, handle y/n
|
|
49
|
-
if (this.exitConfirmMode) {
|
|
50
|
-
if (key.name === 'y') {
|
|
51
|
-
this.confirmExit();
|
|
52
|
-
} else if (key.name === 'n' || key.name === 'escape') {
|
|
53
|
-
this.cancelExit();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// Attach handler
|
|
59
|
-
process.stdin.on('keypress', this.keypressHandler);
|
|
60
|
-
process.stdin.resume();
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Stop listening for keyboard input
|
|
65
|
-
*/
|
|
66
|
-
stop() {
|
|
67
|
-
if (!this.isActive) return;
|
|
68
|
-
|
|
69
|
-
this.isActive = false;
|
|
70
|
-
|
|
71
|
-
// Remove keypress handler
|
|
72
|
-
if (this.keypressHandler) {
|
|
73
|
-
process.stdin.removeListener('keypress', this.keypressHandler);
|
|
74
|
-
this.keypressHandler = null;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Restore stdin to normal mode
|
|
78
|
-
if (process.stdin.isTTY && process.stdin.isRaw) {
|
|
79
|
-
process.stdin.setRawMode(false);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
process.stdin.pause();
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
showExitConfirmation() {
|
|
86
|
-
this.exitConfirmMode = true;
|
|
87
|
-
console.log('\n' + chalk.yellow('─'.repeat(60)));
|
|
88
|
-
console.log(chalk.yellow.bold(' Exit Auto Mode?'));
|
|
89
|
-
console.log(chalk.yellow(' Press ') + chalk.white.bold('y') + chalk.yellow(' to exit, ') + chalk.white.bold('n') + chalk.yellow(' to cancel'));
|
|
90
|
-
console.log(chalk.yellow('─'.repeat(60)) + '\n');
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
cancelExit() {
|
|
94
|
-
this.exitConfirmMode = false;
|
|
95
|
-
console.log(chalk.gray(' Cancelled - continuing Auto Mode...\n'));
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
confirmExit() {
|
|
99
|
-
this.exitConfirmMode = false;
|
|
100
|
-
this.stop();
|
|
101
|
-
|
|
102
|
-
console.log(chalk.green(' Exiting Auto Mode...\n'));
|
|
103
|
-
|
|
104
|
-
if (this.onExit) {
|
|
105
|
-
this.onExit();
|
|
106
|
-
} else {
|
|
107
|
-
process.exit(0);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
handleImmediateExit() {
|
|
112
|
-
console.log(chalk.yellow('\n Ctrl+C detected - force exiting...\n'));
|
|
113
|
-
|
|
114
|
-
// Call onExit callback first if provided (for cleanup)
|
|
115
|
-
if (this.onExit) {
|
|
116
|
-
try {
|
|
117
|
-
this.onExit();
|
|
118
|
-
} catch (err) {
|
|
119
|
-
// Ignore errors during cleanup
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Force exit immediately - don't wait for async cleanup
|
|
124
|
-
// This is critical because the event loop may be blocked on child processes
|
|
125
|
-
this.stop();
|
|
126
|
-
process.exit(0);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Create a keyboard handler for Auto Mode
|
|
132
|
-
* @param {object} options - Configuration options
|
|
133
|
-
* @param {function} options.onExit - Callback when user exits
|
|
134
|
-
* @returns {KeyboardHandler}
|
|
135
|
-
*/
|
|
136
|
-
function createKeyboardHandler(options = {}) {
|
|
137
|
-
return new KeyboardHandler(options);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
module.exports = {
|
|
141
|
-
KeyboardHandler,
|
|
142
|
-
createKeyboardHandler
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
1
|
+
const readline = require('readline');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Lightweight keyboard handler for Auto Mode
|
|
6
|
+
* Listens for 'x' key and Ctrl+C without interfering with child process stdin
|
|
7
|
+
*/
|
|
8
|
+
class KeyboardHandler {
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.onExit = options.onExit;
|
|
11
|
+
this.isActive = false;
|
|
12
|
+
this.exitConfirmMode = false;
|
|
13
|
+
this.keypressHandler = null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Start listening for keyboard input
|
|
18
|
+
*/
|
|
19
|
+
start() {
|
|
20
|
+
if (this.isActive) return;
|
|
21
|
+
|
|
22
|
+
this.isActive = true;
|
|
23
|
+
|
|
24
|
+
// Set up keypress events on stdin
|
|
25
|
+
readline.emitKeypressEvents(process.stdin);
|
|
26
|
+
|
|
27
|
+
// Only set raw mode if stdin is a TTY
|
|
28
|
+
if (process.stdin.isTTY && !process.stdin.isRaw) {
|
|
29
|
+
process.stdin.setRawMode(true);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Create keypress handler
|
|
33
|
+
this.keypressHandler = (str, key) => {
|
|
34
|
+
if (!key) return;
|
|
35
|
+
|
|
36
|
+
// Handle Ctrl+C - immediate exit
|
|
37
|
+
if (key.ctrl && key.name === 'c') {
|
|
38
|
+
this.handleImmediateExit();
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Handle 'x' key - show confirmation
|
|
43
|
+
if (key.name === 'x' && !this.exitConfirmMode) {
|
|
44
|
+
this.showExitConfirmation();
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// In confirmation mode, handle y/n
|
|
49
|
+
if (this.exitConfirmMode) {
|
|
50
|
+
if (key.name === 'y') {
|
|
51
|
+
this.confirmExit();
|
|
52
|
+
} else if (key.name === 'n' || key.name === 'escape') {
|
|
53
|
+
this.cancelExit();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
// Attach handler
|
|
59
|
+
process.stdin.on('keypress', this.keypressHandler);
|
|
60
|
+
process.stdin.resume();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Stop listening for keyboard input
|
|
65
|
+
*/
|
|
66
|
+
stop() {
|
|
67
|
+
if (!this.isActive) return;
|
|
68
|
+
|
|
69
|
+
this.isActive = false;
|
|
70
|
+
|
|
71
|
+
// Remove keypress handler
|
|
72
|
+
if (this.keypressHandler) {
|
|
73
|
+
process.stdin.removeListener('keypress', this.keypressHandler);
|
|
74
|
+
this.keypressHandler = null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Restore stdin to normal mode
|
|
78
|
+
if (process.stdin.isTTY && process.stdin.isRaw) {
|
|
79
|
+
process.stdin.setRawMode(false);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
process.stdin.pause();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
showExitConfirmation() {
|
|
86
|
+
this.exitConfirmMode = true;
|
|
87
|
+
console.log('\n' + chalk.yellow('─'.repeat(60)));
|
|
88
|
+
console.log(chalk.yellow.bold(' Exit Auto Mode?'));
|
|
89
|
+
console.log(chalk.yellow(' Press ') + chalk.white.bold('y') + chalk.yellow(' to exit, ') + chalk.white.bold('n') + chalk.yellow(' to cancel'));
|
|
90
|
+
console.log(chalk.yellow('─'.repeat(60)) + '\n');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
cancelExit() {
|
|
94
|
+
this.exitConfirmMode = false;
|
|
95
|
+
console.log(chalk.gray(' Cancelled - continuing Auto Mode...\n'));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
confirmExit() {
|
|
99
|
+
this.exitConfirmMode = false;
|
|
100
|
+
this.stop();
|
|
101
|
+
|
|
102
|
+
console.log(chalk.green(' Exiting Auto Mode...\n'));
|
|
103
|
+
|
|
104
|
+
if (this.onExit) {
|
|
105
|
+
this.onExit();
|
|
106
|
+
} else {
|
|
107
|
+
process.exit(0);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
handleImmediateExit() {
|
|
112
|
+
console.log(chalk.yellow('\n Ctrl+C detected - force exiting...\n'));
|
|
113
|
+
|
|
114
|
+
// Call onExit callback first if provided (for cleanup)
|
|
115
|
+
if (this.onExit) {
|
|
116
|
+
try {
|
|
117
|
+
this.onExit();
|
|
118
|
+
} catch (err) {
|
|
119
|
+
// Ignore errors during cleanup
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Force exit immediately - don't wait for async cleanup
|
|
124
|
+
// This is critical because the event loop may be blocked on child processes
|
|
125
|
+
this.stop();
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Create a keyboard handler for Auto Mode
|
|
132
|
+
* @param {object} options - Configuration options
|
|
133
|
+
* @param {function} options.onExit - Callback when user exits
|
|
134
|
+
* @returns {KeyboardHandler}
|
|
135
|
+
*/
|
|
136
|
+
function createKeyboardHandler(options = {}) {
|
|
137
|
+
return new KeyboardHandler(options);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
module.exports = {
|
|
141
|
+
KeyboardHandler,
|
|
142
|
+
createKeyboardHandler
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
|