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.
- 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 +64 -59
- package/dist/ai/agentkit-orchestrator.d.ts +116 -0
- package/dist/ai/agentkit-orchestrator.d.ts.map +1 -0
- package/dist/ai/agentkit-orchestrator.js +417 -0
- package/dist/ai/agentkit-orchestrator.js.map +1 -0
- package/dist/ai/gemini-code-fixer.d.ts +85 -0
- package/dist/ai/gemini-code-fixer.d.ts.map +1 -0
- package/dist/ai/gemini-code-fixer.js +452 -0
- package/dist/ai/gemini-code-fixer.js.map +1 -0
- package/dist/ai/jules-implementer.d.ts +5 -4
- package/dist/ai/jules-implementer.d.ts.map +1 -1
- package/dist/ai/jules-implementer.js +6 -5
- package/dist/ai/jules-implementer.js.map +1 -1
- package/dist/ai/unified-code-fixer.d.ts +69 -0
- package/dist/ai/unified-code-fixer.d.ts.map +1 -0
- package/dist/ai/unified-code-fixer.js +289 -0
- package/dist/ai/unified-code-fixer.js.map +1 -0
- package/dist/commands/check.d.ts +3 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +166 -34
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +183 -0
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/fix.d.ts.map +1 -1
- package/dist/commands/fix.js +89 -91
- package/dist/commands/fix.js.map +1 -1
- package/dist/commands/index.d.ts +1 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +1 -0
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +16 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/status.d.ts +14 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +254 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/core/baseguard.d.ts +47 -5
- package/dist/core/baseguard.d.ts.map +1 -1
- package/dist/core/baseguard.js +506 -52
- package/dist/core/baseguard.js.map +1 -1
- package/dist/core/cache-manager.d.ts.map +1 -1
- package/dist/core/cache-manager.js +3 -1
- package/dist/core/cache-manager.js.map +1 -1
- package/dist/core/configuration-recovery.d.ts +116 -0
- package/dist/core/configuration-recovery.d.ts.map +1 -0
- package/dist/core/configuration-recovery.js +552 -0
- package/dist/core/configuration-recovery.js.map +1 -0
- package/dist/core/configuration.d.ts +4 -0
- package/dist/core/configuration.d.ts.map +1 -1
- package/dist/core/configuration.js +35 -0
- package/dist/core/configuration.js.map +1 -1
- package/dist/core/debug-logger.d.ts +181 -0
- package/dist/core/debug-logger.d.ts.map +1 -0
- package/dist/core/debug-logger.js +479 -0
- package/dist/core/debug-logger.js.map +1 -0
- package/dist/core/file-processor.d.ts.map +1 -1
- package/dist/core/file-processor.js +8 -2
- package/dist/core/file-processor.js.map +1 -1
- package/dist/core/graceful-degradation-manager.d.ts +123 -0
- package/dist/core/graceful-degradation-manager.d.ts.map +1 -0
- package/dist/core/graceful-degradation-manager.js +512 -0
- package/dist/core/graceful-degradation-manager.js.map +1 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/logger.d.ts +1 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +2 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/memory-manager.d.ts +84 -0
- package/dist/core/memory-manager.d.ts.map +1 -1
- package/dist/core/memory-manager.js +236 -1
- package/dist/core/memory-manager.js.map +1 -1
- package/dist/core/startup-optimizer.d.ts +12 -0
- package/dist/core/startup-optimizer.d.ts.map +1 -1
- package/dist/core/startup-optimizer.js +60 -0
- package/dist/core/startup-optimizer.js.map +1 -1
- package/dist/core/system-error-handler.d.ts +65 -0
- package/dist/core/system-error-handler.d.ts.map +1 -0
- package/dist/core/system-error-handler.js +646 -0
- package/dist/core/system-error-handler.js.map +1 -0
- package/dist/git/github-manager.d.ts +5 -16
- package/dist/git/github-manager.d.ts.map +1 -1
- package/dist/git/github-manager.js +6 -61
- package/dist/git/github-manager.js.map +1 -1
- package/dist/parsers/react-parser-optimized.d.ts +16 -0
- package/dist/parsers/react-parser-optimized.d.ts.map +1 -0
- package/dist/parsers/react-parser-optimized.js +147 -0
- package/dist/parsers/react-parser-optimized.js.map +1 -0
- package/dist/parsers/react-parser.d.ts.map +1 -1
- package/dist/parsers/react-parser.js +17 -15
- package/dist/parsers/react-parser.js.map +1 -1
- package/dist/parsers/svelte-parser.d.ts.map +1 -1
- package/dist/parsers/svelte-parser.js +7 -3
- package/dist/parsers/svelte-parser.js.map +1 -1
- package/dist/parsers/vanilla-parser.d.ts.map +1 -1
- package/dist/parsers/vanilla-parser.js +7 -3
- package/dist/parsers/vanilla-parser.js.map +1 -1
- package/dist/parsers/vue-parser.d.ts +18 -0
- package/dist/parsers/vue-parser.d.ts.map +1 -1
- package/dist/parsers/vue-parser.js +387 -1
- package/dist/parsers/vue-parser.js.map +1 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/ui/help.js +1 -1
- package/dist/ui/help.js.map +1 -1
- package/dist/ui/prompts.d.ts +7 -4
- package/dist/ui/prompts.d.ts.map +1 -1
- package/dist/ui/prompts.js +48 -55
- package/dist/ui/prompts.js.map +1 -1
- package/package.json +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 +70 -0
- 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
|
+
}
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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)) {
|