vibecodingmachine-cli 2026.2.26-1752 → 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.
- package/bin/auth/auth-compliance.js +7 -1
- package/bin/commands/agent-commands.js +150 -228
- package/bin/commands/command-aliases.js +68 -0
- package/bin/vibecodingmachine.js +1 -2
- package/package.json +2 -2
- package/src/commands/agents/list.js +71 -115
- package/src/commands/agents-check.js +16 -4
- package/src/commands/analyze-file-sizes.js +1 -1
- package/src/commands/auto-direct/auto-provider-manager.js +290 -0
- package/src/commands/auto-direct/auto-status-display.js +331 -0
- package/src/commands/auto-direct/auto-utils.js +439 -0
- package/src/commands/auto-direct/file-operations.js +110 -0
- package/src/commands/auto-direct/provider-config.js +1 -1
- package/src/commands/auto-direct/provider-manager.js +1 -1
- package/src/commands/auto-direct/status-display.js +1 -1
- package/src/commands/auto-direct/utils.js +24 -18
- package/src/commands/auto-direct-refactored.js +413 -0
- package/src/commands/auto-direct.js +594 -188
- package/src/commands/requirements/commands.js +353 -0
- package/src/commands/requirements/default-handlers.js +272 -0
- package/src/commands/requirements/disable.js +97 -0
- package/src/commands/requirements/enable.js +97 -0
- package/src/commands/requirements/utils.js +194 -0
- package/src/commands/requirements-refactored.js +60 -0
- package/src/commands/requirements.js +38 -771
- package/src/commands/specs/disable.js +96 -0
- package/src/commands/specs/enable.js +96 -0
- package/src/trui/TruiInterface.js +5 -11
- package/src/trui/agents/AgentInterface.js +24 -396
- package/src/trui/agents/handlers/CommandHandler.js +93 -0
- package/src/trui/agents/handlers/ContextManager.js +117 -0
- package/src/trui/agents/handlers/DisplayHandler.js +243 -0
- package/src/trui/agents/handlers/HelpHandler.js +51 -0
- package/src/utils/auth.js +13 -111
- package/src/utils/config.js +4 -0
- package/src/utils/interactive/requirements-navigation.js +17 -15
- package/src/utils/interactive-broken.js +2 -2
- package/src/utils/provider-checker/agent-runner.js +15 -1
- package/src/utils/provider-checker/cli-installer.js +149 -7
- package/src/utils/provider-checker/opencode-checker.js +588 -0
- package/src/utils/provider-checker/provider-validator.js +88 -3
- package/src/utils/provider-checker/time-formatter.js +3 -2
- package/src/utils/provider-manager.js +28 -20
- package/src/utils/provider-registry.js +35 -3
- package/src/utils/requirements-navigator/index.js +94 -0
- package/src/utils/requirements-navigator/input-handler.js +217 -0
- package/src/utils/requirements-navigator/section-loader.js +188 -0
- package/src/utils/requirements-navigator/tree-builder.js +105 -0
- package/src/utils/requirements-navigator/tree-renderer.js +50 -0
- package/src/utils/requirements-navigator.js +2 -583
- package/src/utils/trui-clarifications.js +188 -0
- package/src/utils/trui-feedback.js +54 -1
- package/src/utils/trui-kiro-integration.js +398 -0
- package/src/utils/trui-main-handlers.js +194 -0
- package/src/utils/trui-main-menu.js +235 -0
- package/src/utils/trui-nav-agents.js +178 -25
- package/src/utils/trui-nav-requirements.js +203 -27
- package/src/utils/trui-nav-settings.js +114 -1
- package/src/utils/trui-nav-specifications.js +44 -3
- package/src/utils/trui-navigation-backup.js +603 -0
- package/src/utils/trui-navigation.js +70 -228
- package/src/utils/trui-provider-health.js +274 -0
- package/src/utils/trui-provider-manager.js +376 -0
- package/src/utils/trui-quick-menu.js +25 -1
- package/src/utils/trui-req-actions-backup.js +507 -0
- package/src/utils/trui-req-actions.js +148 -216
- package/src/utils/trui-req-editor.js +170 -0
- package/src/utils/trui-req-file-ops.js +278 -0
- package/src/utils/trui-req-tree-old.js +719 -0
- package/src/utils/trui-req-tree.js +348 -627
- package/src/utils/trui-specifications.js +25 -7
- package/src/utils/trui-windsurf.js +231 -10
- package/src/utils/welcome-screen-extracted.js +2 -2
- 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
|
-
*
|
|
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 {
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
*
|
|
27
|
+
* TRUI Navigation System
|
|
67
28
|
*/
|
|
68
29
|
class TRUINavigation {
|
|
69
30
|
constructor() {
|
|
70
|
-
this.
|
|
71
|
-
this.
|
|
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
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
|
|
46
|
+
await this._showMainMenu();
|
|
83
47
|
} catch (error) {
|
|
84
|
-
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (
|
|
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
|
-
|
|
84
|
+
break;
|
|
123
85
|
}
|
|
124
86
|
|
|
125
|
-
|
|
126
|
-
|
|
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
|
|
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
|
+
};
|