baseguard 1.0.3 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (167) 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 +44 -15
  33. package/dist/commands/fix.js.map +1 -1
  34. package/dist/core/api-key-manager.js +2 -2
  35. package/dist/core/api-key-manager.js.map +1 -1
  36. package/dist/core/baseguard.d.ts +1 -0
  37. package/dist/core/baseguard.d.ts.map +1 -1
  38. package/dist/core/baseguard.js +13 -10
  39. package/dist/core/baseguard.js.map +1 -1
  40. package/dist/core/baseline-checker.d.ts.map +1 -1
  41. package/dist/core/baseline-checker.js +2 -1
  42. package/dist/core/baseline-checker.js.map +1 -1
  43. package/dist/core/configuration-recovery.d.ts.map +1 -1
  44. package/dist/core/configuration-recovery.js +1 -1
  45. package/dist/core/configuration-recovery.js.map +1 -1
  46. package/dist/core/debug-logger.d.ts.map +1 -1
  47. package/dist/core/debug-logger.js +1 -1
  48. package/dist/core/debug-logger.js.map +1 -1
  49. package/dist/core/error-handler.d.ts.map +1 -1
  50. package/dist/core/error-handler.js +2 -1
  51. package/dist/core/error-handler.js.map +1 -1
  52. package/dist/core/gitignore-manager.js +5 -5
  53. package/dist/core/graceful-degradation-manager.d.ts.map +1 -1
  54. package/dist/core/graceful-degradation-manager.js +16 -16
  55. package/dist/core/graceful-degradation-manager.js.map +1 -1
  56. package/dist/core/lazy-loader.d.ts.map +1 -1
  57. package/dist/core/lazy-loader.js +9 -2
  58. package/dist/core/lazy-loader.js.map +1 -1
  59. package/dist/core/memory-manager.d.ts +0 -3
  60. package/dist/core/memory-manager.d.ts.map +1 -1
  61. package/dist/core/memory-manager.js.map +1 -1
  62. package/dist/core/parser-worker.d.ts +2 -0
  63. package/dist/core/parser-worker.d.ts.map +1 -0
  64. package/dist/core/parser-worker.js +19 -0
  65. package/dist/core/parser-worker.js.map +1 -0
  66. package/dist/core/startup-optimizer.d.ts.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 +264 -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 +564 -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/tsconfig.json +34 -34
  165. package/vitest.config.ts +11 -11
  166. package/dist/terminal-header.d.ts +0 -12
  167. package/dist/terminal-header.js +0 -45
