vibecodingmachine-cli 2026.3.9-850 → 2026.3.10-1547
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/README.md +85 -85
- package/bin/commands/agent-commands.js +295 -28
- package/bin/vibecodingmachine.js +0 -0
- package/package.json +2 -2
- package/scripts/postinstall.js +161 -161
- package/src/commands/auth.js +100 -100
- package/src/commands/auto-execution.js +120 -32
- package/src/commands/auto-requirement-management.js +9 -9
- package/src/commands/auto-status-helpers.js +6 -12
- package/src/commands/computers.js +318 -318
- package/src/commands/feature.js +123 -123
- package/src/commands/locale.js +72 -72
- package/src/commands/repo.js +163 -163
- package/src/commands/setup.js +93 -93
- package/src/commands/sync.js +287 -287
- package/src/index.js +5 -5
- package/src/utils/agent-selector.js +50 -50
- package/src/utils/asset-cleanup.js +60 -60
- package/src/utils/auth.js +6 -0
- package/src/utils/auto-mode-ansi-ui.js +237 -237
- package/src/utils/auto-mode-simple-ui.js +141 -141
- package/src/utils/copy-with-progress.js +167 -167
- package/src/utils/download-with-progress.js +84 -84
- package/src/utils/keyboard-handler.js +153 -153
- package/src/utils/kiro-installer.js +178 -178
- package/src/utils/logger.js +4 -4
- package/src/utils/persistent-header.js +114 -114
- package/src/utils/prompt-helper.js +63 -63
- package/src/utils/provider-checker/agent-runner.js +110 -31
- package/src/utils/provider-checker/ide-manager.js +37 -8
- package/src/utils/provider-checker/provider-validator.js +50 -0
- package/src/utils/provider-checker/requirements-manager.js +21 -6
- package/src/utils/status-card.js +121 -121
- package/src/utils/stdout-interceptor.js +127 -127
- package/src/utils/trui-main-handlers.js +41 -8
- package/src/utils/trui-main-menu.js +10 -3
- package/src/utils/trui-nav-agents.js +23 -33
- package/src/utils/trui-navigation.js +2 -2
- package/src/utils/user-tracking.js +299 -299
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
const inquirer = require('inquirer');
|
|
2
|
-
const chalk = require('chalk');
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Enhanced inquirer.prompt that shows a helpful hint for questions with defaults
|
|
6
|
-
* @param {Array} questions - Array of inquirer question objects
|
|
7
|
-
* @param {Object} options - Options object
|
|
8
|
-
* @param {boolean} options.showDefaultHint - Whether to show the default hint (default: true)
|
|
9
|
-
* @returns {Promise} - Promise resolving to answers
|
|
10
|
-
*/
|
|
11
|
-
async function promptWithDefaults(questions, options = {}) {
|
|
12
|
-
const { showDefaultHint = true } = options;
|
|
13
|
-
|
|
14
|
-
// Check if any questions have defaults and if we should show the hint
|
|
15
|
-
const hasDefaults = questions.some(q => q.default !== undefined);
|
|
16
|
-
|
|
17
|
-
if (showDefaultHint && hasDefaults) {
|
|
18
|
-
// Show the hint in gray before the first question with a default
|
|
19
|
-
console.log(chalk.gray('(Capital letters are defaults--press return to select the defaults)'));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
return await inquirer.prompt(questions);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Track whether we've shown the default hint in this session
|
|
27
|
-
* This ensures we only show it once per CLI session
|
|
28
|
-
*/
|
|
29
|
-
let hasShownDefaultHint = false;
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Enhanced inquirer.prompt that shows the default hint only once per session
|
|
33
|
-
* @param {Array} questions - Array of inquirer question objects
|
|
34
|
-
* @param {Object} options - Options object
|
|
35
|
-
* @param {boolean} options.forceShowHint - Force showing the hint even if already shown
|
|
36
|
-
* @returns {Promise} - Promise resolving to answers
|
|
37
|
-
*/
|
|
38
|
-
async function promptWithDefaultsOnce(questions, options = {}) {
|
|
39
|
-
const { forceShowHint = false } = options;
|
|
40
|
-
|
|
41
|
-
// Check if any questions have defaults
|
|
42
|
-
const hasDefaults = questions.some(q => q.default !== undefined);
|
|
43
|
-
|
|
44
|
-
if (hasDefaults && (!hasShownDefaultHint || forceShowHint)) {
|
|
45
|
-
// Show the hint in gray before the first question with a default
|
|
46
|
-
console.log(chalk.gray('(Capital letters are defaults--press return to select the defaults)'));
|
|
47
|
-
hasShownDefaultHint = true;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return await inquirer.prompt(questions);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Reset the hint tracking (useful for testing or new sessions)
|
|
55
|
-
*/
|
|
56
|
-
function resetDefaultHint() {
|
|
57
|
-
hasShownDefaultHint = false;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
module.exports = {
|
|
61
|
-
promptWithDefaults,
|
|
62
|
-
promptWithDefaultsOnce,
|
|
63
|
-
resetDefaultHint
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Enhanced inquirer.prompt that shows a helpful hint for questions with defaults
|
|
6
|
+
* @param {Array} questions - Array of inquirer question objects
|
|
7
|
+
* @param {Object} options - Options object
|
|
8
|
+
* @param {boolean} options.showDefaultHint - Whether to show the default hint (default: true)
|
|
9
|
+
* @returns {Promise} - Promise resolving to answers
|
|
10
|
+
*/
|
|
11
|
+
async function promptWithDefaults(questions, options = {}) {
|
|
12
|
+
const { showDefaultHint = true } = options;
|
|
13
|
+
|
|
14
|
+
// Check if any questions have defaults and if we should show the hint
|
|
15
|
+
const hasDefaults = questions.some(q => q.default !== undefined);
|
|
16
|
+
|
|
17
|
+
if (showDefaultHint && hasDefaults) {
|
|
18
|
+
// Show the hint in gray before the first question with a default
|
|
19
|
+
console.log(chalk.gray('(Capital letters are defaults--press return to select the defaults)'));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return await inquirer.prompt(questions);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Track whether we've shown the default hint in this session
|
|
27
|
+
* This ensures we only show it once per CLI session
|
|
28
|
+
*/
|
|
29
|
+
let hasShownDefaultHint = false;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Enhanced inquirer.prompt that shows the default hint only once per session
|
|
33
|
+
* @param {Array} questions - Array of inquirer question objects
|
|
34
|
+
* @param {Object} options - Options object
|
|
35
|
+
* @param {boolean} options.forceShowHint - Force showing the hint even if already shown
|
|
36
|
+
* @returns {Promise} - Promise resolving to answers
|
|
37
|
+
*/
|
|
38
|
+
async function promptWithDefaultsOnce(questions, options = {}) {
|
|
39
|
+
const { forceShowHint = false } = options;
|
|
40
|
+
|
|
41
|
+
// Check if any questions have defaults
|
|
42
|
+
const hasDefaults = questions.some(q => q.default !== undefined);
|
|
43
|
+
|
|
44
|
+
if (hasDefaults && (!hasShownDefaultHint || forceShowHint)) {
|
|
45
|
+
// Show the hint in gray before the first question with a default
|
|
46
|
+
console.log(chalk.gray('(Capital letters are defaults--press return to select the defaults)'));
|
|
47
|
+
hasShownDefaultHint = true;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return await inquirer.prompt(questions);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Reset the hint tracking (useful for testing or new sessions)
|
|
55
|
+
*/
|
|
56
|
+
function resetDefaultHint() {
|
|
57
|
+
hasShownDefaultHint = false;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
promptWithDefaults,
|
|
62
|
+
promptWithDefaultsOnce,
|
|
63
|
+
resetDefaultHint
|
|
64
64
|
};
|
|
@@ -7,7 +7,7 @@ const chokidar = require('chokidar');
|
|
|
7
7
|
|
|
8
8
|
const { NODE_EXECUTABLE } = require('./node-detector');
|
|
9
9
|
const { IDE_INFO, isIDERunning, openIDEApp } = require('./ide-manager');
|
|
10
|
-
const { getResultFilePath } = require('./requirements-manager');
|
|
10
|
+
const { getResultFilePath, addTestRequirement, removeTestRequirement } = require('./requirements-manager');
|
|
11
11
|
|
|
12
12
|
// Timeout for direct LLM round-trips via auto:direct (ms)
|
|
13
13
|
const DIRECT_TIMEOUT_MS = 60000;
|
|
@@ -15,6 +15,7 @@ const DIRECT_TIMEOUT_MS = 60000;
|
|
|
15
15
|
const IDE_TIMEOUT_MS = 90000;
|
|
16
16
|
|
|
17
17
|
const CLI_ENTRY_POINT = path.resolve(path.join(__dirname, '../../../bin/vibecodingmachine.js'));
|
|
18
|
+
const TEST_REQ_TITLE = 'VCM agent connectivity check';
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Run an agent for 1 iteration and watch for the result file to be written.
|
|
@@ -33,6 +34,11 @@ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, s
|
|
|
33
34
|
// Remove stale result file so we detect a fresh write
|
|
34
35
|
try { fs.unlinkSync(resultFile); } catch { }
|
|
35
36
|
|
|
37
|
+
// Calculate requirements path early so it's available in the Promise scope
|
|
38
|
+
const os = require('os');
|
|
39
|
+
const hostname = os.hostname();
|
|
40
|
+
const requirementsPath = path.join(repoPath, `REQUIREMENTS-${hostname}.md`);
|
|
41
|
+
|
|
36
42
|
// For IDE providers: verify the IDE is running/installed, install if needed
|
|
37
43
|
let ideLaunchNote = '';
|
|
38
44
|
if (def.type === 'ide') {
|
|
@@ -116,24 +122,24 @@ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, s
|
|
|
116
122
|
}
|
|
117
123
|
}
|
|
118
124
|
|
|
119
|
-
// IDE is now installed (either was already or we just installed it) - launch it
|
|
120
|
-
if (checkResult.installed
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
//
|
|
136
|
-
|
|
125
|
+
// IDE is now installed (either was already or we just installed it) - launch it if not already running
|
|
126
|
+
if (checkResult.installed) {
|
|
127
|
+
// Check if IDE is already running before attempting to launch
|
|
128
|
+
const isRunning = isIDERunning(info.process);
|
|
129
|
+
if (!isRunning) {
|
|
130
|
+
console.log(`🪟 [AGENT CHECK] ${info.app} not running, attempting to launch...`);
|
|
131
|
+
// Use openIDEApp which will use WindowsAutomationManager
|
|
132
|
+
const launchSuccess = await openIDEApp(info.app, repoPath);
|
|
133
|
+
if (launchSuccess) {
|
|
134
|
+
ideLaunchNote = ideLaunchNote || ` (VCM launched ${info.app})`;
|
|
135
|
+
console.log(`🪟 [AGENT CHECK] Successfully launched ${info.app}`);
|
|
136
|
+
} else {
|
|
137
|
+
console.warn(`🪟 [AGENT CHECK] Could not launch ${info.app}, continuing anyway...`);
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
console.log(`[AGENT CHECK] ${info.app} is already running, skipping launch`);
|
|
141
|
+
// Give running IDE a moment to be ready
|
|
142
|
+
await new Promise(r => setTimeout(r, 2000));
|
|
137
143
|
}
|
|
138
144
|
}
|
|
139
145
|
}
|
|
@@ -145,14 +151,26 @@ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, s
|
|
|
145
151
|
let resolved = false;
|
|
146
152
|
let child = null;
|
|
147
153
|
let output = '';
|
|
154
|
+
let watcher;
|
|
155
|
+
let requirementsWatcher;
|
|
148
156
|
|
|
149
157
|
async function done(result) {
|
|
150
158
|
if (resolved) return;
|
|
151
159
|
resolved = true;
|
|
152
|
-
try { watcher.close(); } catch { }
|
|
160
|
+
try { if (watcher) watcher.close(); } catch { }
|
|
161
|
+
try { if (requirementsWatcher) requirementsWatcher.close(); } catch { }
|
|
153
162
|
clearTimeout(timeout);
|
|
154
163
|
clearInterval(cancelCheckInterval);
|
|
155
164
|
try { if (child) child.kill(); } catch { }
|
|
165
|
+
|
|
166
|
+
// Remove test requirement after check completes (pass or fail)
|
|
167
|
+
try {
|
|
168
|
+
removeTestRequirement(requirementsPath);
|
|
169
|
+
console.log(`[AGENT CHECK] Removed test requirement from ${requirementsPath}`);
|
|
170
|
+
} catch (err) {
|
|
171
|
+
console.warn(`[AGENT CHECK] Could not remove test requirement: ${err.message}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
156
174
|
resolve(result);
|
|
157
175
|
}
|
|
158
176
|
|
|
@@ -168,10 +186,27 @@ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, s
|
|
|
168
186
|
}
|
|
169
187
|
}
|
|
170
188
|
|
|
171
|
-
|
|
189
|
+
// Watch for result file creation
|
|
190
|
+
watcher = chokidar.watch(resultFile, { persistent: true, ignoreInitial: false, disableGlobbing: true });
|
|
172
191
|
watcher.on('add', checkResult);
|
|
173
192
|
watcher.on('change', checkResult);
|
|
174
193
|
|
|
194
|
+
// Also watch requirements file for status changes to [DONE]
|
|
195
|
+
requirementsWatcher = chokidar.watch(requirementsPath, { persistent: true, ignoreInitial: true });
|
|
196
|
+
requirementsWatcher.on('change', () => {
|
|
197
|
+
try {
|
|
198
|
+
const content = fs.readFileSync(requirementsPath, 'utf8');
|
|
199
|
+
// Check if test requirement status is [DONE]
|
|
200
|
+
if (content.includes(TEST_REQ_TITLE) && content.match(/VCM agent connectivity check[\s\S]*?Status:.*?\[DONE\]/)) {
|
|
201
|
+
console.log(`[AGENT CHECK] Detected [DONE] status in requirements file for ${providerId}`);
|
|
202
|
+
if (onProgress) onProgress(providerId, 'response_detected', null, 'Status updated to DONE.');
|
|
203
|
+
done({ status: 'success', message: 'Agent updated status to DONE', checkedAt });
|
|
204
|
+
}
|
|
205
|
+
} catch (err) {
|
|
206
|
+
console.warn(`[AGENT CHECK] Error reading requirements file: ${err.message}`);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
|
|
175
210
|
const timeout = setTimeout(() => {
|
|
176
211
|
// Diagnose: is the IDE process still running?
|
|
177
212
|
let diagnosis = '';
|
|
@@ -212,7 +247,7 @@ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, s
|
|
|
212
247
|
|
|
213
248
|
let args;
|
|
214
249
|
if (def.type === 'ide') {
|
|
215
|
-
args = [CLI_ENTRY_POINT, 'auto:start', '--ide', def.ide || providerId, '--max-chats', '
|
|
250
|
+
args = [CLI_ENTRY_POINT, 'auto:start', '--ide', def.ide || providerId, '--max-chats', '5'];
|
|
216
251
|
if (def.defaultModel) args.push('--ide-model', String(def.defaultModel));
|
|
217
252
|
if (def.extension) args.push('--extension', String(def.extension));
|
|
218
253
|
} else {
|
|
@@ -257,9 +292,23 @@ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, s
|
|
|
257
292
|
console.log(`[AGENT CHECK] CWD: ${repoPath}`);
|
|
258
293
|
console.log(`[AGENT CHECK] Result file: ${resultFile}`);
|
|
259
294
|
|
|
295
|
+
// Add test requirement to REQUIREMENTS-<hostname>.md
|
|
296
|
+
// This tells the IDE agent to respond, and will be deleted after check completes
|
|
297
|
+
// (requirementsPath already calculated at function start)
|
|
298
|
+
console.log(`[AGENT CHECK] Using requirements file: ${requirementsPath}`);
|
|
299
|
+
try {
|
|
300
|
+
addTestRequirement(requirementsPath, resultFile);
|
|
301
|
+
console.log(`[AGENT CHECK] Added test requirement to ${requirementsPath}`);
|
|
302
|
+
} catch (err) {
|
|
303
|
+
console.warn(`[AGENT CHECK] Could not add test requirement: ${err.message}`);
|
|
304
|
+
}
|
|
305
|
+
|
|
260
306
|
// Prepare environment - inherit all process.env and add NODE_PATH if needed
|
|
261
307
|
const spawnEnv = {
|
|
262
308
|
...process.env,
|
|
309
|
+
// Set IDE check mode flag so auto-execution knows to use --ide option instead of configured providers
|
|
310
|
+
VCM_IDE_CHECK_MODE: 'true',
|
|
311
|
+
VCM_SKIP_AUTH: 'true',
|
|
263
312
|
// Ensure NODE_PATH includes the monorepo node_modules if it exists
|
|
264
313
|
NODE_PATH: [
|
|
265
314
|
path.join(__dirname, '../../node_modules'),
|
|
@@ -268,6 +317,13 @@ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, s
|
|
|
268
317
|
].filter(Boolean).join(path.delimiter)
|
|
269
318
|
};
|
|
270
319
|
|
|
320
|
+
// Log the command being executed
|
|
321
|
+
console.log(`[AGENT CHECK] Starting check for ${providerId}`);
|
|
322
|
+
console.log(`[AGENT CHECK] Node Executable: ${NODE_EXECUTABLE}`);
|
|
323
|
+
console.log(`[AGENT CHECK] Args: ${args.join(' ')}`);
|
|
324
|
+
console.log(`[AGENT CHECK] CWD: ${repoPath}`);
|
|
325
|
+
console.log(`[AGENT CHECK] Result file: ${resultFile}`);
|
|
326
|
+
|
|
271
327
|
child = spawn(NODE_EXECUTABLE, args, {
|
|
272
328
|
cwd: repoPath,
|
|
273
329
|
env: spawnEnv,
|
|
@@ -301,6 +357,21 @@ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, s
|
|
|
301
357
|
if (resolved) return;
|
|
302
358
|
console.log(`[AGENT CHECK] ${providerId} process exited with code ${code}`);
|
|
303
359
|
console.log(`[AGENT CHECK] ${providerId} process output: ${output.slice(-500)}`);
|
|
360
|
+
|
|
361
|
+
// Additional debugging for Windsurf authentication issues
|
|
362
|
+
if (providerId === 'windsurf' && code === 8) {
|
|
363
|
+
console.log(`[AGENT CHECK] Windsurf specific debugging - code 8 often indicates authentication or startup issues`);
|
|
364
|
+
console.log(`[AGENT CHECK] Windsurf output analysis:`, output.split('\n').slice(-10));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// Check for DONE status in output (indicates successful completion)
|
|
368
|
+
if (code === 0 && output.includes('Status: ✅ DONE') && output.includes('Requirement complete')) {
|
|
369
|
+
console.log(`[AGENT CHECK] Detected successful completion in output for ${providerId}`);
|
|
370
|
+
if (onProgress) onProgress(providerId, 'response_detected', null, 'Auto mode completed successfully.');
|
|
371
|
+
done({ status: 'success', message: 'Agent completed requirement successfully', checkedAt });
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
|
|
304
375
|
// Check one more time after process exits
|
|
305
376
|
checkResult();
|
|
306
377
|
if (!resolved) {
|
|
@@ -382,29 +453,37 @@ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, s
|
|
|
382
453
|
return;
|
|
383
454
|
}
|
|
384
455
|
|
|
385
|
-
debugLog(`No quota keywords in process output or message, checking
|
|
456
|
+
debugLog(`No quota keywords in process output or message, checking platform-specific UI fallback for ${providerId}`);
|
|
386
457
|
|
|
387
|
-
//
|
|
458
|
+
// Get quota manager based on platform
|
|
459
|
+
let quotaManager = null;
|
|
388
460
|
if (process.platform === 'darwin') {
|
|
461
|
+
const { AppleScriptManager } = require('vibecodingmachine-core');
|
|
462
|
+
quotaManager = new AppleScriptManager();
|
|
463
|
+
} else if (process.platform === 'win32') {
|
|
464
|
+
const { WindowsAutomationManager } = require('vibecodingmachine-core');
|
|
465
|
+
quotaManager = new WindowsAutomationManager();
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Check platform-specific UI scraping as fallback for IDEs that support it
|
|
469
|
+
if (quotaManager) {
|
|
389
470
|
try {
|
|
390
|
-
const { AppleScriptManager } = require('vibecodingmachine-core');
|
|
391
|
-
const appleScriptManager = new AppleScriptManager();
|
|
392
471
|
let quotaCheck = null;
|
|
393
472
|
|
|
394
473
|
// Use specific quota detection methods for each IDE
|
|
395
474
|
switch (providerId) {
|
|
396
475
|
case 'antigravity':
|
|
397
|
-
quotaCheck = await
|
|
476
|
+
quotaCheck = await quotaManager.checkAntigravityQuotaLimit();
|
|
398
477
|
break;
|
|
399
478
|
case 'windsurf':
|
|
400
|
-
quotaCheck = await
|
|
479
|
+
quotaCheck = await quotaManager.checkWindsurfQuotaLimit();
|
|
401
480
|
break;
|
|
402
481
|
case 'cursor':
|
|
403
|
-
quotaCheck = await
|
|
482
|
+
quotaCheck = await quotaManager.checkCursorQuotaLimit();
|
|
404
483
|
break;
|
|
405
484
|
case 'github-copilot':
|
|
406
485
|
// GitHub Copilot uses the same detection as Cursor (both are VS Code extensions)
|
|
407
|
-
quotaCheck = await
|
|
486
|
+
quotaCheck = await quotaManager.checkCursorQuotaLimit();
|
|
408
487
|
break;
|
|
409
488
|
default:
|
|
410
489
|
debugLog(`No specific quota detection method available for ${providerId}`);
|
|
@@ -414,7 +493,7 @@ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, s
|
|
|
414
493
|
debugLog(`${providerId} quota check result: ` + JSON.stringify(quotaCheck));
|
|
415
494
|
|
|
416
495
|
if (quotaCheck && (quotaCheck.isRateLimited || quotaCheck.hasQuotaWarning)) {
|
|
417
|
-
debugLog(`🚨 ${providerId} quota limit detected via
|
|
496
|
+
debugLog(`🚨 ${providerId} quota limit detected via platform UI check`);
|
|
418
497
|
errorResult.rateLimited = true;
|
|
419
498
|
errorResult.rateLimitMessage = quotaCheck.message || quotaCheck.matchedText || `${providerId} quota limit detected`;
|
|
420
499
|
if (quotaCheck.resumeAt) {
|
|
@@ -49,18 +49,47 @@ function isIDERunning(processName) {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
|
-
* Open the IDE using `open -a <app> <repoPath>` (macOS).
|
|
52
|
+
* Open the IDE using `open -a <app> <repoPath>` (macOS) or Windows automation manager.
|
|
53
53
|
* Returns true when the launch command was sent.
|
|
54
54
|
*/
|
|
55
55
|
async function openIDEApp(appName, repoPath) {
|
|
56
|
-
if (!appName
|
|
56
|
+
if (!appName) return false;
|
|
57
|
+
|
|
57
58
|
try {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
59
|
+
if (process.platform === 'darwin') {
|
|
60
|
+
// macOS: use `open -a`
|
|
61
|
+
const safeRepo = repoPath ? ` "${repoPath.replace(/"/g, '\\"')}"` : '';
|
|
62
|
+
execSync(`open -a "${appName}"${safeRepo}`, { stdio: 'ignore' });
|
|
63
|
+
// Give it a few seconds to start before the automation begins
|
|
64
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
65
|
+
return true;
|
|
66
|
+
} else if (process.platform === 'win32') {
|
|
67
|
+
// Windows: use WindowsAutomationManager
|
|
68
|
+
console.log(`🪟 [IDE MANAGER] Opening ${appName} on Windows...`);
|
|
69
|
+
const { WindowsAutomationManager } = require('vibecodingmachine-core');
|
|
70
|
+
const manager = new WindowsAutomationManager();
|
|
71
|
+
|
|
72
|
+
// Map app name to the appropriate method
|
|
73
|
+
let result;
|
|
74
|
+
if (appName === 'Windsurf') {
|
|
75
|
+
console.log('🪟 [IDE MANAGER] Calling openWindsurf()...');
|
|
76
|
+
result = await manager.openWindsurf(repoPath);
|
|
77
|
+
} else if (appName === 'Cursor') {
|
|
78
|
+
console.log('🪟 [IDE MANAGER] Calling openCursorNative()...');
|
|
79
|
+
result = await manager.openCursorNative(repoPath);
|
|
80
|
+
} else {
|
|
81
|
+
console.log(`🪟 [IDE MANAGER] No Windows opener for ${appName}`);
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
console.log('🪟 [IDE MANAGER] Result:', result);
|
|
86
|
+
return result && result.success;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Other platforms: not supported
|
|
90
|
+
return false;
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error(`❌ [IDE MANAGER] Error opening ${appName}:`, error.message);
|
|
64
93
|
return false;
|
|
65
94
|
}
|
|
66
95
|
}
|
|
@@ -188,11 +188,61 @@ async function checkProvider(providerId, config = {}, repoPath, onProgress = nul
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
// Special handling for IDE providers - only check configuration for those that need it
|
|
192
|
+
if (def.type === 'ide') {
|
|
193
|
+
// Check if this IDE provider requires special configuration
|
|
194
|
+
try {
|
|
195
|
+
const { getProviderDefinition } = require('../provider-registry');
|
|
196
|
+
const providerDef = getProviderDefinition(providerId);
|
|
197
|
+
|
|
198
|
+
// Only check configuration if the provider has configKeys defined
|
|
199
|
+
if (providerDef && providerDef.configKeys) {
|
|
200
|
+
const { getAutoConfig } = require('../config');
|
|
201
|
+
const autoConfig = getAutoConfig();
|
|
202
|
+
|
|
203
|
+
// Check if all required config keys are available
|
|
204
|
+
const hasRequiredConfig = Object.entries(providerDef.configKeys).every(([configKey]) => {
|
|
205
|
+
return autoConfig && autoConfig[configKey];
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
if (!hasRequiredConfig) {
|
|
209
|
+
let configMessage = `${def.name} is installed but CLI is not configured for automation. `;
|
|
210
|
+
|
|
211
|
+
// Generate specific config instructions based on configKeys
|
|
212
|
+
const configInstructions = Object.keys(providerDef.configKeys).map(key => {
|
|
213
|
+
const envVar = key.toUpperCase();
|
|
214
|
+
return `Set ${envVar} or run "vcm auto:config".`;
|
|
215
|
+
}).join(' ');
|
|
216
|
+
|
|
217
|
+
configMessage += configInstructions;
|
|
218
|
+
|
|
219
|
+
return {
|
|
220
|
+
status: 'error',
|
|
221
|
+
message: configMessage,
|
|
222
|
+
checkedAt: new Date().toISOString(),
|
|
223
|
+
requirementLeftPending: false,
|
|
224
|
+
needsConfiguration: true
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// If no configKeys are defined (like Windsurf), assume no special configuration needed
|
|
230
|
+
console.log(`[AGENT CHECK] ${def.name} requires no special configuration`);
|
|
231
|
+
|
|
232
|
+
} catch (configError) {
|
|
233
|
+
console.warn(`[AGENT CHECK] Could not check provider configuration: ${configError.message}`);
|
|
234
|
+
// Continue with automation check even if configuration check fails
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
191
238
|
// Add test requirement (idempotent — safe to call even if already present from a prior failed agent)
|
|
192
239
|
try { addTestRequirement(reqPath, resultFile); } catch (err) {
|
|
193
240
|
return { status: 'error', message: `Could not write to REQUIREMENTS.md: ${err.message}`, checkedAt: new Date().toISOString(), requirementLeftPending: false };
|
|
194
241
|
}
|
|
195
242
|
|
|
243
|
+
// IDE providers generally don't need CLI system configuration to work
|
|
244
|
+
// They can communicate directly with the IDE without requiring VCM CLI setup
|
|
245
|
+
|
|
196
246
|
const { DIRECT_TIMEOUT_MS, IDE_TIMEOUT_MS } = require('./agent-runner');
|
|
197
247
|
const timeoutMs = def.type === 'ide' ? IDE_TIMEOUT_MS : DIRECT_TIMEOUT_MS;
|
|
198
248
|
const result = await runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, signal, onProgress);
|
|
@@ -5,6 +5,7 @@ const path = require('path');
|
|
|
5
5
|
|
|
6
6
|
const TEST_REQ_TITLE = 'VCM agent connectivity check';
|
|
7
7
|
const PENDING_HEADER = '## ⏳ Requirements not yet completed';
|
|
8
|
+
const IN_PROGRESS_HEADER = '## 🔨 Current In Progress Requirement';
|
|
8
9
|
const VERIFIED_HEADER = '## ✅ Verified by AI';
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -15,7 +16,8 @@ function getResultFilePath(repoPath) {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
|
-
* Add the test requirement
|
|
19
|
+
* Add the test requirement as the FIRST item in the pending section.
|
|
20
|
+
* The first item in the "Requirements not yet completed" section is the current in-progress item.
|
|
19
21
|
* Idempotent — if it's already there, do nothing.
|
|
20
22
|
*/
|
|
21
23
|
function addTestRequirement(reqPath, resultFile) {
|
|
@@ -25,11 +27,24 @@ function addTestRequirement(reqPath, resultFile) {
|
|
|
25
27
|
// Already present?
|
|
26
28
|
if (content.includes(TEST_REQ_TITLE)) return;
|
|
27
29
|
|
|
28
|
-
const testBlock =
|
|
29
|
-
🚦 Current Status: PREPARE
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
const testBlock = `- ${TEST_REQ_TITLE}
|
|
31
|
+
🚦 Current Status: [PREPARE]
|
|
32
|
+
|
|
33
|
+
**AUTOMATED CONNECTIVITY TEST - Please read and acknowledge:**
|
|
34
|
+
|
|
35
|
+
This is a simple test to verify VCM can communicate with your IDE.
|
|
36
|
+
|
|
37
|
+
**To complete this test, update the status above to [DONE]:**
|
|
38
|
+
- Change \`🚦 Current Status: [PREPARE]\` to \`🚦 Current Status: [DONE]\`
|
|
39
|
+
|
|
40
|
+
That's it! VCM will detect the status change and mark the connectivity test as successful.
|
|
41
|
+
|
|
42
|
+
**Alternative (if you want to create a file):**
|
|
43
|
+
1. Create file: \`${resultFile}\`
|
|
44
|
+
2. Write: \`VCM_CHECK_OK\`
|
|
45
|
+
3. Save
|
|
46
|
+
|
|
47
|
+
Either method works - status update is simplest.
|
|
33
48
|
|
|
34
49
|
`;
|
|
35
50
|
|