baseguard 1.0.0
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/.eslintrc.json +25 -0
- package/.prettierrc +8 -0
- package/README.md +94 -0
- package/bin/base.js +494 -0
- package/dist/ai/fix-manager.d.ts +67 -0
- package/dist/ai/fix-manager.d.ts.map +1 -0
- package/dist/ai/fix-manager.js +326 -0
- package/dist/ai/fix-manager.js.map +1 -0
- package/dist/ai/gemini-analyzer.d.ts +116 -0
- package/dist/ai/gemini-analyzer.d.ts.map +1 -0
- package/dist/ai/gemini-analyzer.js +572 -0
- package/dist/ai/gemini-analyzer.js.map +1 -0
- package/dist/ai/index.d.ts +4 -0
- package/dist/ai/index.d.ts.map +1 -0
- package/dist/ai/index.js +5 -0
- package/dist/ai/index.js.map +1 -0
- package/dist/ai/jules-implementer.d.ts +115 -0
- package/dist/ai/jules-implementer.d.ts.map +1 -0
- package/dist/ai/jules-implementer.js +387 -0
- package/dist/ai/jules-implementer.js.map +1 -0
- package/dist/commands/automation.d.ts +5 -0
- package/dist/commands/automation.d.ts.map +1 -0
- package/dist/commands/automation.js +305 -0
- package/dist/commands/automation.js.map +1 -0
- package/dist/commands/check.d.ts +9 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +113 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/config.d.ts +11 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +324 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/fix.d.ts +9 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +207 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +125 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/core/api-key-manager.d.ts +83 -0
- package/dist/core/api-key-manager.d.ts.map +1 -0
- package/dist/core/api-key-manager.js +244 -0
- package/dist/core/api-key-manager.js.map +1 -0
- package/dist/core/baseguard.d.ts +46 -0
- package/dist/core/baseguard.d.ts.map +1 -0
- package/dist/core/baseguard.js +132 -0
- package/dist/core/baseguard.js.map +1 -0
- package/dist/core/baseline-checker.d.ts +63 -0
- package/dist/core/baseline-checker.d.ts.map +1 -0
- package/dist/core/baseline-checker.js +502 -0
- package/dist/core/baseline-checker.js.map +1 -0
- package/dist/core/cache-manager.d.ts +88 -0
- package/dist/core/cache-manager.d.ts.map +1 -0
- package/dist/core/cache-manager.js +213 -0
- package/dist/core/cache-manager.js.map +1 -0
- package/dist/core/configuration.d.ts +140 -0
- package/dist/core/configuration.d.ts.map +1 -0
- package/dist/core/configuration.js +474 -0
- package/dist/core/configuration.js.map +1 -0
- package/dist/core/directory-filter.d.ts +90 -0
- package/dist/core/directory-filter.d.ts.map +1 -0
- package/dist/core/directory-filter.js +319 -0
- package/dist/core/directory-filter.js.map +1 -0
- package/dist/core/error-handler.d.ts +110 -0
- package/dist/core/error-handler.d.ts.map +1 -0
- package/dist/core/error-handler.js +392 -0
- package/dist/core/error-handler.js.map +1 -0
- package/dist/core/file-processor.d.ts +80 -0
- package/dist/core/file-processor.d.ts.map +1 -0
- package/dist/core/file-processor.js +259 -0
- package/dist/core/file-processor.js.map +1 -0
- package/dist/core/gitignore-manager.d.ts +44 -0
- package/dist/core/gitignore-manager.d.ts.map +1 -0
- package/dist/core/gitignore-manager.js +147 -0
- package/dist/core/gitignore-manager.js.map +1 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +13 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lazy-loader.d.ts +68 -0
- package/dist/core/lazy-loader.d.ts.map +1 -0
- package/dist/core/lazy-loader.js +260 -0
- package/dist/core/lazy-loader.js.map +1 -0
- package/dist/core/memory-manager.d.ts +1 -0
- package/dist/core/memory-manager.d.ts.map +1 -0
- package/dist/core/memory-manager.js +2 -0
- package/dist/core/memory-manager.js.map +1 -0
- package/dist/core/startup-optimizer.d.ts +45 -0
- package/dist/core/startup-optimizer.d.ts.map +1 -0
- package/dist/core/startup-optimizer.js +140 -0
- package/dist/core/startup-optimizer.js.map +1 -0
- package/dist/git/automation-engine.d.ts +58 -0
- package/dist/git/automation-engine.d.ts.map +1 -0
- package/dist/git/automation-engine.js +318 -0
- package/dist/git/automation-engine.js.map +1 -0
- package/dist/git/github-manager.d.ts +71 -0
- package/dist/git/github-manager.d.ts.map +1 -0
- package/dist/git/github-manager.js +226 -0
- package/dist/git/github-manager.js.map +1 -0
- package/dist/git/hook-manager.d.ts +43 -0
- package/dist/git/hook-manager.d.ts.map +1 -0
- package/dist/git/hook-manager.js +191 -0
- package/dist/git/hook-manager.js.map +1 -0
- package/dist/git/index.d.ts +4 -0
- package/dist/git/index.d.ts.map +1 -0
- package/dist/git/index.js +5 -0
- package/dist/git/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/feature-validator.d.ts +60 -0
- package/dist/parsers/feature-validator.d.ts.map +1 -0
- package/dist/parsers/feature-validator.js +483 -0
- package/dist/parsers/feature-validator.js.map +1 -0
- package/dist/parsers/index.d.ts +8 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +9 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/parsers/parser-manager.d.ts +103 -0
- package/dist/parsers/parser-manager.d.ts.map +1 -0
- package/dist/parsers/parser-manager.js +321 -0
- package/dist/parsers/parser-manager.js.map +1 -0
- package/dist/parsers/parser.d.ts +23 -0
- package/dist/parsers/parser.d.ts.map +1 -0
- package/dist/parsers/parser.js +6 -0
- package/dist/parsers/parser.js.map +1 -0
- package/dist/parsers/react-parser.d.ts +22 -0
- package/dist/parsers/react-parser.d.ts.map +1 -0
- package/dist/parsers/react-parser.js +307 -0
- package/dist/parsers/react-parser.js.map +1 -0
- package/dist/parsers/svelte-parser.d.ts +33 -0
- package/dist/parsers/svelte-parser.d.ts.map +1 -0
- package/dist/parsers/svelte-parser.js +408 -0
- package/dist/parsers/svelte-parser.js.map +1 -0
- package/dist/parsers/vanilla-parser.d.ts +31 -0
- package/dist/parsers/vanilla-parser.d.ts.map +1 -0
- package/dist/parsers/vanilla-parser.js +590 -0
- package/dist/parsers/vanilla-parser.js.map +1 -0
- package/dist/parsers/vue-parser.d.ts +9 -0
- package/dist/parsers/vue-parser.d.ts.map +1 -0
- package/dist/parsers/vue-parser.js +16 -0
- package/dist/parsers/vue-parser.js.map +1 -0
- package/dist/terminal-header.d.ts +12 -0
- package/dist/terminal-header.js +45 -0
- package/dist/types/index.d.ts +83 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/components.d.ts +133 -0
- package/dist/ui/components.d.ts.map +1 -0
- package/dist/ui/components.js +482 -0
- package/dist/ui/components.js.map +1 -0
- package/dist/ui/help.d.ts +11 -0
- package/dist/ui/help.d.ts.map +1 -0
- package/dist/ui/help.js +161 -0
- package/dist/ui/help.js.map +1 -0
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +5 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/ui/prompts.d.ts +63 -0
- package/dist/ui/prompts.d.ts.map +1 -0
- package/dist/ui/prompts.js +611 -0
- package/dist/ui/prompts.js.map +1 -0
- package/dist/ui/terminal-header.d.ts +13 -0
- package/dist/ui/terminal-header.d.ts.map +1 -0
- package/dist/ui/terminal-header.js +46 -0
- package/dist/ui/terminal-header.js.map +1 -0
- package/package.json +80 -0
- package/src/ai/__tests__/gemini-analyzer.test.ts +181 -0
- package/src/ai/fix-manager.ts +362 -0
- package/src/ai/gemini-analyzer.ts +671 -0
- package/src/ai/index.ts +4 -0
- package/src/ai/jules-implementer.ts +459 -0
- package/src/commands/automation.ts +344 -0
- package/src/commands/check.ts +299 -0
- package/src/commands/config.ts +365 -0
- package/src/commands/fix.ts +234 -0
- package/src/commands/index.ts +6 -0
- package/src/commands/init.ts +142 -0
- package/src/commands/status.ts +0 -0
- package/src/core/api-key-manager.ts +298 -0
- package/src/core/baseguard.ts +742 -0
- package/src/core/baseline-checker.ts +563 -0
- package/src/core/cache-manager.ts +270 -0
- package/src/core/configuration-recovery.ts +676 -0
- package/src/core/configuration.ts +559 -0
- package/src/core/debug-logger.ts +590 -0
- package/src/core/directory-filter.ts +421 -0
- package/src/core/error-handler.ts +517 -0
- package/src/core/file-processor.ts +331 -0
- package/src/core/gitignore-manager.ts +169 -0
- package/src/core/graceful-degradation-manager.ts +596 -0
- package/src/core/index.ts +13 -0
- package/src/core/lazy-loader.ts +307 -0
- package/src/core/logger.ts +0 -0
- package/src/core/memory-manager.ts +294 -0
- package/src/core/startup-optimizer.ts +173 -0
- package/src/core/system-error-handler.ts +746 -0
- package/src/git/automation-engine.ts +361 -0
- package/src/git/github-manager.ts +260 -0
- package/src/git/hook-manager.ts +210 -0
- package/src/git/index.ts +4 -0
- package/src/index.ts +8 -0
- package/src/parsers/feature-validator.ts +559 -0
- package/src/parsers/index.ts +8 -0
- package/src/parsers/parser-manager.ts +419 -0
- package/src/parsers/parser.ts +26 -0
- package/src/parsers/react-parser-optimized.ts +161 -0
- package/src/parsers/react-parser.ts +359 -0
- package/src/parsers/svelte-parser.ts +506 -0
- package/src/parsers/vanilla-parser.ts +682 -0
- package/src/parsers/vue-parser.ts +472 -0
- package/src/types/index.ts +92 -0
- package/src/ui/components.ts +567 -0
- package/src/ui/help.ts +193 -0
- package/src/ui/index.ts +4 -0
- package/src/ui/prompts.ts +688 -0
- package/src/ui/terminal-header.ts +59 -0
- package/test-config-commands.js +56 -0
- package/test-header-simple.js +33 -0
- package/test-terminal-header.js +12 -0
- package/test-ui.js +29 -0
- package/tests/e2e/baseguard.e2e.test.ts +516 -0
- package/tests/e2e/cross-platform.e2e.test.ts +420 -0
- package/tests/e2e/git-integration.e2e.test.ts +487 -0
- package/tests/fixtures/react-project/package.json +14 -0
- package/tests/fixtures/react-project/src/App.css +76 -0
- package/tests/fixtures/react-project/src/App.tsx +77 -0
- package/tests/fixtures/svelte-project/package.json +11 -0
- package/tests/fixtures/svelte-project/src/App.svelte +369 -0
- package/tests/fixtures/vanilla-project/index.html +76 -0
- package/tests/fixtures/vanilla-project/script.js +331 -0
- package/tests/fixtures/vanilla-project/styles.css +359 -0
- package/tests/fixtures/vue-project/package.json +12 -0
- package/tests/fixtures/vue-project/src/App.vue +216 -0
- package/tsconfig.json +36 -0
- package/vitest.config.ts +10 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { UIComponents, Prompts } from '../ui/index.js';
|
|
2
|
+
import { ConfigurationManager, ApiKeyManager, GitignoreManager } from '../core/index.js';
|
|
3
|
+
import { ErrorHandler } from '../core/error-handler.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Manage BaseGuard configuration
|
|
7
|
+
*/
|
|
8
|
+
export async function config(action: string, options?: {
|
|
9
|
+
add?: string;
|
|
10
|
+
remove?: string;
|
|
11
|
+
preset?: string;
|
|
12
|
+
file?: string;
|
|
13
|
+
format?: string;
|
|
14
|
+
}): Promise<void> {
|
|
15
|
+
try {
|
|
16
|
+
switch (action) {
|
|
17
|
+
case 'show':
|
|
18
|
+
await showConfiguration();
|
|
19
|
+
break;
|
|
20
|
+
case 'list':
|
|
21
|
+
await listConfiguration(options?.format);
|
|
22
|
+
break;
|
|
23
|
+
case 'set-keys':
|
|
24
|
+
await setupApiKeys();
|
|
25
|
+
break;
|
|
26
|
+
case 'targets':
|
|
27
|
+
await updateTargets(options);
|
|
28
|
+
break;
|
|
29
|
+
case 'automation':
|
|
30
|
+
await updateAutomation();
|
|
31
|
+
break;
|
|
32
|
+
case 'update':
|
|
33
|
+
await updateConfiguration();
|
|
34
|
+
break;
|
|
35
|
+
case 'validate':
|
|
36
|
+
await validateConfiguration();
|
|
37
|
+
break;
|
|
38
|
+
case 'security':
|
|
39
|
+
await checkSecurity();
|
|
40
|
+
break;
|
|
41
|
+
case 'backup':
|
|
42
|
+
await backupConfiguration();
|
|
43
|
+
break;
|
|
44
|
+
case 'restore':
|
|
45
|
+
await restoreConfiguration(options?.file);
|
|
46
|
+
break;
|
|
47
|
+
default:
|
|
48
|
+
UIComponents.showErrorBox(`Unknown config action: ${action}`);
|
|
49
|
+
showConfigHelp();
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
} catch (error) {
|
|
54
|
+
const apiError = ErrorHandler.handleAPIError(error);
|
|
55
|
+
ErrorHandler.displayError(apiError);
|
|
56
|
+
|
|
57
|
+
// Provide specific help for config command issues
|
|
58
|
+
console.log('\nš” Configuration help:');
|
|
59
|
+
if (action === 'set-keys') {
|
|
60
|
+
UIComponents.showList([
|
|
61
|
+
'Get Gemini API key from https://aistudio.google.com',
|
|
62
|
+
'Get Jules API key from https://jules.google.com',
|
|
63
|
+
'Ensure API keys are valid and have proper permissions',
|
|
64
|
+
'Check your internet connection for key validation'
|
|
65
|
+
]);
|
|
66
|
+
} else if (action === 'targets') {
|
|
67
|
+
UIComponents.showList([
|
|
68
|
+
'Use format "browser version" (e.g., "chrome 100")',
|
|
69
|
+
'Available browsers: chrome, safari, firefox, edge',
|
|
70
|
+
'Use "baseline" for Baseline-only support',
|
|
71
|
+
'Check available presets with "base config targets --help"'
|
|
72
|
+
]);
|
|
73
|
+
} else if (action === 'validate') {
|
|
74
|
+
UIComponents.showList([
|
|
75
|
+
'Check .baseguardrc.json file exists',
|
|
76
|
+
'Verify JSON syntax is correct',
|
|
77
|
+
'Run "base init" to recreate configuration if needed'
|
|
78
|
+
]);
|
|
79
|
+
} else {
|
|
80
|
+
UIComponents.showList([
|
|
81
|
+
'Run "base config show" to see current configuration',
|
|
82
|
+
'Use "base config --help" to see available commands',
|
|
83
|
+
'Check file permissions in the current directory'
|
|
84
|
+
]);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function showConfiguration(): Promise<void> {
|
|
92
|
+
const display = await ConfigurationManager.getConfigurationDisplay();
|
|
93
|
+
|
|
94
|
+
UIComponents.showConfiguration(display.config);
|
|
95
|
+
|
|
96
|
+
// Show security status
|
|
97
|
+
if (!display.security.configIgnored) {
|
|
98
|
+
UIComponents.showWarningBox('Configuration file is not in .gitignore - API keys may be exposed!');
|
|
99
|
+
|
|
100
|
+
if (display.security.recommendations.length > 0) {
|
|
101
|
+
console.log('\nSecurity recommendations:');
|
|
102
|
+
UIComponents.showList(display.security.recommendations);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Show validation errors if any
|
|
107
|
+
if (!display.validation.valid) {
|
|
108
|
+
UIComponents.showErrorBox('Configuration validation failed');
|
|
109
|
+
UIComponents.showList(display.validation.errors);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function listConfiguration(format?: string): Promise<void> {
|
|
114
|
+
const display = await ConfigurationManager.getConfigurationDisplay();
|
|
115
|
+
|
|
116
|
+
if (format === 'json') {
|
|
117
|
+
// Output as JSON for programmatic use
|
|
118
|
+
const output = {
|
|
119
|
+
configuration: display.config,
|
|
120
|
+
security: display.security,
|
|
121
|
+
validation: display.validation,
|
|
122
|
+
status: {
|
|
123
|
+
configured: display.config.apiKeys.jules !== null || display.config.apiKeys.gemini !== null,
|
|
124
|
+
automationEnabled: display.config.automation.enabled,
|
|
125
|
+
targetCount: display.config.targets.length
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
console.log(JSON.stringify(output, null, 2));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Default table format
|
|
133
|
+
UIComponents.showSectionHeader('BaseGuard Configuration Summary');
|
|
134
|
+
|
|
135
|
+
// Configuration overview
|
|
136
|
+
console.log('š Configuration:');
|
|
137
|
+
console.log(` Version: ${display.config.version}`);
|
|
138
|
+
console.log(` Targets: ${display.config.targets.length} browser(s)`);
|
|
139
|
+
console.log(` API Keys: ${display.config.apiKeys.jules ? 'ā' : 'ā'} Jules, ${display.config.apiKeys.gemini ? 'ā' : 'ā'} Gemini`);
|
|
140
|
+
console.log(` Automation: ${display.config.automation.enabled ? 'ā enabled' : 'ā disabled'}`);
|
|
141
|
+
|
|
142
|
+
// Browser targets
|
|
143
|
+
console.log('\nšÆ Browser Targets:');
|
|
144
|
+
display.config.targets.forEach(target => {
|
|
145
|
+
console.log(` ⢠${target.browser} ${target.minVersion}`);
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Automation settings
|
|
149
|
+
console.log('\nš¤ Automation Settings:');
|
|
150
|
+
console.log(` Enabled: ${display.config.automation.enabled ? 'ā' : 'ā'}`);
|
|
151
|
+
console.log(` Trigger: ${display.config.automation.trigger}`);
|
|
152
|
+
console.log(` Auto-analyze: ${display.config.automation.autoAnalyze ? 'ā' : 'ā'}`);
|
|
153
|
+
console.log(` Auto-fix: ${display.config.automation.autoFix ? 'ā' : 'ā'}`);
|
|
154
|
+
console.log(` Block commits: ${display.config.automation.blockCommit ? 'ā' : 'ā'}`);
|
|
155
|
+
|
|
156
|
+
// Security status
|
|
157
|
+
console.log('\nš Security Status:');
|
|
158
|
+
console.log(` .gitignore exists: ${display.security.gitignoreExists ? 'ā' : 'ā'}`);
|
|
159
|
+
console.log(` Config file ignored: ${display.security.configIgnored ? 'ā' : 'ā'}`);
|
|
160
|
+
|
|
161
|
+
// Validation status
|
|
162
|
+
console.log('\nā
Validation Status:');
|
|
163
|
+
console.log(` Configuration valid: ${display.validation.valid ? 'ā' : 'ā'}`);
|
|
164
|
+
|
|
165
|
+
// Show warnings/errors
|
|
166
|
+
if (!display.security.configIgnored) {
|
|
167
|
+
UIComponents.showWarningBox('Configuration file is not in .gitignore - API keys may be exposed!');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (!display.validation.valid) {
|
|
171
|
+
UIComponents.showErrorBox('Configuration validation failed');
|
|
172
|
+
UIComponents.showList(display.validation.errors);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (display.security.recommendations.length > 0) {
|
|
176
|
+
console.log('\nš” Recommendations:');
|
|
177
|
+
UIComponents.showList(display.security.recommendations);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function setupApiKeys(): Promise<void> {
|
|
182
|
+
const apiKeys = await Prompts.setupApiKeys();
|
|
183
|
+
|
|
184
|
+
if (apiKeys.julesApiKey || apiKeys.geminiApiKey) {
|
|
185
|
+
await ApiKeyManager.storeApiKeys({
|
|
186
|
+
jules: apiKeys.julesApiKey,
|
|
187
|
+
gemini: apiKeys.geminiApiKey
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
UIComponents.showSuccessBox('API keys updated successfully');
|
|
191
|
+
|
|
192
|
+
// Show security reminder
|
|
193
|
+
const security = await GitignoreManager.isConfigSecure();
|
|
194
|
+
if (!security.configIgnored) {
|
|
195
|
+
UIComponents.showWarningBox('Remember to add .baseguardrc.json to .gitignore to protect your API keys');
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
UIComponents.showInfoBox('No API keys were configured');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function updateTargets(options?: { add?: string; remove?: string; preset?: string }): Promise<void> {
|
|
203
|
+
if (options?.add) {
|
|
204
|
+
// Add a specific browser target
|
|
205
|
+
const target = ConfigurationManager.parseBrowserTarget(options.add);
|
|
206
|
+
if (!target) {
|
|
207
|
+
UIComponents.showErrorBox(`Invalid browser target format: ${options.add}`);
|
|
208
|
+
UIComponents.showInfoBox('Format: "browser version" (e.g., "chrome 100", "safari baseline")');
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
await ConfigurationManager.addBrowserTarget(target);
|
|
213
|
+
UIComponents.showSuccessBox(`Added browser target: ${target.browser} ${target.minVersion}`);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (options?.remove) {
|
|
218
|
+
// Remove a specific browser target
|
|
219
|
+
await ConfigurationManager.removeBrowserTarget(options.remove);
|
|
220
|
+
UIComponents.showSuccessBox(`Removed browser target: ${options.remove}`);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (options?.preset) {
|
|
225
|
+
// Set preset targets
|
|
226
|
+
const presetName = options.preset as any;
|
|
227
|
+
const availablePresets = ConfigurationManager.getAvailablePresets();
|
|
228
|
+
|
|
229
|
+
if (!availablePresets.includes(presetName)) {
|
|
230
|
+
UIComponents.showErrorBox(`Invalid preset: ${options.preset}`);
|
|
231
|
+
UIComponents.showInfoBox(`Available presets: ${availablePresets.join(', ')}`);
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
await ConfigurationManager.updateWithPreset(presetName);
|
|
236
|
+
UIComponents.showSuccessBox(`Updated to ${presetName} preset`);
|
|
237
|
+
UIComponents.showInfoBox(ConfigurationManager.getPresetDescription(presetName));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// Interactive target configuration
|
|
242
|
+
const targets = await Prompts.promptCustomTargets();
|
|
243
|
+
await ConfigurationManager.updateWithCustomTargets(targets);
|
|
244
|
+
UIComponents.showSuccessBox('Browser targets updated successfully');
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
async function updateAutomation(): Promise<void> {
|
|
248
|
+
const automation = await Prompts.promptAutomationSettings();
|
|
249
|
+
const config = await ConfigurationManager.load();
|
|
250
|
+
config.automation = { ...config.automation, ...automation };
|
|
251
|
+
await ConfigurationManager.save(config);
|
|
252
|
+
UIComponents.showSuccessBox('Automation settings updated successfully');
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async function updateConfiguration(): Promise<void> {
|
|
256
|
+
const currentConfig = await ConfigurationManager.load();
|
|
257
|
+
const updates = await Prompts.promptConfigUpdate(currentConfig);
|
|
258
|
+
|
|
259
|
+
if (Object.keys(updates).length === 0) {
|
|
260
|
+
UIComponents.showInfoBox('No changes made');
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
let config = currentConfig;
|
|
265
|
+
|
|
266
|
+
// Apply updates
|
|
267
|
+
for (const [key, value] of Object.entries(updates)) {
|
|
268
|
+
switch (key) {
|
|
269
|
+
case 'targets':
|
|
270
|
+
await ConfigurationManager.updateWithCustomTargets(value as any);
|
|
271
|
+
config = await ConfigurationManager.load(); // Reload after update
|
|
272
|
+
break;
|
|
273
|
+
case 'apiKeys':
|
|
274
|
+
const apiKeys = value as any;
|
|
275
|
+
if (apiKeys.julesApiKey) config.apiKeys.jules = apiKeys.julesApiKey;
|
|
276
|
+
if (apiKeys.geminiApiKey) config.apiKeys.gemini = apiKeys.geminiApiKey;
|
|
277
|
+
break;
|
|
278
|
+
case 'automation':
|
|
279
|
+
config.automation = { ...config.automation, ...(value as any) };
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
await ConfigurationManager.save(config);
|
|
285
|
+
UIComponents.showSuccessBox('Configuration updated successfully');
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
async function validateConfiguration(): Promise<void> {
|
|
289
|
+
const display = await ConfigurationManager.getConfigurationDisplay();
|
|
290
|
+
|
|
291
|
+
if (display.validation.valid) {
|
|
292
|
+
UIComponents.showSuccessBox('Configuration is valid');
|
|
293
|
+
} else {
|
|
294
|
+
UIComponents.showErrorBox('Configuration validation failed');
|
|
295
|
+
UIComponents.showList(display.validation.errors);
|
|
296
|
+
process.exit(1);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
async function checkSecurity(): Promise<void> {
|
|
301
|
+
const security = await GitignoreManager.isConfigSecure();
|
|
302
|
+
|
|
303
|
+
UIComponents.showSectionHeader('Security Status');
|
|
304
|
+
|
|
305
|
+
console.log(`ā .gitignore exists: ${security.gitignoreExists ? 'Yes' : 'No'}`);
|
|
306
|
+
console.log(`ā Config file ignored: ${security.configIgnored ? 'Yes' : 'No'}`);
|
|
307
|
+
|
|
308
|
+
if (security.recommendations.length > 0) {
|
|
309
|
+
console.log('\nRecommendations:');
|
|
310
|
+
UIComponents.showList(security.recommendations);
|
|
311
|
+
} else {
|
|
312
|
+
UIComponents.showSuccessBox('Configuration is secure');
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function backupConfiguration(): Promise<void> {
|
|
317
|
+
try {
|
|
318
|
+
const backupFile = await ConfigurationManager.backupConfiguration();
|
|
319
|
+
UIComponents.showSuccessBox(`Configuration backed up to: ${backupFile}`);
|
|
320
|
+
} catch (error) {
|
|
321
|
+
UIComponents.showErrorBox(`Backup failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
322
|
+
process.exit(1);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
async function restoreConfiguration(backupFile?: string): Promise<void> {
|
|
327
|
+
if (!backupFile) {
|
|
328
|
+
UIComponents.showErrorBox('Backup file path is required');
|
|
329
|
+
console.log('Usage: base config restore --file <backup-file>');
|
|
330
|
+
process.exit(1);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
try {
|
|
334
|
+
await ConfigurationManager.restoreConfiguration(backupFile);
|
|
335
|
+
UIComponents.showSuccessBox('Configuration restored successfully');
|
|
336
|
+
} catch (error) {
|
|
337
|
+
UIComponents.showErrorBox(`Restore failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
338
|
+
process.exit(1);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function showConfigHelp(): void {
|
|
343
|
+
UIComponents.showSectionHeader('Configuration Commands');
|
|
344
|
+
UIComponents.showList([
|
|
345
|
+
'base config show - Display current configuration',
|
|
346
|
+
'base config list - List configuration summary',
|
|
347
|
+
'base config list --format json - List configuration as JSON',
|
|
348
|
+
'base config set-keys - Set up API keys for AI services',
|
|
349
|
+
'base config targets - Configure browser targets',
|
|
350
|
+
'base config targets --add "chrome 100" - Add browser target',
|
|
351
|
+
'base config targets --remove chrome - Remove browser target',
|
|
352
|
+
'base config targets --preset baseline-widely - Set preset targets',
|
|
353
|
+
'base config automation - Configure git automation',
|
|
354
|
+
'base config update - Interactive configuration update',
|
|
355
|
+
'base config validate - Validate configuration file',
|
|
356
|
+
'base config security - Check configuration security',
|
|
357
|
+
'base config backup - Create configuration backup',
|
|
358
|
+
'base config restore --file <backup> - Restore from backup',
|
|
359
|
+
'',
|
|
360
|
+
'Shorthand commands:',
|
|
361
|
+
'base add "chrome 100" - Add browser target',
|
|
362
|
+
'base remove chrome - Remove browser target',
|
|
363
|
+
'base list - List configuration summary'
|
|
364
|
+
]);
|
|
365
|
+
}
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { UIComponents } from '../ui/index.js';
|
|
3
|
+
import { BaseGuard } from '../core/index.js';
|
|
4
|
+
import { ConfigurationManager } from '../core/configuration.js';
|
|
5
|
+
import { ErrorHandler } from '../core/error-handler.js';
|
|
6
|
+
import { JulesImplementer } from '../ai/jules-implementer.js';
|
|
7
|
+
import { GeminiAnalyzer } from '../ai/gemini-analyzer.js';
|
|
8
|
+
import { glob } from 'glob';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Fix violations with AI analysis and implementation
|
|
12
|
+
*/
|
|
13
|
+
export async function fix(options: {
|
|
14
|
+
auto?: boolean;
|
|
15
|
+
analyzeOnly?: boolean;
|
|
16
|
+
files?: string;
|
|
17
|
+
}): Promise<void> {
|
|
18
|
+
try {
|
|
19
|
+
console.log(chalk.cyan('š§ BaseGuard AI Fix\n'));
|
|
20
|
+
|
|
21
|
+
// Load configuration
|
|
22
|
+
const config = await ConfigurationManager.load();
|
|
23
|
+
|
|
24
|
+
// Check API keys
|
|
25
|
+
if (!config.apiKeys.jules) {
|
|
26
|
+
UIComponents.showErrorBox('Jules API key not configured. Run "base init" to set up API keys.');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!config.apiKeys.gemini) {
|
|
31
|
+
UIComponents.showErrorBox('Gemini API key not configured. Run "base init" to set up API keys.');
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Initialize services
|
|
36
|
+
const baseGuard = new BaseGuard(config);
|
|
37
|
+
const julesImplementer = new JulesImplementer(config.apiKeys.jules);
|
|
38
|
+
const geminiAnalyzer = new GeminiAnalyzer(config.apiKeys.gemini);
|
|
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
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Step 1: Check for violations
|
|
64
|
+
console.log(chalk.cyan('š Scanning for compatibility violations...'));
|
|
65
|
+
|
|
66
|
+
// Get files to fix
|
|
67
|
+
const filePattern = options.files || '**/*.{js,jsx,ts,tsx,vue,svelte,css,html}';
|
|
68
|
+
const files = await glob(filePattern, {
|
|
69
|
+
ignore: [
|
|
70
|
+
'node_modules/**',
|
|
71
|
+
'dist/**',
|
|
72
|
+
'build/**',
|
|
73
|
+
'.git/**',
|
|
74
|
+
'**/*.min.js',
|
|
75
|
+
'**/*.min.css'
|
|
76
|
+
]
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const violations = await baseGuard.checkViolations(files);
|
|
80
|
+
|
|
81
|
+
if (violations.length === 0) {
|
|
82
|
+
UIComponents.showSuccessBox('No compatibility violations found!');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
console.log(chalk.yellow(`\nā ļø Found ${violations.length} compatibility violations\n`));
|
|
87
|
+
UIComponents.showViolations(violations);
|
|
88
|
+
|
|
89
|
+
// Step 2: Analyze violations with Gemini
|
|
90
|
+
console.log(chalk.cyan('\nš§ Analyzing violations with AI...'));
|
|
91
|
+
const analyses = await geminiAnalyzer.analyzeViolations(violations);
|
|
92
|
+
|
|
93
|
+
// If analyze-only mode, show analysis and exit
|
|
94
|
+
if (options.analyzeOnly) {
|
|
95
|
+
console.log(chalk.cyan('\nš Analysis Results:\n'));
|
|
96
|
+
analyses.forEach((analysis, index) => {
|
|
97
|
+
console.log(chalk.yellow(`${index + 1}. ${analysis.violation.feature} in ${analysis.violation.file}`));
|
|
98
|
+
console.log(` Impact: ${analysis.userImpact}`);
|
|
99
|
+
console.log(` Strategy: ${analysis.fixStrategy}`);
|
|
100
|
+
console.log(` Confidence: ${Math.round(analysis.confidence * 100)}%\n`);
|
|
101
|
+
});
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
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);
|
|
108
|
+
|
|
109
|
+
// Show results
|
|
110
|
+
console.log(chalk.cyan('\nš Fix Results:\n'));
|
|
111
|
+
|
|
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();
|
|
118
|
+
}
|
|
119
|
+
|
|
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();
|
|
126
|
+
}
|
|
127
|
+
|
|
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();
|
|
134
|
+
}
|
|
135
|
+
|
|
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
|
+
]);
|
|
161
|
+
|
|
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
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
UIComponents.showSuccessBox('Fix process completed!');
|
|
188
|
+
|
|
189
|
+
} catch (error) {
|
|
190
|
+
const apiError = ErrorHandler.handleAPIError(error);
|
|
191
|
+
ErrorHandler.displayError(apiError);
|
|
192
|
+
|
|
193
|
+
// Provide specific help for fix command issues
|
|
194
|
+
console.log('\nš” Troubleshooting:');
|
|
195
|
+
if (apiError.type === 'authentication') {
|
|
196
|
+
UIComponents.showList([
|
|
197
|
+
'Check your API keys with "base config show"',
|
|
198
|
+
'Update API keys with "base config set-keys"',
|
|
199
|
+
'Verify API keys are valid and not expired',
|
|
200
|
+
'Ensure you have proper permissions for Jules and Gemini'
|
|
201
|
+
]);
|
|
202
|
+
} else if (apiError.type === 'configuration') {
|
|
203
|
+
UIComponents.showList([
|
|
204
|
+
'Run "base init" to set up BaseGuard configuration',
|
|
205
|
+
'Configure API keys with "base config set-keys"',
|
|
206
|
+
'Check GitHub integration for Jules fixing'
|
|
207
|
+
]);
|
|
208
|
+
} else if (apiError.type === 'network') {
|
|
209
|
+
UIComponents.showList([
|
|
210
|
+
'Check your internet connection',
|
|
211
|
+
'Verify firewall allows access to AI services',
|
|
212
|
+
'Try again when network connection is stable'
|
|
213
|
+
]);
|
|
214
|
+
} else {
|
|
215
|
+
UIComponents.showList([
|
|
216
|
+
'Try running "base check" for basic violation detection',
|
|
217
|
+
'Verify your API keys are configured correctly',
|
|
218
|
+
'Check the documentation for troubleshooting steps'
|
|
219
|
+
]);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Show fallback suggestions
|
|
223
|
+
if (ErrorHandler.shouldUseFallbackMode(apiError)) {
|
|
224
|
+
console.log('\nš Alternative options:');
|
|
225
|
+
UIComponents.showList([
|
|
226
|
+
'Run "base check" for offline compatibility checking',
|
|
227
|
+
'Review violations manually using browser compatibility tables',
|
|
228
|
+
'Try AI features again when services are available'
|
|
229
|
+
]);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
}
|