vibecodingmachine-cli 2025.12.6-1702 → 2025.12.24-2348

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.
@@ -5,21 +5,33 @@
5
5
  */
6
6
 
7
7
  const chalk = require('chalk');
8
- const { DirectLLMManager } = require('vibecodingmachine-core');
9
- const { getRepoPath, getAutoConfig, setAutoConfig } = require('../utils/config');
8
+ const { DirectLLMManager, AppleScriptManager, t, detectLocale, setLocale } = require('vibecodingmachine-core');
9
+
10
+ // Initialize locale detection for auto mode
11
+ const detectedLocale = detectLocale();
12
+ setLocale(detectedLocale);
13
+ const { getRepoPath, getAutoConfig, setAutoConfig, getStages, DEFAULT_STAGES } = require('../utils/config');
10
14
  const { getRequirementsPath, readRequirements } = require('vibecodingmachine-core');
11
15
  const fs = require('fs-extra');
12
16
  const path = require('path');
13
17
  const { spawn } = require('child_process');
14
18
  const chokidar = require('chokidar');
19
+ const stringWidth = require('string-width');
20
+ const { getProviderPreferences, getProviderDefinition } = require('../utils/provider-registry');
21
+ const { createKeyboardHandler } = require('../utils/keyboard-handler');
22
+ const logger = require('../utils/logger');
23
+ const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
24
+ const { checkAntigravityRateLimit, handleAntigravityRateLimit } = require('../utils/antigravity-js-handler');
25
+
15
26
  // Status management will use in-process tracking instead of external file
16
27
  const CLI_ENTRY_POINT = path.join(__dirname, '../../bin/vibecodingmachine.js');
17
- const { getProviderPreferences, getProviderDefinition } = require('../utils/provider-registry');
18
28
 
19
29
  // CRITICAL: Shared ProviderManager instance to track rate limits across all function calls
20
- const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
21
30
  const sharedProviderManager = new ProviderManager();
22
31
 
32
+ // Configured stages (will be loaded in handleAutoStart)
33
+ let configuredStages = DEFAULT_STAGES;
34
+
23
35
  /**
24
36
  * Get timestamp for logging
25
37
  */
@@ -33,6 +45,25 @@ function getTimestamp() {
33
45
  }) + ' MST';
34
46
  }
35
47
 
48
+ /**
49
+ * Translate workflow stage names
50
+ */
51
+ function translateStage(stage) {
52
+ const stageMap = {
53
+ 'PREPARE': 'workflow.stage.prepare',
54
+ 'REPRODUCE': 'workflow.stage.reproduce',
55
+ 'CREATE UNIT TEST': 'workflow.stage.create.unit.test',
56
+ 'ACT': 'workflow.stage.act',
57
+ 'CLEAN UP': 'workflow.stage.clean.up',
58
+ 'VERIFY': 'workflow.stage.verify',
59
+ 'RUN UNIT TESTS': 'workflow.stage.run.unit.tests',
60
+ 'DONE': 'workflow.stage.done'
61
+ };
62
+
63
+ const key = stageMap[stage];
64
+ return key ? t(key) : stage;
65
+ }
66
+
36
67
  /**
37
68
  * Strip ANSI escape codes from a string
38
69
  */
