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,123 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const os = require('os');
|
|
7
|
+
|
|
8
|
+
// Direct CLI providers that can be auto-installed
|
|
9
|
+
const CLI_AUTO_INSTALL = {
|
|
10
|
+
'cline': { cmd: 'cline', pkg: '@cline/cli', type: 'npm' },
|
|
11
|
+
'opencode': {
|
|
12
|
+
cmd: 'opencode',
|
|
13
|
+
type: 'direct',
|
|
14
|
+
installScript: 'curl -fsSL https://raw.githubusercontent.com/opencode-ai/opencode/refs/heads/main/install | bash',
|
|
15
|
+
// Well-known install locations that may not be in Electron's PATH
|
|
16
|
+
knownPaths: [
|
|
17
|
+
path.join(os.homedir(), '.opencode', 'bin'),
|
|
18
|
+
]
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Build an augmented PATH that includes known install directories for a provider.
|
|
24
|
+
*/
|
|
25
|
+
function getAugmentedPath(providerId) {
|
|
26
|
+
const config = CLI_AUTO_INSTALL[providerId];
|
|
27
|
+
if (!config || !config.knownPaths || config.knownPaths.length === 0) {
|
|
28
|
+
return process.env.PATH || '';
|
|
29
|
+
}
|
|
30
|
+
const existing = process.env.PATH || '';
|
|
31
|
+
const extras = config.knownPaths.filter(p => !existing.split(path.delimiter).includes(p));
|
|
32
|
+
return extras.length > 0 ? extras.join(path.delimiter) + path.delimiter + existing : existing;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Check if a CLI command is available in PATH or well-known install locations.
|
|
37
|
+
* @param {string} cmd - command name
|
|
38
|
+
* @param {string} [providerId] - optional provider id to check knownPaths
|
|
39
|
+
*/
|
|
40
|
+
function isCLIAvailable(cmd, providerId) {
|
|
41
|
+
// 1. Try the augmented PATH (covers Electron's stripped-down env)
|
|
42
|
+
try {
|
|
43
|
+
const { execSync } = require('child_process');
|
|
44
|
+
const augPath = providerId ? getAugmentedPath(providerId) : (process.env.PATH || '');
|
|
45
|
+
const env = { ...process.env, PATH: augPath };
|
|
46
|
+
const command = process.platform === 'win32' ? `where "${cmd}"` : `which "${cmd}"`;
|
|
47
|
+
execSync(command, { stdio: 'ignore', env });
|
|
48
|
+
return true;
|
|
49
|
+
} catch {
|
|
50
|
+
// fall through
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// 2. Check knownPaths directly on disk (handles case where even `which` can't find it)
|
|
54
|
+
if (providerId) {
|
|
55
|
+
const config = CLI_AUTO_INSTALL[providerId];
|
|
56
|
+
if (config && config.knownPaths) {
|
|
57
|
+
for (const dir of config.knownPaths) {
|
|
58
|
+
const fullPath = path.join(dir, cmd);
|
|
59
|
+
try {
|
|
60
|
+
fs.accessSync(fullPath, fs.constants.X_OK);
|
|
61
|
+
return true;
|
|
62
|
+
} catch {
|
|
63
|
+
// continue
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Install a CLI tool and wait for it to complete.
|
|
74
|
+
* Returns { installed: bool, note: string }.
|
|
75
|
+
*/
|
|
76
|
+
async function installCLI(providerId) {
|
|
77
|
+
const config = CLI_AUTO_INSTALL[providerId];
|
|
78
|
+
if (!config) {
|
|
79
|
+
return { installed: false, note: `Unknown provider: ${providerId}` };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Augmented PATH so the install script and post-install verification can find binaries
|
|
83
|
+
const augPath = getAugmentedPath(providerId);
|
|
84
|
+
const spawnEnv = { ...process.env, PATH: augPath };
|
|
85
|
+
|
|
86
|
+
return new Promise((resolve) => {
|
|
87
|
+
if (config.type === 'direct' && config.installScript) {
|
|
88
|
+
// Direct installation using shell script
|
|
89
|
+
const proc = spawn('bash', ['-c', config.installScript], { stdio: ['ignore', 'pipe', 'pipe'], env: spawnEnv });
|
|
90
|
+
let out = '';
|
|
91
|
+
proc.stdout.on('data', d => { out += d.toString(); });
|
|
92
|
+
proc.stderr.on('data', d => { out += d.toString(); });
|
|
93
|
+
proc.on('error', () => resolve({ installed: false, note: `Failed to run install script for ${providerId}` }));
|
|
94
|
+
proc.on('close', (code) => {
|
|
95
|
+
if (code === 0 && isCLIAvailable(config.cmd, providerId)) {
|
|
96
|
+
resolve({ installed: true, note: `Installed ${providerId} via direct script` });
|
|
97
|
+
} else {
|
|
98
|
+
resolve({ installed: false, note: `Install script for ${providerId} exited (${code})` });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
} else {
|
|
102
|
+
// NPM installation
|
|
103
|
+
const proc = spawn('npm', ['install', '-g', config.pkg], { stdio: ['ignore', 'pipe', 'pipe'], env: spawnEnv });
|
|
104
|
+
let out = '';
|
|
105
|
+
proc.stdout.on('data', d => { out += d.toString(); });
|
|
106
|
+
proc.stderr.on('data', d => { out += d.toString(); });
|
|
107
|
+
proc.on('error', () => resolve({ installed: false, note: `Failed to run npm install -g ${config.pkg}` }));
|
|
108
|
+
proc.on('close', (code) => {
|
|
109
|
+
if (code === 0 && isCLIAvailable(config.cmd, providerId)) {
|
|
110
|
+
resolve({ installed: true, note: `Installed ${config.pkg} via npm` });
|
|
111
|
+
} else {
|
|
112
|
+
resolve({ installed: false, note: `npm install -g ${config.pkg} exited (${code})` });
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = {
|
|
120
|
+
CLI_AUTO_INSTALL,
|
|
121
|
+
isCLIAvailable,
|
|
122
|
+
installCLI
|
|
123
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI Utilities Module
|
|
3
|
+
*
|
|
4
|
+
* Contains CLI command availability and installation utilities.
|
|
5
|
+
*
|
|
6
|
+
* NOTE: This module re-exports from cli-installer.js to avoid duplication.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const { CLI_AUTO_INSTALL, isCLIAvailable, installCLI } = require('./cli-installer');
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
CLI_AUTO_INSTALL,
|
|
13
|
+
isCLIAvailable,
|
|
14
|
+
installCLI
|
|
15
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format Utilities Module
|
|
3
|
+
*
|
|
4
|
+
* Contains formatting utilities for dates and other data.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Format a checkedAt ISO timestamp for display.
|
|
9
|
+
* e.g. "April 12, 2025 at 4:23 pm"
|
|
10
|
+
*/
|
|
11
|
+
function formatCheckedAt(checkedAt) {
|
|
12
|
+
if (!checkedAt) return '';
|
|
13
|
+
const d = new Date(checkedAt);
|
|
14
|
+
if (isNaN(d.getTime())) return checkedAt;
|
|
15
|
+
|
|
16
|
+
const months = [
|
|
17
|
+
'January', 'February', 'March', 'April', 'May', 'June',
|
|
18
|
+
'July', 'August', 'September', 'October', 'November', 'December'
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const hours = d.getHours();
|
|
22
|
+
const ampm = hours >= 12 ? 'pm' : 'am';
|
|
23
|
+
const hour12 = hours % 12 || 12;
|
|
24
|
+
const minutes = d.getMinutes().toString().padStart(2, '0');
|
|
25
|
+
const timePart = `${hour12}:${minutes} ${ampm}`;
|
|
26
|
+
|
|
27
|
+
return `${months[d.getMonth()]} ${d.getDate()}, ${d.getFullYear()} at ${timePart}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
formatCheckedAt
|
|
32
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
|
|
5
|
+
// Map provider id → { process: process name for tasklist/pgrep, app: app name for opening }
|
|
6
|
+
const IDE_INFO = {
|
|
7
|
+
windsurf: { process: 'Windsurf', app: 'Windsurf' },
|
|
8
|
+
cursor: { process: 'Cursor', app: 'Cursor' },
|
|
9
|
+
antigravity: { process: 'Antigravity', app: 'Antigravity' },
|
|
10
|
+
kiro: { process: 'Kiro', app: 'Kiro' },
|
|
11
|
+
'github-copilot': { process: 'Code', app: 'Visual Studio Code' },
|
|
12
|
+
'amazon-q': { process: 'Code', app: 'Visual Studio Code' },
|
|
13
|
+
cline: { process: 'Code', app: 'Visual Studio Code' },
|
|
14
|
+
vscode: { process: 'Code', app: 'Visual Studio Code' },
|
|
15
|
+
replit: { process: null, app: null }, // web-based
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns true if the IDE process is currently running.
|
|
20
|
+
*/
|
|
21
|
+
function isIDERunning(processName) {
|
|
22
|
+
if (!processName) return false;
|
|
23
|
+
|
|
24
|
+
if (process.platform === 'darwin') {
|
|
25
|
+
// macOS: use pgrep
|
|
26
|
+
try {
|
|
27
|
+
execSync(`pgrep -x "${processName}"`, { stdio: 'ignore' });
|
|
28
|
+
return true;
|
|
29
|
+
} catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
} else if (process.platform === 'win32') {
|
|
33
|
+
// Windows: use tasklist
|
|
34
|
+
try {
|
|
35
|
+
const result = execSync(`tasklist /FI "IMAGENAME eq ${processName}.exe" /NH`, {
|
|
36
|
+
encoding: 'utf8',
|
|
37
|
+
stdio: 'pipe',
|
|
38
|
+
shell: true,
|
|
39
|
+
windowsHide: true
|
|
40
|
+
});
|
|
41
|
+
return result.toLowerCase().includes(processName.toLowerCase());
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Other platforms: assume not running
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Open the IDE using `open -a <app> <repoPath>` (macOS).
|
|
53
|
+
* Returns true when the launch command was sent.
|
|
54
|
+
*/
|
|
55
|
+
async function openIDEApp(appName, repoPath) {
|
|
56
|
+
if (!appName || process.platform !== 'darwin') return false;
|
|
57
|
+
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 {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
module.exports = {
|
|
69
|
+
IDE_INFO,
|
|
70
|
+
isIDERunning,
|
|
71
|
+
openIDEApp
|
|
72
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IDE Utilities Module
|
|
3
|
+
*
|
|
4
|
+
* Contains IDE process detection and launching utilities.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
|
|
9
|
+
// Map provider id → { process: process name for tasklist/pgrep, app: app name for opening }
|
|
10
|
+
const IDE_INFO = {
|
|
11
|
+
windsurf: { process: 'Windsurf', app: 'Windsurf' },
|
|
12
|
+
cursor: { process: 'Cursor', app: 'Cursor' },
|
|
13
|
+
antigravity: { process: 'Antigravity', app: 'Antigravity' },
|
|
14
|
+
'vscode': { process: 'Code', app: 'Visual Studio Code' },
|
|
15
|
+
'vscode-insiders': { process: 'Code - Insiders', app: 'Visual Studio Code - Insiders' },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns true if the IDE process is currently running.
|
|
20
|
+
*/
|
|
21
|
+
function isIDERunning(processName) {
|
|
22
|
+
if (!processName) return false;
|
|
23
|
+
|
|
24
|
+
if (process.platform === 'darwin') {
|
|
25
|
+
// macOS: use pgrep
|
|
26
|
+
try {
|
|
27
|
+
const result = execSync(`pgrep -i "${processName}"`, { encoding: 'utf8' });
|
|
28
|
+
return result.trim().length > 0;
|
|
29
|
+
} catch (_) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
} else if (process.platform === 'win32') {
|
|
33
|
+
// Windows: use tasklist
|
|
34
|
+
try {
|
|
35
|
+
const result = execSync('tasklist', { encoding: 'utf8' });
|
|
36
|
+
return result.toLowerCase().includes(processName.toLowerCase());
|
|
37
|
+
} catch (_) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
// Linux: use pgrep
|
|
42
|
+
try {
|
|
43
|
+
const result = execSync(`pgrep -i "${processName}"`, { encoding: 'utf8' });
|
|
44
|
+
return result.trim().length > 0;
|
|
45
|
+
} catch (_) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Open the IDE using `open -a <app> <repoPath>` (macOS).
|
|
53
|
+
* Returns true when the launch command was sent.
|
|
54
|
+
*/
|
|
55
|
+
async function openIDEApp(appName, repoPath) {
|
|
56
|
+
if (!appName || process.platform !== 'darwin') return false;
|
|
57
|
+
try {
|
|
58
|
+
const safeRepo = repoPath ? ` "${repoPath.replace(/"/g, '\\"')}"` : '';
|
|
59
|
+
const { execSync } = require('child_process');
|
|
60
|
+
execSync(`open -a "${appName}"${safeRepo}`, { stdio: 'ignore' });
|
|
61
|
+
return true;
|
|
62
|
+
} catch (_) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
IDE_INFO,
|
|
69
|
+
isIDERunning,
|
|
70
|
+
openIDEApp
|
|
71
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { execSync } = require('child_process');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Get the Node.js executable path
|
|
9
|
+
* When running in Electron, process.execPath points to electron executable, not node
|
|
10
|
+
*/
|
|
11
|
+
function getNodeExecutable() {
|
|
12
|
+
// First try to get the actual node executable from process.env
|
|
13
|
+
if (process.env.NODE_BINARY_PATH) {
|
|
14
|
+
return process.env.NODE_BINARY_PATH;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Try to find node in PATH
|
|
18
|
+
try {
|
|
19
|
+
const nodeCmd = process.platform === 'win32' ? 'where node' : 'which node';
|
|
20
|
+
const nodePath = execSync(nodeCmd, { encoding: 'utf8' }).trim().split('\n')[0];
|
|
21
|
+
if (nodePath && fs.existsSync(nodePath)) {
|
|
22
|
+
return nodePath;
|
|
23
|
+
}
|
|
24
|
+
} catch (_) {}
|
|
25
|
+
|
|
26
|
+
// Fallback: try common node installation paths
|
|
27
|
+
const commonPaths = process.platform === 'win32'
|
|
28
|
+
? [
|
|
29
|
+
'C:\\Program Files\\nodejs\\node.exe',
|
|
30
|
+
'C:\\Program Files (x86)\\nodejs\\node.exe',
|
|
31
|
+
path.join(process.env.PROGRAMFILES || '', 'nodejs', 'node.exe'),
|
|
32
|
+
path.join(process.env['PROGRAMFILES(X86)'] || '', 'nodejs', 'node.exe')
|
|
33
|
+
]
|
|
34
|
+
: [
|
|
35
|
+
'/usr/bin/node',
|
|
36
|
+
'/usr/local/bin/node',
|
|
37
|
+
'/opt/homebrew/bin/node'
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
for (const nodePath of commonPaths) {
|
|
41
|
+
if (nodePath && fs.existsSync(nodePath)) {
|
|
42
|
+
return nodePath;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Last resort: use process.execPath (might be electron but worth trying)
|
|
47
|
+
console.warn('[AGENT CHECK] Could not find node executable, falling back to process.execPath');
|
|
48
|
+
return process.execPath;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const NODE_EXECUTABLE = getNodeExecutable();
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
getNodeExecutable,
|
|
55
|
+
NODE_EXECUTABLE
|
|
56
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Node Utilities Module
|
|
3
|
+
*
|
|
4
|
+
* Contains Node.js executable detection and related utilities.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { execSync } = require('child_process');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get the Node.js executable path
|
|
13
|
+
* When running in Electron, process.execPath points to electron executable, not node
|
|
14
|
+
*/
|
|
15
|
+
function getNodeExecutable() {
|
|
16
|
+
// First try to get the actual node executable from process.env
|
|
17
|
+
if (process.env.NODE_BINARY_PATH) {
|
|
18
|
+
return process.env.NODE_BINARY_PATH;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Try to find node in PATH
|
|
22
|
+
try {
|
|
23
|
+
const nodeCmd = process.platform === 'win32' ? 'where node' : 'which node';
|
|
24
|
+
const nodePath = execSync(nodeCmd, { encoding: 'utf8' }).trim().split('\n')[0];
|
|
25
|
+
if (nodePath && fs.existsSync(nodePath)) {
|
|
26
|
+
return nodePath;
|
|
27
|
+
}
|
|
28
|
+
} catch (_) {}
|
|
29
|
+
|
|
30
|
+
// Fallback: try common node installation paths
|
|
31
|
+
const commonPaths = process.platform === 'win32'
|
|
32
|
+
? [
|
|
33
|
+
'C:\\Program Files\\nodejs\\node.exe',
|
|
34
|
+
'C:\\Program Files (x86)\\nodejs\\node.exe',
|
|
35
|
+
path.join(process.env.PROGRAMFILES || '', 'nodejs', 'node.exe'),
|
|
36
|
+
path.join(process.env['PROGRAMFILES(X86)'] || '', 'nodejs', 'node.exe')
|
|
37
|
+
]
|
|
38
|
+
: [
|
|
39
|
+
'/usr/bin/node',
|
|
40
|
+
'/usr/local/bin/node',
|
|
41
|
+
'/opt/homebrew/bin/node'
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
for (const nodePath of commonPaths) {
|
|
45
|
+
if (nodePath && fs.existsSync(nodePath)) {
|
|
46
|
+
return nodePath;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Last resort: use process.execPath (might be electron but worth trying)
|
|
51
|
+
console.warn('[AGENT CHECK] Could not find node executable, falling back to process.execPath');
|
|
52
|
+
return process.execPath;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Cache the node executable path
|
|
56
|
+
const NODE_EXECUTABLE = getNodeExecutable();
|
|
57
|
+
|
|
58
|
+
module.exports = {
|
|
59
|
+
getNodeExecutable,
|
|
60
|
+
NODE_EXECUTABLE
|
|
61
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Spawn a process and wait for it to exit. Returns { code, output }.
|
|
7
|
+
*/
|
|
8
|
+
function spawnAndWait(cmd, args, opts = {}) {
|
|
9
|
+
return new Promise((resolve) => {
|
|
10
|
+
let output = '';
|
|
11
|
+
const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'], ...opts });
|
|
12
|
+
child.stdout && child.stdout.on('data', d => { output += d.toString(); });
|
|
13
|
+
child.stderr && child.stderr.on('data', d => { output += d.toString(); });
|
|
14
|
+
child.on('error', () => resolve({ code: -1, output }));
|
|
15
|
+
child.on('exit', (code) => resolve({ code, output }));
|
|
16
|
+
return child;
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
module.exports = {
|
|
21
|
+
spawnAndWait
|
|
22
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process Utilities Module
|
|
3
|
+
*
|
|
4
|
+
* Contains process spawning and management utilities.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { spawn } = require('child_process');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Spawn a process and wait for it to exit. Returns { code, output }.
|
|
11
|
+
*/
|
|
12
|
+
function spawnAndWait(cmd, args, opts = {}) {
|
|
13
|
+
return new Promise((resolve) => {
|
|
14
|
+
let output = '';
|
|
15
|
+
const child = spawn(cmd, args, { stdio: ['ignore', 'pipe', 'pipe'], ...opts });
|
|
16
|
+
|
|
17
|
+
child.stdout.on('data', (data) => {
|
|
18
|
+
output += data.toString();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
child.stderr.on('data', (data) => {
|
|
22
|
+
output += data.toString();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
child.on('close', (code) => {
|
|
26
|
+
resolve({ code, output });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
child.on('error', (error) => {
|
|
30
|
+
resolve({ code: -1, output: error.message });
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
spawnAndWait
|
|
37
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const { CLI_AUTO_INSTALL, isCLIAvailable, installCLI } = require('./cli-installer');
|
|
7
|
+
const { getResultFilePath, addTestRequirement, removeTestRequirement } = require('./requirements-manager');
|
|
8
|
+
const { runAgentCheck } = require('./agent-runner');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Check a single provider end-to-end using the actual REQUIREMENTS.md.
|
|
12
|
+
*
|
|
13
|
+
* Flow:
|
|
14
|
+
* 1. Add test requirement to top of REQUIREMENTS.md
|
|
15
|
+
* 2. Run the agent for 1 iteration
|
|
16
|
+
* 3. On success, requirement is auto-moved to Verified by the agent; remove it
|
|
17
|
+
* 4. On failure, leave requirement in pending for the NEXT agent (caller handles cleanup)
|
|
18
|
+
*
|
|
19
|
+
* Returns { status, message, checkedAt, requirementLeftPending }
|
|
20
|
+
*/
|
|
21
|
+
async function checkProvider(providerId, config = {}, repoPath, onProgress = null, signal = null) {
|
|
22
|
+
const { getProviderDefinition } = require('../provider-registry');
|
|
23
|
+
console.log(`[AGENT CHECK] Checking provider: ${providerId} in repo: ${repoPath}`);
|
|
24
|
+
|
|
25
|
+
const def = getProviderDefinition(providerId);
|
|
26
|
+
if (!def) {
|
|
27
|
+
console.error(`[AGENT CHECK] Unknown provider: ${providerId}`);
|
|
28
|
+
return { status: 'error', message: `Unknown provider: ${providerId}`, checkedAt: new Date().toISOString(), requirementLeftPending: false };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// No platform restrictions needed anymore - all IDEs have cross-platform support
|
|
32
|
+
|
|
33
|
+
if (!repoPath) {
|
|
34
|
+
console.error(`[AGENT CHECK] No repository path available`);
|
|
35
|
+
return { status: 'error', message: 'No repository path available', checkedAt: new Date().toISOString(), requirementLeftPending: false };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const { getRequirementsPath } = require('vibecodingmachine-core');
|
|
39
|
+
let reqPath;
|
|
40
|
+
try {
|
|
41
|
+
reqPath = await getRequirementsPath(repoPath);
|
|
42
|
+
} catch {
|
|
43
|
+
reqPath = path.join(repoPath, '.vibecodingmachine', 'REQUIREMENTS.md');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Ensure .vibecodingmachine directory exists
|
|
47
|
+
const vibeDir = path.join(repoPath, '.vibecodingmachine');
|
|
48
|
+
const tempDir = path.join(vibeDir, 'temp');
|
|
49
|
+
try {
|
|
50
|
+
fs.mkdirSync(vibeDir, { recursive: true });
|
|
51
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
52
|
+
console.log(`[AGENT CHECK] Ensured .vibecodingmachine directories exist`);
|
|
53
|
+
} catch (err) {
|
|
54
|
+
console.error(`[AGENT CHECK] Failed to create .vibecodingmachine directories: ${err.message}`);
|
|
55
|
+
return { status: 'error', message: `Could not create .vibecodingmachine: ${err.message}`, checkedAt: new Date().toISOString(), requirementLeftPending: false };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Ensure REQUIREMENTS.md exists with proper structure
|
|
59
|
+
try {
|
|
60
|
+
if (!fs.existsSync(reqPath)) {
|
|
61
|
+
const initialRequirements = `# Requirements for this project
|
|
62
|
+
|
|
63
|
+
## ⏳ Requirements not yet completed
|
|
64
|
+
|
|
65
|
+
## ✅ Verified by AI
|
|
66
|
+
|
|
67
|
+
`;
|
|
68
|
+
fs.writeFileSync(reqPath, initialRequirements, 'utf8');
|
|
69
|
+
console.log(`[AGENT CHECK] Created initial REQUIREMENTS.md`);
|
|
70
|
+
} else {
|
|
71
|
+
console.log(`[AGENT CHECK] REQUIREMENTS.md already exists`);
|
|
72
|
+
}
|
|
73
|
+
} catch (err) {
|
|
74
|
+
console.error(`[AGENT CHECK] Failed to ensure REQUIREMENTS.md: ${err.message}`);
|
|
75
|
+
return { status: 'error', message: `Could not create REQUIREMENTS.md: ${err.message}`, checkedAt: new Date().toISOString(), requirementLeftPending: false };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const resultFile = getResultFilePath(repoPath);
|
|
79
|
+
|
|
80
|
+
// Ensure the config has repoPath set for the child process
|
|
81
|
+
try {
|
|
82
|
+
const { getRepoPath, setRepoPath } = require('./config');
|
|
83
|
+
const currentRepoPath = await getRepoPath();
|
|
84
|
+
if (currentRepoPath !== repoPath) {
|
|
85
|
+
console.log(`[AGENT CHECK] Setting main config repoPath to: ${repoPath}`);
|
|
86
|
+
await setRepoPath(repoPath);
|
|
87
|
+
console.log(`[AGENT CHECK] Wrote repoPath to config successfully`);
|
|
88
|
+
} else {
|
|
89
|
+
console.log(`[AGENT CHECK] repoPath already configured: ${currentRepoPath}`);
|
|
90
|
+
}
|
|
91
|
+
} catch (err) {
|
|
92
|
+
console.warn(`[AGENT CHECK] Warning: Could not ensure repoPath in config: ${err.message}`);
|
|
93
|
+
// Don't fail - we'll try anyway
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// For direct CLI providers: auto-install if missing
|
|
97
|
+
const cliInfo = CLI_AUTO_INSTALL[providerId];
|
|
98
|
+
if (cliInfo && !isCLIAvailable(cliInfo.cmd, providerId)) {
|
|
99
|
+
if (onProgress) onProgress(providerId, 'installing');
|
|
100
|
+
const { installed, note } = await installCLI(providerId);
|
|
101
|
+
if (!installed) {
|
|
102
|
+
return { status: 'error', message: `${def.name} not installed and auto-install failed: ${note}`, checkedAt: new Date().toISOString(), requirementLeftPending: false };
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Add test requirement (idempotent — safe to call even if already present from a prior failed agent)
|
|
107
|
+
try { addTestRequirement(reqPath, resultFile); } catch (err) {
|
|
108
|
+
return { status: 'error', message: `Could not write to REQUIREMENTS.md: ${err.message}`, checkedAt: new Date().toISOString(), requirementLeftPending: false };
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const { DIRECT_TIMEOUT_MS, IDE_TIMEOUT_MS } = require('./agent-runner');
|
|
112
|
+
const timeoutMs = def.type === 'ide' ? IDE_TIMEOUT_MS : DIRECT_TIMEOUT_MS;
|
|
113
|
+
const result = await runAgentCheck(providerId, def, repoPath, resultFile, timeoutMs, signal, onProgress);
|
|
114
|
+
|
|
115
|
+
if (result.status === 'success') {
|
|
116
|
+
// Agent completed — requirement has been moved to Verified; remove it and the result file
|
|
117
|
+
try { removeTestRequirement(reqPath); } catch { }
|
|
118
|
+
try { fs.unlinkSync(resultFile); } catch { }
|
|
119
|
+
return { ...result, requirementLeftPending: false };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Agent failed — leave the requirement in pending for the next agent
|
|
123
|
+
return { ...result, requirementLeftPending: true };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Check all providers sequentially.
|
|
128
|
+
* The test requirement is shared: it stays pending between agents until one
|
|
129
|
+
* succeeds, then it's removed. If all fail, it's removed at the end.
|
|
130
|
+
*
|
|
131
|
+
* Returns { [providerId]: checkResult }
|
|
132
|
+
*/
|
|
133
|
+
async function checkAllProviders(providerIds, config = {}, repoPath, onProgress = null, signal = null) {
|
|
134
|
+
const results = {};
|
|
135
|
+
|
|
136
|
+
for (const id of providerIds) {
|
|
137
|
+
if (signal && signal.cancelled) break;
|
|
138
|
+
if (onProgress) onProgress(id, 'checking');
|
|
139
|
+
results[id] = await checkProvider(id, config, repoPath, onProgress, signal);
|
|
140
|
+
if (onProgress) onProgress(id, 'done', results[id]);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Final cleanup — remove requirement if still pending (all agents failed or skipped)
|
|
144
|
+
if (repoPath) {
|
|
145
|
+
const { getRequirementsPath } = require('vibecodingmachine-core');
|
|
146
|
+
let reqPath;
|
|
147
|
+
try { reqPath = await getRequirementsPath(repoPath); } catch {
|
|
148
|
+
reqPath = path.join(repoPath, '.vibecodingmachine', 'REQUIREMENTS.md');
|
|
149
|
+
}
|
|
150
|
+
try { removeTestRequirement(reqPath); } catch { }
|
|
151
|
+
try { fs.unlinkSync(getResultFilePath(repoPath)); } catch { }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return results;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
module.exports = {
|
|
158
|
+
checkProvider,
|
|
159
|
+
checkAllProviders
|
|
160
|
+
};
|