vibecodingmachine-cli 2025.12.6-1702 → 2025.12.24-2348
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/vibecodingmachine.js +260 -52
- package/logs/audit/2025-12-24.jsonl +2 -0
- package/package.json +2 -2
- package/reproduce_issue.js +160 -0
- package/src/commands/auth.js +19 -19
- package/src/commands/auto-direct.js +133 -93
- package/src/commands/auto.js +165 -67
- package/src/commands/computers.js +62 -59
- package/src/commands/locale.js +73 -0
- package/src/commands/repo.js +0 -1
- package/src/commands/requirements-remote.js +14 -9
- package/src/commands/requirements.js +29 -3
- package/src/commands/setup.js +14 -13
- package/src/commands/status.js +17 -18
- package/src/commands/sync.js +72 -71
- package/src/utils/agent-selector.js +50 -0
- package/src/utils/antigravity-installer.js +212 -0
- package/src/utils/antigravity-js-handler.js +60 -0
- package/src/utils/asset-cleanup.js +0 -1
- package/src/utils/auth.js +149 -2
- package/src/utils/auto-mode-ansi-ui.js +0 -1
- package/src/utils/auto-mode-simple-ui.js +1 -1
- package/src/utils/compliance-check.js +166 -0
- package/src/utils/config.js +27 -1
- package/src/utils/copy-with-progress.js +167 -0
- package/src/utils/download-with-progress.js +84 -0
- package/src/utils/first-run.js +189 -71
- package/src/utils/interactive.js +419 -362
- package/src/utils/kiro-installer.js +56 -24
- package/src/utils/persistent-header.js +1 -3
- package/src/utils/provider-registry.js +43 -5
- package/src/utils/user-tracking.js +300 -0
- package/tests/requirements-navigator-buildtree-await.test.js +28 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const { getRequirementsPath } = require('vibecodingmachine-core');
|
|
4
|
+
const { getRepoPath } = require('./src/utils/config');
|
|
5
|
+
const requirements = require('./src/commands/requirements');
|
|
6
|
+
|
|
7
|
+
// Mock specific functions we need from interactive.js's logic
|
|
8
|
+
// helping function to move requirement to recycled (deletion logic)
|
|
9
|
+
async function moveRequirementToRecycled(reqPath, requirementTitle, fromSection) {
|
|
10
|
+
const content = await fs.readFile(reqPath, 'utf8');
|
|
11
|
+
const lines = content.split('\n');
|
|
12
|
+
|
|
13
|
+
let requirementStartIndex = -1;
|
|
14
|
+
let requirementEndIndex = -1;
|
|
15
|
+
|
|
16
|
+
for (let i = 0; i < lines.length; i++) {
|
|
17
|
+
const line = lines[i].trim();
|
|
18
|
+
if (line.startsWith('###')) {
|
|
19
|
+
const title = line.replace(/^###\s*/, '').trim();
|
|
20
|
+
// Logic from interactive.js
|
|
21
|
+
if (title && title.includes(requirementTitle)) {
|
|
22
|
+
requirementStartIndex = i;
|
|
23
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
24
|
+
const nextLine = lines[j].trim();
|
|
25
|
+
if (nextLine.startsWith('###') || (nextLine.startsWith('##') && !nextLine.startsWith('###'))) {
|
|
26
|
+
requirementEndIndex = j;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (requirementEndIndex === -1) {
|
|
31
|
+
requirementEndIndex = lines.length;
|
|
32
|
+
}
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (requirementStartIndex === -1) {
|
|
39
|
+
console.log('⚠️ Could not find requirement to recycle');
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log(`Found requirement at lines ${requirementStartIndex}-${requirementEndIndex}`);
|
|
44
|
+
|
|
45
|
+
const requirementBlock = lines.slice(requirementStartIndex, requirementEndIndex);
|
|
46
|
+
lines.splice(requirementStartIndex, requirementEndIndex - requirementStartIndex);
|
|
47
|
+
|
|
48
|
+
if (requirementStartIndex < lines.length) {
|
|
49
|
+
const nextLine = lines[requirementStartIndex]?.trim();
|
|
50
|
+
const packageNames = ['cli', 'core', 'electron-app', 'web', 'mobile', 'vscode-extension', 'sync-server'];
|
|
51
|
+
if (nextLine && packageNames.includes(nextLine.toLowerCase()) &&
|
|
52
|
+
!nextLine.startsWith('###') && !nextLine.startsWith('PACKAGE:')) {
|
|
53
|
+
lines.splice(requirementStartIndex, 1);
|
|
54
|
+
}
|
|
55
|
+
while (requirementStartIndex < lines.length && lines[requirementStartIndex]?.trim() === '') {
|
|
56
|
+
lines.splice(requirementStartIndex, 1);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let recycledIndex = -1;
|
|
61
|
+
for (let i = 0; i < lines.length; i++) {
|
|
62
|
+
if (lines[i].includes('♻️ Recycled') || lines[i].includes('🗑️ Recycled')) {
|
|
63
|
+
recycledIndex = i;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (recycledIndex === -1) {
|
|
69
|
+
let lastSectionIndex = -1;
|
|
70
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
71
|
+
if (lines[i].startsWith('##') && !lines[i].startsWith('###')) {
|
|
72
|
+
lastSectionIndex = i;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const insertIndex = lastSectionIndex > 0 ? lastSectionIndex : lines.length;
|
|
77
|
+
lines.splice(insertIndex, 0, '', '## ♻️ Recycled', '');
|
|
78
|
+
recycledIndex = insertIndex + 1;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let insertIndex = recycledIndex + 1;
|
|
82
|
+
while (insertIndex < lines.length && lines[insertIndex].trim() === '') {
|
|
83
|
+
insertIndex++;
|
|
84
|
+
}
|
|
85
|
+
lines.splice(insertIndex, 0, ...requirementBlock);
|
|
86
|
+
|
|
87
|
+
if (insertIndex + requirementBlock.length < lines.length && lines[insertIndex + requirementBlock.length].trim() !== '') {
|
|
88
|
+
lines.splice(insertIndex + requirementBlock.length, 0, '');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
await fs.writeFile(reqPath, lines.join('\n'));
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async function run() {
|
|
96
|
+
try {
|
|
97
|
+
const repoPath = '/Users/jesse/code/mediawink/vibecodingmachine'; // Hardcoded valid repo path
|
|
98
|
+
console.log('Repo path:', repoPath);
|
|
99
|
+
|
|
100
|
+
const reqPath = await getRequirementsPath(repoPath);
|
|
101
|
+
console.log('<<< PATH >>>', reqPath);
|
|
102
|
+
|
|
103
|
+
if (await fs.pathExists(reqPath)) {
|
|
104
|
+
const content = await fs.readFile(reqPath, 'utf8');
|
|
105
|
+
console.log('Current content length:', content.length);
|
|
106
|
+
console.log('Current content PRE-TEST:\n', content);
|
|
107
|
+
} else {
|
|
108
|
+
console.log('Requirements file does not exist');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
console.log('\n--- Adding TESTREQ1 ---');
|
|
112
|
+
await requirements.add('TESTREQ1', 'all', 'Description 1');
|
|
113
|
+
|
|
114
|
+
console.log('\n--- Adding TESTREQ2 ---');
|
|
115
|
+
await requirements.add('TESTREQ2', 'all', 'Description 2');
|
|
116
|
+
|
|
117
|
+
let content = await fs.readFile(reqPath, 'utf8');
|
|
118
|
+
console.log('Content after adding:\n', content);
|
|
119
|
+
|
|
120
|
+
// Verify order
|
|
121
|
+
// We expect TESTREQ2 to be above TESTREQ1 if it inserts at the top of the section
|
|
122
|
+
const lines = content.split('\n');
|
|
123
|
+
let idx1 = -1, idx2 = -1;
|
|
124
|
+
for (let i = 0; i < lines.length; i++) {
|
|
125
|
+
if (lines[i].includes('### TESTREQ1')) idx1 = i;
|
|
126
|
+
if (lines[i].includes('### TESTREQ2')) idx2 = i;
|
|
127
|
+
}
|
|
128
|
+
console.log(`TESTREQ1 line: ${idx1}, TESTREQ2 line: ${idx2}`);
|
|
129
|
+
if (idx2 < idx1 && idx2 > -1) {
|
|
130
|
+
console.log('SUCCESS: TESTREQ2 is above TESTREQ1 (Correct LIFO/Stack behavior for "Top of list")');
|
|
131
|
+
} else {
|
|
132
|
+
console.log('FAIL: Order is not correct for "Top of list" insertion');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
console.log('\n--- Deleting TESTREQ1 ---');
|
|
136
|
+
const success = await moveRequirementToRecycled(reqPath, 'TESTREQ1', 'todo');
|
|
137
|
+
console.log('Delete success:', success);
|
|
138
|
+
|
|
139
|
+
content = await fs.readFile(reqPath, 'utf8');
|
|
140
|
+
console.log('Content after delete:\n', content);
|
|
141
|
+
|
|
142
|
+
if (content.includes('### TESTREQ1')) {
|
|
143
|
+
// It should be in recycled section
|
|
144
|
+
const recycledIndex = content.indexOf('## ♻️ Recycled');
|
|
145
|
+
const reqIndex = content.indexOf('### TESTREQ1');
|
|
146
|
+
if (reqIndex > recycledIndex) {
|
|
147
|
+
console.log('SUCCESS: TESTREQ1 moved to Recycled');
|
|
148
|
+
} else {
|
|
149
|
+
console.log('FAIL: TESTREQ1 is still in TODO or wrong place');
|
|
150
|
+
}
|
|
151
|
+
} else {
|
|
152
|
+
console.log('FAIL: TESTREQ1 disappeared completely (should be recycled)');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
} catch (error) {
|
|
156
|
+
console.error('Error:', error);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
run();
|
package/src/commands/auth.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const chalk = require('chalk');
|
|
2
2
|
const auth = require('../utils/auth');
|
|
3
|
+
const { t } = require('vibecodingmachine-core');
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Login command
|
|
@@ -12,7 +13,7 @@ async function login(options = {}) {
|
|
|
12
13
|
const isAuth = await auth.isAuthenticated();
|
|
13
14
|
if (isAuth) {
|
|
14
15
|
const profile = await auth.getUserProfile();
|
|
15
|
-
console.log(chalk.green(`\n✓
|
|
16
|
+
console.log(chalk.green(`\n✓ ${t('auth.login.already', { email: chalk.bold(profile.email) })}`));
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -21,12 +22,12 @@ async function login(options = {}) {
|
|
|
21
22
|
|
|
22
23
|
// After successful authentication, start interactive mode
|
|
23
24
|
if (result) {
|
|
24
|
-
console.log(chalk.cyan(
|
|
25
|
+
console.log(chalk.cyan(`\n🚀 ${t('auth.starting.interactive')}\n`));
|
|
25
26
|
const { startInteractive } = require('../utils/interactive');
|
|
26
27
|
await startInteractive();
|
|
27
28
|
}
|
|
28
29
|
} catch (error) {
|
|
29
|
-
console.error(chalk.red(
|
|
30
|
+
console.error(chalk.red(`\n✗ ${t('auth.login.failed')}:`), error.message);
|
|
30
31
|
process.exit(1);
|
|
31
32
|
}
|
|
32
33
|
}
|
|
@@ -37,9 +38,9 @@ async function login(options = {}) {
|
|
|
37
38
|
async function logout() {
|
|
38
39
|
try {
|
|
39
40
|
await auth.logout();
|
|
40
|
-
console.log(chalk.green(
|
|
41
|
+
console.log(chalk.green(`\n✓ ${t('auth.logout.success')}`));
|
|
41
42
|
} catch (error) {
|
|
42
|
-
console.error(chalk.red(
|
|
43
|
+
console.error(chalk.red(`\n✗ ${t('auth.logout.failed')}:`), error.message);
|
|
43
44
|
process.exit(1);
|
|
44
45
|
}
|
|
45
46
|
}
|
|
@@ -52,40 +53,39 @@ async function status() {
|
|
|
52
53
|
const isAuth = await auth.isAuthenticated();
|
|
53
54
|
|
|
54
55
|
if (!isAuth) {
|
|
55
|
-
console.log(chalk.yellow('
|
|
56
|
-
console.log(
|
|
56
|
+
console.log(chalk.yellow(`\n${t('auth.not.authenticated')}`));
|
|
57
|
+
console.log(t('auth.run.login', { command: chalk.cyan('vcm auth:login') }));
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
const profile = await auth.getUserProfile();
|
|
61
|
-
const token = await auth.getToken();
|
|
62
62
|
|
|
63
63
|
// Get usage stats
|
|
64
64
|
const canRun = await auth.canRunAutoMode();
|
|
65
65
|
|
|
66
|
-
console.log(chalk.bold(
|
|
67
|
-
console.log(`
|
|
68
|
-
console.log(`
|
|
69
|
-
console.log(`
|
|
66
|
+
console.log(chalk.bold(`\n👤 ${t('profile.name')}:`));
|
|
67
|
+
console.log(` ${t('profile.name')}: ${profile.name}`);
|
|
68
|
+
console.log(` ${t('profile.email')}: ${profile.email}`);
|
|
69
|
+
console.log(` ${t('profile.tier')}: ${profile.tier === 'premium' ? chalk.green(t('profile.tier.premium')) : t('profile.tier.free')}`);
|
|
70
70
|
|
|
71
|
-
console.log(chalk.bold(
|
|
71
|
+
console.log(chalk.bold(`\n📊 ${t('profile.usage')}:`));
|
|
72
72
|
if (canRun.features && canRun.features.unlimitedIterations) {
|
|
73
|
-
console.log(`
|
|
74
|
-
console.log(`
|
|
73
|
+
console.log(` ${t('profile.daily.usage')}: ${canRun.todayUsage} ${t('profile.iterations')}`);
|
|
74
|
+
console.log(` ${t('profile.limit')}: ${chalk.green(t('profile.unlimited'))}`);
|
|
75
75
|
} else {
|
|
76
76
|
const limitColor = canRun.todayUsage >= canRun.maxIterations ? chalk.red : chalk.green;
|
|
77
|
-
console.log(`
|
|
77
|
+
console.log(` ${t('profile.daily.usage')}: ${limitColor(`${canRun.todayUsage}/${canRun.maxIterations}`)} ${t('profile.iterations')}`);
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
if (!canRun.canRun) {
|
|
81
|
-
console.log(chalk.red(`\n⚠️ ${canRun.reason}`));
|
|
81
|
+
console.log(chalk.red(`\n⚠️ ${t('quota.exceeded.warning', { reason: canRun.reason })}`));
|
|
82
82
|
if (profile.tier !== 'premium') {
|
|
83
|
-
console.log(chalk.gray('
|
|
83
|
+
console.log(chalk.gray(t('profile.upgrade.suggestion')));
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
} catch (error) {
|
|
88
|
-
console.error(chalk.red(
|
|
88
|
+
console.error(chalk.red(`\n✗ ${t('status.check.failed')}:`), error.message);
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|