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,596 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { promises as fs } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import type { Violation, Analysis, Fix } from '../types/index.js';
|
|
5
|
+
import { ErrorType } from './error-handler.js';
|
|
6
|
+
import { UIComponents } from '../ui/components.js';
|
|
7
|
+
|
|
8
|
+
export interface DegradationMode {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
capabilities: {
|
|
12
|
+
baselineChecking: boolean;
|
|
13
|
+
aiAnalysis: boolean;
|
|
14
|
+
autoFix: boolean;
|
|
15
|
+
caching: boolean;
|
|
16
|
+
offlineMode: boolean;
|
|
17
|
+
};
|
|
18
|
+
limitations: string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface FallbackOptions {
|
|
22
|
+
useCache: boolean;
|
|
23
|
+
skipAI: boolean;
|
|
24
|
+
basicAnalysis: boolean;
|
|
25
|
+
offlineMode: boolean;
|
|
26
|
+
continueOnError: boolean;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Manages graceful degradation when services are unavailable
|
|
31
|
+
*/
|
|
32
|
+
export class GracefulDegradationManager {
|
|
33
|
+
private static currentMode: DegradationMode | null = null;
|
|
34
|
+
private static fallbackOptions: FallbackOptions = {
|
|
35
|
+
useCache: true,
|
|
36
|
+
skipAI: false,
|
|
37
|
+
basicAnalysis: true,
|
|
38
|
+
offlineMode: false,
|
|
39
|
+
continueOnError: true
|
|
40
|
+
};
|
|
41
|
+
private static serviceStatus = new Map<string, { available: boolean; lastCheck: number; error?: string }>();
|
|
42
|
+
private static cacheDir = path.join(process.cwd(), '.baseguard', 'cache');
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Available degradation modes
|
|
46
|
+
*/
|
|
47
|
+
private static readonly DEGRADATION_MODES: Record<string, DegradationMode> = {
|
|
48
|
+
full: {
|
|
49
|
+
name: 'Full Functionality',
|
|
50
|
+
description: 'All features available including AI analysis and fixing',
|
|
51
|
+
capabilities: {
|
|
52
|
+
baselineChecking: true,
|
|
53
|
+
aiAnalysis: true,
|
|
54
|
+
autoFix: true,
|
|
55
|
+
caching: true,
|
|
56
|
+
offlineMode: false
|
|
57
|
+
},
|
|
58
|
+
limitations: []
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
aiLimited: {
|
|
62
|
+
name: 'AI Limited',
|
|
63
|
+
description: 'Basic compatibility checking with limited AI features',
|
|
64
|
+
capabilities: {
|
|
65
|
+
baselineChecking: true,
|
|
66
|
+
aiAnalysis: false,
|
|
67
|
+
autoFix: false,
|
|
68
|
+
caching: true,
|
|
69
|
+
offlineMode: false
|
|
70
|
+
},
|
|
71
|
+
limitations: [
|
|
72
|
+
'AI analysis unavailable',
|
|
73
|
+
'Automatic fixing disabled',
|
|
74
|
+
'Using cached analysis when available'
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
offline: {
|
|
79
|
+
name: 'Offline Mode',
|
|
80
|
+
description: 'Baseline checking only using local data',
|
|
81
|
+
capabilities: {
|
|
82
|
+
baselineChecking: true,
|
|
83
|
+
aiAnalysis: false,
|
|
84
|
+
autoFix: false,
|
|
85
|
+
caching: true,
|
|
86
|
+
offlineMode: true
|
|
87
|
+
},
|
|
88
|
+
limitations: [
|
|
89
|
+
'No network-dependent features',
|
|
90
|
+
'AI services unavailable',
|
|
91
|
+
'Using local web-features data only',
|
|
92
|
+
'Cached results when available'
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
|
|
96
|
+
minimal: {
|
|
97
|
+
name: 'Minimal Mode',
|
|
98
|
+
description: 'Basic error detection with minimal features',
|
|
99
|
+
capabilities: {
|
|
100
|
+
baselineChecking: true,
|
|
101
|
+
aiAnalysis: false,
|
|
102
|
+
autoFix: false,
|
|
103
|
+
caching: false,
|
|
104
|
+
offlineMode: true
|
|
105
|
+
},
|
|
106
|
+
limitations: [
|
|
107
|
+
'No AI features',
|
|
108
|
+
'No caching',
|
|
109
|
+
'Basic compatibility checking only',
|
|
110
|
+
'Manual review required for all issues'
|
|
111
|
+
]
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Initialize degradation manager
|
|
117
|
+
*/
|
|
118
|
+
static async initialize(): Promise<void> {
|
|
119
|
+
// Ensure cache directory exists
|
|
120
|
+
await fs.mkdir(this.cacheDir, { recursive: true });
|
|
121
|
+
|
|
122
|
+
// Set initial mode based on environment
|
|
123
|
+
if (process.env.BASEGUARD_OFFLINE === 'true') {
|
|
124
|
+
await this.setDegradationMode('offline');
|
|
125
|
+
} else {
|
|
126
|
+
await this.setDegradationMode('full');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Check service availability
|
|
130
|
+
await this.checkServiceAvailability();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Set degradation mode
|
|
135
|
+
*/
|
|
136
|
+
static async setDegradationMode(modeName: string): Promise<void> {
|
|
137
|
+
const mode = this.DEGRADATION_MODES[modeName];
|
|
138
|
+
if (!mode) {
|
|
139
|
+
throw new Error(`Unknown degradation mode: ${modeName}`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
this.currentMode = mode;
|
|
143
|
+
|
|
144
|
+
// Update environment variables based on mode
|
|
145
|
+
if (mode.capabilities.offlineMode) {
|
|
146
|
+
process.env.BASEGUARD_OFFLINE = 'true';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Update fallback options
|
|
150
|
+
this.fallbackOptions = {
|
|
151
|
+
useCache: mode.capabilities.caching,
|
|
152
|
+
skipAI: !mode.capabilities.aiAnalysis,
|
|
153
|
+
basicAnalysis: true,
|
|
154
|
+
offlineMode: mode.capabilities.offlineMode,
|
|
155
|
+
continueOnError: true
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
console.log(chalk.cyan(`š Switched to ${mode.name}: ${mode.description}`));
|
|
159
|
+
|
|
160
|
+
if (mode.limitations.length > 0) {
|
|
161
|
+
console.log(chalk.yellow('ā ļø Limitations in this mode:'));
|
|
162
|
+
mode.limitations.forEach(limitation => {
|
|
163
|
+
console.log(chalk.yellow(` ⢠${limitation}`));
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Check availability of external services
|
|
170
|
+
*/
|
|
171
|
+
static async checkServiceAvailability(): Promise<void> {
|
|
172
|
+
const services = ['gemini', 'jules', 'network'];
|
|
173
|
+
|
|
174
|
+
for (const service of services) {
|
|
175
|
+
try {
|
|
176
|
+
const available = await this.testServiceAvailability(service);
|
|
177
|
+
this.serviceStatus.set(service, {
|
|
178
|
+
available,
|
|
179
|
+
lastCheck: Date.now(),
|
|
180
|
+
error: available ? undefined : 'Service unavailable'
|
|
181
|
+
});
|
|
182
|
+
} catch (error) {
|
|
183
|
+
this.serviceStatus.set(service, {
|
|
184
|
+
available: false,
|
|
185
|
+
lastCheck: Date.now(),
|
|
186
|
+
error: error instanceof Error ? error.message : 'Unknown error'
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Auto-adjust degradation mode based on service availability
|
|
192
|
+
await this.autoAdjustDegradationMode();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Test individual service availability
|
|
197
|
+
*/
|
|
198
|
+
private static async testServiceAvailability(service: string): Promise<boolean> {
|
|
199
|
+
switch (service) {
|
|
200
|
+
case 'network':
|
|
201
|
+
try {
|
|
202
|
+
// Simple network connectivity test
|
|
203
|
+
const response = await fetch('https://www.google.com', {
|
|
204
|
+
method: 'HEAD',
|
|
205
|
+
signal: AbortSignal.timeout(5000)
|
|
206
|
+
});
|
|
207
|
+
return response.ok;
|
|
208
|
+
} catch (error) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
case 'gemini':
|
|
213
|
+
// This would be implemented with actual Gemini API test
|
|
214
|
+
return this.serviceStatus.get('network')?.available ?? false;
|
|
215
|
+
|
|
216
|
+
case 'jules':
|
|
217
|
+
// This would be implemented with actual Jules API test
|
|
218
|
+
return this.serviceStatus.get('network')?.available ?? false;
|
|
219
|
+
|
|
220
|
+
default:
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Auto-adjust degradation mode based on service availability
|
|
227
|
+
*/
|
|
228
|
+
private static async autoAdjustDegradationMode(): Promise<void> {
|
|
229
|
+
const networkAvailable = this.serviceStatus.get('network')?.available ?? false;
|
|
230
|
+
const geminiAvailable = this.serviceStatus.get('gemini')?.available ?? false;
|
|
231
|
+
const julesAvailable = this.serviceStatus.get('jules')?.available ?? false;
|
|
232
|
+
|
|
233
|
+
if (!networkAvailable) {
|
|
234
|
+
await this.setDegradationMode('offline');
|
|
235
|
+
} else if (!geminiAvailable && !julesAvailable) {
|
|
236
|
+
await this.setDegradationMode('aiLimited');
|
|
237
|
+
} else if (!geminiAvailable || !julesAvailable) {
|
|
238
|
+
await this.setDegradationMode('aiLimited');
|
|
239
|
+
} else if (this.currentMode?.name !== 'Full Functionality') {
|
|
240
|
+
await this.setDegradationMode('full');
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Handle service failure and adjust accordingly
|
|
246
|
+
*/
|
|
247
|
+
static async handleServiceFailure(service: string, errorType: ErrorType): Promise<void> {
|
|
248
|
+
console.log(chalk.yellow(`ā ļø Service failure detected: ${service} (${errorType})`));
|
|
249
|
+
|
|
250
|
+
// Update service status
|
|
251
|
+
this.serviceStatus.set(service, {
|
|
252
|
+
available: false,
|
|
253
|
+
lastCheck: Date.now(),
|
|
254
|
+
error: `Service failed: ${errorType}`
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// Provide specific guidance based on error type
|
|
258
|
+
switch (errorType) {
|
|
259
|
+
case ErrorType.NETWORK:
|
|
260
|
+
console.log(chalk.cyan('š Switching to offline mode due to network issues'));
|
|
261
|
+
await this.setDegradationMode('offline');
|
|
262
|
+
break;
|
|
263
|
+
|
|
264
|
+
case ErrorType.AUTHENTICATION:
|
|
265
|
+
console.log(chalk.yellow('š API authentication failed - disabling AI features'));
|
|
266
|
+
await this.setDegradationMode('aiLimited');
|
|
267
|
+
UIComponents.showWarningBox('Run "base config" to update your API keys');
|
|
268
|
+
break;
|
|
269
|
+
|
|
270
|
+
case ErrorType.RATE_LIMIT:
|
|
271
|
+
console.log(chalk.yellow('š¦ Rate limit reached - using cached responses'));
|
|
272
|
+
this.fallbackOptions.useCache = true;
|
|
273
|
+
this.fallbackOptions.skipAI = true;
|
|
274
|
+
break;
|
|
275
|
+
|
|
276
|
+
case ErrorType.QUOTA_EXCEEDED:
|
|
277
|
+
console.log(chalk.yellow('š API quota exceeded - switching to basic mode'));
|
|
278
|
+
await this.setDegradationMode('aiLimited');
|
|
279
|
+
break;
|
|
280
|
+
|
|
281
|
+
default:
|
|
282
|
+
console.log(chalk.yellow('š Service error - enabling fallback mode'));
|
|
283
|
+
await this.setDegradationMode('aiLimited');
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Show available alternatives
|
|
288
|
+
this.showFallbackOptions();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Show available fallback options to user
|
|
293
|
+
*/
|
|
294
|
+
private static showFallbackOptions(): void {
|
|
295
|
+
const mode = this.currentMode;
|
|
296
|
+
if (!mode) return;
|
|
297
|
+
|
|
298
|
+
console.log(chalk.cyan('\nš Available features in current mode:'));
|
|
299
|
+
|
|
300
|
+
if (mode.capabilities.baselineChecking) {
|
|
301
|
+
console.log(chalk.green(' ā
Baseline compatibility checking'));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
if (mode.capabilities.caching) {
|
|
305
|
+
console.log(chalk.green(' ā
Cached analysis results'));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (!mode.capabilities.aiAnalysis) {
|
|
309
|
+
console.log(chalk.yellow(' ā ļø AI analysis disabled - manual review required'));
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (!mode.capabilities.autoFix) {
|
|
313
|
+
console.log(chalk.yellow(' ā ļø Auto-fixing disabled - manual fixes required'));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
console.log(chalk.cyan('\nš” Suggestions:'));
|
|
317
|
+
console.log(chalk.cyan(' ⢠Review violations manually using browser compatibility tables'));
|
|
318
|
+
console.log(chalk.cyan(' ⢠Use progressive enhancement techniques'));
|
|
319
|
+
console.log(chalk.cyan(' ⢠Test across your target browsers'));
|
|
320
|
+
|
|
321
|
+
if (!mode.capabilities.offlineMode) {
|
|
322
|
+
console.log(chalk.cyan(' ⢠Try again when network/services are restored'));
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Create fallback analysis when AI is unavailable
|
|
328
|
+
*/
|
|
329
|
+
static createFallbackAnalysis(violation: Violation, reason: string = 'AI services unavailable'): Analysis {
|
|
330
|
+
return {
|
|
331
|
+
violation,
|
|
332
|
+
userImpact: `Users on ${violation.browser} ${violation.required} may experience compatibility issues with ${violation.feature}`,
|
|
333
|
+
marketShare: this.estimateMarketShare(violation.browser, violation.required),
|
|
334
|
+
fixStrategy: this.getDefaultFixStrategy(violation.feature),
|
|
335
|
+
bestPractices: [
|
|
336
|
+
'Use @supports for CSS feature detection',
|
|
337
|
+
'Implement feature detection for JavaScript APIs',
|
|
338
|
+
'Provide fallback implementations',
|
|
339
|
+
'Test across target browsers'
|
|
340
|
+
],
|
|
341
|
+
sources: [],
|
|
342
|
+
plainEnglish: `${reason}. This feature (${violation.feature}) may not be supported in ${violation.browser} ${violation.required}. Consider using progressive enhancement techniques and providing fallbacks for better compatibility.`,
|
|
343
|
+
confidence: 0.3
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Estimate market share for fallback analysis
|
|
349
|
+
*/
|
|
350
|
+
private static estimateMarketShare(browser: string, version: string): number {
|
|
351
|
+
const estimates: Record<string, number> = {
|
|
352
|
+
'chrome': 0.65,
|
|
353
|
+
'firefox': 0.08,
|
|
354
|
+
'safari': 0.18,
|
|
355
|
+
'edge': 0.05,
|
|
356
|
+
'opera': 0.02,
|
|
357
|
+
'samsung': 0.02
|
|
358
|
+
};
|
|
359
|
+
|
|
360
|
+
const baseShare = estimates[browser.toLowerCase()] || 0.05;
|
|
361
|
+
|
|
362
|
+
// Reduce estimate for older versions
|
|
363
|
+
if (version !== 'baseline' && version !== 'baseline-newly') {
|
|
364
|
+
const versionNum = parseInt(version, 10);
|
|
365
|
+
if (!isNaN(versionNum)) {
|
|
366
|
+
const currentYear = new Date().getFullYear();
|
|
367
|
+
const estimatedYear = 2008 + (versionNum / 10);
|
|
368
|
+
const yearsDiff = currentYear - estimatedYear;
|
|
369
|
+
|
|
370
|
+
if (yearsDiff > 2) {
|
|
371
|
+
return baseShare * 0.1;
|
|
372
|
+
} else if (yearsDiff > 1) {
|
|
373
|
+
return baseShare * 0.3;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
return baseShare;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Get default fix strategy based on feature type
|
|
383
|
+
*/
|
|
384
|
+
private static getDefaultFixStrategy(feature: string): string {
|
|
385
|
+
const lowerFeature = feature.toLowerCase();
|
|
386
|
+
|
|
387
|
+
if (lowerFeature.includes('css') || lowerFeature.includes('grid') || lowerFeature.includes('flex')) {
|
|
388
|
+
return 'progressive enhancement with @supports';
|
|
389
|
+
} else if (lowerFeature.includes('api') || lowerFeature.includes('js')) {
|
|
390
|
+
return 'feature detection with polyfills';
|
|
391
|
+
} else if (lowerFeature.includes('element') || lowerFeature.includes('html')) {
|
|
392
|
+
return 'graceful degradation';
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return 'progressive enhancement';
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Try to load cached analysis
|
|
400
|
+
*/
|
|
401
|
+
static async loadCachedAnalysis(violation: Violation): Promise<Analysis | null> {
|
|
402
|
+
if (!this.fallbackOptions.useCache) {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
try {
|
|
407
|
+
const cacheKey = this.generateCacheKey(violation);
|
|
408
|
+
const cacheFile = path.join(this.cacheDir, `analysis-${cacheKey}.json`);
|
|
409
|
+
|
|
410
|
+
const content = await fs.readFile(cacheFile, 'utf-8');
|
|
411
|
+
const cached = JSON.parse(content);
|
|
412
|
+
|
|
413
|
+
// Check if cache is still valid (24 hours)
|
|
414
|
+
const cacheAge = Date.now() - cached.timestamp;
|
|
415
|
+
if (cacheAge < 24 * 60 * 60 * 1000) {
|
|
416
|
+
console.log(chalk.dim(`š¦ Using cached analysis for ${violation.feature}`));
|
|
417
|
+
return cached.analysis;
|
|
418
|
+
}
|
|
419
|
+
} catch (error) {
|
|
420
|
+
// Cache miss or error - return null
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* Save analysis to cache
|
|
428
|
+
*/
|
|
429
|
+
static async saveAnalysisToCache(analysis: Analysis): Promise<void> {
|
|
430
|
+
if (!this.fallbackOptions.useCache) {
|
|
431
|
+
return;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
try {
|
|
435
|
+
const cacheKey = this.generateCacheKey(analysis.violation);
|
|
436
|
+
const cacheFile = path.join(this.cacheDir, `analysis-${cacheKey}.json`);
|
|
437
|
+
|
|
438
|
+
const cacheData = {
|
|
439
|
+
timestamp: Date.now(),
|
|
440
|
+
analysis
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
await fs.writeFile(cacheFile, JSON.stringify(cacheData, null, 2));
|
|
444
|
+
} catch (error) {
|
|
445
|
+
// Ignore cache write errors
|
|
446
|
+
console.warn(chalk.dim(`Warning: Could not save analysis to cache: ${error instanceof Error ? error.message : 'Unknown error'}`));
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Generate cache key for violation
|
|
452
|
+
*/
|
|
453
|
+
private static generateCacheKey(violation: Violation): string {
|
|
454
|
+
const { createHash } = require('crypto');
|
|
455
|
+
const keyData = `${violation.feature}:${violation.browser}:${violation.required}:${violation.baselineStatus}`;
|
|
456
|
+
return createHash('md5').update(keyData).digest('hex');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Create basic fix suggestion when auto-fix is unavailable
|
|
461
|
+
*/
|
|
462
|
+
static createBasicFixSuggestion(violation: Violation, analysis: Analysis): Fix {
|
|
463
|
+
const basicPatch = this.generateBasicPatch(violation);
|
|
464
|
+
|
|
465
|
+
return {
|
|
466
|
+
violation,
|
|
467
|
+
analysis,
|
|
468
|
+
patch: basicPatch,
|
|
469
|
+
explanation: `Manual fix required for ${violation.feature} compatibility:\n\n` +
|
|
470
|
+
`1. Review the code at ${violation.file}:${violation.line}\n` +
|
|
471
|
+
`2. Implement ${analysis.fixStrategy}\n` +
|
|
472
|
+
`3. Test in ${violation.browser} ${violation.required}\n` +
|
|
473
|
+
`4. Consider using: ${analysis.bestPractices.join(', ')}`,
|
|
474
|
+
filePath: violation.file,
|
|
475
|
+
preview: `Manual review required:\n- Feature: ${violation.feature}\n- Location: ${violation.file}:${violation.line}\n- Strategy: ${analysis.fixStrategy}`,
|
|
476
|
+
confidence: 0.5,
|
|
477
|
+
testable: false
|
|
478
|
+
};
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Generate basic patch template
|
|
483
|
+
*/
|
|
484
|
+
private static generateBasicPatch(violation: Violation): string {
|
|
485
|
+
return `# Manual fix required for ${violation.feature}
|
|
486
|
+
# File: ${violation.file}
|
|
487
|
+
# Line: ${violation.line}
|
|
488
|
+
#
|
|
489
|
+
# Current code:
|
|
490
|
+
# ${violation.context}
|
|
491
|
+
#
|
|
492
|
+
# Suggested approach:
|
|
493
|
+
# 1. Add feature detection or @supports rule
|
|
494
|
+
# 2. Provide fallback for ${violation.browser} ${violation.required}
|
|
495
|
+
# 3. Test across target browsers
|
|
496
|
+
#
|
|
497
|
+
# Example patterns:
|
|
498
|
+
# CSS: @supports (${violation.feature}: value) { /* modern code */ }
|
|
499
|
+
# JS: if ('${violation.feature}' in window) { /* modern code */ }
|
|
500
|
+
`;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Get current degradation mode
|
|
505
|
+
*/
|
|
506
|
+
static getCurrentMode(): DegradationMode | null {
|
|
507
|
+
return this.currentMode;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Get service status
|
|
512
|
+
*/
|
|
513
|
+
static getServiceStatus(): Map<string, { available: boolean; lastCheck: number; error?: string }> {
|
|
514
|
+
return new Map(this.serviceStatus);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
/**
|
|
518
|
+
* Get fallback options
|
|
519
|
+
*/
|
|
520
|
+
static getFallbackOptions(): FallbackOptions {
|
|
521
|
+
return { ...this.fallbackOptions };
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Force refresh service status
|
|
526
|
+
*/
|
|
527
|
+
static async refreshServiceStatus(): Promise<void> {
|
|
528
|
+
console.log(chalk.cyan('š Checking service availability...'));
|
|
529
|
+
await this.checkServiceAvailability();
|
|
530
|
+
|
|
531
|
+
const status = this.getServiceStatus();
|
|
532
|
+
console.log(chalk.cyan('\nš Service Status:'));
|
|
533
|
+
|
|
534
|
+
for (const [service, info] of status) {
|
|
535
|
+
const statusIcon = info.available ? 'ā
' : 'ā';
|
|
536
|
+
const statusText = info.available ? 'Available' : 'Unavailable';
|
|
537
|
+
console.log(chalk.cyan(` ${statusIcon} ${service}: ${statusText}`));
|
|
538
|
+
|
|
539
|
+
if (!info.available && info.error) {
|
|
540
|
+
console.log(chalk.dim(` Error: ${info.error}`));
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Clean up old cache files
|
|
547
|
+
*/
|
|
548
|
+
static async cleanupCache(): Promise<void> {
|
|
549
|
+
try {
|
|
550
|
+
const files = await fs.readdir(this.cacheDir);
|
|
551
|
+
const now = Date.now();
|
|
552
|
+
const maxAge = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
553
|
+
|
|
554
|
+
for (const file of files) {
|
|
555
|
+
const filePath = path.join(this.cacheDir, file);
|
|
556
|
+
const stats = await fs.stat(filePath);
|
|
557
|
+
|
|
558
|
+
if (now - stats.mtime.getTime() > maxAge) {
|
|
559
|
+
await fs.unlink(filePath);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
} catch (error) {
|
|
563
|
+
// Ignore cleanup errors
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* Show degradation status to user
|
|
569
|
+
*/
|
|
570
|
+
static showStatus(): void {
|
|
571
|
+
const mode = this.currentMode;
|
|
572
|
+
if (!mode) {
|
|
573
|
+
console.log(chalk.red('ā Degradation manager not initialized'));
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
UIComponents.showInfoBox(`Current Mode: ${mode.name}`);
|
|
578
|
+
console.log(chalk.dim(mode.description));
|
|
579
|
+
|
|
580
|
+
if (mode.limitations.length > 0) {
|
|
581
|
+
console.log(chalk.yellow('\nā ļø Current limitations:'));
|
|
582
|
+
mode.limitations.forEach(limitation => {
|
|
583
|
+
console.log(chalk.yellow(` ⢠${limitation}`));
|
|
584
|
+
});
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
const status = this.getServiceStatus();
|
|
588
|
+
console.log(chalk.cyan('\nš Service Status:'));
|
|
589
|
+
|
|
590
|
+
for (const [service, info] of status) {
|
|
591
|
+
const statusIcon = info.available ? 'ā
' : 'ā';
|
|
592
|
+
const age = Math.round((Date.now() - info.lastCheck) / 1000);
|
|
593
|
+
console.log(chalk.cyan(` ${statusIcon} ${service} (checked ${age}s ago)`));
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Core engine exports
|
|
2
|
+
export * from './baseguard.js';
|
|
3
|
+
export * from './baseline-checker.js';
|
|
4
|
+
export { ConfigurationManager, BROWSER_TARGET_PRESETS } from './configuration.js';
|
|
5
|
+
export type { PresetName } from './configuration.js';
|
|
6
|
+
export { ApiKeyManager } from './api-key-manager.js';
|
|
7
|
+
export { GitignoreManager } from './gitignore-manager.js';
|
|
8
|
+
export { CacheManager, LRUCache } from './cache-manager.js';
|
|
9
|
+
export { FileProcessor } from './file-processor.js';
|
|
10
|
+
export { DirectoryFilter } from './directory-filter.js';
|
|
11
|
+
export { LazyLoader } from './lazy-loader.js';
|
|
12
|
+
export { MemoryManager } from './memory-manager.js';
|
|
13
|
+
export { StartupOptimizer } from './startup-optimizer.js';
|