@@ -46,7 +77,6 @@ function stripAnsi(str) {
46
77
  * Uses string-width library for accurate Unicode width calculation
47
78
  */
48
79
  function getVisualWidth(str) {
49
- const stringWidth = require('string-width');
50
80
  return stringWidth(str);
51
81
  }
52
82
 
@@ -111,7 +141,8 @@ async function updateRequirementsStatus(repoPath, status) {
111
141
  break;
112
142
  }
113
143
 
114
- if (inStatusSection && line.trim().match(/^(PREPARE|CREATE|ACT|CLEAN UP|VERIFY|DONE)$/)) {
144
+ // Check against configured stages
145
+ if (inStatusSection && configuredStages.includes(line.trim())) {
115
146
  statusLineIndex = i;
116
147
  break;
117
148
  }
@@ -143,7 +174,7 @@ async function updateRequirementsStatus(repoPath, status) {
143
174
  await fs.writeFile(reqPath, lines.join('\n'));
144
175
  } catch (error) {
145
176
  // Silently fail - don't break execution if status update fails
146
- console.error(chalk.gray(` Warning: Could not update status in requirements file: ${error.message}`));
177
+ console.error(chalk.gray(` ${t('auto.direct.status.update.warning')} ${error.message}`));
147
178
  }
148
179
  }
149
180
 
@@ -160,28 +191,24 @@ let storedStatus = '';
160
191
  * Now uses persistent header that stays at top while output scrolls
161
192
  */
162
193
  function printStatusCard(currentTitle, currentStatus) {
163
- const stages = ['PREPARE', 'ACT', 'CLEAN UP', 'VERIFY', 'DONE'];
164
- const stageMap = {
165
- 'PREPARE': 0,
166
- 'ACT': 1,
167
- 'CLEAN UP': 2,
168
- 'VERIFY': 3,
169
- 'DONE': 4
170
- };
194
+ const stages = configuredStages;
195
+ const stageMap = {};
196
+ stages.forEach((s, i) => stageMap[s] = i);
171
197
 
172
198
  const currentIndex = stageMap[currentStatus] || 0;
173
199
 
174
200
  // Build workflow line with visual prominence for current stage
175
201
  const stageParts = stages.map((stage, idx) => {
202
+ const translatedStage = translateStage(stage);
176
203
  if (idx < currentIndex) {
177
204
  // Completed stages - grey with checkmark
178
- return chalk.grey(`āœ… ${stage}`);
205
+ return chalk.grey(`āœ… ${translatedStage}`);
179
206
  } else if (idx === currentIndex) {
180
207
  // CURRENT stage - BRIGHT WHITE with hammer
181
- return chalk.bold.white(`šŸ”Ø ${stage}`);
208
+ return chalk.bold.white(`šŸ”Ø ${translatedStage}`);
182
209
  } else {
183
210
  // Future stages - grey with hourglass
184
- return chalk.grey(`ā³ ${stage}`);
211
+ return chalk.grey(`ā³ ${translatedStage}`);
185
212
  }
186
213
  });
187
214
 
@@ -192,9 +219,10 @@ function printStatusCard(currentTitle, currentStatus) {
192
219
  const boxWidth = Math.max(terminalWidth - 4, 80); // Leave 4 chars margin, minimum 80
193
220
 
194
221
  // Truncate title if needed to fit in box
195
- const maxTitleWidth = boxWidth - 20; // Leave room for "šŸŽÆ Working on: "
222
+ const workingOnLabel = `šŸŽÆ ${t('auto.direct.requirement.working.on')} `;
223
+ const maxTitleWidth = boxWidth - stringWidth(workingOnLabel) - 2; // Leave room for label
196
224
  const titleShort = currentTitle?.substring(0, maxTitleWidth) + (currentTitle?.length > maxTitleWidth ? '...' : '');
197
- const titleLine = chalk.cyan(`šŸŽÆ Working on: `) + chalk.white(titleShort);
225
+ const titleLine = chalk.cyan(workingOnLabel) + chalk.white(titleShort);
198
226
 
199
227
  // Build the status box content
200
228
  const statusBoxContent =
@@ -249,7 +277,7 @@ async function getCurrentRequirement(repoPath) {
249
277
  // Skip empty titles
250
278
  if (title && title.length > 0) {
251
279
  // Read package and description (optional)
252
- let package = null;
280
+ let pkg = null;
253
281
  let description = '';
254
282
  let j = i + 1;
255
283
 
@@ -262,7 +290,7 @@ async function getCurrentRequirement(repoPath) {
262
290
  }
263
291
  // Check for PACKAGE line
264
292
  if (nextLine.startsWith('PACKAGE:')) {
265
- package = nextLine.replace(/^PACKAGE:\s*/, '').trim();
293
+ pkg = nextLine.replace(/^PACKAGE:\s*/, '').trim();
266
294
  } else if (nextLine && !nextLine.startsWith('PACKAGE:')) {
267
295
  // Description line (not empty, not package)
268
296
  if (description) {
@@ -277,7 +305,7 @@ async function getCurrentRequirement(repoPath) {
277
305
  return {
278
306
  text: title,
279
307
  fullLine: lines[i],
280
- package: package,
308
+ package: pkg,
281
309
  description: description
282
310
  };
283
311
  }
@@ -286,7 +314,7 @@ async function getCurrentRequirement(repoPath) {
286
314
 
287
315
  return null;
288
316
  } catch (err) {
289
- console.error('Error reading requirement:', err.message);
317
+ console.error(t('auto.direct.requirement.read.error'), err.message);
290
318
  return null;
291
319
  }
292
320
  }
@@ -333,7 +361,7 @@ async function countTodoRequirements(repoPath) {
333
361
 
334
362
  return count;
335
363
  } catch (err) {
336
- console.error('Error counting requirements:', err.message);
364
+ console.error(t('auto.direct.requirement.count.error'), err.message);
337
365
  return 0;
338
366
  }
339
367
  }
@@ -412,7 +440,7 @@ async function moveRequirementToVerify(repoPath, requirementText) {
412
440
  }
413
441
 
414
442
  if (requirementStartIndex === -1) {
415
- console.log(chalk.yellow(`āš ļø Could not find requirement "${requirementText.substring(0, 60)}..." in TODO section`));
443
+ console.log(chalk.yellow(`āš ļø ${t('auto.direct.requirement.not.found.todo', { requirement: requirementText.substring(0, 60) + '...' })}`));
416
444
  return false;
417
445
  }
418
446
 
@@ -448,7 +476,7 @@ async function moveRequirementToVerify(repoPath, requirementText) {
448
476
 
449
477
  // If no more TODO requirements, log message
450
478
  if (!hasMoreTodoRequirements) {
451
- console.log(chalk.green('šŸŽ‰ No more requirements in TODO section'));
479
+ console.log(chalk.green(`šŸŽ‰ ${t('auto.direct.requirement.no.more.todo')}`));
452
480
  }
453
481
 
454
482
 
@@ -533,7 +561,7 @@ async function moveRequirementToVerify(repoPath, requirementText) {
533
561
 
534
562
  // Safety check: verifyIndex should be valid
535
563
  if (verifyIndex === -1) {
536
- console.error('Failed to create TO VERIFY BY HUMAN section');
564
+ console.error(t('auto.direct.verify.section.create.failed'));
537
565
  return false;
538
566
  }
539
567
  }
@@ -616,7 +644,7 @@ async function moveRequirementToVerify(repoPath, requirementText) {
616
644
  console.log(chalk.green(`āœ… Moved requirement to TO VERIFY BY HUMAN: ${requirementText.substring(0, 80)}...`));
617
645
  return true;
618
646
  } catch (err) {
619
- console.error('Error moving requirement to TO VERIFY:', err.message);
647
+ console.error(t('auto.direct.requirement.move.verify.error'), err.message);
620
648
  console.error('āš ļø Requirement may have been lost. Please check the requirements file.');
621
649
  return false;
622
650
  }
@@ -647,7 +675,7 @@ async function moveRequirementToRecycle(repoPath, requirementText) {
647
675
  }
648
676
 
649
677
  if (requirementIndex === -1) {
650
- console.log(chalk.yellow('āš ļø Could not find requirement'));
678
+ console.log(chalk.yellow(`āš ļø ${t('auto.direct.requirement.not.found')}`));
651
679
  return false;
652
680
  }
653
681
 
@@ -677,7 +705,7 @@ async function moveRequirementToRecycle(repoPath, requirementText) {
677
705
  await fs.writeFile(reqPath, lines.join('\n'));
678
706
  return true;
679
707
  } catch (err) {
680
- console.error('Error moving requirement:', err.message);
708
+ console.error(t('auto.direct.requirement.move.error'), err.message);
681
709
  return false;
682
710
  }
683
711
  }
@@ -859,19 +887,19 @@ async function acquireProviderConfig(excludeProvider = null) {
859
887
  }
860
888
 
861
889
  if (selection.status === 'no_providers') {
862
- console.log(chalk.red('\nāœ— No providers available. Configure API keys or IDE agents first.\n'));
890
+ console.log(chalk.red(`\nāœ— ${t('auto.direct.provider.none.available')}\n`));
863
891
  return null;
864
892
  }
865
893
 
866
894
  if (selection.status === 'no_enabled') {
867
- console.log(chalk.red('\nāœ— All providers are disabled. Enable at least one provider in the Agent menu.\n'));
895
+ console.log(chalk.red(`\nāœ— ${t('auto.direct.provider.all.disabled')}\n`));
868
896
  return null;
869
897
  }
870
898
 
871
899
  if (selection.status === 'all_rate_limited') {
872
- console.log(chalk.yellow('\nāš ļø All enabled providers are currently rate limited.'));
900
+ console.log(chalk.yellow(`\nāš ļø ${t('auto.direct.provider.all.rate.limited')}`));
873
901
  if (selection.disabledProviders && selection.disabledProviders.length > 0) {
874
- console.log(chalk.gray(' Tip: Enable additional providers in the Agent menu for more fallbacks.'));
902
+ console.log(chalk.gray(` ${t('auto.direct.provider.enable.tip')}`));
875
903
  }
876
904
  const waitMs = selection.nextResetMs || 60000;
877
905
  const waitMinutes = Math.max(1, Math.ceil(waitMs / 60000));
@@ -987,7 +1015,7 @@ async function applyFileChange(change, repoPath) {
987
1015
  let content = await fs.readFile(fullPath, 'utf8');
988
1016
 
989
1017
  // Try exact match first
990
- console.log(chalk.gray(` šŸ” Trying exact match...`));
1018
+ console.log(chalk.gray(` šŸ” ${t('auto.direct.files.trying.exact')}`));
991
1019
  if (content.includes(change.search)) {
992
1020
  const newContent = content.replace(change.search, change.replace);
993
1021
  await fs.writeFile(fullPath, newContent, 'utf8');
@@ -997,7 +1025,7 @@ async function applyFileChange(change, repoPath) {
997
1025
  console.log(chalk.gray(` āœ— Exact match failed`));
998
1026
 
999
1027
  // Try with normalized whitespace (fuzzy match)
1000
- console.log(chalk.gray(` šŸ” Trying fuzzy match (normalized whitespace)...`));
1028
+ console.log(chalk.gray(` šŸ” ${t('auto.direct.files.trying.fuzzy')}`));
1001
1029
  const normalizedSearch = normalizeWhitespace(change.search);
1002
1030
  const lines = content.split('\n');
1003
1031
  const searchLines = change.search.split('\n');
@@ -1125,7 +1153,7 @@ async function findRelevantFiles(requirement, repoPath) {
1125
1153
  relevantFiles.push('packages/cli/src/utils/interactive.js');
1126
1154
  }
1127
1155
  } catch (error) {
1128
- console.log(chalk.yellow(`āš ļø Error finding files: ${error.message}`));
1156
+ console.log(chalk.yellow(`āš ļø ${t('auto.direct.files.error')} ${error.message}`));
1129
1157
  }
1130
1158
 
1131
1159
  return relevantFiles;
@@ -1298,7 +1326,7 @@ async function readFileSnippets(files, repoPath, requirement) {
1298
1326
 
1299
1327
  async function runIdeProviderIteration(providerConfig, repoPath) {
1300
1328
  return new Promise((resolve) => {
1301
- console.log(chalk.cyan(`āš™ļø Launching ${providerConfig.displayName} fallback (auto:start)...\n`));
1329
+ console.log(chalk.cyan(`āš™ļø ${t('auto.direct.provider.launching', { provider: providerConfig.displayName })}\n`));
1302
1330
 
1303
1331
  const args = [CLI_ENTRY_POINT, 'auto:start', '--ide', providerConfig.ide || providerConfig.provider, '--max-chats', String(providerConfig.maxChats || 1)];
1304
1332
  const child = spawn(process.execPath, args, {
@@ -1334,11 +1362,14 @@ async function runIdeProviderIteration(providerConfig, repoPath) {
1334
1362
  resolve({ success: true, output: combinedOutput });
1335
1363
  } else {
1336
1364
  const message = `${providerConfig.displayName} exited with code ${code}`;
1365
+ const antigravityRateLimit = checkAntigravityRateLimit(combinedOutput);
1366
+
1337
1367
  resolve({
1338
1368
  success: false,
1339
1369
  error: combinedOutput ? `${message}\n${combinedOutput}` : message,
1340
1370
  output: combinedOutput,
1341
- rateLimited: isRateLimitMessage(combinedOutput)
1371
+ rateLimited: isRateLimitMessage(combinedOutput) || antigravityRateLimit.isRateLimited,
1372
+ antigravityRateLimited: antigravityRateLimit.isRateLimited
1342
1373
  });
1343
1374
  }
1344
1375
  });
@@ -1362,9 +1393,9 @@ async function waitForIdeCompletion(repoPath, requirementText, ideType = '', tim
1362
1393
  let quotaHandled = false;
1363
1394
  const checkIntervalMs = 2000; // Check every 2 seconds
1364
1395
 
1365
- console.log(chalk.gray('\nā³ Waiting for IDE agent to complete...'));
1366
- console.log(chalk.gray(` Monitoring: ${path.basename(reqPath)}`));
1367
- console.log(chalk.gray(` Timeout: ${Math.floor(timeoutMs / 60000)} minutes\n`));
1396
+ console.log(chalk.gray(`\nā³ ${t('auto.direct.ide.waiting')}`));
1397
+ console.log(chalk.gray(` ${t('auto.direct.ide.monitoring', { filename: path.basename(reqPath) })}`));
1398
+ console.log(chalk.gray(` ${t('auto.direct.ide.timeout', { minutes: Math.floor(timeoutMs / 60000) })}\n`));
1368
1399
 
1369
1400
  const watcher = chokidar.watch(reqPath, {
1370
1401
  persistent: true,
@@ -1435,26 +1466,15 @@ async function waitForIdeCompletion(repoPath, requirementText, ideType = '', tim
1435
1466
  // Check 3: Quota limit detection for Antigravity (after 2 minutes of waiting)
1436
1467
  const elapsed = Date.now() - startTime;
1437
1468
  if (ideType === 'antigravity' && !quotaHandled && elapsed >= 120000) {
1438
- console.log(chalk.yellow('\nāš ļø No progress detected after 2 minutes - checking for quota limit...\n'));
1439
- try {
1440
- const { AppleScriptManager } = require('vibecodingmachine-core');
1441
- const manager = new AppleScriptManager();
1442
- const result = await manager.handleAntigravityQuotaLimit();
1443
-
1444
- if (result.success) {
1445
- console.log(chalk.green(`āœ“ Switched to model: ${result.model || 'alternative'}`));
1446
- console.log(chalk.cyan(' Resuming work with new model...\n'));
1447
- quotaHandled = true;
1448
- // Reset start time to give new model time to work
1449
- startTime = Date.now();
1450
- } else {
1451
- console.log(chalk.yellow(`āš ļø Could not switch models: ${result.error}\n`));
1452
- quotaHandled = true; // Don't try again
1453
- }
1454
- } catch (error) {
1455
- console.error(chalk.red(`Error handling quota limit: ${error.message}\n`));
1456
- quotaHandled = true; // Don't try again
1457
- }
1469
+ console.log(chalk.yellow('\nāš ļø Antigravity quota limit detected after 2 minutes\n'));
1470
+ console.log(chalk.cyan(' Switching to next available IDE agent...\n'));
1471
+ watcher.close();
1472
+ resolve({
1473
+ success: false,
1474
+ reason: 'antigravity-quota',
1475
+ antigravityRateLimited: true // This triggers switching to next provider
1476
+ });
1477
+ return;
1458
1478
  }
1459
1479
 
1460
1480
  // Check 4: Timeout
@@ -1469,7 +1489,7 @@ async function waitForIdeCompletion(repoPath, requirementText, ideType = '', tim
1469
1489
  if (Date.now() - lastCheckTime >= 30000) {
1470
1490
  const elapsedMin = Math.floor(elapsed / 60000);
1471
1491
  const remainingMin = Math.floor((timeoutMs - elapsed) / 60000);
1472
- console.log(chalk.gray(` Still waiting... (${elapsedMin}m elapsed, ${remainingMin}m remaining)`));
1492
+ console.log(chalk.gray(` ${t('auto.direct.ide.still.waiting', { elapsed: elapsedMin, remaining: remainingMin })}`));
1473
1493
  lastCheckTime = Date.now();
1474
1494
  }
1475
1495
  } catch (error) {
@@ -1503,7 +1523,7 @@ async function runIdeFallbackIteration(requirement, providerConfig, repoPath, pr
1503
1523
  // Update console and requirements file with PREPARE status
1504
1524
  printStatusCard(requirement.text, 'PREPARE');
1505
1525
  await updateRequirementsStatus(repoPath, 'PREPARE');
1506
- console.log(chalk.gray('Skipping direct file context - delegating to IDE agent.\n'));
1526
+ console.log(chalk.gray(`${t('auto.direct.ide.skipping.context')}\n`));
1507
1527
 
1508
1528
  // Update console and requirements file with ACT status
1509
1529
  printStatusCard(requirement.text, 'ACT');
@@ -1511,17 +1531,27 @@ async function runIdeFallbackIteration(requirement, providerConfig, repoPath, pr
1511
1531
  const ideResult = await runIdeProviderIteration(providerConfig, repoPath);
1512
1532
 
1513
1533
  if (!ideResult.success) {
1534
+ if (ideResult.antigravityRateLimited) {
1535
+ await handleAntigravityRateLimit();
1536
+ return { success: false, error: 'Antigravity rate limit detected, retrying with next provider.', shouldRetry: true };
1537
+ }
1514
1538
  // CRITICAL: Mark provider as unavailable for ANY error so acquireProviderConfig() will skip it
1515
1539
  providerManager.markRateLimited(providerConfig.provider, providerConfig.model, ideResult.output || ideResult.error || 'IDE provider failed');
1516
1540
  return { success: false, error: ideResult.error || 'IDE provider failed' };
1517
1541
  }
1518
1542
 
1519
- console.log(chalk.green('āœ“ Prompt sent to IDE agent successfully'));
1543
+ console.log(chalk.green(`āœ“ ${t('auto.direct.ide.prompt.sent')}`));
1520
1544
 
1521
1545
  // Wait for IDE agent to complete the work (IDE will update status to DONE itself)
1522
1546
  const completionResult = await waitForIdeCompletion(repoPath, requirement.text, providerConfig.ide || providerConfig.provider);
1523
1547
 
1524
1548
  if (!completionResult.success) {
1549
+ if (completionResult.antigravityRateLimited) {
1550
+ console.log(chalk.yellow(`āš ļø ${t('auto.direct.provider.quota.exhausted', { provider: 'Antigravity' })}\n`));
1551
+ providerManager.markRateLimited(providerConfig.provider, providerConfig.model, 'Quota limit reached');
1552
+ return { success: false, error: 'Antigravity quota limit', shouldRetry: true };
1553
+ }
1554
+
1525
1555
  const errorMsg = completionResult.reason === 'timeout'
1526
1556
  ? 'IDE agent timed out'
1527
1557
  : 'IDE agent failed to complete';
@@ -1530,7 +1560,7 @@ async function runIdeFallbackIteration(requirement, providerConfig, repoPath, pr
1530
1560
  }
1531
1561
 
1532
1562
  printStatusCard(requirement.text, 'VERIFY');
1533
- console.log(chalk.green('āœ… IDE provider completed iteration\n'));
1563
+ console.log(chalk.green(`āœ… ${t('auto.direct.provider.completed')}\n`));
1534
1564
 
1535
1565
  printStatusCard(requirement.text, 'DONE');
1536
1566
  const duration = Date.now() - startTime;
@@ -1538,7 +1568,7 @@ async function runIdeFallbackIteration(requirement, providerConfig, repoPath, pr
1538
1568
 
1539
1569
  const moved = await moveRequirementToVerify(repoPath, requirement.text);
1540
1570
  if (moved) {
1541
- console.log(chalk.green('āœ“ Requirement moved to TO VERIFY BY HUMAN section'));
1571
+ console.log(chalk.green(`āœ“ ${t('auto.direct.status.verification.pending')}`));
1542
1572
  } else {
1543
1573
  console.log(chalk.yellow('āš ļø Requirement still pending verification in REQUIREMENTS file'));
1544
1574
  }
@@ -1569,15 +1599,15 @@ async function runIteration(requirement, providerConfig, repoPath) {
1569
1599
 
1570
1600
  console.log(chalk.bold.white('šŸ“‹ REQUIREMENT:'));
1571
1601
  console.log(chalk.cyan(` ${requirement.text}\n`));
1572
- console.log(chalk.gray('Provider:'), chalk.white(providerConfig.displayName));
1573
- console.log(chalk.gray('Repository:'), chalk.white(repoPath));
1602
+ console.log(chalk.gray(t('auto.direct.summary.provider')), chalk.white(providerConfig.displayName));
1603
+ console.log(chalk.gray(t('auto.repository')), chalk.white(repoPath));
1574
1604
  console.log();
1575
1605
 
1576
- console.log(chalk.cyan('šŸ” Searching for relevant files...\n'));
1606
+ console.log(chalk.cyan(`šŸ” ${t('auto.direct.files.searching')}...\n`));
1577
1607
  const relevantFiles = await findRelevantFiles(requirement.text, repoPath);
1578
1608
 
1579
1609
  if (relevantFiles.length > 0) {
1580
- console.log(chalk.white('Found relevant files:'));
1610
+ console.log(chalk.white(`${t('auto.direct.files.found', { count: relevantFiles.length })}:`));
1581
1611
  relevantFiles.forEach((file, i) => {
1582
1612
  console.log(chalk.gray(` ${i + 1}. ${file}`));
1583
1613
  });
@@ -1841,17 +1871,17 @@ Now implement the requirement. Remember: COPY THE SEARCH BLOCK EXACTLY!`;
1841
1871
 
1842
1872
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
1843
1873
 
1844
- console.log(chalk.bold.green('āœ… REQUIREMENT COMPLETED!\n'));
1845
- console.log(chalk.white('Requirement:'), chalk.cyan(requirement.text));
1846
- console.log(chalk.white('Files modified:'), chalk.cyan(changes.length));
1847
- console.log(chalk.white('Status:'), chalk.green('Moving to TO VERIFY BY HUMAN'));
1848
- console.log(chalk.white('Time:'), chalk.gray(`${elapsed}s`));
1874
+ console.log(chalk.bold.green(`āœ… ${t('auto.direct.requirement.completed')}\n`));
1875
+ console.log(chalk.white(`${t('auto.direct.requirement.title')}`), chalk.cyan(requirement.text));
1876
+ console.log(chalk.white(t('auto.direct.summary.files.modified')), chalk.cyan(changes.length));
1877
+ console.log(chalk.white(t('auto.direct.summary.status')), chalk.green(t('auto.direct.summary.moving.to.verify')));
1878
+ console.log(chalk.white(t('auto.direct.summary.time')), chalk.gray(`${elapsed}s`));
1849
1879
  console.log();
1850
1880
 
1851
1881
  // Move requirement to TO VERIFY section
1852
1882
  const moved = await moveRequirementToVerify(repoPath, requirement.text);
1853
1883
  if (moved) {
1854
- console.log(chalk.green('āœ“ Requirement moved to TO VERIFY BY HUMAN section'));
1884
+ console.log(chalk.green(`āœ“ ${t('auto.direct.status.verification.pending')}`));
1855
1885
  } else {
1856
1886
  console.log(chalk.yellow('āš ļø Could not automatically move requirement'));
1857
1887
  }
@@ -1886,22 +1916,32 @@ async function handleAutoStart(options) {
1886
1916
  }
1887
1917
  }
1888
1918
 
1889
- console.log(chalk.bold.cyan('\nšŸ¤– Vibe Coding Machine - Direct API Auto Mode\n'));
1919
+ console.log(chalk.bold.cyan('\n' + t('auto.direct.title') + '\n'));
1890
1920
  console.log(chalk.gray('═'.repeat(80)));
1891
1921
  console.log();
1892
1922
 
1893
1923
  // Get repo path
1924
+ // Load configured stages
1925
+ configuredStages = await getStages();
1926
+
1894
1927
  const repoPath = await getRepoPath();
1895
1928
  if (!repoPath) {
1896
1929
  console.log(chalk.red('āœ— No repository configured'));
1897
- console.log(chalk.gray('Run:'), chalk.cyan('vcm repo:set <path>'));
1930
+ console.log(chalk.gray(t('auto.direct.config.repo.not.set')));
1898
1931
  return;
1899
1932
  }
1900
1933
 
1901
- console.log(chalk.white('Repository:'), chalk.cyan(repoPath));
1934
+ console.log(chalk.white(t('auto.repository')), chalk.cyan(repoPath));
1902
1935
 
1903
- // Get provider configuration
1904
- let providerConfig = await acquireProviderConfig();
1936
+ // Get effective agent using centralized selector
1937
+ const { getEffectiveAgent } = require('../utils/agent-selector');
1938
+ const { PROVIDER_DEFINITIONS } = require('../utils/provider-registry');
1939
+ const PROVIDER_DEFINITION_MAP = new Map(PROVIDER_DEFINITIONS.map(def => [def.id, def]));
1940
+
1941
+ const { effectiveAgent } = await getEffectiveAgent(options, PROVIDER_DEFINITIONS, PROVIDER_DEFINITION_MAP);
1942
+
1943
+ // Get provider configuration for the selected agent
1944
+ let providerConfig = await acquireProviderConfig(effectiveAgent);
1905
1945
  if (!providerConfig) {
1906
1946
  return;
1907
1947
  }
@@ -1912,7 +1952,7 @@ async function handleAutoStart(options) {
1912
1952
  const config = await getAutoConfig();
1913
1953
  const unlimited = !options.maxChats && !config.maxChats && config.neverStop;
1914
1954
  const maxChats = unlimited ? Number.MAX_SAFE_INTEGER : (options.maxChats || config.maxChats || 1);
1915
- console.log(chalk.white('Max iterations:'), unlimited ? chalk.cyan('āˆž (never stop)') : chalk.cyan(maxChats));
1955
+ console.log(chalk.white(`${t('auto.direct.config.max.iterations')}`), unlimited ? chalk.cyan('āˆž (never stop)') : chalk.cyan(maxChats));
1916
1956
  console.log();
1917
1957
  console.log(chalk.gray('═'.repeat(80)));
1918
1958
 
@@ -1929,7 +1969,7 @@ async function handleAutoStart(options) {
1929
1969
  const requirement = await getCurrentRequirement(repoPath);
1930
1970
  if (!requirement) {
1931
1971
  console.log(chalk.bold.yellow('\nšŸŽ‰ All requirements completed!'));
1932
- console.log(chalk.gray('No more TODO items found in REQUIREMENTS file\n'));
1972
+ console.log(chalk.gray(`${t('auto.direct.no.more.todo.items')}\n`));
1933
1973
  break;
1934
1974
  }
1935
1975
 
@@ -1938,7 +1978,7 @@ async function handleAutoStart(options) {
1938
1978
  const currentReqNumber = completedCount + failedCount + 1;
1939
1979
 
1940
1980
  console.log(chalk.bold.magenta(`\n${'━'.repeat(80)}`));
1941
- console.log(chalk.bold.magenta(` REQUIREMENT ${currentReqNumber} of ${initialEffectiveMax}`));
1981
+ console.log(chalk.bold.magenta(` ${t('auto.direct.requirement.header', { current: currentReqNumber, total: initialEffectiveMax })}`));
1942
1982
  console.log(chalk.bold.magenta(`${'━'.repeat(80)}\n`));
1943
1983
 
1944
1984
  // Run iteration with full workflow
@@ -1971,7 +2011,7 @@ async function handleAutoStart(options) {
1971
2011
 
1972
2012
  // Handle child errors (but don't wait for completion)
1973
2013
  child.on('error', (err) => {
1974
- console.error(chalk.red('Error restarting CLI:'), err.message);
2014
+ console.error(chalk.red(t('auto.direct.config.restart.error')), err.message);
1975
2015
  });
1976
2016
 
1977
2017
  // Don't wait for child - unref so parent can exit
@@ -2027,20 +2067,20 @@ async function handleAutoStart(options) {
2027
2067
  console.log(chalk.bold.magenta(`${'━'.repeat(80)}\n`));
2028
2068
 
2029
2069
  const totalProcessed = completedCount + failedCount;
2030
- console.log(chalk.white('Total requirements:'), chalk.cyan(totalProcessed));
2031
- console.log(chalk.white('Completed:'), chalk.green(`${completedCount} āœ“`));
2070
+ console.log(chalk.white(t('auto.direct.summary.total.requirements')), chalk.cyan(totalProcessed));
2071
+ console.log(chalk.white(t('auto.direct.summary.completed')), chalk.green(`${completedCount} āœ“`));
2032
2072
  if (failedCount > 0) {
2033
- console.log(chalk.white('Failed:'), chalk.red(`${failedCount} āœ—`));
2073
+ console.log(chalk.white(t('auto.direct.summary.failed')), chalk.red(`${failedCount} āœ—`));
2034
2074
  }
2035
- console.log(chalk.white('Provider:'), chalk.cyan(providerConfig.displayName));
2075
+ console.log(chalk.white(t('auto.direct.summary.provider')), chalk.cyan(providerConfig.displayName));
2036
2076
  console.log();
2037
2077
 
2038
2078
  if (completedCount > 0) {
2039
- console.log(chalk.bold.green(`šŸŽ‰ ${completedCount} requirement${completedCount > 1 ? 's' : ''} moved to TO VERIFY BY HUMAN!`));
2079
+ console.log(chalk.bold.green(`šŸŽ‰ ${t('auto.direct.summary.final.message', { count: completedCount, plural: completedCount > 1 ? 's' : '' })}`));
2040
2080
  }
2041
2081
 
2042
2082
  } catch (error) {
2043
- console.error(chalk.red('\nāœ— Fatal Error:'), error.message);
2083
+ console.error(chalk.red('\n' + t('auto.fatal.error')), error.message);
2044
2084
  if (error.stack) {
2045
2085
  console.log(chalk.gray(error.stack));
2046
2086
  }