baseguard 1.0.2 → 1.0.4

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 (169) hide show
  1. package/.baseguardrc.example.json +63 -63
  2. package/.eslintrc.json +24 -24
  3. package/.prettierrc +7 -7
  4. package/CHANGELOG.md +195 -195
  5. package/DEPLOYMENT.md +624 -624
  6. package/DEPLOYMENT_CHECKLIST.md +239 -239
  7. package/DEPLOYMENT_SUMMARY_v1.0.2.md +202 -202
  8. package/QUICK_START.md +134 -134
  9. package/README.md +488 -488
  10. package/RELEASE_NOTES_v1.0.2.md +434 -434
  11. package/bin/base.js +628 -613
  12. package/dist/ai/fix-manager.d.ts.map +1 -1
  13. package/dist/ai/fix-manager.js +1 -1
  14. package/dist/ai/fix-manager.js.map +1 -1
  15. package/dist/ai/gemini-analyzer.d.ts.map +1 -1
  16. package/dist/ai/gemini-analyzer.js +29 -35
  17. package/dist/ai/gemini-analyzer.js.map +1 -1
  18. package/dist/ai/gemini-code-fixer.d.ts.map +1 -1
  19. package/dist/ai/gemini-code-fixer.js +58 -58
  20. package/dist/ai/gemini-code-fixer.js.map +1 -1
  21. package/dist/ai/jules-implementer.d.ts +3 -0
  22. package/dist/ai/jules-implementer.d.ts.map +1 -1
  23. package/dist/ai/jules-implementer.js +63 -32
  24. package/dist/ai/jules-implementer.js.map +1 -1
  25. package/dist/ai/unified-code-fixer.js.map +1 -1
  26. package/dist/commands/check.d.ts.map +1 -1
  27. package/dist/commands/check.js +1 -1
  28. package/dist/commands/check.js.map +1 -1
  29. package/dist/commands/config.js +2 -1
  30. package/dist/commands/config.js.map +1 -1
  31. package/dist/commands/fix.d.ts.map +1 -1
  32. package/dist/commands/fix.js +44 -15
  33. package/dist/commands/fix.js.map +1 -1
  34. package/dist/core/api-key-manager.js +2 -2
  35. package/dist/core/api-key-manager.js.map +1 -1
  36. package/dist/core/baseguard.d.ts +1 -0
  37. package/dist/core/baseguard.d.ts.map +1 -1
  38. package/dist/core/baseguard.js +13 -10
  39. package/dist/core/baseguard.js.map +1 -1
  40. package/dist/core/baseline-checker.d.ts.map +1 -1
  41. package/dist/core/baseline-checker.js +2 -1
  42. package/dist/core/baseline-checker.js.map +1 -1
  43. package/dist/core/configuration-recovery.d.ts.map +1 -1
  44. package/dist/core/configuration-recovery.js +1 -1
  45. package/dist/core/configuration-recovery.js.map +1 -1
  46. package/dist/core/debug-logger.d.ts.map +1 -1
  47. package/dist/core/debug-logger.js +1 -1
  48. package/dist/core/debug-logger.js.map +1 -1
  49. package/dist/core/error-handler.d.ts.map +1 -1
  50. package/dist/core/error-handler.js +2 -1
  51. package/dist/core/error-handler.js.map +1 -1
  52. package/dist/core/gitignore-manager.js +5 -5
  53. package/dist/core/graceful-degradation-manager.d.ts.map +1 -1
  54. package/dist/core/graceful-degradation-manager.js +16 -16
  55. package/dist/core/graceful-degradation-manager.js.map +1 -1
  56. package/dist/core/lazy-loader.d.ts.map +1 -1
  57. package/dist/core/lazy-loader.js +9 -2
  58. package/dist/core/lazy-loader.js.map +1 -1
  59. package/dist/core/memory-manager.d.ts +0 -3
  60. package/dist/core/memory-manager.d.ts.map +1 -1
  61. package/dist/core/memory-manager.js.map +1 -1
  62. package/dist/core/parser-worker.d.ts +2 -0
  63. package/dist/core/parser-worker.d.ts.map +1 -0
  64. package/dist/core/parser-worker.js +19 -0
  65. package/dist/core/parser-worker.js.map +1 -0
  66. package/dist/core/startup-optimizer.d.ts +2 -0
  67. package/dist/core/startup-optimizer.d.ts.map +1 -1
  68. package/dist/core/startup-optimizer.js +19 -12
  69. package/dist/core/startup-optimizer.js.map +1 -1
  70. package/dist/core/system-error-handler.d.ts.map +1 -1
  71. package/dist/core/system-error-handler.js +18 -11
  72. package/dist/core/system-error-handler.js.map +1 -1
  73. package/dist/git/automation-engine.d.ts.map +1 -1
  74. package/dist/git/automation-engine.js +5 -4
  75. package/dist/git/automation-engine.js.map +1 -1
  76. package/dist/git/github-manager.d.ts.map +1 -1
  77. package/dist/git/github-manager.js.map +1 -1
  78. package/dist/git/hook-manager.js +5 -5
  79. package/dist/git/hook-manager.js.map +1 -1
  80. package/dist/parsers/parser-manager.d.ts.map +1 -1
  81. package/dist/parsers/parser-manager.js +1 -1
  82. package/dist/parsers/parser-manager.js.map +1 -1
  83. package/dist/parsers/svelte-parser.js +1 -1
  84. package/dist/parsers/svelte-parser.js.map +1 -1
  85. package/dist/parsers/vanilla-parser.d.ts.map +1 -1
  86. package/dist/parsers/vanilla-parser.js.map +1 -1
  87. package/dist/parsers/vue-parser.d.ts.map +1 -1
  88. package/dist/parsers/vue-parser.js.map +1 -1
  89. package/dist/ui/components.d.ts +1 -1
  90. package/dist/ui/components.d.ts.map +1 -1
  91. package/dist/ui/components.js +11 -11
  92. package/dist/ui/components.js.map +1 -1
  93. package/dist/ui/terminal-header.js +14 -14
  94. package/package.json +105 -105
  95. package/src/ai/__tests__/gemini-analyzer.test.ts +180 -180
  96. package/src/ai/agentkit-orchestrator.ts +533 -533
  97. package/src/ai/fix-manager.ts +362 -362
  98. package/src/ai/gemini-analyzer.ts +665 -671
  99. package/src/ai/gemini-code-fixer.ts +539 -540
  100. package/src/ai/index.ts +3 -3
  101. package/src/ai/jules-implementer.ts +504 -460
  102. package/src/ai/unified-code-fixer.ts +347 -347
  103. package/src/commands/automation.ts +343 -343
  104. package/src/commands/check.ts +298 -299
  105. package/src/commands/config.ts +584 -583
  106. package/src/commands/fix.ts +264 -238
  107. package/src/commands/index.ts +6 -6
  108. package/src/commands/init.ts +155 -155
  109. package/src/commands/status.ts +306 -306
  110. package/src/core/api-key-manager.ts +298 -298
  111. package/src/core/baseguard.ts +757 -756
  112. package/src/core/baseline-checker.ts +564 -563
  113. package/src/core/cache-manager.ts +271 -271
  114. package/src/core/configuration-recovery.ts +672 -673
  115. package/src/core/configuration.ts +595 -595
  116. package/src/core/debug-logger.ts +590 -590
  117. package/src/core/directory-filter.ts +420 -420
  118. package/src/core/error-handler.ts +518 -517
  119. package/src/core/file-processor.ts +337 -337
  120. package/src/core/gitignore-manager.ts +168 -168
  121. package/src/core/graceful-degradation-manager.ts +596 -596
  122. package/src/core/index.ts +16 -16
  123. package/src/core/lazy-loader.ts +317 -307
  124. package/src/core/memory-manager.ts +290 -295
  125. package/src/core/parser-worker.ts +33 -0
  126. package/src/core/startup-optimizer.ts +246 -243
  127. package/src/core/system-error-handler.ts +755 -750
  128. package/src/git/automation-engine.ts +361 -361
  129. package/src/git/github-manager.ts +190 -192
  130. package/src/git/hook-manager.ts +210 -210
  131. package/src/git/index.ts +3 -3
  132. package/src/index.ts +7 -7
  133. package/src/parsers/feature-validator.ts +558 -558
  134. package/src/parsers/index.ts +7 -7
  135. package/src/parsers/parser-manager.ts +418 -419
  136. package/src/parsers/parser.ts +25 -25
  137. package/src/parsers/react-parser-optimized.ts +160 -160
  138. package/src/parsers/react-parser.ts +358 -358
  139. package/src/parsers/svelte-parser.ts +510 -510
  140. package/src/parsers/vanilla-parser.ts +685 -686
  141. package/src/parsers/vue-parser.ts +476 -478
  142. package/src/types/index.ts +95 -95
  143. package/src/ui/components.ts +567 -567
  144. package/src/ui/help.ts +192 -192
  145. package/src/ui/index.ts +3 -3
  146. package/src/ui/prompts.ts +680 -680
  147. package/src/ui/terminal-header.ts +58 -58
  148. package/test-build.js +40 -40
  149. package/test-config-commands.js +55 -55
  150. package/test-header-simple.js +32 -32
  151. package/test-terminal-header.js +11 -11
  152. package/test-ui.js +28 -28
  153. package/tests/e2e/baseguard.e2e.test.ts +515 -515
  154. package/tests/e2e/cross-platform.e2e.test.ts +419 -419
  155. package/tests/e2e/git-integration.e2e.test.ts +486 -486
  156. package/tests/fixtures/react-project/package.json +13 -13
  157. package/tests/fixtures/react-project/src/App.css +75 -75
  158. package/tests/fixtures/react-project/src/App.tsx +76 -76
  159. package/tests/fixtures/svelte-project/package.json +10 -10
  160. package/tests/fixtures/svelte-project/src/App.svelte +368 -368
  161. package/tests/fixtures/vanilla-project/index.html +75 -75
  162. package/tests/fixtures/vanilla-project/script.js +330 -330
  163. package/tests/fixtures/vanilla-project/styles.css +358 -358
  164. package/tests/fixtures/vue-project/package.json +11 -11
  165. package/tests/fixtures/vue-project/src/App.vue +215 -215
  166. package/tsconfig.json +34 -34
  167. package/vitest.config.ts +11 -11
  168. package/dist/terminal-header.d.ts +0 -12
  169. package/dist/terminal-header.js +0 -45
