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.
- package/bin/auth/auth-compliance.js +126 -0
- package/bin/cli-program.js +104 -0
- package/bin/cli-setup.js +52 -0
- package/bin/commands/agent-commands.js +310 -0
- package/bin/commands/auto-commands.js +70 -0
- package/bin/commands/command-aliases.js +118 -0
- package/bin/commands/repo-commands.js +39 -0
- package/bin/commands/rui-commands.js +152 -0
- package/bin/config/cli-config.js +394 -0
- package/bin/init/environment-setup.js +84 -0
- package/bin/update/update-checker.js +126 -0
- package/bin/vibecodingmachine-new.js +50 -0
- package/bin/vibecodingmachine.js +29 -663
- package/package.json +8 -2
- package/src/commands/agents/add.js +277 -0
- package/src/commands/agents/check.js +380 -0
- package/src/commands/agents/list.js +471 -0
- package/src/commands/agents/remove.js +351 -0
- package/src/commands/analyze-file-sizes.js +428 -0
- package/src/commands/auto-direct/code-processor.js +282 -0
- package/src/commands/auto-direct/file-scanner.js +266 -0
- package/src/commands/auto-direct/provider-config.js +178 -0
- package/src/commands/auto-direct/provider-manager.js +219 -0
- package/src/commands/auto-direct/requirement-manager.js +172 -0
- package/src/commands/auto-direct/status-display.js +91 -0
- package/src/commands/auto-direct/utils.js +106 -0
- package/src/commands/auto-direct.js +875 -488
- package/src/commands/auto-execution.js +342 -0
- package/src/commands/auto-provider-management.js +102 -0
- package/src/commands/auto-requirement-management.js +161 -0
- package/src/commands/auto-status-helpers.js +141 -0
- package/src/commands/auto.js +105 -5155
- package/src/commands/check-compliance.js +536 -0
- package/src/commands/continuous-scan.js +119 -0
- package/src/commands/ide.js +16 -4
- package/src/commands/refactor-file.js +486 -0
- package/src/commands/requirements.js +301 -2
- package/src/commands/timeout.js +290 -0
- package/src/trui/TruiInterface.js +108 -0
- package/src/trui/agents/AgentInterface.js +580 -0
- package/src/utils/antigravity-installer.js +60 -6
- package/src/utils/clarification-actions.js +290 -0
- package/src/utils/config.js +123 -2
- package/src/utils/first-run.js +5 -5
- package/src/utils/ide-handlers.js +212 -0
- package/src/utils/interactive/clarification-actions.js +348 -0
- package/src/utils/interactive/core-ui.js +265 -0
- package/src/utils/interactive/file-backup.js +237 -0
- package/src/utils/interactive/file-import-export.js +305 -0
- package/src/utils/interactive/file-operations.js +49 -0
- package/src/utils/interactive/file-validation.js +276 -0
- package/src/utils/interactive/interactive-prompts.js +480 -0
- package/src/utils/interactive/requirement-actions.js +127 -0
- package/src/utils/interactive/requirement-crud.js +356 -0
- package/src/utils/interactive/requirements-navigation.js +286 -0
- package/src/utils/interactive.js +390 -3459
- package/src/utils/provider-checker/agent-checker.js +250 -0
- package/src/utils/provider-checker/agent-runner.js +450 -0
- package/src/utils/provider-checker/cli-installer.js +123 -0
- package/src/utils/provider-checker/cli-utils.js +15 -0
- package/src/utils/provider-checker/format-utils.js +32 -0
- package/src/utils/provider-checker/ide-manager.js +72 -0
- package/src/utils/provider-checker/ide-utils.js +71 -0
- package/src/utils/provider-checker/node-detector.js +56 -0
- package/src/utils/provider-checker/node-utils.js +61 -0
- package/src/utils/provider-checker/process-spawn.js +22 -0
- package/src/utils/provider-checker/process-utils.js +37 -0
- package/src/utils/provider-checker/provider-validator.js +160 -0
- package/src/utils/provider-checker/quota-checker.js +54 -0
- package/src/utils/provider-checker/quota-detector.js +44 -0
- package/src/utils/provider-checker/requirements-manager.js +94 -0
- package/src/utils/provider-checker/test-requirements.js +95 -0
- package/src/utils/provider-checker/time-formatter.js +18 -0
- package/src/utils/provider-checker-new.js +14 -0
- package/src/utils/provider-checker.js +12 -407
- package/src/utils/provider-checkers/ide-manager.js +128 -0
- package/src/utils/provider-checkers/node-executable-finder.js +51 -0
- package/src/utils/provider-checkers/provider-checker-core.js +172 -0
- package/src/utils/provider-checkers/provider-checker-main.js +107 -0
- package/src/utils/provider-manager.js +60 -4
- package/src/utils/provider-registry.js +26 -3
- package/src/utils/provider-utils.js +173 -0
- package/src/utils/quota-detectors.js +212 -0
- package/src/utils/requirement-action-handlers.js +288 -0
- package/src/utils/requirement-actions/clarification-actions.js +229 -0
- package/src/utils/requirement-actions/confirmation-prompts.js +93 -0
- package/src/utils/requirement-actions/file-operations.js +92 -0
- package/src/utils/requirement-actions/helpers.js +40 -0
- package/src/utils/requirement-actions/requirement-operations.js +335 -0
- package/src/utils/requirement-actions.js +46 -856
- package/src/utils/requirement-file-operations.js +259 -0
- package/src/utils/requirement-helpers.js +128 -0
- package/src/utils/requirement-management.js +279 -0
- package/src/utils/requirement-navigation.js +146 -0
- package/src/utils/requirement-organization.js +271 -0
- package/src/utils/simple-trui.js +75 -1
- package/src/utils/trui-navigation.js +28 -2
- package/src/utils/trui-req-tree.js +196 -11
- package/src/utils/trui-specifications.js +31 -1
- package/src/utils/interactive-backup.js +0 -5664
- 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
|
+
};
|