vibecodingmachine-cli 2025.12.25-25 → 2026.1.22-1441

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/__tests__/antigravity-js-handler.test.js +23 -0
  2. package/__tests__/provider-manager.test.js +84 -0
  3. package/__tests__/provider-rate-cache.test.js +27 -0
  4. package/bin/vibecodingmachine.js +92 -118
  5. package/logs/audit/2025-12-27.jsonl +1 -0
  6. package/logs/audit/2026-01-03.jsonl +2 -0
  7. package/package.json +2 -2
  8. package/reset_provider_order.js +21 -0
  9. package/scripts/convert-requirements.js +35 -0
  10. package/scripts/debug-parse.js +24 -0
  11. package/src/commands/auth.js +5 -1
  12. package/src/commands/auto-direct.js +747 -182
  13. package/src/commands/auto.js +206 -48
  14. package/src/commands/computers.js +9 -0
  15. package/src/commands/feature.js +123 -0
  16. package/src/commands/ide.js +108 -3
  17. package/src/commands/repo.js +27 -22
  18. package/src/commands/requirements-remote.js +34 -2
  19. package/src/commands/requirements.js +129 -9
  20. package/src/commands/setup.js +2 -1
  21. package/src/commands/status.js +39 -1
  22. package/src/commands/sync.js +7 -1
  23. package/src/utils/antigravity-js-handler.js +13 -4
  24. package/src/utils/auth.js +56 -25
  25. package/src/utils/compliance-check.js +10 -0
  26. package/src/utils/config.js +42 -1
  27. package/src/utils/date-formatter.js +44 -0
  28. package/src/utils/first-run.js +8 -6
  29. package/src/utils/interactive.js +1363 -334
  30. package/src/utils/kiro-js-handler.js +188 -0
  31. package/src/utils/prompt-helper.js +64 -0
  32. package/src/utils/provider-rate-cache.js +31 -0
  33. package/src/utils/provider-registry.js +42 -1
  34. package/src/utils/requirements-converter.js +107 -0
  35. package/src/utils/requirements-parser.js +144 -0
  36. package/tests/antigravity-js-handler.test.js +23 -0
  37. package/tests/home-bootstrap.test.js +76 -0
  38. package/tests/integration/health-tracking.integration.test.js +284 -0
  39. package/tests/provider-manager.test.js +92 -0
  40. package/tests/rate-limit-display.test.js +44 -0
  41. package/tests/requirements-bullet-parsing.test.js +15 -0
  42. package/tests/requirements-converter.test.js +42 -0
  43. package/tests/requirements-heading-count.test.js +27 -0
  44. package/tests/requirements-legacy-parsing.test.js +15 -0
  45. package/tests/requirements-parse-integration.test.js +44 -0
  46. package/tests/wait-for-ide-completion.test.js +56 -0
  47. package/tests/wait-for-ide-quota-detection-cursor-screenshot.test.js +61 -0
  48. package/tests/wait-for-ide-quota-detection-cursor.test.js +60 -0
  49. package/tests/wait-for-ide-quota-detection-negative.test.js +45 -0
  50. package/tests/wait-for-ide-quota-detection.test.js +59 -0
  51. package/verify_fix.js +36 -0
  52. package/verify_ui.js +38 -0
