vibecodingmachine-cli 2026.2.26-1739 → 2026.3.9-1621

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 (74) hide show
  1. package/bin/auth/auth-compliance.js +7 -1
  2. package/bin/commands/agent-commands.js +150 -228
  3. package/bin/commands/command-aliases.js +68 -0
  4. package/bin/vibecodingmachine.js +1 -2
  5. package/package.json +2 -2
  6. package/src/commands/agents/list.js +71 -115
  7. package/src/commands/agents-check.js +16 -4
  8. package/src/commands/analyze-file-sizes.js +1 -1
  9. package/src/commands/auto-direct/auto-provider-manager.js +290 -0
  10. package/src/commands/auto-direct/auto-status-display.js +331 -0
  11. package/src/commands/auto-direct/auto-utils.js +439 -0
  12. package/src/commands/auto-direct/file-operations.js +110 -0
  13. package/src/commands/auto-direct/provider-config.js +1 -1
  14. package/src/commands/auto-direct/provider-manager.js +1 -1
  15. package/src/commands/auto-direct/status-display.js +1 -1
  16. package/src/commands/auto-direct/utils.js +24 -18
  17. package/src/commands/auto-direct-refactored.js +413 -0
  18. package/src/commands/auto-direct.js +594 -188
  19. package/src/commands/requirements/commands.js +353 -0
  20. package/src/commands/requirements/default-handlers.js +272 -0
  21. package/src/commands/requirements/disable.js +97 -0
  22. package/src/commands/requirements/enable.js +97 -0
  23. package/src/commands/requirements/utils.js +194 -0
  24. package/src/commands/requirements-refactored.js +60 -0
  25. package/src/commands/requirements.js +38 -771
  26. package/src/commands/specs/disable.js +96 -0
  27. package/src/commands/specs/enable.js +96 -0
  28. package/src/trui/TruiInterface.js +5 -11
  29. package/src/trui/agents/AgentInterface.js +24 -396
  30. package/src/trui/agents/handlers/CommandHandler.js +93 -0
  31. package/src/trui/agents/handlers/ContextManager.js +117 -0
  32. package/src/trui/agents/handlers/DisplayHandler.js +243 -0
  33. package/src/trui/agents/handlers/HelpHandler.js +51 -0
  34. package/src/utils/auth.js +13 -111
  35. package/src/utils/config.js +5 -1
  36. package/src/utils/interactive/requirements-navigation.js +17 -15
  37. package/src/utils/interactive-broken.js +2 -2
  38. package/src/utils/provider-checker/agent-runner.js +15 -1
  39. package/src/utils/provider-checker/cli-installer.js +149 -7
  40. package/src/utils/provider-checker/opencode-checker.js +588 -0
  41. package/src/utils/provider-checker/provider-validator.js +88 -3
  42. package/src/utils/provider-checker/time-formatter.js +3 -2
  43. package/src/utils/provider-manager.js +28 -20
  44. package/src/utils/provider-registry.js +35 -3
  45. package/src/utils/requirements-navigator/index.js +94 -0
  46. package/src/utils/requirements-navigator/input-handler.js +217 -0
  47. package/src/utils/requirements-navigator/section-loader.js +188 -0
  48. package/src/utils/requirements-navigator/tree-builder.js +105 -0
  49. package/src/utils/requirements-navigator/tree-renderer.js +50 -0
  50. package/src/utils/requirements-navigator.js +2 -583
  51. package/src/utils/trui-clarifications.js +188 -0
  52. package/src/utils/trui-feedback.js +54 -1
  53. package/src/utils/trui-kiro-integration.js +398 -0
  54. package/src/utils/trui-main-handlers.js +194 -0
  55. package/src/utils/trui-main-menu.js +235 -0
  56. package/src/utils/trui-nav-agents.js +178 -25
  57. package/src/utils/trui-nav-requirements.js +203 -27
  58. package/src/utils/trui-nav-settings.js +114 -1
  59. package/src/utils/trui-nav-specifications.js +44 -3
  60. package/src/utils/trui-navigation-backup.js +603 -0
  61. package/src/utils/trui-navigation.js +70 -228
  62. package/src/utils/trui-provider-health.js +274 -0
  63. package/src/utils/trui-provider-manager.js +376 -0
  64. package/src/utils/trui-quick-menu.js +25 -1
  65. package/src/utils/trui-req-actions-backup.js +507 -0
  66. package/src/utils/trui-req-actions.js +148 -216
  67. package/src/utils/trui-req-editor.js +170 -0
  68. package/src/utils/trui-req-file-ops.js +278 -0
  69. package/src/utils/trui-req-tree-old.js +719 -0
  70. package/src/utils/trui-req-tree.js +348 -627
  71. package/src/utils/trui-specifications.js +25 -7
  72. package/src/utils/trui-windsurf.js +231 -10
  73. package/src/utils/welcome-screen-extracted.js +2 -2
  74. package/src/utils/welcome-screen.js +2 -2
