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.
- package/bin/vibecodingmachine.js +301 -12
- package/package.json +5 -2
- package/repro_open.js +13 -0
- package/reproduce_issue.js +160 -0
- package/scripts/postinstall.js +80 -0
- package/src/commands/auth.js +0 -1
- package/src/commands/auto-direct.js +455 -136
- package/src/commands/auto.js +488 -163
- package/src/commands/computers.js +306 -0
- package/src/commands/repo.js +0 -1
- package/src/commands/requirements-remote.js +308 -0
- package/src/commands/requirements.js +233 -16
- package/src/commands/status.js +0 -1
- package/src/commands/sync.js +280 -0
- package/src/utils/agent-selector.js +50 -0
- package/src/utils/antigravity-installer.js +212 -0
- package/src/utils/antigravity-js-handler.js +60 -0
- package/src/utils/asset-cleanup.js +60 -0
- package/src/utils/auth.js +232 -8
- package/src/utils/auto-mode-ansi-ui.js +0 -1
- package/src/utils/auto-mode-simple-ui.js +3 -23
- package/src/utils/compliance-check.js +166 -0
- package/src/utils/config.js +27 -1
- package/src/utils/copy-with-progress.js +167 -0
- package/src/utils/download-with-progress.js +84 -0
- package/src/utils/first-run.js +410 -0
- package/src/utils/interactive.js +1197 -391
- package/src/utils/kiro-installer.js +178 -0
- package/src/utils/persistent-header.js +1 -3
- package/src/utils/provider-registry.js +13 -4
- package/src/utils/status-card.js +2 -1
- package/src/utils/user-tracking.js +300 -0
- package/tests/requirements-navigator-buildtree-await.test.js +28 -0
package/src/commands/auto.js
CHANGED
|
@@ -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 {
|
|
6
|
-
const {
|
|
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
|
-
|
|
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 &&
|
|
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 &&
|
|
217
|
+
if (inNotYetCompleted && !requirementFound && trimmed.startsWith('- ')) {
|
|
219
218
|
// Add the requirement before the first existing requirement
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
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 (
|
|
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
|
-
|
|
247
|
-
|
|
249
|
+
await fs.writeFile(reqPath, updatedLines.join('\n'));
|
|
250
|
+
return { success: true };
|
|
248
251
|
}
|
|
249
252
|
}
|
|
250
253
|
}
|
|
251
254
|
|
|
252
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
442
|
-
if (trimmed.startsWith('##') &&
|
|
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
|
-
|
|
445
|
-
updatedLines.push(line);
|
|
501
|
+
}
|
|
446
502
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
-
|
|
457
|
-
|
|
458
|
-
|
|
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
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
//
|
|
736
|
+
// Get provider preferences and definitions
|
|
568
737
|
const savedConfig = await getAutoConfig();
|
|
569
738
|
const prefs = await getProviderPreferences();
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
const
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
|
|
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 ||
|
|
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
|
-
|
|
844
|
-
const stageMap = {
|
|
845
|
-
|
|
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 (
|
|
892
|
-
|
|
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
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
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
|
-
|
|
904
|
-
|
|
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
|
|
1793
|
-
for (
|
|
1794
|
-
|
|
1795
|
-
|
|
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
|
-
//
|
|
1801
|
-
if (inTodoSection && line.
|
|
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
|
-
//
|
|
1809
|
-
if (inTodoSection && line.
|
|
1810
|
-
|
|
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
|
|
2650
|
-
console.log(chalk.cyan(`\n[${getTimestamp()}] 🔍
|
|
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
|
-
//
|
|
2653
|
-
|
|
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
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
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
|
-
|
|
2680
|
-
|
|
2948
|
+
const searchFindings = searchResult.output || 'Search completed but no findings reported.';
|
|
2949
|
+
console.log(chalk.gray(`\nFindings: ${searchFindings}\n`));
|
|
2681
2950
|
|
|
2682
|
-
|
|
2683
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
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
|
-
|
|
2725
|
-
|
|
2993
|
+
const vagueCheckOutput = vagueCheckResult.output || '';
|
|
2994
|
+
const isVague = vagueCheckOutput.toUpperCase().includes('REQUIREMENT NEEDS CLARIFICATION');
|
|
2726
2995
|
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
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
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
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
|
-
|
|
2740
|
-
|
|
3008
|
+
// Move requirement to "Requirements needing manual feedback" section with findings
|
|
3009
|
+
const moveToFeedbackResult = await moveRequirementToFeedback(repoPath, currentTitle, questions, searchFindings);
|
|
2741
3010
|
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
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.
|
|
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.
|
|
3043
|
+
console.log(chalk.red(`\n❌ Error 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✓
|
|
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.
|
|
3134
|
+
console.log(chalk.red(`\n❌ Error 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✓
|
|
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
|
};
|