baseguard 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +25 -0
- package/.prettierrc +8 -0
- package/README.md +94 -0
- package/bin/base.js +494 -0
- package/dist/ai/fix-manager.d.ts +67 -0
- package/dist/ai/fix-manager.d.ts.map +1 -0
- package/dist/ai/fix-manager.js +326 -0
- package/dist/ai/fix-manager.js.map +1 -0
- package/dist/ai/gemini-analyzer.d.ts +116 -0
- package/dist/ai/gemini-analyzer.d.ts.map +1 -0
- package/dist/ai/gemini-analyzer.js +572 -0
- package/dist/ai/gemini-analyzer.js.map +1 -0
- package/dist/ai/index.d.ts +4 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +5 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/jules-implementer.d.ts +115 -0
- package/dist/ai/jules-implementer.d.ts.map +1 -0
- package/dist/ai/jules-implementer.js +387 -0
- package/dist/ai/jules-implementer.js.map +1 -0
- package/dist/commands/automation.d.ts +5 -0
- package/dist/commands/automation.d.ts.map +1 -0
- package/dist/commands/automation.js +305 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/check.d.ts +9 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +113 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/config.d.ts +11 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +324 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/fix.d.ts +9 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +207 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +125 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/core/api-key-manager.d.ts +83 -0
- package/dist/core/api-key-manager.d.ts.map +1 -0
- package/dist/core/api-key-manager.js +244 -0
- package/dist/core/api-key-manager.js.map +1 -0
- package/dist/core/baseguard.d.ts +46 -0
- package/dist/core/baseguard.d.ts.map +1 -0
- package/dist/core/baseguard.js +132 -0
- package/dist/core/baseguard.js.map +1 -0
- package/dist/core/baseline-checker.d.ts +63 -0
- package/dist/core/baseline-checker.d.ts.map +1 -0
- package/dist/core/baseline-checker.js +502 -0
- package/dist/core/baseline-checker.js.map +1 -0
- package/dist/core/cache-manager.d.ts +88 -0
- package/dist/core/cache-manager.d.ts.map +1 -0
- package/dist/core/cache-manager.js +213 -0
- package/dist/core/cache-manager.js.map +1 -0
- package/dist/core/configuration.d.ts +140 -0
- package/dist/core/configuration.d.ts.map +1 -0
- package/dist/core/configuration.js +474 -0
- package/dist/core/configuration.js.map +1 -0
- package/dist/core/directory-filter.d.ts +90 -0
- package/dist/core/directory-filter.d.ts.map +1 -0
- package/dist/core/directory-filter.js +319 -0
- package/dist/core/directory-filter.js.map +1 -0
- package/dist/core/error-handler.d.ts +110 -0
- package/dist/core/error-handler.d.ts.map +1 -0
- package/dist/core/error-handler.js +392 -0
- package/dist/core/error-handler.js.map +1 -0
- package/dist/core/file-processor.d.ts +80 -0
- package/dist/core/file-processor.d.ts.map +1 -0
- package/dist/core/file-processor.js +259 -0
- package/dist/core/file-processor.js.map +1 -0
- package/dist/core/gitignore-manager.d.ts +44 -0
- package/dist/core/gitignore-manager.d.ts.map +1 -0
- package/dist/core/gitignore-manager.js +147 -0
- package/dist/core/gitignore-manager.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lazy-loader.d.ts +68 -0
- package/dist/core/lazy-loader.d.ts.map +1 -0
- package/dist/core/lazy-loader.js +260 -0
- package/dist/core/lazy-loader.js.map +1 -0
- package/dist/core/memory-manager.d.ts +1 -0
- package/dist/core/memory-manager.d.ts.map +1 -0
- package/dist/core/memory-manager.js +2 -0
- package/dist/core/memory-manager.js.map +1 -0
- package/dist/core/startup-optimizer.d.ts +45 -0
- package/dist/core/startup-optimizer.d.ts.map +1 -0
- package/dist/core/startup-optimizer.js +140 -0
- package/dist/core/startup-optimizer.js.map +1 -0
- package/dist/git/automation-engine.d.ts +58 -0
- package/dist/git/automation-engine.d.ts.map +1 -0
- package/dist/git/automation-engine.js +318 -0
- package/dist/git/automation-engine.js.map +1 -0
- package/dist/git/github-manager.d.ts +71 -0
- package/dist/git/github-manager.d.ts.map +1 -0
- package/dist/git/github-manager.js +226 -0
- package/dist/git/github-manager.js.map +1 -0
- package/dist/git/hook-manager.d.ts +43 -0
- package/dist/git/hook-manager.d.ts.map +1 -0
- package/dist/git/hook-manager.js +191 -0
- package/dist/git/hook-manager.js.map +1 -0
- package/dist/git/index.d.ts +4 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +5 -0
- package/dist/git/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/feature-validator.d.ts +60 -0
- package/dist/parsers/feature-validator.d.ts.map +1 -0
- package/dist/parsers/feature-validator.js +483 -0
- package/dist/parsers/feature-validator.js.map +1 -0
- package/dist/parsers/index.d.ts +8 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +9 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/parser-manager.d.ts +103 -0
- package/dist/parsers/parser-manager.d.ts.map +1 -0
- package/dist/parsers/parser-manager.js +321 -0
- package/dist/parsers/parser-manager.js.map +1 -0
- package/dist/parsers/parser.d.ts +23 -0
- package/dist/parsers/parser.d.ts.map +1 -0
- package/dist/parsers/parser.js +6 -0
- package/dist/parsers/parser.js.map +1 -0
- package/dist/parsers/react-parser.d.ts +22 -0
- package/dist/parsers/react-parser.d.ts.map +1 -0
- package/dist/parsers/react-parser.js +307 -0
- package/dist/parsers/react-parser.js.map +1 -0
- package/dist/parsers/svelte-parser.d.ts +33 -0
- package/dist/parsers/svelte-parser.d.ts.map +1 -0
- package/dist/parsers/svelte-parser.js +408 -0
- package/dist/parsers/svelte-parser.js.map +1 -0
- package/dist/parsers/vanilla-parser.d.ts +31 -0
- package/dist/parsers/vanilla-parser.d.ts.map +1 -0
- package/dist/parsers/vanilla-parser.js +590 -0
- package/dist/parsers/vanilla-parser.js.map +1 -0
- package/dist/parsers/vue-parser.d.ts +9 -0
- package/dist/parsers/vue-parser.d.ts.map +1 -0
- package/dist/parsers/vue-parser.js +16 -0
- package/dist/parsers/vue-parser.js.map +1 -0
- package/dist/terminal-header.d.ts +12 -0
- package/dist/terminal-header.js +45 -0
- package/dist/types/index.d.ts +83 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/components.d.ts +133 -0
- package/dist/ui/components.d.ts.map +1 -0
- package/dist/ui/components.js +482 -0
- package/dist/ui/components.js.map +1 -0
- package/dist/ui/help.d.ts +11 -0
- package/dist/ui/help.d.ts.map +1 -0
- package/dist/ui/help.js +161 -0
- package/dist/ui/help.js.map +1 -0
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +5 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/prompts.d.ts +63 -0
- package/dist/ui/prompts.d.ts.map +1 -0
- package/dist/ui/prompts.js +611 -0
- package/dist/ui/prompts.js.map +1 -0
- package/dist/ui/terminal-header.d.ts +13 -0
- package/dist/ui/terminal-header.d.ts.map +1 -0
- package/dist/ui/terminal-header.js +46 -0
- package/dist/ui/terminal-header.js.map +1 -0
- package/package.json +80 -0
- package/src/ai/__tests__/gemini-analyzer.test.ts +181 -0
- package/src/ai/fix-manager.ts +362 -0
- package/src/ai/gemini-analyzer.ts +671 -0
- package/src/ai/index.ts +4 -0
- package/src/ai/jules-implementer.ts +459 -0
- package/src/commands/automation.ts +344 -0
- package/src/commands/check.ts +299 -0
- package/src/commands/config.ts +365 -0
- package/src/commands/fix.ts +234 -0
- package/src/commands/index.ts +6 -0
- package/src/commands/init.ts +142 -0
- package/src/commands/status.ts +0 -0
- package/src/core/api-key-manager.ts +298 -0
- package/src/core/baseguard.ts +742 -0
- package/src/core/baseline-checker.ts +563 -0
- package/src/core/cache-manager.ts +270 -0
- package/src/core/configuration-recovery.ts +676 -0
- package/src/core/configuration.ts +559 -0
- package/src/core/debug-logger.ts +590 -0
- package/src/core/directory-filter.ts +421 -0
- package/src/core/error-handler.ts +517 -0
- package/src/core/file-processor.ts +331 -0
- package/src/core/gitignore-manager.ts +169 -0
- package/src/core/graceful-degradation-manager.ts +596 -0
- package/src/core/index.ts +13 -0
- package/src/core/lazy-loader.ts +307 -0
- package/src/core/logger.ts +0 -0
- package/src/core/memory-manager.ts +294 -0
- package/src/core/startup-optimizer.ts +173 -0
- package/src/core/system-error-handler.ts +746 -0
- package/src/git/automation-engine.ts +361 -0
- package/src/git/github-manager.ts +260 -0
- package/src/git/hook-manager.ts +210 -0
- package/src/git/index.ts +4 -0
- package/src/index.ts +8 -0
- package/src/parsers/feature-validator.ts +559 -0
- package/src/parsers/index.ts +8 -0
- package/src/parsers/parser-manager.ts +419 -0
- package/src/parsers/parser.ts +26 -0
- package/src/parsers/react-parser-optimized.ts +161 -0
- package/src/parsers/react-parser.ts +359 -0
- package/src/parsers/svelte-parser.ts +506 -0
- package/src/parsers/vanilla-parser.ts +682 -0
- package/src/parsers/vue-parser.ts +472 -0
- package/src/types/index.ts +92 -0
- package/src/ui/components.ts +567 -0
- package/src/ui/help.ts +193 -0
- package/src/ui/index.ts +4 -0
- package/src/ui/prompts.ts +688 -0
- package/src/ui/terminal-header.ts +59 -0
- package/test-config-commands.js +56 -0
- package/test-header-simple.js +33 -0
- package/test-terminal-header.js +12 -0
- package/test-ui.js +29 -0
- package/tests/e2e/baseguard.e2e.test.ts +516 -0
- package/tests/e2e/cross-platform.e2e.test.ts +420 -0
- package/tests/e2e/git-integration.e2e.test.ts +487 -0
- package/tests/fixtures/react-project/package.json +14 -0
- package/tests/fixtures/react-project/src/App.css +76 -0
- package/tests/fixtures/react-project/src/App.tsx +77 -0
- package/tests/fixtures/svelte-project/package.json +11 -0
- package/tests/fixtures/svelte-project/src/App.svelte +369 -0
- package/tests/fixtures/vanilla-project/index.html +76 -0
- package/tests/fixtures/vanilla-project/script.js +331 -0
- package/tests/fixtures/vanilla-project/styles.css +359 -0
- package/tests/fixtures/vue-project/package.json +12 -0
- package/tests/fixtures/vue-project/src/App.vue +216 -0
- package/tsconfig.json +36 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import type { Violation, Analysis, Fix, JulesSession, JulesActivity } from '../types/index.js';
|
|
2
|
+
import { GitHubManager } from '../git/github-manager.js';
|
|
3
|
+
import { FixManager } from './fix-manager.js';
|
|
4
|
+
import { ErrorHandler, APIError, ErrorType } from '../core/error-handler.js';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Jules AI implementer for autonomous code fixing
|
|
9
|
+
*/
|
|
10
|
+
export class JulesImplementer {
|
|
11
|
+
private apiKey: string;
|
|
12
|
+
private baseUrl = 'https://jules.googleapis.com/v1alpha';
|
|
13
|
+
private githubManager: GitHubManager;
|
|
14
|
+
private fixManager: FixManager;
|
|
15
|
+
|
|
16
|
+
constructor(apiKey: string) {
|
|
17
|
+
this.apiKey = apiKey;
|
|
18
|
+
this.githubManager = new GitHubManager();
|
|
19
|
+
this.fixManager = new FixManager();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate a fix using Jules AI
|
|
24
|
+
*/
|
|
25
|
+
async generateFix(violation: Violation, analysis: Analysis, repoSource?: string): Promise<Fix> {
|
|
26
|
+
const context = ErrorHandler.createContext('jules_fix_generation', {
|
|
27
|
+
feature: violation.feature,
|
|
28
|
+
file: violation.file,
|
|
29
|
+
browser: violation.browser
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
// Get repository source if not provided
|
|
34
|
+
const source = repoSource || await this.githubManager.getCurrentSourceIdentifier();
|
|
35
|
+
|
|
36
|
+
// Create a session for this specific fix with retry logic
|
|
37
|
+
const session = await ErrorHandler.withRetry(
|
|
38
|
+
() => this.createSession(violation, analysis, source),
|
|
39
|
+
{
|
|
40
|
+
maxRetries: 2,
|
|
41
|
+
retryableErrors: [ErrorType.NETWORK, ErrorType.TIMEOUT, ErrorType.RATE_LIMIT, ErrorType.SERVER_ERROR]
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
// Monitor session activities until completion
|
|
46
|
+
const activities = await this.waitForCompletion(session.id);
|
|
47
|
+
|
|
48
|
+
// Extract the generated code changes
|
|
49
|
+
const fix = await this.extractFix(session.id, activities, violation, analysis);
|
|
50
|
+
|
|
51
|
+
return fix;
|
|
52
|
+
} catch (error) {
|
|
53
|
+
const apiError = ErrorHandler.handleAPIError(error, context);
|
|
54
|
+
|
|
55
|
+
// Log error for debugging
|
|
56
|
+
console.error('Jules fix generation failed:', {
|
|
57
|
+
feature: violation.feature,
|
|
58
|
+
error: apiError.message,
|
|
59
|
+
type: apiError.type
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Re-throw with proper error handling
|
|
63
|
+
throw apiError;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Create a Jules session for fixing
|
|
69
|
+
*/
|
|
70
|
+
private async createSession(violation: Violation, analysis: Analysis, source: string): Promise<JulesSession> {
|
|
71
|
+
const prompt = this.buildFixPrompt(violation, analysis);
|
|
72
|
+
|
|
73
|
+
const response = await fetch(`${this.baseUrl}/sessions`, {
|
|
74
|
+
method: 'POST',
|
|
75
|
+
headers: {
|
|
76
|
+
'Content-Type': 'application/json',
|
|
77
|
+
'X-Goog-Api-Key': this.apiKey
|
|
78
|
+
},
|
|
79
|
+
body: JSON.stringify({
|
|
80
|
+
prompt: prompt,
|
|
81
|
+
sourceContext: {
|
|
82
|
+
source: source, // e.g., "sources/github/user/repo"
|
|
83
|
+
githubRepoContext: {
|
|
84
|
+
startingBranch: "main"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
title: `Fix ${violation.feature} compatibility in ${violation.file}`,
|
|
88
|
+
requirePlanApproval: false // Auto-approve for BaseGuard automation
|
|
89
|
+
})
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
const errorText = await response.text();
|
|
94
|
+
const error = new Error(`Jules API error: ${response.status} ${response.statusText} - ${errorText}`);
|
|
95
|
+
(error as any).response = response;
|
|
96
|
+
throw error;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const sessionData = await response.json();
|
|
100
|
+
|
|
101
|
+
// Validate session response
|
|
102
|
+
ErrorHandler.validateAPIResponse(sessionData, ['id']);
|
|
103
|
+
|
|
104
|
+
return sessionData;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Wait for Jules session completion
|
|
109
|
+
*/
|
|
110
|
+
private async waitForCompletion(sessionId: string): Promise<JulesActivity[]> {
|
|
111
|
+
let attempts = 0;
|
|
112
|
+
const maxAttempts = 30; // 5 minutes max (10 seconds * 30)
|
|
113
|
+
|
|
114
|
+
while (attempts < maxAttempts) {
|
|
115
|
+
const activities = await this.getActivities(sessionId);
|
|
116
|
+
const lastActivity = activities[activities.length - 1];
|
|
117
|
+
|
|
118
|
+
// Check if session is complete
|
|
119
|
+
if (lastActivity?.status === 'completed' || lastActivity?.type === 'agent_finished') {
|
|
120
|
+
return activities;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Check for failure states
|
|
124
|
+
if (lastActivity?.status === 'failed' || lastActivity?.status === 'error') {
|
|
125
|
+
throw new Error(`Jules session failed: ${lastActivity.status}`);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Wait 10 seconds before checking again
|
|
129
|
+
await new Promise(resolve => setTimeout(resolve, 10000));
|
|
130
|
+
attempts++;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
throw new Error('Jules session timed out after 5 minutes');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get activities for a Jules session
|
|
138
|
+
*/
|
|
139
|
+
private async getActivities(sessionId: string): Promise<JulesActivity[]> {
|
|
140
|
+
const response = await fetch(`${this.baseUrl}/sessions/${sessionId}/activities`, {
|
|
141
|
+
headers: {
|
|
142
|
+
'X-Goog-Api-Key': this.apiKey
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
if (!response.ok) {
|
|
147
|
+
const error = new Error(`Failed to get activities: ${response.status} ${response.statusText}`);
|
|
148
|
+
(error as any).response = response;
|
|
149
|
+
throw error;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const data = await response.json();
|
|
153
|
+
|
|
154
|
+
// Validate response structure
|
|
155
|
+
if (!data || typeof data !== 'object') {
|
|
156
|
+
throw new APIError(
|
|
157
|
+
'Invalid activities response from Jules API',
|
|
158
|
+
ErrorType.VALIDATION,
|
|
159
|
+
{
|
|
160
|
+
suggestions: [
|
|
161
|
+
'Check Jules API service status',
|
|
162
|
+
'Verify session ID is valid',
|
|
163
|
+
'Try the request again'
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return data.activities || [];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Extract fix from completed Jules session
|
|
174
|
+
*/
|
|
175
|
+
private async extractFix(sessionId: string, activities: JulesActivity[], violation: Violation, analysis: Analysis): Promise<Fix> {
|
|
176
|
+
// Get the final session state to extract code changes
|
|
177
|
+
const sessionResponse = await fetch(`${this.baseUrl}/sessions/${sessionId}`, {
|
|
178
|
+
headers: {
|
|
179
|
+
'X-Goog-Api-Key': this.apiKey
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
if (!sessionResponse.ok) {
|
|
184
|
+
throw new Error(`Failed to get session details: ${sessionResponse.status}`);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const sessionData = await sessionResponse.json();
|
|
188
|
+
|
|
189
|
+
// Extract code changes from activities or session data
|
|
190
|
+
const codeChanges = this.extractCodeChanges(activities, sessionData);
|
|
191
|
+
|
|
192
|
+
// Generate unified diff patch
|
|
193
|
+
const patch = this.generateUnifiedDiff(violation.file, codeChanges);
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
violation,
|
|
197
|
+
analysis,
|
|
198
|
+
patch,
|
|
199
|
+
explanation: this.generateFixExplanation(violation, analysis, codeChanges),
|
|
200
|
+
filePath: violation.file,
|
|
201
|
+
preview: this.generatePreview(codeChanges),
|
|
202
|
+
confidence: 0.8, // Jules confidence score
|
|
203
|
+
testable: true
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Extract code changes from Jules activities and session data
|
|
209
|
+
*/
|
|
210
|
+
private extractCodeChanges(activities: JulesActivity[], sessionData: any): { original: string; modified: string } {
|
|
211
|
+
// Look for code changes in activities
|
|
212
|
+
const codeActivity = activities.find(activity =>
|
|
213
|
+
activity.type === 'code_change' || activity.type === 'file_edit'
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
if (codeActivity) {
|
|
217
|
+
// Extract from activity data (implementation depends on Jules API response format)
|
|
218
|
+
return {
|
|
219
|
+
original: sessionData.originalCode || '',
|
|
220
|
+
modified: sessionData.modifiedCode || ''
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Fallback: extract from session data
|
|
225
|
+
return {
|
|
226
|
+
original: sessionData.originalCode || '',
|
|
227
|
+
modified: sessionData.modifiedCode || ''
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Generate unified diff patch
|
|
233
|
+
*/
|
|
234
|
+
private generateUnifiedDiff(filePath: string, changes: { original: string; modified: string }): string {
|
|
235
|
+
const originalLines = changes.original.split('\n');
|
|
236
|
+
const modifiedLines = changes.modified.split('\n');
|
|
237
|
+
|
|
238
|
+
// Simple diff generation (in production, use a proper diff library)
|
|
239
|
+
let patch = `--- a/${filePath}\n+++ b/${filePath}\n`;
|
|
240
|
+
|
|
241
|
+
// Find differences and generate patch format
|
|
242
|
+
for (let i = 0; i < Math.max(originalLines.length, modifiedLines.length); i++) {
|
|
243
|
+
const originalLine = originalLines[i] || '';
|
|
244
|
+
const modifiedLine = modifiedLines[i] || '';
|
|
245
|
+
|
|
246
|
+
if (originalLine !== modifiedLine) {
|
|
247
|
+
if (originalLine) {
|
|
248
|
+
patch += `-${originalLine}\n`;
|
|
249
|
+
}
|
|
250
|
+
if (modifiedLine) {
|
|
251
|
+
patch += `+${modifiedLine}\n`;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return patch;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Generate fix explanation
|
|
261
|
+
*/
|
|
262
|
+
private generateFixExplanation(violation: Violation, analysis: Analysis, changes: { original: string; modified: string }): string {
|
|
263
|
+
return `Fixed ${violation.feature} compatibility issue in ${violation.file}:\n\n` +
|
|
264
|
+
`- Added progressive enhancement using ${analysis.fixStrategy}\n` +
|
|
265
|
+
`- Implemented fallback for ${violation.browser} ${violation.required}\n` +
|
|
266
|
+
`- Applied best practices: ${analysis.bestPractices.join(', ')}\n\n` +
|
|
267
|
+
`This fix ensures the feature works across all target browsers while maintaining the original functionality.`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Generate human-readable preview
|
|
272
|
+
*/
|
|
273
|
+
private generatePreview(changes: { original: string; modified: string }): string {
|
|
274
|
+
const originalLines = changes.original.split('\n');
|
|
275
|
+
const modifiedLines = changes.modified.split('\n');
|
|
276
|
+
|
|
277
|
+
let preview = 'Changes:\n';
|
|
278
|
+
|
|
279
|
+
for (let i = 0; i < Math.max(originalLines.length, modifiedLines.length); i++) {
|
|
280
|
+
const originalLine = originalLines[i];
|
|
281
|
+
const modifiedLine = modifiedLines[i];
|
|
282
|
+
|
|
283
|
+
if (originalLine !== modifiedLine) {
|
|
284
|
+
if (originalLine) {
|
|
285
|
+
preview += `- ${originalLine}\n`;
|
|
286
|
+
}
|
|
287
|
+
if (modifiedLine) {
|
|
288
|
+
preview += `+ ${modifiedLine}\n`;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return preview;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Build fix prompt for Jules
|
|
298
|
+
*/
|
|
299
|
+
private buildFixPrompt(violation: Violation, analysis: Analysis): string {
|
|
300
|
+
return `Fix browser compatibility issue in ${violation.file}:
|
|
301
|
+
|
|
302
|
+
ISSUE:
|
|
303
|
+
- Feature: ${violation.feature} (line ${violation.line})
|
|
304
|
+
- Unsupported in: ${violation.browser} ${violation.required}
|
|
305
|
+
- Baseline Status: ${violation.baselineStatus}
|
|
306
|
+
- Current code: ${violation.context}
|
|
307
|
+
|
|
308
|
+
ANALYSIS:
|
|
309
|
+
${analysis.plainEnglish}
|
|
310
|
+
|
|
311
|
+
FIX STRATEGY:
|
|
312
|
+
${analysis.fixStrategy}
|
|
313
|
+
|
|
314
|
+
REQUIREMENTS:
|
|
315
|
+
1. Implement progressive enhancement using @supports for CSS features
|
|
316
|
+
2. Use feature detection for JavaScript APIs
|
|
317
|
+
3. Add appropriate fallbacks for older browsers
|
|
318
|
+
4. Preserve all original functionality
|
|
319
|
+
5. Follow best practices: ${analysis.bestPractices.join(', ')}
|
|
320
|
+
6. Ensure the fix works in ${violation.browser} ${violation.required} and newer versions
|
|
321
|
+
|
|
322
|
+
Please fix this compatibility issue while maintaining the existing functionality. The fix should be production-ready and follow web standards.`;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Test Jules API connectivity
|
|
327
|
+
*/
|
|
328
|
+
async testConnection(): Promise<{ success: boolean; error?: string; errorType?: ErrorType }> {
|
|
329
|
+
try {
|
|
330
|
+
const response = await fetch(`${this.baseUrl}/sessions`, {
|
|
331
|
+
method: 'GET',
|
|
332
|
+
headers: {
|
|
333
|
+
'X-Goog-Api-Key': this.apiKey
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
if (response.ok || response.status === 404) {
|
|
338
|
+
// 404 is acceptable for sessions endpoint when no sessions exist
|
|
339
|
+
return { success: true };
|
|
340
|
+
} else {
|
|
341
|
+
const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
342
|
+
(error as any).response = response;
|
|
343
|
+
throw error;
|
|
344
|
+
}
|
|
345
|
+
} catch (error) {
|
|
346
|
+
const apiError = ErrorHandler.handleAPIError(error);
|
|
347
|
+
|
|
348
|
+
return {
|
|
349
|
+
success: false,
|
|
350
|
+
error: apiError.message,
|
|
351
|
+
errorType: apiError.type
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Setup Jules GitHub integration
|
|
358
|
+
*/
|
|
359
|
+
async setupGitHubIntegration(): Promise<string> {
|
|
360
|
+
return await this.githubManager.setupJulesGitHubIntegration();
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Check if GitHub integration is set up
|
|
365
|
+
*/
|
|
366
|
+
async isGitHubIntegrationSetup(): Promise<boolean> {
|
|
367
|
+
return await this.githubManager.isJulesIntegrationSetup();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Verify GitHub connection and permissions
|
|
372
|
+
*/
|
|
373
|
+
async verifyGitHubConnection(): Promise<boolean> {
|
|
374
|
+
return await this.githubManager.verifyGitHubConnection();
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Get repository information
|
|
379
|
+
*/
|
|
380
|
+
getRepositoryInfo(): { owner: string | null; name: string | null } {
|
|
381
|
+
return this.githubManager.getRepositoryInfo();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Get current source identifier
|
|
386
|
+
*/
|
|
387
|
+
async getSourceIdentifier(): Promise<string> {
|
|
388
|
+
return await this.githubManager.getCurrentSourceIdentifier();
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Generate and apply fixes with interactive preview
|
|
393
|
+
*/
|
|
394
|
+
async generateAndApplyFixes(violations: Violation[], analyses: Analysis[]): Promise<{ applied: Fix[]; skipped: Fix[]; failed: { fix: Fix; error: string }[] }> {
|
|
395
|
+
const fixes: Fix[] = [];
|
|
396
|
+
|
|
397
|
+
// Generate fixes for each violation
|
|
398
|
+
for (let i = 0; i < violations.length; i++) {
|
|
399
|
+
const violation = violations[i];
|
|
400
|
+
const analysis = analyses[i];
|
|
401
|
+
|
|
402
|
+
if (!violation || !analysis) {
|
|
403
|
+
console.log(chalk.red(`❌ Missing violation or analysis data for index ${i}`));
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
try {
|
|
408
|
+
console.log(chalk.cyan(`\n🔧 Generating fix ${i + 1}/${violations.length} for ${violation.feature}...`));
|
|
409
|
+
const fix = await this.generateFix(violation, analysis);
|
|
410
|
+
fixes.push(fix);
|
|
411
|
+
} catch (error) {
|
|
412
|
+
console.log(chalk.red(`❌ Failed to generate fix for ${violation.feature}: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
if (fixes.length === 0) {
|
|
417
|
+
console.log(chalk.yellow('⚠️ No fixes were generated'));
|
|
418
|
+
return { applied: [], skipped: [], failed: [] };
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Apply fixes with interactive preview
|
|
422
|
+
return await this.fixManager.applyFixes(fixes);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Preview a single fix
|
|
427
|
+
*/
|
|
428
|
+
async previewFix(fix: Fix): Promise<string> {
|
|
429
|
+
return await this.fixManager.generatePreview(fix);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Apply a single fix
|
|
434
|
+
*/
|
|
435
|
+
async applySingleFix(fix: Fix): Promise<void> {
|
|
436
|
+
await this.fixManager.applyFix(fix);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Rollback applied fixes
|
|
441
|
+
*/
|
|
442
|
+
async rollbackFix(filePath: string): Promise<void> {
|
|
443
|
+
await this.fixManager.rollbackFix(filePath);
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Rollback all applied fixes
|
|
448
|
+
*/
|
|
449
|
+
async rollbackAllFixes(): Promise<void> {
|
|
450
|
+
await this.fixManager.rollbackAllFixes();
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* Get list of applied fixes
|
|
455
|
+
*/
|
|
456
|
+
getAppliedFixes(): string[] {
|
|
457
|
+
return this.fixManager.getAppliedFixes();
|
|
458
|
+
}
|
|
459
|
+
}
|