vibecodingmachine-cli 2025.12.1-534 → 2025.12.22-2230

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.
@@ -2,18 +2,18 @@ const chalk = require('chalk');
2
2
  const ora = require('ora');
3
3
  const path = require('path');
4
4
  const os = require('os');
5
- const { AppleScriptManager, ClineCLIManager, AiderCLIManager, ClaudeCodeCLIManager, logIDEMessage, runContinueCLICommand, runContinueCLIAutoMode } = require('vibecodingmachine-core');
6
- const { getRepoPath, getAutoConfig, setAutoConfig } = require('../utils/config');
5
+ const { spawn } = require('child_process');
6
+ const { AppleScriptManager, ClineCLIManager, AiderCLIManager, ClaudeCodeCLIManager, logIDEMessage, runContinueCLIAutoMode } = require('vibecodingmachine-core');
7
+ const { getRepoPath, getAutoConfig, setAutoConfig, getStages } = require('../utils/config');
7
8
  const { checkAutoModeStatus, startAutoMode, stopAutoMode, updateAutoModeStatus } = require('../utils/auto-mode');
8
9
  const logger = require('../utils/logger');
9
10
  const { createKeyboardHandler } = require('../utils/keyboard-handler');
10
11
  const { getProviderDefinitions, getProviderPreferences } = require('../utils/provider-registry');
11
12
  const PROVIDER_DEFINITIONS = getProviderDefinitions();
12
- const DIRECT_AGENT_IDS = PROVIDER_DEFINITIONS.filter(def => def.type === 'direct').map(def => def.id);
13
13
  const PROVIDER_DEFINITION_MAP = new Map(PROVIDER_DEFINITIONS.map(def => [def.id, def]));
14
14
  const { handleAutoStart: handleDirectAutoStart } = require('./auto-direct');
15
15
 
16
- const DEFAULT_INSTRUCTION_TEXT = 'Follow INSTRUCTIONS.md from .vibecodingmachine directory.\n\nCRITICAL FOR IDE AGENTS: You MUST work through ALL stages (ACT → CLEAN UP → VERIFY → DONE) without stopping. Update the "🚦 Current Status" section in the REQUIREMENTS file as you progress through each stage. DO NOT stop after acknowledging stages - you must COMPLETE the work and set status to DONE in the requirements file. The CLI is monitoring the file and waiting for you to finish.';
16
+
17
17
 
18
18
  /**
19
19
  * Get available LLM providers from config and environment variables
@@ -182,6 +182,7 @@ async function moveRequirementBackToTodo(repoPath, requirementText) {
182
182
 
183
183
  for (let i = 0; i < lines.length; i++) {
184
184
  const line = lines[i];
185
+ const trimmed = line.trim();
185
186
 
186
187
  // Find verified section
187
188
  if (line.includes('## ✅ Verified by AI screenshot')) {
@@ -199,7 +200,7 @@ async function moveRequirementBackToTodo(repoPath, requirementText) {
199
200
  }
200
201
 
201
202
  // Check if we're in verified section and this is the requirement to move
202
- if (inVerifiedSection && line.trim().startsWith('- ')) {
203
+ if (inVerifiedSection && trimmed.startsWith('- ')) {
203
204
  const lineRequirement = line.substring(2).trim();
204
205
  // Remove date prefix if present (format: "2025-11-05: **requirement**")
205
206
  const cleanRequirement = lineRequirement.replace(/^\d{4}-\d{2}-\d{2}:\s*\*\*/, '').replace(/\*\*$/, '').trim();
@@ -210,20 +211,21 @@ async function moveRequirementBackToTodo(repoPath, requirementText) {
210
211
  requirementFound = true;
211
212
  continue;
212
213
  }
213
- updatedLines.push(line);
214
- continue;
215
214
  }
216
215
 
217
216
  // If we're in not yet completed section and haven't added the requirement yet, add it at the top