@@ -1,583 +1,584 @@
1
- import { UIComponents, Prompts } from '../ui/index.js';
2
- import { ConfigurationManager, ApiKeyManager, GitignoreManager } from '../core/index.js';
3
- import { ConfigurationRecovery } from '../core/configuration-recovery.js';
4
- import { ErrorHandler } from '../core/error-handler.js';
5
- import chalk from 'chalk';
6
-
7
- /**
8
- * Manage BaseGuard configuration
9
- */
10
- export async function config(action: string, options?: {
11
- add?: string;
12
- remove?: string;
13
- preset?: string;
14
- file?: string;
15
- format?: string;
16
- backup?: boolean;
17
- interactive?: boolean;
18
- agent?: string;
19
- show?: boolean;
20
- }): Promise<void> {
21
- try {
22
- switch (action) {
23
- case 'show':
24
- await showConfiguration();
25
- break;
26
- case 'list':
27
- await listConfiguration(options?.format);
28
- break;
29
- case 'set-keys':
30
- await setupApiKeys();
31
- break;
32
- case 'targets':
33
- await updateTargets(options);
34
- break;
35
- case 'automation':
36
- await updateAutomation();
37
- break;
38
- case 'update':
39
- await updateConfiguration();
40
- break;
41
- case 'validate':
42
- await validateConfiguration();
43
- break;
44
- case 'security':
45
- await checkSecurity();
46
- break;
47
- case 'backup':
48
- await backupConfiguration();
49
- break;
50
- case 'restore':
51
- await restoreConfiguration(options?.file);
52
- break;
53
- case 'recover':
54
- await recoverConfiguration(options);
55
- break;
56
- case 'coding-agent':
57
- await manageCodingAgent(options);
58
- break;
59
- default:
60
- UIComponents.showErrorBox(`Unknown config action: ${action}`);
61
- showConfigHelp();
62
- process.exit(1);
63
- }
64
-
65
- } catch (error) {
66
- const apiError = ErrorHandler.handleAPIError(error);
67
- ErrorHandler.displayError(apiError);
68
-
69
- // Provide specific help for config command issues
70
- console.log('\nšŸ’” Configuration help:');
71
- if (action === 'set-keys') {
72
- UIComponents.showList([
73
- 'Get Gemini API key from https://aistudio.google.com',
74
- 'Get Jules API key from https://jules.google.com',
75
- 'Ensure API keys are valid and have proper permissions',
76
- 'Check your internet connection for key validation'
77
- ]);
78
- } else if (action === 'targets') {
79
- UIComponents.showList([
80
- 'Use format "browser version" (e.g., "chrome 100")',
81
- 'Available browsers: chrome, safari, firefox, edge',
82
- 'Use "baseline" for Baseline-only support',
83
- 'Check available presets with "base config targets --help"'
84
- ]);
85
- } else if (action === 'validate') {
86
- UIComponents.showList([
87
- 'Check .baseguardrc.json file exists',
88
- 'Verify JSON syntax is correct',
89
- 'Run "base init" to recreate configuration if needed'
90
- ]);
91
- } else {
92
- UIComponents.showList([
93
- 'Run "base config show" to see current configuration',
94
- 'Use "base config --help" to see available commands',
95
- 'Check file permissions in the current directory'
96
- ]);
97
- }
98
-
99
- process.exit(1);
100
- }
101
- }
102
-
103
- async function showConfiguration(): Promise<void> {
104
- const display = await ConfigurationManager.getConfigurationDisplay();
105
-
106
- UIComponents.showConfiguration(display.config);
107
-
108
- // Show security status
109
- if (!display.security.configIgnored) {
110
- UIComponents.showWarningBox('Configuration file is not in .gitignore - API keys may be exposed!');
111
-
112
- if (display.security.recommendations.length > 0) {
113
- console.log('\nSecurity recommendations:');
114
- UIComponents.showList(display.security.recommendations);
115
- }
116
- }
117
-
118
- // Show validation errors if any
119
- if (!display.validation.valid) {
120
- UIComponents.showErrorBox('Configuration validation failed');
121
- UIComponents.showList(display.validation.errors);
122
- }
123
- }
124
-
125
- async function listConfiguration(format?: string): Promise<void> {
126
- const display = await ConfigurationManager.getConfigurationDisplay();
127
-
128
- if (format === 'json') {
129
- // Output as JSON for programmatic use
130
- const output = {
131
- configuration: display.config,
132
- security: display.security,
133
- validation: display.validation,
134
- status: {
135
- configured: display.config.apiKeys.jules !== null || display.config.apiKeys.gemini !== null,
136
- automationEnabled: display.config.automation.enabled,
137
- targetCount: display.config.targets.length
138
- }
139
- };
140
- console.log(JSON.stringify(output, null, 2));
141
- return;
142
- }
143
-
144
- // Default table format
145
- UIComponents.showSectionHeader('BaseGuard Configuration Summary');
146
-
147
- // Configuration overview
148
- console.log('šŸ“‹ Configuration:');
149
- console.log(` Version: ${display.config.version}`);
150
- console.log(` Targets: ${display.config.targets.length} browser(s)`);
151
- console.log(` API Keys: ${display.config.apiKeys.jules ? 'āœ“' : 'āœ—'} Jules, ${display.config.apiKeys.gemini ? 'āœ“' : 'āœ—'} Gemini`);
152
- console.log(` Automation: ${display.config.automation.enabled ? 'āœ“ enabled' : 'āœ— disabled'}`);
153
-
154
- // Browser targets
155
- console.log('\nšŸŽÆ Browser Targets:');
156
- display.config.targets.forEach(target => {
157
- console.log(` • ${target.browser} ${target.minVersion}`);
158
- });
159
-
160
- // Automation settings
161
- console.log('\nšŸ¤– Automation Settings:');
162
- console.log(` Enabled: ${display.config.automation.enabled ? 'āœ“' : 'āœ—'}`);
163
- console.log(` Trigger: ${display.config.automation.trigger}`);
164
- console.log(` Auto-analyze: ${display.config.automation.autoAnalyze ? 'āœ“' : 'āœ—'}`);
165
- console.log(` Auto-fix: ${display.config.automation.autoFix ? 'āœ“' : 'āœ—'}`);
166
- console.log(` Block commits: ${display.config.automation.blockCommit ? 'āœ“' : 'āœ—'}`);
167
-
168
- // Security status
169
- console.log('\nšŸ”’ Security Status:');
170
- console.log(` .gitignore exists: ${display.security.gitignoreExists ? 'āœ“' : 'āœ—'}`);
171
- console.log(` Config file ignored: ${display.security.configIgnored ? 'āœ“' : 'āœ—'}`);
172
-
173
- // Validation status
174
- console.log('\nāœ… Validation Status:');
175
- console.log(` Configuration valid: ${display.validation.valid ? 'āœ“' : 'āœ—'}`);
176
-
177
- // Show warnings/errors
178
- if (!display.security.configIgnored) {
179
- UIComponents.showWarningBox('Configuration file is not in .gitignore - API keys may be exposed!');
180
- }
181
-
182
- if (!display.validation.valid) {
183
- UIComponents.showErrorBox('Configuration validation failed');
184
- UIComponents.showList(display.validation.errors);
185
- }
186
-
187
- if (display.security.recommendations.length > 0) {
188
- console.log('\nšŸ’” Recommendations:');
189
- UIComponents.showList(display.security.recommendations);
190
- }
191
- }
192
-
193
- async function setupApiKeys(): Promise<void> {
194
- const apiKeys = await Prompts.setupApiKeys();
195
-
196
- if (apiKeys.julesApiKey || apiKeys.geminiApiKey) {
197
- await ApiKeyManager.storeApiKeys({
198
- jules: apiKeys.julesApiKey,
199
- gemini: apiKeys.geminiApiKey
200
- });
201
-
202
- UIComponents.showSuccessBox('API keys updated successfully');
203
-
204
- // Show security reminder
205
- const security = await GitignoreManager.isConfigSecure();
206
- if (!security.configIgnored) {
207
- UIComponents.showWarningBox('Remember to add .baseguardrc.json to .gitignore to protect your API keys');
208
- }
209
- } else {
210
- UIComponents.showInfoBox('No API keys were configured');
211
- }
212
- }
213
-
214
- async function updateTargets(options?: { add?: string; remove?: string; preset?: string }): Promise<void> {
215
- if (options?.add) {
216
- // Add a specific browser target
217
- const target = ConfigurationManager.parseBrowserTarget(options.add);
218
- if (!target) {
219
- UIComponents.showErrorBox(`Invalid browser target format: ${options.add}`);
220
- UIComponents.showInfoBox('Format: "browser version" (e.g., "chrome 100", "safari baseline")');
221
- return;
222
- }
223
-
224
- await ConfigurationManager.addBrowserTarget(target);
225
- UIComponents.showSuccessBox(`Added browser target: ${target.browser} ${target.minVersion}`);
226
- return;
227
- }
228
-
229
- if (options?.remove) {
230
- // Remove a specific browser target
231
- await ConfigurationManager.removeBrowserTarget(options.remove);
232
- UIComponents.showSuccessBox(`Removed browser target: ${options.remove}`);
233
- return;
234
- }
235
-
236
- if (options?.preset) {
237
- // Set preset targets
238
- const presetName = options.preset as any;
239
- const availablePresets = ConfigurationManager.getAvailablePresets();
240
-
241
- if (!availablePresets.includes(presetName)) {
242
- UIComponents.showErrorBox(`Invalid preset: ${options.preset}`);
243
- UIComponents.showInfoBox(`Available presets: ${availablePresets.join(', ')}`);
244
- return;
245
- }
246
-
247
- await ConfigurationManager.updateWithPreset(presetName);
248
- UIComponents.showSuccessBox(`Updated to ${presetName} preset`);
249
- UIComponents.showInfoBox(ConfigurationManager.getPresetDescription(presetName));
250
- return;
251
- }
252
-
253
- // Interactive target configuration
254
- const targets = await Prompts.promptCustomTargets();
255
- await ConfigurationManager.updateWithCustomTargets(targets);
256
- UIComponents.showSuccessBox('Browser targets updated successfully');
257
- }
258
-
259
- async function updateAutomation(): Promise<void> {
260
- const automation = await Prompts.promptAutomationSettings();
261
- const config = await ConfigurationManager.load();
262
- config.automation = { ...config.automation, ...automation };
263
- await ConfigurationManager.save(config);
264
- UIComponents.showSuccessBox('Automation settings updated successfully');
265
- }
266
-
267
- async function updateConfiguration(): Promise<void> {
268
- const currentConfig = await ConfigurationManager.load();
269
- const updates = await Prompts.promptConfigUpdate(currentConfig);
270
-
271
- if (Object.keys(updates).length === 0) {
272
- UIComponents.showInfoBox('No changes made');
273
- return;
274
- }
275
-
276
- let config = currentConfig;
277
-
278
- // Apply updates
279
- for (const [key, value] of Object.entries(updates)) {
280
- switch (key) {
281
- case 'targets':
282
- await ConfigurationManager.updateWithCustomTargets(value as any);
283
- config = await ConfigurationManager.load(); // Reload after update
284
- break;
285
- case 'apiKeys':
286
- const apiKeys = value as any;
287
- if (apiKeys.julesApiKey) config.apiKeys.jules = apiKeys.julesApiKey;
288
- if (apiKeys.geminiApiKey) config.apiKeys.gemini = apiKeys.geminiApiKey;
289
- break;
290
- case 'automation':
291
- config.automation = { ...config.automation, ...(value as any) };
292
- break;
293
- }
294
- }
295
-
296
- await ConfigurationManager.save(config);
297
- UIComponents.showSuccessBox('Configuration updated successfully');
298
- }
299
-
300
- async function validateConfiguration(): Promise<void> {
301
- const display = await ConfigurationManager.getConfigurationDisplay();
302
-
303
- if (display.validation.valid) {
304
- UIComponents.showSuccessBox('Configuration is valid');
305
- } else {
306
- UIComponents.showErrorBox('Configuration validation failed');
307
- UIComponents.showList(display.validation.errors);
308
- process.exit(1);
309
- }
310
- }
311
-
312
- async function checkSecurity(): Promise<void> {
313
- const security = await GitignoreManager.isConfigSecure();
314
-
315
- UIComponents.showSectionHeader('Security Status');
316
-
317
- console.log(`āœ“ .gitignore exists: ${security.gitignoreExists ? 'Yes' : 'No'}`);
318
- console.log(`āœ“ Config file ignored: ${security.configIgnored ? 'Yes' : 'No'}`);
319
-
320
- if (security.recommendations.length > 0) {
321
- console.log('\nRecommendations:');
322
- UIComponents.showList(security.recommendations);
323
- } else {
324
- UIComponents.showSuccessBox('Configuration is secure');
325
- }
326
- }
327
-
328
- async function backupConfiguration(): Promise<void> {
329
- try {
330
- const backupFile = await ConfigurationManager.backupConfiguration();
331
- UIComponents.showSuccessBox(`Configuration backed up to: ${backupFile}`);
332
- } catch (error) {
333
- UIComponents.showErrorBox(`Backup failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
334
- process.exit(1);
335
- }
336
- }
337
-
338
- async function restoreConfiguration(backupFile?: string): Promise<void> {
339
- if (!backupFile) {
340
- UIComponents.showErrorBox('Backup file path is required');
341
- console.log('Usage: base config restore --file <backup-file>');
342
- process.exit(1);
343
- }
344
-
345
- try {
346
- await ConfigurationManager.restoreConfiguration(backupFile);
347
- UIComponents.showSuccessBox('Configuration restored successfully');
348
- } catch (error) {
349
- UIComponents.showErrorBox(`Restore failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
350
- process.exit(1);
351
- }
352
- }
353
-
354
- async function recoverConfiguration(options?: { backup?: boolean; interactive?: boolean }): Promise<void> {
355
- try {
356
- console.log(chalk.cyan('šŸ”§ BaseGuard Configuration Recovery\n'));
357
-
358
- if (options?.interactive) {
359
- // Run interactive recovery wizard
360
- await ConfigurationRecovery.runRecoveryWizard();
361
- return;
362
- }
363
-
364
- // Automatic recovery
365
- console.log(chalk.cyan('Attempting automatic configuration recovery...'));
366
-
367
- const recoveryResult = await ConfigurationRecovery.recoverConfiguration({
368
- createBackup: options?.backup ?? true,
369
- validateConfig: true,
370
- migrateVersion: true,
371
- repairCorruption: true,
372
- useDefaults: true
373
- });
374
-
375
- if (recoveryResult.success) {
376
- UIComponents.showSuccessBox('Configuration recovered successfully');
377
-
378
- if (recoveryResult.backupCreated) {
379
- console.log(chalk.dim(`Backup created: ${recoveryResult.backupCreated}`));
380
- }
381
-
382
- if (recoveryResult.warnings.length > 0) {
383
- console.log(chalk.yellow('\nāš ļø Recovery warnings:'));
384
- recoveryResult.warnings.forEach(warning => {
385
- console.log(chalk.yellow(` • ${warning}`));
386
- });
387
- }
388
-
389
- // Show recovered configuration
390
- console.log(chalk.cyan('\nšŸ“‹ Recovered Configuration:'));
391
- if (recoveryResult.config) {
392
- console.log(` Version: ${recoveryResult.config.version}`);
393
- console.log(` Targets: ${recoveryResult.config.targets.length} browser(s)`);
394
- console.log(` API Keys: Jules ${recoveryResult.config.apiKeys.jules ? 'āœ“' : 'āœ—'}, Gemini ${recoveryResult.config.apiKeys.gemini ? 'āœ“' : 'āœ—'}`);
395
- console.log(` Automation: ${recoveryResult.config.automation.enabled ? 'Enabled' : 'Disabled'}`);
396
- }
397
-
398
- } else {
399
- UIComponents.showErrorBox('Configuration recovery failed');
400
-
401
- console.log(chalk.red('\nāŒ Recovery errors:'));
402
- recoveryResult.errors.forEach(error => {
403
- console.log(chalk.red(` • ${error}`));
404
- });
405
-
406
- console.log(chalk.cyan('\nšŸ’” Manual recovery options:'));
407
- console.log(chalk.cyan(' • Run "base config recover --interactive" for guided recovery'));
408
- console.log(chalk.cyan(' • Run "base init" to create a fresh configuration'));
409
- console.log(chalk.cyan(' • Manually edit .baseguardrc.json file'));
410
- console.log(chalk.cyan(' • Restore from backup if available'));
411
-
412
- // Show available backups
413
- const backups = await ConfigurationRecovery.listBackups();
414
- if (backups.length > 0) {
415
- console.log(chalk.cyan('\nšŸ“¦ Available backups:'));
416
- backups.slice(0, 3).forEach(backup => {
417
- console.log(chalk.cyan(` • ${backup.timestamp.toLocaleString()} (${backup.source})`));
418
- });
419
- console.log(chalk.cyan('\n Use "base config restore --file <backup-file>" to restore'));
420
- }
421
-
422
- process.exit(1);
423
- }
424
-
425
- } catch (error) {
426
- UIComponents.showErrorBox(`Recovery process failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
427
-
428
- console.log(chalk.cyan('\nšŸ†˜ Emergency recovery options:'));
429
- console.log(chalk.cyan(' • Delete .baseguardrc.json and run "base init"'));
430
- console.log(chalk.cyan(' • Check file permissions in your project directory'));
431
- console.log(chalk.cyan(' • Run "base diagnostics" for comprehensive troubleshooting'));
432
-
433
- process.exit(1);
434
- }
435
- }
436
-
437
- function showConfigHelp(): void {
438
- UIComponents.showSectionHeader('Configuration Commands');
439
- UIComponents.showList([
440
- 'base config show - Display current configuration',
441
- 'base config list - List configuration summary',
442
- 'base config list --format json - List configuration as JSON',
443
- 'base config set-keys - Set up API keys for AI services',
444
- 'base config targets - Configure browser targets',
445
- 'base config targets --add "chrome 100" - Add browser target',
446
- 'base config targets --remove chrome - Remove browser target',
447
- 'base config targets --preset baseline-widely - Set preset targets',
448
- 'base config automation - Configure git automation',
449
- 'base config update - Interactive configuration update',
450
- 'base config validate - Validate configuration file',
451
- 'base config security - Check configuration security',
452
- 'base config backup - Create configuration backup',
453
- 'base config restore --file <backup> - Restore from backup',
454
- 'base config recover - Attempt automatic configuration recovery',
455
- 'base config recover --interactive - Run interactive recovery wizard',
456
- 'base config coding-agent - Manage coding agent selection (Jules vs Gemini)',
457
- 'base config coding-agent --show - Show current agent configuration',
458
- 'base config coding-agent --agent gemini - Set Gemini as primary agent',
459
- '',
460
- 'Shorthand commands:',
461
- 'base add "chrome 100" - Add browser target',
462
- 'base remove chrome - Remove browser target',
463
- 'base list - List configuration summary'
464
- ]);
465
- }
466
-
467
- async function manageCodingAgent(options?: { agent?: string; show?: boolean }): Promise<void> {
468
- try {
469
- const config = await ConfigurationManager.load();
470
-
471
- if (options?.show) {
472
- // Show current coding agent configuration
473
- console.log(chalk.cyan('šŸ¤– Coding Agent Configuration\n'));
474
- console.log(`Primary Agent: ${chalk.white(config.codingAgent.primary)}`);
475
- console.log(`Fallback Agent: ${chalk.white(config.codingAgent.fallback)}`);
476
-
477
- // Show agent status
478
- const { UnifiedCodeFixer } = await import('../ai/unified-code-fixer.js');
479
- const unifiedFixer = new UnifiedCodeFixer(config);
480
- const status = await unifiedFixer.getAgentStatus();
481
-
482
- console.log(chalk.cyan('\nšŸ“Š Agent Status:'));
483
- console.log(`Jules: ${status.jules.configured ? 'šŸ”‘' : 'āŒ'} configured, ${status.jules.available ? 'āœ…' : 'āŒ'} available`);
484
- if (status.jules.repoDetected !== undefined) {
485
- console.log(` ${status.jules.repoDetected ? 'āœ…' : 'āŒ'} GitHub repository detected`);
486
- }
487
- console.log(`Gemini: ${status.gemini.configured ? 'šŸ”‘' : 'āŒ'} configured, ${status.gemini.available ? 'āœ…' : 'āŒ'} available`);
488
-
489
- // Show comparison
490
- unifiedFixer.showAgentComparison();
491
- return;
492
- }
493
-
494
- if (options?.agent) {
495
- // Set specific agent
496
- const agent = options.agent.toLowerCase();
497
- if (agent !== 'jules' && agent !== 'gemini') {
498
- UIComponents.showErrorBox('Invalid agent. Use "jules" or "gemini"');
499
- return;
500
- }
501
-
502
- config.codingAgent.primary = agent as 'jules' | 'gemini';
503
- await ConfigurationManager.save(config);
504
-
505
- console.log(chalk.green(`āœ… Primary coding agent set to ${agent}`));
506
-
507
- // Show setup instructions if API key is missing
508
- if (agent === 'jules' && !config.apiKeys.jules) {
509
- console.log(chalk.yellow('\nāš ļø Jules API key not configured'));
510
- console.log(chalk.cyan('Get your Jules API key: https://jules.google.com/settings#api'));
511
- console.log(chalk.cyan('Run "base config set-keys" to configure it'));
512
- } else if (agent === 'gemini' && !config.apiKeys.gemini) {
513
- console.log(chalk.yellow('\nāš ļø Gemini API key not configured'));
514
- console.log(chalk.cyan('Get your Gemini API key: https://aistudio.google.com'));
515
- console.log(chalk.cyan('Run "base config set-keys" to configure it'));
516
- }
517
-
518
- return;
519
- }
520
-
521
- // Interactive agent selection
522
- const { UnifiedCodeFixer } = await import('../ai/unified-code-fixer.js');
523
- const unifiedFixer = new UnifiedCodeFixer(config);
524
-
525
- // Show current status
526
- console.log(chalk.cyan('šŸ¤– Current Coding Agent Configuration\n'));
527
- console.log(`Primary: ${config.codingAgent.primary}`);
528
- console.log(`Fallback: ${config.codingAgent.fallback}`);
529
-
530
- // Get recommendation
531
- const recommendation = await unifiedFixer.getRecommendedAgent();
532
- console.log(chalk.cyan(`\nšŸ’” Recommended: ${recommendation.agent}`));
533
- console.log(chalk.dim(` Reason: ${recommendation.reason}`));
534
-
535
- // Interactive selection
536
- const { default: inquirer } = await import('inquirer');
537
- const answers = await inquirer.prompt([
538
- {
539
- type: 'list',
540
- name: 'primary',
541
- message: 'Select primary coding agent:',
542
- choices: [
543
- { name: 'Gemini 2.5 Pro (works with any files, immediate)', value: 'gemini' },
544
- { name: 'Jules (GitHub repos only, autonomous)', value: 'jules' }
545
- ],
546
- default: recommendation.agent
547
- },
548
- {
549
- type: 'list',
550
- name: 'fallback',
551
- message: 'Select fallback coding agent:',
552
- choices: [
553
- { name: 'Gemini 2.5 Pro', value: 'gemini' },
554
- { name: 'Jules', value: 'jules' }
555
- ],
556
- default: 'gemini'
557
- }
558
- ]);
559
-
560
- config.codingAgent.primary = answers.primary;
561
- config.codingAgent.fallback = answers.fallback;
562
-
563
- await ConfigurationManager.save(config);
564
-
565
- console.log(chalk.green('\nāœ… Coding agent configuration updated'));
566
- console.log(`Primary: ${answers.primary}`);
567
- console.log(`Fallback: ${answers.fallback}`);
568
-
569
- // Show next steps
570
- console.log(chalk.cyan('\nšŸ”§ Next Steps:'));
571
- if (!config.apiKeys[answers.primary as keyof typeof config.apiKeys]) {
572
- console.log(chalk.cyan(`• Configure ${answers.primary} API key: "base config set-keys"`));
573
- }
574
- if (answers.primary !== answers.fallback && !config.apiKeys[answers.fallback as keyof typeof config.apiKeys]) {
575
- console.log(chalk.cyan(`• Configure ${answers.fallback} API key for fallback: "base config set-keys"`));
576
- }
577
- console.log(chalk.cyan('• Test with: "base fix --analyze-only"'));
578
-
579
- } catch (error) {
580
- UIComponents.showErrorBox(`Failed to manage coding agent: ${error instanceof Error ? error.message : 'Unknown error'}`);
581
- process.exit(1);
582
- }
583
- }
1
+ import { UIComponents, Prompts } from '../ui/index.js';
2
+ import { ConfigurationManager, ApiKeyManager, GitignoreManager } from '../core/index.js';
3
+ import { ConfigurationRecovery } from '../core/configuration-recovery.js';
4
+ import { ErrorHandler } from '../core/error-handler.js';
5
+ import chalk from 'chalk';
6
+
7
+ /**
8
+ * Manage BaseGuard configuration
9
+ */
10
+ export async function config(action: string, options?: {
11
+ add?: string;
12
+ remove?: string;
13
+ preset?: string;
14
+ file?: string;
15
+ format?: string;
16
+ backup?: boolean;
17
+ interactive?: boolean;
18
+ agent?: string;
19
+ show?: boolean;
20
+ }): Promise<void> {
21
+ try {
22
+ switch (action) {
23
+ case 'show':
24
+ await showConfiguration();
25
+ break;
26
+ case 'list':
27
+ await listConfiguration(options?.format);
28
+ break;
29
+ case 'set-keys':
30
+ await setupApiKeys();
31
+ break;
32
+ case 'targets':
33
+ await updateTargets(options);
34
+ break;
35
+ case 'automation':
36
+ await updateAutomation();
37
+ break;
38
+ case 'update':
39
+ await updateConfiguration();
40
+ break;
41
+ case 'validate':
42
+ await validateConfiguration();
43
+ break;
44
+ case 'security':
45
+ await checkSecurity();
46
+ break;
47
+ case 'backup':
48
+ await backupConfiguration();
49
+ break;
50
+ case 'restore':
51
+ await restoreConfiguration(options?.file);
52
+ break;
53
+ case 'recover':
54
+ await recoverConfiguration(options);
55
+ break;
56
+ case 'coding-agent':
57
+ await manageCodingAgent(options);
58
+ break;
59
+ default:
60
+ UIComponents.showErrorBox(`Unknown config action: ${action}`);
61
+ showConfigHelp();
62
+ process.exit(1);
63
+ }
64
+
65
+ } catch (error) {
66
+ const apiError = ErrorHandler.handleAPIError(error);
67
+ ErrorHandler.displayError(apiError);
68
+
69
+ // Provide specific help for config command issues
70
+ console.log('\nšŸ’” Configuration help:');
71
+ if (action === 'set-keys') {
72
+ UIComponents.showList([
73
+ 'Get Gemini API key from https://aistudio.google.com',
74
+ 'Get Jules API key from https://jules.google.com',
75
+ 'Ensure API keys are valid and have proper permissions',
76
+ 'Check your internet connection for key validation'
77
+ ]);
78
+ } else if (action === 'targets') {
79
+ UIComponents.showList([
80
+ 'Use format "browser version" (e.g., "chrome 100")',
81
+ 'Available browsers: chrome, safari, firefox, edge',
82
+ 'Use "baseline" for Baseline-only support',
83
+ 'Check available presets with "base config targets --help"'
84
+ ]);
85
+ } else if (action === 'validate') {
86
+ UIComponents.showList([
87
+ 'Check .baseguardrc.json file exists',
88
+ 'Verify JSON syntax is correct',
89
+ 'Run "base init" to recreate configuration if needed'
90
+ ]);
91
+ } else {
92
+ UIComponents.showList([
93
+ 'Run "base config show" to see current configuration',
94
+ 'Use "base config --help" to see available commands',
95
+ 'Check file permissions in the current directory'
96
+ ]);
97
+ }
98
+
99
+ process.exit(1);
100
+ }
101
+ }
102
+
103
+ async function showConfiguration(): Promise<void> {
104
+ const display = await ConfigurationManager.getConfigurationDisplay();
105
+
106
+ UIComponents.showConfiguration(display.config);
107
+
108
+ // Show security status
109
+ if (!display.security.configIgnored) {
110
+ UIComponents.showWarningBox('Configuration file is not in .gitignore - API keys may be exposed!');
111
+
112
+ if (display.security.recommendations.length > 0) {
113
+ console.log('\nSecurity recommendations:');
114
+ UIComponents.showList(display.security.recommendations);
115
+ }
116
+ }
117
+
118
+ // Show validation errors if any
119
+ if (!display.validation.valid) {
120
+ UIComponents.showErrorBox('Configuration validation failed');
121
+ UIComponents.showList(display.validation.errors);
122
+ }
123
+ }
124
+
125
+ async function listConfiguration(format?: string): Promise<void> {
126
+ const display = await ConfigurationManager.getConfigurationDisplay();
127
+
128
+ if (format === 'json') {
129
+ // Output as JSON for programmatic use
130
+ const output = {
131
+ configuration: display.config,
132
+ security: display.security,
133
+ validation: display.validation,
134
+ status: {
135
+ configured: display.config.apiKeys.jules !== null || display.config.apiKeys.gemini !== null,
136
+ automationEnabled: display.config.automation.enabled,
137
+ targetCount: display.config.targets.length
138
+ }
139
+ };
140
+ console.log(JSON.stringify(output, null, 2));
141
+ return;
142
+ }
143
+
144
+ // Default table format
145
+ UIComponents.showSectionHeader('BaseGuard Configuration Summary');
146
+
147
+ // Configuration overview
148
+ console.log('šŸ“‹ Configuration:');
149
+ console.log(` Version: ${display.config.version}`);
150
+ console.log(` Targets: ${display.config.targets.length} browser(s)`);
151
+ console.log(` API Keys: ${display.config.apiKeys.jules ? 'āœ“' : 'āœ—'} Jules, ${display.config.apiKeys.gemini ? 'āœ“' : 'āœ—'} Gemini`);
152
+ console.log(` Automation: ${display.config.automation.enabled ? 'āœ“ enabled' : 'āœ— disabled'}`);
153
+
154
+ // Browser targets
155
+ console.log('\nšŸŽÆ Browser Targets:');
156
+ display.config.targets.forEach(target => {
157
+ console.log(` • ${target.browser} ${target.minVersion}`);
158
+ });
159
+
160
+ // Automation settings
161
+ console.log('\nšŸ¤– Automation Settings:');
162
+ console.log(` Enabled: ${display.config.automation.enabled ? 'āœ“' : 'āœ—'}`);
163
+ console.log(` Trigger: ${display.config.automation.trigger}`);
164
+ console.log(` Auto-analyze: ${display.config.automation.autoAnalyze ? 'āœ“' : 'āœ—'}`);
165
+ console.log(` Auto-fix: ${display.config.automation.autoFix ? 'āœ“' : 'āœ—'}`);
166
+ console.log(` Block commits: ${display.config.automation.blockCommit ? 'āœ“' : 'āœ—'}`);
167
+
168
+ // Security status
169
+ console.log('\nšŸ”’ Security Status:');
170
+ console.log(` .gitignore exists: ${display.security.gitignoreExists ? 'āœ“' : 'āœ—'}`);
171
+ console.log(` Config file ignored: ${display.security.configIgnored ? 'āœ“' : 'āœ—'}`);
172
+
173
+ // Validation status
174
+ console.log('\nāœ… Validation Status:');
175
+ console.log(` Configuration valid: ${display.validation.valid ? 'āœ“' : 'āœ—'}`);
176
+
177
+ // Show warnings/errors
178
+ if (!display.security.configIgnored) {
179
+ UIComponents.showWarningBox('Configuration file is not in .gitignore - API keys may be exposed!');
180
+ }
181
+
182
+ if (!display.validation.valid) {
183
+ UIComponents.showErrorBox('Configuration validation failed');
184
+ UIComponents.showList(display.validation.errors);
185
+ }
186
+
187
+ if (display.security.recommendations.length > 0) {
188
+ console.log('\nšŸ’” Recommendations:');
189
+ UIComponents.showList(display.security.recommendations);
190
+ }
191
+ }
192
+
193
+ async function setupApiKeys(): Promise<void> {
194
+ const apiKeys = await Prompts.setupApiKeys();
195
+
196
+ if (apiKeys.julesApiKey || apiKeys.geminiApiKey) {
197
+ await ApiKeyManager.storeApiKeys({
198
+ jules: apiKeys.julesApiKey,
199
+ gemini: apiKeys.geminiApiKey
200
+ });
201
+
202
+ UIComponents.showSuccessBox('API keys updated successfully');
203
+
204
+ // Show security reminder
205
+ const security = await GitignoreManager.isConfigSecure();
206
+ if (!security.configIgnored) {
207
+ UIComponents.showWarningBox('Remember to add .baseguardrc.json to .gitignore to protect your API keys');
208
+ }
209
+ } else {
210
+ UIComponents.showInfoBox('No API keys were configured');
211
+ }
212
+ }
213
+
214
+ async function updateTargets(options?: { add?: string; remove?: string; preset?: string }): Promise<void> {
215
+ if (options?.add) {
216
+ // Add a specific browser target
217
+ const target = ConfigurationManager.parseBrowserTarget(options.add);
218
+ if (!target) {
219
+ UIComponents.showErrorBox(`Invalid browser target format: ${options.add}`);
220
+ UIComponents.showInfoBox('Format: "browser version" (e.g., "chrome 100", "safari baseline")');
221
+ return;
222
+ }
223
+
224
+ await ConfigurationManager.addBrowserTarget(target);
225
+ UIComponents.showSuccessBox(`Added browser target: ${target.browser} ${target.minVersion}`);
226
+ return;
227
+ }
228
+
229
+ if (options?.remove) {
230
+ // Remove a specific browser target
231
+ await ConfigurationManager.removeBrowserTarget(options.remove);
232
+ UIComponents.showSuccessBox(`Removed browser target: ${options.remove}`);
233
+ return;
234
+ }
235
+
236
+ if (options?.preset) {
237
+ // Set preset targets
238
+ const presetName = options.preset as any;
239
+ const availablePresets = ConfigurationManager.getAvailablePresets();
240
+
241
+ if (!availablePresets.includes(presetName)) {
242
+ UIComponents.showErrorBox(`Invalid preset: ${options.preset}`);
243
+ UIComponents.showInfoBox(`Available presets: ${availablePresets.join(', ')}`);
244
+ return;
245
+ }
246
+
247
+ await ConfigurationManager.updateWithPreset(presetName);
248
+ UIComponents.showSuccessBox(`Updated to ${presetName} preset`);
249
+ UIComponents.showInfoBox(ConfigurationManager.getPresetDescription(presetName));
250
+ return;
251
+ }
252
+
253
+ // Interactive target configuration
254
+ const targets = await Prompts.promptCustomTargets();
255
+ await ConfigurationManager.updateWithCustomTargets(targets);
256
+ UIComponents.showSuccessBox('Browser targets updated successfully');
257
+ }
258
+
259
+ async function updateAutomation(): Promise<void> {
260
+ const automation = await Prompts.promptAutomationSettings();
261
+ const config = await ConfigurationManager.load();
262
+ config.automation = { ...config.automation, ...automation };
263
+ await ConfigurationManager.save(config);
264
+ UIComponents.showSuccessBox('Automation settings updated successfully');
265
+ }
266
+
267
+ async function updateConfiguration(): Promise<void> {
268
+ const currentConfig = await ConfigurationManager.load();
269
+ const updates = await Prompts.promptConfigUpdate(currentConfig);
270
+
271
+ if (Object.keys(updates).length === 0) {
272
+ UIComponents.showInfoBox('No changes made');
273
+ return;
274
+ }
275
+
276
+ let config = currentConfig;
277
+
278
+ // Apply updates
279
+ for (const [key, value] of Object.entries(updates)) {
280
+ switch (key) {
281
+ case 'targets':
282
+ await ConfigurationManager.updateWithCustomTargets(value as any);
283
+ config = await ConfigurationManager.load(); // Reload after update
284
+ break;
285
+ case 'apiKeys': {
286
+ const apiKeys = value as any;
287
+ if (apiKeys.julesApiKey) config.apiKeys.jules = apiKeys.julesApiKey;
288
+ if (apiKeys.geminiApiKey) config.apiKeys.gemini = apiKeys.geminiApiKey;
289
+ break;
290
+ }
291
+ case 'automation':
292
+ config.automation = { ...config.automation, ...(value as any) };
293
+ break;
294
+ }
295
+ }
296
+
297
+ await ConfigurationManager.save(config);
298
+ UIComponents.showSuccessBox('Configuration updated successfully');
299
+ }
300
+
301
+ async function validateConfiguration(): Promise<void> {
302
+ const display = await ConfigurationManager.getConfigurationDisplay();
303
+
304
+ if (display.validation.valid) {
305
+ UIComponents.showSuccessBox('Configuration is valid');
306
+ } else {
307
+ UIComponents.showErrorBox('Configuration validation failed');
308
+ UIComponents.showList(display.validation.errors);
309
+ process.exit(1);
310
+ }
311
+ }
312
+
313
+ async function checkSecurity(): Promise<void> {
314
+ const security = await GitignoreManager.isConfigSecure();
315
+
316
+ UIComponents.showSectionHeader('Security Status');
317
+
318
+ console.log(`āœ“ .gitignore exists: ${security.gitignoreExists ? 'Yes' : 'No'}`);
319
+ console.log(`āœ“ Config file ignored: ${security.configIgnored ? 'Yes' : 'No'}`);
320
+
321
+ if (security.recommendations.length > 0) {
322
+ console.log('\nRecommendations:');
323
+ UIComponents.showList(security.recommendations);
324
+ } else {
325
+ UIComponents.showSuccessBox('Configuration is secure');
326
+ }
327
+ }
328
+
329
+ async function backupConfiguration(): Promise<void> {
330
+ try {
331
+ const backupFile = await ConfigurationManager.backupConfiguration();
332
+ UIComponents.showSuccessBox(`Configuration backed up to: ${backupFile}`);
333
+ } catch (error) {
334
+ UIComponents.showErrorBox(`Backup failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
335
+ process.exit(1);
336
+ }
337
+ }
338
+
339
+ async function restoreConfiguration(backupFile?: string): Promise<void> {
340
+ if (!backupFile) {
341
+ UIComponents.showErrorBox('Backup file path is required');
342
+ console.log('Usage: base config restore --file <backup-file>');
343
+ process.exit(1);
344
+ }
345
+
346
+ try {
347
+ await ConfigurationManager.restoreConfiguration(backupFile);
348
+ UIComponents.showSuccessBox('Configuration restored successfully');
349
+ } catch (error) {
350
+ UIComponents.showErrorBox(`Restore failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
351
+ process.exit(1);
352
+ }
353
+ }
354
+
355
+ async function recoverConfiguration(options?: { backup?: boolean; interactive?: boolean }): Promise<void> {
356
+ try {
357
+ console.log(chalk.cyan('šŸ”§ BaseGuard Configuration Recovery\n'));
358
+
359
+ if (options?.interactive) {
360
+ // Run interactive recovery wizard
361
+ await ConfigurationRecovery.runRecoveryWizard();
362
+ return;
363
+ }
364
+
365
+ // Automatic recovery
366
+ console.log(chalk.cyan('Attempting automatic configuration recovery...'));
367
+
368
+ const recoveryResult = await ConfigurationRecovery.recoverConfiguration({
369
+ createBackup: options?.backup ?? true,
370
+ validateConfig: true,
371
+ migrateVersion: true,
372
+ repairCorruption: true,
373
+ useDefaults: true
374
+ });
375
+
376
+ if (recoveryResult.success) {
377
+ UIComponents.showSuccessBox('Configuration recovered successfully');
378
+
379
+ if (recoveryResult.backupCreated) {
380
+ console.log(chalk.dim(`Backup created: ${recoveryResult.backupCreated}`));
381
+ }
382
+
383
+ if (recoveryResult.warnings.length > 0) {
384
+ console.log(chalk.yellow('\nāš ļø Recovery warnings:'));
385
+ recoveryResult.warnings.forEach(warning => {
386
+ console.log(chalk.yellow(` • ${warning}`));
387
+ });
388
+ }
389
+
390
+ // Show recovered configuration
391
+ console.log(chalk.cyan('\nšŸ“‹ Recovered Configuration:'));
392
+ if (recoveryResult.config) {
393
+ console.log(` Version: ${recoveryResult.config.version}`);
394
+ console.log(` Targets: ${recoveryResult.config.targets.length} browser(s)`);
395
+ console.log(` API Keys: Jules ${recoveryResult.config.apiKeys.jules ? 'āœ“' : 'āœ—'}, Gemini ${recoveryResult.config.apiKeys.gemini ? 'āœ“' : 'āœ—'}`);
396
+ console.log(` Automation: ${recoveryResult.config.automation.enabled ? 'Enabled' : 'Disabled'}`);
397
+ }
398
+
399
+ } else {
400
+ UIComponents.showErrorBox('Configuration recovery failed');
401
+
402
+ console.log(chalk.red('\nāŒ Recovery errors:'));
403
+ recoveryResult.errors.forEach(error => {
404
+ console.log(chalk.red(` • ${error}`));
405
+ });
406
+
407
+ console.log(chalk.cyan('\nšŸ’” Manual recovery options:'));
408
+ console.log(chalk.cyan(' • Run "base config recover --interactive" for guided recovery'));
409
+ console.log(chalk.cyan(' • Run "base init" to create a fresh configuration'));
410
+ console.log(chalk.cyan(' • Manually edit .baseguardrc.json file'));
411
+ console.log(chalk.cyan(' • Restore from backup if available'));
412
+
413
+ // Show available backups
414
+ const backups = await ConfigurationRecovery.listBackups();
415
+ if (backups.length > 0) {
416
+ console.log(chalk.cyan('\nšŸ“¦ Available backups:'));
417
+ backups.slice(0, 3).forEach(backup => {
418
+ console.log(chalk.cyan(` • ${backup.timestamp.toLocaleString()} (${backup.source})`));
419
+ });
420
+ console.log(chalk.cyan('\n Use "base config restore --file <backup-file>" to restore'));
421
+ }
422
+
423
+ process.exit(1);
424
+ }
425
+
426
+ } catch (error) {
427
+ UIComponents.showErrorBox(`Recovery process failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
428
+
429
+ console.log(chalk.cyan('\nšŸ†˜ Emergency recovery options:'));
430
+ console.log(chalk.cyan(' • Delete .baseguardrc.json and run "base init"'));
431
+ console.log(chalk.cyan(' • Check file permissions in your project directory'));
432
+ console.log(chalk.cyan(' • Run "base diagnostics" for comprehensive troubleshooting'));
433
+
434
+ process.exit(1);
435
+ }
436
+ }
437
+
438
+ function showConfigHelp(): void {
439
+ UIComponents.showSectionHeader('Configuration Commands');
440
+ UIComponents.showList([
441
+ 'base config show - Display current configuration',
442
+ 'base config list - List configuration summary',
443
+ 'base config list --format json - List configuration as JSON',
444
+ 'base config set-keys - Set up API keys for AI services',
445
+ 'base config targets - Configure browser targets',
446
+ 'base config targets --add "chrome 100" - Add browser target',
447
+ 'base config targets --remove chrome - Remove browser target',
448
+ 'base config targets --preset baseline-widely - Set preset targets',
449
+ 'base config automation - Configure git automation',
450
+ 'base config update - Interactive configuration update',
451
+ 'base config validate - Validate configuration file',
452
+ 'base config security - Check configuration security',
453
+ 'base config backup - Create configuration backup',
454
+ 'base config restore --file <backup> - Restore from backup',
455
+ 'base config recover - Attempt automatic configuration recovery',
456
+ 'base config recover --interactive - Run interactive recovery wizard',
457
+ 'base config coding-agent - Manage coding agent selection (Jules vs Gemini)',
458
+ 'base config coding-agent --show - Show current agent configuration',
459
+ 'base config coding-agent --agent gemini - Set Gemini as primary agent',
460
+ '',
461
+ 'Shorthand commands:',
462
+ 'base add "chrome 100" - Add browser target',
463
+ 'base remove chrome - Remove browser target',
464
+ 'base list - List configuration summary'
465
+ ]);
466
+ }
467
+
468
+ async function manageCodingAgent(options?: { agent?: string; show?: boolean }): Promise<void> {
469
+ try {
470
+ const config = await ConfigurationManager.load();
471
+
472
+ if (options?.show) {
473
+ // Show current coding agent configuration
474
+ console.log(chalk.cyan('šŸ¤– Coding Agent Configuration\n'));
475
+ console.log(`Primary Agent: ${chalk.white(config.codingAgent.primary)}`);
476
+ console.log(`Fallback Agent: ${chalk.white(config.codingAgent.fallback)}`);
477
+
478
+ // Show agent status
479
+ const { UnifiedCodeFixer } = await import('../ai/unified-code-fixer.js');
480
+ const unifiedFixer = new UnifiedCodeFixer(config);
481
+ const status = await unifiedFixer.getAgentStatus();
482
+
483
+ console.log(chalk.cyan('\nšŸ“Š Agent Status:'));
484
+ console.log(`Jules: ${status.jules.configured ? 'šŸ”‘' : 'āŒ'} configured, ${status.jules.available ? 'āœ…' : 'āŒ'} available`);
485
+ if (status.jules.repoDetected !== undefined) {
486
+ console.log(` ${status.jules.repoDetected ? 'āœ…' : 'āŒ'} GitHub repository detected`);
487
+ }
488
+ console.log(`Gemini: ${status.gemini.configured ? 'šŸ”‘' : 'āŒ'} configured, ${status.gemini.available ? 'āœ…' : 'āŒ'} available`);
489
+
490
+ // Show comparison
491
+ unifiedFixer.showAgentComparison();
492
+ return;
493
+ }
494
+
495
+ if (options?.agent) {
496
+ // Set specific agent
497
+ const agent = options.agent.toLowerCase();
498
+ if (agent !== 'jules' && agent !== 'gemini') {
499
+ UIComponents.showErrorBox('Invalid agent. Use "jules" or "gemini"');
500
+ return;
501
+ }
502
+
503
+ config.codingAgent.primary = agent as 'jules' | 'gemini';
504
+ await ConfigurationManager.save(config);
505
+
506
+ console.log(chalk.green(`āœ… Primary coding agent set to ${agent}`));
507
+
508
+ // Show setup instructions if API key is missing
509
+ if (agent === 'jules' && !config.apiKeys.jules) {
510
+ console.log(chalk.yellow('\nāš ļø Jules API key not configured'));
511
+ console.log(chalk.cyan('Get your Jules API key: https://jules.google.com/settings#api'));
512
+ console.log(chalk.cyan('Run "base config set-keys" to configure it'));
513
+ } else if (agent === 'gemini' && !config.apiKeys.gemini) {
514
+ console.log(chalk.yellow('\nāš ļø Gemini API key not configured'));
515
+ console.log(chalk.cyan('Get your Gemini API key: https://aistudio.google.com'));
516
+ console.log(chalk.cyan('Run "base config set-keys" to configure it'));
517
+ }
518
+
519
+ return;
520
+ }
521
+
522
+ // Interactive agent selection
523
+ const { UnifiedCodeFixer } = await import('../ai/unified-code-fixer.js');
524
+ const unifiedFixer = new UnifiedCodeFixer(config);
525
+
526
+ // Show current status
527
+ console.log(chalk.cyan('šŸ¤– Current Coding Agent Configuration\n'));
528
+ console.log(`Primary: ${config.codingAgent.primary}`);
529
+ console.log(`Fallback: ${config.codingAgent.fallback}`);
530
+
531
+ // Get recommendation
532
+ const recommendation = await unifiedFixer.getRecommendedAgent();
533
+ console.log(chalk.cyan(`\nšŸ’” Recommended: ${recommendation.agent}`));
534
+ console.log(chalk.dim(` Reason: ${recommendation.reason}`));
535
+
536
+ // Interactive selection
537
+ const { default: inquirer } = await import('inquirer');
538
+ const answers = await inquirer.prompt([
539
+ {
540
+ type: 'list',
541
+ name: 'primary',
542
+ message: 'Select primary coding agent:',
543
+ choices: [
544
+ { name: 'Gemini 2.5 Pro (works with any files, immediate)', value: 'gemini' },
545
+ { name: 'Jules (GitHub repos only, autonomous)', value: 'jules' }
546
+ ],
547
+ default: recommendation.agent
548
+ },
549
+ {
550
+ type: 'list',
551
+ name: 'fallback',
552
+ message: 'Select fallback coding agent:',
553
+ choices: [
554
+ { name: 'Gemini 2.5 Pro', value: 'gemini' },
555
+ { name: 'Jules', value: 'jules' }
556
+ ],
557
+ default: 'gemini'
558
+ }
559
+ ]);
560
+
561
+ config.codingAgent.primary = answers.primary;
562
+ config.codingAgent.fallback = answers.fallback;
563
+
564
+ await ConfigurationManager.save(config);
565
+
566
+ console.log(chalk.green('\nāœ… Coding agent configuration updated'));
567
+ console.log(`Primary: ${answers.primary}`);
568
+ console.log(`Fallback: ${answers.fallback}`);
569
+
570
+ // Show next steps
571
+ console.log(chalk.cyan('\nšŸ”§ Next Steps:'));
572
+ if (!config.apiKeys[answers.primary as keyof typeof config.apiKeys]) {
573
+ console.log(chalk.cyan(`• Configure ${answers.primary} API key: "base config set-keys"`));
574
+ }
575
+ if (answers.primary !== answers.fallback && !config.apiKeys[answers.fallback as keyof typeof config.apiKeys]) {
576
+ console.log(chalk.cyan(`• Configure ${answers.fallback} API key for fallback: "base config set-keys"`));
577
+ }
578
+ console.log(chalk.cyan('• Test with: "base fix --analyze-only"'));
579
+
580
+ } catch (error) {
581
+ UIComponents.showErrorBox(`Failed to manage coding agent: ${error instanceof Error ? error.message : 'Unknown error'}`);
582
+ process.exit(1);
583
+ }
584
+ }