vibecodingmachine-cli 2025.12.22-2230 → 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.
@@ -17,10 +17,36 @@ const {
17
17
  getHostname,
18
18
  getRequirementsFilename,
19
19
  requirementsExists,
20
- isComputerNameEnabled
20
+ isComputerNameEnabled,
21
+ t,
22
+ detectLocale,
23
+ setLocale
21
24
  } = require('vibecodingmachine-core');
25
+
26
+ // Initialize locale detection for interactive mode
27
+ const detectedLocale = detectLocale();
28
+ setLocale(detectedLocale);
22
29
  const pkg = require('../../package.json');
23
30
 
31
+ /**
32
+ * Translate workflow stage names
33
+ */
34
+ function translateStage(stage) {
35
+ const stageMap = {
36
+ 'PREPARE': 'workflow.stage.prepare',
37
+ 'REPRODUCE': 'workflow.stage.reproduce',
38
+ 'CREATE UNIT TEST': 'workflow.stage.create.unit.test',
39
+ 'ACT': 'workflow.stage.act',
40
+ 'CLEAN UP': 'workflow.stage.clean.up',
41
+ 'VERIFY': 'workflow.stage.verify',
42
+ 'RUN UNIT TESTS': 'workflow.stage.run.unit.tests',
43
+ 'DONE': 'workflow.stage.done'
44
+ };
45
+
46
+ const key = stageMap[stage];
47
+ return key ? t(key) : stage;
48
+ }
49
+
24
50
  /**
25
51
  * Format IDE name for display
26
52
  * @param {string} ide - Internal IDE identifier
@@ -295,7 +321,7 @@ async function showWelcomeScreen() {
295
321
  console.log('\n' + boxen(
296
322
  chalk.bold.cyan('Vibe Coding Machine') + '\n' +
297
323
  chalk.gray(version) + '\n' +
298
- chalk.gray('Big Dreams + AI + VibeCodingMachine.com = Your money making apps'),
324
+ chalk.gray(t('banner.tagline')),
299
325
  {
300
326
  padding: 1,
301
327
  margin: 0,
@@ -306,8 +332,8 @@ async function showWelcomeScreen() {
306
332
 
307
333
  // Display repository and system info
308
334
  console.log();
309
- console.log(chalk.gray('Repo: '), formatPath(repoPath));
310
- console.log(chalk.gray('Computer Name: '), chalk.cyan(hostname));
335
+ console.log(chalk.gray(t('system.repo').padEnd(25)), formatPath(repoPath));
336
+ console.log(chalk.gray(t('system.computer.name').padEnd(25)), chalk.cyan(hostname));
311
337
 
312
338
  // Display auto mode progress if running
313
339
  if (autoStatus.running) {
@@ -378,8 +404,8 @@ function indexToLetter(index) {
378
404
 
379
405
  // Tree-style requirements navigator
380
406
  async function showRequirementsTree() {
381
- console.log(chalk.bold.cyan('\nšŸ“‹ Requirements Navigator\n'));
382
- console.log(chalk.gray('Use ↑/↓ to navigate, →/Enter/Space to expand, ←/ESC to collapse/go back\n'));
407
+ console.log(chalk.bold.cyan('\nšŸ“‹ ' + t('requirements.navigator.title') + '\n'));
408
+ console.log(chalk.gray(t('requirements.navigator.basic.instructions') + '\n'));
383
409
 
384
410
  const tree = {
385
411
  expanded: { root: true },
@@ -392,11 +418,11 @@ async function showRequirementsTree() {
392
418
  tree.items = [];
393
419
 
394
420
  // Root: Requirements
395
- tree.items.push({ level: 0, type: 'root', label: 'šŸ“‹ Requirements', key: 'root' });
421
+ tree.items.push({ level: 0, type: 'root', label: `šŸ“‹ ${t('requirements.menu.label')}`, key: 'root' });
396
422
 
397
423
  if (tree.expanded.root) {
398
- tree.items.push({ level: 1, type: 'add', label: 'āž• Add new requirement', key: 'add-one' });
399
- tree.items.push({ level: 1, type: 'add', label: 'āž• Add multiple requirements', key: 'add-many' });
424
+ tree.items.push({ level: 1, type: 'add', label: 'āž• ' + t('requirements.add.new'), key: 'add-one' });
425
+ tree.items.push({ level: 1, type: 'add', label: 'āž• ' + t('requirements.add.multiple'), key: 'add-many' });
400
426
 
401
427
  // Use pre-calculated stats and labels from shared logic
402
428
  const stats = await countRequirements();
@@ -405,6 +431,19 @@ async function showRequirementsTree() {
405
431
  todoLabel: 'ā³ TODO (0 - 0%)', toVerifyLabel: 'āœ… TO VERIFY (0 - 0%)', verifiedLabel: 'šŸŽ‰ VERIFIED (0 - 0%)'
406
432
  };
407
433
 
434
+ // Create localized labels
435
+ const localizedTodoLabel = todoCount > 0 ?
436
+ `ā³ ${t('requirements.section.todo')} (${todoCount} - ${Math.round((todoCount / total) * 100)}%)` :
437
+ `ā³ ${t('requirements.section.todo')} (0 - 0%)`;
438
+
439
+ const localizedToVerifyLabel = toVerifyCount > 0 ?
440
+ `āœ… ${t('requirements.section.to.verify')} (${toVerifyCount} - ${Math.round((toVerifyCount / total) * 100)}%)` :
441
+ `āœ… ${t('requirements.section.to.verify')} (0 - 0%)`;
442
+
443
+ const localizedVerifiedLabel = verifiedCount > 0 ?
444
+ `šŸŽ‰ ${t('requirements.section.verified')} (${verifiedCount} - ${Math.round((verifiedCount / total) * 100)}%)` :
445
+ `šŸŽ‰ ${t('requirements.section.verified')} (0 - 0%)`;
446
+
408
447
  const verifiedReqs = tree.verifiedReqs || [];
409
448
  const verifyReqs = tree.verifyReqs || [];
410
449
  const clarificationReqs = tree.clarificationReqs || [];
@@ -413,7 +452,7 @@ async function showRequirementsTree() {
413
452
 
414
453
  // VERIFIED section (first) - only show if has requirements
415
454
  if (verifiedReqs.length > 0 || verifiedCount > 0) {
416
- tree.items.push({ level: 1, type: 'section', label: `šŸŽ‰ ${verifiedLabel}`, key: 'verified' });
455
+ tree.items.push({ level: 1, type: 'section', label: localizedVerifiedLabel, key: 'verified' });
417
456
 
418
457
  if (tree.expanded.verified) {
419
458
  verifiedReqs.forEach((req, idx) => {
@@ -424,7 +463,7 @@ async function showRequirementsTree() {
424
463
 
425
464
  // TO VERIFY section (second) - only show if has requirements
426
465
  if (verifyReqs.length > 0 || toVerifyCount > 0) {
427
- tree.items.push({ level: 1, type: 'section', label: `āœ… ${toVerifyLabel}`, key: 'verify', section: 'āœ… Verified by AI screenshot' });
466
+ tree.items.push({ level: 1, type: 'section', label: localizedToVerifyLabel, key: 'verify', section: 'āœ… Verified by AI screenshot' });
428
467
 
429
468
  if (tree.expanded.verify) {
430
469
  verifyReqs.forEach((req, idx) => {
@@ -446,7 +485,7 @@ async function showRequirementsTree() {
446
485
 
447
486
  // TODO section (fourth) - only show if has requirements
448
487
  if (todoReqs.length > 0 || todoCount > 0) {
449
- tree.items.push({ level: 1, type: 'section', label: `ā³ ${todoLabel}`, key: 'todo', section: 'ā³ Requirements not yet completed' });
488
+ tree.items.push({ level: 1, type: 'section', label: localizedTodoLabel, key: 'todo', section: 'ā³ Requirements not yet completed' });
450
489
 
451
490
  if (tree.expanded.todo) {
452
491
  todoReqs.forEach((req, idx) => {
@@ -727,13 +766,13 @@ async function showRequirementsTree() {
727
766
 
728
767
  while (inTree) {
729
768
  console.clear();
730
- console.log(chalk.bold.cyan('\nšŸ“‹ Requirements Navigator\n'));
731
- console.log(chalk.gray('Use ↑/↓ to navigate, ') + chalk.white('→/Enter') + chalk.gray(' to expand/view questions, ← to go back, ') + chalk.white('R') + chalk.gray(' to Remove, ') + chalk.white('J') + chalk.gray(' to move down, ') + chalk.white('K') + chalk.gray(' to move up, ') + chalk.white('U') + chalk.gray(' Promote (šŸ‘), ') + chalk.white('D') + chalk.gray(' Demote/Move to TODO (šŸ‘Ž), ') + chalk.white('X/ESC') + chalk.gray(' to Exit.\n'));
769
+ console.log(chalk.bold.cyan('\nšŸ“‹ ' + t('requirements.navigator.title') + '\n'));
770
+ console.log(chalk.gray(t('requirements.navigator.instructions') + '\n'));
732
771
 
733
772
  // Safety check: ensure tree.selected is within bounds
734
773
  if (tree.items.length === 0) {
735
774
  console.log(chalk.yellow('No items to display.'));
736
- console.log(chalk.gray('\nPress any key to return to main menu...'));
775
+ console.log(chalk.gray(`\n${t('interactive.press.any.key.return')}`));
737
776
  await new Promise((resolve) => {
738
777
  process.stdin.once('keypress', () => resolve());
739
778
  });
@@ -883,7 +922,7 @@ async function showRequirementsTree() {
883
922
  console.clear();
884
923
  console.log(chalk.bold.green(`\n${current.label}\n`));
885
924
  console.log(chalk.gray('(From CHANGELOG.md - read only)'));
886
- console.log(chalk.gray('\nPress any key to go back...'));
925
+ console.log(chalk.gray(`\n${t('interactive.press.any.key.back')}`));
887
926
  await new Promise((resolve) => {
888
927
  readline.emitKeypressEvents(process.stdin);
889
928
  if (process.stdin.isTTY) {
@@ -986,7 +1025,7 @@ async function showRequirementsTree() {
986
1025
  function showGoodbyeMessage() {
987
1026
  const hour = new Date().getHours();
988
1027
  const message = hour < 21
989
- ? '\nšŸ‘‹ Goodbye! Be dreaming about what requirements to add!\n'
1028
+ ? '\nšŸ‘‹ ' + t('interactive.goodbye') + '\n'
990
1029
  : '\nšŸ‘‹ Goodbye! Go get some sleep!\n';
991
1030
  console.log(chalk.cyan(message));
992
1031
  }
@@ -1056,7 +1095,7 @@ async function confirmAction(message) {
1056
1095
  async function confirmAndExit() {
1057
1096
  console.log(chalk.gray('\n[DEBUG] confirmAndExit called'));
1058
1097
  console.log();
1059
- process.stdout.write(chalk.yellow(`Are you sure you want to exit? (${chalk.white('x')}/${chalk.white('y')}/${chalk.white('N')}) `));
1098
+ process.stdout.write(chalk.yellow(`${t('interactive.confirm.exit')} `));
1060
1099
 
1061
1100
  const confirmed = await new Promise((resolve) => {
1062
1101
  readline.emitKeypressEvents(process.stdin);
@@ -2550,7 +2589,7 @@ async function showQuickMenu(items, initialSelectedIndex = 0) {
2550
2589
  const lastLetter = letterCount > 0 ? indexToLetter(letterCount - 1) : 'a';
2551
2590
  const rangeText = letterCount > 1 ? `a-${lastLetter}` : (letterCount === 1 ? 'a' : '');
2552
2591
  const helpText = rangeText ? `${rangeText}, x` : 'x';
2553
- const helpString = `\n ↑/↓ to navigate, →/Enter to select, ←/X to exit, or press a letter (${helpText})`;
2592
+ const helpString = `\n ${t('interactive.navigation.help', { letters: helpText })}`;
2554
2593
  console.log(chalk.gray(helpString));
2555
2594
  linesPrinted += getVisualLineCount(helpString);
2556
2595
 
@@ -2699,7 +2738,7 @@ async function showProviderManagerMenu() {
2699
2738
 
2700
2739
  const render = async () => {
2701
2740
  process.stdout.write('\x1Bc');
2702
- console.log(chalk.bold.cyan('āš™ Provider Order & Availability\n'));
2741
+ console.log(chalk.bold.cyan('āš™ ' + t('provider.title') + '\n'));
2703
2742
 
2704
2743
  // Fetch quota info
2705
2744
  const sharedAuth = require('vibecodingmachine-core/src/auth/shared-auth-storage');
@@ -2719,13 +2758,13 @@ async function showProviderManagerMenu() {
2719
2758
  let quotaDisplay;
2720
2759
  if (remaining === 0) {
2721
2760
  // Rate limit active - show when it resets (in red)
2722
- quotaDisplay = chalk.gray(' Overall Quota: ') + chalk.red(`ā° Rate limit resets in ${hoursUntilReset}h ${minsUntilReset}m`);
2761
+ quotaDisplay = chalk.gray(' ' + t('provider.overall.quota') + ': ') + chalk.red(`ā° ${t('provider.rate.limit.resets')} ${hoursUntilReset}h ${minsUntilReset}m`);
2723
2762
  } else {
2724
2763
  // Quota available - show when it resets (in green)
2725
- quotaDisplay = chalk.gray(' Overall Quota: ') + chalk.green(`āœ“ Available (${remaining}/${quotaInfo.maxIterations})`) + chalk.gray(' • Resets in ') + chalk.cyan(`${hoursUntilReset}h ${minsUntilReset}m`);
2764
+ quotaDisplay = chalk.gray(' ' + t('provider.overall.quota') + ': ') + chalk.green(`āœ“ ${t('provider.available')} (${remaining}/${quotaInfo.maxIterations})`) + chalk.gray(' • ' + t('provider.resets.in') + ' ') + chalk.cyan(`${hoursUntilReset}h ${minsUntilReset}m`);
2726
2765
  }
2727
2766
  console.log(quotaDisplay);
2728
- console.log(chalk.gray(' ↑/↓ move selection j/k reorder e enable d disable Space toggle Enter save/select Esc cancel\n'));
2767
+ console.log(chalk.gray(' ' + t('provider.instructions') + '\n'));
2729
2768
 
2730
2769
  for (let idx = 0; idx < order.length; idx++) {
2731
2770
  const id = order[idx];
@@ -2779,7 +2818,7 @@ async function showProviderManagerMenu() {
2779
2818
  }
2780
2819
 
2781
2820
  if (quota.type === 'infinite') {
2782
- line += ` ${chalk.gray('[Quota: Infinite]')}`;
2821
+ line += ` ${chalk.gray('[' + t('provider.status.quota.infinite') + ']')}`;
2783
2822
  } else if (quota.type === 'rate-limit') {
2784
2823
  if (quota.isExceeded()) {
2785
2824
  if (quota.resetsAt) {
@@ -2792,9 +2831,9 @@ async function showProviderManagerMenu() {
2792
2831
  // Show time until rate limit starts (when it resets)
2793
2832
  if (quota.resetsAt) {
2794
2833
  const msUntilReset = new Date(quota.resetsAt).getTime() - Date.now();
2795
- line += ` ${chalk.green(`[āœ“ available • resets in ${formatDuration(msUntilReset)}]`)}`;
2834
+ line += ` ${chalk.green(`[āœ“ ${t('provider.status.available.resets')} ${formatDuration(msUntilReset)}]`)}`;
2796
2835
  } else {
2797
- line += ` ${chalk.green('[Available]')}`;
2836
+ line += ` ${chalk.green('[' + t('provider.status.available') + ']')}`;
2798
2837
  }
2799
2838
  }
2800
2839
  }
@@ -2807,9 +2846,9 @@ async function showProviderManagerMenu() {
2807
2846
 
2808
2847
  console.log();
2809
2848
  if (dirty) {
2810
- console.log(chalk.yellow('Pending changes will be saved on Enter...'));
2849
+ console.log(chalk.yellow(t('provider.pending.changes')));
2811
2850
  } else {
2812
- console.log(chalk.gray('No pending changes.'));
2851
+ console.log(chalk.gray(t('provider.no.pending.changes')));
2813
2852
  }
2814
2853
  };
2815
2854
 
@@ -3030,7 +3069,7 @@ async function showProviderManagerMenu() {
3030
3069
  */
