baseguard 1.0.1 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.baseguardrc.example.json +64 -0
- package/.eslintrc.json +1 -1
- package/CHANGELOG.md +196 -0
- package/DEPLOYMENT.md +625 -0
- package/DEPLOYMENT_CHECKLIST.md +239 -0
- package/DEPLOYMENT_SUMMARY_v1.0.2.md +202 -0
- package/QUICK_START.md +134 -0
- package/README.md +447 -52
- package/RELEASE_NOTES_v1.0.2.md +434 -0
- package/bin/base.js +81 -61
- package/dist/ai/agentkit-orchestrator.d.ts +116 -0
- package/dist/ai/agentkit-orchestrator.d.ts.map +1 -0
- package/dist/ai/agentkit-orchestrator.js +417 -0
- package/dist/ai/agentkit-orchestrator.js.map +1 -0
- package/dist/ai/gemini-code-fixer.d.ts +85 -0
- package/dist/ai/gemini-code-fixer.d.ts.map +1 -0
- package/dist/ai/gemini-code-fixer.js +452 -0
- package/dist/ai/gemini-code-fixer.js.map +1 -0
- package/dist/ai/jules-implementer.d.ts +5 -4
- package/dist/ai/jules-implementer.d.ts.map +1 -1
- package/dist/ai/jules-implementer.js +6 -5
- package/dist/ai/jules-implementer.js.map +1 -1
- package/dist/ai/unified-code-fixer.d.ts +69 -0
- package/dist/ai/unified-code-fixer.d.ts.map +1 -0
- package/dist/ai/unified-code-fixer.js +289 -0
- package/dist/ai/unified-code-fixer.js.map +1 -0
- package/dist/commands/check.d.ts +3 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +166 -34
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +183 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/fix.d.ts.map +1 -1
- package/dist/commands/fix.js +89 -91
- package/dist/commands/fix.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +16 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/status.d.ts +14 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +254 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/core/baseguard.d.ts +47 -5
- package/dist/core/baseguard.d.ts.map +1 -1
- package/dist/core/baseguard.js +506 -52
- package/dist/core/baseguard.js.map +1 -1
- package/dist/core/cache-manager.d.ts.map +1 -1
- package/dist/core/cache-manager.js +3 -1
- package/dist/core/cache-manager.js.map +1 -1
- package/dist/core/configuration-recovery.d.ts +116 -0
- package/dist/core/configuration-recovery.d.ts.map +1 -0
- package/dist/core/configuration-recovery.js +552 -0
- package/dist/core/configuration-recovery.js.map +1 -0
- package/dist/core/configuration.d.ts +4 -0
- package/dist/core/configuration.d.ts.map +1 -1
- package/dist/core/configuration.js +35 -0
- package/dist/core/configuration.js.map +1 -1
- package/dist/core/debug-logger.d.ts +181 -0
- package/dist/core/debug-logger.d.ts.map +1 -0
- package/dist/core/debug-logger.js +479 -0
- package/dist/core/debug-logger.js.map +1 -0
- package/dist/core/file-processor.d.ts.map +1 -1
- package/dist/core/file-processor.js +8 -2
- package/dist/core/file-processor.js.map +1 -1
- package/dist/core/graceful-degradation-manager.d.ts +123 -0
- package/dist/core/graceful-degradation-manager.d.ts.map +1 -0
- package/dist/core/graceful-degradation-manager.js +512 -0
- package/dist/core/graceful-degradation-manager.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/logger.d.ts +1 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +2 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/memory-manager.d.ts +84 -0
- package/dist/core/memory-manager.d.ts.map +1 -1
- package/dist/core/memory-manager.js +236 -1
- package/dist/core/memory-manager.js.map +1 -1
- package/dist/core/startup-optimizer.d.ts +14 -0
- package/dist/core/startup-optimizer.d.ts.map +1 -1
- package/dist/core/startup-optimizer.js +74 -3
- package/dist/core/startup-optimizer.js.map +1 -1
- package/dist/core/system-error-handler.d.ts +65 -0
- package/dist/core/system-error-handler.d.ts.map +1 -0
- package/dist/core/system-error-handler.js +653 -0
- package/dist/core/system-error-handler.js.map +1 -0
- package/dist/git/github-manager.d.ts +5 -16
- package/dist/git/github-manager.d.ts.map +1 -1
- package/dist/git/github-manager.js +6 -61
- package/dist/git/github-manager.js.map +1 -1
- package/dist/parsers/react-parser-optimized.d.ts +16 -0
- package/dist/parsers/react-parser-optimized.d.ts.map +1 -0
- package/dist/parsers/react-parser-optimized.js +147 -0
- package/dist/parsers/react-parser-optimized.js.map +1 -0
- package/dist/parsers/react-parser.d.ts.map +1 -1
- package/dist/parsers/react-parser.js +17 -15
- package/dist/parsers/react-parser.js.map +1 -1
- package/dist/parsers/svelte-parser.d.ts.map +1 -1
- package/dist/parsers/svelte-parser.js +7 -3
- package/dist/parsers/svelte-parser.js.map +1 -1
- package/dist/parsers/vanilla-parser.d.ts.map +1 -1
- package/dist/parsers/vanilla-parser.js +7 -3
- package/dist/parsers/vanilla-parser.js.map +1 -1
- package/dist/parsers/vue-parser.d.ts +18 -0
- package/dist/parsers/vue-parser.d.ts.map +1 -1
- package/dist/parsers/vue-parser.js +387 -1
- package/dist/parsers/vue-parser.js.map +1 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/ui/help.js +1 -1
- package/dist/ui/help.js.map +1 -1
- package/dist/ui/prompts.d.ts +7 -4
- package/dist/ui/prompts.d.ts.map +1 -1
- package/dist/ui/prompts.js +48 -55
- package/dist/ui/prompts.js.map +1 -1
- package/package.json +31 -6
- package/src/ai/__tests__/gemini-analyzer.test.ts +2 -2
- package/src/ai/agentkit-orchestrator.ts +534 -0
- package/src/ai/gemini-code-fixer.ts +540 -0
- package/src/ai/jules-implementer.ts +6 -5
- package/src/ai/unified-code-fixer.ts +347 -0
- package/src/commands/config.ts +126 -0
- package/src/commands/fix.ts +98 -94
- package/src/commands/init.ts +16 -2
- package/src/core/cache-manager.ts +4 -2
- package/src/core/configuration.ts +37 -0
- package/src/core/debug-logger.ts +2 -2
- package/src/core/file-processor.ts +10 -3
- package/src/core/index.ts +5 -1
- package/src/core/memory-manager.ts +4 -3
- package/src/core/startup-optimizer.ts +85 -3
- package/src/core/system-error-handler.ts +17 -11
- package/src/git/github-manager.ts +11 -79
- package/src/parsers/react-parser.ts +2 -2
- package/src/parsers/svelte-parser.ts +13 -9
- package/src/parsers/vanilla-parser.ts +18 -14
- package/src/parsers/vue-parser.ts +20 -14
- package/src/types/index.ts +4 -0
- package/src/ui/help.ts +1 -1
- package/src/ui/prompts.ts +54 -61
- package/test-build.js +41 -0
- package/tests/e2e/git-integration.e2e.test.ts +1 -1
- package/tsconfig.json +0 -1
- package/vitest.config.ts +4 -2
package/src/commands/fix.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
37
|
+
const unifiedCodeFixer = new UnifiedCodeFixer(config);
|
|
38
38
|
const geminiAnalyzer = new GeminiAnalyzer(config.apiKeys.gemini);
|
|
39
39
|
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
|
106
|
-
console.log(chalk.cyan(
|
|
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
|
-
|
|
110
|
-
|
|
112
|
+
const fixes = [];
|
|
113
|
+
let successCount = 0;
|
|
114
|
+
let failedCount = 0;
|
|
111
115
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
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 (
|
|
121
|
-
console.log(chalk.yellow(
|
|
122
|
-
|
|
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
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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
|
|
137
|
-
if (
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
{
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
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
|
-
'
|
|
210
|
+
'Ensure you are in a GitHub repository for Jules fixing'
|
|
207
211
|
]);
|
|
208
212
|
} else if (apiError.type === 'network') {
|
|
209
213
|
UIComponents.showList([
|
package/src/commands/init.ts
CHANGED
|
@@ -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
|
-
|
|
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,
|
package/src/core/debug-logger.ts
CHANGED
|
@@ -130,8 +130,8 @@ export class DebugLogger {
|
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
this.currentSession.endTime = new Date();
|
|
133
|
-
this.currentSession.
|
|
134
|
-
|
|
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(
|
|
112
|
+
this.cacheManager.setCachedParseResult(task.filePath, result.value);
|
|
110
113
|
} else {
|
|
111
|
-
console.warn(`Failed to process ${
|
|
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
|
-
//
|
|
4
|
+
// Use Node.js built-in gc type
|
|
5
5
|
declare global {
|
|
6
|
-
var gc:
|
|
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
|
+
}
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
export class StartupOptimizer {
|
|
5
5
|
private static startTime = Date.now();
|
|
6
6
|
private static initialized = false;
|
|
7
|
+
private static gcInterval: NodeJS.Timeout | null = null;
|
|
8
|
+
private static memoryInterval: NodeJS.Timeout | null = null;
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Initialize BaseGuard with optimized startup
|
|
@@ -25,7 +27,7 @@ export class StartupOptimizer {
|
|
|
25
27
|
this.initialized = true;
|
|
26
28
|
|
|
27
29
|
const initTime = Date.now() - startTime;
|
|
28
|
-
if (initTime >
|
|
30
|
+
if (initTime > 1000) {
|
|
29
31
|
console.warn(`Slow startup detected: ${initTime}ms`);
|
|
30
32
|
}
|
|
31
33
|
} catch (error) {
|
|
@@ -57,7 +59,7 @@ export class StartupOptimizer {
|
|
|
57
59
|
// Enable garbage collection hints if available
|
|
58
60
|
if (global.gc) {
|
|
59
61
|
// Set up periodic GC for long-running processes
|
|
60
|
-
setInterval(() => {
|
|
62
|
+
this.gcInterval = setInterval(() => {
|
|
61
63
|
const { MemoryManager } = require('./memory-manager.js');
|
|
62
64
|
const memCheck = MemoryManager.checkMemoryUsage();
|
|
63
65
|
|
|
@@ -124,6 +126,16 @@ export class StartupOptimizer {
|
|
|
124
126
|
const { LazyLoader } = require('./lazy-loader.js');
|
|
125
127
|
const { MemoryManager } = require('./memory-manager.js');
|
|
126
128
|
|
|
129
|
+
// Clear intervals
|
|
130
|
+
if (this.gcInterval) {
|
|
131
|
+
clearInterval(this.gcInterval);
|
|
132
|
+
this.gcInterval = null;
|
|
133
|
+
}
|
|
134
|
+
if (this.memoryInterval) {
|
|
135
|
+
clearInterval(this.memoryInterval);
|
|
136
|
+
this.memoryInterval = null;
|
|
137
|
+
}
|
|
138
|
+
|
|
127
139
|
// Clear caches
|
|
128
140
|
LazyLoader.clearCache();
|
|
129
141
|
|
|
@@ -145,7 +157,7 @@ export class StartupOptimizer {
|
|
|
145
157
|
const metrics = this.getStartupMetrics();
|
|
146
158
|
|
|
147
159
|
// Check startup time
|
|
148
|
-
if (metrics.totalStartupTime >
|
|
160
|
+
if (metrics.totalStartupTime > 2000) {
|
|
149
161
|
issues.push(`Slow startup: ${metrics.totalStartupTime}ms`);
|
|
150
162
|
recommendations.push('Consider reducing dependencies or using lazy loading');
|
|
151
163
|
}
|
|
@@ -170,4 +182,74 @@ export class StartupOptimizer {
|
|
|
170
182
|
recommendations
|
|
171
183
|
};
|
|
172
184
|
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Optimize memory usage by reducing object overhead
|
|
188
|
+
*/
|
|
189
|
+
static optimizeMemoryUsage(): void {
|
|
190
|
+
// Enable V8 memory optimizations if available
|
|
191
|
+
if (process.env.NODE_ENV !== 'development') {
|
|
192
|
+
// Set V8 flags for better memory management
|
|
193
|
+
process.env.NODE_OPTIONS = (process.env.NODE_OPTIONS || '') + ' --max-old-space-size=512 --optimize-for-size';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Setup memory monitoring
|
|
197
|
+
if (global.gc) {
|
|
198
|
+
this.memoryInterval = setInterval(() => {
|
|
199
|
+
const usage = process.memoryUsage();
|
|
200
|
+
const heapUsedMB = usage.heapUsed / 1024 / 1024;
|
|
201
|
+
|
|
202
|
+
// Force GC if memory usage is high
|
|
203
|
+
if (heapUsedMB > 100 && global.gc) {
|
|
204
|
+
global.gc();
|
|
205
|
+
}
|
|
206
|
+
}, 30000);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Reduce startup time by deferring non-critical operations
|
|
212
|
+
*/
|
|
213
|
+
static async deferNonCriticalOperations(): Promise<void> {
|
|
214
|
+
// Defer heavy operations until after startup
|
|
215
|
+
setTimeout(async () => {
|
|
216
|
+
try {
|
|
217
|
+
// Preload remaining dependencies
|
|
218
|
+
const { LazyLoader } = await import('./lazy-loader.js');
|
|
219
|
+
LazyLoader.preloadCommon();
|
|
220
|
+
|
|
221
|
+
// Initialize caches
|
|
222
|
+
const { CacheManager } = await import('./cache-manager.js');
|
|
223
|
+
// Cache initialization would happen here
|
|
224
|
+
|
|
225
|
+
// Cleanup old logs
|
|
226
|
+
const { logger } = await import('./debug-logger.js');
|
|
227
|
+
logger.cleanupOldLogs().catch(() => {});
|
|
228
|
+
} catch (error) {
|
|
229
|
+
// Ignore errors in deferred operations
|
|
230
|
+
}
|
|
231
|
+
}, 100); // Defer by 100ms
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Optimize startup by preloading critical dependencies
|
|
236
|
+
*/
|
|
237
|
+
static async optimizeStartup(): Promise<void> {
|
|
238
|
+
// Start loading critical dependencies in background
|
|
239
|
+
const { LazyLoader } = await import('./lazy-loader.js');
|
|
240
|
+
|
|
241
|
+
const criticalLoads = [
|
|
242
|
+
LazyLoader.getWebFeatures().catch(() => {}),
|
|
243
|
+
LazyLoader.getBabelParser().catch(() => {})
|
|
244
|
+
];
|
|
245
|
+
|
|
246
|
+
// Don't wait for all to complete, just start the process
|
|
247
|
+
Promise.all(criticalLoads);
|
|
248
|
+
|
|
249
|
+
// Setup memory optimizations
|
|
250
|
+
this.optimizeMemoryUsage();
|
|
251
|
+
|
|
252
|
+
// Defer non-critical operations
|
|
253
|
+
this.deferNonCriticalOperations();
|
|
254
|
+
}
|
|
173
255
|
}
|
|
@@ -499,22 +499,28 @@ export class SystemErrorHandler {
|
|
|
499
499
|
|
|
500
500
|
static async handleProcessSignals(): Promise<void> {
|
|
501
501
|
const gracefulShutdown = async (signal: string) => {
|
|
502
|
-
|
|
502
|
+
// Only log for non-interactive signals (SIGTERM, not SIGINT from Ctrl+C)
|
|
503
|
+
if (signal !== 'SIGINT') {
|
|
504
|
+
console.log(chalk.yellow(`\n⚠️ Received ${signal}, shutting down gracefully...`));
|
|
505
|
+
}
|
|
503
506
|
|
|
504
|
-
//
|
|
507
|
+
// Cleanup intervals and timers
|
|
505
508
|
try {
|
|
506
|
-
await
|
|
509
|
+
const { StartupOptimizer } = await import('./startup-optimizer.js');
|
|
510
|
+
StartupOptimizer.cleanup();
|
|
507
511
|
} catch (error) {
|
|
508
|
-
// Ignore errors
|
|
512
|
+
// Ignore cleanup errors
|
|
509
513
|
}
|
|
510
514
|
|
|
511
|
-
//
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
515
|
+
// Save error log before exit (but don't wait too long)
|
|
516
|
+
try {
|
|
517
|
+
const savePromise = SystemErrorHandler.saveErrorLog();
|
|
518
|
+
await Promise.race([
|
|
519
|
+
savePromise,
|
|
520
|
+
new Promise(resolve => setTimeout(resolve, 100)) // Max 100ms wait
|
|
521
|
+
]);
|
|
522
|
+
} catch (error) {
|
|
523
|
+
// Ignore errors during shutdown
|
|
518
524
|
}
|
|
519
525
|
|
|
520
526
|
process.exit(0);
|