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,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File scanning functions for auto-direct command
|
|
3
|
+
* Extracted from auto-direct.js to reduce file size
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require('fs-extra');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
const chalk = require('chalk');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Find relevant files based on requirement
|
|
12
|
+
*/
|
|
13
|
+
async function findRelevantFiles(requirement, repoPath) {
|
|
14
|
+
const relevantFiles = [];
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// Common file patterns to search for
|
|
18
|
+
const patterns = [
|
|
19
|
+
'**/*.js',
|
|
20
|
+
'**/*.jsx',
|
|
21
|
+
'**/*.ts',
|
|
22
|
+
'**/*.tsx',
|
|
23
|
+
'**/*.json',
|
|
24
|
+
'**/*.md',
|
|
25
|
+
'**/*.yml',
|
|
26
|
+
'**/*.yaml'
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
// Keywords to look for in requirement
|
|
30
|
+
const keywords = extractKeywords(requirement);
|
|
31
|
+
|
|
32
|
+
// Search for files containing keywords
|
|
33
|
+
for (const pattern of patterns) {
|
|
34
|
+
const files = await glob(pattern, { cwd: repoPath, ignore: ['**/node_modules/**', '**/.git/**'] });
|
|
35
|
+
|
|
36
|
+
for (const file of files) {
|
|
37
|
+
const fullPath = path.join(repoPath, file);
|
|
38
|
+
|
|
39
|
+
// Skip if not a file
|
|
40
|
+
if (!await fs.pathExists(fullPath) || !await fs.stat(fullPath).then(stat => stat.isFile())) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Check if file contains relevant keywords
|
|
45
|
+
const isRelevant = await isFileRelevant(fullPath, keywords);
|
|
46
|
+
if (isRelevant) {
|
|
47
|
+
relevantFiles.push(file);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Remove duplicates and sort by relevance
|
|
53
|
+
const uniqueFiles = [...new Set(relevantFiles)];
|
|
54
|
+
return uniqueFiles.slice(0, 20); // Limit to top 20 files
|
|
55
|
+
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error('Error finding relevant files:', error.message);
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Read file snippets to give LLM context
|
|
64
|
+
*/
|
|
65
|
+
async function readFileSnippets(files, repoPath, requirement) {
|
|
66
|
+
const snippets = [];
|
|
67
|
+
|
|
68
|
+
for (const file of files) {
|
|
69
|
+
try {
|
|
70
|
+
const fullPath = path.join(repoPath, file);
|
|
71
|
+
|
|
72
|
+
if (!await fs.pathExists(fullPath)) {
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const content = await fs.readFile(fullPath, 'utf8');
|
|
77
|
+
const lines = content.split('\n');
|
|
78
|
+
|
|
79
|
+
// For large files, find relevant sections
|
|
80
|
+
let startLine = 0;
|
|
81
|
+
let endLine = lines.length;
|
|
82
|
+
|
|
83
|
+
if (lines.length > 100) {
|
|
84
|
+
// Try to find relevant sections based on requirement keywords
|
|
85
|
+
const keywords = extractKeywords(requirement);
|
|
86
|
+
const relevantSections = findRelevantSections(lines, keywords);
|
|
87
|
+
|
|
88
|
+
if (relevantSections.length > 0) {
|
|
89
|
+
// Use the most relevant section
|
|
90
|
+
const section = relevantSections[0];
|
|
91
|
+
startLine = Math.max(0, section.start - 10); // Add context
|
|
92
|
+
endLine = Math.min(lines.length, section.end + 10);
|
|
93
|
+
} else {
|
|
94
|
+
// Fall back to beginning of file
|
|
95
|
+
endLine = 50;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const snippet = lines.slice(startLine, endLine).join('\n');
|
|
100
|
+
|
|
101
|
+
snippets.push({
|
|
102
|
+
file,
|
|
103
|
+
content: snippet,
|
|
104
|
+
startLine: startLine + 1,
|
|
105
|
+
endLine: endLine,
|
|
106
|
+
totalLines: lines.length
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.warn(`Warning: Could not read file ${file}:`, error.message);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return snippets;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Extract keywords from requirement text
|
|
119
|
+
*/
|
|
120
|
+
function extractKeywords(requirement) {
|
|
121
|
+
// Simple keyword extraction - look for technical terms
|
|
122
|
+
const technicalTerms = [
|
|
123
|
+
'function', 'class', 'component', 'module', 'package', 'file',
|
|
124
|
+
'test', 'spec', 'config', 'build', 'deploy', 'api', 'endpoint',
|
|
125
|
+
'database', 'model', 'view', 'controller', 'service', 'utility',
|
|
126
|
+
'helper', 'constant', 'variable', 'method', 'property', 'interface'
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
const words = requirement.toLowerCase().split(/\s+/);
|
|
130
|
+
const keywords = new Set();
|
|
131
|
+
|
|
132
|
+
// Add technical terms found in requirement
|
|
133
|
+
words.forEach(word => {
|
|
134
|
+
if (technicalTerms.includes(word) || word.length > 5) {
|
|
135
|
+
keywords.add(word);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Look for file extensions and patterns
|
|
140
|
+
const filePatterns = requirement.match(/\b\w+\.(js|jsx|ts|tsx|json|md|yml|yaml)\b/g);
|
|
141
|
+
if (filePatterns) {
|
|
142
|
+
filePatterns.forEach(pattern => keywords.add(pattern));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Look for specific file names in quotes
|
|
146
|
+
const quotedFiles = requirement.match(/['"`]([^'"`]+\.(js|jsx|ts|tsx|json|md|yml|yaml))['"`]/g);
|
|
147
|
+
if (quotedFiles) {
|
|
148
|
+
quotedFiles.forEach(file => keywords.add(file.replace(/['"`]/g, '')));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return Array.from(keywords);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Check if file contains relevant keywords
|
|
156
|
+
*/
|
|
157
|
+
async function isFileRelevant(filePath, keywords) {
|
|
158
|
+
try {
|
|
159
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
160
|
+
const lowerContent = content.toLowerCase();
|
|
161
|
+
|
|
162
|
+
// Check if any keywords are present in the file
|
|
163
|
+
return keywords.some(keyword =>
|
|
164
|
+
lowerContent.includes(keyword.toLowerCase())
|
|
165
|
+
);
|
|
166
|
+
} catch (error) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Find relevant sections in file based on keywords
|
|
173
|
+
*/
|
|
174
|
+
function findRelevantSections(lines, keywords) {
|
|
175
|
+
const sections = [];
|
|
176
|
+
|
|
177
|
+
keywords.forEach(keyword => {
|
|
178
|
+
const lowerKeyword = keyword.toLowerCase();
|
|
179
|
+
|
|
180
|
+
lines.forEach((line, index) => {
|
|
181
|
+
if (line.toLowerCase().includes(lowerKeyword)) {
|
|
182
|
+
// Found a keyword, create a section around it
|
|
183
|
+
const start = Math.max(0, index - 5);
|
|
184
|
+
const end = Math.min(lines.length, index + 15);
|
|
185
|
+
|
|
186
|
+
sections.push({
|
|
187
|
+
keyword,
|
|
188
|
+
start,
|
|
189
|
+
end,
|
|
190
|
+
line: index + 1,
|
|
191
|
+
content: line.trim()
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Sort by keyword relevance (prefer function/class definitions)
|
|
198
|
+
sections.sort((a, b) => {
|
|
199
|
+
const aScore = calculateRelevanceScore(a.content);
|
|
200
|
+
const bScore = calculateRelevanceScore(b.content);
|
|
201
|
+
return bScore - aScore;
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
return sections;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Calculate relevance score for a line
|
|
209
|
+
*/
|
|
210
|
+
function calculateRelevanceScore(line) {
|
|
211
|
+
let score = 0;
|
|
212
|
+
|
|
213
|
+
// Higher score for function/class definitions
|
|
214
|
+
if (line.includes('function ') || line.includes('class ') || line.includes('const ')) {
|
|
215
|
+
score += 10;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Higher score for exports
|
|
219
|
+
if (line.includes('module.exports') || line.includes('export ')) {
|
|
220
|
+
score += 8;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Higher score for imports/requires
|
|
224
|
+
if (line.includes('require(') || line.includes('import ')) {
|
|
225
|
+
score += 5;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Higher score for comments
|
|
229
|
+
if (line.includes('//') || line.includes('*') || line.includes('/*')) {
|
|
230
|
+
score += 3;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return score;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Simple glob implementation (or you can use the 'glob' package)
|
|
238
|
+
*/
|
|
239
|
+
async function glob(pattern, options = {}) {
|
|
240
|
+
const { cwd = process.cwd(), ignore = [] } = options;
|
|
241
|
+
const { promisify } = require('util');
|
|
242
|
+
const { exec } = require('child_process');
|
|
243
|
+
|
|
244
|
+
try {
|
|
245
|
+
const { stdout } = await promisify(exec)(`find . -name "${pattern.replace('**/', '*')}"`, { cwd });
|
|
246
|
+
let files = stdout.trim().split('\n').filter(file => file);
|
|
247
|
+
|
|
248
|
+
// Apply ignore patterns
|
|
249
|
+
ignore.forEach(ignorePattern => {
|
|
250
|
+
files = files.filter(file => !file.includes(ignorePattern.replace('**/', '')));
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
return files;
|
|
254
|
+
} catch (error) {
|
|
255
|
+
return [];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
module.exports = {
|
|
260
|
+
findRelevantFiles,
|
|
261
|
+
readFileSnippets,
|
|
262
|
+
extractKeywords,
|
|
263
|
+
isFileRelevant,
|
|
264
|
+
findRelevantSections,
|
|
265
|
+
calculateRelevanceScore
|
|
266
|
+
};
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider configuration functions for auto-direct command
|
|
3
|
+
* Extracted from auto-direct.js to reduce file size
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { getAutoConfig } = require('../../utils/config');
|
|
7
|
+
const { getProviderPreferences, getProviderDefinition, saveProviderPreferences } = require('../../utils/provider-registry');
|
|
8
|
+
const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
|
|
9
|
+
const { checkAntigravityRateLimit, handleAntigravityRateLimit } = require('../../utils/antigravity-js-handler');
|
|
10
|
+
const { checkKiroRateLimit, handleKiroRateLimit } = require('../../utils/kiro-js-handler');
|
|
11
|
+
const { checkClineRateLimit, handleClineRateLimit } = require('../../utils/cline-js-handler');
|
|
12
|
+
|
|
13
|
+
// CRITICAL: Shared ProviderManager instance to track rate limits across all function calls
|
|
14
|
+
const sharedProviderManager = new ProviderManager();
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Get all available provider configurations
|
|
18
|
+
*/
|
|
19
|
+
async function getAllAvailableProviders() {
|
|
20
|
+
const config = await getAutoConfig();
|
|
21
|
+
const prefs = await getProviderPreferences();
|
|
22
|
+
|
|
23
|
+
const providers = [];
|
|
24
|
+
const skipped = [];
|
|
25
|
+
|
|
26
|
+
// Check each provider in config
|
|
27
|
+
for (const [providerName, providerConfig] of Object.entries(config.providers || {})) {
|
|
28
|
+
// Skip if provider is disabled in preferences
|
|
29
|
+
if (prefs.disabled?.includes(providerName)) {
|
|
30
|
+
skipped.push(providerName);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Check if provider is properly configured
|
|
35
|
+
const definition = getProviderDefinition(providerName);
|
|
36
|
+
if (!definition) {
|
|
37
|
+
skipped.push(providerName);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Check required credentials
|
|
42
|
+
let hasCredentials = true;
|
|
43
|
+
if (definition.credentials) {
|
|
44
|
+
for (const cred of definition.credentials) {
|
|
45
|
+
if (!providerConfig[cred]) {
|
|
46
|
+
hasCredentials = false;
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (hasCredentials) {
|
|
53
|
+
providers.push({
|
|
54
|
+
name: providerName,
|
|
55
|
+
displayName: definition.displayName || providerName,
|
|
56
|
+
config: providerConfig,
|
|
57
|
+
definition
|
|
58
|
+
});
|
|
59
|
+
} else {
|
|
60
|
+
skipped.push(providerName);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { providers, skipped };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Get provider configuration with automatic failover
|
|
69
|
+
*/
|
|
70
|
+
async function getProviderConfig(excludeProvider = null) {
|
|
71
|
+
const config = await getAutoConfig();
|
|
72
|
+
const providerManager = sharedProviderManager; // Use shared instance to persist rate limit state
|
|
73
|
+
const { providers, skipped } = await getAllAvailableProviders();
|
|
74
|
+
|
|
75
|
+
// Filter out excluded provider
|
|
76
|
+
const availableProviders = providers.filter(p => p.name !== excludeProvider);
|
|
77
|
+
|
|
78
|
+
if (availableProviders.length === 0) {
|
|
79
|
+
throw new Error('No providers available. Check your configuration.');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Sort providers by reliability (health score)
|
|
83
|
+
const sortedProviders = availableProviders.sort((a, b) => {
|
|
84
|
+
const aHealth = providerManager.getHealthScore(a.name);
|
|
85
|
+
const bHealth = providerManager.getHealthScore(b.name);
|
|
86
|
+
return bHealth - aHealth; // Higher health score first
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Try providers in order of reliability
|
|
90
|
+
for (const provider of sortedProviders) {
|
|
91
|
+
// Check rate limits for specific providers
|
|
92
|
+
if (provider.name === 'antigravity') {
|
|
93
|
+
const isRateLimited = checkAntigravityRateLimit();
|
|
94
|
+
if (isRateLimited) {
|
|
95
|
+
console.warn(`⚠️ ${provider.displayName} is rate limited, trying next provider`);
|
|
96
|
+
handleAntigravityRateLimit();
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
} else if (provider.name === 'kiro') {
|
|
100
|
+
const isRateLimited = checkKiroRateLimit();
|
|
101
|
+
if (isRateLimited) {
|
|
102
|
+
console.warn(`⚠️ ${provider.displayName} is rate limited, trying next provider`);
|
|
103
|
+
handleKiroRateLimit();
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
} else if (provider.name === 'cline') {
|
|
107
|
+
const isRateLimited = checkClineRateLimit();
|
|
108
|
+
if (isRateLimited) {
|
|
109
|
+
console.warn(`⚠️ ${provider.displayName} is rate limited, trying next provider`);
|
|
110
|
+
handleClineRateLimit();
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
provider: provider.name,
|
|
117
|
+
displayName: provider.displayName,
|
|
118
|
+
config: provider.config,
|
|
119
|
+
definition: provider.definition
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
throw new Error('All providers are rate limited or unavailable');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Acquire provider configuration with enhanced failover and model selection
|
|
128
|
+
*/
|
|
129
|
+
async function acquireProviderConfig(excludeProvider = null, excludeModel = null, forcedProvider = null) {
|
|
130
|
+
// If a specific provider is forced, bypass normal selection
|
|
131
|
+
if (forcedProvider) {
|
|
132
|
+
const { providers } = await getAllAvailableProviders();
|
|
133
|
+
const provider = providers.find(p => p.name === forcedProvider);
|
|
134
|
+
|
|
135
|
+
if (!provider) {
|
|
136
|
+
throw new Error(`Forced provider "${forcedProvider}" not available`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
provider: provider.name,
|
|
141
|
+
displayName: provider.displayName,
|
|
142
|
+
config: provider.config,
|
|
143
|
+
definition: provider.definition,
|
|
144
|
+
model: provider.config.model || provider.definition.defaultModel
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const config = await getProviderConfig(excludeProvider);
|
|
149
|
+
|
|
150
|
+
// Model selection logic
|
|
151
|
+
let selectedModel = config.config.model;
|
|
152
|
+
|
|
153
|
+
// Exclude specific model if requested
|
|
154
|
+
if (excludeModel && selectedModel === excludeModel) {
|
|
155
|
+
// Try alternative models
|
|
156
|
+
const alternativeModels = config.definition.models || [];
|
|
157
|
+
const availableModel = alternativeModels.find(m => m !== excludeModel && m !== selectedModel);
|
|
158
|
+
|
|
159
|
+
if (availableModel) {
|
|
160
|
+
selectedModel = availableModel;
|
|
161
|
+
} else {
|
|
162
|
+
// If no alternative model, try next provider
|
|
163
|
+
return acquireProviderConfig(config.provider, excludeModel, null);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
...config,
|
|
169
|
+
model: selectedModel
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
module.exports = {
|
|
174
|
+
getAllAvailableProviders,
|
|
175
|
+
getProviderConfig,
|
|
176
|
+
acquireProviderConfig,
|
|
177
|
+
sharedProviderManager
|
|
178
|
+
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider management functions for auto-direct command
|
|
3
|
+
* Extracted from auto-direct.js to reduce file size
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const { getAutoConfig } = require('../../utils/config');
|
|
7
|
+
const { getProviderPreferences, getProviderDefinition, saveProviderPreferences } = require('../../utils/provider-registry');
|
|
8
|
+
const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
|
|
9
|
+
const { checkAntigravityRateLimit, handleAntigravityRateLimit } = require('../../utils/antigravity-js-handler');
|
|
10
|
+
const { checkKiroRateLimit, handleKiroRateLimit } = require('../../utils/kiro-js-handler');
|
|
11
|
+
const { checkClineRateLimit, handleClineRateLimit } = require('../../utils/cline-js-handler');
|
|
12
|
+
const { DirectLLMManager } = require('vibecodingmachine-core');
|
|
13
|
+
|
|
14
|
+
// CRITICAL: Shared ProviderManager instance to track rate limits across all function calls
|
|
15
|
+
const sharedProviderManager = new ProviderManager();
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get all available provider configurations
|
|
19
|
+
*/
|
|
20
|
+
async function getAllAvailableProviders() {
|
|
21
|
+
const config = await getAutoConfig();
|
|
22
|
+
const prefs = await getProviderPreferences();
|
|
23
|
+
|
|
24
|
+
const providers = [];
|
|
25
|
+
const skipped = [];
|
|
26
|
+
|
|
27
|
+
// Check each configured provider
|
|
28
|
+
for (const [providerName, providerConfig] of Object.entries(config.providers || {})) {
|
|
29
|
+
if (!providerConfig.enabled) {
|
|
30
|
+
skipped.push(`${providerName} (disabled)`);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Check rate limits for specific providers
|
|
35
|
+
let isRateLimited = false;
|
|
36
|
+
let rateLimitReason = '';
|
|
37
|
+
|
|
38
|
+
if (providerName === 'antigravity') {
|
|
39
|
+
const rateLimitCheck = await checkAntigravityRateLimit();
|
|
40
|
+
if (rateLimitCheck.isLimited) {
|
|
41
|
+
isRateLimited = true;
|
|
42
|
+
rateLimitReason = rateLimitCheck.reason;
|
|
43
|
+
}
|
|
44
|
+
} else if (providerName === 'kiro') {
|
|
45
|
+
const rateLimitCheck = await checkKiroRateLimit();
|
|
46
|
+
if (rateLimitCheck.isLimited) {
|
|
47
|
+
isRateLimited = true;
|
|
48
|
+
rateLimitReason = rateLimitCheck.reason;
|
|
49
|
+
}
|
|
50
|
+
} else if (providerName === 'cline') {
|
|
51
|
+
const rateLimitCheck = await checkClineRateLimit();
|
|
52
|
+
if (rateLimitCheck.isLimited) {
|
|
53
|
+
isRateLimited = true;
|
|
54
|
+
rateLimitReason = rateLimitCheck.reason;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (isRateLimited) {
|
|
59
|
+
skipped.push(`${providerName} (${rateLimitReason})`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Get provider definition for display name
|
|
64
|
+
const providerDef = getProviderDefinition(providerName);
|
|
65
|
+
const displayName = providerDef?.displayName || providerName;
|
|
66
|
+
|
|
67
|
+
providers.push({
|
|
68
|
+
name: providerName,
|
|
69
|
+
displayName,
|
|
70
|
+
config: providerConfig,
|
|
71
|
+
models: providerConfig.models || []
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return { providers, skipped };
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get provider configuration with automatic failover
|
|
80
|
+
*/
|
|
81
|
+
async function getProviderConfig(excludeProvider = null) {
|
|
82
|
+
const config = await getAutoConfig();
|
|
83
|
+
const providerManager = sharedProviderManager; // Use shared instance to persist rate limit state
|
|
84
|
+
const { providers, skipped } = await getAllAvailableProviders();
|
|
85
|
+
|
|
86
|
+
// Filter out excluded provider
|
|
87
|
+
const availableProviders = providers.filter(p => p.name !== excludeProvider);
|
|
88
|
+
|
|
89
|
+
if (availableProviders.length === 0) {
|
|
90
|
+
return {
|
|
91
|
+
success: false,
|
|
92
|
+
error: `No available providers. Skipped: ${skipped.join(', ')}`
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Try providers in order
|
|
97
|
+
for (const provider of availableProviders) {
|
|
98
|
+
try {
|
|
99
|
+
// Check if provider is rate limited through ProviderManager
|
|
100
|
+
const rateLimitStatus = providerManager.getRateLimitStatus(provider.name);
|
|
101
|
+
if (rateLimitStatus.isLimited) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Select first available model
|
|
106
|
+
const availableModels = provider.models.filter(m => m.enabled);
|
|
107
|
+
if (availableModels.length === 0) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const selectedModel = availableModels[0];
|
|
112
|
+
|
|
113
|
+
return {
|
|
114
|
+
success: true,
|
|
115
|
+
provider: provider.name,
|
|
116
|
+
ide: provider.name,
|
|
117
|
+
displayName: provider.displayName,
|
|
118
|
+
model: selectedModel.name,
|
|
119
|
+
config: {
|
|
120
|
+
...provider.config,
|
|
121
|
+
model: selectedModel
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
} catch (error) {
|
|
125
|
+
console.warn(`Failed to configure provider ${provider.name}:`, error.message);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return {
|
|
131
|
+
success: false,
|
|
132
|
+
error: `All providers failed. Skipped: ${skipped.join(', ')}`
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Acquire provider configuration with enhanced error handling
|
|
138
|
+
*/
|
|
139
|
+
async function acquireProviderConfig(excludeProvider = null, excludeModel = null, forcedProvider = null) {
|
|
140
|
+
// If a specific provider is forced, bypass normal selection
|
|
141
|
+
if (forcedProvider) {
|
|
142
|
+
// Special handling for Cline CLI - auto-install if not available
|
|
143
|
+
if (forcedProvider === 'cline') {
|
|
144
|
+
await ensureClineInstalled(true);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const config = await getAutoConfig();
|
|
148
|
+
const providerConfig = config.providers[forcedProvider];
|
|
149
|
+
|
|
150
|
+
if (!providerConfig || !providerConfig.enabled) {
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
error: `Forced provider ${forcedProvider} is not available or disabled`
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const availableModels = providerConfig.models.filter(m =>
|
|
158
|
+
m.enabled && m.name !== excludeModel
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
if (availableModels.length === 0) {
|
|
162
|
+
return {
|
|
163
|
+
success: false,
|
|
164
|
+
error: `No available models for provider ${forcedProvider}`
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
success: true,
|
|
170
|
+
provider: forcedProvider,
|
|
171
|
+
ide: forcedProvider,
|
|
172
|
+
displayName: getProviderDefinition(forcedProvider)?.displayName || forcedProvider,
|
|
173
|
+
model: availableModels[0].name,
|
|
174
|
+
config: {
|
|
175
|
+
...providerConfig,
|
|
176
|
+
model: availableModels[0]
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Normal provider selection logic
|
|
182
|
+
return await getProviderConfig(excludeProvider);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Ensure Cline CLI is installed and available
|
|
187
|
+
*/
|
|
188
|
+
async function ensureClineInstalled(forceInstall = false) {
|
|
189
|
+
const llm = new DirectLLMManager();
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
const isAvailable = await llm.checkClineAvailability();
|
|
193
|
+
if (isAvailable && !forceInstall) {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log('Installing Cline CLI...');
|
|
198
|
+
const installResult = await llm.installCline();
|
|
199
|
+
|
|
200
|
+
if (installResult.success) {
|
|
201
|
+
console.log('✅ Cline CLI installed successfully');
|
|
202
|
+
return true;
|
|
203
|
+
} else {
|
|
204
|
+
console.error('❌ Failed to install Cline CLI:', installResult.error);
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.error('❌ Error installing Cline CLI:', error.message);
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
module.exports = {
|
|
214
|
+
getAllAvailableProviders,
|
|
215
|
+
getProviderConfig,
|
|
216
|
+
acquireProviderConfig,
|
|
217
|
+
ensureClineInstalled,
|
|
218
|
+
sharedProviderManager
|
|
219
|
+
};
|