baseguard 1.0.2 → 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 (169) hide show
  1. package/.baseguardrc.example.json +63 -63
  2. package/.eslintrc.json +24 -24
  3. package/.prettierrc +7 -7
  4. package/CHANGELOG.md +195 -195
  5. package/DEPLOYMENT.md +624 -624
  6. package/DEPLOYMENT_CHECKLIST.md +239 -239
  7. package/DEPLOYMENT_SUMMARY_v1.0.2.md +202 -202
  8. package/QUICK_START.md +134 -134
  9. package/README.md +488 -488
  10. package/RELEASE_NOTES_v1.0.2.md +434 -434
  11. package/bin/base.js +628 -613
  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 +2 -0
  67. package/dist/core/startup-optimizer.d.ts.map +1 -1
  68. package/dist/core/startup-optimizer.js +19 -12
  69. package/dist/core/startup-optimizer.js.map +1 -1
  70. package/dist/core/system-error-handler.d.ts.map +1 -1
  71. package/dist/core/system-error-handler.js +18 -11
  72. package/dist/core/system-error-handler.js.map +1 -1
  73. package/dist/git/automation-engine.d.ts.map +1 -1
  74. package/dist/git/automation-engine.js +5 -4
  75. package/dist/git/automation-engine.js.map +1 -1
  76. package/dist/git/github-manager.d.ts.map +1 -1
  77. package/dist/git/github-manager.js.map +1 -1
  78. package/dist/git/hook-manager.js +5 -5
  79. package/dist/git/hook-manager.js.map +1 -1
  80. package/dist/parsers/parser-manager.d.ts.map +1 -1
  81. package/dist/parsers/parser-manager.js +1 -1
  82. package/dist/parsers/parser-manager.js.map +1 -1
  83. package/dist/parsers/svelte-parser.js +1 -1
  84. package/dist/parsers/svelte-parser.js.map +1 -1
  85. package/dist/parsers/vanilla-parser.d.ts.map +1 -1
  86. package/dist/parsers/vanilla-parser.js.map +1 -1
  87. package/dist/parsers/vue-parser.d.ts.map +1 -1
  88. package/dist/parsers/vue-parser.js.map +1 -1
  89. package/dist/ui/components.d.ts +1 -1
  90. package/dist/ui/components.d.ts.map +1 -1
  91. package/dist/ui/components.js +11 -11
  92. package/dist/ui/components.js.map +1 -1
  93. package/dist/ui/terminal-header.js +14 -14
  94. package/package.json +105 -105
  95. package/src/ai/__tests__/gemini-analyzer.test.ts +180 -180
  96. package/src/ai/agentkit-orchestrator.ts +533 -533
  97. package/src/ai/fix-manager.ts +362 -362
  98. package/src/ai/gemini-analyzer.ts +665 -671
  99. package/src/ai/gemini-code-fixer.ts +539 -540
  100. package/src/ai/index.ts +3 -3
  101. package/src/ai/jules-implementer.ts +504 -460
  102. package/src/ai/unified-code-fixer.ts +347 -347
  103. package/src/commands/automation.ts +343 -343
  104. package/src/commands/check.ts +298 -299
  105. package/src/commands/config.ts +584 -583
  106. package/src/commands/fix.ts +264 -238
  107. package/src/commands/index.ts +6 -6
  108. package/src/commands/init.ts +155 -155
  109. package/src/commands/status.ts +306 -306
  110. package/src/core/api-key-manager.ts +298 -298
  111. package/src/core/baseguard.ts +757 -756
  112. package/src/core/baseline-checker.ts +564 -563
  113. package/src/core/cache-manager.ts +271 -271
  114. package/src/core/configuration-recovery.ts +672 -673
  115. package/src/core/configuration.ts +595 -595
  116. package/src/core/debug-logger.ts +590 -590
  117. package/src/core/directory-filter.ts +420 -420
  118. package/src/core/error-handler.ts +518 -517
  119. package/src/core/file-processor.ts +337 -337
  120. package/src/core/gitignore-manager.ts +168 -168
  121. package/src/core/graceful-degradation-manager.ts +596 -596
  122. package/src/core/index.ts +16 -16
  123. package/src/core/lazy-loader.ts +317 -307
  124. package/src/core/memory-manager.ts +290 -295
  125. package/src/core/parser-worker.ts +33 -0
  126. package/src/core/startup-optimizer.ts +246 -243
  127. package/src/core/system-error-handler.ts +755 -750
  128. package/src/git/automation-engine.ts +361 -361
  129. package/src/git/github-manager.ts +190 -192
  130. package/src/git/hook-manager.ts +210 -210
  131. package/src/git/index.ts +3 -3
  132. package/src/index.ts +7 -7
  133. package/src/parsers/feature-validator.ts +558 -558
  134. package/src/parsers/index.ts +7 -7
  135. package/src/parsers/parser-manager.ts +418 -419
  136. package/src/parsers/parser.ts +25 -25
  137. package/src/parsers/react-parser-optimized.ts +160 -160
  138. package/src/parsers/react-parser.ts +358 -358
  139. package/src/parsers/svelte-parser.ts +510 -510
  140. package/src/parsers/vanilla-parser.ts +685 -686
  141. package/src/parsers/vue-parser.ts +476 -478
  142. package/src/types/index.ts +95 -95
  143. package/src/ui/components.ts +567 -567
  144. package/src/ui/help.ts +192 -192
  145. package/src/ui/index.ts +3 -3
  146. package/src/ui/prompts.ts +680 -680
  147. package/src/ui/terminal-header.ts +58 -58
  148. package/test-build.js +40 -40
  149. package/test-config-commands.js +55 -55
  150. package/test-header-simple.js +32 -32
  151. package/test-terminal-header.js +11 -11
  152. package/test-ui.js +28 -28
  153. package/tests/e2e/baseguard.e2e.test.ts +515 -515
  154. package/tests/e2e/cross-platform.e2e.test.ts +419 -419
  155. package/tests/e2e/git-integration.e2e.test.ts +486 -486
  156. package/tests/fixtures/react-project/package.json +13 -13
  157. package/tests/fixtures/react-project/src/App.css +75 -75
  158. package/tests/fixtures/react-project/src/App.tsx +76 -76
  159. package/tests/fixtures/svelte-project/package.json +10 -10
  160. package/tests/fixtures/svelte-project/src/App.svelte +368 -368
  161. package/tests/fixtures/vanilla-project/index.html +75 -75
  162. package/tests/fixtures/vanilla-project/script.js +330 -330
  163. package/tests/fixtures/vanilla-project/styles.css +358 -358
  164. package/tests/fixtures/vue-project/package.json +11 -11
  165. package/tests/fixtures/vue-project/src/App.vue +215 -215
  166. package/tsconfig.json +34 -34
  167. package/vitest.config.ts +11 -11
  168. package/dist/terminal-header.d.ts +0 -12
  169. package/dist/terminal-header.js +0 -45
@@ -1,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
  }