@@ -0,0 +1,23 @@
1
+ const { handleAntigravityRateLimit } = require('../src/utils/antigravity-js-handler');
2
+ const providerRegistry = require('../src/utils/provider-registry');
3
+
4
+ jest.mock('../src/utils/provider-registry');
5
+
6
+ describe('handleAntigravityRateLimit', () => {
7
+ beforeEach(() => {
8
+ jest.resetAllMocks();
9
+ });
10
+
11
+ test('suggests next provider and does not persistently disable antigravity', async () => {
12
+ providerRegistry.getProviderPreferences.mockResolvedValue({
13
+ order: ['antigravity', 'vscode'],
14
+ enabled: { antigravity: true, vscode: true }
15
+ });
16
+
17
+ const result = await handleAntigravityRateLimit();
18
+
19
+ expect(result.success).toBe(true);
20
+ expect(result.nextProvider).toBe('vscode');
21
+ expect(providerRegistry.saveProviderPreferences).not.toHaveBeenCalled();
22
+ });
23
+ });
@@ -0,0 +1,84 @@
1
+ const providerRegistry = require('../src/utils/provider-registry');
2
+ const interactive = require('../src/utils/interactive');
3
+
4
+ jest.mock('../src/utils/provider-registry');
5
+
6
+ describe('showProviderManagerMenu', () => {
7
+ const origIsTTY = process.stdin.isTTY;
8
+ const origSetRawMode = process.stdin.setRawMode;
9
+
10
+ beforeAll(() => {
11
+ // Ensure stdin behaves like a TTY for the menu
12
+ process.stdin.isTTY = true;
13
+ process.stdin.setRawMode = () => {};
14
+ });
15
+
16
+ afterAll(() => {
17
+ process.stdin.isTTY = origIsTTY;
18
+ process.stdin.setRawMode = origSetRawMode;
19
+ });
20
+
21
+ beforeEach(() => {
22
+ jest.resetAllMocks();
23
+ });
24
+
25
+ test('pressing left after reordering calls saveProviderPreferences', async () => {
26
+ providerRegistry.getProviderDefinitions.mockReturnValue([
27
+ { id: 'groq', name: 'Groq' },
28
+ { id: 'antigravity', name: 'Antigravity' }
29
+ ]);
30
+
31
+ providerRegistry.getProviderPreferences.mockResolvedValue({
32
+ order: ['groq', 'antigravity'],
33
+ enabled: { groq: true, antigravity: true }
34
+ });
35
+
36
+ providerRegistry.saveProviderPreferences.mockResolvedValue();
37
+
38
+ // Start the menu
39
+ const menuPromise = interactive.showProviderManagerMenu();
40
+
41
+ // Allow the menu to initialize
42
+ await new Promise(resolve => setImmediate(resolve));
43
+
44
+ // Simulate 'j' (reorder downward)
45
+ process.stdin.emit('keypress', 'j', { name: 'j' });
46
+ await new Promise(resolve => setImmediate(resolve));
47
+
48
+ // Simulate left arrow to save and exit
49
+ process.stdin.emit('keypress', undefined, { name: 'left' });
50
+
51
+ await menuPromise; // wait for menu to finish
52
+
53
+ expect(providerRegistry.saveProviderPreferences).toHaveBeenCalledTimes(1);
54
+ expect(providerRegistry.saveProviderPreferences).toHaveBeenCalledWith(['antigravity', 'groq'], { groq: true, antigravity: true });
55
+ });
56
+
57
+ test('pressing escape after reordering does NOT call saveProviderPreferences', async () => {
58
+ providerRegistry.getProviderDefinitions.mockReturnValue([
59
+ { id: 'groq', name: 'Groq' },
60
+ { id: 'antigravity', name: 'Antigravity' }
61
+ ]);
62
+
63
+ providerRegistry.getProviderPreferences.mockResolvedValue({
64
+ order: ['groq', 'antigravity'],
65
+ enabled: { groq: true, antigravity: true }
66
+ });
67
+
68
+ providerRegistry.saveProviderPreferences.mockResolvedValue();
69
+
70
+ const menuPromise = interactive.showProviderManagerMenu();
71
+ await new Promise(resolve => setImmediate(resolve));
72
+
73
+ // Make a change
74
+ process.stdin.emit('keypress', 'j', { name: 'j' });
75
+ await new Promise(resolve => setImmediate(resolve));
76
+
77
+ // Press escape to cancel (should not persist)
78
+ process.stdin.emit('keypress', undefined, { name: 'escape' });
79
+
80
+ await menuPromise;
81
+
82
+ expect(providerRegistry.saveProviderPreferences).not.toHaveBeenCalled();
83
+ });
84
+ });
@@ -0,0 +1,27 @@
1
+ const { getProviderRateLimitedQuotas } = require('../src/utils/provider-rate-cache');
2
+ const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
3
+
4
+ describe('getProviderRateLimitedQuotas', () => {
5
+ let pm;
6
+
7
+ beforeEach(() => {
8
+ pm = new ProviderManager();
9
+ pm.clearAllRateLimits();
10
+ });
11
+
12
+ afterEach(() => {
13
+ pm.clearAllRateLimits();
14
+ });
15
+
16
+ test('returns rate-limited entry when ProviderManager has a limit', () => {
17
+ pm.markRateLimited('antigravity', undefined, 'Quota limit reached');
18
+
19
+ const defs = [{ id: 'antigravity' }, { id: 'vscode' }];
20
+ const map = getProviderRateLimitedQuotas(defs);
21
+
22
+ expect(map.has('antigravity')).toBe(true);
23
+ const q = map.get('antigravity');
24
+ expect(q).toHaveProperty('type', 'rate-limit');
25
+ expect(q).toHaveProperty('resetsAt');
26
+ });
27
+ });
@@ -46,7 +46,10 @@ const streamPipeline = promisify(pipeline);
46
46
  const packageJson = require('../package.json');
