vibecodingmachine-cli 2026.2.20-438 → 2026.2.26-1739

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 (101) hide show
  1. package/bin/auth/auth-compliance.js +126 -0
  2. package/bin/cli-program.js +104 -0
  3. package/bin/cli-setup.js +52 -0
  4. package/bin/commands/agent-commands.js +310 -0
  5. package/bin/commands/auto-commands.js +70 -0
  6. package/bin/commands/command-aliases.js +118 -0
  7. package/bin/commands/repo-commands.js +39 -0
  8. package/bin/commands/rui-commands.js +152 -0
  9. package/bin/config/cli-config.js +394 -0
  10. package/bin/init/environment-setup.js +84 -0
  11. package/bin/update/update-checker.js +126 -0
  12. package/bin/vibecodingmachine-new.js +50 -0
  13. package/bin/vibecodingmachine.js +29 -663
  14. package/package.json +8 -2
  15. package/src/commands/agents/add.js +277 -0
  16. package/src/commands/agents/check.js +380 -0
  17. package/src/commands/agents/list.js +471 -0
  18. package/src/commands/agents/remove.js +351 -0
  19. package/src/commands/analyze-file-sizes.js +428 -0
  20. package/src/commands/auto-direct/code-processor.js +282 -0
  21. package/src/commands/auto-direct/file-scanner.js +266 -0
  22. package/src/commands/auto-direct/provider-config.js +178 -0
  23. package/src/commands/auto-direct/provider-manager.js +219 -0
  24. package/src/commands/auto-direct/requirement-manager.js +172 -0
  25. package/src/commands/auto-direct/status-display.js +91 -0
  26. package/src/commands/auto-direct/utils.js +106 -0
  27. package/src/commands/auto-direct.js +875 -488
  28. package/src/commands/auto-execution.js +342 -0
  29. package/src/commands/auto-provider-management.js +102 -0
  30. package/src/commands/auto-requirement-management.js +161 -0
  31. package/src/commands/auto-status-helpers.js +141 -0
  32. package/src/commands/auto.js +105 -5155
  33. package/src/commands/check-compliance.js +536 -0
  34. package/src/commands/continuous-scan.js +119 -0
  35. package/src/commands/ide.js +16 -4
  36. package/src/commands/refactor-file.js +486 -0
  37. package/src/commands/requirements.js +301 -2
  38. package/src/commands/timeout.js +290 -0
  39. package/src/trui/TruiInterface.js +108 -0
  40. package/src/trui/agents/AgentInterface.js +580 -0
  41. package/src/utils/antigravity-installer.js +60 -6
  42. package/src/utils/clarification-actions.js +290 -0
  43. package/src/utils/config.js +123 -2
  44. package/src/utils/first-run.js +5 -5
  45. package/src/utils/ide-handlers.js +212 -0
  46. package/src/utils/interactive/clarification-actions.js +348 -0
  47. package/src/utils/interactive/core-ui.js +265 -0
  48. package/src/utils/interactive/file-backup.js +237 -0
  49. package/src/utils/interactive/file-import-export.js +305 -0
  50. package/src/utils/interactive/file-operations.js +49 -0
  51. package/src/utils/interactive/file-validation.js +276 -0
  52. package/src/utils/interactive/interactive-prompts.js +480 -0
  53. package/src/utils/interactive/requirement-actions.js +127 -0
  54. package/src/utils/interactive/requirement-crud.js +356 -0
  55. package/src/utils/interactive/requirements-navigation.js +286 -0
  56. package/src/utils/interactive.js +390 -3459
  57. package/src/utils/provider-checker/agent-checker.js +250 -0
  58. package/src/utils/provider-checker/agent-runner.js +450 -0
  59. package/src/utils/provider-checker/cli-installer.js +123 -0
  60. package/src/utils/provider-checker/cli-utils.js +15 -0
  61. package/src/utils/provider-checker/format-utils.js +32 -0
  62. package/src/utils/provider-checker/ide-manager.js +72 -0
  63. package/src/utils/provider-checker/ide-utils.js +71 -0
  64. package/src/utils/provider-checker/node-detector.js +56 -0
  65. package/src/utils/provider-checker/node-utils.js +61 -0
  66. package/src/utils/provider-checker/process-spawn.js +22 -0
  67. package/src/utils/provider-checker/process-utils.js +37 -0
  68. package/src/utils/provider-checker/provider-validator.js +160 -0
  69. package/src/utils/provider-checker/quota-checker.js +54 -0
  70. package/src/utils/provider-checker/quota-detector.js +44 -0
  71. package/src/utils/provider-checker/requirements-manager.js +94 -0
  72. package/src/utils/provider-checker/test-requirements.js +95 -0
  73. package/src/utils/provider-checker/time-formatter.js +18 -0
  74. package/src/utils/provider-checker-new.js +14 -0
  75. package/src/utils/provider-checker.js +12 -407
  76. package/src/utils/provider-checkers/ide-manager.js +128 -0
  77. package/src/utils/provider-checkers/node-executable-finder.js +51 -0
  78. package/src/utils/provider-checkers/provider-checker-core.js +172 -0
  79. package/src/utils/provider-checkers/provider-checker-main.js +107 -0
  80. package/src/utils/provider-manager.js +60 -4
  81. package/src/utils/provider-registry.js +26 -3
  82. package/src/utils/provider-utils.js +173 -0
  83. package/src/utils/quota-detectors.js +212 -0
  84. package/src/utils/requirement-action-handlers.js +288 -0
  85. package/src/utils/requirement-actions/clarification-actions.js +229 -0
  86. package/src/utils/requirement-actions/confirmation-prompts.js +93 -0
  87. package/src/utils/requirement-actions/file-operations.js +92 -0
  88. package/src/utils/requirement-actions/helpers.js +40 -0
  89. package/src/utils/requirement-actions/requirement-operations.js +335 -0
  90. package/src/utils/requirement-actions.js +46 -856
  91. package/src/utils/requirement-file-operations.js +259 -0
  92. package/src/utils/requirement-helpers.js +128 -0
  93. package/src/utils/requirement-management.js +279 -0
  94. package/src/utils/requirement-navigation.js +146 -0
  95. package/src/utils/requirement-organization.js +271 -0
  96. package/src/utils/simple-trui.js +75 -1
  97. package/src/utils/trui-navigation.js +28 -2
  98. package/src/utils/trui-req-tree.js +196 -11
  99. package/src/utils/trui-specifications.js +31 -1
  100. package/src/utils/interactive-backup.js +0 -5664
  101. package/src/utils/trui-provider-manager.js +0 -182
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Agent Checker Module
3
+ *
4
+ * Contains main agent checking functionality.
5
+ */
6
+
7
+ const path = require('path');
8
+ const fs = require('fs');
9
+ const { NODE_EXECUTABLE } = require('./node-utils');
10
+ const { isCLIAvailable, installCLI, CLI_AUTO_INSTALL } = require('./cli-utils');
11
+ const { IDE_INFO, isIDERunning, openIDEApp } = require('./ide-utils');
12
+ const {
13
+ getResultFilePath,
14
+ addTestRequirement,
15
+ removeTestRequirement
16
+ } = require('./test-requirements');
17
+ const { spawnAndWait } = require('./process-utils');
18
+ const { checkAntigravityQuota } = require('./quota-checker');
19
+
20
+ const CLI_ENTRY_POINT = path.resolve(path.join(__dirname, '../../../bin/vibecodingmachine.js'));
21
+
22
+ // Timeout for direct LLM round-trips via auto:direct (ms)
23
+ const DIRECT_TIMEOUT_MS = 60000;
24
+ // Timeout for IDE automation round-trips via auto:start (ms)
25
+ const IDE_TIMEOUT_MS = 90000;
26
+
27
+ /**
28
+ * For IDE providers: ensure the IDE is open first, launching it if needed.
29
+ * Returns { status, message, checkedAt, rateLimited?, rateLimitMessage?, rateLimitResume? }.
30
+ */
31
+ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, signal = null, onProgress = null) {
32
+ const checkedAt = new Date().toISOString();
33
+
34
+ // Ensure temp dir exists
35
+ const tempDir = path.dirname(resultFile);
36
+ if (!fs.existsSync(tempDir)) {
37
+ fs.mkdirSync(tempDir, { recursive: true });
38
+ }
39
+
40
+ // Clean up any previous result
41
+ if (fs.existsSync(resultFile)) {
42
+ fs.unlinkSync(resultFile);
43
+ }
44
+
45
+ // For IDE providers, ensure IDE is running
46
+ if (def.type === 'ide' && IDE_INFO[providerId]) {
47
+ const ideInfo = IDE_INFO[providerId];
48
+ const isRunning = isIDERunning(ideInfo.process);
49
+
50
+ if (!isRunning) {
51
+ if (onProgress) onProgress({ type: 'ide_launch', message: `Launching ${ideInfo.app}...` });
52
+
53
+ const launched = await openIDEApp(ideInfo.app, repoPath);
54
+ if (!launched) {
55
+ return {
56
+ status: 'error',
57
+ message: `Failed to launch ${ideInfo.app}`,
58
+ checkedAt
59
+ };
60
+ }
61
+
62
+ // Wait a bit for IDE to fully start
63
+ await new Promise(resolve => setTimeout(resolve, 3000));
64
+ }
65
+ }
66
+
67
+ // Check for rate limits on specific providers
68
+ if (providerId === 'antigravity') {
69
+ const quotaCheck = await checkAntigravityQuota();
70
+ if (quotaCheck.isRateLimited) {
71
+ return {
72
+ status: 'rate_limited',
73
+ message: quotaCheck.message,
74
+ checkedAt,
75
+ rateLimited: true,
76
+ rateLimitMessage: quotaCheck.message,
77
+ rateLimitResume: quotaCheck.resumeAt
78
+ };
79
+ }
80
+ }
81
+
82
+ // Prepare command arguments
83
+ let args = [];
84
+ let cmd;
85
+
86
+ if (def.type === 'cli') {
87
+ // CLI provider
88
+ const cliInfo = CLI_AUTO_INSTALL[providerId];
89
+ if (!cliInfo) {
90
+ return {
91
+ status: 'error',
92
+ message: `Unknown CLI provider: ${providerId}`,
93
+ checkedAt
94
+ };
95
+ }
96
+
97
+ // Ensure CLI is available
98
+ if (!isCLIAvailable(cliInfo.cmd, providerId)) {
99
+ if (onProgress) onProgress({ type: 'cli_install', message: `Installing ${providerId}...` });
100
+
101
+ const installResult = await installCLI(providerId);
102
+ if (!installResult.installed) {
103
+ return {
104
+ status: 'error',
105
+ message: `Failed to install ${providerId}: ${installResult.note}`,
106
+ checkedAt
107
+ };
108
+ }
109
+ }
110
+
111
+ cmd = cliInfo.cmd;
112
+ args = ['agent', 'test', '--repo', repoPath, '--result', resultFile];
113
+ } else if (def.type === 'ide') {
114
+ // IDE provider - use our CLI to communicate with IDE
115
+ cmd = NODE_EXECUTABLE;
116
+ args = [CLI_ENTRY_POINT, 'agent', 'test', '--repo', repoPath, '--result', resultFile, '--ide', providerId];
117
+ } else {
118
+ return {
119
+ status: 'error',
120
+ message: `Unknown provider type: ${def.type}`,
121
+ checkedAt
122
+ };
123
+ }
124
+
125
+ // Run the agent test
126
+ if (onProgress) onProgress({ type: 'test_start', message: 'Running agent connectivity test...' });
127
+
128
+ const result = await spawnAndWait(cmd, args, {
129
+ signal,
130
+ timeout: timeoutMs,
131
+ cwd: repoPath
132
+ });
133
+
134
+ // Check if result file was created
135
+ let testResult = null;
136
+ if (fs.existsSync(resultFile)) {
137
+ try {
138
+ testResult = fs.readFileSync(resultFile, 'utf8');
139
+ } catch (_) { }
140
+ }
141
+
142
+ if (result.code !== 0 || !testResult) {
143
+ return {
144
+ status: 'error',
145
+ message: `Agent test failed (exit code: ${result.code})`,
146
+ checkedAt,
147
+ output: result.output
148
+ };
149
+ }
150
+
151
+ // Parse the test result
152
+ try {
153
+ const parsed = JSON.parse(testResult);
154
+ return {
155
+ status: 'success',
156
+ message: 'Agent test completed successfully',
157
+ checkedAt,
158
+ result: parsed
159
+ };
160
+ } catch (_) {
161
+ return {
162
+ status: 'success',
163
+ message: 'Agent test completed (raw output)',
164
+ checkedAt,
165
+ result: testResult
166
+ };
167
+ }
168
+ }
169
+
170
+ /**
171
+ * Check a single provider.
172
+ * Returns { status, message, checkedAt, requirementLeftPending }.
173
+ */
174
+ async function checkProvider(providerId, config = {}, repoPath, onProgress = null, signal = null) {
175
+ const { getProviderDefinition } = require('../provider-registry');
176
+ console.log(`[AGENT CHECK] Checking provider: ${providerId} in repo: ${repoPath}`);
177
+
178
+ const def = getProviderDefinition(providerId);
179
+ if (!def) {
180
+ return {
181
+ status: 'error',
182
+ message: `Unknown provider: ${providerId}`,
183
+ checkedAt: new Date().toISOString(),
184
+ requirementLeftPending: false
185
+ };
186
+ }
187
+
188
+ const reqPath = path.join(repoPath, 'REQUIREMENTS.md');
189
+ const resultFile = getResultFilePath(repoPath);
190
+
191
+ // Add test requirement
192
+ addTestRequirement(reqPath, resultFile);
193
+
194
+ try {
195
+ // Choose timeout based on provider type
196
+ const timeoutMs = def.type === 'cli' ? DIRECT_TIMEOUT_MS : IDE_TIMEOUT_MS;
197
+
198
+ const result = await runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, signal, onProgress);
199
+
200
+ // Remove test requirement (clean up)
201
+ removeTestRequirement(reqPath);
202
+
203
+ // Clean up result file
204
+ if (fs.existsSync(resultFile)) {
205
+ fs.unlinkSync(resultFile);
206
+ }
207
+
208
+ return {
209
+ ...result,
210
+ requirementLeftPending: false
211
+ };
212
+ } catch (error) {
213
+ // Ensure cleanup on error
214
+ removeTestRequirement(reqPath);
215
+ if (fs.existsSync(resultFile)) {
216
+ fs.unlinkSync(resultFile);
217
+ }
218
+
219
+ return {
220
+ status: 'error',
221
+ message: `Check failed: ${error.message}`,
222
+ checkedAt: new Date().toISOString(),
223
+ requirementLeftPending: false
224
+ };
225
+ }
226
+ }
227
+
228
+ /**
229
+ * Check multiple providers in sequence.
230
+ * Returns { [providerId]: checkResult }.
231
+ */
232
+ async function checkAllProviders(providerIds, config = {}, repoPath, onProgress = null, signal = null) {
233
+ const results = {};
234
+
235
+ for (const id of providerIds) {
236
+ if (signal && signal.aborted) break;
237
+
238
+ results[id] = await checkProvider(id, config, repoPath, onProgress, signal);
239
+ }
240
+
241
+ return results;
242
+ }
243
+
244
+ module.exports = {
245
+ runAgentCheck,
246
+ checkProvider,
247
+ checkAllProviders,
248
+ DIRECT_TIMEOUT_MS,
249
+ IDE_TIMEOUT_MS
250
+ };
@@ -0,0 +1,450 @@
1
+ 'use strict';
2
+
3
+ const { spawn } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const chokidar = require('chokidar');
7
+
8
+ const { NODE_EXECUTABLE } = require('./node-detector');
9
+ const { IDE_INFO, isIDERunning, openIDEApp } = require('./ide-manager');
10
+ const { getResultFilePath } = require('./requirements-manager');
11
+
12
+ // Timeout for direct LLM round-trips via auto:direct (ms)
13
+ const DIRECT_TIMEOUT_MS = 60000;
14
+ // Timeout for IDE automation round-trips via auto:start (ms)
15
+ const IDE_TIMEOUT_MS = 90000;
16
+
17
+ const CLI_ENTRY_POINT = path.resolve(path.join(__dirname, '../../../bin/vibecodingmachine.js'));
18
+
19
+ /**
20
+ * Run an agent for 1 iteration and watch for the result file to be written.
21
+ * For IDE providers: ensure the IDE is open first, launching it if needed.
22
+ * Returns { status, message, checkedAt, rateLimited?, rateLimitMessage?, rateLimitResume? }.
23
+ */
24
+ async function runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, signal = null, onProgress = null) {
25
+ const checkedAt = new Date().toISOString();
26
+
27
+ // Ensure temp dir exists
28
+ fs.mkdirSync(path.dirname(resultFile), { recursive: true });
29
+ // Remove stale result file so we detect a fresh write
30
+ try { fs.unlinkSync(resultFile); } catch { }
31
+
32
+ // For IDE providers: verify the IDE is running/installed, install if needed
33
+ let ideLaunchNote = '';
34
+ if (def.type === 'ide') {
35
+ const info = IDE_INFO[providerId] || IDE_INFO[def.ide] || null;
36
+ if (info && info.process) {
37
+ if (!isIDERunning(info.process)) {
38
+ // macOS: launch the app if not running
39
+ if (process.platform === 'darwin' && info.app) {
40
+ const launchSuccess = await openIDEApp(info.app, repoPath);
41
+ if (launchSuccess) {
42
+ ideLaunchNote = ` (VCM launched ${info.app})`;
43
+ } else {
44
+ // Failed to launch on macOS - check if installed
45
+ const { IDEInstaller } = require('../../../electron-app/src/main/ide-installer');
46
+ const installer = new IDEInstaller();
47
+ const ideKey = def.ide || providerId;
48
+ const checkResult = await installer.checkIDEInstallation(ideKey);
49
+ if (!checkResult.installed) {
50
+ return {
51
+ status: 'error',
52
+ message: `${info.app} is not installed. Please download from ${IDEInstaller.IDE_CONFIG[ideKey]?.downloadBrowserUrl || 'its official website'}`,
53
+ checkedAt
54
+ };
55
+ }
56
+ }
57
+ }
58
+ // Windows: check if installed, install if possible, launch if installed
59
+ else if (process.platform === 'win32') {
60
+ const { IDEInstaller } = require('../../../electron-app/src/main/ide-installer');
61
+ const installer = new IDEInstaller();
62
+ const ideKey = def.ide || providerId;
63
+ const ideConfig = IDEInstaller.IDE_CONFIG[ideKey];
64
+
65
+ // Check if IDE is installed
66
+ let checkResult = await installer.checkIDEInstallation(ideKey);
67
+
68
+ if (!checkResult.installed) {
69
+ // IDE is not installed - try to install if we have a download URL
70
+ const downloadUrl = ideConfig?.downloadUrl?.[process.platform];
71
+
72
+ if (downloadUrl) {
73
+ // Has a direct download URL - auto-install
74
+ console.log(`[AGENT CHECK] ${info.app || ideKey} not installed, installing...`);
75
+ if (onProgress) onProgress(providerId, 'installing');
76
+
77
+ try {
78
+ const installResult = await installer.installIDE(ideKey, (progress) => {
79
+ console.log(`[AGENT CHECK] Installation progress for ${ideKey}: ${progress.progress}% - ${progress.message}`);
80
+ });
81
+
82
+ if (!installResult || !installResult.success) {
83
+ console.error(`[AGENT CHECK] Installation failed for ${info.app || ideKey}`);
84
+ return {
85
+ status: 'error',
86
+ message: `Failed to install ${info.app || ideKey}: ${installResult?.error || 'Installation failed'}. Please install manually and try again.`,
87
+ checkedAt
88
+ };
89
+ }
90
+
91
+ console.log(`[AGENT CHECK] ${info.app || ideKey} installed successfully`);
92
+ ideLaunchNote = ` (VCM installed ${info.app || ideKey})`;
93
+ // Re-check that installation succeeded
94
+ await new Promise(r => setTimeout(r, 3000));
95
+ checkResult = await installer.checkIDEInstallation(ideKey);
96
+ } catch (installError) {
97
+ console.error(`[AGENT CHECK] Installation error for ${info.app || ideKey}:`, installError.message);
98
+ return {
99
+ status: 'error',
100
+ message: `Installation failed for ${info.app || ideKey}: ${installError.message}. Please install manually and try again.`,
101
+ checkedAt
102
+ };
103
+ }
104
+ } else {
105
+ // No direct download URL - provide browser download link
106
+ const browserUrl = ideConfig?.downloadBrowserUrl || `${ideKey}'s official website`;
107
+ return {
108
+ status: 'error',
109
+ message: `${info.app || ideKey} is not installed. Please download from: ${browserUrl}`,
110
+ checkedAt
111
+ };
112
+ }
113
+ }
114
+
115
+ // IDE is now installed (either was already or we just installed it) - launch it
116
+ if (checkResult.installed && checkResult.path) {
117
+ try {
118
+ const exePath = checkResult.path;
119
+ const repoArg = repoPath ? ` "${repoPath}"` : '';
120
+ const { execSync } = require('child_process');
121
+ execSync(`start "" "${exePath}"${repoArg}`, {
122
+ stdio: 'ignore',
123
+ windowsHide: true,
124
+ timeout: 10000,
125
+ shell: true
126
+ });
127
+ ideLaunchNote = ideLaunchNote || ` (VCM launched ${info.app})`;
128
+ // Give IDE time to start
129
+ await new Promise(r => setTimeout(r, 5000));
130
+ } catch (launchError) {
131
+ // Launch failed but IDE is installed - continue anyway
132
+ console.warn(`[AGENT CHECK] Could not launch ${info.app}, continuing...`);
133
+ }
134
+ }
135
+ }
136
+ }
137
+ }
138
+ }
139
+
140
+ return new Promise((resolve) => {
141
+ let resolved = false;
142
+ let child = null;
143
+ let output = '';
144
+
145
+ async function done(result) {
146
+ if (resolved) return;
147
+ resolved = true;
148
+ try { watcher.close(); } catch { }
149
+ clearTimeout(timeout);
150
+ clearInterval(cancelCheckInterval);
151
+ try { if (child) child.kill(); } catch { }
152
+ resolve(result);
153
+ }
154
+
155
+ function checkResult() {
156
+ if (!resolved && fs.existsSync(resultFile)) {
157
+ try {
158
+ const content = fs.readFileSync(resultFile, 'utf8');
159
+ if (content.includes('VCM_CHECK_OK')) {
160
+ done({ status: 'success', message: 'End-to-end check passed', checkedAt });
161
+ }
162
+ } catch { }
163
+ }
164
+ }
165
+
166
+ const watcher = chokidar.watch(resultFile, { persistent: true, ignoreInitial: false, disableGlobbing: true });
167
+ watcher.on('add', checkResult);
168
+ watcher.on('change', checkResult);
169
+
170
+ const timeout = setTimeout(() => {
171
+ // Diagnose: is the IDE process still running?
172
+ let diagnosis = '';
173
+ if (def.type === 'ide') {
174
+ const info = IDE_INFO[providerId] || IDE_INFO[def.ide] || null;
175
+ if (info && info.process) {
176
+ diagnosis = isIDERunning(info.process)
177
+ ? ` — ${info.app || info.process} is running but did not respond`
178
+ : ` — ${info.app || info.process} is not running`;
179
+ }
180
+ }
181
+ console.warn(`[AGENT CHECK] Timeout for ${providerId} after ${timeoutMs / 1000}s${diagnosis}`);
182
+
183
+ const timeoutResult = { status: 'error', message: `No response within ${timeoutMs / 1000}s${ideLaunchNote}${diagnosis}`, checkedAt };
184
+
185
+ // For IDE timeout, also check for quota limit (in output + UI)
186
+ if (def.type === 'ide') {
187
+ checkIDEQuotaLimitAndDone(providerId, timeoutResult).catch(err => {
188
+ console.error('[AGENT CHECK] Error in quota check:', err);
189
+ done(timeoutResult);
190
+ });
191
+ } else {
192
+ done(timeoutResult);
193
+ }
194
+ }, timeoutMs);
195
+
196
+ // Periodically check for cancellation signal
197
+ const cancelCheckInterval = setInterval(() => {
198
+ if (signal && signal.cancelled) {
199
+ done({ status: 'error', message: 'Check cancelled by user', checkedAt });
200
+ }
201
+ }, 1000); // Check every second
202
+
203
+ let args;
204
+ if (def.type === 'ide') {
205
+ args = [CLI_ENTRY_POINT, 'auto:start', '--ide', def.ide || providerId, '--max-chats', '1'];
206
+ if (def.defaultModel) args.push('--ide-model', String(def.defaultModel));
207
+ if (def.extension) args.push('--extension', String(def.extension));
208
+ } else {
209
+ // Direct LLM: use auto:direct --provider to force this specific provider
210
+ args = [CLI_ENTRY_POINT, 'auto:direct', '--provider', providerId, '--max-chats', '1'];
211
+ }
212
+
213
+ // Verify CLI entry point exists and is readable
214
+ if (!fs.existsSync(CLI_ENTRY_POINT)) {
215
+ console.error(`[AGENT CHECK] CLI entry point not found: ${CLI_ENTRY_POINT}`);
216
+ done({ status: 'error', message: `CLI entry point not found: ${CLI_ENTRY_POINT}`, checkedAt });
217
+ return;
218
+ }
219
+
220
+ try {
221
+ fs.accessSync(CLI_ENTRY_POINT, fs.constants.R_OK);
222
+ } catch (err) {
223
+ console.error(`[AGENT CHECK] CLI entry point not readable: ${CLI_ENTRY_POINT} - ${err.message}`);
224
+ done({ status: 'error', message: `CLI entry point not readable: ${err.message}`, checkedAt });
225
+ return;
226
+ }
227
+
228
+ // Verify repo path exists and is accessible
229
+ if (!fs.existsSync(repoPath)) {
230
+ console.error(`[AGENT CHECK] Repository path not found: ${repoPath}`);
231
+ done({ status: 'error', message: `Repository path not found: ${repoPath}`, checkedAt });
232
+ return;
233
+ }
234
+
235
+ try {
236
+ fs.accessSync(repoPath, fs.constants.R_OK | fs.constants.W_OK);
237
+ } catch (err) {
238
+ console.error(`[AGENT CHECK] Repository path not accessible: ${repoPath} - ${err.message}`);
239
+ done({ status: 'error', message: `Repository path not accessible: ${err.message}`, checkedAt });
240
+ return;
241
+ }
242
+
243
+ // Log the command being executed
244
+ console.log(`[AGENT CHECK] Starting check for ${providerId}`);
245
+ console.log(`[AGENT CHECK] Node Executable: ${NODE_EXECUTABLE}`);
246
+ console.log(`[AGENT CHECK] Args: ${args.join(' ')}`);
247
+ console.log(`[AGENT CHECK] CWD: ${repoPath}`);
248
+ console.log(`[AGENT CHECK] Result file: ${resultFile}`);
249
+
250
+ // Prepare environment - inherit all process.env and add NODE_PATH if needed
251
+ const spawnEnv = {
252
+ ...process.env,
253
+ // Ensure NODE_PATH includes the monorepo node_modules if it exists
254
+ NODE_PATH: [
255
+ path.join(__dirname, '../../node_modules'),
256
+ path.join(__dirname, '../../../node_modules'),
257
+ process.env.NODE_PATH || ''
258
+ ].filter(Boolean).join(path.delimiter)
259
+ };
260
+
261
+ child = spawn(NODE_EXECUTABLE, args, {
262
+ cwd: repoPath,
263
+ env: spawnEnv,
264
+ stdio: ['ignore', 'pipe', 'pipe'],
265
+ detached: false
266
+ });
267
+
268
+ console.log(`[AGENT CHECK] Child process spawned for ${providerId}, PID: ${child.pid}`);
269
+
270
+ child.stdout.on('data', d => {
271
+ const data = d.toString();
272
+ output += data;
273
+ console.log(`[AGENT CHECK ${providerId}] STDOUT: ${data.slice(0, 200)}`);
274
+ });
275
+ child.stderr.on('data', d => {
276
+ const data = d.toString();
277
+ output += data;
278
+ console.log(`[AGENT CHECK ${providerId}] STDERR: ${data.slice(0, 200)}`);
279
+ });
280
+
281
+ child.on('error', (err) => {
282
+ console.error(`[AGENT CHECK] Failed to start ${providerId}: ${err.message}`);
283
+ done({ status: 'error', message: `Failed to start automation: ${err.message}`, checkedAt });
284
+ });
285
+
286
+ child.on('exit', (code) => {
287
+ if (resolved) return;
288
+ console.log(`[AGENT CHECK] ${providerId} process exited with code ${code}`);
289
+ console.log(`[AGENT CHECK] ${providerId} process output: ${output.slice(-500)}`);
290
+ // Check one more time after process exits
291
+ checkResult();
292
+ if (!resolved) {
293
+ const tail = output.slice(-300).trim().replace(/\n/g, ' ');
294
+ let codeInfo = '';
295
+ if (code === 4294967295 || code === -1) {
296
+ codeInfo = ` (process may not have started or crashed immediately)`;
297
+ if (def.type === 'ide') {
298
+ const ideInfo = IDE_INFO[providerId] || IDE_INFO[def.ide];
299
+ if (ideInfo && ideInfo.app) {
300
+ codeInfo += ` — Make sure ${ideInfo.app} is installed and running`;
301
+ }
302
+ }
303
+ }
304
+ console.error(`[AGENT CHECK] ${providerId} error: Automation exited (code ${code})${codeInfo}${tail ? ': ' + tail : ''}`);
305
+
306
+ const errorResult = { status: 'error', message: `Automation exited (code ${code})${codeInfo}${tail ? ': ' + tail : ''}`, checkedAt };
307
+
308
+ // For IDE providers, check for quota limit (UI + process output)
309
+ if (def.type === 'ide') {
310
+ checkIDEQuotaLimitAndDone(providerId, errorResult).catch(err => {
311
+ console.error('[AGENT CHECK] Error in quota check:', err);
312
+ done(errorResult);
313
+ });
314
+ } else {
315
+ done(errorResult);
316
+ }
317
+ }
318
+ });
319
+
320
+ // Helper function to check IDE quota limits and call done with enriched result
321
+ async function checkIDEQuotaLimitAndDone(providerId, errorResult) {
322
+ const debugLog = (msg) => {
323
+ const timestamp = new Date().toISOString();
324
+ const logLine = `[${timestamp}] ${msg}\n`;
325
+ try {
326
+ fs.appendFileSync(`/tmp/vibe-${providerId}-quota-debug.log`, logLine);
327
+ } catch (_) { }
328
+ console.log(`[AGENT CHECK] ${msg}`);
329
+ };
330
+
331
+ debugLog(`Starting checkIDEQuotaLimitAndDone for ${providerId}`);
332
+ debugLog('errorResult.message: ' + JSON.stringify(errorResult.message).substring(0, 200));
333
+
334
+ try {
335
+ debugLog(`Checking for ${providerId} quota limit...`);
336
+
337
+ // Check process output first for quota error keywords
338
+ const lowerOutput = output.toLowerCase();
339
+ const lowerErrorMsg = errorResult.message.toLowerCase();
340
+ debugLog('Checking process output length: ' + output.length);
341
+ debugLog('Process output sample: ' + output.substring(0, 300));
342
+
343
+ // Check both output and error message for quota keywords
344
+ const quotaKeywords = ['quota', 'rate limit', 'resource_exhausted', 'usage limit', 'model quota', 'limit exceeded', 'spending cap', 'usage cap', 'you\'ve reached your monthly chat messages quota', 'upgrade to copilot pro', 'wait for your allowance to renew'];
345
+ const hasQuotaKeyword = quotaKeywords.some(kw => lowerOutput.includes(kw) || lowerErrorMsg.includes(kw));
346
+
347
+ if (hasQuotaKeyword) {
348
+ debugLog(`🚨 Quota keywords found in process output or message for ${providerId}`);
349
+ errorResult.rateLimited = true;
350
+ errorResult.rateLimitMessage = output || errorResult.message;
351
+ // Set provider-specific rate limit flags for compatibility
352
+ switch (providerId) {
353
+ case 'antigravity':
354
+ errorResult.antigravityRateLimited = true;
355
+ break;
356
+ case 'windsurf':
357
+ errorResult.windsurfRateLimited = true;
358
+ break;
359
+ case 'cursor':
360
+ errorResult.cursorRateLimited = true;
361
+ break;
362
+ case 'github-copilot':
363
+ errorResult.githubCopilotRateLimited = true;
364
+ break;
365
+ }
366
+ debugLog('Set rateLimited to true, calling done()');
367
+ done(errorResult);
368
+ return;
369
+ }
370
+
371
+ debugLog(`No quota keywords in process output or message, checking AppleScript UI as fallback for ${providerId}`);
372
+
373
+ // Then check AppleScript UI scraping as fallback for IDEs that support it
374
+ if (process.platform === 'darwin') {
375
+ try {
376
+ const { AppleScriptManager } = require('vibecodingmachine-core');
377
+ const appleScriptManager = new AppleScriptManager();
378
+ let quotaCheck = null;
379
+
380
+ // Use specific quota detection methods for each IDE
381
+ switch (providerId) {
382
+ case 'antigravity':
383
+ quotaCheck = await appleScriptManager.checkAntigravityQuotaLimit();
384
+ break;
385
+ case 'windsurf':
386
+ quotaCheck = await appleScriptManager.checkWindsurfQuotaLimit();
387
+ break;
388
+ case 'cursor':
389
+ quotaCheck = await appleScriptManager.checkCursorQuotaLimit();
390
+ break;
391
+ case 'github-copilot':
392
+ // GitHub Copilot uses the same detection as Cursor (both are VS Code extensions)
393
+ quotaCheck = await appleScriptManager.checkCursorQuotaLimit();
394
+ break;
395
+ default:
396
+ debugLog(`No specific quota detection method available for ${providerId}`);
397
+ break;
398
+ }
399
+
400
+ debugLog(`${providerId} quota check result: ` + JSON.stringify(quotaCheck));
401
+
402
+ if (quotaCheck && (quotaCheck.isRateLimited || quotaCheck.hasQuotaWarning)) {
403
+ debugLog(`🚨 ${providerId} quota limit detected via AppleScript`);
404
+ errorResult.rateLimited = true;
405
+ errorResult.rateLimitMessage = quotaCheck.message || quotaCheck.matchedText || `${providerId} quota limit detected`;
406
+ if (quotaCheck.resumeAt) {
407
+ errorResult.rateLimitResume = quotaCheck.resumeAt;
408
+ }
409
+ // Set provider-specific rate limit flags for compatibility
410
+ switch (providerId) {
411
+ case 'antigravity':
412
+ errorResult.antigravityRateLimited = true;
413
+ break;
414
+ case 'windsurf':
415
+ errorResult.windsurfRateLimited = true;
416
+ break;
417
+ case 'cursor':
418
+ errorResult.cursorRateLimited = true;
419
+ break;
420
+ case 'github-copilot':
421
+ errorResult.githubCopilotRateLimited = true;
422
+ break;
423
+ }
424
+ debugLog('Enriched error result with quota limit');
425
+ } else {
426
+ debugLog(`No rate limit detected for ${providerId}`);
427
+ }
428
+ } catch (appleScriptError) {
429
+ debugLog(`AppleScript quota detection failed for ${providerId}: ${appleScriptError.message}`);
430
+ }
431
+ } else {
432
+ debugLog(`Skipping AppleScript quota detection for ${providerId} on non-macOS platform`);
433
+ }
434
+ } catch (err) {
435
+ debugLog(`Error checking ${providerId} quota: ${err.message}`);
436
+ } finally {
437
+ debugLog('Calling done() with final errorResult');
438
+ debugLog('Final errorResult.rateLimited: ' + errorResult.rateLimited);
439
+ debugLog('Final errorResult.rateLimitMessage: ' + (errorResult.rateLimitMessage ? errorResult.rateLimitMessage.substring(0, 100) : 'none'));
440
+ done(errorResult);
441
+ }
442
+ }
443
+ });
444
+ }
445
+
446
+ module.exports = {
447
+ runAgentCheck,
448
+ DIRECT_TIMEOUT_MS,
449
+ IDE_TIMEOUT_MS
450
+ };