@@ -5,12 +5,14 @@
5
5
  * Follows constitutional requirements: <555 lines, test-first approach.
6
6
  */
7
7
 
8
- const AgentConfigManager = require('../../../../../packages/core/src/agents/config/AgentConfigManager');
9
- const AgentLogger = require('../../../../../packages/core/src/agents/logging/AgentLogger');
10
- const FileManager = require('../../../../../packages/core/src/agents/storage/FileManager');
11
- const { AgentStatus } = require('../../../../../packages/core/src/agents/AgentStatus');
12
- const AgentCommands = require('../../../../../packages/core/src/rui/commands/AgentCommands');
13
- const AgentResponseFormatter = require('../../../../../packages/core/src/rui/commands/AgentResponseFormatter');
8
+ const {
9
+ getProviderDefinitions,
10
+ getProviderDisplayName,
11
+ getDefaultProviderOrder,
12
+ mergeProviderPreferences
13
+ } = require('../../utils/provider-registry');
14
+ const { getAutoConfig } = require('../../../utils/config');
15
+ const { checkAllProviders } = require('../../utils/provider-checker');
14
16
 
15
17
  /**
16
18
  * CLI list agents command implementation
@@ -21,28 +23,12 @@ class ListAgentsCommand {
21
23
  * @param {Object} options - Command options
22
24
  */
23
25
  constructor(options = {}) {
24
- this.configManager = options.configManager || new AgentConfigManager();
25
- this.logger = options.logger || new AgentLogger({
26
- fileManager: new FileManager()
27
- });
28
- this.fileManager = options.fileManager || new FileManager();
29
-
30
- // Initialize RUI components
31
- this.agentCommands = new AgentCommands({
32
- configManager: this.configManager,
33
- logger: this.logger,
34
- fileManager: this.fileManager
35
- });
36
-
37
- this.responseFormatter = new AgentResponseFormatter({
38
- defaultFormat: 'table',
39
- includeTimestamp: true,
40
- prettyPrint: options.pretty !== false
41
- });
26
+ this.config = getAutoConfig();
27
+ this.providerPreferences = this.config.providerPreferences || {};
42
28
  }
43
29
 
