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.
Files changed (39) hide show
  1. package/README.md +85 -85
  2. package/bin/commands/agent-commands.js +295 -28
  3. package/bin/vibecodingmachine.js +0 -0
  4. package/package.json +2 -2
  5. package/scripts/postinstall.js +161 -161
  6. package/src/commands/auth.js +100 -100
  7. package/src/commands/auto-execution.js +120 -32
  8. package/src/commands/auto-requirement-management.js +9 -9
  9. package/src/commands/auto-status-helpers.js +6 -12
  10. package/src/commands/computers.js +318 -318
  11. package/src/commands/feature.js +123 -123
  12. package/src/commands/locale.js +72 -72
  13. package/src/commands/repo.js +163 -163
  14. package/src/commands/setup.js +93 -93
  15. package/src/commands/sync.js +287 -287
  16. package/src/index.js +5 -5
  17. package/src/utils/agent-selector.js +50 -50
  18. package/src/utils/asset-cleanup.js +60 -60
  19. package/src/utils/auth.js +6 -0
  20. package/src/utils/auto-mode-ansi-ui.js +237 -237
  21. package/src/utils/auto-mode-simple-ui.js +141 -141
  22. package/src/utils/copy-with-progress.js +167 -167
  23. package/src/utils/download-with-progress.js +84 -84
  24. package/src/utils/keyboard-handler.js +153 -153
  25. package/src/utils/kiro-installer.js +178 -178
  26. package/src/utils/logger.js +4 -4
  27. package/src/utils/persistent-header.js +114 -114
  28. package/src/utils/prompt-helper.js +63 -63
  29. package/src/utils/provider-checker/agent-runner.js +110 -31
  30. package/src/utils/provider-checker/ide-manager.js +37 -8
  31. package/src/utils/provider-checker/provider-validator.js +50 -0
  32. package/src/utils/provider-checker/requirements-manager.js +21 -6
  33. package/src/utils/status-card.js +121 -121
  34. package/src/utils/stdout-interceptor.js +127 -127
  35. package/src/utils/trui-main-handlers.js +41 -8
  36. package/src/utils/trui-main-menu.js +10 -3
  37. package/src/utils/trui-nav-agents.js +23 -33
  38. package/src/utils/trui-navigation.js +2 -2
  39. 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 && checkResult.path) {
121
- try {
122
- const exePath = checkResult.path;
123
- const repoArg = repoPath ? ` "${repoPath}"` : '';
124
- const { execSync } = require('child_process');
125
- execSync(`start "" "${exePath}"${repoArg}`, {
126
- stdio: 'ignore',
127
- windowsHide: true,
128
- timeout: 10000,
129
- shell: true
130
- });
131
- ideLaunchNote = ideLaunchNote || ` (VCM launched ${info.app})`;
132
- // Give IDE time to start
133
- await new Promise(r => setTimeout(r, 5000));
134
- } catch (launchError) {
135
- // Launch failed but IDE is installed - continue anyway
136
- console.warn(`[AGENT CHECK] Could not launch ${info.app}, continuing...`);
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
- const watcher = chokidar.watch(resultFile, { persistent: true, ignoreInitial: false, disableGlobbing: true });
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', '1'];
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 AppleScript UI as fallback for ${providerId}`);
456
+ debugLog(`No quota keywords in process output or message, checking platform-specific UI fallback for ${providerId}`);
386
457
 
387
- // Then check AppleScript UI scraping as fallback for IDEs that support it
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 appleScriptManager.checkAntigravityQuotaLimit();
476
+ quotaCheck = await quotaManager.checkAntigravityQuotaLimit();
398
477
  break;
399
478
  case 'windsurf':
400
- quotaCheck = await appleScriptManager.checkWindsurfQuotaLimit();
479
+ quotaCheck = await quotaManager.checkWindsurfQuotaLimit();
401
480
  break;
402
481
  case 'cursor':
403
- quotaCheck = await appleScriptManager.checkCursorQuotaLimit();
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 appleScriptManager.checkCursorQuotaLimit();
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 AppleScript`);
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 || process.platform !== 'darwin') return false;
56
+ if (!appName) return false;
57
+
57
58
  try {
58
- const safeRepo = repoPath ? ` "${repoPath.replace(/"/g, '\\"')}"` : '';
59
- execSync(`open -a "${appName}"${safeRepo}`, { stdio: 'ignore' });
60
- // Give it a few seconds to start before the automation begins
61
- await new Promise(r => setTimeout(r, 5000));
62
- return true;
63
- } catch {
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 at the TOP of the pending section.
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 = `### 1. ${TEST_REQ_TITLE}
29
- 🚦 Current Status: PREPARE
30
- Create a new file at the following absolute path: ${resultFile}
31
- The file must contain exactly this text on the first line: VCM_CHECK_OK
32
- Do not modify any other files. This is an automated connectivity test.
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