baseguard 1.0.3 → 1.0.5

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 +627 -627
  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 +48 -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 +8 -5
  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.map +1 -1
  67. package/dist/core/startup-optimizer.js +4 -8
  68. package/dist/core/startup-optimizer.js.map +1 -1
  69. package/dist/core/system-error-handler.d.ts.map +1 -1
  70. package/dist/core/system-error-handler.js.map +1 -1
  71. package/dist/git/automation-engine.d.ts.map +1 -1
  72. package/dist/git/automation-engine.js +5 -4
  73. package/dist/git/automation-engine.js.map +1 -1
  74. package/dist/git/github-manager.d.ts.map +1 -1
  75. package/dist/git/github-manager.js.map +1 -1
  76. package/dist/git/hook-manager.js +5 -5
  77. package/dist/git/hook-manager.js.map +1 -1
  78. package/dist/parsers/parser-manager.d.ts.map +1 -1
  79. package/dist/parsers/parser-manager.js +1 -1
  80. package/dist/parsers/parser-manager.js.map +1 -1
  81. package/dist/parsers/svelte-parser.js +1 -1
  82. package/dist/parsers/svelte-parser.js.map +1 -1
  83. package/dist/parsers/vanilla-parser.d.ts.map +1 -1
  84. package/dist/parsers/vanilla-parser.js.map +1 -1
  85. package/dist/parsers/vue-parser.d.ts.map +1 -1
  86. package/dist/parsers/vue-parser.js.map +1 -1
  87. package/dist/ui/components.d.ts +1 -1
  88. package/dist/ui/components.d.ts.map +1 -1
  89. package/dist/ui/components.js +11 -11
  90. package/dist/ui/components.js.map +1 -1
  91. package/dist/ui/terminal-header.js +14 -14
  92. package/package.json +105 -105
  93. package/src/ai/__tests__/gemini-analyzer.test.ts +180 -180
  94. package/src/ai/agentkit-orchestrator.ts +533 -533
  95. package/src/ai/fix-manager.ts +362 -362
  96. package/src/ai/gemini-analyzer.ts +665 -671
  97. package/src/ai/gemini-code-fixer.ts +539 -540
  98. package/src/ai/index.ts +3 -3
  99. package/src/ai/jules-implementer.ts +504 -460
  100. package/src/ai/unified-code-fixer.ts +347 -347
  101. package/src/commands/automation.ts +343 -343
  102. package/src/commands/check.ts +298 -299
  103. package/src/commands/config.ts +584 -583
  104. package/src/commands/fix.ts +269 -238
  105. package/src/commands/index.ts +6 -6
  106. package/src/commands/init.ts +155 -155
  107. package/src/commands/status.ts +306 -306
  108. package/src/core/api-key-manager.ts +298 -298
  109. package/src/core/baseguard.ts +757 -756
  110. package/src/core/baseline-checker.ts +566 -563
  111. package/src/core/cache-manager.ts +271 -271
  112. package/src/core/configuration-recovery.ts +672 -673
  113. package/src/core/configuration.ts +595 -595
  114. package/src/core/debug-logger.ts +590 -590
  115. package/src/core/directory-filter.ts +420 -420
  116. package/src/core/error-handler.ts +518 -517
  117. package/src/core/file-processor.ts +337 -337
  118. package/src/core/gitignore-manager.ts +168 -168
  119. package/src/core/graceful-degradation-manager.ts +596 -596
  120. package/src/core/index.ts +16 -16
  121. package/src/core/lazy-loader.ts +317 -307
  122. package/src/core/memory-manager.ts +290 -295
  123. package/src/core/parser-worker.ts +33 -0
  124. package/src/core/startup-optimizer.ts +246 -255
  125. package/src/core/system-error-handler.ts +755 -756
  126. package/src/git/automation-engine.ts +361 -361
  127. package/src/git/github-manager.ts +190 -192
  128. package/src/git/hook-manager.ts +210 -210
  129. package/src/git/index.ts +3 -3
  130. package/src/index.ts +7 -7
  131. package/src/parsers/feature-validator.ts +558 -558
  132. package/src/parsers/index.ts +7 -7
  133. package/src/parsers/parser-manager.ts +418 -419
  134. package/src/parsers/parser.ts +25 -25
  135. package/src/parsers/react-parser-optimized.ts +160 -160
  136. package/src/parsers/react-parser.ts +358 -358
  137. package/src/parsers/svelte-parser.ts +510 -510
  138. package/src/parsers/vanilla-parser.ts +685 -686
  139. package/src/parsers/vue-parser.ts +476 -478
  140. package/src/types/index.ts +95 -95
  141. package/src/ui/components.ts +567 -567
  142. package/src/ui/help.ts +192 -192
  143. package/src/ui/index.ts +3 -3
  144. package/src/ui/prompts.ts +680 -680
  145. package/src/ui/terminal-header.ts +58 -58
  146. package/test-build.js +40 -40
  147. package/test-config-commands.js +55 -55
  148. package/test-header-simple.js +32 -32
  149. package/test-terminal-header.js +11 -11
  150. package/test-ui.js +28 -28
  151. package/tests/e2e/baseguard.e2e.test.ts +515 -515
  152. package/tests/e2e/cross-platform.e2e.test.ts +419 -419
  153. package/tests/e2e/git-integration.e2e.test.ts +486 -486
  154. package/tests/fixtures/react-project/package.json +13 -13
  155. package/tests/fixtures/react-project/src/App.css +75 -75
  156. package/tests/fixtures/react-project/src/App.tsx +76 -76
  157. package/tests/fixtures/svelte-project/package.json +10 -10
  158. package/tests/fixtures/svelte-project/src/App.svelte +368 -368
  159. package/tests/fixtures/vanilla-project/index.html +75 -75
  160. package/tests/fixtures/vanilla-project/script.js +330 -330
  161. package/tests/fixtures/vanilla-project/styles.css +358 -358
  162. package/tests/fixtures/vue-project/package.json +11 -11
  163. package/tests/fixtures/vue-project/src/App.vue +215 -215
  164. package/tmp-smoke/.baseguard/backups/config-2026-02-19T12-04-11-067Z-auto.json +30 -0
  165. package/tmp-smoke/src/bad.css +3 -0
  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,361 +1,361 @@
