baseguard 1.0.5 → 1.0.6

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 (80) hide show
  1. package/dist/ai/gemini-analyzer.d.ts.map +1 -1
  2. package/dist/ai/gemini-analyzer.js +1 -1
  3. package/dist/ai/gemini-analyzer.js.map +1 -1
  4. package/dist/ai/gemini-code-fixer.d.ts.map +1 -1
  5. package/dist/ai/gemini-code-fixer.js +2 -7
  6. package/dist/ai/gemini-code-fixer.js.map +1 -1
  7. package/dist/ai/jules-implementer.d.ts +8 -0
  8. package/dist/ai/jules-implementer.d.ts.map +1 -1
  9. package/dist/ai/jules-implementer.js +115 -17
  10. package/dist/ai/jules-implementer.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/ai/__tests__/gemini-analyzer.test.ts +0 -181
  13. package/src/ai/agentkit-orchestrator.ts +0 -534
  14. package/src/ai/fix-manager.ts +0 -362
  15. package/src/ai/gemini-analyzer.ts +0 -665
  16. package/src/ai/gemini-code-fixer.ts +0 -539
  17. package/src/ai/index.ts +0 -4
  18. package/src/ai/jules-implementer.ts +0 -504
  19. package/src/ai/unified-code-fixer.ts +0 -347
  20. package/src/commands/automation.ts +0 -344
  21. package/src/commands/check.ts +0 -298
  22. package/src/commands/config.ts +0 -584
  23. package/src/commands/fix.ts +0 -269
  24. package/src/commands/index.ts +0 -7
  25. package/src/commands/init.ts +0 -156
  26. package/src/commands/status.ts +0 -307
  27. package/src/core/api-key-manager.ts +0 -298
  28. package/src/core/baseguard.ts +0 -757
  29. package/src/core/baseline-checker.ts +0 -566
  30. package/src/core/cache-manager.ts +0 -272
  31. package/src/core/configuration-recovery.ts +0 -672
  32. package/src/core/configuration.ts +0 -596
  33. package/src/core/debug-logger.ts +0 -590
  34. package/src/core/directory-filter.ts +0 -421
  35. package/src/core/error-handler.ts +0 -518
  36. package/src/core/file-processor.ts +0 -338
  37. package/src/core/gitignore-manager.ts +0 -169
  38. package/src/core/graceful-degradation-manager.ts +0 -596
  39. package/src/core/index.ts +0 -17
  40. package/src/core/lazy-loader.ts +0 -317
  41. package/src/core/logger.ts +0 -0
  42. package/src/core/memory-manager.ts +0 -290
  43. package/src/core/parser-worker.ts +0 -33
  44. package/src/core/startup-optimizer.ts +0 -246
  45. package/src/core/system-error-handler.ts +0 -755
  46. package/src/git/automation-engine.ts +0 -361
  47. package/src/git/github-manager.ts +0 -190
  48. package/src/git/hook-manager.ts +0 -210
  49. package/src/git/index.ts +0 -4
  50. package/src/index.ts +0 -8
  51. package/src/parsers/feature-validator.ts +0 -559
  52. package/src/parsers/index.ts +0 -8
  53. package/src/parsers/parser-manager.ts +0 -418
  54. package/src/parsers/parser.ts +0 -26
  55. package/src/parsers/react-parser-optimized.ts +0 -161
  56. package/src/parsers/react-parser.ts +0 -359
  57. package/src/parsers/svelte-parser.ts +0 -510
  58. package/src/parsers/vanilla-parser.ts +0 -685
  59. package/src/parsers/vue-parser.ts +0 -476
  60. package/src/types/index.ts +0 -96
  61. package/src/ui/components.ts +0 -567
  62. package/src/ui/help.ts +0 -193
  63. package/src/ui/index.ts +0 -4
  64. package/src/ui/prompts.ts +0 -681
  65. package/src/ui/terminal-header.ts +0 -59
  66. package/tests/e2e/baseguard.e2e.test.ts +0 -516
  67. package/tests/e2e/cross-platform.e2e.test.ts +0 -420
  68. package/tests/e2e/git-integration.e2e.test.ts +0 -487
  69. package/tests/fixtures/react-project/package.json +0 -14
  70. package/tests/fixtures/react-project/src/App.css +0 -76
  71. package/tests/fixtures/react-project/src/App.tsx +0 -77
  72. package/tests/fixtures/svelte-project/package.json +0 -11
  73. package/tests/fixtures/svelte-project/src/App.svelte +0 -369
  74. package/tests/fixtures/vanilla-project/index.html +0 -76
  75. package/tests/fixtures/vanilla-project/script.js +0 -331
  76. package/tests/fixtures/vanilla-project/styles.css +0 -359
  77. package/tests/fixtures/vue-project/package.json +0 -12
  78. package/tests/fixtures/vue-project/src/App.vue +0 -216
  79. package/tmp-smoke/.baseguard/backups/config-2026-02-19T12-04-11-067Z-auto.json +0 -30
  80. package/tmp-smoke/src/bad.css +0 -3
