vibecodingmachine-cli 1.0.0

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.
Files changed (44) hide show
  1. package/.allnightai/REQUIREMENTS.md +11 -0
  2. package/.allnightai/temp/auto-status.json +6 -0
  3. package/.env +7 -0
  4. package/.eslintrc.js +16 -0
  5. package/README.md +85 -0
  6. package/bin/vibecodingmachine.js +274 -0
  7. package/jest.config.js +8 -0
  8. package/logs/audit/2025-11-07.jsonl +2 -0
  9. package/package.json +64 -0
  10. package/scripts/README.md +128 -0
  11. package/scripts/auto-start-wrapper.sh +92 -0
  12. package/scripts/postinstall.js +81 -0
  13. package/src/commands/auth.js +96 -0
  14. package/src/commands/auto-direct.js +1748 -0
  15. package/src/commands/auto.js +4692 -0
  16. package/src/commands/auto.js.bak +710 -0
  17. package/src/commands/ide.js +70 -0
  18. package/src/commands/repo.js +159 -0
  19. package/src/commands/requirements.js +161 -0
  20. package/src/commands/setup.js +91 -0
  21. package/src/commands/status.js +88 -0
  22. package/src/components/RequirementPage.js +0 -0
  23. package/src/file.js +0 -0
  24. package/src/index.js +5 -0
  25. package/src/main.js +0 -0
  26. package/src/ui/requirements-page.js +0 -0
  27. package/src/utils/auth.js +548 -0
  28. package/src/utils/auto-mode-ansi-ui.js +238 -0
  29. package/src/utils/auto-mode-simple-ui.js +161 -0
  30. package/src/utils/auto-mode-ui.js.bak.blessed +207 -0
  31. package/src/utils/auto-mode.js +65 -0
  32. package/src/utils/config.js +64 -0
  33. package/src/utils/interactive.js +3616 -0
  34. package/src/utils/keyboard-handler.js +152 -0
  35. package/src/utils/logger.js +4 -0
  36. package/src/utils/persistent-header.js +116 -0
  37. package/src/utils/provider-registry.js +128 -0
  38. package/src/utils/requirementUtils.js +0 -0
  39. package/src/utils/status-card.js +120 -0
  40. package/src/utils/status-manager.js +0 -0
  41. package/src/utils/status.js +0 -0
  42. package/src/utils/stdout-interceptor.js +127 -0
  43. package/tests/auto-mode.test.js +37 -0
  44. package/tests/config.test.js +34 -0