@@ -1,534 +1,534 @@
1
- /**
2
- * AgentKit-inspired orchestrator for managing multiple coding agents
3
- * Based on OpenAI's AgentKit principles for production-ready agent workflows
4
- */
5
-
6
- import type { Violation, Analysis, Fix } from '../types/index.js';
7
- import { GeminiCodeFixer } from './gemini-code-fixer.js';
8
- import { JulesImplementer } from './jules-implementer.js';
9
- import { logger } from '../core/debug-logger.js';
10
- import chalk from 'chalk';
11
-
12
- export interface AgentCapabilities {
13
- codeGeneration: boolean;
14
- fileAnalysis: boolean;
15
- webSearch: boolean;
16
- repositoryAccess: boolean;
17
- realTimeProcessing: boolean;
18
- autonomousExecution: boolean;
19
- }
20
-
21
- export interface AgentMetrics {
22
- successRate: number;
23
- averageResponseTime: number;
24
- totalExecutions: number;
25
- lastUsed: Date;
26
- reliability: number;
27
- }
28
-
29
- export interface AgentStatus {
30
- available: boolean;
31
- capabilities: AgentCapabilities;
32
- metrics: AgentMetrics;
33
- lastError?: string;
34
- configurationValid: boolean;
35
- }
36
-
37
- /**
38
- * AgentKit-inspired orchestrator for intelligent agent selection and workflow optimization
39
- */
40
- export class AgentKitOrchestrator {
41
- private geminiAgent: GeminiCodeFixer | null = null;
42
- private julesAgent: JulesImplementer | null = null;
43
- private agentMetrics: Map<string, AgentMetrics>;
44
- private categoryLogger: ReturnType<typeof logger.createCategoryLogger>;
45
- private geminiApiKey: string | null;
46
- private julesApiKey: string | null;
47
-
48
- constructor(geminiApiKey: string | null, julesApiKey: string | null) {
49
- this.geminiApiKey = geminiApiKey;
50
- this.julesApiKey = julesApiKey;
51
- this.agentMetrics = new Map();
52
- this.categoryLogger = logger.createCategoryLogger('agentkit-orchestrator');
53
-
54
- // Initialize agents if API keys are available
55
- if (geminiApiKey) {
56
- this.geminiAgent = new GeminiCodeFixer(geminiApiKey);
57
- }
58
- if (julesApiKey) {
59
- this.julesAgent = new JulesImplementer(julesApiKey);
60
- }
61
-
62
- // Initialize metrics
63
- this.initializeMetrics();
64
- }
65
-
66
- /**
67
- * Initialize agent metrics tracking
68
- */
69
- private initializeMetrics(): void {
70
- this.agentMetrics.set('gemini', {
71
- successRate: 0.95,
72
- averageResponseTime: 2500, // ms
73
- totalExecutions: 0,
74
- lastUsed: new Date(),
75
- reliability: 0.95
76
- });
77
-
78
- this.agentMetrics.set('jules', {
79
- successRate: 0.88,
80
- averageResponseTime: 15000, // ms (async processing)
81
- totalExecutions: 0,
82
- lastUsed: new Date(),
83
- reliability: 0.88
84
- });
85
- }
86
-
87
- /**
88
- * Get comprehensive status of all agents
89
- */
90
- async getAgentStatus(): Promise<Record<string, AgentStatus>> {
91
- const status: Record<string, AgentStatus> = {};
92
-
93
- // Check Gemini status
94
- if (this.geminiAgent) {
95
- try {
96
- const testResult = await this.geminiAgent.testConnection();
97
- status.gemini = {
98
- available: testResult.success,
99
- capabilities: {
100
- codeGeneration: true,
101
- fileAnalysis: true,
102
- webSearch: true,
103
- repositoryAccess: false,
104
- realTimeProcessing: true,
105
- autonomousExecution: false
106
- },
107
- metrics: this.agentMetrics.get('gemini')!,
108
- configurationValid: testResult.success,
109
- lastError: testResult.error
110
- };
111
- } catch (error) {
112
- status.gemini = {
113
- available: false,
114
- capabilities: {
115
- codeGeneration: false,
116
- fileAnalysis: false,
117
- webSearch: false,
118
- repositoryAccess: false,
119
- realTimeProcessing: false,
120
- autonomousExecution: false
121
- },
122
- metrics: this.agentMetrics.get('gemini')!,
123
- lastError: error instanceof Error ? error.message : 'Unknown error',
124
- configurationValid: false
125
- };
126
- }
127
- } else {
128
- status.gemini = {
129
- available: false,
130
- capabilities: {
131
- codeGeneration: false,
132
- fileAnalysis: false,
133
- webSearch: false,
134
- repositoryAccess: false,
135
- realTimeProcessing: false,
136
- autonomousExecution: false
137
- },
138
- metrics: this.agentMetrics.get('gemini')!,
139
- lastError: 'Gemini API key not configured',
140
- configurationValid: false
141
- };
142
- }
143
-
144
- // Check Jules status
145
- if (this.julesAgent) {
146
- try {
147
- const testResult = await this.julesAgent.testConnection();
148
- const hasRepository = await this.julesAgent.isRepositoryDetected();
149
-
150
- status.jules = {
151
- available: testResult.success && hasRepository,
152
- capabilities: {
153
- codeGeneration: true,
154
- fileAnalysis: true,
155
- webSearch: false,
156
- repositoryAccess: true,
157
- realTimeProcessing: false,
158
- autonomousExecution: true
159
- },
160
- metrics: this.agentMetrics.get('jules')!,
161
- configurationValid: testResult.success,
162
- lastError: testResult.error || (!hasRepository ? 'No GitHub repository detected' : undefined)
163
- };
164
- } catch (error) {
165
- status.jules = {
166
- available: false,
167
- capabilities: {
168
- codeGeneration: false,
169
- fileAnalysis: false,
170
- webSearch: false,
171
- repositoryAccess: false,
172
- realTimeProcessing: false,
173
- autonomousExecution: false
174
- },
175
- metrics: this.agentMetrics.get('jules')!,
176
- lastError: error instanceof Error ? error.message : 'Unknown error',
177
- configurationValid: false
178
- };
179
- }
180
- } else {
181
- status.jules = {
182
- available: false,
183
- capabilities: {
184
- codeGeneration: false,
185
- fileAnalysis: false,
186
- webSearch: false,
187
- repositoryAccess: false,
188
- realTimeProcessing: false,
189
- autonomousExecution: false
190
- },
191
- metrics: this.agentMetrics.get('jules')!,
192
- lastError: 'Jules API key not configured',
193
- configurationValid: false
194
- };
195
- }
196
-
197
- return status;
198
- }
199
-
200
- /**
201
- * Intelligent agent selection based on context and requirements
202
- */
203
- async selectOptimalAgent(
204
- violations: Violation[],
205
- context: {
206
- hasRepository: boolean;
207
- requiresRealTime: boolean;
208
- complexityLevel: 'low' | 'medium' | 'high';
209
- userPreference?: 'gemini' | 'jules';
210
- }
211
- ): Promise<{
212
- primary: 'gemini' | 'jules';
213
- fallback: 'gemini' | 'jules';
214
- reasoning: string;
215
- confidence: number;
216
- }> {
217
- const agentStatus = await this.getAgentStatus();
218
- const geminiMetrics = this.agentMetrics.get('gemini')!;
219
- const julesMetrics = this.agentMetrics.get('jules')!;
220
-
221
- // Calculate scores for each agent
222
- let geminiScore = 0;
223
- let julesScore = 0;
224
-
225
- // Availability scoring
226
- if (agentStatus.gemini?.available) geminiScore += 30;
227
- if (agentStatus.jules?.available) julesScore += 30;
228
-
229
- // Capability scoring
230
- if (context.requiresRealTime) {
231
- geminiScore += 25; // Gemini is real-time
232
- julesScore += 5; // Jules is async
233
- }
234
-
235
- if (context.hasRepository) {
236
- julesScore += 20; // Jules excels with repositories
237
- geminiScore += 10; // Gemini can work with repos but not optimized
238
- } else {
239
- geminiScore += 25; // Gemini works with any files
240
- julesScore += 0; // Jules requires repository
241
- }
242
-
243
- // Complexity scoring
244
- switch (context.complexityLevel) {
245
- case 'low':
246
- geminiScore += 15; // Gemini is faster for simple fixes
247
- julesScore += 10;
248
- break;
249
- case 'medium':
250
- geminiScore += 12;
251
- julesScore += 12;
252
- break;
253
- case 'high':
254
- geminiScore += 8;
255
- julesScore += 18; // Jules better for complex autonomous work
256
- break;
257
- }
258
-
259
- // Reliability scoring
260
- geminiScore += geminiMetrics.reliability * 10;
261
- julesScore += julesMetrics.reliability * 10;
262
-
263
- // User preference bonus
264
- if (context.userPreference === 'gemini') geminiScore += 15;
265
- if (context.userPreference === 'jules') julesScore += 15;
266
-
267
- // Determine primary and fallback
268
- const primary = geminiScore >= julesScore ? 'gemini' : 'jules';
269
- const fallback = primary === 'gemini' ? 'jules' : 'gemini';
270
-
271
- const confidence = Math.max(geminiScore, julesScore) / 100;
272
-
273
- let reasoning = '';
274
- if (primary === 'gemini') {
275
- reasoning = `Gemini selected: ${context.requiresRealTime ? 'real-time processing needed, ' : ''}${!context.hasRepository ? 'works with local files, ' : ''}high reliability (${Math.round(geminiMetrics.reliability * 100)}%)`;
276
- } else {
277
- reasoning = `Jules selected: ${context.hasRepository ? 'repository context available, ' : ''}${context.complexityLevel === 'high' ? 'complex autonomous work, ' : ''}good for comprehensive fixes`;
278
- }
279
-
280
- this.categoryLogger.info('Agent selection completed', {
281
- primary,
282
- fallback,
283
- geminiScore,
284
- julesScore,
285
- confidence,
286
- reasoning
287
- });
288
-
289
- return { primary, fallback, reasoning, confidence };
290
- }
291
-
292
- /**
293
- * Execute fixes using the optimal agent with fallback
294
- */
295
- async executeFixes(
296
- violations: Violation[],
297
- analyses: Analysis[],
298
- options: {
299
- auto?: boolean;
300
- userPreference?: 'gemini' | 'jules';
301
- requiresRealTime?: boolean;
302
- } = {}
303
- ): Promise<{
304
- fixes: Fix[];
305
- agentUsed: 'gemini' | 'jules';
306
- executionTime: number;
307
- success: boolean;
308
- error?: string;
309
- }> {
310
- const startTime = Date.now();
311
-
312
- // Determine context
313
- const hasRepository = this.julesAgent ? await this.julesAgent.isRepositoryDetected() : false;
314
- const context = {
315
- hasRepository,
316
- requiresRealTime: options.requiresRealTime ?? true,
317
- complexityLevel: this.assessComplexity(violations),
318
- userPreference: options.userPreference
319
- };
320
-
321
- // Select optimal agent
322
- const selection = await this.selectOptimalAgent(violations, context);
323
-
324
- console.log(chalk.cyan(`🤖 Using ${selection.primary} agent (${Math.round(selection.confidence * 100)}% confidence)`));
325
- console.log(chalk.dim(` Reasoning: ${selection.reasoning}`));
326
-
327
- try {
328
- // Try primary agent
329
- const result = await this.executeWithAgent(
330
- selection.primary,
331
- violations,
332
- analyses,
333
- options
334
- );
335
-
336
- // Update metrics
337
- this.updateAgentMetrics(selection.primary, true, Date.now() - startTime);
338
-
339
- return {
340
- ...result,
341
- agentUsed: selection.primary,
342
- executionTime: Date.now() - startTime,
343
- success: true
344
- };
345
-
346
- } catch (primaryError) {
347
- this.categoryLogger.warn(`Primary agent ${selection.primary} failed`, { error: primaryError });
348
-
349
- // Update metrics for failure
350
- this.updateAgentMetrics(selection.primary, false, Date.now() - startTime);
351
-
352
- console.log(chalk.yellow(`⚠️ ${selection.primary} failed, trying ${selection.fallback}...`));
353
-
354
- try {
355
- // Try fallback agent
356
- const result = await this.executeWithAgent(
357
- selection.fallback,
358
- violations,
359
- analyses,
360
- options
361
- );
362
-
363
- // Update metrics
364
- this.updateAgentMetrics(selection.fallback, true, Date.now() - startTime);
365
-
366
- return {
367
- ...result,
368
- agentUsed: selection.fallback,
369
- executionTime: Date.now() - startTime,
370
- success: true
371
- };
372
-
373
- } catch (fallbackError) {
374
- this.categoryLogger.error('Both agents failed', {
375
- primaryError,
376
- fallbackError
377
- });
378
-
379
- // Update metrics for failure
380
- this.updateAgentMetrics(selection.fallback, false, Date.now() - startTime);
381
-
382
- return {
383
- fixes: [],
384
- agentUsed: selection.primary,
385
- executionTime: Date.now() - startTime,
386
- success: false,
387
- error: `Both agents failed. Primary (${selection.primary}): ${primaryError instanceof Error ? primaryError.message : 'Unknown error'}. Fallback (${selection.fallback}): ${fallbackError instanceof Error ? fallbackError.message : 'Unknown error'}`
388
- };
389
- }
390
- }
391
- }
392
-
393
- /**
394
- * Execute fixes with a specific agent
395
- */
396
- private async executeWithAgent(
397
- agentType: 'gemini' | 'jules',
398
- violations: Violation[],
399
- analyses: Analysis[],
400
- _options: { auto?: boolean } = {}
401
- ): Promise<{ fixes: Fix[] }> {
402
- const fixes: Fix[] = [];
403
-
404
- if (agentType === 'gemini' && this.geminiAgent) {
405
- // Generate fixes one by one for Gemini
406
- for (let i = 0; i < violations.length; i++) {
407
- const violation = violations[i];
408
- const analysis = analyses[i];
409
- if (violation && analysis) {
410
- const fix = await this.geminiAgent.generateFix(violation, analysis);
411
- fixes.push(fix);
412
- }
413
- }
414
- } else if (agentType === 'jules' && this.julesAgent) {
415
- // Generate fixes one by one for Jules
416
- for (let i = 0; i < violations.length; i++) {
417
- const violation = violations[i];
418
- const analysis = analyses[i];
419
- if (violation && analysis) {
420
- const fix = await this.julesAgent.generateFix(violation, analysis);
421
- fixes.push(fix);
422
- }
423
- }
424
- } else {
425
- throw new Error(`Agent ${agentType} is not available or not configured`);
426
- }
427
-
428
- return { fixes };
429
- }
430
-
431
- /**
432
- * Assess complexity level of violations
433
- */
434
- private assessComplexity(violations: Violation[]): 'low' | 'medium' | 'high' {
435
- if (violations.length <= 3) return 'low';
436
- if (violations.length <= 10) return 'medium';
437
- return 'high';
438
- }
439
-
440
- /**
441
- * Update agent performance metrics
442
- */
443
- private updateAgentMetrics(
444
- agentType: 'gemini' | 'jules',
445
- success: boolean,
446
- responseTime: number
447
- ): void {
448
- const metrics = this.agentMetrics.get(agentType);
449
- if (!metrics) return;
450
-
451
- metrics.totalExecutions++;
452
- metrics.lastUsed = new Date();
453
-
454
- // Update success rate (exponential moving average)
455
- const alpha = 0.1;
456
- metrics.successRate = success
457
- ? metrics.successRate + alpha * (1 - metrics.successRate)
458
- : metrics.successRate + alpha * (0 - metrics.successRate);
459
-
460
- // Update average response time (exponential moving average)
461
- metrics.averageResponseTime = metrics.averageResponseTime + alpha * (responseTime - metrics.averageResponseTime);
462
-
463
- // Update reliability (combination of success rate and consistency)
464
- metrics.reliability = metrics.successRate * 0.8 + (1 - Math.min(responseTime / 10000, 1)) * 0.2;
465
-
466
- this.agentMetrics.set(agentType, metrics);
467
- }
468
-
469
- /**
470
- * Get performance analytics for all agents
471
- */
472
- getPerformanceAnalytics(): {
473
- gemini: AgentMetrics & { recommendation: string };
474
- jules: AgentMetrics & { recommendation: string };
475
- overall: {
476
- totalExecutions: number;
477
- averageSuccessRate: number;
478
- recommendedPrimary: 'gemini' | 'jules';
479
- };
480
- } {
481
- const geminiMetrics = this.agentMetrics.get('gemini')!;
482
- const julesMetrics = this.agentMetrics.get('jules')!;
483
-
484
- const geminiRecommendation = this.getAgentRecommendation('gemini', geminiMetrics);
485
- const julesRecommendation = this.getAgentRecommendation('jules', julesMetrics);
486
-
487
- const totalExecutions = geminiMetrics.totalExecutions + julesMetrics.totalExecutions;
488
- const averageSuccessRate = (geminiMetrics.successRate + julesMetrics.successRate) / 2;
489
- const recommendedPrimary = geminiMetrics.reliability >= julesMetrics.reliability ? 'gemini' : 'jules';
490
-
491
- return {
492
- gemini: { ...geminiMetrics, recommendation: geminiRecommendation },
493
- jules: { ...julesMetrics, recommendation: julesRecommendation },
494
- overall: {
495
- totalExecutions,
496
- averageSuccessRate,
497
- recommendedPrimary
498
- }
499
- };
500
- }
501
-
502
- /**
503
- * Get recommendation for specific agent
504
- */
505
- private getAgentRecommendation(agentType: 'gemini' | 'jules', metrics: AgentMetrics): string {
506
- if (metrics.reliability > 0.9) {
507
- return `Excellent performance - recommended for ${agentType === 'gemini' ? 'real-time fixes' : 'complex autonomous work'}`;
508
- } else if (metrics.reliability > 0.8) {
509
- return `Good performance - suitable for most tasks`;
510
- } else if (metrics.reliability > 0.6) {
511
- return `Moderate performance - consider as fallback option`;
512
- } else {
513
- return `Poor performance - check configuration and API keys`;
514
- }
515
- }
516
-
517
- /**
518
- * Reset metrics (useful for testing or fresh start)
519
- */
520
- resetMetrics(): void {
521
- this.initializeMetrics();
522
- this.categoryLogger.info('Agent metrics reset');
523
- }
524
-
525
- /**
526
- * Export metrics for external analysis
527
- */
528
- exportMetrics(): Record<string, AgentMetrics> {
529
- return {
530
- gemini: { ...this.agentMetrics.get('gemini')! },
531
- jules: { ...this.agentMetrics.get('jules')! }
532
- };
533
- }
1
+ /**
2
+ * AgentKit-inspired orchestrator for managing multiple coding agents
3
+ * Based on OpenAI's AgentKit principles for production-ready agent workflows
4
+ */
5
+
6
+ import type { Violation, Analysis, Fix } from '../types/index.js';
7
+ import { GeminiCodeFixer } from './gemini-code-fixer.js';
8
+ import { JulesImplementer } from './jules-implementer.js';
9
+ import { logger } from '../core/debug-logger.js';
10
+ import chalk from 'chalk';
11
+
12
+ export interface AgentCapabilities {
13
+ codeGeneration: boolean;
14
+ fileAnalysis: boolean;
15
+ webSearch: boolean;
16
+ repositoryAccess: boolean;
17
+ realTimeProcessing: boolean;
18
+ autonomousExecution: boolean;
19
+ }
20
+
21
+ export interface AgentMetrics {
22
+ successRate: number;
23
+ averageResponseTime: number;
24
+ totalExecutions: number;
25
+ lastUsed: Date;
26
+ reliability: number;
27
+ }
28
+
29
+ export interface AgentStatus {
30
+ available: boolean;
31
+ capabilities: AgentCapabilities;
32
+ metrics: AgentMetrics;
33
+ lastError?: string;
34
+ configurationValid: boolean;
35
+ }
36
+
37
+ /**
38
+ * AgentKit-inspired orchestrator for intelligent agent selection and workflow optimization
39
+ */
40
+ export class AgentKitOrchestrator {
41
+ private geminiAgent: GeminiCodeFixer | null = null;
42
+ private julesAgent: JulesImplementer | null = null;
43
+ private agentMetrics: Map<string, AgentMetrics>;
44
+ private categoryLogger: ReturnType<typeof logger.createCategoryLogger>;
45
+ private geminiApiKey: string | null;
46
+ private julesApiKey: string | null;
47
+
48
+ constructor(geminiApiKey: string | null, julesApiKey: string | null) {
49
+ this.geminiApiKey = geminiApiKey;
50
+ this.julesApiKey = julesApiKey;
51
+ this.agentMetrics = new Map();
52
+ this.categoryLogger = logger.createCategoryLogger('agentkit-orchestrator');
53
+
54
+ // Initialize agents if API keys are available
55
+ if (geminiApiKey) {
56
+ this.geminiAgent = new GeminiCodeFixer(geminiApiKey);
57
+ }
58
+ if (julesApiKey) {
59
+ this.julesAgent = new JulesImplementer(julesApiKey);
60
+ }
61
+
62
+ // Initialize metrics
63
+ this.initializeMetrics();
64
+ }
65
+
66
+ /**
67
+ * Initialize agent metrics tracking
68
+ */
69
+ private initializeMetrics(): void {
70
+ this.agentMetrics.set('gemini', {
71
+ successRate: 0.95,
72
+ averageResponseTime: 2500, // ms
73
+ totalExecutions: 0,
74
+ lastUsed: new Date(),
75
+ reliability: 0.95
76
+ });
77
+
78
+ this.agentMetrics.set('jules', {
79
+ successRate: 0.88,
80
+ averageResponseTime: 15000, // ms (async processing)
81
+ totalExecutions: 0,
82
+ lastUsed: new Date(),
83
+ reliability: 0.88
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Get comprehensive status of all agents
89
+ */
90
+ async getAgentStatus(): Promise<Record<string, AgentStatus>> {
91
+ const status: Record<string, AgentStatus> = {};
92
+
93
+ // Check Gemini status
94
+ if (this.geminiAgent) {
95
+ try {
96
+ const testResult = await this.geminiAgent.testConnection();
97
+ status.gemini = {
98
+ available: testResult.success,
99
+ capabilities: {
100
+ codeGeneration: true,
101
+ fileAnalysis: true,
102
+ webSearch: true,
103
+ repositoryAccess: false,
104
+ realTimeProcessing: true,
105
+ autonomousExecution: false
106
+ },
107
+ metrics: this.agentMetrics.get('gemini')!,
108
+ configurationValid: testResult.success,
109
+ lastError: testResult.error
110
+ };
111
+ } catch (error) {
112
+ status.gemini = {
113
+ available: false,
114
+ capabilities: {
115
+ codeGeneration: false,
116
+ fileAnalysis: false,
117
+ webSearch: false,
118
+ repositoryAccess: false,
119
+ realTimeProcessing: false,
120
+ autonomousExecution: false
121
+ },
122
+ metrics: this.agentMetrics.get('gemini')!,
123
+ lastError: error instanceof Error ? error.message : 'Unknown error',
124
+ configurationValid: false
125
+ };
126
+ }
127
+ } else {
128
+ status.gemini = {
129
+ available: false,
130
+ capabilities: {
131
+ codeGeneration: false,
132
+ fileAnalysis: false,
133
+ webSearch: false,
134
+ repositoryAccess: false,
135
+ realTimeProcessing: false,
136
+ autonomousExecution: false
137
+ },
138
+ metrics: this.agentMetrics.get('gemini')!,
139
+ lastError: 'Gemini API key not configured',
140
+ configurationValid: false
141
+ };
142
+ }
143
+
144
+ // Check Jules status
145
+ if (this.julesAgent) {
146
+ try {
147
+ const testResult = await this.julesAgent.testConnection();
148
+ const hasRepository = await this.julesAgent.isRepositoryDetected();
149
+
150
+ status.jules = {
151
+ available: testResult.success && hasRepository,
152
+ capabilities: {
153
+ codeGeneration: true,
154
+ fileAnalysis: true,
155
+ webSearch: false,
156
+ repositoryAccess: true,
157
+ realTimeProcessing: false,
158
+ autonomousExecution: true
159
+ },
160
+ metrics: this.agentMetrics.get('jules')!,
161
+ configurationValid: testResult.success,
162
+ lastError: testResult.error || (!hasRepository ? 'No GitHub repository detected' : undefined)
163
+ };
164
+ } catch (error) {
165
+ status.jules = {
166
+ available: false,
167
+ capabilities: {
168
+ codeGeneration: false,
169
+ fileAnalysis: false,
170
+ webSearch: false,
171
+ repositoryAccess: false,
172
+ realTimeProcessing: false,
173
+ autonomousExecution: false
174
+ },
175
+ metrics: this.agentMetrics.get('jules')!,
176
+ lastError: error instanceof Error ? error.message : 'Unknown error',
177
+ configurationValid: false
178
+ };
179
+ }
180
+ } else {
181
+ status.jules = {
182
+ available: false,
183
+ capabilities: {
184
+ codeGeneration: false,
185
+ fileAnalysis: false,
186
+ webSearch: false,
187
+ repositoryAccess: false,
188
+ realTimeProcessing: false,
189
+ autonomousExecution: false
190
+ },
191
+ metrics: this.agentMetrics.get('jules')!,
192
+ lastError: 'Jules API key not configured',
193
+ configurationValid: false
194
+ };
195
+ }
196
+
197
+ return status;
198
+ }
199
+
200
+ /**
201
+ * Intelligent agent selection based on context and requirements
202
+ */
203
+ async selectOptimalAgent(
204
+ violations: Violation[],
205
+ context: {
206
+ hasRepository: boolean;
207
+ requiresRealTime: boolean;
208
+ complexityLevel: 'low' | 'medium' | 'high';
209
+ userPreference?: 'gemini' | 'jules';
210
+ }
211
+ ): Promise<{
212
+ primary: 'gemini' | 'jules';
213
+ fallback: 'gemini' | 'jules';
214
+ reasoning: string;
215
+ confidence: number;
216
+ }> {
217
+ const agentStatus = await this.getAgentStatus();
218
+ const geminiMetrics = this.agentMetrics.get('gemini')!;
219
+ const julesMetrics = this.agentMetrics.get('jules')!;
220
+
221
+ // Calculate scores for each agent
222
+ let geminiScore = 0;
223
+ let julesScore = 0;
224
+
225
+ // Availability scoring
226
+ if (agentStatus.gemini?.available) geminiScore += 30;
227
+ if (agentStatus.jules?.available) julesScore += 30;
228
+
229
+ // Capability scoring
230
+ if (context.requiresRealTime) {
231
+ geminiScore += 25; // Gemini is real-time
232
+ julesScore += 5; // Jules is async
233
+ }
234
+
235
+ if (context.hasRepository) {
236
+ julesScore += 20; // Jules excels with repositories
237
+ geminiScore += 10; // Gemini can work with repos but not optimized
238
+ } else {
239
+ geminiScore += 25; // Gemini works with any files
240
+ julesScore += 0; // Jules requires repository
241
+ }
242
+
243
+ // Complexity scoring
244
+ switch (context.complexityLevel) {
245
+ case 'low':
246
+ geminiScore += 15; // Gemini is faster for simple fixes
247
+ julesScore += 10;
248
+ break;
249
+ case 'medium':
250
+ geminiScore += 12;
251
+ julesScore += 12;
252
+ break;
253
+ case 'high':
254
+ geminiScore += 8;
255
+ julesScore += 18; // Jules better for complex autonomous work
256
+ break;
257
+ }
258
+
259
+ // Reliability scoring
260
+ geminiScore += geminiMetrics.reliability * 10;
261
+ julesScore += julesMetrics.reliability * 10;
262
+
263
+ // User preference bonus
264
+ if (context.userPreference === 'gemini') geminiScore += 15;
265
+ if (context.userPreference === 'jules') julesScore += 15;
266
+
267
+ // Determine primary and fallback
268
+ const primary = geminiScore >= julesScore ? 'gemini' : 'jules';
269
+ const fallback = primary === 'gemini' ? 'jules' : 'gemini';
270
+
271
+ const confidence = Math.max(geminiScore, julesScore) / 100;
272
+
273
+ let reasoning = '';
274
+ if (primary === 'gemini') {
275
+ reasoning = `Gemini selected: ${context.requiresRealTime ? 'real-time processing needed, ' : ''}${!context.hasRepository ? 'works with local files, ' : ''}high reliability (${Math.round(geminiMetrics.reliability * 100)}%)`;
276
+ } else {
277
+ reasoning = `Jules selected: ${context.hasRepository ? 'repository context available, ' : ''}${context.complexityLevel === 'high' ? 'complex autonomous work, ' : ''}good for comprehensive fixes`;
278
+ }
279
+
280
+ this.categoryLogger.info('Agent selection completed', {
281
+ primary,
282
+ fallback,
283
+ geminiScore,
284
+ julesScore,
285
+ confidence,
286
+ reasoning
287
+ });
288
+
289
+ return { primary, fallback, reasoning, confidence };
290
+ }
291
+
292
+ /**
293
+ * Execute fixes using the optimal agent with fallback
294
+ */
295
+ async executeFixes(
296
+ violations: Violation[],
297
+ analyses: Analysis[],
298
+ options: {
299
+ auto?: boolean;
300
+ userPreference?: 'gemini' | 'jules';
301
+ requiresRealTime?: boolean;
302
+ } = {}
303
+ ): Promise<{
304
+ fixes: Fix[];
305
+ agentUsed: 'gemini' | 'jules';
306
+ executionTime: number;
307
+ success: boolean;
308
+ error?: string;
309
+ }> {
310
+ const startTime = Date.now();
311
+
312
+ // Determine context
313
+ const hasRepository = this.julesAgent ? await this.julesAgent.isRepositoryDetected() : false;
314
+ const context = {
315
+ hasRepository,
316
+ requiresRealTime: options.requiresRealTime ?? true,
317
+ complexityLevel: this.assessComplexity(violations),
318
+ userPreference: options.userPreference
319
+ };
320
+
321
+ // Select optimal agent
322
+ const selection = await this.selectOptimalAgent(violations, context);
323
+
324
+ console.log(chalk.cyan(`🤖 Using ${selection.primary} agent (${Math.round(selection.confidence * 100)}% confidence)`));
325
+ console.log(chalk.dim(` Reasoning: ${selection.reasoning}`));
326
+
327
+ try {
328
+ // Try primary agent
329
+ const result = await this.executeWithAgent(
330
+ selection.primary,
331
+ violations,
332
+ analyses,
333
+ options
334
+ );
335
+
336
+ // Update metrics
337
+ this.updateAgentMetrics(selection.primary, true, Date.now() - startTime);
338
+
339
+ return {
340
+ ...result,
341
+ agentUsed: selection.primary,
342
+ executionTime: Date.now() - startTime,
343
+ success: true
344
+ };
345
+
346
+ } catch (primaryError) {
347
+ this.categoryLogger.warn(`Primary agent ${selection.primary} failed`, { error: primaryError });
348
+
349
+ // Update metrics for failure
350
+ this.updateAgentMetrics(selection.primary, false, Date.now() - startTime);
351
+
352
+ console.log(chalk.yellow(`⚠️ ${selection.primary} failed, trying ${selection.fallback}...`));
353
+
354
+ try {
355
+ // Try fallback agent
356
+ const result = await this.executeWithAgent(
357
+ selection.fallback,
358
+ violations,
359
+ analyses,
360
+ options
361
+ );
362
+
363
+ // Update metrics
364
+ this.updateAgentMetrics(selection.fallback, true, Date.now() - startTime);
365
+
366
+ return {
367
+ ...result,
368
+ agentUsed: selection.fallback,
369
+ executionTime: Date.now() - startTime,
370
+ success: true
371
+ };
372
+
373
+ } catch (fallbackError) {
374
+ this.categoryLogger.error('Both agents failed', {
375
+ primaryError,
376
+ fallbackError
377
+ });
378
+
379
+ // Update metrics for failure
380
+ this.updateAgentMetrics(selection.fallback, false, Date.now() - startTime);
381
+
382
+ return {
383
+ fixes: [],
384
+ agentUsed: selection.primary,
385
+ executionTime: Date.now() - startTime,
386
+ success: false,
387
+ error: `Both agents failed. Primary (${selection.primary}): ${primaryError instanceof Error ? primaryError.message : 'Unknown error'}. Fallback (${selection.fallback}): ${fallbackError instanceof Error ? fallbackError.message : 'Unknown error'}`
388
+ };
389
+ }
390
+ }
391
+ }
392
+
393
+ /**
394
+ * Execute fixes with a specific agent
395
+ */
396
+ private async executeWithAgent(
397
+ agentType: 'gemini' | 'jules',
398
+ violations: Violation[],
399
+ analyses: Analysis[],
400
+ _options: { auto?: boolean } = {}
401
+ ): Promise<{ fixes: Fix[] }> {
402
+ const fixes: Fix[] = [];
403
+
404
+ if (agentType === 'gemini' && this.geminiAgent) {
405
+ // Generate fixes one by one for Gemini
406
+ for (let i = 0; i < violations.length; i++) {
407
+ const violation = violations[i];
408
+ const analysis = analyses[i];
409
+ if (violation && analysis) {
410
+ const fix = await this.geminiAgent.generateFix(violation, analysis);
411
+ fixes.push(fix);
412
+ }
413
+ }
414
+ } else if (agentType === 'jules' && this.julesAgent) {
415
+ // Generate fixes one by one for Jules
416
+ for (let i = 0; i < violations.length; i++) {
417
+ const violation = violations[i];
418
+ const analysis = analyses[i];
419
+ if (violation && analysis) {
420
+ const fix = await this.julesAgent.generateFix(violation, analysis);
421
+ fixes.push(fix);
422
+ }
423
+ }
424
+ } else {
425
+ throw new Error(`Agent ${agentType} is not available or not configured`);
426
+ }
427
+
428
+ return { fixes };
429
+ }
430
+
431
+ /**
432
+ * Assess complexity level of violations
433
+ */
434
+ private assessComplexity(violations: Violation[]): 'low' | 'medium' | 'high' {
435
+ if (violations.length <= 3) return 'low';
436
+ if (violations.length <= 10) return 'medium';
437
+ return 'high';
438
+ }
439
+
440
+ /**
441
+ * Update agent performance metrics
442
+ */
443
+ private updateAgentMetrics(
444
+ agentType: 'gemini' | 'jules',
445
+ success: boolean,
446
+ responseTime: number
447
+ ): void {
448
+ const metrics = this.agentMetrics.get(agentType);
449
+ if (!metrics) return;
450
+
451
+ metrics.totalExecutions++;
452
+ metrics.lastUsed = new Date();
453
+
454
+ // Update success rate (exponential moving average)
455
+ const alpha = 0.1;
456
+ metrics.successRate = success
457
+ ? metrics.successRate + alpha * (1 - metrics.successRate)
458
+ : metrics.successRate + alpha * (0 - metrics.successRate);
459
+
460
+ // Update average response time (exponential moving average)
461
+ metrics.averageResponseTime = metrics.averageResponseTime + alpha * (responseTime - metrics.averageResponseTime);
462
+
463
+ // Update reliability (combination of success rate and consistency)
464
+ metrics.reliability = metrics.successRate * 0.8 + (1 - Math.min(responseTime / 10000, 1)) * 0.2;
465
+
466
+ this.agentMetrics.set(agentType, metrics);
467
+ }
468
+
469
+ /**
470
+ * Get performance analytics for all agents
471
+ */
472
+ getPerformanceAnalytics(): {
473
+ gemini: AgentMetrics & { recommendation: string };
474
+ jules: AgentMetrics & { recommendation: string };
475
+ overall: {
476
+ totalExecutions: number;
477
+ averageSuccessRate: number;
478
+ recommendedPrimary: 'gemini' | 'jules';
479
+ };
480
+ } {
481
+ const geminiMetrics = this.agentMetrics.get('gemini')!;
482
+ const julesMetrics = this.agentMetrics.get('jules')!;
483
+
484
+ const geminiRecommendation = this.getAgentRecommendation('gemini', geminiMetrics);
485
+ const julesRecommendation = this.getAgentRecommendation('jules', julesMetrics);
486
+
487
+ const totalExecutions = geminiMetrics.totalExecutions + julesMetrics.totalExecutions;
488
+ const averageSuccessRate = (geminiMetrics.successRate + julesMetrics.successRate) / 2;
489
+ const recommendedPrimary = geminiMetrics.reliability >= julesMetrics.reliability ? 'gemini' : 'jules';
490
+
491
+ return {
492
+ gemini: { ...geminiMetrics, recommendation: geminiRecommendation },
493
+ jules: { ...julesMetrics, recommendation: julesRecommendation },
494
+ overall: {
495
+ totalExecutions,
496
+ averageSuccessRate,
497
+ recommendedPrimary
498
+ }
499
+ };
500
+ }
501
+
502
+ /**
503
+ * Get recommendation for specific agent
504
+ */
505
+ private getAgentRecommendation(agentType: 'gemini' | 'jules', metrics: AgentMetrics): string {
506
+ if (metrics.reliability > 0.9) {
507
+ return `Excellent performance - recommended for ${agentType === 'gemini' ? 'real-time fixes' : 'complex autonomous work'}`;
508
+ } else if (metrics.reliability > 0.8) {
509
+ return `Good performance - suitable for most tasks`;
510
+ } else if (metrics.reliability > 0.6) {
511
+ return `Moderate performance - consider as fallback option`;
512
+ } else {
513
+ return `Poor performance - check configuration and API keys`;
514
+ }
515
+ }
516
+
517
+ /**
518
+ * Reset metrics (useful for testing or fresh start)
519
+ */
520
+ resetMetrics(): void {
521
+ this.initializeMetrics();
522
+ this.categoryLogger.info('Agent metrics reset');
523
+ }
524
+
525
+ /**
526
+ * Export metrics for external analysis
527
+ */
528
+ exportMetrics(): Record<string, AgentMetrics> {
529
+ return {
530
+ gemini: { ...this.agentMetrics.get('gemini')! },
531
+ jules: { ...this.agentMetrics.get('jules')! }
532
+ };
533
+ }
534
534
  }