@@ -1,307 +0,0 @@
1
- import { BaseGuard } from '../core/baseguard.js';
2
- import { ConfigurationManager } from '../core/configuration.js';
3
- import { ConfigurationRecovery } from '../core/configuration-recovery.js';
4
- import { GracefulDegradationManager } from '../core/graceful-degradation-manager.js';
5
- import { SystemErrorHandler } from '../core/system-error-handler.js';
6
- import { logger } from '../core/debug-logger.js';
7
- import { UIComponents } from '../ui/components.js';
8
- import chalk from 'chalk';
9
-
10
- /**
11
- * Show BaseGuard system status and health
12
- */
13
- export async function status(options: {
14
- verbose?: boolean;
15
- services?: boolean;
16
- config?: boolean;
17
- errors?: boolean;
18
- }): Promise<void> {
19
- const categoryLogger = logger.createCategoryLogger('status-command');
20
-
21
- try {
22
- UIComponents.showHeader();
23
- console.log(chalk.cyan('🔍 BaseGuard System Status\n'));
24
-
25
- // Load configuration with recovery if needed
26
- let config;
27
- try {
28
- config = await ConfigurationManager.load();
29
- } catch (error) {
30
- console.log(chalk.red('❌ Configuration Error'));
31
- console.log(chalk.dim(` ${error instanceof Error ? error.message : 'Unknown error'}`));
32
-
33
- if (options.config) {
34
- console.log(chalk.cyan('\n🔧 Configuration Recovery Options:'));
35
- console.log(chalk.cyan(' • Run "base config recover" to attempt automatic recovery'));
36
- console.log(chalk.cyan(' • Run "base init" to create a new configuration'));
37
- console.log(chalk.cyan(' • Check .baseguardrc.json file manually'));
38
- }
39
-
40
- return;
41
- }
42
-
43
- // Initialize BaseGuard
44
- const baseGuard = new BaseGuard(config);
45
-
46
- // Show system health
47
- const health = await baseGuard.getHealthStatus();
48
-
49
- // Overall status
50
- const statusIcon = health.overall === 'healthy' ? '✅' : health.overall === 'degraded' ? '⚠️' : '❌';
51
- const statusColor = health.overall === 'healthy' ? chalk.green : health.overall === 'degraded' ? chalk.yellow : chalk.red;
52
-
53
- console.log(statusColor(`${statusIcon} Overall Status: ${health.overall.toUpperCase()}`));
54
- console.log(chalk.dim(` Degradation Mode: ${health.degradationMode}`));
55
-
56
- // Component status
57
- console.log(chalk.cyan('\n📊 Component Status:'));
58
- for (const [component, status] of Object.entries(health.components)) {
59
- const componentIcon = status.status === 'healthy' ? '✅' : status.status === 'degraded' ? '⚠️' : '❌';
60
- console.log(` ${componentIcon} ${component}: ${status.status}`);
61
-
62
- if (options.verbose && status.details) {
63
- if (status.details.errors?.length > 0) {
64
- console.log(chalk.dim(` Errors: ${status.details.errors.slice(0, 3).join(', ')}`));
65
- }
66
- if (status.details.error) {
67
- console.log(chalk.dim(` Error: ${status.details.error}`));
68
- }
69
- if (status.details.lastCheck) {
70
- const age = Math.round((Date.now() - status.details.lastCheck) / 1000);
71
- console.log(chalk.dim(` Last Check: ${age}s ago`));
72
- }
73
- }
74
- }
75
-
76
- // Service status (if requested)
77
- if (options.services) {
78
- console.log(chalk.cyan('\n🌐 Service Status:'));
79
- const serviceStatus = GracefulDegradationManager.getServiceStatus();
80
-
81
- for (const [service, info] of serviceStatus) {
82
- const serviceIcon = info.available ? '✅' : '❌';
83
- const age = Math.round((Date.now() - info.lastCheck) / 1000);
84
- console.log(` ${serviceIcon} ${service}: ${info.available ? 'Available' : 'Unavailable'} (${age}s ago)`);
85
-
86
- if (!info.available && info.error && options.verbose) {
87
- console.log(chalk.dim(` Error: ${info.error}`));
88
- }
89
- }
90
-
91
- // Refresh service status
92
- console.log(chalk.dim('\n🔄 Refreshing service status...'));
93
- await GracefulDegradationManager.refreshServiceStatus();
94
- }
95
-
96
- // Configuration status (if requested)
97
- if (options.config) {
98
- console.log(chalk.cyan('\n⚙️ Configuration Status:'));
99
-
100
- const configIntegrity = await ConfigurationRecovery.validateIntegrity();
101
- const configIcon = configIntegrity.valid ? '✅' : '❌';
102
- console.log(` ${configIcon} Configuration File: ${configIntegrity.valid ? 'Valid' : 'Invalid'}`);
103
-
104
- if (!configIntegrity.valid) {
105
- console.log(chalk.red(' Errors:'));
106
- configIntegrity.errors.forEach(error => {
107
- console.log(chalk.red(` • ${error}`));
108
- });
109
-
110
- console.log(chalk.cyan(' Suggestions:'));
111
- configIntegrity.suggestions.forEach(suggestion => {
112
- console.log(chalk.cyan(` • ${suggestion}`));
113
- });
114
- }
115
-
116
- // Show configuration details
117
- if (options.verbose) {
118
- console.log(chalk.dim('\n Configuration Details:'));
119
- console.log(chalk.dim(` Version: ${config.version}`));
120
- console.log(chalk.dim(` Targets: ${config.targets.length} browser(s)`));
121
- console.log(chalk.dim(` API Keys: Jules ${config.apiKeys.jules ? '✓' : '✗'}, Gemini ${config.apiKeys.gemini ? '✓' : '✗'}`));
122
- console.log(chalk.dim(` Automation: ${config.automation.enabled ? 'Enabled' : 'Disabled'}`));
123
- }
124
-
125
- // Show available backups
126
- const backups = await ConfigurationRecovery.listBackups();
127
- if (backups.length > 0) {
128
- console.log(chalk.dim(`\n Available Backups: ${backups.length}`));
129
- if (options.verbose) {
130
- backups.slice(0, 3).forEach(backup => {
131
- console.log(chalk.dim(` • ${backup.timestamp.toLocaleString()} (${backup.source})`));
132
- });
133
- }
134
- }
135
- }
136
-
137
- // Error summary (if requested)
138
- if (options.errors) {
139
- console.log(chalk.cyan('\n🚨 Error Summary:'));
140
-
141
- const errorSummary = logger.getErrorSummary();
142
- console.log(` Total Errors: ${errorSummary.totalErrors}`);
143
- console.log(` Total Warnings: ${errorSummary.totalWarnings}`);
144
-
145
- if (errorSummary.totalErrors > 0) {
146
- console.log(chalk.red('\n Error Categories:'));
147
- for (const [category, count] of Object.entries(errorSummary.errorsByCategory)) {
148
- console.log(chalk.red(` ${category}: ${count}`));
149
- }
150
-
151
- if (options.verbose && errorSummary.recentErrors.length > 0) {
152
- console.log(chalk.red('\n Recent Errors:'));
153
- errorSummary.recentErrors.slice(0, 3).forEach(error => {
154
- console.log(chalk.red(` • ${error.message} (${error.category})`));
155
- });
156
- }
157
- }
158
-
159
- // System error handler status
160
- const systemErrorSummary = SystemErrorHandler.getErrorSummary();
161
- if (systemErrorSummary.total > 0) {
162
- console.log(chalk.yellow('\n System Errors:'));
163
- console.log(` Total: ${systemErrorSummary.total}`);
164
- console.log(` Critical: ${systemErrorSummary.critical}`);
165
- console.log(` Recoverable: ${systemErrorSummary.recoverable}`);
166
-
167
- if (options.verbose) {
168
- console.log(chalk.yellow('\n By Severity:'));
169
- for (const [severity, count] of Object.entries(systemErrorSummary.bySeverity)) {
170
- if (count > 0) {
171
- console.log(` ${severity}: ${count}`);
172
- }
173
- }
174
- }
175
- }
176
- }
177
-
178
- // Recommendations
179
- if (health.recommendations.length > 0) {
180
- console.log(chalk.cyan('\n💡 Recommendations:'));
181
- health.recommendations.forEach(rec => {
182
- console.log(chalk.cyan(` • ${rec}`));
183
- });
184
- }
185
-
186
- // Show degradation mode details
187
- const mode = GracefulDegradationManager.getCurrentMode();
188
- if (mode && mode.name !== 'Full Functionality') {
189
- console.log(chalk.yellow(`\n⚠️ Currently in ${mode.name} Mode`));
190
- console.log(chalk.dim(` ${mode.description}`));
191
-
192
- if (mode.limitations.length > 0) {
193
- console.log(chalk.yellow('\n Limitations:'));
194
- mode.limitations.forEach(limitation => {
195
- console.log(chalk.yellow(` • ${limitation}`));
196
- });
197
- }
198
-
199
- console.log(chalk.cyan('\n Available Features:'));
200
- if (mode.capabilities.baselineChecking) {
201
- console.log(chalk.green(' ✅ Baseline compatibility checking'));
202
- }
203
- if (mode.capabilities.caching) {
204
- console.log(chalk.green(' ✅ Result caching'));
205
- }
206
- if (!mode.capabilities.aiAnalysis) {
207
- console.log(chalk.yellow(' ⚠️ AI analysis disabled'));
208
- }
209
- if (!mode.capabilities.autoFix) {
210
- console.log(chalk.yellow(' ⚠️ Auto-fixing disabled'));
211
- }
212
- }
213
-
214
- // Performance info
215
- if (options.verbose) {
216
- const memoryUsage = process.memoryUsage();
217
- const uptime = process.uptime();
218
-
219
- console.log(chalk.cyan('\n📈 Performance Info:'));
220
- console.log(` Uptime: ${Math.round(uptime)}s`);
221
- console.log(` Memory: ${Math.round(memoryUsage.heapUsed / 1024 / 1024)}MB used / ${Math.round(memoryUsage.heapTotal / 1024 / 1024)}MB total`);
222
- console.log(` Platform: ${process.platform} ${process.arch}`);
223
- console.log(` Node.js: ${process.version}`);
224
- }
225
-
226
- // Quick actions
227
- console.log(chalk.cyan('\n🔧 Quick Actions:'));
228
- const actions = [];
229
-
230
- if (health.overall !== 'healthy') {
231
- actions.push('Run "base config recover" to attempt automatic recovery');
232
- }
233
-
234
- if (!mode?.capabilities.aiAnalysis) {
235
- actions.push('Check network connectivity to restore AI features');
236
- }
237
-
238
- const errorSummary = logger.getErrorSummary();
239
- if (errorSummary.totalErrors > 5) {
240
- actions.push('Run with --errors flag to see detailed error information');
241
- }
242
-
243
- actions.push('Run "base check" to scan for compatibility issues');
244
- actions.push('Run "base status --verbose" for detailed information');
245
-
246
- actions.forEach(action => {
247
- console.log(chalk.cyan(` • ${action}`));
248
- });
249
-
250
- } catch (error) {
251
- categoryLogger.error('Status command failed', { error });
252
-
253
- console.log(chalk.red('\n❌ Failed to get system status'));
254
- console.log(chalk.red(` Error: ${error instanceof Error ? error.message : 'Unknown error'}`));
255
-
256
- console.log(chalk.cyan('\n🔧 Recovery Options:'));
257
- console.log(chalk.cyan(' • Run "base init" to reinitialize BaseGuard'));
258
- console.log(chalk.cyan(' • Check file permissions in your project directory'));
259
- console.log(chalk.cyan(' • Verify BaseGuard installation: npm list baseguard'));
260
-
261
- process.exit(1);
262
- }
263
- }
264
-
265
- /**
266
- * Show detailed system diagnostics
267
- */
268
- export async function diagnostics(): Promise<void> {
269
- const categoryLogger = logger.createCategoryLogger('diagnostics');
270
-
271
- try {
272
- console.log(chalk.cyan('🔬 BaseGuard System Diagnostics\n'));
273
-
274
- // Generate comprehensive debug report
275
- const reportFile = await logger.generateDebugReport();
276
- console.log(chalk.green(`✅ Debug report generated: ${reportFile}`));
277
-
278
- // Show configuration recovery wizard
279
- console.log(chalk.cyan('\n🔧 Running Configuration Recovery Wizard...'));
280
- await ConfigurationRecovery.runRecoveryWizard();
281
-
282
- // Show service status
283
- console.log(chalk.cyan('\n🌐 Checking Service Availability...'));
284
- await GracefulDegradationManager.refreshServiceStatus();
285
-
286
- // Show error log summary
287
- const loggerErrorSummary = logger.getErrorSummary();
288
- if (loggerErrorSummary.totalErrors > 0) {
289
- console.log(chalk.yellow(`\n⚠️ Found ${loggerErrorSummary.totalErrors} errors in logs`));
290
- console.log(chalk.cyan('Recent errors:'));
291
- loggerErrorSummary.recentErrors.slice(0, 5).forEach(error => {
292
- console.log(chalk.red(` • ${error.message} (${error.category})`));
293
- });
294
- }
295
-
296
- // Cleanup old files
297
- console.log(chalk.cyan('\n🧹 Cleaning up old files...'));
298
- await logger.cleanupOldLogs();
299
- await GracefulDegradationManager.cleanupCache();
300
-
301
- console.log(chalk.green('\n✅ Diagnostics completed'));
302
-
303
- } catch (error) {
304
- categoryLogger.error('Diagnostics failed', { error });
305
- console.log(chalk.red(`\n❌ Diagnostics failed: ${error instanceof Error ? error.message : 'Unknown error'}`));
306
- }
307
- }
@@ -1,298 +0,0 @@
1
- import { ConfigurationManager } from './configuration.js';
2
- import { UIComponents } from '../ui/components.js';
3
-
4
- /**
5
- * API key validation patterns and utilities
6
- */
7
- export class ApiKeyManager {
8
- /**
9
- * Validate Jules API key format
10
- */
11
- static validateJulesApiKey(apiKey: string): { valid: boolean; error?: string } {
12
- if (!apiKey || typeof apiKey !== 'string') {
13
- return { valid: false, error: 'API key is required' };
14
- }
15
-
16
- const trimmed = apiKey.trim();
17
-
18
- if (trimmed.length < 10) {
19
- return { valid: false, error: 'API key seems too short' };
20
- }
21
-
22
- if (trimmed.length > 200) {
23
- return { valid: false, error: 'API key seems too long' };
24
- }
25
-
26
- // Basic format validation - Jules keys might have specific patterns
27
- if (!/^[A-Za-z0-9_.-]+$/.test(trimmed)) {
28
- return { valid: false, error: 'API key contains invalid characters' };
29
- }
30
-
31
- return { valid: true };
32
- }
33
-
34
- /**
35
- * Validate Gemini API key format
36
- */
37
- static validateGeminiApiKey(apiKey: string): { valid: boolean; error?: string } {
38
- if (!apiKey || typeof apiKey !== 'string') {
39
- return { valid: false, error: 'API key is required' };
40
- }
41
-
42
- const trimmed = apiKey.trim();
43
-
44
- if (trimmed.length < 30) {
45
- return { valid: false, error: 'Gemini API key seems too short' };
46
- }
47
-
48
- if (trimmed.length > 100) {
49
- return { valid: false, error: 'Gemini API key seems too long' };
50
- }
51
-
52
- // Gemini API keys typically start with "AIza"
53
- if (!trimmed.startsWith('AIza')) {
54
- return { valid: false, error: 'Gemini API keys typically start with "AIza"' };
55
- }
56
-
57
- // Basic format validation
58
- if (!/^[A-Za-z0-9_-]+$/.test(trimmed)) {
59
- return { valid: false, error: 'API key contains invalid characters' };
60
- }
61
-
62
- return { valid: true };
63
- }
64
-
65
- /**
66
- * Test Jules API key connectivity
67
- */
68
- static async testJulesApiKey(apiKey: string): Promise<{ success: boolean; error?: string }> {
69
- try {
70
- // Validate format first
71
- const validation = this.validateJulesApiKey(apiKey);
72
- if (!validation.valid) {
73
- return { success: false, error: validation.error };
74
- }
75
-
76
- // Test connectivity with a simple API call
77
- const response = await fetch('https://jules.googleapis.com/v1alpha/sessions', {
78
- method: 'GET',
79
- headers: {
80
- 'X-Goog-Api-Key': apiKey.trim(),
81
- 'Content-Type': 'application/json'
82
- }
83
- });
84
-
85
- if (response.status === 401) {
86
- return { success: false, error: 'Invalid API key or insufficient permissions' };
87
- }
88
-
89
- if (response.status === 403) {
90
- return { success: false, error: 'API key does not have required permissions' };
91
- }
92
-
93
- if (response.status === 429) {
94
- return { success: false, error: 'Rate limit exceeded. Please try again later' };
95
- }
96
-
97
- if (!response.ok && response.status !== 404) {
98
- return { success: false, error: `API error: ${response.status} ${response.statusText}` };
99
- }
100
-
101
- // 404 is acceptable for a test call to sessions endpoint
102
- return { success: true };
103
-
104
- } catch (error) {
105
- if (error instanceof Error) {
106
- if (error.message.includes('fetch')) {
107
- return { success: false, error: 'Network error. Please check your internet connection' };
108
- }
109
- return { success: false, error: error.message };
110
- }
111
- return { success: false, error: 'Unknown error occurred during API test' };
112
- }
113
- }
114
-
115
- /**
116
- * Test Gemini API key connectivity
117
- */
118
- static async testGeminiApiKey(apiKey: string): Promise<{ success: boolean; error?: string }> {
119
- try {
120
- // Validate format first
121
- const validation = this.validateGeminiApiKey(apiKey);
122
- if (!validation.valid) {
123
- return { success: false, error: validation.error };
124
- }
125
-
126
- // Test connectivity with a simple API call
127
- const response = await fetch('https://generativelanguage.googleapis.com/v1beta/models', {
128
- method: 'GET',
129
- headers: {
130
- 'x-goog-api-key': apiKey.trim()
131
- }
132
- });
133
-
134
- if (response.status === 401) {
135
- return { success: false, error: 'Invalid API key' };
136
- }
137
-
138
- if (response.status === 403) {
139
- return { success: false, error: 'API key does not have required permissions' };
140
- }
141
-
142
- if (response.status === 429) {
143
- return { success: false, error: 'Rate limit exceeded. Please try again later' };
144
- }
145
-
146
- if (!response.ok) {
147
- return { success: false, error: `API error: ${response.status} ${response.statusText}` };
148
- }
149
-
150
- // Verify we can parse the response
151
- const data = await response.json();
152
- if (!data.models || !Array.isArray(data.models)) {
153
- return { success: false, error: 'Unexpected API response format' };
154
- }
155
-
156
- return { success: true };
157
-
158
- } catch (error) {
159
- if (error instanceof Error) {
160
- if (error.message.includes('fetch')) {
161
- return { success: false, error: 'Network error. Please check your internet connection' };
162
- }
163
- return { success: false, error: error.message };
164
- }
165
- return { success: false, error: 'Unknown error occurred during API test' };
166
- }
167
- }
168
-
169
- /**
170
- * Store API keys securely in configuration
171
- */
172
- static async storeApiKeys(keys: { jules?: string; gemini?: string }): Promise<void> {
173
- const config = await ConfigurationManager.load();
174
-
175
- if (keys.jules) {
176
- config.apiKeys.jules = keys.jules.trim();
177
- }
178
-
179
- if (keys.gemini) {
180
- config.apiKeys.gemini = keys.gemini.trim();
181
- }
182
-
183
- await ConfigurationManager.save(config);
184
- }
185
-
186
- /**
187
- * Get stored API keys
188
- */
189
- static async getStoredApiKeys(): Promise<{ jules: string | null; gemini: string | null }> {
190
- const config = await ConfigurationManager.load();
191
- return {
192
- jules: config.apiKeys.jules,
193
- gemini: config.apiKeys.gemini
194
- };
195
- }
196
-
197
- /**
198
- * Check if API keys are configured
199
- */
200
- static async hasApiKeys(): Promise<{ jules: boolean; gemini: boolean }> {
201
- const keys = await this.getStoredApiKeys();
202
- return {
203
- jules: !!keys.jules,
204
- gemini: !!keys.gemini
205
- };
206
- }
207
-
208
- /**
209
- * Clear stored API keys
210
- */
211
- static async clearApiKeys(): Promise<void> {
212
- const config = await ConfigurationManager.load();
213
- config.apiKeys.jules = null;
214
- config.apiKeys.gemini = null;
215
- await ConfigurationManager.save(config);
216
- }
217
-
218
- /**
219
- * Validate and test all stored API keys
220
- */
221
- static async validateStoredKeys(): Promise<{
222
- jules: { valid: boolean; error?: string };
223
- gemini: { valid: boolean; error?: string };
224
- }> {
225
- const keys = await this.getStoredApiKeys();
226
-
227
- const results = {
228
- jules: { valid: false, error: 'No API key configured' },
229
- gemini: { valid: false, error: 'No API key configured' }
230
- };
231
-
232
- if (keys.jules) {
233
- const julesResult = await this.testJulesApiKey(keys.jules);
234
- results.jules = { valid: julesResult.success, error: julesResult.error || '' };
235
- }
236
-
237
- if (keys.gemini) {
238
- const geminiResult = await this.testGeminiApiKey(keys.gemini);
239
- results.gemini = { valid: geminiResult.success, error: geminiResult.error || '' };
240
- }
241
-
242
- return results;
243
- }
244
-
245
- /**
246
- * Get API key status for display
247
- */
248
- static async getApiKeyStatus(): Promise<{
249
- jules: 'configured' | 'missing' | 'invalid';
250
- gemini: 'configured' | 'missing' | 'invalid';
251
- }> {
252
- const keys = await this.getStoredApiKeys();
253
- const status: {
254
- jules: 'configured' | 'missing' | 'invalid';
255
- gemini: 'configured' | 'missing' | 'invalid';
256
- } = {
257
- jules: 'missing',
258
- gemini: 'missing'
259
- };
260
-
261
- if (keys.jules) {
262
- const validation = this.validateJulesApiKey(keys.jules);
263
- status.jules = validation.valid ? 'configured' : 'invalid';
264
- }
265
-
266
- if (keys.gemini) {
267
- const validation = this.validateGeminiApiKey(keys.gemini);
268
- status.gemini = validation.valid ? 'configured' : 'invalid';
269
- }
270
-
271
- return status;
272
- }
273
-
274
- /**
275
- * Show helpful error messages for API failures
276
- */
277
- static showApiErrorHelp(service: 'jules' | 'gemini', error: string): void {
278
- UIComponents.showErrorBox(`${service.toUpperCase()} API Error: ${error}`);
279
-
280
- console.log('\nTroubleshooting steps:');
281
-
282
- if (service === 'jules') {
283
- UIComponents.showList([
284
- 'Verify your Jules API key at https://jules.google.com',
285
- 'Check that the Jules GitHub app is installed on your repository',
286
- 'Ensure your API key has the required permissions',
287
- 'Try regenerating your API key if the issue persists'
288
- ]);
289
- } else {
290
- UIComponents.showList([
291
- 'Verify your Gemini API key at https://aistudio.google.com/app/apikey',
292
- 'Check that the Gemini API is enabled in your Google Cloud project',
293
- 'Ensure you have sufficient quota remaining',
294
- 'Try regenerating your API key if the issue persists'
295
- ]);
296
- }
297
- }
298
- }