1
- import { execSync } from 'child_process';
2
- import { readFileSync } from 'fs';
3
- import chalk from 'chalk';
4
- import ora from 'ora';
5
- import inquirer from 'inquirer';
6
- import type { AutomationOptions, Violation, Analysis, Fix, Configuration } from '../types/index.js';
7
- import { ConfigurationManager } from '../core/configuration.js';
8
- import { BaseGuard } from '../core/baseguard.js';
9
- import { UIComponents } from '../ui/components.js';
10
- import { GeminiAnalyzer } from '../ai/gemini-analyzer.js';
11
- import { JulesImplementer } from '../ai/jules-implementer.js';
12
-
13
- /**
14
- * Automation engine for git workflow integration
15
- */
16
- export class AutomationEngine {
17
- private config: Configuration;
18
- private baseGuard: BaseGuard;
19
-
20
- constructor(config?: Configuration) {
21
- this.config = config || ConfigurationManager.createDefault();
22
- this.baseGuard = new BaseGuard(this.config);
23
- }
24
-
25
- /**
26
- * Run automation for git hooks
27
- */
28
- async run(options: AutomationOptions): Promise<void> {
29
- try {
30
- // Load current configuration
31
- this.config = await ConfigurationManager.load();
32
- this.baseGuard = new BaseGuard(this.config);
33
-
34
- // Check if automation is enabled
35
- if (!this.config.automation.enabled) {
36
- console.log(chalk.yellow('⚠️ BaseGuard automation is disabled. Run "base automation enable" to enable it.'));
37
- return;
38
- }
39
-
40
- // Check if this is the correct trigger
41
- if (this.config.automation.trigger !== options.trigger) {
42
- // Silently exit if this isn't the configured trigger
43
- return;
44
- }
45
-
46
- console.log(chalk.cyan(`🛡️ BaseGuard automation running (${options.trigger})...`));
47
-
48
- // Step 1: Check violations in staged files
49
- const violations = await this.checkViolations(options.trigger);
50
-
51
- if (violations.length === 0) {
52
- console.log(chalk.green('✅ No compatibility issues found'));
53
- return;
54
- }
55
-
56
- console.log(chalk.yellow(`⚠️ Found ${violations.length} compatibility issue(s)`));
57
- UIComponents.showViolations(violations);
58
-
59
- // Step 2: Analyze violations (if enabled and API key available)
60
- let analyses: Analysis[] = [];
61
- if (this.config.automation.autoAnalyze && this.config.apiKeys.gemini) {
62
- analyses = await this.analyzeViolations(violations);
63
- }
64
-
65
- // Step 3: Auto-fix (if enabled and API keys available)
66
- if (this.config.automation.autoFix && this.config.apiKeys.jules && this.config.apiKeys.gemini) {
67
- const fixes = await this.generateFixes(violations, analyses);
68
- if (fixes.length > 0) {
69
- await this.applyFixes(fixes);
70
- await this.stageChanges();
71
- console.log(chalk.green('✅ All issues fixed automatically and staged'));
72
- return;
73
- }
74
- }
75
-
76
- // Manual mode - show options
77
- await this.showManualOptions(violations, analyses);
78
-
79
- // Block commit if configured to do so
80
- if (this.config.automation.blockCommit && !options.strict === false) {
81
- console.log(chalk.red('❌ Commit blocked due to compatibility issues'));
82
- console.log(chalk.dim('Use --no-verify to bypass this check'));
83
- process.exit(1);
84
- }
85
-
86
- } catch (error) {
87
- console.error(chalk.red(' BaseGuard automation failed:'), error instanceof Error ? error.message : 'Unknown error');
88
-
89
- // Don't block commit on automation errors unless in strict mode
90
- if (options.strict) {
91
- process.exit(1);
92
- }
93
- }
94
- }
95
-
96
- /**
97
- * Check violations in staged files (for pre-commit) or all files (for pre-push)
98
- */
99
- private async checkViolations(trigger: 'pre-commit' | 'pre-push'): Promise<Violation[]> {
100
- const spinner = ora('Checking for compatibility violations...').start();
101
-
102
- try {
103
- let filesToCheck: string[] = [];
104
-
105
- if (trigger === 'pre-commit') {
106
- // Get staged files for pre-commit
107
- filesToCheck = this.getStagedFiles();
108
- } else {
109
- // For pre-push, check all files in the repository
110
- filesToCheck = this.getAllTrackedFiles();
111
- }
112
-
113
- // Filter to only supported file types
114
- const supportedExtensions = ['.js', '.ts', '.jsx', '.tsx', '.vue', '.svelte', '.css', '.html'];
115
- const filteredFiles = filesToCheck.filter(file =>
116
- supportedExtensions.some(ext => file.endsWith(ext))
117
- );
118
-
119
- if (filteredFiles.length === 0) {
120
- spinner.succeed('No supported files to check');
121
- return [];
122
- }
123
-
124
- spinner.text = `Checking ${filteredFiles.length} file(s)...`;
125
-
126
- // Use BaseGuard to check violations
127
- const violations = await this.baseGuard.checkViolations(filteredFiles);
128
-
129
- spinner.succeed(`Checked ${filteredFiles.length} file(s)`);
130
- return violations;
131
-
132
- } catch (error) {
133
- spinner.fail('Failed to check violations');
134
- throw error;
135
- }
136
- }
137
-
138
- /**
139
- * Get staged files from git
140
- */
141
- private getStagedFiles(): string[] {
142
- try {
143
- const output = execSync('git diff --cached --name-only', { encoding: 'utf-8' });
144
- return output.trim().split('\n').filter(file => file.length > 0);
145
- } catch (error) {
146
- console.warn(chalk.yellow('⚠️ Could not get staged files, checking all files'));
147
- return this.getAllTrackedFiles();
148
- }
149
- }
150
-
151
- /**
152
- * Get all tracked files from git
153
- */
154
- private getAllTrackedFiles(): string[] {
155
- try {
156
- const output = execSync('git ls-files', { encoding: 'utf-8' });
157
- return output.trim().split('\n').filter(file => file.length > 0);
158
- } catch (error) {
159
- throw new Error('Could not get tracked files from git');
160
- }
161
- }
162
-
163
- /**
164
- * Analyze violations if auto-analyze is enabled
165
- */
166
- private async analyzeViolations(violations: Violation[]): Promise<Analysis[]> {
167
- if (!this.config.apiKeys.gemini) {
168
- console.log(chalk.yellow('⚠️ Gemini API key not configured, skipping analysis'));
169
- return [];
170
- }
171
-
172
- const spinner = ora('Analyzing violations with AI...').start();
173
-
174
- try {
175
- const analyzer = new GeminiAnalyzer(this.config.apiKeys.gemini);
176
- const analyses: Analysis[] = [];
177
-
178
- // Analyze violations in batches to avoid rate limiting
179
- for (const violation of violations) {
180
- try {
181
- const analysis = await analyzer.analyzeViolation(violation);
182
- analyses.push(analysis);
183
- } catch (error) {
184
- console.warn(chalk.yellow(`⚠️ Could not analyze ${violation.feature}: ${error instanceof Error ? error.message : 'Unknown error'}`));
185
- }
186
- }
187
-
188
- spinner.succeed(`Analyzed ${analyses.length} violation(s)`);
189
- return analyses;
190
-
191
- } catch (error) {
192
- spinner.fail('Failed to analyze violations');
193
- throw error;
194
- }
195
- }
196
-
197
- /**
198
- * Generate and apply fixes if auto-fix is enabled
199
- */
200
- private async generateFixes(violations: Violation[], analyses: Analysis[]): Promise<Fix[]> {
201
- if (!this.config.apiKeys.jules) {
202
- console.log(chalk.yellow('⚠️ Jules API key not configured, skipping auto-fix'));
203
- return [];
204
- }
205
-
206
- const spinner = ora('Generating fixes with AI...').start();
207
-
208
- try {
209
- const implementer = new JulesImplementer(this.config.apiKeys.jules);
210
- const fixes: Fix[] = [];
211
-
212
- // Generate fixes for violations that have analyses
213
- for (const violation of violations) {
214
- const analysis = analyses.find(a => a.violation.feature === violation.feature);
215
- if (!analysis) continue;
216
-
217
- try {
218
- // For automation, we need a repository source - this would need to be configured
219
- // For now, we'll skip Jules integration in automation mode
220
- console.log(chalk.yellow('⚠️ Jules integration requires repository setup, skipping auto-fix'));
221
- break;
222
- } catch (error) {
223
- console.warn(chalk.yellow(`⚠️ Could not generate fix for ${violation.feature}: ${error instanceof Error ? error.message : 'Unknown error'}`));
224
- }
225
- }
226
-
227
- spinner.succeed(`Generated ${fixes.length} fix(es)`);
228
- return fixes;
229
-
230
- } catch (error) {
231
- spinner.fail('Failed to generate fixes');
232
- throw error;
233
- }
234
- }
235
-
236
- /**
237
- * Apply fixes to files
238
- */
239
- private async applyFixes(fixes: Fix[]): Promise<void> {
240
- const spinner = ora('Applying fixes...').start();
241
-
242
- try {
243
- // This would use the BaseGuard.applyFixes method when implemented
244
- // For now, we'll just log that fixes would be applied
245
- spinner.succeed(`Applied ${fixes.length} fix(es)`);
246
- } catch (error) {
247
- spinner.fail('Failed to apply fixes');
248
- throw error;
249
- }
250
- }
251
-
252
- /**
253
- * Stage changes after fixing
254
- */
255
- private async stageChanges(): Promise<void> {
256
- try {
257
- execSync('git add -u', { stdio: 'ignore' });
258
- } catch (error) {
259
- console.warn(chalk.yellow('⚠️ Could not stage changes automatically'));
260
- }
261
- }
262
-
263
- /**
264
- * Show manual options when auto-fix is disabled
265
- */
266
- private async showManualOptions(violations: Violation[], analyses: Analysis[] = []): Promise<void> {
267
- console.log(chalk.cyan('\n🔧 Manual Options:'));
268
-
269
- const choices = [
270
- {
271
- name: 'Continue with commit (ignore violations)',
272
- value: 'continue'
273
- },
274
- {
275
- name: 'Fix violations manually and retry',
276
- value: 'manual'
277
- }
278
- ];
279
-
280
- // Add AI options if API keys are available
281
- if (this.config.apiKeys.gemini && analyses.length === 0) {
282
- choices.unshift({
283
- name: 'Analyze violations with AI first',
284
- value: 'analyze'
285
- });
286
- }
287
-
288
- if (this.config.apiKeys.jules && this.config.apiKeys.gemini) {
289
- choices.unshift({
290
- name: 'Generate and preview AI fixes',
291
- value: 'fix'
292
- });
293
- }
294
-
295
- const { action } = await inquirer.prompt([
296
- {
297
- type: 'list',
298
- name: 'action',
299
- message: 'What would you like to do?',
300
- choices
301
- }
302
- ]);
303
-
304
- switch (action) {
305
- case 'continue':
306
- console.log(chalk.yellow('⚠️ Continuing with violations...'));
307
- break;
308
-
309
- case 'manual':
310
- console.log(chalk.blue('💡 Fix the violations manually and run git commit again'));
311
- process.exit(1);
312
-
313
- case 'analyze':
314
- console.log(chalk.blue('🔍 Run "base check --analyze" to get AI analysis'));
315
- process.exit(1);
316
-
317
- case 'fix':
318
- console.log(chalk.blue('🤖 Run "base fix" to generate and preview AI fixes'));
319
- process.exit(1);
320
-
321
- default:
322
- process.exit(1);
323
- }
324
- }
325
-
326
- /**
327
- * Check if git repository has uncommitted changes
328
- */
329
- private hasUncommittedChanges(): boolean {
330
- try {
331
- const output = execSync('git status --porcelain', { encoding: 'utf-8' });
332
- return output.trim().length > 0;
333
- } catch {
334
- return false;
335
- }
336
- }
337
-
338
- /**
339
- * Get current git branch
340
- */
341
- private getCurrentBranch(): string {
342
- try {
343
- const output = execSync('git branch --show-current', { encoding: 'utf-8' });
344
- return output.trim();
345
- } catch {
346
- return 'unknown';
347
- }
348
- }
349
-
350
- /**
351
- * Check if we're in a git repository
352
- */
353
- private isGitRepository(): boolean {
354
- try {
355
- execSync('git rev-parse --git-dir', { stdio: 'ignore' });
356
- return true;
357
- } catch {
358
- return false;
359
- }
360
- }
361
- }
1
+ import { execSync } from 'child_process';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ import inquirer from 'inquirer';
5
+ import type { AutomationOptions, Violation, Analysis, Fix, Configuration } from '../types/index.js';
6
+ import { ConfigurationManager } from '../core/configuration.js';
7
+ import { BaseGuard } from '../core/baseguard.js';
8
+ import { UIComponents } from '../ui/components.js';
9
+ import { GeminiAnalyzer } from '../ai/gemini-analyzer.js';
10
+
11
+ /**
12
+ * Automation engine for git workflow integration
13
+ */
14
+ export class AutomationEngine {
15
+ private config: Configuration;
16
+ private baseGuard: BaseGuard;
17
+
18
+ constructor(config?: Configuration) {
19
+ this.config = config || ConfigurationManager.createDefault();
20
+ this.baseGuard = new BaseGuard(this.config);
21
+ }
22
+
23
+ /**
24
+ * Run automation for git hooks
25
+ */
26
+ async run(options: AutomationOptions): Promise<void> {
27
+ try {
28
+ // Load current configuration
29
+ this.config = await ConfigurationManager.load();
30
+ this.baseGuard = new BaseGuard(this.config);
31
+
32
+ // Check if automation is enabled
33
+ if (!this.config.automation.enabled) {
34
+ console.log(chalk.yellow('⚠️ BaseGuard automation is disabled. Run "base automation enable" to enable it.'));
35
+ return;
36
+ }
37
+
38
+ // Check if this is the correct trigger
39
+ if (this.config.automation.trigger !== options.trigger) {
40
+ // Silently exit if this isn't the configured trigger
41
+ return;
42
+ }
43
+
44
+ console.log(chalk.cyan(`🛡️ BaseGuard automation running (${options.trigger})...`));
45
+
46
+ // Step 1: Check violations in staged files
47
+ const violations = await this.checkViolations(options.trigger);
48
+
49
+ if (violations.length === 0) {
50
+ console.log(chalk.green('✅ No compatibility issues found'));
51
+ return;
52
+ }
53
+
54
+ console.log(chalk.yellow(`⚠️ Found ${violations.length} compatibility issue(s)`));
55
+ UIComponents.showViolations(violations);
56
+
57
+ // Step 2: Analyze violations (if enabled and API key available)
58
+ let analyses: Analysis[] = [];
59
+ if (this.config.automation.autoAnalyze && this.config.apiKeys.gemini) {
60
+ analyses = await this.analyzeViolations(violations);
61
+ }
62
+
63
+ // Step 3: Auto-fix (if enabled and API keys available)
64
+ if (this.config.automation.autoFix && this.config.apiKeys.jules && this.config.apiKeys.gemini) {
65
+ const fixes = await this.generateFixes(violations, analyses);
66
+ if (fixes.length > 0) {
67
+ await this.applyFixes(fixes);
68
+ await this.stageChanges();
69
+ console.log(chalk.green('✅ All issues fixed automatically and staged'));
70
+ return;
71
+ }
72
+ }
73
+
74
+ // Manual mode - show options
75
+ await this.showManualOptions(violations, analyses);
76
+
77
+ // Block commit if configured to do so
78
+ if (this.config.automation.blockCommit && options.strict !== false) {
79
+ console.log(chalk.red('❌ Commit blocked due to compatibility issues'));
80
+ console.log(chalk.dim('Use --no-verify to bypass this check'));
81
+ process.exit(1);
82
+ }
83
+
84
+ } catch (error) {
85
+ console.error(chalk.red('❌ BaseGuard automation failed:'), error instanceof Error ? error.message : 'Unknown error');
86
+
87
+ // Don't block commit on automation errors unless in strict mode
88
+ if (options.strict) {
89
+ process.exit(1);
90
+ }
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Check violations in staged files (for pre-commit) or all files (for pre-push)
96
+ */
97
+ private async checkViolations(trigger: 'pre-commit' | 'pre-push'): Promise<Violation[]> {
98
+ const spinner = ora('Checking for compatibility violations...').start();
99
+
100
+ try {
101
+ let filesToCheck: string[] = [];
102
+
103
+ if (trigger === 'pre-commit') {
104
+ // Get staged files for pre-commit
105
+ filesToCheck = this.getStagedFiles();
106
+ } else {
107
+ // For pre-push, check all files in the repository
108
+ filesToCheck = this.getAllTrackedFiles();
109
+ }
110
+
111
+ // Filter to only supported file types
112
+ const supportedExtensions = ['.js', '.ts', '.jsx', '.tsx', '.vue', '.svelte', '.css', '.html'];
113
+ const filteredFiles = filesToCheck.filter(file =>
114
+ supportedExtensions.some(ext => file.endsWith(ext))
115
+ );
116
+
117
+ if (filteredFiles.length === 0) {
118
+ spinner.succeed('No supported files to check');
119
+ return [];
120
+ }
121
+
122
+ spinner.text = `Checking ${filteredFiles.length} file(s)...`;
123
+
124
+ // Use BaseGuard to check violations
125
+ const violations = await this.baseGuard.checkViolations(filteredFiles);
126
+
127
+ spinner.succeed(`Checked ${filteredFiles.length} file(s)`);
128
+ return violations;
129
+
130
+ } catch (error) {
131
+ spinner.fail('Failed to check violations');
132
+ throw error;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Get staged files from git
138
+ */
139
+ private getStagedFiles(): string[] {
140
+ try {
141
+ const output = execSync('git diff --cached --name-only', { encoding: 'utf-8' });
142
+ return output.trim().split('\n').filter(file => file.length > 0);
143
+ } catch (error) {
144
+ console.warn(chalk.yellow('⚠️ Could not get staged files, checking all files'));
145
+ return this.getAllTrackedFiles();
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Get all tracked files from git
151
+ */
152
+ private getAllTrackedFiles(): string[] {
153
+ try {
154
+ const output = execSync('git ls-files', { encoding: 'utf-8' });
155
+ return output.trim().split('\n').filter(file => file.length > 0);
156
+ } catch (error) {
157
+ throw new Error('Could not get tracked files from git');
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Analyze violations if auto-analyze is enabled
163
+ */
164
+ private async analyzeViolations(violations: Violation[]): Promise<Analysis[]> {
165
+ if (!this.config.apiKeys.gemini) {
166
+ console.log(chalk.yellow('⚠️ Gemini API key not configured, skipping analysis'));
167
+ return [];
168
+ }
169
+
170
+ const spinner = ora('Analyzing violations with AI...').start();
171
+
172
+ try {
173
+ const analyzer = new GeminiAnalyzer(this.config.apiKeys.gemini);
174
+ const analyses: Analysis[] = [];
175
+
176
+ // Analyze violations in batches to avoid rate limiting
177
+ for (const violation of violations) {
178
+ try {
179
+ const analysis = await analyzer.analyzeViolation(violation);
180
+ analyses.push(analysis);
181
+ } catch (error) {
182
+ console.warn(chalk.yellow(`⚠️ Could not analyze ${violation.feature}: ${error instanceof Error ? error.message : 'Unknown error'}`));
183
+ }
184
+ }
185
+
186
+ spinner.succeed(`Analyzed ${analyses.length} violation(s)`);
187
+ return analyses;
188
+
189
+ } catch (error) {
190
+ spinner.fail('Failed to analyze violations');
191
+ throw error;
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Generate and apply fixes if auto-fix is enabled
197
+ */
198
+ private async generateFixes(violations: Violation[], analyses: Analysis[]): Promise<Fix[]> {
199
+ if (!this.config.apiKeys.jules) {
200
+ console.log(chalk.yellow('⚠️ Jules API key not configured, skipping auto-fix'));
201
+ return [];
202
+ }
203
+
204
+ const spinner = ora('Generating fixes with AI...').start();
205
+
206
+ try {
207
+ const fixes: Fix[] = [];
208
+
209
+ // Generate fixes for violations that have analyses
210
+ for (const violation of violations) {
211
+ const analysis = analyses.find(a => a.violation.feature === violation.feature);
212
+ if (!analysis) continue;
213
+
214
+ try {
215
+ // For automation, we need a repository source - this would need to be configured
216
+ // For now, we'll skip Jules integration in automation mode
217
+ console.log(chalk.yellow('⚠️ Jules integration requires repository setup, skipping auto-fix'));
218
+ break;
219
+ } catch (error) {
220
+ console.warn(chalk.yellow(`⚠️ Could not generate fix for ${violation.feature}: ${error instanceof Error ? error.message : 'Unknown error'}`));
221
+ }
222
+ }
223
+
224
+ spinner.succeed(`Generated ${fixes.length} fix(es)`);
225
+ return fixes;
226
+
227
+ } catch (error) {
228
+ spinner.fail('Failed to generate fixes');
229
+ throw error;
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Apply fixes to files
235
+ */
236
+ private async applyFixes(fixes: Fix[]): Promise<void> {
237
+ const spinner = ora('Applying fixes...').start();
238
+
239
+ try {
240
+ // This would use the BaseGuard.applyFixes method when implemented
241
+ // For now, we'll just log that fixes would be applied
242
+ spinner.succeed(`Applied ${fixes.length} fix(es)`);
243
+ } catch (error) {
244
+ spinner.fail('Failed to apply fixes');
245
+ throw error;
246
+ }
247
+ }
248
+
249
+ /**
250
+ * Stage changes after fixing
251
+ */
252
+ private async stageChanges(): Promise<void> {
253
+ try {
254
+ execSync('git add -u', { stdio: 'ignore' });
255
+ } catch (error) {
256
+ console.warn(chalk.yellow('⚠️ Could not stage changes automatically'));
257
+ }
258
+ }
259
+
260
+ /**
261
+ * Show manual options when auto-fix is disabled
262
+ */
263
+ private async showManualOptions(violations: Violation[], analyses: Analysis[] = []): Promise<void> {
264
+ console.log(chalk.cyan('\n🔧 Manual Options:'));
265
+
266
+ const choices = [
267
+ {
268
+ name: 'Continue with commit (ignore violations)',
269
+ value: 'continue'
270
+ },
271
+ {
272
+ name: 'Fix violations manually and retry',
273
+ value: 'manual'
274
+ }
275
+ ];
276
+
277
+ // Add AI options if API keys are available
278
+ if (this.config.apiKeys.gemini && analyses.length === 0) {
279
+ choices.unshift({
280
+ name: 'Analyze violations with AI first',
281
+ value: 'analyze'
282
+ });
283
+ }
284
+
285
+ if (this.config.apiKeys.jules && this.config.apiKeys.gemini) {
286
+ choices.unshift({
287
+ name: 'Generate and preview AI fixes',
288
+ value: 'fix'
289
+ });
290
+ }
291
+
292
+ const { action } = await inquirer.prompt([
293
+ {
294
+ type: 'list',
295
+ name: 'action',
296
+ message: 'What would you like to do?',
297
+ choices
298
+ }
299
+ ]);
300
+
301
+ switch (action) {
302
+ case 'continue':
303
+ console.log(chalk.yellow('⚠️ Continuing with violations...'));
304
+ break;
305
+
306
+ case 'manual':
307
+ console.log(chalk.blue('💡 Fix the violations manually and run git commit again'));
308
+ process.exit(1);
309
+ return;
310
+
311
+ case 'analyze':
312
+ console.log(chalk.blue('🔍 Run "base fix --analyze-only" to get AI analysis'));
313
+ process.exit(1);
314
+ return;
315
+
316
+ case 'fix':
317
+ console.log(chalk.blue('🤖 Run "base fix" to generate and preview AI fixes'));
318
+ process.exit(1);
319
+ return;
320
+
321
+ default:
322
+ process.exit(1);
323
+ }
324
+ }
325
+
326
+ /**
327
+ * Check if git repository has uncommitted changes
328
+ */
329
+ private hasUncommittedChanges(): boolean {
330
+ try {
331
+ const output = execSync('git status --porcelain', { encoding: 'utf-8' });
332
+ return output.trim().length > 0;
333
+ } catch {
334
+ return false;
335
+ }
336
+ }
337
+
338
+ /**
339
+ * Get current git branch
340
+ */
341
+ private getCurrentBranch(): string {
342
+ try {
343
+ const output = execSync('git branch --show-current', { encoding: 'utf-8' });
344
+ return output.trim();
345
+ } catch {
346
+ return 'unknown';
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Check if we're in a git repository
352
+ */
353
+ private isGitRepository(): boolean {
354
+ try {
355
+ execSync('git rev-parse --git-dir', { stdio: 'ignore' });
356
+ return true;
357
+ } catch {
358
+ return false;
359
+ }
360
+ }
361
+ }