baseguard 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/dist/ai/gemini-analyzer.d.ts.map +1 -1
  2. package/dist/ai/gemini-analyzer.js +1 -1
  3. package/dist/ai/gemini-analyzer.js.map +1 -1
  4. package/dist/ai/gemini-code-fixer.d.ts.map +1 -1
  5. package/dist/ai/gemini-code-fixer.js +2 -7
  6. package/dist/ai/gemini-code-fixer.js.map +1 -1
  7. package/dist/ai/jules-implementer.d.ts +8 -0
  8. package/dist/ai/jules-implementer.d.ts.map +1 -1
  9. package/dist/ai/jules-implementer.js +115 -17
  10. package/dist/ai/jules-implementer.js.map +1 -1
  11. package/package.json +1 -1
  12. package/src/ai/__tests__/gemini-analyzer.test.ts +0 -181
  13. package/src/ai/agentkit-orchestrator.ts +0 -534
  14. package/src/ai/fix-manager.ts +0 -362
  15. package/src/ai/gemini-analyzer.ts +0 -665
  16. package/src/ai/gemini-code-fixer.ts +0 -539
  17. package/src/ai/index.ts +0 -4
  18. package/src/ai/jules-implementer.ts +0 -504
  19. package/src/ai/unified-code-fixer.ts +0 -347
  20. package/src/commands/automation.ts +0 -344
  21. package/src/commands/check.ts +0 -298
  22. package/src/commands/config.ts +0 -584
  23. package/src/commands/fix.ts +0 -269
  24. package/src/commands/index.ts +0 -7
  25. package/src/commands/init.ts +0 -156
  26. package/src/commands/status.ts +0 -307
  27. package/src/core/api-key-manager.ts +0 -298
  28. package/src/core/baseguard.ts +0 -757
  29. package/src/core/baseline-checker.ts +0 -566
  30. package/src/core/cache-manager.ts +0 -272
  31. package/src/core/configuration-recovery.ts +0 -672
  32. package/src/core/configuration.ts +0 -596
  33. package/src/core/debug-logger.ts +0 -590
  34. package/src/core/directory-filter.ts +0 -421
  35. package/src/core/error-handler.ts +0 -518
  36. package/src/core/file-processor.ts +0 -338
  37. package/src/core/gitignore-manager.ts +0 -169
  38. package/src/core/graceful-degradation-manager.ts +0 -596
  39. package/src/core/index.ts +0 -17
  40. package/src/core/lazy-loader.ts +0 -317
  41. package/src/core/logger.ts +0 -0
  42. package/src/core/memory-manager.ts +0 -290
  43. package/src/core/parser-worker.ts +0 -33
  44. package/src/core/startup-optimizer.ts +0 -246
  45. package/src/core/system-error-handler.ts +0 -755
  46. package/src/git/automation-engine.ts +0 -361
  47. package/src/git/github-manager.ts +0 -190
  48. package/src/git/hook-manager.ts +0 -210
  49. package/src/git/index.ts +0 -4
  50. package/src/index.ts +0 -8
  51. package/src/parsers/feature-validator.ts +0 -559
  52. package/src/parsers/index.ts +0 -8
  53. package/src/parsers/parser-manager.ts +0 -418
  54. package/src/parsers/parser.ts +0 -26
  55. package/src/parsers/react-parser-optimized.ts +0 -161
  56. package/src/parsers/react-parser.ts +0 -359
  57. package/src/parsers/svelte-parser.ts +0 -510
  58. package/src/parsers/vanilla-parser.ts +0 -685
  59. package/src/parsers/vue-parser.ts +0 -476
  60. package/src/types/index.ts +0 -96
  61. package/src/ui/components.ts +0 -567
  62. package/src/ui/help.ts +0 -193
  63. package/src/ui/index.ts +0 -4
  64. package/src/ui/prompts.ts +0 -681
  65. package/src/ui/terminal-header.ts +0 -59
  66. package/tests/e2e/baseguard.e2e.test.ts +0 -516
  67. package/tests/e2e/cross-platform.e2e.test.ts +0 -420
  68. package/tests/e2e/git-integration.e2e.test.ts +0 -487
  69. package/tests/fixtures/react-project/package.json +0 -14
  70. package/tests/fixtures/react-project/src/App.css +0 -76
  71. package/tests/fixtures/react-project/src/App.tsx +0 -77
  72. package/tests/fixtures/svelte-project/package.json +0 -11
  73. package/tests/fixtures/svelte-project/src/App.svelte +0 -369
  74. package/tests/fixtures/vanilla-project/index.html +0 -76
  75. package/tests/fixtures/vanilla-project/script.js +0 -331
  76. package/tests/fixtures/vanilla-project/styles.css +0 -359
  77. package/tests/fixtures/vue-project/package.json +0 -12
  78. package/tests/fixtures/vue-project/src/App.vue +0 -216
  79. package/tmp-smoke/.baseguard/backups/config-2026-02-19T12-04-11-067Z-auto.json +0 -30
  80. package/tmp-smoke/src/bad.css +0 -3
