baseguard 1.0.1 → 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.
Files changed (151) hide show
  1. package/.baseguardrc.example.json +64 -0
  2. package/.eslintrc.json +1 -1
  3. package/CHANGELOG.md +196 -0
  4. package/DEPLOYMENT.md +625 -0
  5. package/DEPLOYMENT_CHECKLIST.md +239 -0
  6. package/DEPLOYMENT_SUMMARY_v1.0.2.md +202 -0
  7. package/QUICK_START.md +134 -0
  8. package/README.md +447 -52
  9. package/RELEASE_NOTES_v1.0.2.md +434 -0
  10. package/bin/base.js +64 -59
  11. package/dist/ai/agentkit-orchestrator.d.ts +116 -0
  12. package/dist/ai/agentkit-orchestrator.d.ts.map +1 -0
  13. package/dist/ai/agentkit-orchestrator.js +417 -0
  14. package/dist/ai/agentkit-orchestrator.js.map +1 -0
  15. package/dist/ai/gemini-code-fixer.d.ts +85 -0
  16. package/dist/ai/gemini-code-fixer.d.ts.map +1 -0
  17. package/dist/ai/gemini-code-fixer.js +452 -0
  18. package/dist/ai/gemini-code-fixer.js.map +1 -0
  19. package/dist/ai/jules-implementer.d.ts +5 -4
  20. package/dist/ai/jules-implementer.d.ts.map +1 -1
  21. package/dist/ai/jules-implementer.js +6 -5
  22. package/dist/ai/jules-implementer.js.map +1 -1
  23. package/dist/ai/unified-code-fixer.d.ts +69 -0
  24. package/dist/ai/unified-code-fixer.d.ts.map +1 -0
  25. package/dist/ai/unified-code-fixer.js +289 -0
  26. package/dist/ai/unified-code-fixer.js.map +1 -0
  27. package/dist/commands/check.d.ts +3 -1
  28. package/dist/commands/check.d.ts.map +1 -1
  29. package/dist/commands/check.js +166 -34
  30. package/dist/commands/check.js.map +1 -1
  31. package/dist/commands/config.d.ts +4 -0
  32. package/dist/commands/config.d.ts.map +1 -1
  33. package/dist/commands/config.js +183 -0
  34. package/dist/commands/config.js.map +1 -1
  35. package/dist/commands/fix.d.ts.map +1 -1
  36. package/dist/commands/fix.js +89 -91
  37. package/dist/commands/fix.js.map +1 -1
  38. package/dist/commands/index.d.ts +1 -0
  39. package/dist/commands/index.d.ts.map +1 -1
  40. package/dist/commands/index.js +1 -0
  41. package/dist/commands/index.js.map +1 -1
  42. package/dist/commands/init.d.ts.map +1 -1
  43. package/dist/commands/init.js +16 -2
  44. package/dist/commands/init.js.map +1 -1
  45. package/dist/commands/status.d.ts +14 -0
  46. package/dist/commands/status.d.ts.map +1 -0
  47. package/dist/commands/status.js +254 -0
  48. package/dist/commands/status.js.map +1 -0
  49. package/dist/core/baseguard.d.ts +47 -5
  50. package/dist/core/baseguard.d.ts.map +1 -1
  51. package/dist/core/baseguard.js +506 -52
  52. package/dist/core/baseguard.js.map +1 -1
  53. package/dist/core/cache-manager.d.ts.map +1 -1
  54. package/dist/core/cache-manager.js +3 -1
  55. package/dist/core/cache-manager.js.map +1 -1
  56. package/dist/core/configuration-recovery.d.ts +116 -0
  57. package/dist/core/configuration-recovery.d.ts.map +1 -0
  58. package/dist/core/configuration-recovery.js +552 -0
  59. package/dist/core/configuration-recovery.js.map +1 -0
  60. package/dist/core/configuration.d.ts +4 -0
  61. package/dist/core/configuration.d.ts.map +1 -1
  62. package/dist/core/configuration.js +35 -0
  63. package/dist/core/configuration.js.map +1 -1
  64. package/dist/core/debug-logger.d.ts +181 -0
  65. package/dist/core/debug-logger.d.ts.map +1 -0
  66. package/dist/core/debug-logger.js +479 -0
  67. package/dist/core/debug-logger.js.map +1 -0
  68. package/dist/core/file-processor.d.ts.map +1 -1
  69. package/dist/core/file-processor.js +8 -2
  70. package/dist/core/file-processor.js.map +1 -1
  71. package/dist/core/graceful-degradation-manager.d.ts +123 -0
  72. package/dist/core/graceful-degradation-manager.d.ts.map +1 -0
  73. package/dist/core/graceful-degradation-manager.js +512 -0
  74. package/dist/core/graceful-degradation-manager.js.map +1 -0
  75. package/dist/core/index.d.ts +4 -0
  76. package/dist/core/index.d.ts.map +1 -1
  77. package/dist/core/index.js +4 -0
  78. package/dist/core/index.js.map +1 -1
  79. package/dist/core/logger.d.ts +1 -0
  80. package/dist/core/logger.d.ts.map +1 -0
  81. package/dist/core/logger.js +2 -0
  82. package/dist/core/logger.js.map +1 -0
  83. package/dist/core/memory-manager.d.ts +84 -0
  84. package/dist/core/memory-manager.d.ts.map +1 -1
  85. package/dist/core/memory-manager.js +236 -1
  86. package/dist/core/memory-manager.js.map +1 -1
  87. package/dist/core/startup-optimizer.d.ts +12 -0
  88. package/dist/core/startup-optimizer.d.ts.map +1 -1
  89. package/dist/core/startup-optimizer.js +60 -0
  90. package/dist/core/startup-optimizer.js.map +1 -1
  91. package/dist/core/system-error-handler.d.ts +65 -0
  92. package/dist/core/system-error-handler.d.ts.map +1 -0
  93. package/dist/core/system-error-handler.js +646 -0
  94. package/dist/core/system-error-handler.js.map +1 -0
  95. package/dist/git/github-manager.d.ts +5 -16
  96. package/dist/git/github-manager.d.ts.map +1 -1
  97. package/dist/git/github-manager.js +6 -61
  98. package/dist/git/github-manager.js.map +1 -1
  99. package/dist/parsers/react-parser-optimized.d.ts +16 -0
  100. package/dist/parsers/react-parser-optimized.d.ts.map +1 -0
  101. package/dist/parsers/react-parser-optimized.js +147 -0
  102. package/dist/parsers/react-parser-optimized.js.map +1 -0
  103. package/dist/parsers/react-parser.d.ts.map +1 -1
  104. package/dist/parsers/react-parser.js +17 -15
  105. package/dist/parsers/react-parser.js.map +1 -1
  106. package/dist/parsers/svelte-parser.d.ts.map +1 -1
  107. package/dist/parsers/svelte-parser.js +7 -3
  108. package/dist/parsers/svelte-parser.js.map +1 -1
  109. package/dist/parsers/vanilla-parser.d.ts.map +1 -1
  110. package/dist/parsers/vanilla-parser.js +7 -3
  111. package/dist/parsers/vanilla-parser.js.map +1 -1
  112. package/dist/parsers/vue-parser.d.ts +18 -0
  113. package/dist/parsers/vue-parser.d.ts.map +1 -1
  114. package/dist/parsers/vue-parser.js +387 -1
  115. package/dist/parsers/vue-parser.js.map +1 -1
  116. package/dist/types/index.d.ts +4 -0
  117. package/dist/types/index.d.ts.map +1 -1
  118. package/dist/ui/help.js +1 -1
  119. package/dist/ui/help.js.map +1 -1
  120. package/dist/ui/prompts.d.ts +7 -4
  121. package/dist/ui/prompts.d.ts.map +1 -1
  122. package/dist/ui/prompts.js +48 -55
  123. package/dist/ui/prompts.js.map +1 -1
  124. package/package.json +31 -6
  125. package/src/ai/__tests__/gemini-analyzer.test.ts +2 -2
  126. package/src/ai/agentkit-orchestrator.ts +534 -0
  127. package/src/ai/gemini-code-fixer.ts +540 -0
  128. package/src/ai/jules-implementer.ts +6 -5
  129. package/src/ai/unified-code-fixer.ts +347 -0
  130. package/src/commands/config.ts +126 -0
  131. package/src/commands/fix.ts +98 -94
  132. package/src/commands/init.ts +16 -2
  133. package/src/core/cache-manager.ts +4 -2
  134. package/src/core/configuration.ts +37 -0
  135. package/src/core/debug-logger.ts +2 -2
  136. package/src/core/file-processor.ts +10 -3
  137. package/src/core/index.ts +5 -1
  138. package/src/core/memory-manager.ts +4 -3
  139. package/src/core/startup-optimizer.ts +70 -0
  140. package/src/git/github-manager.ts +11 -79
  141. package/src/parsers/react-parser.ts +2 -2
  142. package/src/parsers/svelte-parser.ts +13 -9
  143. package/src/parsers/vanilla-parser.ts +18 -14
  144. package/src/parsers/vue-parser.ts +20 -14
  145. package/src/types/index.ts +4 -0
  146. package/src/ui/help.ts +1 -1
  147. package/src/ui/prompts.ts +54 -61
  148. package/test-build.js +41 -0
  149. package/tests/e2e/git-integration.e2e.test.ts +1 -1
  150. package/tsconfig.json +0 -1
  151. package/vitest.config.ts +4 -2