@@ -0,0 +1,152 @@
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
+
@@ -0,0 +1,4 @@
1
+ const { logger } = require('@vibecodingmachine/core');
2
+
3
+ // Re-export the logger from core for CLI use
4
+ module.exports = logger;
@@ -0,0 +1,116 @@
1
+ const chalk = require('chalk');
2
+
3
+ /**
4
+ * Simple persistent header that stays at top while content scrolls below
5
+ * Uses ANSI terminal control codes instead of blessed
6
+ */
7
+ class PersistentHeader {
8
+ constructor(lines = 10) {
9
+ this.headerLines = lines;
10
+ this.headerContent = '';
11
+ this.isActive = false;
12
+ }
13
+
14
+ /**
15
+ * Initialize the header by saving cursor and creating space
16
+ */
17
+ start() {
18
+ if (this.isActive) return;
19
+ this.isActive = true;
20
+
21
+ // Clear screen and move to top
22
+ process.stdout.write('\x1B[2J\x1B[H');
23
+
24
+ // Create space for header by printing empty lines
25
+ for (let i = 0; i < this.headerLines; i++) {
26
+ process.stdout.write('\n');
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Update the header content
32
+ * @param {string} content - New header content
33
+ */
34
+ update(content) {
35
+ if (!this.isActive) return;
36
+
37
+ this.headerContent = content;
38
+
39
+ // Save current cursor position
40
+ process.stdout.write('\x1B[s');
41
+
42
+ // Move to top of screen
43
+ process.stdout.write('\x1B[H');
44
+
45
+ // Clear the header area
46
+ for (let i = 0; i < this.headerLines; i++) {
47
+ process.stdout.write('\x1B[2K'); // Clear line
48
+ if (i < this.headerLines - 1) process.stdout.write('\n');
49
+ }
50
+
51
+ // Move back to top
52
+ process.stdout.write('\x1B[H');
53
+
54
+ // Write header content
55
+ process.stdout.write(content);
56
+
57
+ // Restore cursor position
58
+ process.stdout.write('\x1B[u');
59
+ }
60
+
61
+ /**
62
+ * Stop the persistent header
63
+ */
64
+ stop() {
65
+ if (!this.isActive) return;
66
+ this.isActive = false;
67
+ }
68
+ }
69
+
70
+ /**
71
+ * Format auto mode header
72
+ */
73
+ function formatAutoModeHeader(status) {
74
+ const {
75
+ requirement = 'No requirement',
76
+ step = 'PREPARE',
77
+ chatCount = 0,
78
+ maxChats = null,
79
+ progress = 0,
80
+ repoPath = '',
81
+ hostname = ''
82
+ } = status;
83
+
84
+ const stepColors = {
85
+ 'PREPARE': chalk.cyan,
86
+ 'ACT': chalk.yellow,
87
+ 'CLEAN UP': chalk.magenta,
88
+ 'VERIFY': chalk.blue,
89
+ 'DONE': chalk.green,
90
+ 'UNKNOWN': chalk.gray
91
+ };
92
+
93
+ const stepColor = stepColors[step] || chalk.gray;
94
+
95
+ const chatDisplay = maxChats
96
+ ? `Chat ${chatCount}/${maxChats}`
97
+ : `Chat ${chatCount} (unlimited)`;
98
+
99
+ const progressBar = chalk.green('█'.repeat(Math.floor(progress / 5))) +
100
+ chalk.gray('░'.repeat(20 - Math.floor(progress / 5)));
101
+
102
+ return `${chalk.cyan('━'.repeat(80))}
103
+ ${chalk.bold.cyan(' VibeCodingMachine Auto Mode')} ${chalk.gray('- Press Ctrl+C to stop')}
104
+ ${chalk.cyan('━'.repeat(80))}
105
+ ${chalk.bold(' Requirement:')} ${requirement.substring(0, 60)}
106
+ ${chalk.bold(' Status:')} ${stepColor(step)} ${chalk.bold('Progress:')} ${progressBar} ${progress}%
107
+ ${chalk.bold(' Chats:')} ${chatDisplay}
108
+ ${chalk.cyan('━'.repeat(80))}
109
+
110
+ `;
111
+ }
112
+
113
+ module.exports = {
114
+ PersistentHeader,
115
+ formatAutoModeHeader
116
+ };
@@ -0,0 +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
+
File without changes
@@ -0,0 +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
+ };
File without changes
File without changes
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Intercept stdout and stderr to capture console output
3
+ * Allows routing output to custom handlers (like blessed UI) while optionally preserving original output
4
+ */
5
+ class StdoutInterceptor {
6
+ constructor() {
7
+ this.originalStdoutWrite = null;
8
+ this.originalStderrWrite = null;
9
+ this.outputHandlers = [];
10
+ this.isIntercepting = false;
11
+ this.buffer = '<span style="color: white;">';
12
+ }
13
+
14
+ /**
15
+ * Add a handler that will receive output
16
+ * @param {function} handler - Function that receives output strings
17
+ */
18
+ addHandler(handler) {
19
+ this.outputHandlers.push(handler);
20
+ }
21
+
22
+ /**
23
+ * Remove a handler
24
+ * @param {function} handler - Handler to remove
25
+ */
26
+ removeHandler(handler) {
27
+ const index = this.outputHandlers.indexOf(handler);
28
+ if (index > -1) {
29
+ this.outputHandlers.splice(index, 1);
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Start intercepting stdout/stderr
35
+ * @param {boolean} passthrough - If true, still write to original stdout/stderr
36
+ */
37
+ start(passthrough = false) {
38
+ if (this.isIntercepting) {
39
+ return;
40
+ }
41
+
42
+ this.isIntercepting = true;
43
+
44
+ // Save original write functions
45
+ this.originalStdoutWrite = process.stdout.write;
46
+ this.originalStderrWrite = process.stderr.write;
47
+
48
+ // Intercept stdout
49
+ process.stdout.write = (chunk, encoding, callback) => {
50
+ const str = chunk.toString();
51
+
52
+ // Call all registered handlers
53
+ this.outputHandlers.forEach(handler => {
54
+ try {
55
+ handler(str);
56
+ } catch (error) {
57
+ // Silently ignore handler errors to prevent breaking the interceptor
58
+ }
59
+ });
60
+
61
+ // Optionally pass through to original stdout
62
+ if (passthrough && this.originalStdoutWrite) {
63
+ return this.originalStdoutWrite.call(process.stdout, chunk, encoding, callback);
64
+ }
65
+
66
+ // If not passing through, still call the callback if provided
67
+ if (typeof callback === 'function') {
68
+ callback();
69
+ }
70
+ return true;
71
+ };
72
+
73
+ // Intercept stderr
74
+ process.stderr.write = (chunk, encoding, callback) => {
75
+ const str = chunk.toString();
76
+
77
+ // Call all registered handlers
78
+ this.outputHandlers.forEach(handler => {
79
+ try {
80
+ handler(str);
81
+ } catch (error) {
82
+ // Silently ignore handler errors
83
+ }
84
+ });
85
+
86
+ // Optionally pass through to original stderr
87
+ if (passthrough && this.originalStderrWrite) {
88
+ return this.originalStderrWrite.call(process.stderr, chunk, encoding, callback);
89
+ }
90
+
91
+ // If not passing through, still call the callback if provided
92
+ if (typeof callback === 'function') {
93
+ callback();
94
+ }
95
+ return true;
96
+ };
97
+ }
98
+
99
+ /**
100
+ * Stop intercepting and restore original stdout/stderr
101
+ */
102
+ stop() {
103
+ if (!this.isIntercepting) {
104
+ return;
105
+ }
106
+
107
+ if (this.originalStdoutWrite) {
108
+ process.stdout.write = this.originalStdoutWrite;
109
+ }
110
+ if (this.originalStderrWrite) {
111
+ process.stderr.write = this.originalStderrWrite;
112
+ }
113
+
114
+ this.isIntercepting = false;
115
+ }
116
+
117
+ /**
118
+ * Clear all handlers
119
+ */
120
+ clearHandlers() {
121
+ this.outputHandlers = [];
122
+ }
123
+ }
124
+
125
+ module.exports = {
126
+ StdoutInterceptor
127
+ };
@@ -0,0 +1,37 @@
1
+ const os = require('os');
2
+ const path = require('path');
3
+ const fs = require('fs-extra');
4
+
5
+ describe('auto-mode utils', () => {
6
+ const tmpConfig = path.join(os.tmpdir(), `allnightai_test_config_${Date.now()}.json`);
7
+ const tmpRepo = path.join(os.tmpdir(), `allnightai_test_repo_${Date.now()}`);
8
+
9
+ beforeAll(async () => {
10
+ process.env.ALLNIGHTAI_CONFIG_PATH = tmpConfig;
11
+ await fs.ensureDir(path.join(tmpRepo, '.vibecodingmachine', 'temp'));
12
+ const { setRepoPath } = require('../src/utils/config');
13
+ await setRepoPath(tmpRepo);
14
+ });
15
+
16
+ afterAll(async () => {
17
+ delete process.env.ALLNIGHTAI_CONFIG_PATH;
18
+ await fs.remove(tmpConfig).catch(() => {});
19
+ await fs.remove(tmpRepo).catch(() => {});
20
+ });
21
+
22
+ test('start/stop and status', async () => {
23
+ const { startAutoMode, stopAutoMode, checkAutoModeStatus } = require('../src/utils/auto-mode');
24
+ const { getAutoConfig } = require('../src/utils/config');
25
+ await startAutoMode(tmpRepo, { ide: 'cursor' });
26
+ let status = await checkAutoModeStatus();
27
+ expect(status.running).toBe(true);
28
+ expect(status.ide).toBe('cursor');
29
+
30
+ await stopAutoMode();
31
+ status = await checkAutoModeStatus();
32
+ expect(status.running).toBe(false);
33
+ });
34
+ });
35
+
36
+
37
+