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
@@ -1,257 +1,91 @@
1
1
  /**
2
- * TRUI Navigation — Main Menu
2
+ * TRUI Navigation — Main Menu (Refactored)
3
3
  *
4
4
  * Renders the status-rich main menu using showQuickMenu (raw keypress).
5
5
  * Status/settings lines shown in gray at top; action items in white below.
6
- * Dispatches to: Requirements tree, Provider manager, Settings, Spec creation.
6
+ * Uses inline accordion expansion for sections.
7
7
  * Now using RUI pattern for consistent command structure.
8
+ * Refactored to meet 555-line limit by extracting modules.
8
9
  */
9
10
 
10
11
  const chalk = require('chalk');
11
12
  const { showQuickMenu } = require('./trui-quick-menu');
12
- const { initializeWindsurfIntegration, getWindsurfStatus } = require('./trui-windsurf');
13
- const { debugLogger } = require('./trui-debug');
13
+ const { debugLogger, perfMonitor, stateTracker } = require('./trui-debug');
14
14
  const RUITRUIAdapter = require('./rui-trui-adapter');
15
15
 
16
- /**
17
- * Build main-menu items array with live status at top
18
- */
19
- async function buildMainMenuItems() {
20
- const items = [];
21
-
22
- // Auto Mode status
23
- let autoStatus = { running: false };
24
- try {
25
- const { checkAutoModeStatus } = require('./auto-mode');
26
- autoStatus = await checkAutoModeStatus();
27
- } catch (_) {}
28
-
29
- items.push({
30
- type: 'setting',
31
- name: `Auto Mode: ${autoStatus.running ? chalk.green('Running ✓') : chalk.yellow('Stopped ○')}`,
32
- value: 'setting:auto',
33
- });
34
-
35
- // Requirements summary
36
- try {
37
- const { countRequirements } = require('./status-helpers-extracted');
38
- const counts = await countRequirements();
39
- if (counts) {
40
- const total = (counts.todoCount || 0) + (counts.toVerifyCount || 0) + (counts.verifiedCount || 0);
41
- const pct = n => total > 0 ? Math.round((n / total) * 100) : 0;
42
- items.push({
43
- type: 'setting',
44
- name: `Requirements: ${chalk.yellow(counts.todoCount + ' todo')}, ${chalk.cyan(counts.toVerifyCount + ' verify')}, ${chalk.green(counts.verifiedCount + ' done')} (${pct(counts.verifiedCount)}% complete)`,
45
- value: 'setting:requirements',
46
- });
47
- }
48
- } catch (_) {}
49
-
50
- items.push({ type: 'blank', name: '', value: 'blank' });
16
+ // Import extracted modules
17
+ const {
18
+ buildMainMenuItems
19
+ } = require('./trui-main-menu');
51
20
 
52
- // Action items
53
- items.push({ type: 'action', name: '📋 Requirements', value: 'requirements' });
54
- items.push({ type: 'action', name: '🤖 Agents / Providers', value: 'agents' });
55
- items.push({ type: 'action', name: '⚙️ Settings', value: 'settings' });
56
- items.push({ type: 'action', name: '[+ Add Requirement]', value: 'add-req' });
57
- items.push({ type: 'action', name: '[+ Add Specification]', value: 'add-spec' });
58
- items.push({ type: 'action', name: '💬 Send Continue to Windsurf', value: 'continue-windsurf' });
59
- items.push({ type: 'action', name: '🔄 Sync Now', value: 'sync' });
60
- items.push({ type: 'action', name: 'Exit', value: 'exit' });
61
-
62
- return items;
63
- }
21
+ const {
22
+ handleMainMenuSelection,
23
+ setupMainMenuExtraKeys
24
+ } = require('./trui-main-handlers');
64
25
 
65
26
  /**
66
- * TRUINavigation main menu loop
27
+ * TRUI Navigation System
67
28
  */