47
47
 
48
48
  // Import localization
49
- const { t, detectLocale, setLocale } = require('vibecodingmachine-core');
49
+ const { t, detectLocale, setLocale, errorReporter } = require('vibecodingmachine-core');
50
+
51
+ // Import prompt helper
52
+ const { promptWithDefaultsOnce } = require('../src/utils/prompt-helper');
50
53
 
51
54
  // Initialize locale detection
52
55
  const detectedLocale = detectLocale();
@@ -56,6 +59,7 @@ setLocale(detectedLocale);
56
59
  const repoCommands = require('../src/commands/repo');
57
60
  const autoCommands = require('../src/commands/auto');
58
61
  const reqCommands = require('../src/commands/requirements');
62
+ const featureCommands = require('../src/commands/feature');
59
63
  const ideCommands = require('../src/commands/ide');
60
64
  const statusCommands = require('../src/commands/status');
61
65
 
@@ -99,6 +103,8 @@ program
99
103
  .command('auto:start')
100
104
  .description(t('cli.auto.start'))
101
105
  .option('-i, --ide <ide>', 'IDE to use (claude-code, aider, cursor, vscode, windsurf, cline)')
106
+ .option('--ide-model <model>', 'IDE agent/model to use (for IDE sub-agents like Windsurf/Antigravity)')
107
+ .option('--extension <extension>', 'VS Code extension to use (amazon-q, github-copilot, windsurf)')
102
108
  .option('-m, --max-chats <number>', 'Maximum number of chat iterations', parseInt)
103
109
  .option('-n, --never-stop', 'Run indefinitely without stopping')
104
110
  .option('-f, --force-provider-setup', 'Force provider selection even if already configured')
@@ -140,6 +146,9 @@ program
140
146
  .command('req:list')
141
147
  .description(t('cli.req.list'))
142
148
  .option('-s, --status <status>', 'Filter by status (pending, in-progress, completed)')
149
+ .option('-c, --computer <hostname>', 'Filter by computer hostname')
150
+ .option('-f, --focus <area>', 'Filter by focus area')
151
+ .option('-a, --all-computers', 'Show requirements from all computers with computer tags')
143
152
  .action(reqCommands.list);
144
153
 
145
154
  program
@@ -172,6 +181,33 @@ program
172
181
  .description(t('cli.req.rename'))
173
182
  .action((oldTitle, newTitle, description) => reqCommands.rename(oldTitle, newTitle, description));
174
183
 
184
+ program
185
+ .command('req:number-all')
186
+ .description('Number all existing requirements with R1, R2, R3, etc.')
187
+ .action(reqCommands.numberAll);
188
+
189
+ // Feature branch management commands
190
+ program
191
+ .command('feature:start <requirement-title>')
192
+ .description('Create and checkout feature branch for requirement (e.g., "R1: Email System")')
193
+ .action(featureCommands.start);
194
+
195
+ program
196
+ .command('feature:finish <requirement-title>')
197
+ .description('Merge feature branch back to parent and delete branch')
198
+ .option('-p, --parent <branch>', 'Parent branch to merge into', 'main')
199
+ .action(featureCommands.finish);
200
+
201
+ program
202
+ .command('feature:remove <requirement-title>')
203
+ .description('Remove a feature by reverting its merge commit')
204
+ .action(featureCommands.remove);
205
+
206
+ program
207
+ .command('feature:list')
208
+ .description('List all requirement feature branches')
209
+ .action(featureCommands.list);
210
+
175
211
  // IDE integration commands
176
212
  program
177
213
  .command('ide:list')
@@ -189,6 +225,12 @@ program
189
225
  .option('-i, --ide <ide>', 'IDE to use (cursor, vscode, windsurf)', 'cursor')
190
226
  .action(ideCommands.send);
191
227
 
228
+ program
229
+ .command('ide:health')
230
+ .description('Test health and connectivity of all configured IDEs')
231
+ .option('-v, --verbose', 'Show detailed health metrics', false)
232
+ .action(ideCommands.health);
233
+
192
234
  // Status and monitoring commands
