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,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
+ };