vibecodingmachine-core 1.0.0 → 1.0.1

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 (48) hide show
  1. package/.babelrc +13 -13
  2. package/README.md +28 -28
  3. package/__tests__/applescript-manager-claude-fix.test.js +286 -286
  4. package/__tests__/requirement-2-auto-start-looping.test.js +69 -69
  5. package/__tests__/requirement-3-auto-start-looping.test.js +69 -69
  6. package/__tests__/requirement-4-auto-start-looping.test.js +69 -69
  7. package/__tests__/requirement-6-auto-start-looping.test.js +73 -73
  8. package/__tests__/requirement-7-status-tracking.test.js +332 -332
  9. package/jest.config.js +18 -18
  10. package/jest.setup.js +12 -12
  11. package/package.json +47 -45
  12. package/src/auth/access-denied.html +119 -119
  13. package/src/auth/shared-auth-storage.js +230 -230
  14. package/src/autonomous-mode/feature-implementer.cjs +70 -70
  15. package/src/autonomous-mode/feature-implementer.js +425 -425
  16. package/src/chat-management/chat-manager.cjs +71 -71
  17. package/src/chat-management/chat-manager.js +342 -342
  18. package/src/ide-integration/__tests__/applescript-manager-thread-closure.test.js +227 -227
  19. package/src/ide-integration/aider-cli-manager.cjs +850 -850
  20. package/src/ide-integration/applescript-manager.cjs +1088 -1088
  21. package/src/ide-integration/applescript-manager.js +2802 -2802
  22. package/src/ide-integration/applescript-utils.js +306 -306
  23. package/src/ide-integration/cdp-manager.cjs +221 -221
  24. package/src/ide-integration/cdp-manager.js +321 -321
  25. package/src/ide-integration/claude-code-cli-manager.cjs +301 -301
  26. package/src/ide-integration/cline-cli-manager.cjs +2252 -2252
  27. package/src/ide-integration/continue-cli-manager.js +431 -431
  28. package/src/ide-integration/provider-manager.cjs +354 -354
  29. package/src/ide-integration/quota-detector.cjs +34 -34
  30. package/src/ide-integration/quota-detector.js +349 -349
  31. package/src/ide-integration/windows-automation-manager.js +262 -262
  32. package/src/index.cjs +43 -43
  33. package/src/index.js +17 -17
  34. package/src/llm/direct-llm-manager.cjs +609 -609
  35. package/src/ui/ButtonComponents.js +247 -247
  36. package/src/ui/ChatInterface.js +499 -499
  37. package/src/ui/StateManager.js +259 -259
  38. package/src/utils/audit-logger.cjs +116 -116
  39. package/src/utils/config-helpers.cjs +94 -94
  40. package/src/utils/config-helpers.js +94 -94
  41. package/src/utils/electron-update-checker.js +85 -78
  42. package/src/utils/gcloud-auth.cjs +394 -394
  43. package/src/utils/logger.cjs +193 -193
  44. package/src/utils/logger.js +191 -191
  45. package/src/utils/repo-helpers.cjs +120 -120
  46. package/src/utils/repo-helpers.js +120 -120
  47. package/src/utils/requirement-helpers.js +432 -432
  48. package/src/utils/update-checker.js +167 -167