3031
3070
  async function showCloudSyncMenu() {
3032
3071
  console.clear();
3033
- console.log(chalk.bold.cyan('\nā˜ļø Cloud Sync Management\n'));
3072
+ console.log(chalk.bold.cyan(`\nā˜ļø ${t('cloud.sync.title')}\n`));
3034
3073
 
3035
3074
  // Check if cloud sync is configured
3036
3075
  try {
@@ -3039,14 +3078,14 @@ async function showCloudSyncMenu() {
3039
3078
  await testEngine.initialize();
3040
3079
  testEngine.stop();
3041
3080
  } catch (error) {
3042
- console.log(chalk.yellow('āš ļø Cloud sync is not configured.\n'));
3043
- console.log(chalk.white('To set up cloud sync:\n'));
3044
- console.log(chalk.gray('1. Run: ') + chalk.cyan('./scripts/setup-cloud-sync.sh'));
3045
- console.log(chalk.gray('2. Add AWS configuration to your .env file'));
3046
- console.log(chalk.gray('3. Restart vcm\n'));
3047
- console.log(chalk.gray('For more info, see: ') + chalk.cyan('docs/CLOUD_SYNC.md\n'));
3048
-
3049
- console.log(chalk.gray('Press Enter to return to main menu...'));
3081
+ console.log(chalk.yellow(`āš ļø ${t('cloud.sync.not.configured')}\n`));
3082
+ console.log(chalk.white(`${t('cloud.sync.setup.title')}\n`));
3083
+ console.log(chalk.gray(`1. ${t('cloud.sync.setup.step1')} `) + chalk.cyan('./scripts/setup-cloud-sync.sh'));
3084
+ console.log(chalk.gray(`2. ${t('cloud.sync.setup.step2')}`));
3085
+ console.log(chalk.gray(`3. ${t('cloud.sync.setup.step3')}\n`));
3086
+ console.log(chalk.gray(`${t('cloud.sync.setup.info')} `) + chalk.cyan('docs/CLOUD_SYNC.md\n'));
3087
+
3088
+ console.log(chalk.gray(t('interactive.press.enter.return')));
3050
3089
  await new Promise(resolve => {
3051
3090
  const rl = readline.createInterface({
3052
3091
  input: process.stdin,
@@ -3064,22 +3103,22 @@ async function showCloudSyncMenu() {
3064
3103
  const syncCommands = require('../commands/sync');
3065
3104
 
3066
3105
  const choices = [
3067
- { name: 'šŸ“Š View All Computers', value: 'computers' },
3068
- { name: 'šŸ–„ļø Manage Another Computer\'s Requirements', value: 'manage-remote' },
3069
- { name: 'šŸ”„ Sync Now', value: 'sync-now' },
3070
- { name: 'šŸ“ˆ Sync Status', value: 'sync-status' },
3071
- { name: 'šŸ“œ Sync History', value: 'sync-history' },
3072
- { name: 'šŸ“‹ View Offline Queue', value: 'sync-queue' },
3073
- { name: 'šŸ–„ļø Register This Computer', value: 'register' },
3074
- { name: 'šŸŽÆ Update Focus Area', value: 'update-focus' },
3075
- { name: chalk.gray('← Back to Main Menu'), value: 'back' }
3106
+ { name: t('cloud.sync.menu.view.computers'), value: 'computers' },
3107
+ { name: t('cloud.sync.menu.manage.remote'), value: 'manage-remote' },
3108
+ { name: t('cloud.sync.menu.sync.now'), value: 'sync-now' },
3109
+ { name: t('cloud.sync.menu.sync.status'), value: 'sync-status' },
3110
+ { name: t('cloud.sync.menu.sync.history'), value: 'sync-history' },
3111
+ { name: t('cloud.sync.menu.offline.queue'), value: 'sync-queue' },
3112
+ { name: t('cloud.sync.menu.register'), value: 'register' },
3113
+ { name: t('cloud.sync.menu.update.focus'), value: 'update-focus' },
3114
+ { name: chalk.gray(t('interactive.back.to.menu')), value: 'back' }
3076
3115
  ];
3077
3116
 
3078
3117
  const { action } = await inquirer.prompt([
3079
3118
  {
3080
3119
  type: 'list',
3081
3120
  name: 'action',
3082
- message: 'Select an option:',
3121
+ message: t('interactive.select.option'),
3083
3122
  choices: choices
3084
3123
  }
3085
3124
  ]);
@@ -3092,7 +3131,7 @@ async function showCloudSyncMenu() {
3092
3131
  console.log(chalk.red('\nāœ— Error: ') + error.message);
3093
3132
  console.log(chalk.gray('\nTip: Make sure AWS credentials are configured and DynamoDB tables exist.'));
3094
3133
  }
3095
- console.log(chalk.gray('\nPress Enter to continue...'));
3134
+ console.log(chalk.gray(`\n${t('interactive.press.enter.continue')}`));
3096
3135
  await new Promise(resolve => {
3097
3136
  const rl = readline.createInterface({
3098
3137
  input: process.stdin,
@@ -3123,20 +3162,20 @@ async function showCloudSyncMenu() {
3123
3162
  syncEngine.stop();
3124
3163
 
3125
3164
  if (computers.length === 0) {
3126
- console.log(chalk.yellow('\n⚠ No computers registered yet.\n'));
3165
+ console.log(chalk.yellow(`\n⚠ ${t('computers.no.computers')}\n`));
3127
3166
  } else {
3128
3167
  // Let user select a computer
3129
3168
  const computerChoices = computers.map(c => ({
3130
- name: `${c.hostname || c.computerId} - ${c.focusArea || 'No focus'}`,
3169
+ name: `${c.hostname || c.computerId} - ${c.focusArea || t('computers.no.focus')}`,
3131
3170
  value: c.computerId
3132
3171
  }));
3133
- computerChoices.push({ name: chalk.gray('← Cancel'), value: null });
3172
+ computerChoices.push({ name: chalk.gray(t('computers.cancel')), value: null });
3134
3173
 
3135
3174
  const { selectedComputer } = await inquirer.prompt([
3136
3175
  {
3137
3176
  type: 'list',
3138
3177
  name: 'selectedComputer',
3139
- message: 'Select computer to manage:',
3178
+ message: t('computers.select.to.manage'),
3140
3179
  choices: computerChoices
3141
3180
  }
3142
3181
  ]);
@@ -3158,7 +3197,7 @@ async function showCloudSyncMenu() {
3158
3197
  } catch (error) {
3159
3198
  console.log(chalk.red('\nāœ— Error: ') + error.message);
3160
3199
  }
3161
- console.log(chalk.gray('\nPress Enter to continue...'));
3200
+ console.log(chalk.gray(`\n${t('interactive.press.enter.continue')}`));
3162
3201
  await new Promise(resolve => {
3163
3202
  const rl = readline.createInterface({
3164
3203
  input: process.stdin,
@@ -3178,7 +3217,7 @@ async function showCloudSyncMenu() {
3178
3217
  } catch (error) {
3179
3218
  console.log(chalk.red('\nāœ— Error: ') + error.message);
3180
3219
  }
3181
- console.log(chalk.gray('\nPress Enter to continue...'));
3220
+ console.log(chalk.gray(`\n${t('interactive.press.enter.continue')}`));
3182
3221
  await new Promise(resolve => {
3183
3222
  const rl = readline.createInterface({
3184
3223
  input: process.stdin,
@@ -3198,7 +3237,7 @@ async function showCloudSyncMenu() {
3198
3237
  } catch (error) {
3199
3238
  console.log(chalk.red('\nāœ— Error: ') + error.message);
3200
3239
  }
3201
- console.log(chalk.gray('\nPress Enter to continue...'));
3240
+ console.log(chalk.gray(`\n${t('interactive.press.enter.continue')}`));
3202
3241
  await new Promise(resolve => {
3203
3242
  const rl = readline.createInterface({
3204
3243
  input: process.stdin,
@@ -3218,7 +3257,7 @@ async function showCloudSyncMenu() {
3218
3257
  } catch (error) {
3219
3258
  console.log(chalk.red('\nāœ— Error: ') + error.message);
3220
3259
  }
3221
- console.log(chalk.gray('\nPress Enter to continue...'));
3260
+ console.log(chalk.gray(`\n${t('interactive.press.enter.continue')}`));
3222
3261
  await new Promise(resolve => {
3223
3262
  const rl = readline.createInterface({
3224
3263
  input: process.stdin,
@@ -3238,15 +3277,15 @@ async function showCloudSyncMenu() {
3238
3277
  {
3239
3278
  type: 'input',
3240
3279
  name: 'focusArea',
3241
- message: 'Enter focus area for this computer:',
3242
- default: 'General Development'
3280
+ message: t('computers.register.focus.prompt'),
3281
+ default: t('computers.register.focus.default')
3243
3282
  }
3244
3283
  ]);
3245
3284
  await computerCommands.registerComputer(focusArea);
3246
3285
  } catch (error) {
3247
3286
  console.log(chalk.red('\nāœ— Error: ') + error.message);
3248
3287
  }
3249
- console.log(chalk.gray('\nPress Enter to continue...'));
3288
+ console.log(chalk.gray(`\n${t('interactive.press.enter.continue')}`));
3250
3289
  await new Promise(resolve => {
3251
3290
  const rl = readline.createInterface({
3252
3291
  input: process.stdin,
@@ -3275,7 +3314,7 @@ async function showCloudSyncMenu() {
3275
3314
  } catch (error) {
3276
3315
  console.log(chalk.red('\nāœ— Error: ') + error.message);
3277
3316
  }
3278
- console.log(chalk.gray('\nPress Enter to continue...'));
3317
+ console.log(chalk.gray(`\n${t('interactive.press.enter.continue')}`));
3279
3318
  await new Promise(resolve => {
3280
3319
  const rl = readline.createInterface({
3281
3320
  input: process.stdin,
@@ -3371,7 +3410,7 @@ async function startInteractive() {
3371
3410
  }
3372
3411
  // Fallback to current agent if no enabled agents found
3373
3412
  const displayAgent = firstEnabledAgent || autoConfig.agent || autoConfig.ide || 'ollama';
3374
- let agentDisplay = `First Agent: ${chalk.cyan(getAgentDisplayName(displayAgent))}`;
3413
+ let agentDisplay = `${t('interactive.first.agent')}: ${chalk.cyan(getAgentDisplayName(displayAgent))}`;
3375
3414
 
3376
3415
  // Check for rate limits (for LLM-based agents and Claude Code)
3377
3416
  if (displayAgent === 'ollama' || displayAgent === 'groq' || displayAgent === 'anthropic' || displayAgent === 'bedrock' || displayAgent === 'claude-code') {
@@ -3443,9 +3482,9 @@ async function startInteractive() {
3443
3482
 
3444
3483
 
3445
3484
  // Get stop condition from already loaded autoConfig (line 1704)
3446
- const stopCondition = autoConfig.neverStop ? 'Never Stop' :
3447
- autoConfig.maxChats ? `Stop after ${autoConfig.maxChats}` :
3448
- 'Never Stop';
3485
+ const stopCondition = autoConfig.neverStop ? t('interactive.never.stop') :
3486
+ autoConfig.maxChats ? t('interactive.stop.after', { count: autoConfig.maxChats }) :
3487
+ t('interactive.never.stop');
3449
3488
 
3450
3489
  if (autoStatus.running) {
3451
3490
  items.push({
@@ -3456,7 +3495,7 @@ async function startInteractive() {
3456
3495
  } else {
3457
3496
  items.push({
3458
3497
  type: 'setting',
3459
- name: `Auto Mode: ${chalk.yellow('Stopped ā—‹')}`,
3498
+ name: `${t('interactive.auto.mode')}: ${chalk.yellow(t('interactive.auto.stopped') + ' ā—‹')}`,
3460
3499
  value: 'setting:auto-start'
3461
3500
  });
3462
3501
  }
@@ -3464,7 +3503,7 @@ async function startInteractive() {
3464
3503
  // Add separate stop condition setting
3465
3504
  items.push({
3466
3505
  type: 'setting',
3467
- name: ` └─ Stop Condition: ${chalk.cyan(stopCondition)}`,
3506
+ name: ` └─ ${t('interactive.stop.condition')}: ${chalk.cyan(stopCondition)}`,
3468
3507
  value: 'setting:auto-stop-condition'
3469
3508
  });
3470
3509
 
@@ -3478,17 +3517,15 @@ async function startInteractive() {
3478
3517
  // Add Requirements as a selectable setting with counts
3479
3518
  const hasRequirements = await requirementsExists();
3480
3519
  const counts = hasRequirements ? await countRequirements() : null;
3481
- let requirementsText = 'Requirements: ';
3520
+ let requirementsText = t('interactive.requirements') + ': ';
3482
3521
  if (counts) {
3483
- // Calculate actual iterations: lesser of stop after number and TODO requirements
3484
- const actualIterations = autoConfig.neverStop ? counts.todoCount :
3485
- Math.min(autoConfig.maxChats || counts.todoCount, counts.todoCount);
3522
+ // Use actual counts for display (not capped by maxChats)
3486
3523
  const total = counts.todoCount + counts.toVerifyCount + counts.verifiedCount;
3487
3524
  if (total > 0) {
3488
- const todoPercent = Math.round((actualIterations / total) * 100);
3525
+ const todoPercent = Math.round((counts.todoCount / total) * 100);
3489
3526
  const toVerifyPercent = Math.round((counts.toVerifyCount / total) * 100);
3490
3527
  const verifiedPercent = Math.round((counts.verifiedCount / total) * 100);
3491
- requirementsText += `${chalk.yellow(actualIterations + ' (' + todoPercent + '%) TODO')}, ${chalk.cyan(counts.toVerifyCount + ' (' + toVerifyPercent + '%) TO VERIFY')}, ${chalk.green(counts.verifiedCount + ' (' + verifiedPercent + '%) VERIFIED')}`;
3528
+ requirementsText += `${chalk.yellow(counts.todoCount + ' (' + todoPercent + '%) ' + t('interactive.todo'))}, ${chalk.cyan(counts.toVerifyCount + ' (' + toVerifyPercent + '%) ' + t('interactive.to.verify'))}, ${chalk.green(counts.verifiedCount + ' (' + verifiedPercent + '%) ' + t('interactive.verified'))}`;
3492
3529
  } else {
3493
3530
  requirementsText = '';
3494
3531
  }
@@ -3508,7 +3545,7 @@ async function startInteractive() {
3508
3545
 
3509
3546
  items.push({
3510
3547
  type: 'setting',
3511
- name: ` └─ Use Hostname in Req File: ${useHostname ? chalk.green('āœ“') : chalk.red('šŸ›‘')} ${useHostname ? 'āœ“ ENABLED' : 'šŸ›‘ DISABLED'}`,
3548
+ name: ` └─ ${t('interactive.hostname.enabled')}: ${useHostname ? chalk.green('āœ“') : chalk.red('šŸ›‘')} ${useHostname ? 'āœ“ ENABLED' : 'šŸ›‘ ' + t('interactive.hostname.disabled')}`,
3512
3549
  value: 'setting:hostname'
3513
3550
  });
3514
3551
 
@@ -3518,7 +3555,7 @@ async function startInteractive() {
3518
3555
  const stagesCount = configuredStages.length;
3519
3556
  items.push({
3520
3557
  type: 'setting',
3521
- name: ` └─ Configure Stages: ${chalk.cyan(stagesCount + ' stages')}`,
3558
+ name: ` └─ ${t('interactive.configure.stages')}: ${chalk.cyan(stagesCount + ' ' + t('interactive.stages'))}`,
3522
3559
  value: 'setting:stages'
3523
3560
  });
3524
3561
 
@@ -3534,12 +3571,12 @@ async function startInteractive() {
3534
3571
  syncEngine.stop();
3535
3572
 
3536
3573
  const onlineIcon = syncStatus.isOnline ? chalk.green('ā—') : chalk.red('ā—');
3537
- const onlineText = syncStatus.isOnline ? 'Online' : 'Offline';
3574
+ const onlineText = syncStatus.isOnline ? t('interactive.online') : t('interactive.offline');
3538
3575
  const queueText = syncStatus.queuedChanges > 0 ? chalk.yellow(` (${syncStatus.queuedChanges} queued)`) : '';
3539
3576
 
3540
3577
  items.push({
3541
3578
  type: 'setting',
3542
- name: `Cloud Sync: ${onlineIcon} ${onlineText}${queueText}`,
3579
+ name: `${t('interactive.cloud.sync')}: ${onlineIcon} ${onlineText}${queueText}`,
3543
3580
  value: 'setting:cloud-sync'
3544
3581
  });
3545
3582
  } catch (initError) {
@@ -3608,14 +3645,18 @@ async function startInteractive() {
3608
3645
 
3609
3646
  description += nextLine + '\n';
3610
3647
  }
3611
- nextReqText = title + '\n' + description;
3648
+ // Translate requirement labels
3649
+ let displayText = title + '\n' + description;
3650
+ displayText = displayText.replace(/PACKAGE:/g, t('requirement.label.package'));
3651
+ displayText = displayText.replace(/STATUS:/g, t('requirement.label.status'));
3652
+ nextReqText = displayText;
3612
3653
  break;
3613
3654
  }
3614
3655
  }
3615
3656
  }
3616
3657
  items.push({
3617
3658
  type: 'info',
3618
- name: ` └─ Next TODO Requirement: ${nextReqText}`,
3659
+ name: ` └─ ${t('interactive.next.todo')}: ${nextReqText}`,
3619
3660
  value: 'info:next-requirement'
3620
3661
  });
3621
3662
  }
@@ -3640,13 +3681,13 @@ async function startInteractive() {
3640
3681
  // Action items (with letters)
3641
3682
  // Only show Initialize option if neither directory exists
3642
3683
  if (!allnightStatus.exists) {
3643
- items.push({ type: 'action', name: 'Initialize repository (.vibecodingmachine)', value: 'repo:init' });
3684
+ items.push({ type: 'action', name: t('interactive.initialize'), value: 'repo:init' });
3644
3685
  }
3645
3686
 
3646
- items.push({ type: 'action', name: 'View All Computers', value: 'computers:list' });
3647
- items.push({ type: 'action', name: 'Sync Now', value: 'sync:now' });
3648
- items.push({ type: 'action', name: 'Logout', value: 'logout' });
3649
- items.push({ type: 'action', name: 'Exit', value: 'exit' });
3687
+ items.push({ type: 'action', name: t('interactive.view.computers'), value: 'computers:list' });
3688
+ items.push({ type: 'action', name: t('interactive.sync.now'), value: 'sync:now' });
3689
+ items.push({ type: 'action', name: t('interactive.logout'), value: 'logout' });
3690
+ items.push({ type: 'action', name: t('interactive.exit'), value: 'exit' });
3650
3691
 
3651
3692
 
3652
3693
  // Use custom quick menu with last selected index
@@ -3813,7 +3854,7 @@ async function startInteractive() {
3813
3854
  fs.writeFileSync(configPath, yaml.dump(config), 'utf8');
3814
3855
 
3815
3856
  console.log(chalk.green(`āœ“ Set ${model.name || modelName} as default model\n`));
3816
- console.log(chalk.gray('Press Enter to continue...'));
3857
+ console.log(chalk.gray(t('interactive.press.enter.continue')));
3817
3858
  await inquirer.prompt([
3818
3859
  {
3819
3860
  type: 'input',
@@ -3831,7 +3872,7 @@ async function startInteractive() {
3831
3872
  {
3832
3873
  type: 'input',
3833
3874
  name: 'continue',
3834
- message: 'Press Enter to return to menu...',
3875
+ message: t('interactive.press.enter.return'),
3835
3876
  }
3836
3877
  ]);
3837
3878
  }
@@ -3844,7 +3885,7 @@ async function startInteractive() {
3844
3885
  {
3845
3886
  type: 'input',
3846
3887
  name: 'continue',
3847
- message: 'Press Enter to return to menu...',
3888
+ message: t('interactive.press.enter.return'),
3848
3889
  }
3849
3890
  ]);
3850
3891
  }
@@ -3856,7 +3897,7 @@ async function startInteractive() {
3856
3897
  {
3857
3898
  type: 'input',
3858
3899
  name: 'continue',
3859
- message: 'Press Enter to return to menu...',
3900
+ message: t('interactive.press.enter.return'),
3860
3901
  }
3861
3902
  ]);
3862
3903
  }
@@ -3884,24 +3925,40 @@ async function startInteractive() {
3884
3925
  const { getStages, setStages, DEFAULT_STAGES } = require('./config');
3885
3926
  const inquirer = require('inquirer');
3886
3927
 
3928
+ // Override inquirer's checkbox help text for current locale
3929
+ const CheckboxPrompt = require('inquirer/lib/prompts/checkbox');
3930
+ const originalGetHelpText = CheckboxPrompt.prototype.getHelp || function() {
3931
+ return '(Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to proceed)';
3932
+ };
3933
+
3934
+ CheckboxPrompt.prototype.getHelp = function() {
3935
+ const locale = detectLocale();
3936
+ if (locale === 'es') {
3937
+ return '(Presiona <espacio> para seleccionar, <a> para alternar todo, <i> para invertir selección, y <enter> para proceder)';
3938
+ }
3939
+ return originalGetHelpText.call(this);
3940
+ };
3941
+
3887
3942
  const currentStages = await getStages();
3888
3943
 
3889
- console.log(chalk.cyan('\nšŸ”Ø Configure Workflow Stages\n'));
3890
- console.log(chalk.gray('Select the stages you want to include in the auto-mode workflow.'));
3891
- console.log(chalk.gray('Stages will be executed in the order shown.\n'));
3944
+ console.log(chalk.cyan(`\nšŸ”Ø ${t('workflow.config.title')}\n`));
3945
+ console.log(chalk.gray(t('workflow.config.description')));
3946
+ console.log(chalk.gray(t('workflow.config.order.note')));
3947
+ console.log(chalk.gray(`${t('workflow.config.instructions')}\n`));
3892
3948
 
3893
3949
  const { selectedStages } = await inquirer.prompt([
3894
3950
  {
3895
3951
  type: 'checkbox',
3896
3952
  name: 'selectedStages',
3897
- message: 'Select stages:',
3953
+ message: t('workflow.config.select.prompt'),
3898
3954
  choices: DEFAULT_STAGES.map(stage => ({
3899
- name: stage,
3955
+ name: translateStage(stage),
3956
+ value: stage, // Keep original English value for internal use
3900
3957
  checked: currentStages.includes(stage)
3901
3958
  })),
3902
3959
  validate: (answer) => {
3903
3960
  if (answer.length < 1) {
3904
- return 'You must select at least one stage.';
3961
+ return t('workflow.config.validation.error');
3905
3962
  }
3906
3963
  return true;
3907
3964
  },
@@ -3910,17 +3967,21 @@ async function startInteractive() {
3910
3967
  }
3911
3968
  ]);
3912
3969
 
3970
+ // Restore original getHelp method
3971
+ CheckboxPrompt.prototype.getHelp = originalGetHelpText;
3972
+
3913
3973
  // Preserve order from DEFAULT_STAGES for selected items
3914
3974
  // This ensures stages always run in the correct logical order
3915
3975
  const newStages = DEFAULT_STAGES.filter(stage => selectedStages.includes(stage));
3916
3976
 
3917
3977
  await setStages(newStages);
3918
- console.log(chalk.green('\nāœ“'), `Stages configuration updated: ${newStages.join(' → ')}\n`);
3978
+ const translatedStages = newStages.map(stage => translateStage(stage));
3979
+ console.log(chalk.green('\nāœ“'), `${t('workflow.config.updated')} ${translatedStages.join(' → ')}\n`);
3919
3980
 
3920
3981
  const { continue: _ } = await inquirer.prompt([{
3921
3982
  type: 'input',
3922
3983
  name: 'continue',
3923
- message: 'Press Enter to return to menu...'
3984
+ message: t('interactive.press.enter.return')
3924
3985
  }]);
3925
3986
 
3926
3987
  await showWelcomeScreen();
@@ -3928,7 +3989,7 @@ async function startInteractive() {
3928
3989
  }
3929
3990
  case 'setting:auto-start': {
3930
3991
  try {
3931
- console.log(chalk.bold.cyan('\nšŸš€ Starting Auto Mode...\n'));
3992
+ console.log(chalk.bold.cyan('\n' + t('auto.starting') + '\n'));
3932
3993
  // Check if there are requirements to work on
3933
3994
  const hasRequirements = await requirementsExists();
3934
3995
  const counts = hasRequirements ? await countRequirements() : null;
@@ -3940,7 +4001,7 @@ async function startInteractive() {
3940
4001
  await inquirer.prompt([{
3941
4002
  type: 'input',
3942
4003
  name: 'continue',
3943
- message: 'Press Enter to return to menu...',
4004
+ message: t('interactive.press.enter.return'),
3944
4005
  }]);
3945
4006
  await showWelcomeScreen();
3946
4007
  break;
@@ -3984,7 +4045,7 @@ async function startInteractive() {
3984
4045
  await inquirer.prompt([{
3985
4046
  type: 'input',
3986
4047
  name: 'continue',
3987
- message: 'Press Enter to return to menu...',
4048
+ message: t('interactive.press.enter.return'),
3988
4049
  }]);
3989
4050
 
3990
4051
  await showWelcomeScreen();
@@ -4017,7 +4078,7 @@ async function startInteractive() {
4017
4078
  await inquirer.prompt([{
4018
4079
  type: 'input',
4019
4080
  name: 'continue',
4020
- message: 'Press Enter to return to menu...',
4081
+ message: t('interactive.press.enter.return'),
4021
4082
  }]);
4022
4083
  await showWelcomeScreen();
4023
4084
  }
@@ -4031,7 +4092,7 @@ async function startInteractive() {
4031
4092
  await inquirer.prompt([{
4032
4093
  type: 'input',
4033
4094
  name: 'continue',
4034
- message: 'Press Enter to return to menu...',
4095
+ message: t('interactive.press.enter.return'),
4035
4096
  }]);
4036
4097
  await showWelcomeScreen();
4037
4098
  }
@@ -4048,7 +4109,7 @@ async function startInteractive() {
4048
4109
  await inquirer.prompt([{
4049
4110
  type: 'input',
4050
4111
  name: 'continue',
4051
- message: 'Press Enter to return to menu...',
4112
+ message: t('interactive.press.enter.return'),
4052
4113
  }]);
4053
4114
  await showWelcomeScreen();
4054
4115
  break;
@@ -4075,12 +4136,12 @@ async function startInteractive() {
4075
4136
  defaultMaxChats = String(currentConfig.maxChats);
4076
4137
  }
4077
4138
 
4078
- console.log(chalk.bold.cyan('\nāš™ļø Configure Stop Condition\n'));
4139
+ console.log(chalk.bold.cyan('\n' + t('config.stop.condition.title') + '\n'));
4079
4140
 
4080
4141
  const { maxChats } = await inquirer.prompt([{
4081
4142
  type: 'input',
4082
4143
  name: 'maxChats',
4083
- message: 'Max chats (0 for never stop):',
4144
+ message: t('config.max.chats.prompt'),
4084
4145
  default: defaultMaxChats
4085
4146
  }]);
4086
4147
 
@@ -4089,11 +4150,11 @@ async function startInteractive() {
4089
4150
  if (maxChats && maxChats.trim() !== '' && maxChats.trim() !== '0') {
4090
4151
  newConfig.maxChats = parseInt(maxChats);
4091
4152
  newConfig.neverStop = false;
4092
- console.log(chalk.green('\nāœ“'), `Stop condition updated: ${chalk.cyan(`Stop after ${newConfig.maxChats}`)}\n`);
4153
+ console.log(chalk.green('\nāœ“'), `${t('config.stop.condition.updated')} ${chalk.cyan(t('config.stop.after', { count: newConfig.maxChats }))}\n`);
4093
4154
  } else {
4094
4155
  delete newConfig.maxChats;
4095
4156
  newConfig.neverStop = true;
4096
- console.log(chalk.green('\nāœ“'), `Stop condition updated: ${chalk.cyan('Never Stop')}\n`);
4157
+ console.log(chalk.green('\nāœ“'), `${t('config.stop.condition.updated')} ${chalk.cyan(t('config.never.stop'))}\n`);
4097
4158
  }
4098
4159
 
4099
4160
  await setAutoConfig(newConfig);
@@ -4116,7 +4177,7 @@ async function startInteractive() {
4116
4177
  case 'computers:list': {
4117
4178
  const computerCommands = require('../commands/computers');
4118
4179
  await computerCommands.listComputers();
4119
- console.log(chalk.gray('\nPress Enter to continue...'));
4180
+ console.log(chalk.gray(`\n${t('interactive.press.enter.continue')}`));
4120
4181
  await new Promise(resolve => {
4121
4182
  const rl = readline.createInterface({
4122
4183
  input: process.stdin,
@@ -4134,7 +4195,7 @@ async function startInteractive() {
4134
4195
  case 'sync:now': {
4135
4196
  const syncCommands = require('../commands/sync');
4136
4197
  await syncCommands.syncNow();
4137
- console.log(chalk.gray('\nPress Enter to continue...'));
4198
+ console.log(chalk.gray(`\n${t('interactive.press.enter.continue')}`));
4138
4199
  await new Promise(resolve => {
4139
4200
  const rl = readline.createInterface({
4140
4201
  input: process.stdin,
@@ -4165,7 +4226,7 @@ async function startInteractive() {
4165
4226
  console.log(chalk.gray('3. Register this computer with: ') + chalk.cyan('vcm computer:register "<focus>"'));
4166
4227
  console.log(chalk.gray('\nFor more info, see: ') + chalk.cyan('docs/CLOUD_SYNC.md\n'));
4167
4228
 
4168
- console.log(chalk.gray('Press Enter to continue...'));
4229
+ console.log(chalk.gray(t('interactive.press.enter.continue')));
4169
4230
  await new Promise(resolve => {
4170
4231
  const rl = readline.createInterface({
4171
4232
  input: process.stdin,
@@ -4199,7 +4260,7 @@ async function startInteractive() {
4199
4260
  {
4200
4261
  type: 'input',
4201
4262
  name: 'maxChats',
4202
- message: 'Max chats (0 for never stop):',
4263
+ message: t('config.max.chats.prompt'),
4203
4264
  default: ''
4204
4265
  }
4205
4266
  ]);
@@ -4233,8 +4294,8 @@ async function startInteractive() {
4233
4294
  │ │
4234
4295
  ╰───────────────────────────────────────────────────────╯
4235
4296
 
4236
- Repo: ${repoPath || 'Not set'}
4237
- Computer Name: ${hostname}
4297
+ ${t('system.repo').padEnd(25)} ${repoPath || 'Not set'}
4298
+ ${t('system.computer.name').padEnd(25)} ${hostname}
4238
4299
  Current IDE: ${formatIDEName(ide)}
4239
4300
  AI Provider: ${getCurrentAIProvider(ide) || 'N/A'}
4240
4301
  Max Chats: ${maxChats || 'Never stop'}`;
@@ -4354,12 +4415,12 @@ Max Chats: ${maxChats || 'Never stop'}`;
4354
4415
  const auth = require('./auth');
4355
4416
  try {
4356
4417
  await auth.logout();
4357
- console.log(chalk.green('\nāœ“ Logged out successfully!\n'));
4358
- console.log(chalk.gray('Run "vcm auth:login" or "vcm" to login again.\n'));
4418
+ console.log(chalk.green(`\nāœ“ ${t('interactive.logout.success')}\n`));
4419
+ console.log(chalk.gray(`${t('interactive.logout.login.again')}\n`));
4359
4420
  process.exit(0);
4360
4421
  } catch (error) {
4361
- console.error(chalk.red('\nāœ— Logout failed:'), error.message);
4362
- console.log(chalk.yellow('\nPress any key to continue...'));
4422
+ console.error(chalk.red(`\nāœ— ${t('interactive.logout.failed')}`), error.message);
4423
+ console.log(chalk.yellow(`\n${t('interactive.press.any.key')}...`));
4363
4424
  await new Promise((resolve) => {
4364
4425
  process.stdin.once('keypress', () => resolve());
4365
4426
  });
@@ -4383,7 +4444,7 @@ Max Chats: ${maxChats || 'Never stop'}`;
4383
4444
  await inquirer.prompt([{
4384
4445
  type: 'input',
4385
4446
  name: 'continue',
4386
- message: 'Press Enter to return to menu...',
4447
+ message: t('interactive.press.enter.return'),
4387
4448
  }]);
4388
4449
  await showWelcomeScreen();
4389
4450
  break;
@@ -4398,7 +4459,7 @@ Max Chats: ${maxChats || 'Never stop'}`;
4398
4459
  await inquirer.prompt([{
4399
4460
  type: 'input',
4400
4461
  name: 'continue',
4401
- message: 'Press Enter to return to menu...',
4462
+ message: t('interactive.press.enter.return'),
4402
4463
  }]);
4403
4464
  await showWelcomeScreen();
4404
4465
  }