44
30
  /**
45
- * Execute list agents command using RUI pattern
31
+ * Execute list agents command using provider registry (matches GUI)
46
32
  * @param {Object} args - Command arguments
47
33
  * @param {Object} options - Command options
48
34
  * @returns {Promise<Object>} - Command result
@@ -57,25 +43,45 @@ class ListAgentsCommand {
57
43
  } = this.parseArguments(args, options);
58
44
 
59
45
  try {
60
- // Load configuration
61
- await this.configManager.load();
62
-
63
- // Execute using RUI pattern
64
- const ruiResult = await this.agentCommands.executeCommand('LIST', 'agents', {
65
- includeDisabled,
66
- includeStatus
67
- });
46
+ // Get provider definitions (same source as GUI)
47
+ const definitions = getProviderDefinitions();
48
+ const prefs = this.providerPreferences;
49
+ let order = Array.isArray(prefs.order) ? prefs.order.slice() : getDefaultProviderOrder();
50
+ let enabled = { ...prefs.enabled };
51
+
52
+ // Filter agents based on preferences
53
+ let agents = definitions.map(def => ({
54
+ id: def.id,
55
+ name: getProviderDisplayName(def.id),
56
+ description: def.description || '',
57
+ type: def.type || 'unknown',
58
+ enabled: enabled[def.id] !== false,
59
+ category: def.category || 'unknown',
60
+ estimatedSpeed: def.estimatedSpeed || 0
61
+ }));
62
+
63
+ // Apply disabled filter
64
+ if (!includeDisabled) {
65
+ agents = agents.filter(agent => agent.enabled);
66
+ }
68
67
 
69
- // Format response for CLI
70
- const formattedResponse = this.responseFormatter.format(ruiResult, 'cli', {
71
- format,
72
- sortBy,
73
- filterStatus
74
- });
68
+ // Add status information if requested
69
+ if (includeStatus) {
70
+ const { getProviderCache } = require('../../utils/provider-registry');
71
+ const savedCache = await getProviderCache();
72
+
73
+ agents = agents.map(agent => ({
74
+ ...agent,
75
+ installed: savedCache[agent.id]?.installed || false,
76
+ status: savedCache[agent.id]?.installed ?
77
+ (agent.enabled ? 'ENABLED' : 'DISABLED') :
78
+ 'NOT_INSTALLED',
79
+ statusDescription: savedCache[agent.id]?.installed ?
80
+ (agent.enabled ? 'Enabled' : 'Disabled') :
81
+ 'Not installed'
82
+ }));
83
+ }
75
84
 
76
- // Apply additional filtering and sorting
77
- let agents = formattedResponse.data?.agents || [];
78
-
79
85
  // Apply status filter
80
86
  if (filterStatus) {
81
87
  agents = agents.filter(agent => agent.status === filterStatus);
@@ -88,9 +94,8 @@ class ListAgentsCommand {
88
94
  this.outputResults(agents, format, includeStatus);
89
95
 
90
96
  return {
91
- success: ruiResult.success,
97
+ success: true,
92
98
  agents,
93
- formatted: formattedResponse,
94
99
  count: agents.length,
95
100
  message: `Listed ${agents.length} agents`
96
101
  };
@@ -179,24 +184,20 @@ class ListAgentsCommand {
179
184
  }
180
185
 
181
186
  /**
182
- * Filter agents by status
183
- * @param {Array<Object>} agents - Agents to filter
184
- * @param {string} status - Status to filter by
185
- * @returns {Promise<Array>} - Filtered agents
187
+ * Get status description
188
+ * @param {string} status - Status code
189
+ * @returns {string} - Human-readable description
186
190
  */