@@ -3,7 +3,7 @@ import { UIComponents } from '../ui/index.js';
3
3
  import { BaseGuard } from '../core/index.js';
4
4
  import { ConfigurationManager } from '../core/configuration.js';
5
5
  import { ErrorHandler } from '../core/error-handler.js';
6
- import { JulesImplementer } from '../ai/jules-implementer.js';
6
+ import { UnifiedCodeFixer } from '../ai/unified-code-fixer.js';
7
7
  import { GeminiAnalyzer } from '../ai/gemini-analyzer.js';
8
8
  import { glob } from 'glob';
9
9
 
@@ -34,30 +34,34 @@ export async function fix(options: {
34
34
 
35
35
  // Initialize services
36
36
  const baseGuard = new BaseGuard(config);
37
- const julesImplementer = new JulesImplementer(config.apiKeys.jules);
37
+ const unifiedCodeFixer = new UnifiedCodeFixer(config);
38
38
  const geminiAnalyzer = new GeminiAnalyzer(config.apiKeys.gemini);
39
39
 
40
- // Check GitHub integration
41
- const isGitHubSetup = await julesImplementer.isGitHubIntegrationSetup();
42
- if (!isGitHubSetup) {
43
- console.log(chalk.yellow('āš ļø Jules GitHub integration not set up'));
44
-
45
- const { default: inquirer } = await import('inquirer');
46
- const { setupNow } = await inquirer.prompt([
47
- {
48
- type: 'confirm',
49
- name: 'setupNow',
50
- message: 'Would you like to set up Jules GitHub integration now?',
51
- default: true
52
- }
53
- ]);
54
-
55
- if (setupNow) {
56
- await julesImplementer.setupGitHubIntegration();
57
- } else {
58
- console.log(chalk.yellow('GitHub integration required for Jules fixing. Exiting.'));
59
- process.exit(0);
60
- }
40
+ // Show agent status and recommendations
41
+ console.log(chalk.cyan('šŸ¤– Coding Agent Status:'));
42
+ const agentStatus = await unifiedCodeFixer.getAgentStatus();
43
+
44
+ const primaryAvailable = agentStatus.primary === 'jules' ? agentStatus.jules.available : agentStatus.gemini.available;
45
+ const fallbackAvailable = agentStatus.fallback === 'jules' ? agentStatus.jules.available : agentStatus.gemini.available;
46
+
47
+ console.log(` Primary: ${agentStatus.primary} ${primaryAvailable ? 'āœ…' : 'āŒ'}`);
48
+ console.log(` Fallback: ${agentStatus.fallback} ${fallbackAvailable ? 'āœ…' : 'āŒ'}`);
49
+
50
+ if (!primaryAvailable && !fallbackAvailable) {
51
+ console.log(chalk.red('\nāŒ No coding agents are available'));
52
+ console.log(chalk.cyan('šŸ’” Configure API keys to enable code fixing:'));
53
+ console.log(chalk.cyan(' • Run "base config set-keys" to configure API keys'));
54
+ console.log(chalk.cyan(' • Get Gemini API key: https://aistudio.google.com'));
55
+ console.log(chalk.cyan(' • Get Jules API key: https://jules.google.com/settings#api'));
56
+ process.exit(1);
57
+ }
58
+
59
+ // Show agent-specific information
60
+ if (agentStatus.primary === 'jules' && agentStatus.jules.repoDetected) {
61
+ console.log(chalk.cyan('šŸ”— GitHub repository detected - Jules available for autonomous fixing'));
62
+ } else if (agentStatus.primary === 'gemini' || !agentStatus.jules.repoDetected) {
63
+ console.log(chalk.cyan('šŸ’Ž Using Gemini 2.5 Pro for local file fixing'));
64
+ console.log(chalk.dim(' This works with any local files, no GitHub required'));
61
65
  }
62
66
 
63
67
  // Step 1: Check for violations
@@ -102,88 +106,88 @@ export async function fix(options: {
102
106
  return;
103
107
  }
104
108
 
105
- // Step 3: Generate and apply fixes with Jules
106
- console.log(chalk.cyan('\nšŸ¤– Generating fixes with Jules AI...'));
107
- const results = await julesImplementer.generateAndApplyFixes(violations, analyses);
109
+ // Step 3: Generate fixes with unified code fixer
110
+ console.log(chalk.cyan(`\nšŸ¤– Generating fixes with ${agentStatus.primary}...`));
108
111
 
109
- // Show results
110
- console.log(chalk.cyan('\nšŸ“Š Fix Results:\n'));
112
+ const fixes = [];
113
+ let successCount = 0;
114
+ let failedCount = 0;
111
115
 
112
- if (results.applied.length > 0) {
113
- console.log(chalk.green(`āœ… Applied ${results.applied.length} fixes:`));
114
- results.applied.forEach(fix => {
115
- console.log(chalk.green(` • ${fix.filePath} - ${fix.violation.feature}`));
116
- });
117
- console.log();
116
+ for (let i = 0; i < violations.length; i++) {
117
+ const violation = violations[i];
118
+ const analysis = analyses[i];
119
+
120
+ if (!violation || !analysis) continue;
121
+
122
+ try {
123
+ console.log(chalk.cyan(`\nšŸ”§ Fixing ${violation.feature} in ${violation.file}...`));
124
+
125
+ const fix = await unifiedCodeFixer.generateFix(violation, analysis);
126
+ fixes.push(fix);
127
+ successCount++;
128
+
129
+ console.log(chalk.green(`āœ… Fix generated (confidence: ${Math.round(fix.confidence * 100)}%)`));
130
+
131
+ // Show preview if not in auto mode
132
+ if (!options.auto) {
133
+ console.log(chalk.dim('\nPreview:'));
134
+ console.log(chalk.dim(fix.preview.substring(0, 200) + (fix.preview.length > 200 ? '...' : '')));
135
+ }
136
+
137
+ } catch (error) {
138
+ failedCount++;
139
+ console.log(chalk.red(`āŒ Failed to generate fix: ${error instanceof Error ? error.message : 'Unknown error'}`));
140
+ }
118
141
  }
119
142
 
120
- if (results.skipped.length > 0) {
121
- console.log(chalk.yellow(`ā­ļø Skipped ${results.skipped.length} fixes:`));
122
- results.skipped.forEach(fix => {
123
- console.log(chalk.yellow(` • ${fix.filePath} - ${fix.violation.feature}`));
124
- });
125
- console.log();
143
+ if (fixes.length === 0) {
144
+ console.log(chalk.yellow('\nāš ļø No fixes were generated'));
145
+ return;
126
146
  }
127
147
 
128
- if (results.failed.length > 0) {
129
- console.log(chalk.red(`āŒ Failed ${results.failed.length} fixes:`));
130
- results.failed.forEach(({ fix, error }) => {
131
- console.log(chalk.red(` • ${fix.filePath} - ${fix.violation.feature}: ${error}`));
132
- });
133
- console.log();
148
+ // Show results summary
149
+ console.log(chalk.cyan('\nšŸ“Š Fix Generation Results:\n'));
150
+ console.log(chalk.green(`āœ… Generated ${successCount} fixes`));
151
+ if (failedCount > 0) {
152
+ console.log(chalk.red(`āŒ Failed to generate ${failedCount} fixes`));
134
153
  }
135
154
 
136
- // Show rollback option if fixes were applied
137
- if (results.applied.length > 0) {
138
- const { default: inquirer } = await import('inquirer');
139
- const { showRollback } = await inquirer.prompt([
140
- {
141
- type: 'confirm',
142
- name: 'showRollback',
143
- message: 'Would you like to see rollback options?',
144
- default: false
145
- }
146
- ]);
147
-
148
- if (showRollback) {
149
- const { rollbackAction } = await inquirer.prompt([
150
- {
151
- type: 'list',
152
- name: 'rollbackAction',
153
- message: 'Rollback options:',
154
- choices: [
155
- { name: 'Keep all fixes', value: 'keep' },
156
- { name: 'Rollback all fixes', value: 'rollback_all' },
157
- { name: 'Rollback specific fixes', value: 'rollback_specific' }
158
- ]
159
- }
160
- ]);
155
+ // Show fixes with previews
156
+ if (!options.auto && fixes.length > 0) {
157
+ console.log(chalk.cyan('\nšŸ” Generated Fixes:\n'));
158
+ fixes.forEach((fix, index) => {
159
+ console.log(chalk.white(`${index + 1}. ${fix.violation.feature} in ${fix.filePath}`));
160
+ console.log(chalk.dim(` Confidence: ${Math.round(fix.confidence * 100)}%`));
161
+ console.log(chalk.dim(` Strategy: ${fix.analysis.fixStrategy}`));
161
162
 
162
- if (rollbackAction === 'rollback_all') {
163
- await julesImplementer.rollbackAllFixes();
164
- UIComponents.showSuccessBox('All fixes have been rolled back');
165
- } else if (rollbackAction === 'rollback_specific') {
166
- const appliedFiles = julesImplementer.getAppliedFixes();
167
- const { filesToRollback } = await inquirer.prompt([
168
- {
169
- type: 'checkbox',
170
- name: 'filesToRollback',
171
- message: 'Select fixes to rollback:',
172
- choices: appliedFiles.map(file => ({ name: file, value: file }))
173
- }
174
- ]);
175
-
176
- for (const file of filesToRollback) {
177
- await julesImplementer.rollbackFix(file);
178
- }
179
-
180
- if (filesToRollback.length > 0) {
181
- UIComponents.showSuccessBox(`Rolled back ${filesToRollback.length} fixes`);
182
- }
163
+ // Show a snippet of the explanation
164
+ const explanation = fix.explanation?.split('\n')[0] || 'No explanation available';
165
+ if (explanation.length > 80) {
166
+ console.log(chalk.dim(` ${explanation.substring(0, 80)}...`));
167
+ } else {
168
+ console.log(chalk.dim(` ${explanation}`));
183
169
  }
184
- }
170
+ console.log();
171
+ });
185
172
  }
186
173
 
174
+ // Show summary
175
+ console.log(chalk.cyan(`\nšŸ“ˆ Summary: ${successCount}/${violations.length} fixes generated successfully`));
176
+
177
+ if (failedCount > 0) {
178
+ console.log(chalk.yellow(`\nāš ļø ${failedCount} fixes failed to generate. This may be due to:`));
179
+ console.log(chalk.yellow(' • Complex compatibility issues requiring manual review'));
180
+ console.log(chalk.yellow(' • API rate limits or temporary service issues'));
181
+ console.log(chalk.yellow(' • Files that couldn\'t be read or analyzed'));
182
+ }
183
+
184
+ // Show next steps
185
+ console.log(chalk.cyan('\nšŸ’” Next Steps:'));
186
+ console.log(chalk.cyan(' • Review the generated fixes above'));
187
+ console.log(chalk.cyan(' • Apply fixes manually to your code'));
188
+ console.log(chalk.cyan(' • Test your application after applying fixes'));
189
+ console.log(chalk.cyan(' • Run "base check" to verify fixes resolve violations'));
190
+
187
191
  UIComponents.showSuccessBox('Fix process completed!');
188
192
 
189
193
  } catch (error) {
@@ -203,7 +207,7 @@ export async function fix(options: {
203
207
  UIComponents.showList([
204
208
  'Run "base init" to set up BaseGuard configuration',
205
209
  'Configure API keys with "base config set-keys"',
206
- 'Check GitHub integration for Jules fixing'
210
+ 'Ensure you are in a GitHub repository for Jules fixing'
207
211
  ]);
208
212
  } else if (apiError.type === 'network') {
209
213
  UIComponents.showList([
@@ -69,11 +69,10 @@ export async function init(options: {
69
69
  }
70
70
  }
71
71
 
72
- // Set up API keys if not skipped
72
+ // Set up API keys and coding agent if not skipped
73
73
  if (!options.skipApiKeys) {
74
74
  spinner.stop();
75
75
  const apiKeys = await Prompts.setupApiKeys();
76
- spinner.start();
77
76
 
78
77
  if (apiKeys.julesApiKey) {
79
78
  config.apiKeys.jules = apiKeys.julesApiKey;
@@ -81,6 +80,21 @@ export async function init(options: {
81
80
  if (apiKeys.geminiApiKey) {
82
81
  config.apiKeys.gemini = apiKeys.geminiApiKey;
83
82
  }
83
+
84
+ // Configure coding agent based on available keys
85
+ if (apiKeys.julesApiKey && apiKeys.geminiApiKey) {
86
+ const codingAgentChoice = await Prompts.chooseCodingAgent();
87
+ config.codingAgent.primary = codingAgentChoice.primary;
88
+ config.codingAgent.fallback = codingAgentChoice.fallback;
89
+ } else if (apiKeys.julesApiKey) {
90
+ config.codingAgent.primary = 'jules';
91
+ config.codingAgent.fallback = 'jules';
92
+ } else if (apiKeys.geminiApiKey) {
93
+ config.codingAgent.primary = 'gemini';
94
+ config.codingAgent.fallback = 'gemini';
95
+ }
96
+
97
+ spinner.start();
84
98
  }
85
99
 
86
100
  await ConfigurationManager.save(config);
@@ -28,8 +28,10 @@ export class LRUCache<K, V> {
28
28
  this.cache.delete(key);
29
29
  } else if (this.cache.size >= this.maxSize) {
30
30
  // Remove least recently used (first item)
31
- const firstKey = this.cache.keys().next().value;
32
- this.cache.delete(firstKey);
31
+ const firstKey = this.cache.keys().next().value as K;
32
+ if (firstKey !== undefined) {
33
+ this.cache.delete(firstKey);
34
+ }
33
35
  }
34
36
  this.cache.set(key, value);
35
37
  }
@@ -77,6 +77,10 @@ export class ConfigurationManager {
77
77
  jules: null,
78
78
  gemini: null
79
79
  },
80
+ codingAgent: {
81
+ primary: 'gemini', // 'jules' or 'gemini'
82
+ fallback: 'gemini' // fallback when primary fails
83
+ },
80
84
  automation: {
81
85
  enabled: false,
82
86
  trigger: 'pre-commit',
@@ -119,6 +123,10 @@ export class ConfigurationManager {
119
123
  jules: config.apiKeys?.jules || null,
120
124
  gemini: config.apiKeys?.gemini || null
121
125
  },
126
+ codingAgent: {
127
+ primary: this.validateCodingAgent(config.codingAgent?.primary) || defaultConfig.codingAgent.primary,
128
+ fallback: this.validateCodingAgent(config.codingAgent?.fallback) || defaultConfig.codingAgent.fallback
129
+ },
122
130
  automation: {
123
131
  enabled: config.automation?.enabled ?? defaultConfig.automation.enabled,
124
132
  trigger: this.validateTrigger(config.automation?.trigger) || defaultConfig.automation.trigger,
@@ -194,6 +202,16 @@ export class ConfigurationManager {
194
202
  return null;
195
203
  }
196
204
 
205
+ /**
206
+ * Validate coding agent selection
207
+ */
208
+ private static validateCodingAgent(agent: any): 'jules' | 'gemini' | null {
209
+ if (agent === 'jules' || agent === 'gemini') {
210
+ return agent;
211
+ }
212
+ return null;
213
+ }
214
+
197
215
  /**
198
216
  * Parse browser target string (e.g., "chrome 100", "safari baseline")
199
217
  */
@@ -437,6 +455,18 @@ export class ConfigurationManager {
437
455
  }
438
456
  }
439
457
 
458
+ // Validate coding agent
459
+ if (!config.codingAgent || typeof config.codingAgent !== 'object') {
460
+ errors.push('Coding agent configuration must be an object');
461
+ } else {
462
+ if (config.codingAgent.primary !== 'jules' && config.codingAgent.primary !== 'gemini') {
463
+ errors.push('Primary coding agent must be "jules" or "gemini"');
464
+ }
465
+ if (config.codingAgent.fallback !== 'jules' && config.codingAgent.fallback !== 'gemini') {
466
+ errors.push('Fallback coding agent must be "jules" or "gemini"');
467
+ }
468
+ }
469
+
440
470
  // Validate automation
441
471
  if (!config.automation || typeof config.automation !== 'object') {
442
472
  errors.push('Automation configuration must be an object');
@@ -481,6 +511,13 @@ export class ConfigurationManager {
481
511
  migratedConfig.apiKeys.gemini = config.apiKeys.gemini || null;
482
512
  }
483
513
 
514
+ if (config.codingAgent) {
515
+ migratedConfig.codingAgent = {
516
+ primary: this.validateCodingAgent(config.codingAgent.primary) || 'gemini',
517
+ fallback: this.validateCodingAgent(config.codingAgent.fallback) || 'gemini'
518
+ };
519
+ }
520
+
484
521
  if (config.automation) {
485
522
  migratedConfig.automation = {
486
523
  ...migratedConfig.automation,
@@ -130,8 +130,8 @@ export class DebugLogger {
130
130
  }
131
131
 
132
132
  this.currentSession.endTime = new Date();
133
- this.currentSession.summary.totalDuration =
134
- this.currentSession.endTime.getTime() - this.currentSession.startTime.getTime();
133
+ const duration = this.currentSession.endTime.getTime() - this.currentSession.startTime.getTime();
134
+ this.currentSession.summary.performance.totalDuration = duration;
135
135
 
136
136
  this.info('session', `Debug session ended: ${this.currentSession.id}`);
137
137
 
@@ -103,12 +103,15 @@ export class FileProcessor {
103
103
  );
104
104
 
105
105
  batchResults.forEach((result, index) => {
106
+ const task = batch[index];
107
+ if (!task) return;
108
+
106
109
  if (result.status === 'fulfilled') {
107
110
  allFeatures.push(...result.value);
108
111
  // Cache the result
109
- this.cacheManager.setCachedParseResult(batch[index].filePath, result.value);
112
+ this.cacheManager.setCachedParseResult(task.filePath, result.value);
110
113
  } else {
111
- console.warn(`Failed to process ${batch[index].filePath}: ${result.reason}`);
114
+ console.warn(`Failed to process ${task.filePath}: ${result.reason}`);
112
115
  }
113
116
  });
114
117
 
@@ -222,7 +225,11 @@ export class FileProcessor {
222
225
  /**
223
226
  * Assign task to worker
224
227
  */
225
- private async assignTaskToWorker(worker: Worker, task: WorkerTask): Promise<void> {
228
+ private async assignTaskToWorker(worker: Worker | undefined, task: WorkerTask): Promise<void> {
229
+ if (!worker) {
230
+ throw new Error('Worker is not available');
231
+ }
232
+
226
233
  return new Promise((resolve) => {
227
234
  const timeout = setTimeout(() => {
228
235
  console.warn(`Worker task ${task.id} timed out`);
package/src/core/index.ts CHANGED
@@ -10,4 +10,8 @@ export { FileProcessor } from './file-processor.js';
10
10
  export { DirectoryFilter } from './directory-filter.js';
11
11
  export { LazyLoader } from './lazy-loader.js';
12
12
  export { MemoryManager } from './memory-manager.js';
13
- export { StartupOptimizer } from './startup-optimizer.js';
13
+ export { StartupOptimizer } from './startup-optimizer.js';
14
+ export { SystemErrorHandler } from './system-error-handler.js';
15
+ export { GracefulDegradationManager } from './graceful-degradation-manager.js';
16
+ export { ConfigurationRecovery } from './configuration-recovery.js';
17
+ export { logger, DebugLogger } from './debug-logger.js';
@@ -1,9 +1,9 @@
1
1
  import { createReadStream } from 'fs';
2
2
  import { createInterface } from 'readline';
3
3
 
4
- // Add global type declaration for gc
4
+ // Use Node.js built-in gc type
5
5
  declare global {
6
- var gc: (() => void) | undefined;
6
+ var gc: NodeJS.GCFunction | undefined;
7
7
  }
8
8
 
9
9
  /**
@@ -291,4 +291,5 @@ class ViolationTracker {
291
291
  this.violations.clear();
292
292
  this.fileIndex.clear();
293
293
  this.nextFileId = 0;
294
- }
294
+ }
295
+ }
@@ -170,4 +170,74 @@ export class StartupOptimizer {
170
170
  recommendations
171
171
  };
172
172
  }
173
+
174
+ /**
175
+ * Optimize memory usage by reducing object overhead
176
+ */
177
+ static optimizeMemoryUsage(): void {
178
+ // Enable V8 memory optimizations if available
179
+ if (process.env.NODE_ENV !== 'development') {
180
+ // Set V8 flags for better memory management
181
+ process.env.NODE_OPTIONS = (process.env.NODE_OPTIONS || '') + ' --max-old-space-size=512 --optimize-for-size';
182
+ }
183
+
184
+ // Setup memory monitoring
185
+ if (global.gc) {
186
+ setInterval(() => {
187
+ const usage = process.memoryUsage();
188
+ const heapUsedMB = usage.heapUsed / 1024 / 1024;
189
+
190
+ // Force GC if memory usage is high
191
+ if (heapUsedMB > 100 && global.gc) {
192
+ global.gc();
193
+ }
194
+ }, 30000);
195
+ }
196
+ }
197
+
198
+ /**
199
+ * Reduce startup time by deferring non-critical operations
200
+ */
201
+ static async deferNonCriticalOperations(): Promise<void> {
202
+ // Defer heavy operations until after startup
203
+ setTimeout(async () => {
204
+ try {
205
+ // Preload remaining dependencies
206
+ const { LazyLoader } = await import('./lazy-loader.js');
207
+ LazyLoader.preloadCommon();
208
+
209
+ // Initialize caches
210
+ const { CacheManager } = await import('./cache-manager.js');
211
+ // Cache initialization would happen here
212
+
213
+ // Cleanup old logs
214
+ const { logger } = await import('./debug-logger.js');
215
+ logger.cleanupOldLogs().catch(() => {});
216
+ } catch (error) {
217
+ // Ignore errors in deferred operations
218
+ }
219
+ }, 100); // Defer by 100ms
220
+ }
221
+
222
+ /**
223
+ * Optimize startup by preloading critical dependencies
224
+ */
225
+ static async optimizeStartup(): Promise<void> {
226
+ // Start loading critical dependencies in background
227
+ const { LazyLoader } = await import('./lazy-loader.js');
228
+
229
+ const criticalLoads = [
230
+ LazyLoader.getWebFeatures().catch(() => {}),
231
+ LazyLoader.getBabelParser().catch(() => {})
232
+ ];
233
+
234
+ // Don't wait for all to complete, just start the process
235
+ Promise.all(criticalLoads);
236
+
237
+ // Setup memory optimizations
238
+ this.optimizeMemoryUsage();
239
+
240
+ // Defer non-critical operations
241
+ this.deferNonCriticalOperations();
242
+ }
173
243
  }
@@ -2,44 +2,21 @@ import { execSync } from 'child_process';
2
2
  import { existsSync } from 'fs';
3
3
  import { join } from 'path';
4
4
  import chalk from 'chalk';
5
- import open from 'open';
5
+
6
6
 
7
7
  /**
8
8
  * GitHub repository manager for Jules integration
9
+ * Note: GitHub app installation should be done on the Jules dashboard, not here
9
10
  */
10
11
  export class GitHubManager {
11
12
  private repoOwner: string | null = null;
12
13
  private repoName: string | null = null;
13
14
  private sourceIdentifier: string | null = null;
14
15
 
15
- /**
16
- * Guide user through Jules GitHub app installation
17
- */
18
- async setupJulesGitHubIntegration(): Promise<string> {
19
- console.log(chalk.cyan('\nšŸ”— Setting up Jules GitHub Integration\n'));
20
-
21
- // Step 1: Check if we're in a git repository
22
- if (!this.isGitRepository()) {
23
- throw new Error('Not in a git repository. Please run this command from within a git repository.');
24
- }
25
-
26
- // Step 2: Get repository information
27
- await this.detectRepositoryInfo();
28
-
29
- // Step 3: Guide user through GitHub app installation
30
- await this.guideGitHubAppInstallation();
31
-
32
- // Step 4: Verify connection and get source identifier
33
- const sourceId = await this.getSourceIdentifier();
34
-
35
- console.log(chalk.green('āœ… Jules GitHub integration setup complete!'));
36
- return sourceId;
37
- }
38
-
39
16
  /**
40
17
  * Check if current directory is a git repository
41
18
  */
42
- private isGitRepository(): boolean {
19
+ isGitRepository(): boolean {
43
20
  try {
44
21
  execSync('git rev-parse --git-dir', { stdio: 'ignore' });
45
22
  return true;
@@ -51,7 +28,7 @@ export class GitHubManager {
51
28
  /**
52
29
  * Detect repository owner and name from git remote
53
30
  */
54
- private async detectRepositoryInfo(): Promise<void> {
31
+ async detectRepositoryInfo(): Promise<void> {
55
32
  try {
56
33
  const remoteUrl = execSync('git config --get remote.origin.url', { encoding: 'utf8' }).trim();
57
34
 
@@ -71,59 +48,16 @@ export class GitHubManager {
71
48
  }
72
49
  }
73
50
 
74
- /**
75
- * Guide user through GitHub app installation process
76
- */
77
- private async guideGitHubAppInstallation(): Promise<void> {
78
- console.log(chalk.yellow('\nšŸ“‹ Jules GitHub App Installation Steps:\n'));
79
-
80
- console.log('1. Opening Jules GitHub app installation page...');
81
-
82
- // Open Jules GitHub app installation URL
83
- const installUrl = 'https://github.com/apps/jules-ai';
84
- await open(installUrl);
85
-
86
- console.log(chalk.dim(` ${installUrl}`));
87
-
88
- console.log('\n2. Follow these steps in your browser:');
89
- console.log(' • Click "Install" on the Jules app page');
90
- console.log(' • Select your repository or organization');
91
- console.log(` • Grant access to ${this.repoOwner}/${this.repoName}`);
92
- console.log(' • Complete the installation process');
93
-
94
- console.log('\n3. After installation:');
95
- console.log(' • Return to this terminal');
96
- console.log(' • The setup will continue automatically');
97
-
98
- // Wait for user confirmation
99
- await this.waitForUserConfirmation();
100
- }
101
51
 
102
- /**
103
- * Wait for user to confirm GitHub app installation
104
- */
105
- private async waitForUserConfirmation(): Promise<void> {
106
- const { default: inquirer } = await import('inquirer');
107
-
108
- const { confirmed } = await inquirer.prompt([
109
- {
110
- type: 'confirm',
111
- name: 'confirmed',
112
- message: 'Have you completed the Jules GitHub app installation?',
113
- default: false
114
- }
115
- ]);
116
-
117
- if (!confirmed) {
118
- console.log(chalk.yellow('\nPlease complete the GitHub app installation and run this command again.'));
119
- process.exit(0);
120
- }
121
- }
122
52
 
123
53
  /**
124
54
  * Get source identifier for Jules API
125
55
  */
126
- private async getSourceIdentifier(): Promise<string> {
56
+ async getSourceIdentifier(): Promise<string> {
57
+ if (!this.repoOwner || !this.repoName) {
58
+ await this.detectRepositoryInfo();
59
+ }
60
+
127
61
  if (!this.repoOwner || !this.repoName) {
128
62
  throw new Error('Repository information not available');
129
63
  }
@@ -131,8 +65,6 @@ export class GitHubManager {
131
65
  // Generate source identifier in the format expected by Jules
132
66
  this.sourceIdentifier = `sources/github/${this.repoOwner}/${this.repoName}`;
133
67
 
134
- console.log(chalk.blue(`šŸ”— Source identifier: ${this.sourceIdentifier}`));
135
-
136
68
  return this.sourceIdentifier;
137
69
  }
138
70
 
@@ -174,7 +106,7 @@ export class GitHubManager {
174
106
  }
175
107
 
176
108
  /**
177
- * Check if Jules GitHub integration is set up
109
+ * Check if we can detect repository information (GitHub integration is handled on Jules dashboard)
178
110
  */
179
111
  async isJulesIntegrationSetup(): Promise<boolean> {
180
112
  try {
@@ -183,7 +115,7 @@ export class GitHubManager {
183
115
  }
184
116
 
185
117
  await this.detectRepositoryInfo();
186
- return await this.verifyGitHubConnection();
118
+ return this.repoOwner !== null && this.repoName !== null;
187
119
  } catch {
188
120
  return false;
189
121
  }
@@ -278,7 +278,7 @@ export class ReactParser extends Parser {
278
278
  const features: DetectedFeature[] = [];
279
279
 
280
280
  // Check if this is likely a style object (has CSS-like properties)
281
- const hasStyleProps = node.properties.some(prop => {
281
+ const hasStyleProps = node.properties.some((prop: any) => {
282
282
  if (t.isObjectProperty(prop) && (t.isIdentifier(prop.key) || t.isStringLiteral(prop.key))) {
283
283
  const key = t.isIdentifier(prop.key) ? prop.key.name : prop.key.value;
284
284
  return this.CSS_PROPERTIES.has(key) || key.includes('-') || key.startsWith('--');
@@ -290,7 +290,7 @@ export class ReactParser extends Parser {
290
290
  return features;
291
291
  }
292
292
 
293
- node.properties.forEach(prop => {
293
+ node.properties.forEach((prop: any) => {
294
294
  if (t.isObjectProperty(prop)) {
295
295
  let key = '';
296
296
  if (t.isIdentifier(prop.key)) {