vibecodingmachine-cli 2025.12.25-25 → 2026.1.3-2209
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/vibecodingmachine.js +84 -118
- package/logs/audit/2025-12-27.jsonl +1 -0
- package/logs/audit/2026-01-03.jsonl +2 -0
- package/package.json +2 -2
- package/src/commands/auth.js +5 -1
- package/src/commands/auto-direct.js +219 -213
- package/src/commands/auto.js +6 -3
- package/src/commands/computers.js +9 -0
- package/src/commands/feature.js +123 -0
- package/src/commands/repo.js +27 -22
- package/src/commands/requirements-remote.js +24 -1
- package/src/commands/requirements.js +129 -9
- package/src/commands/setup.js +2 -1
- package/src/commands/sync.js +7 -1
- package/src/utils/auth.js +20 -13
- package/src/utils/config.js +14 -1
- package/src/utils/first-run.js +8 -6
- package/src/utils/interactive.js +613 -53
- package/src/utils/prompt-helper.js +64 -0
- package/tests/home-bootstrap.test.js +76 -0
package/bin/vibecodingmachine.js
CHANGED
|
@@ -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
|
|
|
@@ -140,6 +144,9 @@ program
|
|
|
140
144
|
.command('req:list')
|
|
141
145
|
.description(t('cli.req.list'))
|
|
142
146
|
.option('-s, --status <status>', 'Filter by status (pending, in-progress, completed)')
|
|
147
|
+
.option('-c, --computer <hostname>', 'Filter by computer hostname')
|
|
148
|
+
.option('-f, --focus <area>', 'Filter by focus area')
|
|
149
|
+
.option('-a, --all-computers', 'Show requirements from all computers with computer tags')
|
|
143
150
|
.action(reqCommands.list);
|
|
144
151
|
|
|
145
152
|
program
|
|
@@ -172,6 +179,33 @@ program
|
|
|
172
179
|
.description(t('cli.req.rename'))
|
|
173
180
|
.action((oldTitle, newTitle, description) => reqCommands.rename(oldTitle, newTitle, description));
|
|
174
181
|
|
|
182
|
+
program
|
|
183
|
+
.command('req:number-all')
|
|
184
|
+
.description('Number all existing requirements with R1, R2, R3, etc.')
|
|
185
|
+
.action(reqCommands.numberAll);
|
|
186
|
+
|
|
187
|
+
// Feature branch management commands
|
|
188
|
+
program
|
|
189
|
+
.command('feature:start <requirement-title>')
|
|
190
|
+
.description('Create and checkout feature branch for requirement (e.g., "R1: Email System")')
|
|
191
|
+
.action(featureCommands.start);
|
|
192
|
+
|
|
193
|
+
program
|
|
194
|
+
.command('feature:finish <requirement-title>')
|
|
195
|
+
.description('Merge feature branch back to parent and delete branch')
|
|
196
|
+
.option('-p, --parent <branch>', 'Parent branch to merge into', 'main')
|
|
197
|
+
.action(featureCommands.finish);
|
|
198
|
+
|
|
199
|
+
program
|
|
200
|
+
.command('feature:remove <requirement-title>')
|
|
201
|
+
.description('Remove a feature by reverting its merge commit')
|
|
202
|
+
.action(featureCommands.remove);
|
|
203
|
+
|
|
204
|
+
program
|
|
205
|
+
.command('feature:list')
|
|
206
|
+
.description('List all requirement feature branches')
|
|
207
|
+
.action(featureCommands.list);
|
|
208
|
+
|
|
175
209
|
// IDE integration commands
|
|
176
210
|
program
|
|
177
211
|
.command('ide:list')
|
|
@@ -314,19 +348,21 @@ program
|
|
|
314
348
|
});
|
|
315
349
|
|
|
316
350
|
// Error handling
|
|
317
|
-
process.on('uncaughtException', (error) => {
|
|
351
|
+
process.on('uncaughtException', async (error) => {
|
|
318
352
|
console.error(chalk.red(`${t('cli.error')}:`), error.message);
|
|
319
353
|
if (process.env.DEBUG) {
|
|
320
354
|
console.error(chalk.gray('Stack:'), error.stack);
|
|
321
355
|
}
|
|
356
|
+
await errorReporter.reportError(error, { type: 'uncaughtException' });
|
|
322
357
|
process.exit(1);
|
|
323
358
|
});
|
|
324
359
|
|
|
325
|
-
process.on('unhandledRejection', (error) => {
|
|
360
|
+
process.on('unhandledRejection', async (error) => {
|
|
326
361
|
console.error(chalk.red(`${t('cli.error')}:`), error.message);
|
|
327
362
|
if (process.env.DEBUG) {
|
|
328
363
|
console.error(chalk.gray('Stack:'), error.stack);
|
|
329
364
|
}
|
|
365
|
+
await errorReporter.reportError(error, { type: 'unhandledRejection' });
|
|
330
366
|
process.exit(1);
|
|
331
367
|
});
|
|
332
368
|
|
|
@@ -336,15 +372,29 @@ async function checkForUpdates() {
|
|
|
336
372
|
if (process.env.VCM_SKIP_UPDATE_CHECK === '1' || process.env.VCM_SKIP_UPDATE_CHECK === 'true') {
|
|
337
373
|
return;
|
|
338
374
|
}
|
|
339
|
-
const { checkForCLIUpdates } = require('vibecodingmachine-core');
|
|
340
375
|
// If running inside the repository (local development), skip update checks entirely
|
|
341
376
|
const isDevWorkspace = fs.existsSync(path.join(rootDir, '.git'));
|
|
342
377
|
if (isDevWorkspace) {
|
|
343
378
|
console.log(chalk.yellow('\nDetected local development workspace; skipping update check.'));
|
|
344
379
|
return;
|
|
345
380
|
}
|
|
381
|
+
// Additional check: if we're in a workspace with package.json containing vibecodingmachine-cli
|
|
382
|
+
const packageJsonPath = path.join(rootDir, 'package.json');
|
|
383
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
384
|
+
try {
|
|
385
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
386
|
+
if (pkg.name === 'vibecodingmachine' || (pkg.workspaces && pkg.workspaces.length > 0)) {
|
|
387
|
+
console.log(chalk.yellow('\nDetected local development workspace; skipping update check.'));
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
} catch (e) {
|
|
391
|
+
// Ignore JSON parse errors
|
|
392
|
+
}
|
|
393
|
+
}
|
|
346
394
|
console.log(chalk.gray(`\n🔍 Checking for updates... (current: v${packageJson.version})`));
|
|
347
|
-
|
|
395
|
+
// Check npm registry for CLI updates (not S3 manifest which is for Electron)
|
|
396
|
+
const { checkForUpdates: checkNpmUpdates } = require('vibecodingmachine-core');
|
|
397
|
+
const updateInfo = await checkNpmUpdates('vibecodingmachine-cli', packageJson.version);
|
|
348
398
|
console.log(chalk.gray(` Update check result: ${JSON.stringify(updateInfo)}\n`));
|
|
349
399
|
|
|
350
400
|
if (updateInfo.hasUpdate) {
|
|
@@ -356,7 +406,7 @@ async function checkForUpdates() {
|
|
|
356
406
|
console.log(chalk.gray(` Published: ${updateInfo.publishedDate}`));
|
|
357
407
|
|
|
358
408
|
// Prompt user to update
|
|
359
|
-
const answer = await
|
|
409
|
+
const answer = await promptWithDefaultsOnce([
|
|
360
410
|
{
|
|
361
411
|
type: 'confirm',
|
|
362
412
|
name: 'shouldUpdate',
|
|
@@ -376,127 +426,19 @@ async function checkForUpdates() {
|
|
|
376
426
|
// Do not attempt global install during development to avoid confusing local dev flow
|
|
377
427
|
return;
|
|
378
428
|
}
|
|
379
|
-
|
|
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...');
|
|
429
|
+
|
|
430
|
+
const spinner = ora('Installing update from npm...').start();
|
|
487
431
|
try {
|
|
488
|
-
|
|
432
|
+
// Use npm directly to install the latest version from registry
|
|
433
|
+
execSync('npm install -g vibecodingmachine-cli@latest', { stdio: 'inherit', encoding: 'utf8' });
|
|
489
434
|
spinner.succeed('Installed update');
|
|
490
435
|
console.log(chalk.green('\n✅ Successfully updated to v' + updateInfo.latestVersion + '!'));
|
|
491
436
|
console.log(chalk.gray(' Please restart your command to use the new version.\n'));
|
|
492
|
-
// Cleanup
|
|
493
|
-
try { fs.unlinkSync(tmpFile); } catch (e) {}
|
|
494
437
|
process.exit(0);
|
|
495
438
|
} catch (err) {
|
|
496
439
|
spinner.fail('Installation failed');
|
|
497
440
|
console.log(chalk.red('\n❌ Update failed:'), err.message);
|
|
498
441
|
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
442
|
}
|
|
501
443
|
} catch (error) {
|
|
502
444
|
console.log(chalk.red('\n❌ Update failed:'), error.message);
|
|
@@ -533,10 +475,22 @@ if (!process.argv.slice(2).length) {
|
|
|
533
475
|
try {
|
|
534
476
|
await auth.login();
|
|
535
477
|
console.log(chalk.green(`\n✓ ${t('cli.auth.success')}\n`));
|
|
478
|
+
|
|
479
|
+
// Initialize error reporter with auth token
|
|
480
|
+
const token = await auth.getAuthToken();
|
|
481
|
+
if (token) {
|
|
482
|
+
errorReporter.setAuthToken(token);
|
|
483
|
+
}
|
|
536
484
|
} catch (error) {
|
|
537
485
|
console.log(chalk.red(`\n✗ ${t('cli.auth.failed')}:`), error.message);
|
|
538
486
|
process.exit(1);
|
|
539
487
|
}
|
|
488
|
+
} else {
|
|
489
|
+
// Initialize error reporter with existing auth token
|
|
490
|
+
const token = await auth.getAuthToken();
|
|
491
|
+
if (token) {
|
|
492
|
+
errorReporter.setAuthToken(token);
|
|
493
|
+
}
|
|
540
494
|
}
|
|
541
495
|
|
|
542
496
|
// Check compliance after authentication
|
|
@@ -574,10 +528,22 @@ if (!process.argv.slice(2).length) {
|
|
|
574
528
|
try {
|
|
575
529
|
await auth.login();
|
|
576
530
|
console.log(chalk.green(`\n✓ ${t('cli.auth.success')}\n`));
|
|
531
|
+
|
|
532
|
+
// Initialize error reporter with auth token
|
|
533
|
+
const token = await auth.getAuthToken();
|
|
534
|
+
if (token) {
|
|
535
|
+
errorReporter.setAuthToken(token);
|
|
536
|
+
}
|
|
577
537
|
} catch (error) {
|
|
578
538
|
console.log(chalk.red(`\n✗ ${t('cli.auth.failed')}:`), error.message);
|
|
579
539
|
process.exit(1);
|
|
580
540
|
}
|
|
541
|
+
} else {
|
|
542
|
+
// Initialize error reporter with existing auth token
|
|
543
|
+
const token = await auth.getAuthToken();
|
|
544
|
+
if (token) {
|
|
545
|
+
errorReporter.setAuthToken(token);
|
|
546
|
+
}
|
|
581
547
|
}
|
|
582
548
|
}
|
|
583
549
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"timestamp":"2025-12-28T01:17:10.393Z","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": "
|
|
3
|
+
"version": "2026.01.03-2209",
|
|
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": "^
|
|
28
|
+
"vibecodingmachine-core": "^2026.01.03-2209",
|
|
29
29
|
"@aws-sdk/client-dynamodb": "^3.600.0",
|
|
30
30
|
"@aws-sdk/lib-dynamodb": "^3.600.0",
|
|
31
31
|
"boxen": "^5.1.2",
|
package/src/commands/auth.js
CHANGED
|
@@ -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
|
}
|