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.
- package/__tests__/antigravity-js-handler.test.js +23 -0
- package/__tests__/provider-manager.test.js +84 -0
- package/__tests__/provider-rate-cache.test.js +27 -0
- package/bin/vibecodingmachine.js +92 -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/reset_provider_order.js +21 -0
- package/scripts/convert-requirements.js +35 -0
- package/scripts/debug-parse.js +24 -0
- package/src/commands/auth.js +5 -1
- package/src/commands/auto-direct.js +747 -182
- package/src/commands/auto.js +206 -48
- package/src/commands/computers.js +9 -0
- package/src/commands/feature.js +123 -0
- package/src/commands/ide.js +108 -3
- package/src/commands/repo.js +27 -22
- package/src/commands/requirements-remote.js +34 -2
- package/src/commands/requirements.js +129 -9
- package/src/commands/setup.js +2 -1
- package/src/commands/status.js +39 -1
- package/src/commands/sync.js +7 -1
- package/src/utils/antigravity-js-handler.js +13 -4
- package/src/utils/auth.js +56 -25
- package/src/utils/compliance-check.js +10 -0
- package/src/utils/config.js +42 -1
- package/src/utils/date-formatter.js +44 -0
- package/src/utils/first-run.js +8 -6
- package/src/utils/interactive.js +1363 -334
- package/src/utils/kiro-js-handler.js +188 -0
- package/src/utils/prompt-helper.js +64 -0
- package/src/utils/provider-rate-cache.js +31 -0
- package/src/utils/provider-registry.js +42 -1
- package/src/utils/requirements-converter.js +107 -0
- package/src/utils/requirements-parser.js +144 -0
- package/tests/antigravity-js-handler.test.js +23 -0
- package/tests/home-bootstrap.test.js +76 -0
- package/tests/integration/health-tracking.integration.test.js +284 -0
- package/tests/provider-manager.test.js +92 -0
- package/tests/rate-limit-display.test.js +44 -0
- package/tests/requirements-bullet-parsing.test.js +15 -0
- package/tests/requirements-converter.test.js +42 -0
- package/tests/requirements-heading-count.test.js +27 -0
- package/tests/requirements-legacy-parsing.test.js +15 -0
- package/tests/requirements-parse-integration.test.js +44 -0
- package/tests/wait-for-ide-completion.test.js +56 -0
- package/tests/wait-for-ide-quota-detection-cursor-screenshot.test.js +61 -0
- package/tests/wait-for-ide-quota-detection-cursor.test.js +60 -0
- package/tests/wait-for-ide-quota-detection-negative.test.js +45 -0
- package/tests/wait-for-ide-quota-detection.test.js +59 -0
- package/verify_fix.js +36 -0
- 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
|
+
});
|
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
|
|
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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)"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vibecodingmachine-cli",
|
|
3
|
-
"version": "
|
|
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": "^
|
|
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));
|
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
|
}
|