218
- if (inNotYetCompleted && !requirementFound && line.trim().startsWith('- ')) {
217
+ if (inNotYetCompleted && !requirementFound && trimmed.startsWith('- ')) {
219
218
  // Add the requirement before the first existing requirement
220
- updatedLines.push(`- ${requirementText}`);
221
- updatedLines.push('');
222
- requirementFound = true; // Mark as added so we don't add it again
219
+ const newUpdatedLines = lines.slice(0, i);
220
+ newUpdatedLines.push(`- ${requirementText}`);
221
+ newUpdatedLines.push('');
222
+ newUpdatedLines.push(...lines.slice(i));
223
+ await fs.writeFile(reqPath, newUpdatedLines.join('\n'));
224
+ return { success: true };
223
225
  }
224
226
 
225
227
  // Reset section flags when hitting new sections
226
- if (line.trim().startsWith('##')) {
228
+ if (trimmed.startsWith('##')) {
227
229
  inVerifiedSection = false;
228
230
  inNotYetCompleted = false;
229
231
  }
@@ -234,6 +236,7 @@ async function moveRequirementBackToTodo(repoPath, requirementText) {
234
236
  // If requirement wasn't found in verified section, try to add it to not yet completed anyway
235
237
  if (!requirementFound) {
236
238
  // Find the not yet completed section and add requirement at the top
239
+ const newUpdatedLines = lines.slice();
237
240
  for (let i = 0; i < updatedLines.length; i++) {
238
241
  if (updatedLines[i].includes('## ⏳ Requirements not yet completed')) {
239
242
  // Find the first requirement line after this section
@@ -243,18 +246,13 @@ async function moveRequirementBackToTodo(repoPath, requirementText) {
243
246
  insertIndex++;
244
247
  }
245
248
  updatedLines.splice(insertIndex, 0, `- ${requirementText}`, '');
246
- requirementFound = true;
247
- break;
249
+ await fs.writeFile(reqPath, updatedLines.join('\n'));
250
+ return { success: true };
248
251
  }
249
252
  }
250
253
  }
251
254
 
252
- if (requirementFound) {
253
- await fs.writeFile(reqPath, updatedLines.join('\n'));
254
- return { success: true };
255
- } else {
256
- return { success: false, error: 'Requirement not found in verified section' };
257
- }
255
+ return { success: false, error: 'Requirement not found in verified section' };
258
256
  } catch (error) {
259
257
  return { success: false, error: error.message };
260
258
  }
@@ -279,10 +277,8 @@ async function moveRequirementToFeedback(repoPath, requirementText, questions, f
279
277
 
280
278
  const content = await fs.readFile(reqPath, 'utf8');
281
279
  const lines = content.split('\n');
282
- const updatedLines = [];
283
280
 
284
281
  let inTodoSection = false;
285
- let inFeedbackSection = false;
286
282
  let requirementRemoved = false;
287
283
  let feedbackAdded = false;
288
284
 
@@ -292,15 +288,13 @@ async function moveRequirementToFeedback(repoPath, requirementText, questions, f
292
288
  // Find TODO section
293
289
  if (trimmed.startsWith('##') && trimmed.includes('Requirements not yet completed')) {
294
290
  inTodoSection = true;
295
- inFeedbackSection = false;
296
- updatedLines.push(line);
297
291
  continue;
298
292
  }
299
293
 
300
294
  // Find "Requirements needing manual feedback" section
301
295
  if (trimmed.startsWith('##') && (trimmed.includes('Requirements needing manual feedback') || trimmed.includes('❓ Requirements needing'))) {
302
296
  inTodoSection = false;
303
- inFeedbackSection = true;
297
+ const updatedLines = lines.slice(0, lines.indexOf(line));
304
298
  updatedLines.push(line);
305
299
 
306
300
  // Add blank line if not already present
@@ -328,13 +322,14 @@ async function moveRequirementToFeedback(repoPath, requirementText, questions, f
328
322
  updatedLines.push('');
329
323
  feedbackAdded = true;
330
324
  }
331
- continue;
325
+ updatedLines.push(...lines.slice(lines.indexOf(line) + 1));
326
+ await fs.writeFile(reqPath, updatedLines.join('\n'));
327
+ return { success: true };
332
328
  }
333
329
 
334
330
  // Stop sections at next header
335
331
  if (trimmed.startsWith('##')) {
336
332
  inTodoSection = false;
337
- inFeedbackSection = false;
338
333
  }
339
334
 
340
335
  // Remove requirement from TODO section (match first occurrence)
@@ -421,60 +416,229 @@ async function moveCompletedRequirement(repoPath, completedRequirement) {
421
416
  const content = await fs.readFile(reqPath, 'utf8');
422
417
  const lines = content.split('\n');
423
418
 
424
- const updatedLines = [];
425
- let inTodoSection = false;
426
- let inVerifiedSection = false;
427
- let removedCompleted = false;
428
- let addedToVerified = false;
419
+ // First, check if requirement is already in TO VERIFY section
420
+ const verifySectionVariants = [
421
+ '## 🔍 TO VERIFY BY HUMAN',
422
+ '## 🔍 TO VERIFY',
423
+ '## TO VERIFY',
424
+ '## ✅ TO VERIFY',
425
+ '## ✅ Verified by AI screenshot. Needs Human to Verify and move to CHANGELOG'
426
+ ];
429
427
 
430
- for (const line of lines) {
428
+ let inVerifySection = false;
429
+ let alreadyInVerify = false;
430
+ const normalizedCompleted = completedRequirement.trim();
431
+ const snippet = normalizedCompleted.substring(0, 80);
432
+
433
+ for (let i = 0; i < lines.length; i++) {
434
+ const line = lines[i];
431
435
  const trimmed = line.trim();
432
436
 
433
- // Find TODO section
437
+ // Check if we're entering TO VERIFY section
438
+ if (trimmed.startsWith('##')) {
439
+ inVerifySection = verifySectionVariants.some(variant => {
440
+ const variantTrimmed = variant.trim();
441
+ return trimmed === variantTrimmed || trimmed.startsWith(variantTrimmed);
442
+ }) && !trimmed.includes('## 📝 VERIFIED') && !trimmed.match(/^##\s+VERIFIED$/i);
443
+
444
+ if (inVerifySection && trimmed.includes('TO VERIFY') || trimmed.includes('Verified by AI screenshot')) {
445
+ continue;
446
+ }
447
+ }
448
+
449
+ // Check if we're leaving TO VERIFY section
450
+ if (inVerifySection && trimmed.startsWith('##') && !trimmed.startsWith('###')) {
451
+ const isVerifyHeader = verifySectionVariants.some(variant => {
452
+ const variantTrimmed = variant.trim();
453
+ return trimmed === variantTrimmed || trimmed.startsWith(variantTrimmed);
454
+ });
455
+ if (!isVerifyHeader) {
456
+ inVerifySection = false;
457
+ }
458
+ }
459
+
460
+ // Check if requirement is already in TO VERIFY
461
+ if (inVerifySection && trimmed.startsWith('###')) {
462
+ const title = trimmed.replace(/^###\s*/, '').trim();
463
+ if (title) {
464
+ const normalizedTitle = title.trim();
465
+ if (normalizedTitle === normalizedCompleted ||
466
+ normalizedTitle.includes(normalizedCompleted) ||
467
+ normalizedCompleted.includes(normalizedTitle) ||
468
+ normalizedTitle.includes(snippet) ||
469
+ snippet.includes(normalizedTitle.substring(0, 80))) {
470
+ alreadyInVerify = true;
471
+ break;
472
+ }
473
+ }
474
+ }
475
+ }
476
+
477
+ if (alreadyInVerify) {
478
+ return { success: true }; // Already in TO VERIFY, nothing to do
479
+ }
480
+
481
+ // Find the requirement by its title (in ### header format)
482
+ // Normalize the completed requirement text for matching
483
+ let requirementStartIndex = -1;
484
+ let requirementEndIndex = -1;
485
+
486
+ // Try to find the requirement in TODO section first
487
+ let inTodoSection = false;
488
+ for (let i = 0; i < lines.length; i++) {
489
+ const line = lines[i];
490
+ const trimmed = line.trim();
491
+
492
+ // Check if we're entering TODO section
434
493
  if (trimmed.startsWith('##') && trimmed.includes('Requirements not yet completed')) {
435
494
  inTodoSection = true;
436
- inVerifiedSection = false;
437
- updatedLines.push(line);
438
495
  continue;
439
496
  }
440
497
 
441
- // Find TO VERIFY section
442
- if (trimmed.startsWith('##') && (trimmed.includes('TO VERIFY') || trimmed.includes('Verified by AI screenshot'))) {
498
+ // Check if we're leaving TODO section
499
+ if (inTodoSection && trimmed.startsWith('##') && !trimmed.startsWith('###') && !trimmed.includes('Requirements not yet completed')) {
443
500
  inTodoSection = false;
444
- inVerifiedSection = true;
445
- updatedLines.push(line);
501
+ }
446
502
 
447
- // Add completed requirement at the top of TO VERIFY section
448
- if (!addedToVerified) {
449
- const today = new Date().toISOString().split('T')[0];
450
- updatedLines.push(`- ${today}: **${completedRequirement}**`);
451
- addedToVerified = true;
503
+ // Only look for requirements in TODO section
504
+ if (inTodoSection && trimmed.startsWith('###')) {
505
+ const title = trimmed.replace(/^###\s*/, '').trim();
506
+ if (title) {
507
+ // Try multiple matching strategies
508
+ const normalizedTitle = title.trim();
509
+ const titleSnippet = normalizedTitle.substring(0, 80);
510
+
511
+ // Exact match
512
+ if (normalizedTitle === normalizedCompleted) {
513
+ requirementStartIndex = i;
514
+ }
515
+ // Check if either contains the other (for partial matches)
516
+ else if (normalizedTitle.includes(normalizedCompleted) || normalizedCompleted.includes(normalizedTitle)) {
517
+ requirementStartIndex = i;
518
+ }
519
+ // Check snippet matches
520
+ else if (normalizedTitle.includes(snippet) || snippet.includes(titleSnippet)) {
521
+ requirementStartIndex = i;
522
+ }
523
+ // Check if they start the same (for REGRESSION: prefix issues)
524
+ else if (normalizedTitle.replace(/^REGRESSION:\s*/i, '') === normalizedCompleted.replace(/^REGRESSION:\s*/i, '') ||
525
+ normalizedTitle.replace(/^REGRESSION:\s*/i, '').includes(snippet.replace(/^REGRESSION:\s*/i, '')) ||
526
+ snippet.replace(/^REGRESSION:\s*/i, '').includes(normalizedTitle.replace(/^REGRESSION:\s*/i, ''))) {
527
+ requirementStartIndex = i;
528
+ }
529
+
530
+ if (requirementStartIndex !== -1) {
531
+ // Find the end of this requirement (next ### or ## header)
532
+ for (let j = i + 1; j < lines.length; j++) {
533
+ const nextLine = lines[j].trim();
534
+ if (nextLine.startsWith('###') || (nextLine.startsWith('##') && !nextLine.startsWith('###'))) {
535
+ requirementEndIndex = j;
536
+ break;
537
+ }
538
+ }
539
+ if (requirementEndIndex === -1) {
540
+ requirementEndIndex = lines.length;
541
+ }
542
+ break;
543
+ }
452
544
  }
453
- continue;
454
545
  }
546
+ }
455
547
 
456
- // Stop sections at next header
457
- if (trimmed.startsWith('##')) {
458
- inTodoSection = false;
459
- inVerifiedSection = false;
460
- }
548
+ if (requirementStartIndex === -1) {
549
+ return { success: false, error: `Could not find requirement "${completedRequirement.substring(0, 60)}..." in TODO section` };
550
+ }
461
551
 
462
- // Remove completed requirement from TODO section (match first occurrence)
463
- if (inTodoSection && !removedCompleted && trimmed.startsWith('- ')) {
464
- const reqText = trimmed.substring(2).trim();
465
- // Simple match - just check if this is the completed requirement
466
- if (reqText === completedRequirement ||
467
- reqText.includes(completedRequirement) ||
468
- completedRequirement.includes(reqText)) {
469
- removedCompleted = true;
470
- continue; // Skip this line
552
+ // Extract the entire requirement block
553
+ const requirementBlock = lines.slice(requirementStartIndex, requirementEndIndex);
554
+
555
+ // Remove the requirement from its current location
556
+ lines.splice(requirementStartIndex, requirementEndIndex - requirementStartIndex);
557
+
558
+ // Find or create TO VERIFY BY HUMAN section (reuse the variants we defined earlier)
559
+ let verifyIndex = -1;
560
+ for (let i = 0; i < lines.length; i++) {
561
+ const line = lines[i];
562
+ const trimmed = line.trim();
563
+
564
+ // Check each variant more carefully
565
+ for (const variant of verifySectionVariants) {
566
+ const variantTrimmed = variant.trim();
567
+ // Exact match or line starts with variant
568
+ if (trimmed === variantTrimmed || trimmed.startsWith(variantTrimmed)) {
569
+ // Double-check: make sure it's NOT a VERIFIED section (without TO VERIFY)
570
+ if (!trimmed.includes('## 📝 VERIFIED') && !trimmed.match(/^##\s+VERIFIED$/i) &&
571
+ (trimmed.includes('TO VERIFY') || trimmed.includes('Verified by AI screenshot'))) {
572
+ verifyIndex = i;
573
+ break;
574
+ }
471
575
  }
472
576
  }
577
+ if (verifyIndex !== -1) break;
578
+ }
473
579
 
474
- updatedLines.push(line);
580
+ if (verifyIndex === -1) {
581
+ // Create TO VERIFY section - place it BEFORE VERIFIED section if one exists, otherwise before CHANGELOG
582
+ const verifiedIndex = lines.findIndex(line => {
583
+ const trimmed = line.trim();
584
+ return trimmed === '## 📝 VERIFIED' || trimmed.startsWith('## 📝 VERIFIED') ||
585
+ (trimmed.startsWith('##') && trimmed.includes('VERIFIED') && !trimmed.includes('TO VERIFY'));
586
+ });
587
+ const changelogIndex = lines.findIndex(line => line.includes('## CHANGELOG'));
588
+ const manualFeedbackIndex = lines.findIndex(line => line.trim().startsWith('## ❓'));
589
+
590
+ // Prefer: before VERIFIED > before CHANGELOG > before manual feedback > at end
591
+ let insertionIndex = lines.length;
592
+ if (verifiedIndex > 0) {
593
+ insertionIndex = verifiedIndex;
594
+ } else if (changelogIndex > 0) {
595
+ insertionIndex = changelogIndex;
596
+ } else if (manualFeedbackIndex > 0) {
597
+ insertionIndex = manualFeedbackIndex;
598
+ }
599
+
600
+ const block = [];
601
+ if (insertionIndex > 0 && lines[insertionIndex - 1].trim() !== '') {
602
+ block.push('');
603
+ }
604
+ block.push('## 🔍 TO VERIFY BY HUMAN', '');
605
+ lines.splice(insertionIndex, 0, ...block);
606
+ verifyIndex = lines.findIndex(line => {
607
+ const trimmed = line.trim();
608
+ return trimmed === '## 🔍 TO VERIFY BY HUMAN' || trimmed.startsWith('## 🔍 TO VERIFY BY HUMAN');
609
+ });
610
+
611
+ if (verifyIndex === -1) {
612
+ return { success: false, error: 'Failed to create TO VERIFY BY HUMAN section' };
613
+ }
475
614
  }
476
615
 
477
- await fs.writeFile(reqPath, updatedLines.join('\n'));
616
+ // Safety check: verify we're not inserting into a VERIFIED section
617
+ const verifyLine = lines[verifyIndex] || '';
618
+ if (verifyLine.includes('## 📝 VERIFIED') || (verifyLine.trim().startsWith('##') && verifyLine.includes('VERIFIED') && !verifyLine.includes('TO VERIFY'))) {
619
+ return { success: false, error: 'Attempted to insert into VERIFIED section instead of TO VERIFY' };
620
+ }
621
+
622
+ // Insert requirement block at TOP of TO VERIFY section (right after section header)
623
+ let insertIndex = verifyIndex + 1;
624
+
625
+ // Ensure there's a blank line after the section header
626
+ if (lines[insertIndex]?.trim() !== '') {
627
+ lines.splice(insertIndex, 0, '');
628
+ insertIndex++;
629
+ }
630
+
631
+ // Insert the requirement block
632
+ lines.splice(insertIndex, 0, ...requirementBlock);
633
+
634
+ // Ensure there's a blank line after the requirement block
635
+ const afterIndex = insertIndex + requirementBlock.length;
636
+ if (afterIndex < lines.length && lines[afterIndex]?.trim() !== '') {
637
+ lines.splice(afterIndex, 0, '');
638
+ }
639
+
640
+ // Write the file
641
+ await fs.writeFile(reqPath, lines.join('\n'));
478
642
  return { success: true };
479
643
  } catch (error) {
480
644
  return { success: false, error: error.message };
@@ -499,6 +663,14 @@ function getTimestamp() {
499
663
  }
500
664
 
501
665
  async function start(options) {
666
+ // First Run Check
667
+ try {
668
+ const { checkFirstRun } = require('../utils/first-run');
669
+ await checkFirstRun();
670
+ } catch (e) {
671
+ // Continue if check fails
672
+ }
673
+
502
674
  // STRICT AUTH CHECK
503
675
  const auth = require('../utils/auth');
504
676
  const isAuth = await auth.isAuthenticated();
@@ -517,8 +689,6 @@ async function start(options) {
517
689
  if (global.pendingUpdate) {
518
690
  const updateSpinner = ora('Installing update...').start();
519
691
  try {
520
- const { spawn } = require('child_process');
521
-
522
692
  // Install update using npm
523
693
  await new Promise((resolve, reject) => {
524
694
  const npmInstall = spawn('npm', ['install', '-g', 'vibecodingmachine-cli'], {
@@ -531,7 +701,6 @@ async function start(options) {
531
701
  console.log(chalk.green('\n✓ Restarting with new version...\n'));
532
702
 
533
703
  // Restart CLI with same arguments
534
- const { spawn } = require('child_process');
535
704
  const args = process.argv.slice(2);
536
705
  spawn(process.argv[0], [process.argv[1], ...args], {
537
706
  stdio: 'inherit',
@@ -564,15 +733,32 @@ async function start(options) {
564
733
  throw new Error('No repository configured');
565
734
  }
566
735
 
567
- // Read saved auto config first, then override with options
736
+ // Get provider preferences and definitions
568
737
  const savedConfig = await getAutoConfig();
569
738
  const prefs = await getProviderPreferences();
570
- const firstEnabledFromPrefs = prefs.order.find(id => prefs.enabled[id] !== false);
571
- const fallbackAgent = firstEnabledFromPrefs || 'claude-code';
572
- const savedAgent = savedConfig.agent || savedConfig.ide;
573
- const requestedAgent = options.ide || savedAgent || fallbackAgent;
574
- const providerDef = PROVIDER_DEFINITION_MAP.get(requestedAgent) || PROVIDER_DEFINITION_MAP.get(fallbackAgent);
575
- const effectiveAgent = providerDef ? providerDef.id : 'claude-code';
739
+
740
+ // Get all available providers in the order specified in preferences
741
+ const availableProviders = [];
742
+ for (const id of prefs.order) {
743
+ if (prefs.enabled[id] !== false && PROVIDER_DEFINITION_MAP.has(id)) {
744
+ availableProviders.push(id);
745
+ }
746
+ }
747
+
748
+ // If no providers are available, use the first one from definitions as fallback
749
+ if (availableProviders.length === 0) {
750
+ availableProviders.push(PROVIDER_DEFINITIONS[0]?.id || 'claude-code');
751
+ }
752
+
753
+ // Use the first available provider by default, unless overridden by options
754
+ let effectiveAgent = options.ide || availableProviders[0];
755
+
756
+ // If the requested agent isn't available, use the first available one
757
+ if (!availableProviders.includes(effectiveAgent)) {
758
+ effectiveAgent = availableProviders[0];
759
+ }
760
+
761
+ const providerDef = PROVIDER_DEFINITION_MAP.get(effectiveAgent);
576
762
 
577
763
  const resolvedNeverStop = (() => {
578
764
  if (options.neverStop !== undefined) return options.neverStop;
@@ -716,8 +902,15 @@ async function start(options) {
716
902
  await startAutoMode(repoPath, config);
717
903
  }
718
904
 
905
+ // Get configured stages
906
+ const stages = await getStages();
907
+ const stagesList = stages.join(' → ');
908
+ const defaultInstructionText = `Follow INSTRUCTIONS.md from .vibecodingmachine directory.
909
+
910
+ CRITICAL FOR IDE AGENTS: You MUST work through ALL configured stages (${stagesList}) without stopping. Update the "🚦 Current Status" section in the REQUIREMENTS file as you progress through each stage. DO NOT stop after acknowledging stages - you must COMPLETE the work and set status to DONE in the requirements file. The CLI is monitoring the file and waiting for you to finish.`;
911
+
719
912
  // Send initial instruction to IDE or Continue/Cline CLI
720
- const textToSend = options.text || DEFAULT_INSTRUCTION_TEXT;
913
+ const textToSend = options.text || defaultInstructionText;
721
914
 
722
915
  if (config.ide === 'continue') {
723
916
  // Use Continue CLI with command-line approach
@@ -840,14 +1033,9 @@ async function start(options) {
840
1033
  'DONE': '⏳'
841
1034
  };
842
1035
 
843
- const stages = ['PREPARE', 'ACT', 'CLEAN UP', 'VERIFY', 'DONE'];
844
- const stageMap = {
845
- 'PREPARE': 0,
846
- 'ACT': 1,
847
- 'CLEAN UP': 2,
848
- 'VERIFY': 3,
849
- 'DONE': 4
850
- };
1036
+ // Build stage map dynamically
1037
+ const stageMap = {};
1038
+ stages.forEach((s, i) => stageMap[s] = i);
851
1039
 
852
1040
  const currentIndex = stageMap[currentStatus] || 0;
853
1041
  const workflowLine = stages.map((stage, idx) => {
@@ -887,21 +1075,65 @@ async function start(options) {
887
1075
  let title = null;
888
1076
  let status = 'PREPARE';
889
1077
  let inTodoSection = false;
1078
+ let inCurrentSection = false;
890
1079
 
891
- for (const line of lines) {
892
- if (line.includes('Requirements not yet completed') && line.trim().startsWith('##')) {
1080
+ for (let i = 0; i < lines.length; i++) {
1081
+ const line = lines[i].trim();
1082
+
1083
+ // Check if we're in the Current section
1084
+ if (line.includes('## 🔨 Current In Progress Requirement') ||
1085
+ line.includes('Current In Progress Requirement')) {
1086
+ inCurrentSection = true;
1087
+ inTodoSection = false;
1088
+ continue;
1089
+ }
1090
+
1091
+ // Check if we're in the TODO section
1092
+ if (line.includes('## ⏳ Requirements not yet completed') ||
1093
+ (line.includes('Requirements not yet completed') && line.startsWith('##'))) {
893
1094
  inTodoSection = true;
1095
+ inCurrentSection = false;
894
1096
  continue;
895
1097
  }
896
1098
 
897
- if (inTodoSection && line.trim().startsWith('- ')) {
898
- title = line.substring(2).trim();
899
- status = 'PREPARE';
900
- break;
1099
+ // If we hit another section header, stop looking in current section/todo section logic
1100
+ if ((inTodoSection || inCurrentSection) && line.startsWith('##') && !line.startsWith('###')) {
1101
+ if (inCurrentSection) {
1102
+ // If we finished current section and found nothing, move to next sections (which might be TODO)
1103
+ inCurrentSection = false;
1104
+ continue;
1105
+ }
1106
+ if (inTodoSection) {
1107
+ break;
1108
+ }
901
1109
  }
902
1110
 
903
- if (inTodoSection && line.trim().startsWith('##')) {
904
- break;
1111
+ // If we're in Current section, look for bullet or header
1112
+ if (inCurrentSection) {
1113
+ if (line.startsWith('- ')) {
1114
+ title = line.substring(2).trim();
1115
+ // Remove bold if present
1116
+ title = title.replace(/\*\*/g, '');
1117
+ if (title) break;
1118
+ }
1119
+ if (line.startsWith('###')) {
1120
+ title = line.replace(/^###\s*/, '').trim();
1121
+ if (title) break;
1122
+ }
1123
+ }
1124
+
1125
+ // If we're in TODO section and find a requirement header (###) or bullet
1126
+ if (inTodoSection) {
1127
+ if (line.startsWith('###')) {
1128
+ title = line.replace(/^###\s*/, '').trim();
1129
+ if (title) break;
1130
+ }
1131
+ // Also support bullet points in TODO if that's a format used
1132
+ if (line.startsWith('- ')) {
1133
+ title = line.substring(2).trim();
1134
+ title = title.replace(/\*\*/g, '');
1135
+ if (title) break;
1136
+ }
905
1137
  }
906
1138
  }
907
1139
 
@@ -1789,25 +2021,30 @@ Please implement this requirement now.`;
1789
2021
  let status = 'PREPARE';
1790
2022
  let inTodoSection = false;
1791
2023
 
1792
- // Read from TODO list instead of "Current In Progress Requirement" section
1793
- for (const line of lines) {
1794
- // Find TODO section
1795
- if (line.includes('Requirements not yet completed') && line.trim().startsWith('##')) {
2024
+ // Read from TODO list - requirements are in ### format
2025
+ for (let i = 0; i < lines.length; i++) {
2026
+ const line = lines[i].trim();
2027
+
2028
+ // Check if we're in the TODO section
2029
+ if (line.includes('## ⏳ Requirements not yet completed') ||
2030
+ (line.includes('Requirements not yet completed') && line.startsWith('##'))) {
1796
2031
  inTodoSection = true;
1797
2032
  continue;
1798
2033
  }
1799
2034
 
1800
- // Get first TODO item
1801
- if (inTodoSection && line.trim().startsWith('- ')) {
1802
- title = line.substring(2).trim();
1803
- // Always start at PREPARE for TODO items
1804
- status = 'PREPARE';
2035
+ // If we hit another section header, stop looking
2036
+ if (inTodoSection && line.startsWith('##') && !line.startsWith('###')) {
1805
2037
  break;
1806
2038
  }
1807
2039
 
1808
- // Stop if we hit another section
1809
- if (inTodoSection && line.trim().startsWith('##')) {
1810
- break;
2040
+ // If we're in TODO section and find a requirement header (###)
2041
+ if (inTodoSection && line.startsWith('###')) {
2042
+ title = line.replace(/^###\s*/, '').trim();
2043
+ // Skip empty titles
2044
+ if (title && title.length > 0) {
2045
+ status = 'PREPARE';
2046
+ break;
2047
+ }
1811
2048
  }
1812
2049
  }
1813
2050
 
@@ -2646,11 +2883,43 @@ NOW: Search for and make the minimal code changes needed.`;
2646
2883
  } else {
2647
2884
  console.log(chalk.yellow(`\n⚠️ Aider did not complete implementation.\n`));
2648
2885
 
2649
- // Check if requirement might be too vague by having Aider search the codebase first
2650
- console.log(chalk.cyan(`\n[${getTimestamp()}] 🔍 Searching codebase for relevant code...\n`));
2886
+ // Check if any code changes were made during implementation attempt
2887
+ console.log(chalk.cyan(`\n[${getTimestamp()}] 🔍 Checking for code changes...\n`));
2888
+
2889
+ let hasCodeChanges = false;
2890
+ try {
2891
+ const { execSync } = require('child_process');
2892
+ const gitStatus = execSync('git status --porcelain', { cwd: repoPath, encoding: 'utf8' });
2893
+ hasCodeChanges = gitStatus.trim().length > 0;
2894
+
2895
+ if (hasCodeChanges) {
2896
+ console.log(chalk.cyan(`✓ Code changes detected. Will move to TO VERIFY.\n`));
2897
+ } else {
2898
+ console.log(chalk.gray(`No code changes detected.\n`));
2899
+ }
2900
+ } catch (err) {
2901
+ console.log(chalk.gray(`Could not check git status: ${err.message}\n`));
2902
+ }
2651
2903
 
2652
- // STEP 1: Have Aider search the codebase for relevant files
2653
- const searchPrompt = `Search the codebase to understand this requirement:
2904
+ // If code changes were made, move to TO VERIFY (even if incomplete)
2905
+ if (hasCodeChanges) {
2906
+ console.log(chalk.cyan(`\n[${getTimestamp()}] Moving requirement to TO VERIFY (code changes were made): "${currentTitle.substring(0, 60)}..."`));
2907
+ const moveResult = await moveCompletedRequirement(repoPath, currentTitle);
2908
+
2909
+ if (moveResult.success) {
2910
+ console.log(chalk.green(`\n✓ Successfully moved requirement to TO VERIFY section (code changes made, needs human verification)`));
2911
+ requirementsCompleted++; // Count as "completed" so we move to next requirement
2912
+ } else {
2913
+ console.log(chalk.red(`\n❌ Error moving requirement: ${moveResult.error}`));
2914
+ console.log(chalk.yellow(` Requirement title: "${currentTitle}"`));
2915
+ console.log(chalk.gray(' Requirement remains in TODO for retry.\n'));
2916
+ }
2917
+ } else {
2918
+ // No code changes made - check if requirement might be too vague by having Aider search the codebase first
2919
+ console.log(chalk.cyan(`\n[${getTimestamp()}] 🔍 Searching codebase for relevant code...\n`));
2920
+
2921
+ // STEP 1: Have Aider search the codebase for relevant files
2922
+ const searchPrompt = `Search the codebase to understand this requirement:
2654
2923
 
2655
2924
  "${currentTitle}"
2656
2925
 
@@ -2659,30 +2928,30 @@ Focus on: What files/functions are related? What patterns exist?
2659
2928
 
2660
2929
  If you cannot find any relevant code, say "NO RELEVANT CODE FOUND".`;
2661
2930
 
2662
- const searchResult = await aiderManager.sendText(
2663
- searchPrompt,
2664
- repoPath,
2665
- provider,
2666
- modelName,
2667
- null,
2668
- [], // No files - let Aider search
2669
- (output) => {
2670
- // Show search progress
2671
- if (output.includes('Searching') || output.includes('Found')) {
2672
- process.stdout.write(chalk.gray(output));
2673
- }
2674
- },
2675
- () => { },
2676
- 90000 // 1.5 minute timeout for search
2677
- );
2931
+ const searchResult = await aiderManager.sendText(
2932
+ searchPrompt,
2933
+ repoPath,
2934
+ provider,
2935
+ modelName,
2936
+ null,
2937
+ [], // No files - let Aider search
2938
+ (output) => {
2939
+ // Show search progress
2940
+ if (output.includes('Searching') || output.includes('Found')) {
2941
+ process.stdout.write(chalk.gray(output));
2942
+ }
2943
+ },
2944
+ () => { },
2945
+ 90000 // 1.5 minute timeout for search
2946
+ );
2678
2947
 
2679
- const searchFindings = searchResult.output || 'Search completed but no findings reported.';
2680
- console.log(chalk.gray(`\nFindings: ${searchFindings}\n`));
2948
+ const searchFindings = searchResult.output || 'Search completed but no findings reported.';
2949
+ console.log(chalk.gray(`\nFindings: ${searchFindings}\n`));
2681
2950
 
2682
- // STEP 2: Check if requirement is vague and generate questions focused on USER INTENT
2683
- console.log(chalk.cyan(`\n[${getTimestamp()}] 🤔 Analyzing if clarification is needed...\n`));
2951
+ // STEP 2: Check if requirement is vague and generate questions focused on USER INTENT
2952
+ console.log(chalk.cyan(`\n[${getTimestamp()}] 🤔 Analyzing if clarification is needed...\n`));
2684
2953
 
2685
- const vagueCheckPrompt = `Based on these findings from the codebase:
2954
+ const vagueCheckPrompt = `Based on these findings from the codebase:
2686
2955
  "${searchFindings}"
2687
2956
 
2688
2957
  Analyze if this requirement needs clarification:
@@ -2709,45 +2978,46 @@ Example BAD questions (never ask these):
2709
2978
  - What file contains the confirmation prompt? (You should search for this yourself)
2710
2979
  - Which component needs to be modified? (You should find this yourself)`;
2711
2980
 
2712
- const vagueCheckResult = await aiderManager.sendText(
2713
- vagueCheckPrompt,
2714
- repoPath,
2715
- provider,
2716
- modelName,
2717
- null,
2718
- [], // No files needed for vague check
2719
- () => { }, // Silent mode
2720
- () => { },
2721
- 60000 // 1 minute timeout
2722
- );
2981
+ const vagueCheckResult = await aiderManager.sendText(
2982
+ vagueCheckPrompt,
2983
+ repoPath,
2984
+ provider,
2985
+ modelName,
2986
+ null,
2987
+ [], // No files needed for vague check
2988
+ () => { }, // Silent mode
2989
+ () => { },
2990
+ 60000 // 1 minute timeout
2991
+ );
2723
2992
 
2724
- const vagueCheckOutput = vagueCheckResult.output || '';
2725
- const isVague = vagueCheckOutput.toUpperCase().includes('REQUIREMENT NEEDS CLARIFICATION');
2993
+ const vagueCheckOutput = vagueCheckResult.output || '';
2994
+ const isVague = vagueCheckOutput.toUpperCase().includes('REQUIREMENT NEEDS CLARIFICATION');
2726
2995
 
2727
- if (isVague) {
2728
- // Extract clarifying questions from output
2729
- const questionMatch = vagueCheckOutput.match(/\d+\.\s*(.+)/g);
2730
- const questions = questionMatch ? questionMatch.map(q => q.trim()).join('\n') :
2731
- '1. What is the desired behavior for this feature?\n2. Should this apply to all cases or specific scenarios?';
2996
+ if (isVague) {
2997
+ // Extract clarifying questions from output
2998
+ const questionMatch = vagueCheckOutput.match(/\d+\.\s*(.+)/g);
2999
+ const questions = questionMatch ? questionMatch.map(q => q.trim()).join('\n') :
3000
+ '1. What is the desired behavior for this feature?\n2. Should this apply to all cases or specific scenarios?';
2732
3001
 
2733
- console.log(chalk.yellow(`\n❓ Requirement flagged as TOO VAGUE. Moving to "Requirements needing manual feedback" section.\n`));
2734
- console.log(chalk.gray('AI Findings:'));
2735
- console.log(chalk.white(searchFindings));
2736
- console.log(chalk.gray('\nClarifying questions:'));
2737
- console.log(chalk.white(questions));
3002
+ console.log(chalk.yellow(`\n❓ Requirement flagged as TOO VAGUE (and no code changes made). Moving to "Requirements needing manual feedback" section.\n`));
3003
+ console.log(chalk.gray('AI Findings:'));
3004
+ console.log(chalk.white(searchFindings));
3005
+ console.log(chalk.gray('\nClarifying questions:'));
3006
+ console.log(chalk.white(questions));
2738
3007
 
2739
- // Move requirement to "Requirements needing manual feedback" section with findings
2740
- const moveToFeedbackResult = await moveRequirementToFeedback(repoPath, currentTitle, questions, searchFindings);
3008
+ // Move requirement to "Requirements needing manual feedback" section with findings
3009
+ const moveToFeedbackResult = await moveRequirementToFeedback(repoPath, currentTitle, questions, searchFindings);
2741
3010
 
2742
- if (moveToFeedbackResult.success) {
2743
- console.log(chalk.green(`\n✓ Requirement moved to feedback section. Please provide clarification.\n`));
2744
- requirementsCompleted++; // Count as "completed" so we move to next requirement
3011
+ if (moveToFeedbackResult.success) {
3012
+ console.log(chalk.green(`\n✓ Requirement moved to feedback section. Please provide clarification.\n`));
3013
+ requirementsCompleted++; // Count as "completed" so we move to next requirement
3014
+ } else {
3015
+ console.log(chalk.yellow(`\n⚠️ Could not move requirement: ${moveToFeedbackResult.error}\n`));
3016
+ console.log(chalk.gray(' Requirement remains in TODO for retry.\n'));
3017
+ }
2745
3018
  } else {
2746
- console.log(chalk.yellow(`\n⚠️ Could not move requirement: ${moveToFeedbackResult.error}\n`));
2747
- console.log(chalk.gray(' Requirement remains in TODO for retry.\n'));
3019
+ console.log(chalk.cyan(`\n Requirement appears clear. Will retry on next run.\n`));
2748
3020
  }
2749
- } else {
2750
- console.log(chalk.cyan(`\n✓ Requirement appears clear. Will retry on next run.\n`));
2751
3021
  }
2752
3022
  }
2753
3023
 
@@ -2766,16 +3036,18 @@ Example BAD questions (never ask these):
2766
3036
  console.log(chalk.green('\n✅ Requirement marked as DONE and verified complete!'));
2767
3037
 
2768
3038
  // Move completed requirement to TO VERIFY section (for human verification)
3039
+ console.log(chalk.cyan(`\n[${getTimestamp()}] Moving requirement to TO VERIFY: "${currentTitle.substring(0, 60)}..."`));
2769
3040
  const moveResult = await moveCompletedRequirement(repoPath, currentTitle);
2770
3041
 
2771
3042
  if (!moveResult.success) {
2772
- console.log(chalk.yellow(`\n⚠️ Error moving requirement: ${moveResult.error}`));
3043
+ console.log(chalk.red(`\nError moving requirement: ${moveResult.error}`));
3044
+ console.log(chalk.yellow(` Requirement title: "${currentTitle}"`));
2773
3045
  console.log(' Auto mode stopping.');
2774
3046
  exitReason = 'error';
2775
3047
  break;
2776
3048
  }
2777
3049
 
2778
- console.log(chalk.green(`\n✓ Moved requirement to TO VERIFY section (awaiting human verification)`));
3050
+ console.log(chalk.green(`\n✓ Successfully moved requirement to TO VERIFY section (awaiting human verification)`));
2779
3051
 
2780
3052
  // Increment requirements completed counter
2781
3053
  requirementsCompleted++;
@@ -2855,16 +3127,18 @@ Example BAD questions (never ask these):
2855
3127
  console.log(chalk.gray(' Marking as complete and moving to next requirement...'));
2856
3128
 
2857
3129
  // Move completed requirement to TO VERIFY section (for human verification)
3130
+ console.log(chalk.cyan(`\n[${getTimestamp()}] Moving requirement to TO VERIFY: "${currentTitle.substring(0, 60)}..."`));
2858
3131
  const moveResult = await moveCompletedRequirement(repoPath, currentTitle);
2859
3132
 
2860
3133
  if (!moveResult.success) {
2861
- console.log(chalk.yellow(`\n⚠️ Error moving requirement: ${moveResult.error}`));
3134
+ console.log(chalk.red(`\nError moving requirement: ${moveResult.error}`));
3135
+ console.log(chalk.yellow(` Requirement title: "${currentTitle}"`));
2862
3136
  console.log(' Auto mode stopping.');
2863
3137
  exitReason = 'error';
2864
3138
  break;
2865
3139
  }
2866
3140
 
2867
- console.log(chalk.green(`\n✓ Moved requirement to TO VERIFY section (awaiting human verification)`));
3141
+ console.log(chalk.green(`\n✓ Successfully moved requirement to TO VERIFY section (awaiting human verification)`));
2868
3142
 
2869
3143
  // Increment requirements completed counter
2870
3144
  requirementsCompleted++;
@@ -4684,9 +4958,60 @@ async function config(options) {
4684
4958
  }
4685
4959
  }
4686
4960
 
4961
+ async function listAgents() {
4962
+ const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
4963
+ const providerManager = new ProviderManager();
4964
+
4965
+ console.log(chalk.blue('\n📋 Available IDE Agents and Quota Status:\n'));
4966
+
4967
+ // Get all provider definitions
4968
+ const providers = getProviderDefinitions();
4969
+
4970
+ // Check each provider's quota status
4971
+ for (const provider of providers) {
4972
+ const rateLimitInfo = providerManager.getRateLimitInfo(provider.id);
4973
+
4974
+ let statusIcon = '✅';
4975
+ let statusText = chalk.green('Available');
4976
+ let quotaInfo = '';
4977
+
4978
+ if (rateLimitInfo.isRateLimited) {
4979
+ statusIcon = '⚠️';
4980
+ statusText = chalk.yellow('Quota Limit');
4981
+
4982
+ if (rateLimitInfo.resetTime) {
4983
+ const resetDate = new Date(rateLimitInfo.resetTime);
4984
+ const now = new Date();
4985
+ const minutesRemaining = Math.ceil((resetDate - now) / (1000 * 60));
4986
+
4987
+ if (minutesRemaining > 60) {
4988
+ const hoursRemaining = Math.ceil(minutesRemaining / 60);
4989
+ quotaInfo = chalk.gray(` (resets in ${hoursRemaining}h)`);
4990
+ } else if (minutesRemaining > 0) {
4991
+ quotaInfo = chalk.gray(` (resets in ${minutesRemaining}m)`);
4992
+ } else {
4993
+ quotaInfo = chalk.gray(' (resetting soon)');
4994
+ }
4995
+ }
4996
+
4997
+ if (rateLimitInfo.reason) {
4998
+ quotaInfo += chalk.gray(` - ${rateLimitInfo.reason}`);
4999
+ }
5000
+ }
5001
+
5002
+ console.log(`${statusIcon} ${chalk.cyan(provider.name)} ${statusText}${quotaInfo}`);
5003
+ if (provider.description) {
5004
+ console.log(` ${chalk.gray(provider.description)}`);
5005
+ }
5006
+ }
5007
+
5008
+ console.log(chalk.gray('\n💡 Tip: Auto mode will automatically skip quota-limited agents\n'));
5009
+ }
5010
+
4687
5011
  module.exports = {
4688
5012
  start,
4689
5013
  stop,
4690
5014
  status,
4691
- config
5015
+ config,
5016
+ listAgents
4692
5017
  };