@@ -1,539 +0,0 @@
1
- import type { Violation, Analysis, Fix } from '../types/index.js';
2
- import { promises as fs } from 'fs';
3
- import { ErrorHandler, APIError, ErrorType } from '../core/error-handler.js';
4
- import { logger } from '../core/debug-logger.js';
5
-
6
- /**
7
- * Gemini 2.5 Pro code fixer for local files and repositories
8
- * Works with any code (GitHub or not, committed or uncommitted)
9
- */
10
- export class GeminiCodeFixer {
11
- private apiKey: string;
12
- private baseUrl = 'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent';
13
- private categoryLogger: ReturnType<typeof logger.createCategoryLogger>;
14
-
15
- constructor(apiKey: string) {
16
- this.apiKey = apiKey;
17
- this.categoryLogger = logger.createCategoryLogger('gemini-code-fixer');
18
- }
19
-
20
- /**
21
- * Generate a fix using Gemini 2.5 Pro with grounding
22
- */
23
- async generateFix(violation: Violation, analysis: Analysis): Promise<Fix> {
24
- const context = ErrorHandler.createContext('gemini_code_fix', {
25
- feature: violation.feature,
26
- file: violation.file,
27
- browser: violation.browser
28
- });
29
-
30
- try {
31
- this.categoryLogger.info('Generating code fix', {
32
- feature: violation.feature,
33
- file: violation.file,
34
- strategy: analysis.fixStrategy
35
- });
36
-
37
- // Read the current file content
38
- const fileContent = await this.readFileContent(violation.file);
39
-
40
- // Build the fix prompt with file context
41
- const prompt = this.buildFixPrompt(violation, analysis, fileContent);
42
-
43
- const response = await ErrorHandler.withRetry(
44
- () => this.makeApiCall(prompt),
45
- {
46
- maxRetries: 2,
47
- retryableErrors: [ErrorType.NETWORK, ErrorType.TIMEOUT, ErrorType.RATE_LIMIT, ErrorType.SERVER_ERROR]
48
- }
49
- );
50
-
51
- const data = await response.json();
52
-
53
- // Validate response structure
54
- ErrorHandler.validateAPIResponse(data, ['candidates']);
55
-
56
- if (!data.candidates || data.candidates.length === 0) {
57
- throw new APIError(
58
- 'No fix candidates returned from Gemini API',
59
- ErrorType.VALIDATION,
60
- {
61
- suggestions: [
62
- 'Try rephrasing the fix request',
63
- 'Check if the code is valid',
64
- 'Try again with a different approach'
65
- ],
66
- context
67
- }
68
- );
69
- }
70
-
71
- const candidate = data.candidates[0];
72
- const content = candidate.content?.parts?.[0]?.text;
73
-
74
- if (!content) {
75
- throw new APIError(
76
- 'Empty fix content returned from Gemini API',
77
- ErrorType.VALIDATION,
78
- {
79
- suggestions: [
80
- 'Try the fix generation again',
81
- 'Check if the violation data is complete',
82
- 'Verify API key permissions'
83
- ],
84
- context
85
- }
86
- );
87
- }
88
-
89
- // Parse the fix response and generate proper diff
90
- const fix = await this.parseFixResponse(content, violation, analysis, fileContent);
91
-
92
- this.categoryLogger.info('Code fix generated successfully', {
93
- feature: violation.feature,
94
- confidence: fix.confidence,
95
- hasPreview: fix.preview.length > 0
96
- });
97
-
98
- return fix;
99
-
100
- } catch (error) {
101
- const apiError = ErrorHandler.handleAPIError(error, context);
102
- this.categoryLogger.error('Code fix generation failed', { error: apiError });
103
- throw apiError;
104
- }
105
- }
106
-
107
- /**
108
- * Make API call to Gemini 2.5 Pro with grounding
109
- */
110
- private async makeApiCall(prompt: string): Promise<Response> {
111
- const response = await fetch(this.baseUrl, {
112
- method: 'POST',
113
- headers: {
114
- 'x-goog-api-key': this.apiKey,
115
- 'Content-Type': 'application/json'
116
- },
117
- body: JSON.stringify({
118
- contents: [{
119
- parts: [{ text: prompt }]
120
- }],
121
- tools: [{
122
- googleSearchRetrieval: {
123
- dynamicRetrievalConfig: {
124
- mode: 'MODE_DYNAMIC',
125
- dynamicThreshold: 0.7
126
- }
127
- }
128
- }],
129
- generationConfig: {
130
- temperature: 0.1,
131
- topK: 40,
132
- topP: 0.95,
133
- maxOutputTokens: 4096,
134
- candidateCount: 1
135
- }
136
- })
137
- });
138
-
139
- if (!response.ok) {
140
- const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
141
- (error as any).response = response;
142
- throw error;
143
- }
144
-
145
- return response;
146
- }
147
-
148
- /**
149
- * Build comprehensive fix prompt for Gemini 2.5 Pro
150
- */
151
- private buildFixPrompt(violation: Violation, analysis: Analysis, fileContent: string): string {
152
- return `You are an expert web developer tasked with fixing browser compatibility issues. Generate a precise code fix with proper diff format.
153
-
154
- ## COMPATIBILITY ISSUE
155
- - **Feature**: ${violation.feature}
156
- - **File**: ${violation.file} (line ${violation.line})
157
- - **Unsupported Browser**: ${violation.browser} ${violation.required}
158
- - **Baseline Status**: ${violation.baselineStatus}
159
- - **Current Code Context**: ${violation.context}
160
-
161
- ## ANALYSIS INSIGHTS
162
- - **Fix Strategy**: ${analysis.fixStrategy}
163
- - **User Impact**: ${analysis.userImpact}
164
- - **Market Share Affected**: ${(analysis.marketShare * 100).toFixed(1)}%
165
- - **Best Practices**: ${analysis.bestPractices.join(', ')}
166
-
167
- ## CURRENT FILE CONTENT
168
- \`\`\`${this.getFileExtension(violation.file)}
169
- ${fileContent}
170
- \`\`\`
171
-
172
- ## REQUIREMENTS
173
- 1. **Fix the compatibility issue** using ${analysis.fixStrategy}
174
- 2. **Preserve all existing functionality** - no breaking changes
175
- 3. **Add proper fallbacks** for ${violation.browser} ${violation.required}
176
- 4. **Follow best practices**: ${analysis.bestPractices.join(', ')}
177
- 5. **Generate a unified diff** showing exactly what changes to make
178
- 6. **Provide clear explanation** of the fix approach
179
-
180
- ## OUTPUT FORMAT
181
- Please provide your response in this exact format:
182
-
183
- ### EXPLANATION
184
- [Explain the fix approach and why it works]
185
-
186
- ### DIFF
187
- \`\`\`diff
188
- --- a/${violation.file}
189
- +++ b/${violation.file}
190
- @@ -[start_line],[num_lines] +[start_line],[num_lines] @@
191
- [unified diff content showing the exact changes]
192
- \`\`\`
193
-
194
- ### PREVIEW
195
- \`\`\`${this.getFileExtension(violation.file)}
196
- [Show the key changed sections with context]
197
- \`\`\`
198
-
199
- ### TESTING
200
- [Suggest how to test the fix works in ${violation.browser} ${violation.required}]
201
-
202
- Focus on creating a production-ready fix that maintains compatibility across all browsers while adding proper support for ${violation.browser} ${violation.required}.`;
203
- }
204
-
205
- /**
206
- * Read file content with error handling
207
- */
208
- private async readFileContent(filePath: string): Promise<string> {
209
- try {
210
- return await fs.readFile(filePath, 'utf-8');
211
- } catch (error) {
212
- this.categoryLogger.warn('Could not read file content', {
213
- file: filePath,
214
- error: error instanceof Error ? error.message : 'Unknown error'
215
- });
216
-
217
- // Return empty content if file can't be read
218
- return `// File content could not be read: ${filePath}`;
219
- }
220
- }
221
-
222
- /**
223
- * Get file extension for syntax highlighting
224
- */
225
- private getFileExtension(filePath: string): string {
226
- const ext = filePath.split('.').pop()?.toLowerCase();
227
-
228
- const extensionMap: Record<string, string> = {
229
- 'js': 'javascript',
230
- 'jsx': 'javascript',
231
- 'ts': 'typescript',
232
- 'tsx': 'typescript',
233
- 'vue': 'vue',
234
- 'svelte': 'svelte',
235
- 'css': 'css',
236
- 'scss': 'scss',
237
- 'sass': 'sass',
238
- 'html': 'html',
239
- 'htm': 'html'
240
- };
241
-
242
- return extensionMap[ext || ''] || 'text';
243
- }
244
-
245
- /**
246
- * Parse Gemini's fix response and create Fix object
247
- */
248
- private async parseFixResponse(
249
- content: string,
250
- violation: Violation,
251
- analysis: Analysis,
252
- originalContent: string
253
- ): Promise<Fix> {
254
- try {
255
- // Extract sections from the response
256
- const explanation = this.extractSection(content, 'EXPLANATION');
257
- const diffContent = this.extractSection(content, 'DIFF');
258
- const preview = this.extractSection(content, 'PREVIEW');
259
- const testing = this.extractSection(content, 'TESTING');
260
-
261
- // Clean up the diff content
262
- const cleanDiff = this.cleanDiffContent(diffContent);
263
-
264
- // Generate a human-readable preview if not provided
265
- const finalPreview = preview || this.generatePreviewFromDiff(cleanDiff, originalContent);
266
-
267
- // Calculate confidence based on response quality
268
- const confidence = this.calculateFixConfidence(content, diffContent);
269
-
270
- // Create comprehensive explanation
271
- const fullExplanation = this.buildFullExplanation(
272
- violation,
273
- analysis,
274
- explanation,
275
- testing
276
- );
277
-
278
- return {
279
- violation,
280
- analysis,
281
- patch: cleanDiff,
282
- explanation: fullExplanation,
283
- filePath: violation.file,
284
- preview: finalPreview,
285
- confidence,
286
- testable: true
287
- };
288
-
289
- } catch (error) {
290
- this.categoryLogger.error('Failed to parse fix response', { error });
291
-
292
- // Return a basic fix with the raw content
293
- return {
294
- violation,
295
- analysis,
296
- patch: this.generateBasicDiff(violation.file, content),
297
- explanation: `Fix generated for ${violation.feature} compatibility issue.\n\n${content}`,
298
- filePath: violation.file,
299
- preview: content.substring(0, 500) + (content.length > 500 ? '...' : ''),
300
- confidence: 0.6,
301
- testable: true
302
- };
303
- }
304
- }
305
-
306
- /**
307
- * Extract a specific section from the response
308
- */
309
- private extractSection(content: string, sectionName: string): string {
310
- const regex = new RegExp(`### ${sectionName}\\s*\\n([\\s\\S]*?)(?=\\n### |$)`, 'i');
311
- const match = content.match(regex);
312
-
313
- if (match && match[1]) {
314
- return match[1].trim();
315
- }
316
-
317
- return '';
318
- }
319
-
320
- /**
321
- * Clean and validate diff content
322
- */
323
- private cleanDiffContent(diffContent: string): string {
324
- if (!diffContent) {
325
- return '';
326
- }
327
-
328
- // Remove code block markers if present
329
- let cleaned = diffContent.replace(/^```diff\\n|```$/gm, '').trim();
330
-
331
- // Ensure it starts with proper diff headers
332
- if (!cleaned.startsWith('---') && !cleaned.startsWith('@@')) {
333
- // If it's just the diff content without headers, add basic headers
334
- cleaned = `--- a/file\n+++ b/file\n${cleaned}`;
335
- }
336
-
337
- return cleaned;
338
- }
339
-
340
- /**
341
- * Generate preview from diff content
342
- */
343
- private generatePreviewFromDiff(diffContent: string, _originalContent: string): string {
344
- if (!diffContent) {
345
- return 'No preview available';
346
- }
347
-
348
- try {
349
- // Extract added lines from diff
350
- const addedLines = diffContent
351
- .split('\n')
352
- .filter(line => line.startsWith('+') && !line.startsWith('+++'))
353
- .map(line => line.substring(1))
354
- .join('\n');
355
-
356
- if (addedLines) {
357
- return `Changes to be applied:\n\n${addedLines}`;
358
- }
359
- } catch (error) {
360
- // Fallback to showing first part of diff
361
- }
362
-
363
- return diffContent.substring(0, 300) + (diffContent.length > 300 ? '...' : '');
364
- }
365
-
366
- /**
367
- * Calculate confidence score based on response quality
368
- */
369
- private calculateFixConfidence(content: string, diffContent: string): number {
370
- let confidence = 0.5; // Base confidence
371
-
372
- // Check if response has proper structure
373
- if (content.includes('### EXPLANATION')) confidence += 0.1;
374
- if (content.includes('### DIFF')) confidence += 0.1;
375
- if (content.includes('### PREVIEW')) confidence += 0.1;
376
- if (content.includes('### TESTING')) confidence += 0.1;
377
-
378
- // Check diff quality
379
- if (diffContent && diffContent.includes('@@')) confidence += 0.1;
380
- if (diffContent && (diffContent.includes('+') || diffContent.includes('-'))) confidence += 0.1;
381
-
382
- return Math.min(confidence, 0.9); // Cap at 0.9
383
- }
384
-
385
- /**
386
- * Build comprehensive explanation
387
- */
388
- private buildFullExplanation(
389
- violation: Violation,
390
- analysis: Analysis,
391
- explanation: string,
392
- testing: string
393
- ): string {
394
- let fullExplanation = `Fixed ${violation.feature} compatibility issue in ${violation.file}\n\n`;
395
-
396
- if (explanation) {
397
- fullExplanation += `## Fix Approach\n${explanation}\n\n`;
398
- }
399
-
400
- fullExplanation += `## Strategy Applied\n${analysis.fixStrategy}\n\n`;
401
- fullExplanation += `## Browser Support\nThis fix ensures compatibility with ${violation.browser} ${violation.required} and newer versions.\n\n`;
402
-
403
- if (testing) {
404
- fullExplanation += `## Testing\n${testing}\n\n`;
405
- }
406
-
407
- fullExplanation += `## Best Practices Applied\n${analysis.bestPractices.map(practice => `• ${practice}`).join('\n')}`;
408
-
409
- return fullExplanation;
410
- }
411
-
412
- /**
413
- * Generate basic diff as fallback
414
- */
415
- private generateBasicDiff(filePath: string, content: string): string {
416
- return `--- a/${filePath}
417
- +++ b/${filePath}
418
- @@ -1,1 +1,1 @@
419
- -// Original code (manual review required)
420
- +// Fixed code: ${content.substring(0, 100)}${content.length > 100 ? '...' : ''}
421
-
422
- # Manual fix required - please review the generated content above
423
- # and apply the appropriate changes to your code.`;
424
- }
425
-
426
- /**
427
- * Test API connectivity
428
- */
429
- async testConnection(): Promise<{ success: boolean; error?: string; errorType?: ErrorType }> {
430
- try {
431
- const testPrompt = 'Generate a simple "Hello, World!" comment in JavaScript.';
432
- const response = await this.makeApiCall(testPrompt);
433
-
434
- const data = await response.json();
435
-
436
- if (data.candidates && data.candidates.length > 0) {
437
- return { success: true };
438
- } else {
439
- return {
440
- success: false,
441
- error: 'API responded but returned no content',
442
- errorType: ErrorType.VALIDATION
443
- };
444
- }
445
- } catch (error) {
446
- const apiError = ErrorHandler.handleAPIError(error);
447
-
448
- return {
449
- success: false,
450
- error: apiError.message,
451
- errorType: apiError.type
452
- };
453
- }
454
- }
455
-
456
- /**
457
- * Validate API key format
458
- */
459
- public static validateApiKey(apiKey: string): boolean {
460
- // Gemini API keys typically start with 'AIza' and are 39+ characters long
461
- return /^AIza[A-Za-z0-9_-]{35,}$/.test(apiKey) || apiKey.length >= 20;
462
- }
463
-
464
- /**
465
- * Generate multiple fix options for complex issues
466
- */
467
- async generateFixOptions(violation: Violation, analysis: Analysis): Promise<Fix[]> {
468
- const fixes: Fix[] = [];
469
-
470
- try {
471
- // Generate primary fix
472
- const primaryFix = await this.generateFix(violation, analysis);
473
- fixes.push(primaryFix);
474
-
475
- // Generate alternative approaches if confidence is low
476
- if (primaryFix.confidence < 0.7) {
477
- this.categoryLogger.info('Generating alternative fix approaches', {
478
- feature: violation.feature,
479
- primaryConfidence: primaryFix.confidence
480
- });
481
-
482
- const alternativeFix = await this.generateAlternativeFix(violation, analysis);
483
- if (alternativeFix) {
484
- fixes.push(alternativeFix);
485
- }
486
- }
487
-
488
- } catch (error) {
489
- this.categoryLogger.error('Failed to generate fix options', { error });
490
- throw error;
491
- }
492
-
493
- return fixes;
494
- }
495
-
496
- /**
497
- * Generate alternative fix approach
498
- */
499
- private async generateAlternativeFix(violation: Violation, analysis: Analysis): Promise<Fix | null> {
500
- try {
501
- const fileContent = await this.readFileContent(violation.file);
502
-
503
- // Build alternative prompt with different strategy
504
- const alternativePrompt = this.buildAlternativeFixPrompt(violation, analysis, fileContent);
505
-
506
- const response = await this.makeApiCall(alternativePrompt);
507
- const data = await response.json();
508
-
509
- if (data.candidates && data.candidates.length > 0) {
510
- const content = data.candidates[0].content?.parts?.[0]?.text;
511
- if (content) {
512
- const fix = await this.parseFixResponse(content, violation, analysis, fileContent);
513
- fix.explanation = `Alternative approach: ${fix.explanation}`;
514
- return fix;
515
- }
516
- }
517
-
518
- } catch (error) {
519
- this.categoryLogger.warn('Failed to generate alternative fix', { error });
520
- }
521
-
522
- return null;
523
- }
524
-
525
- /**
526
- * Build alternative fix prompt with different strategy
527
- */
528
- private buildAlternativeFixPrompt(violation: Violation, analysis: Analysis, fileContent: string): string {
529
- const alternativeStrategies = {
530
- 'progressive enhancement with @supports': 'feature detection with JavaScript',
531
- 'feature detection with polyfills': 'progressive enhancement with @supports',
532
- 'graceful degradation': 'polyfill-based approach'
533
- };
534
-
535
- const altStrategy = alternativeStrategies[analysis.fixStrategy as keyof typeof alternativeStrategies] || 'alternative progressive enhancement';
536
-
537
- return this.buildFixPrompt(violation, { ...analysis, fixStrategy: altStrategy }, fileContent);
538
- }
539
- }
package/src/ai/index.ts DELETED
@@ -1,4 +0,0 @@
1
- // AI layer exports
2
- export * from './gemini-analyzer.js';
3
- export * from './jules-implementer.js';
4
- export * from './fix-manager.js';