193
235
  program
194
236
  .command('status')
@@ -314,19 +356,21 @@ program
314
356
  });
315
357
 
316
358
  // Error handling
317
- process.on('uncaughtException', (error) => {
359
+ process.on('uncaughtException', async (error) => {
318
360
  console.error(chalk.red(`${t('cli.error')}:`), error.message);
319
361
  if (process.env.DEBUG) {
320
362
  console.error(chalk.gray('Stack:'), error.stack);
321
363
  }
364
+ await errorReporter.reportError(error, { type: 'uncaughtException' });
322
365
  process.exit(1);
323
366
  });
324
367
 
325
- process.on('unhandledRejection', (error) => {
368
+ process.on('unhandledRejection', async (error) => {
326
369
  console.error(chalk.red(`${t('cli.error')}:`), error.message);
327
370
  if (process.env.DEBUG) {
328
371
  console.error(chalk.gray('Stack:'), error.stack);
329
372
  }
373
+ await errorReporter.reportError(error, { type: 'unhandledRejection' });
330
374
  process.exit(1);
331
375
  });
332
376
 
@@ -336,15 +380,29 @@ async function checkForUpdates() {
336
380
  if (process.env.VCM_SKIP_UPDATE_CHECK === '1' || process.env.VCM_SKIP_UPDATE_CHECK === 'true') {
337
381
  return;
338
382
  }
339
- const { checkForCLIUpdates } = require('vibecodingmachine-core');
340
383
  // If running inside the repository (local development), skip update checks entirely
341
384
  const isDevWorkspace = fs.existsSync(path.join(rootDir, '.git'));
342
385
  if (isDevWorkspace) {
343
386
  console.log(chalk.yellow('\nDetected local development workspace; skipping update check.'));
344
387
  return;
345
388
  }
389
+ // Additional check: if we're in a workspace with package.json containing vibecodingmachine-cli
390
+ const packageJsonPath = path.join(rootDir, 'package.json');
391
+ if (fs.existsSync(packageJsonPath)) {
392
+ try {
393
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
394
+ if (pkg.name === 'vibecodingmachine' || (pkg.workspaces && pkg.workspaces.length > 0)) {
395
+ console.log(chalk.yellow('\nDetected local development workspace; skipping update check.'));
396
+ return;
397
+ }
398
+ } catch (e) {
399
+ // Ignore JSON parse errors
400
+ }
401
+ }
346
402
  console.log(chalk.gray(`\n🔍 Checking for updates... (current: v${packageJson.version})`));
347
- const updateInfo = await checkForCLIUpdates(packageJson.version);
403
+ // Check npm registry for CLI updates (not S3 manifest which is for Electron)
404
+ const { checkForUpdates: checkNpmUpdates } = require('vibecodingmachine-core');
405
+ const updateInfo = await checkNpmUpdates('vibecodingmachine-cli', packageJson.version);
348
406
  console.log(chalk.gray(` Update check result: ${JSON.stringify(updateInfo)}\n`));
349
407
 
350
408
  if (updateInfo.hasUpdate) {
@@ -356,7 +414,7 @@ async function checkForUpdates() {
356
414
  console.log(chalk.gray(` Published: ${updateInfo.publishedDate}`));
357
415
 
358
416
  // Prompt user to update
359
- const answer = await inquirer.prompt([
417
+ const answer = await promptWithDefaultsOnce([
360
418
  {
361
419
  type: 'confirm',
362
420
  name: 'shouldUpdate',
@@ -376,127 +434,19 @@ async function checkForUpdates() {
376
434
  // Do not attempt global install during development to avoid confusing local dev flow
377
435
  return;
378
436
  }
379
- const spinner = ora('Fetching package metadata...').start();
380
-
381
- // Get latest package metadata from npm registry
382
- const registryUrl = 'https://registry.npmjs.org/vibecodingmachine-cli/latest';
383
- const meta = await new Promise((resolve, reject) => {
384
- https.get(registryUrl, (res) => {
385
- let data = '';
386
- res.on('data', (chunk) => data += chunk);
387
- res.on('end', () => {
388
- try {
389
- resolve(JSON.parse(data));
390
- } catch (err) {
391
- reject(err);
392
- }
393
- });
394
- }).on('error', reject);
395
- });
396
-
397
- const tarball = meta && meta.dist && meta.dist.tarball;
398
- if (!tarball) {
399
- spinner.fail('Could not determine tarball URL for update');
400
- console.log(chalk.yellow(' You can manually update with: ') + chalk.bold.white('npm install -g vibecodingmachine-cli@latest\n'));
401
- return;
402
- }
403
-
404
- spinner.text = 'Resolving tarball...';
405
-
406
- // HEAD to get content-length
407
- const totalBytes = await new Promise((resolve) => {
408
- const req = https.request(tarball, { method: 'HEAD' }, (res) => {
409
- const len = parseInt(res.headers['content-length'] || '0', 10);
410
- resolve(Number.isFinite(len) ? len : 0);
411
- });
412
- req.on('error', () => resolve(0));
413
- req.end();
414
- });
415
-
416
- const tmpFile = path.join(os.tmpdir(), `vcm-update-${Date.now()}.tgz`);
417
-
418
- // Download tarball with progress
419
- spinner.text = 'Downloading update...';
420
- // Stop the spinner so we can write a single-line progress indicator without conflicts
421
- try { spinner.stop(); } catch (e) {}
422
- // Print initial progress line (clear line first)
423
- process.stdout.write('\r\x1b[2KDownloading: 0% — 0.0 MB');
424
- const progressStart = Date.now();
425
- function formatEta(sec) {
426
- if (!isFinite(sec) || sec === null) return '--:--';
427
- const s = Math.max(0, Math.round(sec));
428
- const m = Math.floor(s / 60);
429
- const ss = s % 60;
430
- return `${m}:${ss.toString().padStart(2, '0')}`;
431
- }
432
- await new Promise((resolve, reject) => {
433
- https.get(tarball, (res) => {
434
- const fileStream = fs.createWriteStream(tmpFile);
435
- let downloaded = 0;
436
-
437
- // Print an updating single-line progress indicator (percent + MB)
438
- let lastPercent = -1;
439
- let lastMbReported = -1;
440
- res.on('data', (chunk) => {
441
- downloaded += chunk.length;
442
- const percent = totalBytes ? Math.round((downloaded / totalBytes) * 100) : null;
443
- const mbDownloaded = +(downloaded / (1024 * 1024));
444
- const mbTotal = totalBytes ? (totalBytes / (1024 * 1024)) : null;
445
-
446
- // ETA and speed
447
- const elapsedSec = Math.max(0.001, (Date.now() - progressStart) / 1000);
448
- const speed = downloaded / elapsedSec; // bytes/sec
449
- const remaining = totalBytes ? Math.max(0, totalBytes - downloaded) : null;
450
- const etaSec = remaining && speed > 0 ? remaining / speed : null;
451
-
452
- // Build simple ASCII progress bar
453
- const width = 30;
454
- const fill = percent !== null ? Math.round((percent / 100) * width) : Math.min(width, Math.max(0, Math.round((mbDownloaded / (mbTotal || 1)) * width)));
455
- const bar = '█'.repeat(fill) + '-'.repeat(Math.max(0, width - fill));
456
-
457
- const pctText = percent !== null ? `${percent}%` : '--%';
458
- const mbText = mbTotal ? `${mbDownloaded.toFixed(1)} MB / ${mbTotal.toFixed(1)} MB` : `${mbDownloaded.toFixed(1)} MB`;
459
- const etaText = etaSec ? formatEta(etaSec) : '--:--';
460
-
461
- // Update only when percent changes or every 0.5 MB to reduce noise
462
- const mbReport = Math.floor(mbDownloaded * 2) / 2;
463
- if ((percent !== null && percent !== lastPercent) || (percent === null && mbReport !== lastMbReported) || Math.random() < 0.001) {
464
- lastPercent = percent;
465
- lastMbReported = mbReport;
466
- process.stdout.write(`\r\x1b[2K[${bar}] ${pctText} ${mbText} ETA: ${etaText}`);
467
- }
468
- });
469
-
470
- res.on('end', () => fileStream.end());
471
- res.on('error', (err) => reject(err));
472
-
473
- fileStream.on('finish', () => resolve());
474
- fileStream.on('error', (err) => reject(err));
475
-
476
- res.pipe(fileStream);
477
- }).on('error', reject);
478
- });
479
-
480
- // Ensure progress line ends and move to next line
481
- process.stdout.write('\n');
482
- spinner.start();
483
- spinner.succeed('Downloaded update');
484
-
485
- // Install the downloaded tarball
486
- spinner.start('Installing update...');
437
+
438
+ const spinner = ora('Installing update from npm...').start();
487
439
  try {
488
- execSync(`npm install -g "${tmpFile}"`, { stdio: 'inherit', encoding: 'utf8' });
440
+ // Use npm directly to install the latest version from registry
441
+ execSync('npm install -g vibecodingmachine-cli@latest', { stdio: 'inherit', encoding: 'utf8' });
489
442
  spinner.succeed('Installed update');
490
443
  console.log(chalk.green('\n✅ Successfully updated to v' + updateInfo.latestVersion + '!'));
491
444
  console.log(chalk.gray(' Please restart your command to use the new version.\n'));
492
- // Cleanup
493
- try { fs.unlinkSync(tmpFile); } catch (e) {}
494
445
  process.exit(0);
495
446
  } catch (err) {
496
447
  spinner.fail('Installation failed');
497
448
  console.log(chalk.red('\n❌ Update failed:'), err.message);
498
449
  console.log(chalk.yellow(' You can manually update with: ') + chalk.bold.white('npm install -g vibecodingmachine-cli@latest\n'));
499
- try { fs.unlinkSync(tmpFile); } catch (e) {}
500
450
  }
501
451
  } catch (error) {
502
452
  console.log(chalk.red('\n❌ Update failed:'), error.message);
@@ -533,10 +483,22 @@ if (!process.argv.slice(2).length) {
533
483
  try {
534
484
  await auth.login();
535
485
  console.log(chalk.green(`\n✓ ${t('cli.auth.success')}\n`));
486
+
487
+ // Initialize error reporter with auth token
488
+ const token = await auth.getAuthToken();
489
+ if (token) {
490
+ errorReporter.setAuthToken(token);
491
+ }
536
492
  } catch (error) {
537
493
  console.log(chalk.red(`\n✗ ${t('cli.auth.failed')}:`), error.message);
538
494
  process.exit(1);
539
495
  }
496
+ } else {
497
+ // Initialize error reporter with existing auth token
498
+ const token = await auth.getAuthToken();
499
+ if (token) {
500
+ errorReporter.setAuthToken(token);
501
+ }
540
502
  }
541
503
 
542
504
  // Check compliance after authentication
@@ -574,10 +536,22 @@ if (!process.argv.slice(2).length) {
574
536
  try {
575
537
  await auth.login();
576
538
  console.log(chalk.green(`\n✓ ${t('cli.auth.success')}\n`));
539
+
540
+ // Initialize error reporter with auth token
541
+ const token = await auth.getAuthToken();
542
+ if (token) {
543
+ errorReporter.setAuthToken(token);
544
+ }
577
545
  } catch (error) {
578
546
  console.log(chalk.red(`\n✗ ${t('cli.auth.failed')}:`), error.message);
579
547
  process.exit(1);
580
548
  }
549
+ } else {
550
+ // Initialize error reporter with existing auth token
551
+ const token = await auth.getAuthToken();
552
+ if (token) {
553
+ errorReporter.setAuthToken(token);
554
+ }
581
555
  }
582
556
  }
583
557
 
@@ -0,0 +1 @@
1
+ {"timestamp":"2025-12-28T01:17:10.393Z","type":"auto-mode-stop","reason":"startup","message":"Auto Mode stopped (startup)"}
@@ -0,0 +1,2 @@
1
+ {"timestamp":"2026-01-04T04:29:09.497Z","type":"auto-mode-stop","reason":"startup","message":"Auto Mode stopped (startup)"}
2
+ {"timestamp":"2026-01-04T04:46:49.126Z","type":"auto-mode-stop","reason":"startup","message":"Auto Mode stopped (startup)"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vibecodingmachine-cli",
3
- "version": "2025.12.25-0025",
3
+ "version": "2026.01.22-1441",
4
4
  "description": "Command-line interface for Vibe Coding Machine - Autonomous development",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -25,7 +25,7 @@
25
25
  "author": "Vibe Coding Machine Team",
26
26
  "license": "MIT",
27
27
  "dependencies": {
28
- "vibecodingmachine-core": "^2025.12.25-0025",
28
+ "vibecodingmachine-core": "^2026.01.22-1441",
29
29
  "@aws-sdk/client-dynamodb": "^3.600.0",
30
30
  "@aws-sdk/lib-dynamodb": "^3.600.0",
31
31
  "boxen": "^5.1.2",
@@ -0,0 +1,21 @@
1
+ const { getDefaultProviderOrder, saveProviderPreferences, getProviderPreferences } = require('./src/utils/provider-registry');
2
+ const chalk = require('chalk');
3
+
4
+ async function resetOrder() {
5
+ try {
6
+ const defaultOrder = getDefaultProviderOrder();
7
+ console.log('New Default Order:', defaultOrder);
8
+
9
+ const currentPrefs = await getProviderPreferences();
10
+ console.log('Current User Order:', currentPrefs.order);
11
+
12
+ // Force update the order to match default
13
+ await saveProviderPreferences(defaultOrder, currentPrefs.enabled);
14
+ console.log(chalk.green('Successfully reset provider order to default (Cloud -> IDE -> Local).'));
15
+ } catch (error) {
16
+ console.error('Failed to reset order:', error);
17
+ process.exit(1);
18
+ }
19
+ }
20
+
21
+ resetOrder();
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ const fs = require('fs-extra');
3
+ const path = require('path');
4
+ const os = require('os');
5
+ const { getRequirementsPath } = require('vibecodingmachine-core/src/utils/repo-helpers.cjs');
6
+ const { convertPackageBlocksToHeadings } = require('../src/utils/requirements-converter');
7
+
8
+ async function main() {
9
+ try {
10
+ const repoRoot = path.resolve(__dirname, '..', '..', '..');
11
+ const reqPath = await getRequirementsPath(repoRoot, os.hostname());
12
+ if (!reqPath || !await fs.pathExists(reqPath)) {
13
+ console.error('Requirements file not found for this host:', reqPath);
14
+ process.exit(1);
15
+ }
16
+
17
+ const content = await fs.readFile(reqPath, 'utf8');
18
+ const converted = convertPackageBlocksToHeadings(content, 'todo', '⏳ Requirements not yet completed');
19
+
20
+ // Backup
21
+ const backupPath = `${reqPath}.bak.${Date.now()}`;
22
+ await fs.copy(reqPath, backupPath);
23
+ console.log('Backup created at', backupPath);
24
+
25
+ await fs.writeFile(reqPath, converted, 'utf8');
26
+ console.log('Converted requirements written to', reqPath);
27
+ } catch (e) {
28
+ console.error('Error converting requirements:', e);
29
+ process.exit(1);
30
+ }
31
+ }
32
+
33
+ if (require.main === module) {
34
+ main();
35
+ }
@@ -0,0 +1,24 @@
1
+ const { parseRequirementsFromContent } = require('../src/utils/requirements-parser');
2
+ const content = `# REQUIREMENTS
3
+
4
+ ## ⏳ Requirements not yet completed
5
+
6
+ PACKAGE: cli
7
+ Add filter options to ` + "`vcm req:list`" + `: --computer <hostname>
8
+
9
+ - Add
10
+ - bullet one
11
+ - bullet two
12
+
13
+ ### Modify "Add Requirement" dialog to include computer selection dropdown. Show computer focus areas as hints. Allow selecting a computer.
14
+
15
+ PACKAGE: electron-app
16
+ Create modal dialog for resolving sync conflicts. Show side-by-side diff of local vs remote changes.
17
+
18
+ - Create network status indicator
19
+
20
+ `;
21
+
22
+ const reqs = parseRequirementsFromContent(content, 'todo', '⏳ Requirements not yet completed');
23
+ console.log('Parsed titles:', reqs.map(r => r.title));
24
+ console.log('Full:', JSON.stringify(reqs, null, 2));
@@ -1,6 +1,6 @@
1
1
  const chalk = require('chalk');
2
2
  const auth = require('../utils/auth');
3
- const { t } = require('vibecodingmachine-core');
3
+ const { t, errorReporter } = require('vibecodingmachine-core');
4
4
 
5
5
  /**
6
6
  * Login command
@@ -28,6 +28,10 @@ async function login(options = {}) {
28
28
  }
29
29
  } catch (error) {
30
30
  console.error(chalk.red(`\n✗ ${t('auth.login.failed')}:`), error.message);
31
+ await errorReporter.reportError(error, {
32
+ command: 'auth:login',
33
+ headless: options.headless
34
+ });
31
35
  process.exit(1);
32
36
  }
33
37
  }