@@ -1,431 +1,431 @@
1
- /**
2
- * Continue CLI Manager - Handles Continue CLI integration for auto mode
3
- * Shared between Electron app and CLI package for DRY code
4
- */
5
-
6
- const path = require('path');
7
- const os = require('os');
8
-
9
- /**
10
- * Run Continue CLI command with PTY support
11
- * @param {string} repoPath - Repository path
12
- * @param {string} prompt - Prompt to send to Continue CLI
13
- * @param {string} reqFilename - Requirements filename (e.g., REQUIREMENTS-hostname.md)
14
- * @returns {Promise<{success: boolean, output: string, error?: string, hasError?: boolean, exitCode?: number}>}
15
- */
16
- async function runContinueCLICommand(repoPath, prompt, reqFilename) {
17
- return new Promise((resolve) => {
18
- // Try to use node-pty for PTY support (required for Continue CLI's Ink UI)
19
- let pty;
20
- try {
21
- pty = require('node-pty');
22
- } catch (error) {
23
- // node-pty not available, fall back to regular spawn
24
- }
25
-
26
- const command = 'cn';
27
- const configPath = path.join(os.homedir(), '.continue', 'config.yaml');
28
-
29
- // Prepend working directory context to prompt so Continue CLI knows where to find files
30
- const promptWithContext = `IMPORTANT: You are working in the repository at: ${repoPath}
31
-
32
- All file paths should be relative to this directory. The .vibecodingmachine directory is located at: ${path.join(repoPath, '.vibecodingmachine')}
33
-
34
- The requirements file for this computer is: .vibecodingmachine/${reqFilename}
35
-
36
- CRITICAL FILE OPERATIONS:
37
- - Use the "Read" tool to read local files (NOT the Fetch tool - Fetch is only for URLs)
38
- - Use the "Write" tool to write local files
39
- - File paths are local filesystem paths, NOT URLs
40
- - Example: To read the requirements file, use: Read(.vibecodingmachine/${reqFilename})
41
- - DO NOT use Fetch for local files - Fetch is only for HTTP/HTTPS URLs
42
-
43
- ${prompt}`;
44
-
45
- // Try headless mode (-p) for better autonomous execution
46
- // The --auto flag doesn't seem to execute, it just analyzes
47
- const args = ['-p', promptWithContext, '--config', configPath];
48
-
49
- let output = '';
50
- let errorOutput = '';
51
-
52
- console.log('\n─────────────────────────────────────────────────────────');
53
- console.log('Continue CLI Output:');
54
- console.log('─────────────────────────────────────────────────────────');
55
- console.log('\n⚠️ Note: Do not type in the terminal while Continue CLI is running.');
56
- console.log(' Your input will be sent to Continue CLI and may interfere with auto mode.\n');
57
-
58
- let proc;
59
-
60
- // With -p (headless) mode, we might not need PTY, but let's try PTY first
61
- // If it fails, we'll fall back to regular spawn
62
- if (pty) {
63
- // Use PTY for Continue CLI (may still be needed even in headless mode)
64
- proc = pty.spawn(command, args, {
65
- name: 'xterm-color',
66
- cols: 120,
67
- rows: 30,
68
- cwd: repoPath,
69
- env: process.env
70
- });
71
-
72
- // Track output to detect if Continue CLI is idle/waiting
73
- let lastOutputTime = Date.now();
74
- const maxIdleTime = 30000; // 30 seconds max idle time (reduced from 1 minute)
75
- let idleCheckInterval;
76
- let promptDetected = false;
77
- let promptCheckTimeout;
78
-
79
- // PTY uses onData instead of stdout.on('data')
80
- proc.onData((data) => {
81
- output += data;
82
- process.stdout.write(data);
83
- lastOutputTime = Date.now(); // Update last output time
84
-
85
- // Detect if Continue CLI is showing the interactive prompt
86
- const dataStr = data.toString();
87
- if (dataStr.includes('[⏵⏵ auto]') || dataStr.includes('Ask anything') ||
88
- dataStr.includes('Context:') || (dataStr.includes('auto') && dataStr.includes('Continue CLI'))) {
89
- if (!promptDetected) {
90
- promptDetected = true;
91
- // Wait for prompt to fully render, then send a command to make it proceed
92
- promptCheckTimeout = setTimeout(() => {
93
- const timeSinceLastOutput = Date.now() - lastOutputTime;
94
- // If no output for 3 seconds after prompt, send a command to proceed
95
- if (timeSinceLastOutput > 3000) {
96
- console.log('\n📤 Sending command to Continue CLI to proceed with implementation...\n');
97
- // Send a command to Continue CLI to actually work on the requirement
98
- try {
99
- // Send a direct command to proceed with implementation
100
- const proceedCommand = 'Implement the requirement. Read the REQUIREMENTS file, work through PREPARE → ACT → CLEAN UP → VERIFY → DONE stages, and update the REQUIREMENTS file at each stage using the Write tool.\n';
101
- proc.write(proceedCommand);
102
- lastOutputTime = Date.now(); // Reset timer since we sent input
103
- } catch (error) {
104
- console.log('\n⚠️ Could not send command to Continue CLI:', error.message);
105
- console.log(' Stopping Continue CLI process...\n');
106
- proc.kill();
107
- if (idleCheckInterval) clearInterval(idleCheckInterval);
108
- }
109
- }
110
- }, 3000); // Wait 3 seconds after prompt detection before sending command
111
- }
112
- }
113
- });
114
-
115
- // Set up idle detection - kill if no output for too long
116
- const checkIdle = () => {
117
- const timeSinceLastOutput = Date.now() - lastOutputTime;
118
- if (timeSinceLastOutput > maxIdleTime) {
119
- console.log('\n⚠️ Continue CLI has been idle for too long. It may be waiting for input.');
120
- console.log(' Stopping Continue CLI process...\n');
121
- proc.kill();
122
- clearInterval(idleCheckInterval);
123
- if (promptCheckTimeout) clearTimeout(promptCheckTimeout);
124
- }
125
- };
126
-
127
- // Start idle checking every 5 seconds (very frequent)
128
- idleCheckInterval = setInterval(checkIdle, 5000);
129
-
130
- proc.onExit(({ exitCode }) => {
131
- // Clean up idle checker and timeout
132
- if (idleCheckInterval) {
133
- clearInterval(idleCheckInterval);
134
- }
135
- if (promptCheckTimeout) {
136
- clearTimeout(promptCheckTimeout);
137
- }
138
-
139
- const fullOutput = output;
140
- console.log('\n─────────────────────────────────────────────────────────\n');
141
-
142
- // Check for common errors
143
- const hasAnthropicError = fullOutput.includes('ANTHROPIC_API_KEY') || fullOutput.includes('404');
144
- const hasAuthError = fullOutput.includes('authentication') && fullOutput.includes('error');
145
-
146
- if (hasAnthropicError) {
147
- console.log('\n⚠️ Continue CLI could not find Ollama configuration.');
148
- console.log(' Please ensure:');
149
- console.log(' 1. Ollama is running (ollama serve)');
150
- console.log(' 2. ~/.continue/config.yaml is configured with Ollama models');
151
- console.log(' 3. Models are downloaded (ollama pull model-name)\n');
152
- }
153
-
154
- resolve({
155
- success: !hasAnthropicError && !hasAuthError,
156
- output: fullOutput,
157
- exitCode: exitCode,
158
- hasError: hasAnthropicError || hasAuthError
159
- });
160
- });
161
- } else {
162
- // Fallback to regular spawn (without PTY)
163
- const { spawn } = require('child_process');
164
- proc = spawn(command, args, {
165
- cwd: repoPath,
166
- stdio: ['pipe', 'pipe', 'pipe']
167
- });
168
-
169
- // Close stdin immediately since we're not interactive
170
- proc.stdin.end();
171
-
172
- proc.stdout.on('data', (data) => {
173
- output += data.toString();
174
- process.stdout.write(data);
175
- });
176
-
177
- proc.stderr.on('data', (data) => {
178
- errorOutput += data.toString();
179
- process.stderr.write(data);
180
- });
181
-
182
- proc.on('close', (code) => {
183
- console.log('\n─────────────────────────────────────────────────────────\n');
184
-
185
- // Check for errors
186
- const fullOutput = output + errorOutput;
187
- const hasAnthropicError = fullOutput.includes('ANTHROPIC_API_KEY') || fullOutput.includes('404');
188
- const hasAuthError = fullOutput.includes('authentication') && fullOutput.includes('error');
189
- const hasRawModeError = fullOutput.includes('Raw mode is not supported');
190
-
191
- if (hasRawModeError) {
192
- console.log('\n⚠️ Continue CLI requires PTY support (node-pty package).');
193
- console.log(' Install with: npm install node-pty\n');
194
- } else if (hasAnthropicError) {
195
- console.log('\n⚠️ Continue CLI could not find Ollama configuration.');
196
- console.log(' Please ensure:');
197
- console.log(' 1. Ollama is running (ollama serve)');
198
- console.log(' 2. ~/.continue/config.yaml is configured with Ollama models');
199
- console.log(' 3. Models are downloaded (ollama pull model-name)\n');
200
- }
201
-
202
- resolve({
203
- success: code === 0 && !hasAnthropicError && !hasAuthError && !hasRawModeError,
204
- output: fullOutput,
205
- error: code !== 0 ? errorOutput : undefined,
206
- exitCode: code,
207
- hasError: hasAnthropicError || hasAuthError || hasRawModeError
208
- });
209
- });
210
-
211
- proc.on('error', (error) => {
212
- console.log('\n─────────────────────────────────────────────────────────\n');
213
- console.log(`\n✗ Failed to start Continue CLI: ${error.message}\n`);
214
-
215
- if (error.code === 'ENOENT') {
216
- console.log(' Continue CLI (cn command) not found.');
217
- console.log(' Install with: npm install -g @continuedev/continue-cli\n');
218
- }
219
-
220
- resolve({
221
- success: false,
222
- output: '',
223
- error: error.message,
224
- hasError: true
225
- });
226
- });
227
- }
228
- });
229
- }
230
-
231
- /**
232
- * Run Continue CLI in auto mode loop
233
- * @param {string} repoPath - Repository path
234
- * @param {string} initialPrompt - Initial prompt to send
235
- * @param {object} config - Auto mode configuration
236
- * @param {string} config.ide - IDE type ('continue')
237
- * @param {number|null} config.maxChats - Maximum chats (null for unlimited)
238
- * @param {boolean} config.neverStop - Never stop flag
239
- * @param {function} updateAutoModeStatus - Callback to update auto mode status
240
- * @param {function} isRequirementDone - Callback to check if requirement is done
241
- * @param {function} moveToNextRequirement - Callback to move to next requirement
242
- * @returns {Promise<void>}
243
- */
244
- async function runContinueCLIAutoMode(repoPath, initialPrompt, config, callbacks) {
245
- const { updateAutoModeStatus, isRequirementDone, moveToNextRequirement } = callbacks;
246
- const { getRequirementsPath } = require('../utils/repo-helpers.cjs');
247
- const fs = require('fs-extra');
248
-
249
- let chatCount = 0;
250
- let currentPrompt = initialPrompt;
251
- const maxChats = config.maxChats || 100;
252
- const neverStop = config.neverStop || false;
253
- let exitReason = 'completed';
254
-
255
- console.log(' Auto mode will continue until DONE status is reached');
256
- console.log(` Max chats: ${neverStop ? 'unlimited' : maxChats}`);
257
- console.log();
258
-
259
- while (true) {
260
- // Check max chats
261
- if (!neverStop && chatCount >= maxChats) {
262
- console.log(`\n⏹️ Reached max chats limit (${maxChats})`);
263
- exitReason = 'max-chats';
264
- break;
265
- }
266
-
267
- chatCount++;
268
- console.log(`\n📝 Chat ${chatCount}${neverStop ? '' : `/${maxChats}`}: ${currentPrompt.substring(0, 60)}${currentPrompt.length > 60 ? '...' : ''}`);
269
- console.log(' Running Continue CLI...\n');
270
-
271
- // Update auto mode status
272
- await updateAutoModeStatus(repoPath, { chatCount });
273
-
274
- // Get the computer-specific requirements filename
275
- const reqPath = await getRequirementsPath(repoPath);
276
- const reqFilename = path.basename(reqPath);
277
-
278
- // Read current requirement and status from REQUIREMENTS file
279
- let currentRequirementText = '';
280
- let currentStatus = '';
281
- try {
282
- if (await fs.pathExists(reqPath)) {
283
- const content = await fs.readFile(reqPath, 'utf8');
284
- const lines = content.split('\n');
285
-
286
- // Find current in-progress requirement
287
- let inProgressSection = false;
288
- for (let i = 0; i < lines.length; i++) {
289
- if (lines[i].includes('## 🔨 Current In Progress Requirement')) {
290
- inProgressSection = true;
291
- continue;
292
- }
293
- if (inProgressSection && lines[i].trim().startsWith('- ')) {
294
- currentRequirementText = lines[i].substring(2).trim();
295
- break;
296
- }
297
- if (inProgressSection && lines[i].startsWith('##')) {
298
- break;
299
- }
300
- }
301
-
302
- // Find current status
303
- for (let i = 0; i < lines.length; i++) {
304
- if (lines[i].includes('## 🚦 Current Status')) {
305
- for (let j = i + 1; j < lines.length; j++) {
306
- const statusLine = lines[j].trim();
307
- if (statusLine && !statusLine.startsWith('#')) {
308
- currentStatus = statusLine;
309
- break;
310
- }
311
- }
312
- break;
313
- }
314
- }
315
- }
316
- } catch (error) {
317
- // Continue without current requirement if file read fails
318
- }
319
-
320
- // Build enhanced prompt with current requirement context
321
- const enhancedPrompt = currentRequirementText ?
322
- `${currentPrompt}
323
-
324
- 🚨 FOCUS: You MUST work ONLY on this ONE requirement:
325
-
326
- "${currentRequirementText}"
327
-
328
- CURRENT STATUS: ${currentStatus || 'PREPARE'}
329
-
330
- ⚠️ CRITICAL - DO NOT SUMMARIZE OR ANALYZE OTHER REQUIREMENTS:
331
- - IGNORE all other requirements in the REQUIREMENTS file
332
- - IGNORE completed requirements, CHANGELOG entries, and other sections
333
- - FOCUS EXCLUSIVELY on implementing the requirement listed above
334
- - DO NOT read the entire REQUIREMENTS file and summarize it
335
- - Read ONLY the specific sections you need to understand the current requirement
336
-
337
- 🚨 STEP-BY-STEP WORKFLOW:
338
- 1. Read INSTRUCTIONS.md (.vibecodingmachine/INSTRUCTIONS.md) to understand the workflow
339
- 2. Read ONLY the "🔨 Current In Progress Requirement" section from REQUIREMENTS file to see the current requirement
340
- 3. Read ONLY the "🚦 Current Status" section to see the current status
341
- 4. Start working on "${currentRequirementText}" based on the current status:
342
- - If status is PREPARE: Start planning and preparing
343
- - If status is ACT: Start implementing the code
344
- - If status is CLEAN UP: Clean up code, remove duplicates, apply DRY
345
- - If status is VERIFY: Test and verify the implementation
346
- - If status is DONE: Stop immediately (work is complete)
347
- 5. At EACH stage transition, use the Write tool to UPDATE the REQUIREMENTS file:
348
- - Set "🚦 Current Status" to the NEXT stage (PREPARE → ACT → CLEAN UP → VERIFY → DONE)
349
- - Update the "RESPONSE FROM LAST CHAT" section with what you accomplished
350
- 6. Continue until status is DONE
351
- 7. You have FULL WRITE ACCESS - use Write tool to update the REQUIREMENTS file
352
-
353
- REMEMBER: You are working on ONE requirement: "${currentRequirementText}". Ignore everything else.` :
354
- currentPrompt;
355
-
356
- // Run Continue CLI command with enhanced prompt
357
- const result = await runContinueCLICommand(repoPath, enhancedPrompt, reqFilename);
358
-
359
- if (result.hasError || (!result.success && result.error)) {
360
- console.log(`\n✗ Continue CLI encountered an error: ${result.error || 'Unknown error'}`);
361
- if (result.hasError) {
362
- console.log('\n⚠️ Please fix the configuration issue and try again.');
363
- }
364
- exitReason = 'error';
365
- break;
366
- }
367
-
368
- console.log('\n✓ Continue CLI completed');
369
-
370
- // Wait a moment for file system to sync
371
- await new Promise(resolve => setTimeout(resolve, 2000));
372
-
373
- // Check if requirement is DONE
374
- const isDone = await isRequirementDone(repoPath);
375
-
376
- if (isDone) {
377
- console.log('\n✅ Requirement marked as DONE!');
378
-
379
- // Move to next requirement
380
- const moveResult = await moveToNextRequirement(repoPath);
381
-
382
- if (!moveResult.success) {
383
- console.log(`\n⚠️ ${moveResult.error}`);
384
- console.log(' Auto mode stopping.');
385
- exitReason = 'error';
386
- break;
387
- }
388
-
389
- console.log(`\n🔄 Moving to next requirement: ${moveResult.nextRequirement}`);
390
-
391
- // Prepare next prompt
392
- currentPrompt = initialPrompt;
393
-
394
- // Wait a moment before next iteration
395
- await new Promise(resolve => setTimeout(resolve, 1000));
396
- } else {
397
- console.log('\n⚠️ Requirement not yet DONE. Continue CLI may still be working or needs to update status.');
398
- console.log(' Waiting for DONE status before continuing...');
399
-
400
- // Wait longer before checking again
401
- await new Promise(resolve => setTimeout(resolve, 5000));
402
-
403
- // Check again
404
- const stillNotDone = !(await isRequirementDone(repoPath));
405
- if (stillNotDone) {
406
- console.log('\n⚠️ Status still not DONE after waiting. Moving to next iteration.');
407
-
408
- // Move to next requirement anyway
409
- const moveResult = await moveToNextRequirement(repoPath);
410
-
411
- if (!moveResult.success) {
412
- console.log(`\n⚠️ ${moveResult.error}`);
413
- console.log(' Auto mode stopping.');
414
- break;
415
- }
416
-
417
- console.log(`\n🔄 Moving to next requirement: ${moveResult.nextRequirement}`);
418
- currentPrompt = initialPrompt;
419
- await new Promise(resolve => setTimeout(resolve, 1000));
420
- }
421
- }
422
- }
423
-
424
- console.log(`\n🏁 Auto mode completed. Processed ${chatCount} chat(s).`);
425
- return { exitReason, chatCount };
426
- }
427
-
428
- module.exports = {
429
- runContinueCLICommand,
430
- runContinueCLIAutoMode
431
- };
1
+ /**
2
+ * Continue CLI Manager - Handles Continue CLI integration for auto mode
3
+ * Shared between Electron app and CLI package for DRY code
4
+ */
5
+
6
+ const path = require('path');
7
+ const os = require('os');
8
+
9
+ /**
10
+ * Run Continue CLI command with PTY support
11
+ * @param {string} repoPath - Repository path
12
+ * @param {string} prompt - Prompt to send to Continue CLI
13
+ * @param {string} reqFilename - Requirements filename (e.g., REQUIREMENTS-hostname.md)
14
+ * @returns {Promise<{success: boolean, output: string, error?: string, hasError?: boolean, exitCode?: number}>}
15
+ */
16
+ async function runContinueCLICommand(repoPath, prompt, reqFilename) {
17
+ return new Promise((resolve) => {
18
+ // Try to use node-pty for PTY support (required for Continue CLI's Ink UI)
19
+ let pty;
20
+ try {
21
+ pty = require('node-pty');
22
+ } catch (error) {
23
+ // node-pty not available, fall back to regular spawn
24
+ }
25
+
26
+ const command = 'cn';
27
+ const configPath = path.join(os.homedir(), '.continue', 'config.yaml');
28
+
29
+ // Prepend working directory context to prompt so Continue CLI knows where to find files
30
+ const promptWithContext = `IMPORTANT: You are working in the repository at: ${repoPath}
31
+
32
+ All file paths should be relative to this directory. The .vibecodingmachine directory is located at: ${path.join(repoPath, '.vibecodingmachine')}
33
+
34
+ The requirements file for this computer is: .vibecodingmachine/${reqFilename}
35
+
36
+ CRITICAL FILE OPERATIONS:
37
+ - Use the "Read" tool to read local files (NOT the Fetch tool - Fetch is only for URLs)
38
+ - Use the "Write" tool to write local files
39
+ - File paths are local filesystem paths, NOT URLs
40
+ - Example: To read the requirements file, use: Read(.vibecodingmachine/${reqFilename})
41
+ - DO NOT use Fetch for local files - Fetch is only for HTTP/HTTPS URLs
42
+
43
+ ${prompt}`;
44
+
45
+ // Try headless mode (-p) for better autonomous execution
46
+ // The --auto flag doesn't seem to execute, it just analyzes
47
+ const args = ['-p', promptWithContext, '--config', configPath];
48
+
49
+ let output = '';
50
+ let errorOutput = '';
51
+
52
+ console.log('\n─────────────────────────────────────────────────────────');
53
+ console.log('Continue CLI Output:');
54
+ console.log('─────────────────────────────────────────────────────────');
55
+ console.log('\n⚠️ Note: Do not type in the terminal while Continue CLI is running.');
56
+ console.log(' Your input will be sent to Continue CLI and may interfere with auto mode.\n');
57
+
58
+ let proc;
59
+
60
+ // With -p (headless) mode, we might not need PTY, but let's try PTY first
61
+ // If it fails, we'll fall back to regular spawn
62
+ if (pty) {
63
+ // Use PTY for Continue CLI (may still be needed even in headless mode)
64
+ proc = pty.spawn(command, args, {
65
+ name: 'xterm-color',
66
+ cols: 120,
67
+ rows: 30,
68
+ cwd: repoPath,
69
+ env: process.env
70
+ });
71
+
72
+ // Track output to detect if Continue CLI is idle/waiting
73
+ let lastOutputTime = Date.now();
74
+ const maxIdleTime = 30000; // 30 seconds max idle time (reduced from 1 minute)
75
+ let idleCheckInterval;
76
+ let promptDetected = false;
77
+ let promptCheckTimeout;
78
+
79
+ // PTY uses onData instead of stdout.on('data')
80
+ proc.onData((data) => {
81
+ output += data;
82
+ process.stdout.write(data);
83
+ lastOutputTime = Date.now(); // Update last output time
84
+
85
+ // Detect if Continue CLI is showing the interactive prompt
86
+ const dataStr = data.toString();
87
+ if (dataStr.includes('[⏵⏵ auto]') || dataStr.includes('Ask anything') ||
88
+ dataStr.includes('Context:') || (dataStr.includes('auto') && dataStr.includes('Continue CLI'))) {
89
+ if (!promptDetected) {
90
+ promptDetected = true;
91
+ // Wait for prompt to fully render, then send a command to make it proceed
92
+ promptCheckTimeout = setTimeout(() => {
93
+ const timeSinceLastOutput = Date.now() - lastOutputTime;
94
+ // If no output for 3 seconds after prompt, send a command to proceed
95
+ if (timeSinceLastOutput > 3000) {
96
+ console.log('\n📤 Sending command to Continue CLI to proceed with implementation...\n');
97
+ // Send a command to Continue CLI to actually work on the requirement
98
+ try {
99
+ // Send a direct command to proceed with implementation
100
+ const proceedCommand = 'Implement the requirement. Read the REQUIREMENTS file, work through PREPARE → ACT → CLEAN UP → VERIFY → DONE stages, and update the REQUIREMENTS file at each stage using the Write tool.\n';
101
+ proc.write(proceedCommand);
102
+ lastOutputTime = Date.now(); // Reset timer since we sent input
103
+ } catch (error) {
104
+ console.log('\n⚠️ Could not send command to Continue CLI:', error.message);
105
+ console.log(' Stopping Continue CLI process...\n');
106
+ proc.kill();
107
+ if (idleCheckInterval) clearInterval(idleCheckInterval);
108
+ }
109
+ }
110
+ }, 3000); // Wait 3 seconds after prompt detection before sending command
111
+ }
112
+ }
113
+ });
114
+
115
+ // Set up idle detection - kill if no output for too long
116
+ const checkIdle = () => {
117
+ const timeSinceLastOutput = Date.now() - lastOutputTime;
118
+ if (timeSinceLastOutput > maxIdleTime) {
119
+ console.log('\n⚠️ Continue CLI has been idle for too long. It may be waiting for input.');
120
+ console.log(' Stopping Continue CLI process...\n');
121
+ proc.kill();
122
+ clearInterval(idleCheckInterval);
123
+ if (promptCheckTimeout) clearTimeout(promptCheckTimeout);
124
+ }
125
+ };
126
+
127
+ // Start idle checking every 5 seconds (very frequent)
128
+ idleCheckInterval = setInterval(checkIdle, 5000);
129
+
130
+ proc.onExit(({ exitCode }) => {
131
+ // Clean up idle checker and timeout
132
+ if (idleCheckInterval) {
133
+ clearInterval(idleCheckInterval);
134
+ }
135
+ if (promptCheckTimeout) {
136
+ clearTimeout(promptCheckTimeout);
137
+ }
138
+
139
+ const fullOutput = output;
140
+ console.log('\n─────────────────────────────────────────────────────────\n');
141
+
142
+ // Check for common errors
143
+ const hasAnthropicError = fullOutput.includes('ANTHROPIC_API_KEY') || fullOutput.includes('404');
144
+ const hasAuthError = fullOutput.includes('authentication') && fullOutput.includes('error');
145
+
146
+ if (hasAnthropicError) {
147
+ console.log('\n⚠️ Continue CLI could not find Ollama configuration.');
148
+ console.log(' Please ensure:');
149
+ console.log(' 1. Ollama is running (ollama serve)');
150
+ console.log(' 2. ~/.continue/config.yaml is configured with Ollama models');
151
+ console.log(' 3. Models are downloaded (ollama pull model-name)\n');
152
+ }
153
+
154
+ resolve({
155
+ success: !hasAnthropicError && !hasAuthError,
156
+ output: fullOutput,
157
+ exitCode: exitCode,
158
+ hasError: hasAnthropicError || hasAuthError
159
+ });
160
+ });
161
+ } else {
162
+ // Fallback to regular spawn (without PTY)
163
+ const { spawn } = require('child_process');
164
+ proc = spawn(command, args, {
165
+ cwd: repoPath,
166
+ stdio: ['pipe', 'pipe', 'pipe']
167
+ });
168
+
169
+ // Close stdin immediately since we're not interactive
170
+ proc.stdin.end();
171
+
172
+ proc.stdout.on('data', (data) => {
173
+ output += data.toString();
174
+ process.stdout.write(data);
175
+ });
176
+
177
+ proc.stderr.on('data', (data) => {
178
+ errorOutput += data.toString();
179
+ process.stderr.write(data);
180
+ });
181
+
182
+ proc.on('close', (code) => {
183
+ console.log('\n─────────────────────────────────────────────────────────\n');
184
+
185
+ // Check for errors
186
+ const fullOutput = output + errorOutput;
187
+ const hasAnthropicError = fullOutput.includes('ANTHROPIC_API_KEY') || fullOutput.includes('404');
188
+ const hasAuthError = fullOutput.includes('authentication') && fullOutput.includes('error');
189
+ const hasRawModeError = fullOutput.includes('Raw mode is not supported');
190
+
191
+ if (hasRawModeError) {
192
+ console.log('\n⚠️ Continue CLI requires PTY support (node-pty package).');
193
+ console.log(' Install with: npm install node-pty\n');
194
+ } else if (hasAnthropicError) {
195
+ console.log('\n⚠️ Continue CLI could not find Ollama configuration.');
196
+ console.log(' Please ensure:');
197
+ console.log(' 1. Ollama is running (ollama serve)');
198
+ console.log(' 2. ~/.continue/config.yaml is configured with Ollama models');
199
+ console.log(' 3. Models are downloaded (ollama pull model-name)\n');
200
+ }
201
+
202
+ resolve({
203
+ success: code === 0 && !hasAnthropicError && !hasAuthError && !hasRawModeError,
204
+ output: fullOutput,
205
+ error: code !== 0 ? errorOutput : undefined,
206
+ exitCode: code,
207
+ hasError: hasAnthropicError || hasAuthError || hasRawModeError
208
+ });
209
+ });
210
+
211
+ proc.on('error', (error) => {
212
+ console.log('\n─────────────────────────────────────────────────────────\n');
213
+ console.log(`\n✗ Failed to start Continue CLI: ${error.message}\n`);
214
+
215
+ if (error.code === 'ENOENT') {
216
+ console.log(' Continue CLI (cn command) not found.');
217
+ console.log(' Install with: npm install -g @continuedev/continue-cli\n');
218
+ }
219
+
220
+ resolve({
221
+ success: false,
222
+ output: '',
223
+ error: error.message,
224
+ hasError: true
225
+ });
226
+ });
227
+ }
228
+ });
229
+ }
230
+
231
+ /**
232
+ * Run Continue CLI in auto mode loop
233
+ * @param {string} repoPath - Repository path
234
+ * @param {string} initialPrompt - Initial prompt to send
235
+ * @param {object} config - Auto mode configuration
236
+ * @param {string} config.ide - IDE type ('continue')
237
+ * @param {number|null} config.maxChats - Maximum chats (null for unlimited)
238
+ * @param {boolean} config.neverStop - Never stop flag
239
+ * @param {function} updateAutoModeStatus - Callback to update auto mode status
240
+ * @param {function} isRequirementDone - Callback to check if requirement is done
241
+ * @param {function} moveToNextRequirement - Callback to move to next requirement
242
+ * @returns {Promise<void>}
243
+ */
244
+ async function runContinueCLIAutoMode(repoPath, initialPrompt, config, callbacks) {
245
+ const { updateAutoModeStatus, isRequirementDone, moveToNextRequirement } = callbacks;
246
+ const { getRequirementsPath } = require('../utils/repo-helpers.cjs');
247
+ const fs = require('fs-extra');
248
+
249
+ let chatCount = 0;
250
+ let currentPrompt = initialPrompt;
251
+ const maxChats = config.maxChats || 100;
252
+ const neverStop = config.neverStop || false;
253
+ let exitReason = 'completed';
254
+
255
+ console.log(' Auto mode will continue until DONE status is reached');
256
+ console.log(` Max chats: ${neverStop ? 'unlimited' : maxChats}`);
257
+ console.log();
258
+
259
+ while (true) {
260
+ // Check max chats
261
+ if (!neverStop && chatCount >= maxChats) {
262
+ console.log(`\n⏹️ Reached max chats limit (${maxChats})`);
263
+ exitReason = 'max-chats';
264
+ break;
265
+ }
266
+
267
+ chatCount++;
268
+ console.log(`\n📝 Chat ${chatCount}${neverStop ? '' : `/${maxChats}`}: ${currentPrompt.substring(0, 60)}${currentPrompt.length > 60 ? '...' : ''}`);
269
+ console.log(' Running Continue CLI...\n');
270
+
271
+ // Update auto mode status
272
+ await updateAutoModeStatus(repoPath, { chatCount });
273
+
274
+ // Get the computer-specific requirements filename
275
+ const reqPath = await getRequirementsPath(repoPath);
276
+ const reqFilename = path.basename(reqPath);
277
+
278
+ // Read current requirement and status from REQUIREMENTS file
279
+ let currentRequirementText = '';
280
+ let currentStatus = '';
281
+ try {
282
+ if (await fs.pathExists(reqPath)) {
283
+ const content = await fs.readFile(reqPath, 'utf8');
284
+ const lines = content.split('\n');
285
+
286
+ // Find current in-progress requirement
287
+ let inProgressSection = false;
288
+ for (let i = 0; i < lines.length; i++) {
289
+ if (lines[i].includes('## 🔨 Current In Progress Requirement')) {
290
+ inProgressSection = true;
291
+ continue;
292
+ }
293
+ if (inProgressSection && lines[i].trim().startsWith('- ')) {
294
+ currentRequirementText = lines[i].substring(2).trim();
295
+ break;
296
+ }
297
+ if (inProgressSection && lines[i].startsWith('##')) {
298
+ break;
299
+ }
300
+ }
301
+
302
+ // Find current status
303
+ for (let i = 0; i < lines.length; i++) {
304
+ if (lines[i].includes('## 🚦 Current Status')) {
305
+ for (let j = i + 1; j < lines.length; j++) {
306
+ const statusLine = lines[j].trim();
307
+ if (statusLine && !statusLine.startsWith('#')) {
308
+ currentStatus = statusLine;
309
+ break;
310
+ }
311
+ }
312
+ break;
313
+ }
314
+ }
315
+ }
316
+ } catch (error) {
317
+ // Continue without current requirement if file read fails
318
+ }
319
+
320
+ // Build enhanced prompt with current requirement context
321
+ const enhancedPrompt = currentRequirementText ?
322
+ `${currentPrompt}
323
+
324
+ 🚨 FOCUS: You MUST work ONLY on this ONE requirement:
325
+
326
+ "${currentRequirementText}"
327
+
328
+ CURRENT STATUS: ${currentStatus || 'PREPARE'}
329
+
330
+ ⚠️ CRITICAL - DO NOT SUMMARIZE OR ANALYZE OTHER REQUIREMENTS:
331
+ - IGNORE all other requirements in the REQUIREMENTS file
332
+ - IGNORE completed requirements, CHANGELOG entries, and other sections
333
+ - FOCUS EXCLUSIVELY on implementing the requirement listed above
334
+ - DO NOT read the entire REQUIREMENTS file and summarize it
335
+ - Read ONLY the specific sections you need to understand the current requirement
336
+
337
+ 🚨 STEP-BY-STEP WORKFLOW:
338
+ 1. Read INSTRUCTIONS.md (.vibecodingmachine/INSTRUCTIONS.md) to understand the workflow
339
+ 2. Read ONLY the "🔨 Current In Progress Requirement" section from REQUIREMENTS file to see the current requirement
340
+ 3. Read ONLY the "🚦 Current Status" section to see the current status
341
+ 4. Start working on "${currentRequirementText}" based on the current status:
342
+ - If status is PREPARE: Start planning and preparing
343
+ - If status is ACT: Start implementing the code
344
+ - If status is CLEAN UP: Clean up code, remove duplicates, apply DRY
345
+ - If status is VERIFY: Test and verify the implementation
346
+ - If status is DONE: Stop immediately (work is complete)
347
+ 5. At EACH stage transition, use the Write tool to UPDATE the REQUIREMENTS file:
348
+ - Set "🚦 Current Status" to the NEXT stage (PREPARE → ACT → CLEAN UP → VERIFY → DONE)
349
+ - Update the "RESPONSE FROM LAST CHAT" section with what you accomplished
350
+ 6. Continue until status is DONE
351
+ 7. You have FULL WRITE ACCESS - use Write tool to update the REQUIREMENTS file
352
+
353
+ REMEMBER: You are working on ONE requirement: "${currentRequirementText}". Ignore everything else.` :
354
+ currentPrompt;
355
+
356
+ // Run Continue CLI command with enhanced prompt
357
+ const result = await runContinueCLICommand(repoPath, enhancedPrompt, reqFilename);
358
+
359
+ if (result.hasError || (!result.success && result.error)) {
360
+ console.log(`\n✗ Continue CLI encountered an error: ${result.error || 'Unknown error'}`);
361
+ if (result.hasError) {
362
+ console.log('\n⚠️ Please fix the configuration issue and try again.');
363
+ }
364
+ exitReason = 'error';
365
+ break;
366
+ }
367
+
368
+ console.log('\n✓ Continue CLI completed');
369
+
370
+ // Wait a moment for file system to sync
371
+ await new Promise(resolve => setTimeout(resolve, 2000));
372
+
373
+ // Check if requirement is DONE
374
+ const isDone = await isRequirementDone(repoPath);
375
+
376
+ if (isDone) {
377
+ console.log('\n✅ Requirement marked as DONE!');
378
+
379
+ // Move to next requirement
380
+ const moveResult = await moveToNextRequirement(repoPath);
381
+
382
+ if (!moveResult.success) {
383
+ console.log(`\n⚠️ ${moveResult.error}`);
384
+ console.log(' Auto mode stopping.');
385
+ exitReason = 'error';
386
+ break;
387
+ }
388
+
389
+ console.log(`\n🔄 Moving to next requirement: ${moveResult.nextRequirement}`);
390
+
391
+ // Prepare next prompt
392
+ currentPrompt = initialPrompt;
393
+
394
+ // Wait a moment before next iteration
395
+ await new Promise(resolve => setTimeout(resolve, 1000));
396
+ } else {
397
+ console.log('\n⚠️ Requirement not yet DONE. Continue CLI may still be working or needs to update status.');
398
+ console.log(' Waiting for DONE status before continuing...');
399
+
400
+ // Wait longer before checking again
401
+ await new Promise(resolve => setTimeout(resolve, 5000));
402
+
403
+ // Check again
404
+ const stillNotDone = !(await isRequirementDone(repoPath));
405
+ if (stillNotDone) {
406
+ console.log('\n⚠️ Status still not DONE after waiting. Moving to next iteration.');
407
+
408
+ // Move to next requirement anyway
409
+ const moveResult = await moveToNextRequirement(repoPath);
410
+
411
+ if (!moveResult.success) {
412
+ console.log(`\n⚠️ ${moveResult.error}`);
413
+ console.log(' Auto mode stopping.');
414
+ break;
415
+ }
416
+
417
+ console.log(`\n🔄 Moving to next requirement: ${moveResult.nextRequirement}`);
418
+ currentPrompt = initialPrompt;
419
+ await new Promise(resolve => setTimeout(resolve, 1000));
420
+ }
421
+ }
422
+ }
423
+
424
+ console.log(`\n🏁 Auto mode completed. Processed ${chatCount} chat(s).`);
425
+ return { exitReason, chatCount };
426
+ }
427
+
428
+ module.exports = {
429
+ runContinueCLICommand,
430
+ runContinueCLIAutoMode
431
+ };