vibecodingmachine-cli 1.0.4 → 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,128 +1,128 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const os = require('os');
|
|
3
|
-
const { getAutoConfig, setAutoConfig } = require('./config');
|
|
4
|
-
|
|
5
|
-
const PROVIDER_DEFINITIONS = [
|
|
6
|
-
{
|
|
7
|
-
id: 'groq',
|
|
8
|
-
name: 'Groq (Cloud - Very Fast)',
|
|
9
|
-
type: 'direct',
|
|
10
|
-
category: 'llm',
|
|
11
|
-
defaultModel: 'llama-3.3-70b-versatile',
|
|
12
|
-
configKeys: { apiKey: 'groqApiKey', model: 'groqModel' },
|
|
13
|
-
estimatedSpeed: 15000
|
|
14
|
-
},
|
|
15
|
-
{
|
|
16
|
-
id: 'anthropic',
|
|
17
|
-
name: 'Anthropic (Claude Sonnet 4)',
|
|
18
|
-
type: 'direct',
|
|
19
|
-
category: 'llm',
|
|
20
|
-
defaultModel: 'claude-sonnet-4-20250514',
|
|
21
|
-
configKeys: { apiKey: 'anthropicApiKey', model: 'anthropicModel' },
|
|
22
|
-
estimatedSpeed: 25000
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
id: 'bedrock',
|
|
26
|
-
name: 'AWS Bedrock (Claude)',
|
|
27
|
-
type: 'direct',
|
|
28
|
-
category: 'llm',
|
|
29
|
-
defaultModel: 'anthropic.claude-sonnet-4-v1',
|
|
30
|
-
configKeys: { region: 'awsRegion', accessKeyId: 'awsAccessKeyId', secretAccessKey: 'awsSecretAccessKey' },
|
|
31
|
-
estimatedSpeed: 40000
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
id: 'claude-code',
|
|
35
|
-
name: 'Claude Code CLI (Sonnet 4.5)',
|
|
36
|
-
type: 'direct',
|
|
37
|
-
category: 'llm',
|
|
38
|
-
defaultModel: 'claude-code-cli',
|
|
39
|
-
estimatedSpeed: 35000
|
|
40
|
-
},
|
|
41
|
-
{
|
|
42
|
-
id: 'cursor',
|
|
43
|
-
name: 'Cursor IDE Agent',
|
|
44
|
-
type: 'ide',
|
|
45
|
-
category: 'ide',
|
|
46
|
-
ide: 'cursor',
|
|
47
|
-
estimatedSpeed: 60000
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
id: 'windsurf',
|
|
51
|
-
name: 'Windsurf IDE Agent',
|
|
52
|
-
type: 'ide',
|
|
53
|
-
category: 'ide',
|
|
54
|
-
ide: 'windsurf',
|
|
55
|
-
estimatedSpeed: 90000
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
id: 'antigravity',
|
|
59
|
-
name: 'Google Antigravity IDE Agent',
|
|
60
|
-
type: 'ide',
|
|
61
|
-
category: 'ide',
|
|
62
|
-
ide: 'antigravity',
|
|
63
|
-
estimatedSpeed: 90000
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
id: 'ollama',
|
|
67
|
-
name: 'Ollama (Local)',
|
|
68
|
-
type: 'direct',
|
|
69
|
-
category: 'llm',
|
|
70
|
-
defaultModel: 'qwen2.5-coder:32b',
|
|
71
|
-
estimatedSpeed: 200000
|
|
72
|
-
}
|
|
73
|
-
];
|
|
74
|
-
|
|
75
|
-
function getProviderDefinitions() {
|
|
76
|
-
return PROVIDER_DEFINITIONS.map(def => ({ ...def }));
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function getProviderDefinition(id) {
|
|
80
|
-
return PROVIDER_DEFINITIONS.find(def => def.id === id);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function getDefaultProviderOrder() {
|
|
84
|
-
return PROVIDER_DEFINITIONS.map(def => def.id);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function mergeProviderPreferences(autoConfig) {
|
|
88
|
-
const prefs = (autoConfig && autoConfig.providerPreferences) || {};
|
|
89
|
-
const order = Array.isArray(prefs.order) ? prefs.order.slice() : [];
|
|
90
|
-
const enabled = (prefs.enabled && typeof prefs.enabled === 'object') ? { ...prefs.enabled } : {};
|
|
91
|
-
|
|
92
|
-
const defaultOrder = getDefaultProviderOrder();
|
|
93
|
-
const cleanedOrder = order.filter(id => getProviderDefinition(id));
|
|
94
|
-
defaultOrder.forEach(id => {
|
|
95
|
-
if (!cleanedOrder.includes(id)) {
|
|
96
|
-
cleanedOrder.push(id);
|
|
97
|
-
}
|
|
98
|
-
if (enabled[id] === undefined) {
|
|
99
|
-
enabled[id] = true;
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
return { order: cleanedOrder, enabled };
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async function getProviderPreferences() {
|
|
107
|
-
const autoConfig = await getAutoConfig();
|
|
108
|
-
return mergeProviderPreferences(autoConfig);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async function saveProviderPreferences(order, enabled) {
|
|
112
|
-
await setAutoConfig({
|
|
113
|
-
providerPreferences: {
|
|
114
|
-
order: order.slice(),
|
|
115
|
-
enabled: { ...enabled }
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
module.exports = {
|
|
121
|
-
getProviderDefinitions,
|
|
122
|
-
getProviderDefinition,
|
|
123
|
-
getDefaultProviderOrder,
|
|
124
|
-
mergeProviderPreferences,
|
|
125
|
-
getProviderPreferences,
|
|
126
|
-
saveProviderPreferences
|
|
127
|
-
};
|
|
128
|
-
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const os = require('os');
|
|
3
|
+
const { getAutoConfig, setAutoConfig } = require('./config');
|
|
4
|
+
|
|
5
|
+
const PROVIDER_DEFINITIONS = [
|
|
6
|
+
{
|
|
7
|
+
id: 'groq',
|
|
8
|
+
name: 'Groq (Cloud - Very Fast)',
|
|
9
|
+
type: 'direct',
|
|
10
|
+
category: 'llm',
|
|
11
|
+
defaultModel: 'llama-3.3-70b-versatile',
|
|
12
|
+
configKeys: { apiKey: 'groqApiKey', model: 'groqModel' },
|
|
13
|
+
estimatedSpeed: 15000
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
id: 'anthropic',
|
|
17
|
+
name: 'Anthropic (Claude Sonnet 4)',
|
|
18
|
+
type: 'direct',
|
|
19
|
+
category: 'llm',
|
|
20
|
+
defaultModel: 'claude-sonnet-4-20250514',
|
|
21
|
+
configKeys: { apiKey: 'anthropicApiKey', model: 'anthropicModel' },
|
|
22
|
+
estimatedSpeed: 25000
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'bedrock',
|
|
26
|
+
name: 'AWS Bedrock (Claude)',
|
|
27
|
+
type: 'direct',
|
|
28
|
+
category: 'llm',
|
|
29
|
+
defaultModel: 'anthropic.claude-sonnet-4-v1',
|
|
30
|
+
configKeys: { region: 'awsRegion', accessKeyId: 'awsAccessKeyId', secretAccessKey: 'awsSecretAccessKey' },
|
|
31
|
+
estimatedSpeed: 40000
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 'claude-code',
|
|
35
|
+
name: 'Claude Code CLI (Sonnet 4.5)',
|
|
36
|
+
type: 'direct',
|
|
37
|
+
category: 'llm',
|
|
38
|
+
defaultModel: 'claude-code-cli',
|
|
39
|
+
estimatedSpeed: 35000
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: 'cursor',
|
|
43
|
+
name: 'Cursor IDE Agent',
|
|
44
|
+
type: 'ide',
|
|
45
|
+
category: 'ide',
|
|
46
|
+
ide: 'cursor',
|
|
47
|
+
estimatedSpeed: 60000
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 'windsurf',
|
|
51
|
+
name: 'Windsurf IDE Agent',
|
|
52
|
+
type: 'ide',
|
|
53
|
+
category: 'ide',
|
|
54
|
+
ide: 'windsurf',
|
|
55
|
+
estimatedSpeed: 90000
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 'antigravity',
|
|
59
|
+
name: 'Google Antigravity IDE Agent',
|
|
60
|
+
type: 'ide',
|
|
61
|
+
category: 'ide',
|
|
62
|
+
ide: 'antigravity',
|
|
63
|
+
estimatedSpeed: 90000
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'ollama',
|
|
67
|
+
name: 'Ollama (Local)',
|
|
68
|
+
type: 'direct',
|
|
69
|
+
category: 'llm',
|
|
70
|
+
defaultModel: 'qwen2.5-coder:32b',
|
|
71
|
+
estimatedSpeed: 200000
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
function getProviderDefinitions() {
|
|
76
|
+
return PROVIDER_DEFINITIONS.map(def => ({ ...def }));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getProviderDefinition(id) {
|
|
80
|
+
return PROVIDER_DEFINITIONS.find(def => def.id === id);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function getDefaultProviderOrder() {
|
|
84
|
+
return PROVIDER_DEFINITIONS.map(def => def.id);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function mergeProviderPreferences(autoConfig) {
|
|
88
|
+
const prefs = (autoConfig && autoConfig.providerPreferences) || {};
|
|
89
|
+
const order = Array.isArray(prefs.order) ? prefs.order.slice() : [];
|
|
90
|
+
const enabled = (prefs.enabled && typeof prefs.enabled === 'object') ? { ...prefs.enabled } : {};
|
|
91
|
+
|
|
92
|
+
const defaultOrder = getDefaultProviderOrder();
|
|
93
|
+
const cleanedOrder = order.filter(id => getProviderDefinition(id));
|
|
94
|
+
defaultOrder.forEach(id => {
|
|
95
|
+
if (!cleanedOrder.includes(id)) {
|
|
96
|
+
cleanedOrder.push(id);
|
|
97
|
+
}
|
|
98
|
+
if (enabled[id] === undefined) {
|
|
99
|
+
enabled[id] = true;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
return { order: cleanedOrder, enabled };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function getProviderPreferences() {
|
|
107
|
+
const autoConfig = await getAutoConfig();
|
|
108
|
+
return mergeProviderPreferences(autoConfig);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async function saveProviderPreferences(order, enabled) {
|
|
112
|
+
await setAutoConfig({
|
|
113
|
+
providerPreferences: {
|
|
114
|
+
order: order.slice(),
|
|
115
|
+
enabled: { ...enabled }
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = {
|
|
121
|
+
getProviderDefinitions,
|
|
122
|
+
getProviderDefinition,
|
|
123
|
+
getDefaultProviderOrder,
|
|
124
|
+
mergeProviderPreferences,
|
|
125
|
+
getProviderPreferences,
|
|
126
|
+
saveProviderPreferences
|
|
127
|
+
};
|
|
128
|
+
|
package/src/utils/status-card.js
CHANGED
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
const chalk = require('chalk');
|
|
2
|
-
const boxen = require('boxen');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Render a status card showing current requirement progress
|
|
6
|
-
* Similar to the purple card in the GUI
|
|
7
|
-
* @param {object} status - Current status object
|
|
8
|
-
* @param {string} status.requirement - Current requirement being worked on
|
|
9
|
-
* @param {string} status.step - Current step (PREPARE, ACT, CLEAN UP, VERIFY, DONE)
|
|
10
|
-
* @param {number} status.chatCount - Current chat count
|
|
11
|
-
* @param {number|null} status.maxChats - Maximum chats or null for unlimited
|
|
12
|
-
* @param {number} status.progress - Progress percentage (0-100)
|
|
13
|
-
* @returns {string} Formatted status card
|
|
14
|
-
*/
|
|
15
|
-
function renderStatusCard(status) {
|
|
16
|
-
const {
|
|
17
|
-
requirement = 'No requirement loaded',
|
|
18
|
-
step = 'UNKNOWN',
|
|
19
|
-
chatCount = 0,
|
|
20
|
-
maxChats = null,
|
|
21
|
-
progress = 0
|
|
22
|
-
} = status;
|
|
23
|
-
|
|
24
|
-
// Step color mapping
|
|
25
|
-
const stepColors = {
|
|
26
|
-
'PREPARE': chalk.cyan,
|
|
27
|
-
'ACT': chalk.yellow,
|
|
28
|
-
'CLEAN UP': chalk.magenta,
|
|
29
|
-
'VERIFY': chalk.blue,
|
|
30
|
-
'DONE': chalk.green,
|
|
31
|
-
'UNKNOWN': chalk.gray
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const stepColor = stepColors[step] || chalk.gray;
|
|
35
|
-
|
|
36
|
-
// Progress bar
|
|
37
|
-
const barWidth = 30;
|
|
38
|
-
const filledWidth = Math.round((progress / 100) * barWidth);
|
|
39
|
-
const emptyWidth = barWidth - filledWidth;
|
|
40
|
-
const progressBar = chalk.green('█'.repeat(filledWidth)) + chalk.gray('░'.repeat(emptyWidth));
|
|
41
|
-
|
|
42
|
-
// Chat counter
|
|
43
|
-
const chatDisplay = maxChats
|
|
44
|
-
? `Chat ${chatCount}/${maxChats}`
|
|
45
|
-
: `Chat ${chatCount} (unlimited)`;
|
|
46
|
-
|
|
47
|
-
// Build card content
|
|
48
|
-
const content = [
|
|
49
|
-
chalk.bold('📋 Current Requirement'),
|
|
50
|
-
'',
|
|
51
|
-
chalk.white(requirement.length > 60 ? requirement.substring(0, 57) + '...' : requirement),
|
|
52
|
-
'',
|
|
53
|
-
chalk.bold('🚦 Status: ') + stepColor.bold(step),
|
|
54
|
-
'',
|
|
55
|
-
`${progressBar} ${progress}%`,
|
|
56
|
-
'',
|
|
57
|
-
chalk.gray(chatDisplay)
|
|
58
|
-
].join('\n');
|
|
59
|
-
|
|
60
|
-
// Render with boxen (purple/magenta border like the GUI)
|
|
61
|
-
return boxen(content, {
|
|
62
|
-
padding: 1,
|
|
63
|
-
margin: { top: 0, right: 0, bottom: 1, left: 0 },
|
|
64
|
-
borderStyle: 'round',
|
|
65
|
-
borderColor: 'magenta',
|
|
66
|
-
title: 'Auto Mode Status',
|
|
67
|
-
titleAlignment: 'center'
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Clear the terminal and move cursor to top
|
|
73
|
-
*/
|
|
74
|
-
function clearAndMoveToTop() {
|
|
75
|
-
// ANSI escape codes
|
|
76
|
-
process.stdout.write('\x1B[2J'); // Clear entire screen
|
|
77
|
-
process.stdout.write('\x1B[H'); // Move cursor to home (top-left)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Move cursor up N lines
|
|
82
|
-
* @param {number} lines - Number of lines to move up
|
|
83
|
-
*/
|
|
84
|
-
function moveCursorUp(lines) {
|
|
85
|
-
process.stdout.write(`\x1B[${lines}A`);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Save cursor position
|
|
90
|
-
*/
|
|
91
|
-
function saveCursor() {
|
|
92
|
-
process.stdout.write('\x1B[s');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Restore cursor position
|
|
97
|
-
*/
|
|
98
|
-
function restoreCursor() {
|
|
99
|
-
process.stdout.write('\x1B[u');
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Render the menu header and status card together
|
|
104
|
-
* @param {string} menuContent - The menu content to display
|
|
105
|
-
* @param {object} status - Status object for the status card
|
|
106
|
-
*/
|
|
107
|
-
function renderHeaderWithStatus(menuContent, status) {
|
|
108
|
-
clearAndMoveToTop();
|
|
109
|
-
console.log(menuContent);
|
|
110
|
-
console.log(renderStatusCard(status));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
module.exports = {
|
|
114
|
-
renderStatusCard,
|
|
115
|
-
clearAndMoveToTop,
|
|
116
|
-
moveCursorUp,
|
|
117
|
-
saveCursor,
|
|
118
|
-
restoreCursor,
|
|
119
|
-
renderHeaderWithStatus
|
|
120
|
-
};
|
|
1
|
+
const chalk = require('chalk');
|
|
2
|
+
const boxen = require('boxen');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Render a status card showing current requirement progress
|
|
6
|
+
* Similar to the purple card in the GUI
|
|
7
|
+
* @param {object} status - Current status object
|
|
8
|
+
* @param {string} status.requirement - Current requirement being worked on
|
|
9
|
+
* @param {string} status.step - Current step (PREPARE, ACT, CLEAN UP, VERIFY, DONE)
|
|
10
|
+
* @param {number} status.chatCount - Current chat count
|
|
11
|
+
* @param {number|null} status.maxChats - Maximum chats or null for unlimited
|
|
12
|
+
* @param {number} status.progress - Progress percentage (0-100)
|
|
13
|
+
* @returns {string} Formatted status card
|
|
14
|
+
*/
|
|
15
|
+
function renderStatusCard(status) {
|
|
16
|
+
const {
|
|
17
|
+
requirement = 'No requirement loaded',
|
|
18
|
+
step = 'UNKNOWN',
|
|
19
|
+
chatCount = 0,
|
|
20
|
+
maxChats = null,
|
|
21
|
+
progress = 0
|
|
22
|
+
} = status;
|
|
23
|
+
|
|
24
|
+
// Step color mapping
|
|
25
|
+
const stepColors = {
|
|
26
|
+
'PREPARE': chalk.cyan,
|
|
27
|
+
'ACT': chalk.yellow,
|
|
28
|
+
'CLEAN UP': chalk.magenta,
|
|
29
|
+
'VERIFY': chalk.blue,
|
|
30
|
+
'DONE': chalk.green,
|
|
31
|
+
'UNKNOWN': chalk.gray
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
const stepColor = stepColors[step] || chalk.gray;
|
|
35
|
+
|
|
36
|
+
// Progress bar
|
|
37
|
+
const barWidth = 30;
|
|
38
|
+
const filledWidth = Math.round((progress / 100) * barWidth);
|
|
39
|
+
const emptyWidth = barWidth - filledWidth;
|
|
40
|
+
const progressBar = chalk.green('█'.repeat(filledWidth)) + chalk.gray('░'.repeat(emptyWidth));
|
|
41
|
+
|
|
42
|
+
// Chat counter
|
|
43
|
+
const chatDisplay = maxChats
|
|
44
|
+
? `Chat ${chatCount}/${maxChats}`
|
|
45
|
+
: `Chat ${chatCount} (unlimited)`;
|
|
46
|
+
|
|
47
|
+
// Build card content
|
|
48
|
+
const content = [
|
|
49
|
+
chalk.bold('📋 Current Requirement'),
|
|
50
|
+
'',
|
|
51
|
+
chalk.white(requirement.length > 60 ? requirement.substring(0, 57) + '...' : requirement),
|
|
52
|
+
'',
|
|
53
|
+
chalk.bold('🚦 Status: ') + stepColor.bold(step),
|
|
54
|
+
'',
|
|
55
|
+
`${progressBar} ${progress}%`,
|
|
56
|
+
'',
|
|
57
|
+
chalk.gray(chatDisplay)
|
|
58
|
+
].join('\n');
|
|
59
|
+
|
|
60
|
+
// Render with boxen (purple/magenta border like the GUI)
|
|
61
|
+
return boxen(content, {
|
|
62
|
+
padding: 1,
|
|
63
|
+
margin: { top: 0, right: 0, bottom: 1, left: 0 },
|
|
64
|
+
borderStyle: 'round',
|
|
65
|
+
borderColor: 'magenta',
|
|
66
|
+
title: 'Auto Mode Status',
|
|
67
|
+
titleAlignment: 'center'
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Clear the terminal and move cursor to top
|
|
73
|
+
*/
|
|
74
|
+
function clearAndMoveToTop() {
|
|
75
|
+
// ANSI escape codes
|
|
76
|
+
process.stdout.write('\x1B[2J'); // Clear entire screen
|
|
77
|
+
process.stdout.write('\x1B[H'); // Move cursor to home (top-left)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Move cursor up N lines
|
|
82
|
+
* @param {number} lines - Number of lines to move up
|
|
83
|
+
*/
|
|
84
|
+
function moveCursorUp(lines) {
|
|
85
|
+
process.stdout.write(`\x1B[${lines}A`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Save cursor position
|
|
90
|
+
*/
|
|
91
|
+
function saveCursor() {
|
|
92
|
+
process.stdout.write('\x1B[s');
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Restore cursor position
|
|
97
|
+
*/
|
|
98
|
+
function restoreCursor() {
|
|
99
|
+
process.stdout.write('\x1B[u');
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Render the menu header and status card together
|
|
104
|
+
* @param {string} menuContent - The menu content to display
|
|
105
|
+
* @param {object} status - Status object for the status card
|
|
106
|
+
*/
|
|
107
|
+
function renderHeaderWithStatus(menuContent, status) {
|
|
108
|
+
clearAndMoveToTop();
|
|
109
|
+
console.log(menuContent);
|
|
110
|
+
console.log(renderStatusCard(status));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = {
|
|
114
|
+
renderStatusCard,
|
|
115
|
+
clearAndMoveToTop,
|
|
116
|
+
moveCursorUp,
|
|
117
|
+
saveCursor,
|
|
118
|
+
restoreCursor,
|
|
119
|
+
renderHeaderWithStatus
|
|
120
|
+
};
|