68
29
  class TRUINavigation {
69
30
  constructor() {
70
- this._lastIndex = 0;
71
- this.ruiAdapter = new RUITRUIAdapter();
31
+ this.resolver = new RUITRUIAdapter();
32
+ this.expandedSections = {};
33
+ debugLogger.info('TRUINavigation initialized');
72
34
  }
73
35
 
36
+ /**
37
+ * Start the TRUI navigation system
38
+ */
74
39
  async start() {
75
- const { showWelcomeScreen } = require('./welcome-screen-extracted');
76
-
77
- console.clear();
78
- try { await showWelcomeScreen(); } catch (_) {}
79
-
80
- // Initialize Windsurf integration with error handling
40
+ perfMonitor.start('TRUINavigation.start');
41
+ stateTracker.push('TRUINavigation.start');
42
+
43
+ debugLogger.info('Starting TRUI navigation');
44
+
81
45
  try {
82
- initializeWindsurfIntegration();
46
+ await this._showMainMenu();
83
47
  } catch (error) {
84
- console.log(chalk.yellow(' Windsurf integration disabled: ' + error.message));
48
+ debugLogger.error('TRUI navigation error', { error: error.message });
49
+ console.log(chalk.red('Navigation error: ' + error.message));
50
+ await this._pause();
51
+ } finally {
52
+ perfMonitor.end('TRUINavigation.start');
53
+ stateTracker.pop();
85
54
  }
86
-
87
- await this._loop();
88
55
  }
89
56
 
90
- async _loop() {
91
- const {
92
- showRequirementsTree,
93
- } = require('./trui-req-tree');
94
- const { showProviderManagerMenu } = require('./provider-manager');
95
- const { showSettings } = require('./trui-nav-settings');
96
- const { addRequirementFlow } = require('./trui-req-actions');
97
- const { addSpecificationFlow } = require('./trui-nav-specifications');
98
- const { sendContinueToWindsurf } = require('./trui-windsurf');
99
- const { showFeedbackSubmission } = require('./trui-feedback');
100
- const { showSpecificationsList } = require('./trui-specifications');
57
+ /**
58
+ * Show main menu loop
59
+ */
60
+ async _showMainMenu() {
61
+ perfMonitor.start('TRUINavigation.loop');
62
+ stateTracker.push('TRUINavigation.loop');
101
63
 
102
64
  while (true) {
103
65
  try {
104
- const items = await buildMainMenuItems();
105
-
106
- // Extra keys handler for ! and 1 commands
107
- const extraKeys = (str, key, selectedIndex, context) => {
108
- if (str === '!' || str === '1') {
109
- // Run agents check command
110
- context.resolveWith('agents-check');
111
- return true;
112
- }
113
- return false;
114
- };
115
-
116
- const result = await showQuickMenu(items, this._lastIndex, extraKeys);
117
- this._lastIndex = result.selectedIndex;
118
- const action = result.value;
119
-
120
- if (action === '__cancel__' || action === 'exit') {
66
+ // Build menu items
67
+ const items = await buildMainMenuItems(this.expandedSections);
68
+
69
+ // Setup extra keyboard handlers
70
+ const extraKeys = setupMainMenuExtraKeys(items);
71
+
72
+ // Show menu
73
+ const result = await showQuickMenu(items, 0, { extraKeys });
74
+
75
+ // Handle selection
76
+ const handlerResult = await handleMainMenuSelection(
77
+ result,
78
+ this.expandedSections,
79
+ this
80
+ );
81
+
82
+ if (handlerResult.shouldExit) {
121
83
  await this._confirmExit();
122
- continue;
84
+ break;
123
85
  }
124
86
 
125
- // Dispatch to sub-modules
126
- try {
127
- if (action === 'setting:auto') {
128
- try {
129
- const { checkAutoModeStatus, stopAutoMode } = require('./auto-mode');
130
- const s = await checkAutoModeStatus();
131
- if (s.running) {
132
- await stopAutoMode('manual');
133
- console.log(chalk.yellow('\n⏹ Auto mode stopped\n'));
134
- await this._pause();
135
- console.clear();
136
- } else {
137
- console.log(chalk.bold.cyan('\n▶ Starting Auto Mode...\n'));
138
- try {
139
- const { getAutoConfig } = require('./config');
140
- const currentConfig = await getAutoConfig();
141
- // Pick first enabled provider
142
- const { getProviderPreferences } = require('./provider-registry');
143
- const prefs = await getProviderPreferences();
144
- let agentToUse = currentConfig.ide || currentConfig.agent || 'cline';
145
- for (const agentId of (prefs.order || [])) {
146
- if (prefs.enabled[agentId] !== false) { agentToUse = agentId; break; }
147
- }
148
- // Release raw mode before running auto (so Ctrl+C works)
149
- if (process.stdin.isTTY && process.stdin.setRawMode) {
150
- process.stdin.setRawMode(false);
151
- }
152
- const options = { ide: agentToUse };
153
- if (currentConfig.neverStop) {
154
- options.neverStop = true;
155
- } else if (currentConfig.maxChats) {
156
- options.maxChats = currentConfig.maxChats;
157
- } else {
158
- options.neverStop = true;
159
- }
160
- const { handleAutoStart } = require('../commands/auto-direct');
161
- await handleAutoStart(options);
162
- } catch (startErr) {
163
- if (startErr.message && startErr.message.includes('User force closed')) {
164
- console.log(chalk.yellow('\nCancelled\n'));
165
- } else {
166
- console.log(chalk.red(`\n✗ Error: ${startErr.message}`));
167
- if (startErr.stack) console.log(chalk.gray(startErr.stack.split('\n').slice(0, 8).join('\n')));
168
- console.log(chalk.yellow('\nReturning to menu in 5 seconds...'));
169
- await new Promise(r => setTimeout(r, 5000));
170
- }
171
- }
172
- await this._pause();
173
- console.clear();
174
- }
175
- } catch (err) { console.log(chalk.red('Error: ' + err.message)); await this._pause(); console.clear(); }
176
- continue;
177
- }
178
-
179
- if (action === 'requirements' || action === 'setting:requirements') {
180
- try { await showRequirementsTree(); } catch (err) { console.log(chalk.red('Requirements error: ' + err.message)); await this._pause(); }
181
- console.clear();
182
- continue;
183
- }
184
-
185
- if (action === 'agents') {
186
- try { await showProviderManagerMenu(); } catch (err) { console.log(chalk.red('Agents error: ' + err.message)); await this._pause(); }
187
- console.clear();
188
- continue;
189
- }
190
-
191
- if (action === 'agents-check') {
192
- try {
193
- const agentsCheckModule = require('../commands/agents-check');
194
- console.clear();
195
- console.log(chalk.bold.cyan('🔍 Checking agents...\n'));
196
- await agentsCheckModule();
197
- await this._pause();
198
- } catch (err) {
199
- console.log(chalk.red('Agents check error: ' + err.message));
200
- await this._pause();
201
- }
202
- console.clear();
203
- continue;
204
- }
205
-
206
- if (action === 'settings') {
207
- try { await showSettings(); } catch (err) { console.log(chalk.red('Settings error: ' + err.message)); await this._pause(); }
208
- console.clear();
209
- continue;
210
- }
211
-
212
- if (action === 'add-req') {
213
- try { await addRequirementFlow(); } catch (err) { console.log(chalk.red('Error: ' + err.message)); await this._pause(); }
214
- console.clear();
215
- continue;
216
- }
217
-
218
- if (action === 'add-spec') {
219
- try { await addSpecificationFlow(); } catch (err) { console.log(chalk.red('Error: ' + err.message)); await this._pause(); }
220
- console.clear();
221
- continue;
222
- }
223
-
224
- if (action === 'continue-windsurf') {
225
- try {
226
- await sendContinueToWindsurf();
227
- console.log(chalk.green('\n✓ Continue message sent to Windsurf Cascade\n'));
228
- } catch (err) { console.log(chalk.red('Error: ' + err.message)); }
229
- await this._pause();
230
- console.clear();
231
- continue;
232
- }
233
-
234
- if (action === 'sync') {
235
- try {
236
- const { execSync } = require('child_process');
237
- console.log(chalk.cyan('\n🔄 Syncing...\n'));
238
- execSync('vcm sync:now', { stdio: 'inherit' });
239
- } catch (_) { console.log(chalk.gray('vcm sync:now: command unavailable')); }
240
- await this._pause();
241
- console.clear();
242
- continue;
243
- }
244
-
245
- // Unknown action — show error
246
- console.log(chalk.yellow('Unknown action: ' + action));
247
- await this._pause();
248
- console.clear();
249
- continue;
250
- } catch (err) {
251
- console.log(chalk.red('Action error: ' + err.message));
252
- await this._pause();
253
- console.clear();
254
- continue;
87
+ if (!handlerResult.shouldContinue) {
88
+ break;
255
89
  }
256
90
 
257
91
  } catch (error) {
@@ -261,8 +95,14 @@ class TRUINavigation {
261
95
  continue;
262
96
  }
263
97
  }
98
+
99
+ perfMonitor.end('TRUINavigation.loop');
100
+ stateTracker.pop();
264
101
  }
265
102
 
103
+ /**
104
+ * Confirm exit with keyboard handling
105
+ */
266
106
  async _confirmExit() {
267
107
  console.clear();
268
108
  console.log(chalk.yellow('\nExit Vibe Coding Machine? (Y/n/x)\n'));
@@ -314,18 +154,20 @@ class TRUINavigation {
314
154
  });
315
155
  }
316
156
 
157
+ /**
158
+ * Pause for user input
159
+ */
317
160
  async _pause() {
318
161
  const inquirer = require('inquirer');
319
162
  await inquirer.prompt([{ type: 'input', name: 'c', message: chalk.gray('Press Enter to continue...') }]);
320
163
  }
321
164
 
165
+ /**
166
+ * Prompt user to continue
167
+ */
322
168
  async promptContinue() {
323
169
  await this._pause();
324
170
  }
325
171
  }
326
172
 
327
- module.exports = { TRUINavigation, buildMainMenuItems };
328
-
329
- // Export a singleton instance for use by other modules
330
- const navigationInstance = new TRUINavigation();
331
- module.exports.promptContinue = () => navigationInstance.promptContinue();
173
+ module.exports = { TRUINavigation };
@@ -0,0 +1,274 @@
1
+ /**
2
+ * TRUI Provider Health Module
3
+ *
4
+ * Monitors provider health metrics, quota information, and IDE detection.
5
+ */
6
+
7
+ const chalk = require('chalk');
8
+ const { debugLogger } = require('./trui-debug');
9
+
10
+ /**
11
+ * Get provider health metrics
12
+ */
13
+ async function getProviderHealth(provider) {
14
+ debugLogger.info('Getting provider health', { provider });
15
+
16
+ try {
17
+ const health = {
18
+ provider: provider.name || provider.id,
19
+ status: 'unknown',
20
+ lastCheck: new Date().toISOString(),
21
+ responseTime: null,
22
+ quota: null,
23
+ ideDetection: null,
24
+ errors: []
25
+ };
26
+
27
+ // Check basic connectivity
28
+ const startTime = Date.now();
29
+ try {
30
+ // Simulate health check - replace with actual provider ping
31
+ await checkProviderConnectivity(provider);
32
+ health.status = 'healthy';
33
+ health.responseTime = Date.now() - startTime;
34
+ } catch (error) {
35
+ health.status = 'unhealthy';
36
+ health.errors.push(error.message);
37
+ health.responseTime = Date.now() - startTime;
38
+ }
39
+
40
+ // Get quota information if available
41
+ health.quota = await getProviderQuota(provider);
42
+
43
+ // Check IDE integration
44
+ health.ideDetection = await checkIDEIntegration(provider);
45
+
46
+ debugLogger.info('Provider health retrieved', {
47
+ provider: health.provider,
48
+ status: health.status
49
+ });
50
+
51
+ return health;
52
+ } catch (error) {
53
+ debugLogger.error('Error getting provider health', { error: error.message });
54
+ return {
55
+ provider: provider.name || provider.id,
56
+ status: 'error',
57
+ lastCheck: new Date().toISOString(),
58
+ errors: [error.message]
59
+ };
60
+ }
61
+ }
62
+
63
+ /**
64
+ * Check provider connectivity
65
+ */
66
+ async function checkProviderConnectivity(provider) {
67
+ // Simulate connectivity check
68
+ // In real implementation, this would ping the provider API
69
+ return new Promise((resolve, reject) => {
70
+ setTimeout(() => {
71
+ if (Math.random() > 0.1) { // 90% success rate
72
+ resolve();
73
+ } else {
74
+ reject(new Error('Connection timeout'));
75
+ }
76
+ }, Math.random() * 1000 + 500); // 500-1500ms delay
77
+ });
78
+ }
79
+
80
+ /**
81
+ * Get provider quota information
82
+ */
83
+ async function getProviderQuota(provider) {
84
+ // Simulate quota check
85
+ // In real implementation, this would query provider API
86
+ const quotas = {
87
+ 'claude': { used: 45, limit: 100, resetTime: '2024-01-01T00:00:00Z' },
88
+ 'gpt': { used: 120, limit: 500, resetTime: '2024-01-01T00:00:00Z' },
89
+ 'cline': { used: 23, limit: 50, resetTime: '2024-01-01T00:00:00Z' }
90
+ };
91
+
92
+ return quotas[provider.id] || { used: 0, limit: 0, resetTime: null };
93
+ }
94
+
95
+ /**
96
+ * Check IDE integration for provider
97
+ */
98
+ async function checkIDEIntegration(provider) {
99
+ const detections = {
100
+ 'vscode': await checkVSCodeExtension(provider),
101
+ 'cursor': await checkCursorIntegration(provider),
102
+ 'windsurf': await checkWindsurfIntegration(provider)
103
+ };
104
+
105
+ return detections;
106
+ }
107
+
108
+ /**
109
+ * Check VS Code extension for provider
110
+ */
111
+ async function checkVSCodeExtension(provider) {
112
+ try {
113
+ const fs = require('fs');
114
+ const path = require('path');
115
+ const os = require('os');
116
+
117
+ const vscodeDir = path.join(os.homedir(), '.vscode', 'extensions');
118
+ if (!fs.existsSync(vscodeDir)) {
119
+ return { installed: false, reason: 'VS Code not found' };
120
+ }
121
+
122
+ const extensions = fs.readdirSync(vscodeDir);
123
+ const providerExtensions = {
124
+ 'claude': ['ms-vscode.cpptools', 'ms-vscode.python'],
125
+ 'gpt': ['github.copilot'],
126
+ 'cline': ['saoudrizwan.claude-dev']
127
+ };
128
+
129
+ const relevantExtensions = extensions.filter(ext =>
130
+ (providerExtensions[provider.id] || []).some(prefix => ext.startsWith(prefix))
131
+ );
132
+
133
+ return {
134
+ installed: relevantExtensions.length > 0,
135
+ extensions: relevantExtensions,
136
+ count: relevantExtensions.length
137
+ };
138
+ } catch (error) {
139
+ return { installed: false, reason: error.message };
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Check Cursor integration for provider
145
+ */
146
+ async function checkCursorIntegration(provider) {
147
+ try {
148
+ const fs = require('fs');
149
+ const path = require('path');
150
+ const os = require('os');
151
+
152
+ const cursorDir = path.join(os.homedir(), '.cursor');
153
+ const hasCursor = fs.existsSync(cursorDir);
154
+
155
+ return {
156
+ installed: hasCursor,
157
+ path: hasCursor ? cursorDir : null
158
+ };
159
+ } catch (error) {
160
+ return { installed: false, reason: error.message };
161
+ }
162
+ }
163
+
164
+ /**
165
+ * Check Windsurf integration for provider
166
+ */
167
+ async function checkWindsurfIntegration(provider) {
168
+ try {
169
+ const fs = require('fs');
170
+ const path = require('path');
171
+ const os = require('os');
172
+
173
+ const windsurfDir = path.join(os.homedir(), '.windsurf');
174
+ const hasWindsurf = fs.existsSync(windsurfDir);
175
+
176
+ return {
177
+ installed: hasWindsurf,
178
+ path: hasWindsurf ? windsurfDir : null
179
+ };
180
+ } catch (error) {
181
+ return { installed: false, reason: error.message };
182
+ }
183
+ }
184
+
185
+ /**
186
+ * Get health status icon
187
+ */
188
+ function getHealthIcon(status) {
189
+ switch (status) {
190
+ case 'healthy': return '🟢';
191
+ case 'unhealthy': return '🔴';
192
+ case 'degraded': return '🟡';
193
+ case 'unknown': return '⚪';
194
+ case 'error': return '❌';
195
+ default: return '❓';
196
+ }
197
+ }
198
+
199
+ /**
200
+ * Get quota percentage
201
+ */
202
+ function getQuotaPercentage(quota) {
203
+ if (!quota || quota.limit === 0) return 0;
204
+ return Math.round((quota.used / quota.limit) * 100);
205
+ }
206
+
207
+ /**
208
+ * Get quota color based on usage
209
+ */
210
+ function getQuotaColor(percentage) {
211
+ if (percentage >= 90) return chalk.red;
212
+ if (percentage >= 75) return chalk.yellow;
213
+ return chalk.green;
214
+ }
215
+
216
+ /**
217
+ * Format health display for provider
218
+ */
219
+ function formatHealthDisplay(health) {
220
+ const lines = [];
221
+
222
+ // Status
223
+ lines.push(`${getHealthIcon(health.status)} ${health.provider} - ${health.status}`);
224
+
225
+ // Response time
226
+ if (health.responseTime !== null) {
227
+ const timeColor = health.responseTime < 1000 ? chalk.green :
228
+ health.responseTime < 3000 ? chalk.yellow : chalk.red;
229
+ lines.push(` Response Time: ${timeColor(health.responseTime + 'ms')}`);
230
+ }
231
+
232
+ // Quota information
233
+ if (health.quota && health.quota.limit > 0) {
234
+ const percentage = getQuotaPercentage(health.quota);
235
+ const color = getQuotaColor(percentage);
236
+ lines.push(` Quota: ${color(health.quota.used + '/' + health.quota.limit + ' (' + percentage + '%)')}`);
237
+ }
238
+
239
+ // IDE detection
240
+ if (health.ideDetection) {
241
+ const ideCount = Object.values(health.ideDetection).filter(ide => ide.installed).length;
242
+ lines.push(` IDE Integration: ${ideCount} IDE(s) detected`);
243
+
244
+ Object.entries(health.ideDetection).forEach(([ide, detection]) => {
245
+ if (detection.installed) {
246
+ lines.push(` ${ide}: ✅`);
247
+ }
248
+ });
249
+ }
250
+
251
+ // Errors
252
+ if (health.errors && health.errors.length > 0) {
253
+ lines.push(` Errors: ${chalk.red(health.errors.length)} error(s)`);
254
+ health.errors.forEach(error => {
255
+ lines.push(` ${chalk.red('•')} ${error}`);
256
+ });
257
+ }
258
+
259
+ return lines;
260
+ }
261
+
262
+ module.exports = {
263
+ getProviderHealth,
264
+ checkProviderConnectivity,
265
+ getProviderQuota,
266
+ checkIDEIntegration,
267
+ checkVSCodeExtension,
268
+ checkCursorIntegration,
269
+ checkWindsurfIntegration,
270
+ getHealthIcon,
271
+ getQuotaPercentage,
272
+ getQuotaColor,
273
+ formatHealthDisplay
274
+ };