baseguard 1.0.0 ā 1.0.2
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/.baseguardrc.example.json +64 -0
- package/.eslintrc.json +1 -1
- package/CHANGELOG.md +196 -0
- package/DEPLOYMENT.md +625 -0
- package/DEPLOYMENT_CHECKLIST.md +239 -0
- package/DEPLOYMENT_SUMMARY_v1.0.2.md +202 -0
- package/QUICK_START.md +134 -0
- package/README.md +447 -52
- package/RELEASE_NOTES_v1.0.2.md +434 -0
- package/bin/base.js +155 -36
- package/dist/ai/agentkit-orchestrator.d.ts +116 -0
- package/dist/ai/agentkit-orchestrator.d.ts.map +1 -0
- package/dist/ai/agentkit-orchestrator.js +417 -0
- package/dist/ai/agentkit-orchestrator.js.map +1 -0
- package/dist/ai/gemini-code-fixer.d.ts +85 -0
- package/dist/ai/gemini-code-fixer.d.ts.map +1 -0
- package/dist/ai/gemini-code-fixer.js +452 -0
- package/dist/ai/gemini-code-fixer.js.map +1 -0
- package/dist/ai/jules-implementer.d.ts +5 -4
- package/dist/ai/jules-implementer.d.ts.map +1 -1
- package/dist/ai/jules-implementer.js +6 -5
- package/dist/ai/jules-implementer.js.map +1 -1
- package/dist/ai/unified-code-fixer.d.ts +69 -0
- package/dist/ai/unified-code-fixer.d.ts.map +1 -0
- package/dist/ai/unified-code-fixer.js +289 -0
- package/dist/ai/unified-code-fixer.js.map +1 -0
- package/dist/commands/check.d.ts +3 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +166 -34
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +183 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/fix.d.ts.map +1 -1
- package/dist/commands/fix.js +89 -91
- package/dist/commands/fix.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +16 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/status.d.ts +14 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +254 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/core/baseguard.d.ts +47 -5
- package/dist/core/baseguard.d.ts.map +1 -1
- package/dist/core/baseguard.js +506 -52
- package/dist/core/baseguard.js.map +1 -1
- package/dist/core/cache-manager.d.ts.map +1 -1
- package/dist/core/cache-manager.js +3 -1
- package/dist/core/cache-manager.js.map +1 -1
- package/dist/core/configuration-recovery.d.ts +116 -0
- package/dist/core/configuration-recovery.d.ts.map +1 -0
- package/dist/core/configuration-recovery.js +552 -0
- package/dist/core/configuration-recovery.js.map +1 -0
- package/dist/core/configuration.d.ts +4 -0
- package/dist/core/configuration.d.ts.map +1 -1
- package/dist/core/configuration.js +35 -0
- package/dist/core/configuration.js.map +1 -1
- package/dist/core/debug-logger.d.ts +181 -0
- package/dist/core/debug-logger.d.ts.map +1 -0
- package/dist/core/debug-logger.js +479 -0
- package/dist/core/debug-logger.js.map +1 -0
- package/dist/core/file-processor.d.ts.map +1 -1
- package/dist/core/file-processor.js +8 -2
- package/dist/core/file-processor.js.map +1 -1
- package/dist/core/graceful-degradation-manager.d.ts +123 -0
- package/dist/core/graceful-degradation-manager.d.ts.map +1 -0
- package/dist/core/graceful-degradation-manager.js +512 -0
- package/dist/core/graceful-degradation-manager.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/logger.d.ts +1 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +2 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/memory-manager.d.ts +84 -0
- package/dist/core/memory-manager.d.ts.map +1 -1
- package/dist/core/memory-manager.js +236 -1
- package/dist/core/memory-manager.js.map +1 -1
- package/dist/core/startup-optimizer.d.ts +12 -0
- package/dist/core/startup-optimizer.d.ts.map +1 -1
- package/dist/core/startup-optimizer.js +60 -0
- package/dist/core/startup-optimizer.js.map +1 -1
- package/dist/core/system-error-handler.d.ts +65 -0
- package/dist/core/system-error-handler.d.ts.map +1 -0
- package/dist/core/system-error-handler.js +646 -0
- package/dist/core/system-error-handler.js.map +1 -0
- package/dist/git/github-manager.d.ts +5 -16
- package/dist/git/github-manager.d.ts.map +1 -1
- package/dist/git/github-manager.js +6 -61
- package/dist/git/github-manager.js.map +1 -1
- package/dist/parsers/react-parser-optimized.d.ts +16 -0
- package/dist/parsers/react-parser-optimized.d.ts.map +1 -0
- package/dist/parsers/react-parser-optimized.js +147 -0
- package/dist/parsers/react-parser-optimized.js.map +1 -0
- package/dist/parsers/react-parser.d.ts.map +1 -1
- package/dist/parsers/react-parser.js +17 -15
- package/dist/parsers/react-parser.js.map +1 -1
- package/dist/parsers/svelte-parser.d.ts.map +1 -1
- package/dist/parsers/svelte-parser.js +7 -3
- package/dist/parsers/svelte-parser.js.map +1 -1
- package/dist/parsers/vanilla-parser.d.ts.map +1 -1
- package/dist/parsers/vanilla-parser.js +7 -3
- package/dist/parsers/vanilla-parser.js.map +1 -1
- package/dist/parsers/vue-parser.d.ts +18 -0
- package/dist/parsers/vue-parser.d.ts.map +1 -1
- package/dist/parsers/vue-parser.js +387 -1
- package/dist/parsers/vue-parser.js.map +1 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/ui/help.js +1 -1
- package/dist/ui/help.js.map +1 -1
- package/dist/ui/prompts.d.ts +7 -4
- package/dist/ui/prompts.d.ts.map +1 -1
- package/dist/ui/prompts.js +48 -55
- package/dist/ui/prompts.js.map +1 -1
- package/package.json +30 -5
- package/src/ai/__tests__/gemini-analyzer.test.ts +2 -2
- package/src/ai/agentkit-orchestrator.ts +534 -0
- package/src/ai/gemini-code-fixer.ts +540 -0
- package/src/ai/jules-implementer.ts +6 -5
- package/src/ai/unified-code-fixer.ts +347 -0
- package/src/commands/config.ts +218 -0
- package/src/commands/fix.ts +98 -94
- package/src/commands/index.ts +2 -1
- package/src/commands/init.ts +16 -2
- package/src/commands/status.ts +307 -0
- package/src/core/baseguard.ts +36 -22
- package/src/core/cache-manager.ts +4 -2
- package/src/core/configuration-recovery.ts +3 -6
- package/src/core/configuration.ts +37 -0
- package/src/core/debug-logger.ts +2 -2
- package/src/core/file-processor.ts +10 -3
- package/src/core/index.ts +5 -1
- package/src/core/memory-manager.ts +4 -3
- package/src/core/startup-optimizer.ts +70 -0
- package/src/core/system-error-handler.ts +9 -5
- package/src/git/github-manager.ts +11 -79
- package/src/parsers/react-parser.ts +2 -2
- package/src/parsers/svelte-parser.ts +13 -9
- package/src/parsers/vanilla-parser.ts +18 -14
- package/src/parsers/vue-parser.ts +20 -14
- package/src/types/index.ts +4 -0
- package/src/ui/help.ts +1 -1
- package/src/ui/prompts.ts +54 -61
- package/test-build.js +41 -0
- package/tests/e2e/git-integration.e2e.test.ts +1 -1
- package/tsconfig.json +0 -1
- package/vitest.config.ts +4 -2
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import type { Violation, Analysis, Fix, Configuration } from '../types/index.js';
|
|
2
|
+
import { JulesImplementer } from './jules-implementer.js';
|
|
3
|
+
import { GeminiCodeFixer } from './gemini-code-fixer.js';
|
|
4
|
+
import { ErrorHandler, APIError, ErrorType } from '../core/error-handler.js';
|
|
5
|
+
import { logger } from '../core/debug-logger.js';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Unified code fixer that can use either Jules or Gemini based on configuration
|
|
10
|
+
*/
|
|
11
|
+
export class UnifiedCodeFixer {
|
|
12
|
+
private config: Configuration;
|
|
13
|
+
private julesImplementer?: JulesImplementer;
|
|
14
|
+
private geminiCodeFixer?: GeminiCodeFixer;
|
|
15
|
+
private categoryLogger: ReturnType<typeof logger.createCategoryLogger>;
|
|
16
|
+
|
|
17
|
+
constructor(config: Configuration) {
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.categoryLogger = logger.createCategoryLogger('unified-code-fixer');
|
|
20
|
+
|
|
21
|
+
// Initialize available agents based on API keys
|
|
22
|
+
this.initializeAgents();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Initialize coding agents based on available API keys
|
|
27
|
+
*/
|
|
28
|
+
private initializeAgents(): void {
|
|
29
|
+
if (this.config.apiKeys.jules) {
|
|
30
|
+
this.julesImplementer = new JulesImplementer(this.config.apiKeys.jules);
|
|
31
|
+
this.categoryLogger.debug('Jules implementer initialized');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (this.config.apiKeys.gemini) {
|
|
35
|
+
this.geminiCodeFixer = new GeminiCodeFixer(this.config.apiKeys.gemini);
|
|
36
|
+
this.categoryLogger.debug('Gemini code fixer initialized');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Generate a fix using the configured primary agent with fallback
|
|
42
|
+
*/
|
|
43
|
+
async generateFix(violation: Violation, analysis: Analysis): Promise<Fix> {
|
|
44
|
+
const primaryAgent = this.config.codingAgent.primary;
|
|
45
|
+
const fallbackAgent = this.config.codingAgent.fallback;
|
|
46
|
+
|
|
47
|
+
this.categoryLogger.info('Generating fix', {
|
|
48
|
+
feature: violation.feature,
|
|
49
|
+
primaryAgent,
|
|
50
|
+
fallbackAgent
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// Try primary agent first
|
|
55
|
+
const fix = await this.generateFixWithAgent(violation, analysis, primaryAgent);
|
|
56
|
+
|
|
57
|
+
this.categoryLogger.info('Fix generated successfully with primary agent', {
|
|
58
|
+
agent: primaryAgent,
|
|
59
|
+
confidence: fix.confidence
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
return fix;
|
|
63
|
+
|
|
64
|
+
} catch (primaryError) {
|
|
65
|
+
this.categoryLogger.warn('Primary agent failed, trying fallback', {
|
|
66
|
+
primaryAgent,
|
|
67
|
+
fallbackAgent,
|
|
68
|
+
error: primaryError instanceof Error ? primaryError.message : 'Unknown error'
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Try fallback agent if different from primary
|
|
72
|
+
if (fallbackAgent !== primaryAgent) {
|
|
73
|
+
try {
|
|
74
|
+
const fix = await this.generateFixWithAgent(violation, analysis, fallbackAgent);
|
|
75
|
+
|
|
76
|
+
this.categoryLogger.info('Fix generated successfully with fallback agent', {
|
|
77
|
+
agent: fallbackAgent,
|
|
78
|
+
confidence: fix.confidence
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Add note about fallback usage
|
|
82
|
+
fix.explanation = `[Generated using ${fallbackAgent} as fallback]\n\n${fix.explanation}`;
|
|
83
|
+
|
|
84
|
+
return fix;
|
|
85
|
+
|
|
86
|
+
} catch (fallbackError) {
|
|
87
|
+
this.categoryLogger.error('Both agents failed', {
|
|
88
|
+
primaryError: primaryError instanceof Error ? primaryError.message : 'Unknown error',
|
|
89
|
+
fallbackError: fallbackError instanceof Error ? fallbackError.message : 'Unknown error'
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
throw new Error(`Both coding agents failed. Primary (${primaryAgent}): ${primaryError instanceof Error ? primaryError.message : 'Unknown error'}. Fallback (${fallbackAgent}): ${fallbackError instanceof Error ? fallbackError.message : 'Unknown error'}`);
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
throw primaryError;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Generate fix with specific agent
|
|
102
|
+
*/
|
|
103
|
+
private async generateFixWithAgent(
|
|
104
|
+
violation: Violation,
|
|
105
|
+
analysis: Analysis,
|
|
106
|
+
agent: 'jules' | 'gemini'
|
|
107
|
+
): Promise<Fix> {
|
|
108
|
+
switch (agent) {
|
|
109
|
+
case 'jules':
|
|
110
|
+
return await this.generateFixWithJules(violation, analysis);
|
|
111
|
+
|
|
112
|
+
case 'gemini':
|
|
113
|
+
return await this.generateFixWithGemini(violation, analysis);
|
|
114
|
+
|
|
115
|
+
default:
|
|
116
|
+
throw new Error(`Unknown coding agent: ${agent}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Generate fix using Jules
|
|
122
|
+
*/
|
|
123
|
+
private async generateFixWithJules(violation: Violation, analysis: Analysis): Promise<Fix> {
|
|
124
|
+
if (!this.julesImplementer) {
|
|
125
|
+
throw new APIError(
|
|
126
|
+
'Jules API key not configured',
|
|
127
|
+
ErrorType.AUTHENTICATION,
|
|
128
|
+
{
|
|
129
|
+
suggestions: [
|
|
130
|
+
'Run "base config set-keys" to configure Jules API key',
|
|
131
|
+
'Get Jules API key from https://jules.google.com/settings#api',
|
|
132
|
+
'Switch to Gemini agent with "base config coding-agent gemini"'
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Check if repository is detected for Jules
|
|
139
|
+
const isRepoDetected = await this.julesImplementer.isRepositoryDetected();
|
|
140
|
+
if (!isRepoDetected) {
|
|
141
|
+
throw new APIError(
|
|
142
|
+
'Jules requires a GitHub repository',
|
|
143
|
+
ErrorType.CONFIGURATION,
|
|
144
|
+
{
|
|
145
|
+
suggestions: [
|
|
146
|
+
'Ensure you are in a git repository with GitHub remote',
|
|
147
|
+
'Jules only works with GitHub repositories',
|
|
148
|
+
'Switch to Gemini agent for local files: "base config coding-agent gemini"'
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return await this.julesImplementer.generateFix(violation, analysis);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Generate fix using Gemini
|
|
159
|
+
*/
|
|
160
|
+
private async generateFixWithGemini(violation: Violation, analysis: Analysis): Promise<Fix> {
|
|
161
|
+
if (!this.geminiCodeFixer) {
|
|
162
|
+
throw new APIError(
|
|
163
|
+
'Gemini API key not configured',
|
|
164
|
+
ErrorType.AUTHENTICATION,
|
|
165
|
+
{
|
|
166
|
+
suggestions: [
|
|
167
|
+
'Run "base config set-keys" to configure Gemini API key',
|
|
168
|
+
'Get Gemini API key from https://aistudio.google.com',
|
|
169
|
+
'Switch to Jules agent with "base config coding-agent jules"'
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return await this.geminiCodeFixer.generateFix(violation, analysis);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Generate multiple fix options using available agents
|
|
180
|
+
*/
|
|
181
|
+
async generateFixOptions(violation: Violation, analysis: Analysis): Promise<Fix[]> {
|
|
182
|
+
const fixes: Fix[] = [];
|
|
183
|
+
|
|
184
|
+
try {
|
|
185
|
+
// Try primary agent
|
|
186
|
+
const primaryFix = await this.generateFix(violation, analysis);
|
|
187
|
+
fixes.push(primaryFix);
|
|
188
|
+
|
|
189
|
+
// If primary agent has low confidence, try the other agent for alternatives
|
|
190
|
+
if (primaryFix.confidence < 0.7) {
|
|
191
|
+
const alternativeAgent = this.config.codingAgent.primary === 'jules' ? 'gemini' : 'jules';
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
const alternativeFix = await this.generateFixWithAgent(violation, analysis, alternativeAgent);
|
|
195
|
+
alternativeFix.explanation = `[Alternative approach using ${alternativeAgent}]\n\n${alternativeFix.explanation}`;
|
|
196
|
+
fixes.push(alternativeFix);
|
|
197
|
+
|
|
198
|
+
this.categoryLogger.info('Generated alternative fix', {
|
|
199
|
+
primaryAgent: this.config.codingAgent.primary,
|
|
200
|
+
alternativeAgent,
|
|
201
|
+
primaryConfidence: primaryFix.confidence,
|
|
202
|
+
alternativeConfidence: alternativeFix.confidence
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
} catch (error) {
|
|
206
|
+
this.categoryLogger.debug('Alternative agent failed', {
|
|
207
|
+
agent: alternativeAgent,
|
|
208
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
} catch (error) {
|
|
214
|
+
this.categoryLogger.error('Failed to generate fix options', { error });
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
return fixes;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Get agent capabilities and status
|
|
223
|
+
*/
|
|
224
|
+
async getAgentStatus(): Promise<{
|
|
225
|
+
jules: { available: boolean; configured: boolean; repoDetected?: boolean; error?: string };
|
|
226
|
+
gemini: { available: boolean; configured: boolean; error?: string };
|
|
227
|
+
primary: string;
|
|
228
|
+
fallback: string;
|
|
229
|
+
}> {
|
|
230
|
+
const status = {
|
|
231
|
+
jules: { available: false, configured: !!this.config.apiKeys.jules, error: undefined as string | undefined, repoDetected: undefined as boolean | undefined },
|
|
232
|
+
gemini: { available: false, configured: !!this.config.apiKeys.gemini, error: undefined as string | undefined },
|
|
233
|
+
primary: this.config.codingAgent.primary,
|
|
234
|
+
fallback: this.config.codingAgent.fallback
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// Test Jules availability
|
|
238
|
+
if (this.julesImplementer) {
|
|
239
|
+
try {
|
|
240
|
+
const connectionTest = await this.julesImplementer.testConnection();
|
|
241
|
+
status.jules.available = connectionTest.success;
|
|
242
|
+
if (!connectionTest.success) {
|
|
243
|
+
status.jules.error = connectionTest.error;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Check repository detection
|
|
247
|
+
status.jules.repoDetected = await this.julesImplementer.isRepositoryDetected();
|
|
248
|
+
|
|
249
|
+
} catch (error) {
|
|
250
|
+
status.jules.error = error instanceof Error ? error.message : 'Unknown error';
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// Test Gemini availability
|
|
255
|
+
if (this.geminiCodeFixer) {
|
|
256
|
+
try {
|
|
257
|
+
const connectionTest = await this.geminiCodeFixer.testConnection();
|
|
258
|
+
status.gemini.available = connectionTest.success;
|
|
259
|
+
if (!connectionTest.success) {
|
|
260
|
+
status.gemini.error = connectionTest.error;
|
|
261
|
+
}
|
|
262
|
+
} catch (error) {
|
|
263
|
+
status.gemini.error = error instanceof Error ? error.message : 'Unknown error';
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return status;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Show agent comparison and recommendations
|
|
272
|
+
*/
|
|
273
|
+
showAgentComparison(): void {
|
|
274
|
+
console.log(chalk.cyan('\nš¤ Coding Agent Comparison\n'));
|
|
275
|
+
|
|
276
|
+
console.log(chalk.white('Jules (Google\'s Autonomous Coding Agent):'));
|
|
277
|
+
console.log(chalk.green(' ā
Autonomous operation in cloud VMs'));
|
|
278
|
+
console.log(chalk.green(' ā
Full repository context understanding'));
|
|
279
|
+
console.log(chalk.green(' ā
Asynchronous processing'));
|
|
280
|
+
console.log(chalk.green(' ā
Integrated with GitHub workflows'));
|
|
281
|
+
console.log(chalk.red(' ā Requires GitHub repository'));
|
|
282
|
+
console.log(chalk.red(' ā Cannot work with local/uncommitted files'));
|
|
283
|
+
console.log(chalk.red(' ā Slower (asynchronous processing)'));
|
|
284
|
+
|
|
285
|
+
console.log(chalk.white('\nGemini 2.5 Pro (Direct API Integration):'));
|
|
286
|
+
console.log(chalk.green(' ā
Works with any files (GitHub or not)'));
|
|
287
|
+
console.log(chalk.green(' ā
Immediate processing'));
|
|
288
|
+
console.log(chalk.green(' ā
Works with uncommitted/local files'));
|
|
289
|
+
console.log(chalk.green(' ā
Grounded with real-time web search'));
|
|
290
|
+
console.log(chalk.yellow(' ā ļø Requires manual code application'));
|
|
291
|
+
console.log(chalk.yellow(' ā ļø Limited to single-file context'));
|
|
292
|
+
|
|
293
|
+
console.log(chalk.cyan('\nš” Recommendations:'));
|
|
294
|
+
console.log(chalk.cyan(' ⢠Use Jules for: GitHub repositories, complex multi-file changes'));
|
|
295
|
+
console.log(chalk.cyan(' ⢠Use Gemini for: Local development, quick fixes, non-GitHub projects'));
|
|
296
|
+
console.log(chalk.cyan(' ⢠Configure both for maximum flexibility'));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Switch primary coding agent
|
|
301
|
+
*/
|
|
302
|
+
async switchPrimaryAgent(agent: 'jules' | 'gemini'): Promise<void> {
|
|
303
|
+
this.config.codingAgent.primary = agent;
|
|
304
|
+
this.categoryLogger.info('Switched primary coding agent', { agent });
|
|
305
|
+
|
|
306
|
+
console.log(chalk.green(`ā
Primary coding agent switched to ${agent}`));
|
|
307
|
+
|
|
308
|
+
// Show agent-specific setup instructions
|
|
309
|
+
if (agent === 'jules' && !this.config.apiKeys.jules) {
|
|
310
|
+
console.log(chalk.yellow('\nā ļø Jules API key not configured'));
|
|
311
|
+
console.log(chalk.cyan('Run "base config set-keys" to configure Jules API key'));
|
|
312
|
+
} else if (agent === 'gemini' && !this.config.apiKeys.gemini) {
|
|
313
|
+
console.log(chalk.yellow('\nā ļø Gemini API key not configured'));
|
|
314
|
+
console.log(chalk.cyan('Run "base config set-keys" to configure Gemini API key'));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Get recommended agent based on current context
|
|
320
|
+
*/
|
|
321
|
+
async getRecommendedAgent(): Promise<{ agent: 'jules' | 'gemini'; reason: string }> {
|
|
322
|
+
// Check if we're in a GitHub repository
|
|
323
|
+
const isGitHubRepo = this.julesImplementer ? await this.julesImplementer.isRepositoryDetected() : false;
|
|
324
|
+
|
|
325
|
+
if (isGitHubRepo && this.config.apiKeys.jules) {
|
|
326
|
+
return {
|
|
327
|
+
agent: 'jules',
|
|
328
|
+
reason: 'GitHub repository detected and Jules is configured'
|
|
329
|
+
};
|
|
330
|
+
} else if (this.config.apiKeys.gemini) {
|
|
331
|
+
return {
|
|
332
|
+
agent: 'gemini',
|
|
333
|
+
reason: isGitHubRepo ? 'Gemini works with any files including local changes' : 'Not in a GitHub repository, Gemini works with local files'
|
|
334
|
+
};
|
|
335
|
+
} else if (this.config.apiKeys.jules) {
|
|
336
|
+
return {
|
|
337
|
+
agent: 'jules',
|
|
338
|
+
reason: 'Only Jules is configured'
|
|
339
|
+
};
|
|
340
|
+
} else {
|
|
341
|
+
return {
|
|
342
|
+
agent: 'gemini',
|
|
343
|
+
reason: 'Default recommendation for local development'
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
package/src/commands/config.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { UIComponents, Prompts } from '../ui/index.js';
|
|
2
2
|
import { ConfigurationManager, ApiKeyManager, GitignoreManager } from '../core/index.js';
|
|
3
|
+
import { ConfigurationRecovery } from '../core/configuration-recovery.js';
|
|
3
4
|
import { ErrorHandler } from '../core/error-handler.js';
|
|
5
|
+
import chalk from 'chalk';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* Manage BaseGuard configuration
|
|
@@ -11,6 +13,10 @@ export async function config(action: string, options?: {
|
|
|
11
13
|
preset?: string;
|
|
12
14
|
file?: string;
|
|
13
15
|
format?: string;
|
|
16
|
+
backup?: boolean;
|
|
17
|
+
interactive?: boolean;
|
|
18
|
+
agent?: string;
|
|
19
|
+
show?: boolean;
|
|
14
20
|
}): Promise<void> {
|
|
15
21
|
try {
|
|
16
22
|
switch (action) {
|
|
@@ -44,6 +50,12 @@ export async function config(action: string, options?: {
|
|
|
44
50
|
case 'restore':
|
|
45
51
|
await restoreConfiguration(options?.file);
|
|
46
52
|
break;
|
|
53
|
+
case 'recover':
|
|
54
|
+
await recoverConfiguration(options);
|
|
55
|
+
break;
|
|
56
|
+
case 'coding-agent':
|
|
57
|
+
await manageCodingAgent(options);
|
|
58
|
+
break;
|
|
47
59
|
default:
|
|
48
60
|
UIComponents.showErrorBox(`Unknown config action: ${action}`);
|
|
49
61
|
showConfigHelp();
|
|
@@ -339,6 +351,89 @@ async function restoreConfiguration(backupFile?: string): Promise<void> {
|
|
|
339
351
|
}
|
|
340
352
|
}
|
|
341
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
|
+
|
|
342
437
|
function showConfigHelp(): void {
|
|
343
438
|
UIComponents.showSectionHeader('Configuration Commands');
|
|
344
439
|
UIComponents.showList([
|
|
@@ -356,10 +451,133 @@ function showConfigHelp(): void {
|
|
|
356
451
|
'base config security - Check configuration security',
|
|
357
452
|
'base config backup - Create configuration backup',
|
|
358
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',
|
|
359
459
|
'',
|
|
360
460
|
'Shorthand commands:',
|
|
361
461
|
'base add "chrome 100" - Add browser target',
|
|
362
462
|
'base remove chrome - Remove browser target',
|
|
363
463
|
'base list - List configuration summary'
|
|
364
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
|
+
}
|
|
365
583
|
}
|