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.
- package/dist/ai/gemini-analyzer.d.ts.map +1 -1
- package/dist/ai/gemini-analyzer.js +1 -1
- package/dist/ai/gemini-analyzer.js.map +1 -1
- package/dist/ai/gemini-code-fixer.d.ts.map +1 -1
- package/dist/ai/gemini-code-fixer.js +2 -7
- package/dist/ai/gemini-code-fixer.js.map +1 -1
- package/dist/ai/jules-implementer.d.ts +8 -0
- package/dist/ai/jules-implementer.d.ts.map +1 -1
- package/dist/ai/jules-implementer.js +115 -17
- package/dist/ai/jules-implementer.js.map +1 -1
- package/package.json +1 -1
- package/src/ai/__tests__/gemini-analyzer.test.ts +0 -181
- package/src/ai/agentkit-orchestrator.ts +0 -534
- package/src/ai/fix-manager.ts +0 -362
- package/src/ai/gemini-analyzer.ts +0 -665
- package/src/ai/gemini-code-fixer.ts +0 -539
- package/src/ai/index.ts +0 -4
- package/src/ai/jules-implementer.ts +0 -504
- package/src/ai/unified-code-fixer.ts +0 -347
- package/src/commands/automation.ts +0 -344
- package/src/commands/check.ts +0 -298
- package/src/commands/config.ts +0 -584
- package/src/commands/fix.ts +0 -269
- package/src/commands/index.ts +0 -7
- package/src/commands/init.ts +0 -156
- package/src/commands/status.ts +0 -307
- package/src/core/api-key-manager.ts +0 -298
- package/src/core/baseguard.ts +0 -757
- package/src/core/baseline-checker.ts +0 -566
- package/src/core/cache-manager.ts +0 -272
- package/src/core/configuration-recovery.ts +0 -672
- package/src/core/configuration.ts +0 -596
- package/src/core/debug-logger.ts +0 -590
- package/src/core/directory-filter.ts +0 -421
- package/src/core/error-handler.ts +0 -518
- package/src/core/file-processor.ts +0 -338
- package/src/core/gitignore-manager.ts +0 -169
- package/src/core/graceful-degradation-manager.ts +0 -596
- package/src/core/index.ts +0 -17
- package/src/core/lazy-loader.ts +0 -317
- package/src/core/logger.ts +0 -0
- package/src/core/memory-manager.ts +0 -290
- package/src/core/parser-worker.ts +0 -33
- package/src/core/startup-optimizer.ts +0 -246
- package/src/core/system-error-handler.ts +0 -755
- package/src/git/automation-engine.ts +0 -361
- package/src/git/github-manager.ts +0 -190
- package/src/git/hook-manager.ts +0 -210
- package/src/git/index.ts +0 -4
- package/src/index.ts +0 -8
- package/src/parsers/feature-validator.ts +0 -559
- package/src/parsers/index.ts +0 -8
- package/src/parsers/parser-manager.ts +0 -418
- package/src/parsers/parser.ts +0 -26
- package/src/parsers/react-parser-optimized.ts +0 -161
- package/src/parsers/react-parser.ts +0 -359
- package/src/parsers/svelte-parser.ts +0 -510
- package/src/parsers/vanilla-parser.ts +0 -685
- package/src/parsers/vue-parser.ts +0 -476
- package/src/types/index.ts +0 -96
- package/src/ui/components.ts +0 -567
- package/src/ui/help.ts +0 -193
- package/src/ui/index.ts +0 -4
- package/src/ui/prompts.ts +0 -681
- package/src/ui/terminal-header.ts +0 -59
- package/tests/e2e/baseguard.e2e.test.ts +0 -516
- package/tests/e2e/cross-platform.e2e.test.ts +0 -420
- package/tests/e2e/git-integration.e2e.test.ts +0 -487
- package/tests/fixtures/react-project/package.json +0 -14
- package/tests/fixtures/react-project/src/App.css +0 -76
- package/tests/fixtures/react-project/src/App.tsx +0 -77
- package/tests/fixtures/svelte-project/package.json +0 -11
- package/tests/fixtures/svelte-project/src/App.svelte +0 -369
- package/tests/fixtures/vanilla-project/index.html +0 -76
- package/tests/fixtures/vanilla-project/script.js +0 -331
- package/tests/fixtures/vanilla-project/styles.css +0 -359
- package/tests/fixtures/vue-project/package.json +0 -12
- package/tests/fixtures/vue-project/src/App.vue +0 -216
- package/tmp-smoke/.baseguard/backups/config-2026-02-19T12-04-11-067Z-auto.json +0 -30
- package/tmp-smoke/src/bad.css +0 -3
package/src/commands/status.ts
DELETED
|
@@ -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
|
-
}
|