187
- async filterAgentsByStatus(agents, status) {
188
- const filteredAgents = [];
189
-
190
- for (const agent of agents) {
191
- const agentStatus = await this.configManager.getAgentStatus(agent.id);
192
- const currentStatus = agentStatus ? agentStatus.status : AgentStatus.NOT_INSTALLED;
193
-
194
- if (currentStatus === status) {
195
- filteredAgents.push(agent);
196
- }
197
- }
198
-
199
- return filteredAgents;
191
+ getStatusDescription(status) {
192
+ const descriptions = {
193
+ 'NOT_INSTALLED': 'Not installed',
194
+ 'ENABLED': 'Enabled',
195
+ 'DISABLED': 'Disabled',
196
+ 'ERROR': 'Error occurred',
197
+ 'RATE_LIMITED': 'Rate limited'
198
+ };
199
+
200
+ return descriptions[status] || 'Unknown';
200
201
  }
201
202
 
202
203
  /**
@@ -222,52 +223,7 @@ class ListAgentsCommand {
222
223
  });
223
224
  }
224
225
 
225
- /**
226
- * Add status information to agents
227
- * @param {Array<Object>} agents - Agents to enhance
228
- * @returns {Promise<Array>} - Agents with status info
229
- */
230
- async addStatusInfo(agents) {
231
- const agentsWithStatus = [];
232
-
233
- for (const agent of agents) {
234
- const status = await this.configManager.getAgentStatus(agent.id);
235
-
236
- agentsWithStatus.push({
237
- ...agent,
238
- status: status ? status.status : AgentStatus.NOT_INSTALLED,
239
- statusDescription: this.getStatusDescription(status ? status.status : AgentStatus.NOT_INSTALLED),
240
- lastChecked: status ? status.lastChecked : null,
241
- lastVerified: status ? status.lastVerified : null,
242
- statusMessage: status ? status.message : '',
243
- canInstall: agent.enabled && (!status || status.status === AgentStatus.NOT_INSTALLED),
244
- canVerify: agent.enabled && status && [AgentStatus.INSTALLED, AgentStatus.VERIFIED].includes(status.status)
245
- });
246
- }
247
-
248
- return agentsWithStatus;
249
- }
250
-
251
- /**
252
- * Get status description
253
- * @param {string} status - Status code
254
- * @returns {string} - Human-readable description
255
- */
256
- getStatusDescription(status) {
257
- const descriptions = {
258
- [AgentStatus.NOT_INSTALLED]: 'Not installed',
259
- [AgentStatus.INSTALLING]: 'Installing...',
260
- [AgentStatus.INSTALLED]: 'Installed (not verified)',
261
- [AgentStatus.VERIFYING]: 'Verifying...',
262
- [AgentStatus.VERIFIED]: 'Verified and ready',
263
- [AgentStatus.ERROR]: 'Error occurred',
264
- [AgentStatus.RATE_LIMITED]: 'Rate limited',
265
- [AgentStatus.DISABLED]: 'Disabled'
266
- };
267
-
268
- return descriptions[status] || 'Unknown';
269
- }
270
-
226
+
271
227
  /**
272
228
  * Output results in specified format
273
229
  * @param {Array} agents - Agents to output
@@ -393,7 +349,7 @@ class ListAgentsCommand {
393
349
  */
394
350
  showHelp() {
395
351
  console.log('\n=== LIST AGENTS COMMAND ===');
396
- console.log('Description: List all configured agents');
352
+ console.log('Description: List all available agents (providers)');
397
353
  console.log('');
398
354
  console.log('Usage: app list agents [options]');
399
355
  console.log('');
@@ -401,15 +357,15 @@ class ListAgentsCommand {
401
357
  console.log(' --all, -a Include disabled agents');
402
358
  console.log(' --no-status Exclude status information');
403
359
  console.log(' --format <format> Output format: table, json, csv (default: table)');
404
- console.log(' --sort <field> Sort by: name, status, type, priority (default: name)');
405
- console.log(' --status <status> Filter by status (NOT_INSTALLED, INSTALLING, etc.)');
360
+ console.log(' --sort <field> Sort by: name, status, type, category (default: name)');
361
+ console.log(' --status <status> Filter by status (NOT_INSTALLED, ENABLED, DISABLED, etc.)');
406
362
  console.log('');
407
363
  console.log('Examples:');
408
364
  console.log(' app list agents');
409
365
  console.log(' app list agents --all');
410
366
  console.log(' app list agents --format json');
411
367
  console.log(' app list agents --sort status');
412
- console.log(' app list agents --status VERIFIED');
368
+ console.log(' app list agents --status ENABLED');
413
369
  }
414
370
 
415
371
  /**
@@ -419,14 +375,14 @@ class ListAgentsCommand {
419
375
  getCommandInfo() {
420
376
  return {
421
377
  name: 'list-agents',
422
- description: 'List all configured agents',
378
+ description: 'List all available agents (providers)',
423
379
  usage: 'app list agents [options]',
424
380
  examples: [
425
381
  'app list agents',
426
382
  'app list agents --all',
427
383
  'app list agents --format json',
428
384
  'app list agents --sort status',
429
- 'app list agents --status VERIFIED'
385
+ 'app list agents --status ENABLED'
430
386
  ],
431
387
  options: [
432
388
  {
@@ -443,11 +399,11 @@ class ListAgentsCommand {
443
399
  },
444
400
  {
445
401
  flag: '--sort <field>',
446
- description: 'Sort by: name, status, type, priority (default: name)'
402
+ description: 'Sort by: name, status, type, category (default: name)'
447
403
  },
448
404
  {
449
405
  flag: '--status <status>',
450
- description: 'Filter by status (NOT_INSTALLED, INSTALLING, etc.)'
406
+ description: 'Filter by status (NOT_INSTALLED, ENABLED, DISABLED, etc.)'
451
407
  }
452
408
  ]
453
409
  };
@@ -8,12 +8,24 @@ const { checkAllProviders, formatCheckedAt } = require('../utils/provider-checke
8
8
  async function checkAgents(options = {}) {
9
9
  const config = await getAutoConfig();
10
10
  const definitions = getProviderDefinitions();
11
- const providerIds = options.provider
12
- ? definitions.filter(d => d.id === options.provider).map(d => d.id)
13
- : definitions.map(d => d.id);
11
+ const { getProviderPreferences } = require('../utils/provider-registry');
12
+ const prefs = await getProviderPreferences();
13
+
14
+ // Only check enabled providers unless a specific provider is requested
15
+ let providerIds;
16
+ if (options.enabledOnly && options.enabledAgents) {
17
+ // Use the enabled agents from the provider manager context
18
+ providerIds = definitions.filter(d => options.enabledAgents[d.id] !== false).map(d => d.id);
19
+ } else if (options.provider) {
20
+ providerIds = definitions.filter(d => d.id === options.provider).map(d => d.id);
21
+ } else {
22
+ // Use global enabled preferences
23
+ const prefs = await getProviderPreferences();
24
+ providerIds = definitions.filter(d => prefs.enabled[d.id] !== false).map(d => d.id);
25
+ }
14
26
 
15
27
  if (providerIds.length === 0) {
16
- console.log(chalk.red(`\n✗ Unknown provider: ${options.provider}\n`));
28
+ console.log(chalk.red(`\n✗ No enabled agents to check. Enable agents first.\n`));
17
29
  return;
18
30
  }
19
31
 
@@ -19,7 +19,7 @@ const { StrategyGenerator } = require('@vibecodingmachine/core/src/analysis/stra
19
19
  const { PriorityCalculator } = require('@vibecodingmachine/core/src/analysis/priority-calculator');
20
20
  const { AnalysisReporter } = require('@vibecodingmachine/core/src/analysis/analysis-reporter');
21
21
  const { FileAnalysis } = require('@vibecodingmachine/core/src/models/file-analysis');
22
- const { FileAnalysisCollection } = require('@vibecodingmachine/core/src/models/file-analysis');
22
+ const { FileAnalysisCollection } = require('@vibecodingmachine/core/src/models/file-analysis-collection');
23
23
 
24
24
  /**
25
25
  * Analyze file sizes command
@@ -0,0 +1,290 @@
1
+ /**
2
+ * Auto Mode Provider Management
3
+ *
4
+ * Handles LLM provider configuration and management for auto mode
5
+ */
6
+
7
+ const vibecodingmachineCore = require('vibecodingmachine-core');
8
+ const { getProviderPreferences, getProviderDefinition, saveProviderPreferences } = require('../../utils/provider-registry');
9
+ const ProviderManager = require('vibecodingmachine-core/src/ide-integration/provider-manager.cjs');
10
+ const { checkAntigravityRateLimit, handleAntigravityRateLimit } = require('../../utils/antigravity-js-handler');
11
+ const { checkKiroRateLimit, handleKiroRateLimit } = require('../../utils/kiro-js-handler');
12
+ const { checkClineRateLimit, handleClineRateLimit } = require('../../utils/cline-js-handler');
13
+ const { DirectLLMManager } = vibecodingmachineCore;
14
+
15
+ // Shared instances to track rate limits and health across all function calls
16
+ const sharedProviderManager = new ProviderManager();
17
+ const sharedHealthTracker = vibecodingmachineCore.IDEHealthTracker;
18
+
19
+ /**
20
+ * Auto-install Cline CLI if not available
21
+ */
22
+ async function ensureClineInstalled(forceInstall = false) {
23
+ const llm = new DirectLLMManager();
24
+
25
+ try {
26
+ const isAvailable = await llm.isClineAvailable();
27
+ if (isAvailable && !forceInstall) {
28
+ return true;
29
+ }
30
+
31
+ console.log('Installing Cline CLI...');
32
+ const installResult = await llm.installCline();
33
+
34
+ if (installResult.success) {
35
+ console.log('✓ Cline CLI installed successfully');
36
+ return true;
37
+ } else {
38
+ console.error('✗ Failed to install Cline CLI:', installResult.error);
39
+ return false;
40
+ }
41
+ } catch (error) {
42
+ console.error('✗ Error installing Cline CLI:', error.message);
43
+ return false;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Get all available provider configurations
49
+ */
50
+ async function getAllAvailableProviders() {
51
+ const config = await vibecodingmachineCore.getAutoConfig();
52
+ const prefs = await getProviderPreferences();
53
+
54
+ const providers = [];
55
+ const skipped = [];
56
+
57
+ // Check each provider in configuration
58
+ for (const [providerName, providerConfig] of Object.entries(config.providers || {})) {
59
+ if (!providerConfig.enabled) {
60
+ skipped.push({ provider: providerName, reason: 'disabled' });
61
+ continue;
62
+ }
63
+
64
+ // Check if provider is skipped in preferences
65
+ if (prefs.skippedProviders && prefs.skippedProviders.includes(providerName)) {
66
+ skipped.push({ provider: providerName, reason: 'user_skipped' });
67
+ continue;
68
+ }
69
+
70
+ // Check provider-specific requirements
71
+ let canUse = true;
72
+ let reason = null;
73
+
74
+ switch (providerName) {
75
+ case 'anthropic':
76
+ if (!providerConfig.apiKey) {
77
+ canUse = false;
78
+ reason = 'missing_api_key';
79
+ }
80
+ break;
81
+
82
+ case 'openai':
83
+ if (!providerConfig.apiKey) {
84
+ canUse = false;
85
+ reason = 'missing_api_key';
86
+ }
87
+ break;
88
+
89
+ case 'ollama':
90
+ if (!providerConfig.baseUrl) {
91
+ canUse = false;
92
+ reason = 'missing_base_url';
93
+ }
94
+ break;
95
+
96
+ case 'groq':
97
+ if (!providerConfig.apiKey) {
98
+ canUse = false;
99
+ reason = 'missing_api_key';
100
+ }
101
+ break;
102
+
103
+ case 'bedrock':
104
+ if (!providerConfig.region || !providerConfig.accessKeyId) {
105
+ canUse = false;
106
+ reason = 'missing_credentials';
107
+ }
108
+ break;
109
+ }
110
+
111
+ if (canUse) {
112
+ providers.push({
113
+ name: providerName,
114
+ config: providerConfig,
115
+ definition: await getProviderDefinition(providerName)
116
+ });
117
+ } else {
118
+ skipped.push({ provider: providerName, reason });
119
+ }
120
+ }
121
+
122
+ return { providers, skipped };
123
+ }
124
+
125
+ /**
126
+ * Get provider configuration with automatic failover
127
+ */
128
+ async function getProviderConfig(excludeProvider = null) {
129
+ const config = await vibecodingmachineCore.getAutoConfig();
130
+ const providerManager = sharedProviderManager; // Use shared instance to persist rate limit state
131
+ const { providers, skipped } = await getAllAvailableProviders();
132
+
133
+ // Filter out excluded provider
134
+ const availableProviders = providers.filter(p => p.name !== excludeProvider);
135
+
136
+ if (availableProviders.length === 0) {
137
+ throw new Error('No available providers. Check configuration and API keys.');
138
+ }
139
+
140
+ // Check each provider for rate limits and availability
141
+ for (const provider of availableProviders) {
142
+ const providerName = provider.name;
143
+
144
+ // Check provider-specific rate limits
145
+ let isRateLimited = false;
146
+ let rateLimitInfo = null;
147
+
148
+ switch (providerName) {
149
+ case 'antigravity':
150
+ isRateLimited = checkAntigravityRateLimit(providerManager);
151
+ if (isRateLimited) {
152
+ rateLimitInfo = handleAntigravityRateLimit(providerManager);
153
+ }
154
+ break;
155
+
156
+ case 'kiro':
157
+ isRateLimited = checkKiroRateLimit(providerManager);
158
+ if (isRateLimited) {
159
+ rateLimitInfo = handleKiroRateLimit(providerManager);
160
+ }
161
+ break;
162
+
163
+ case 'cline':
164
+ isRateLimited = checkClineRateLimit(providerManager);
165
+ if (isRateLimited) {
166
+ rateLimitInfo = handleClineRateLimit(providerManager);
167
+ }
168
+ break;
169
+ }
170
+
171
+ if (isRateLimited) {
172
+ console.warn(`Provider ${providerName} is rate limited:`, rateLimitInfo.message);
173
+ continue;
174
+ }
175
+
176
+ // Check IDE health for provider
177
+ const ideHealth = sharedHealthTracker.getHealth(providerName);
178
+ if (ideHealth && ideHealth.consecutiveFailures >= 3) {
179
+ console.warn(`Provider ${providerName} has ${ideHealth.consecutiveFailures} consecutive failures`);
180
+ continue;
181
+ }
182
+
183
+ // Return first available provider
184
+ return {
185
+ provider: providerName,
186
+ config: provider.config,
187
+ definition: provider.definition,
188
+ manager: providerManager
189
+ };
190
+ }
191
+
192
+ // If we get here, all providers are rate limited or unhealthy
193
+ const rateLimitedProviders = availableProviders.filter(p => {
194
+ switch (p.name) {
195
+ case 'antigravity': return checkAntigravityRateLimit(providerManager);
196
+ case 'kiro': return checkKiroRateLimit(providerManager);
197
+ case 'cline': return checkClineRateLimit(providerManager);
198
+ default: return false;
199
+ }
200
+ });
201
+
202
+ if (rateLimitedProviders.length > 0) {
203
+ const waitTime = Math.max(...rateLimitedProviders.map(p => {
204
+ switch (p.name) {
205
+ case 'antigravity': return handleAntigravityRateLimit(providerManager).waitTime || 60000;
206
+ case 'kiro': return handleKiroRateLimit(providerManager).waitTime || 60000;
207
+ case 'cline': return handleClineRateLimit(providerManager).waitTime || 60000;
208
+ default: return 60000;
209
+ }
210
+ }));
211
+
212
+ return {
213
+ action: 'wait',
214
+ waitTime,
215
+ message: `All providers are rate limited. Waiting ${waitTime/1000}s before retry.`
216
+ };
217
+ }
218
+
219
+ throw new Error('All providers are unavailable or unhealthy.');
220
+ }
221
+
222
+ /**
223
+ * Handle provider failure and update tracking
224
+ */
225
+ function handleProviderFailure(providerName, error) {
226
+ sharedHealthTracker.recordFailure(providerName, error);
227
+
228
+ // Mark provider as temporarily skipped if too many failures
229
+ const health = sharedHealthTracker.getHealth(providerName);
230
+ if (health && health.consecutiveFailures >= 3) {
231
+ console.warn(`Provider ${providerName} marked as temporarily unavailable due to failures`);
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Handle provider success and update tracking
237
+ */
238
+ function handleProviderSuccess(providerName) {
239
+ sharedHealthTracker.recordSuccess(providerName);
240
+ }
241
+
242
+ /**
243
+ * Check if provider should be skipped due to health issues
244
+ */
245
+ function shouldSkipProvider(providerName) {
246
+ const health = sharedHealthTracker.getHealth(providerName);
247
+ return health && health.consecutiveFailures >= 3;
248
+ }
249
+
250
+ /**
251
+ * Get provider health status
252
+ */
253
+ function getProviderHealth(providerName) {
254
+ return sharedHealthTracker.getHealth(providerName);
255
+ }
256
+
257
+ /**
258
+ * Get all providers health status
259
+ */
260
+ function getAllProvidersHealth() {
261
+ return sharedHealthTracker.getAllHealth();
262
+ }
263
+
264
+ /**
265
+ * Reset provider health tracking
266
+ */
267
+ function resetProviderHealth(providerName) {
268
+ sharedHealthTracker.reset(providerName);
269
+ }
270
+
271
+ // Listen for consecutive failures to warn user
272
+ sharedHealthTracker.on('consecutive-failures', ({ ideId, count, lastError }) => {
273
+ console.warn(`⚠️ Provider ${ideId} has ${count} consecutive failures`);
274
+ console.warn(` Last error: ${lastError.message}`);
275
+ console.warn(` Consider switching providers or checking configuration`);
276
+ });
277
+
278
+ module.exports = {
279
+ ensureClineInstalled,
280
+ getAllAvailableProviders,
281
+ getProviderConfig,
282
+ handleProviderFailure,
283
+ handleProviderSuccess,
284
+ shouldSkipProvider,
285
+ getProviderHealth,
286
+ getAllProvidersHealth,
287
+ resetProviderHealth,
288
+ sharedProviderManager,
289
+ sharedHealthTracker
290
+ };