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.
Files changed (244) hide show
  1. package/.eslintrc.json +25 -0
  2. package/.prettierrc +8 -0
  3. package/README.md +94 -0
  4. package/bin/base.js +494 -0
  5. package/dist/ai/fix-manager.d.ts +67 -0
  6. package/dist/ai/fix-manager.d.ts.map +1 -0
  7. package/dist/ai/fix-manager.js +326 -0
  8. package/dist/ai/fix-manager.js.map +1 -0
  9. package/dist/ai/gemini-analyzer.d.ts +116 -0
  10. package/dist/ai/gemini-analyzer.d.ts.map +1 -0
  11. package/dist/ai/gemini-analyzer.js +572 -0
  12. package/dist/ai/gemini-analyzer.js.map +1 -0
  13. package/dist/ai/index.d.ts +4 -0
  14. package/dist/ai/index.d.ts.map +1 -0
  15. package/dist/ai/index.js +5 -0
  16. package/dist/ai/index.js.map +1 -0
  17. package/dist/ai/jules-implementer.d.ts +115 -0
  18. package/dist/ai/jules-implementer.d.ts.map +1 -0
  19. package/dist/ai/jules-implementer.js +387 -0
  20. package/dist/ai/jules-implementer.js.map +1 -0
  21. package/dist/commands/automation.d.ts +5 -0
  22. package/dist/commands/automation.d.ts.map +1 -0
  23. package/dist/commands/automation.js +305 -0
  24. package/dist/commands/automation.js.map +1 -0
  25. package/dist/commands/check.d.ts +9 -0
  26. package/dist/commands/check.d.ts.map +1 -0
  27. package/dist/commands/check.js +113 -0
  28. package/dist/commands/check.js.map +1 -0
  29. package/dist/commands/config.d.ts +11 -0
  30. package/dist/commands/config.d.ts.map +1 -0
  31. package/dist/commands/config.js +324 -0
  32. package/dist/commands/config.js.map +1 -0
  33. package/dist/commands/fix.d.ts +9 -0
  34. package/dist/commands/fix.d.ts.map +1 -0
  35. package/dist/commands/fix.js +207 -0
  36. package/dist/commands/fix.js.map +1 -0
  37. package/dist/commands/index.d.ts +6 -0
  38. package/dist/commands/index.d.ts.map +1 -0
  39. package/dist/commands/index.js +7 -0
  40. package/dist/commands/index.js.map +1 -0
  41. package/dist/commands/init.d.ts +9 -0
  42. package/dist/commands/init.d.ts.map +1 -0
  43. package/dist/commands/init.js +125 -0
  44. package/dist/commands/init.js.map +1 -0
  45. package/dist/core/api-key-manager.d.ts +83 -0
  46. package/dist/core/api-key-manager.d.ts.map +1 -0
  47. package/dist/core/api-key-manager.js +244 -0
  48. package/dist/core/api-key-manager.js.map +1 -0
  49. package/dist/core/baseguard.d.ts +46 -0
  50. package/dist/core/baseguard.d.ts.map +1 -0
  51. package/dist/core/baseguard.js +132 -0
  52. package/dist/core/baseguard.js.map +1 -0
  53. package/dist/core/baseline-checker.d.ts +63 -0
  54. package/dist/core/baseline-checker.d.ts.map +1 -0
  55. package/dist/core/baseline-checker.js +502 -0
  56. package/dist/core/baseline-checker.js.map +1 -0
  57. package/dist/core/cache-manager.d.ts +88 -0
  58. package/dist/core/cache-manager.d.ts.map +1 -0
  59. package/dist/core/cache-manager.js +213 -0
  60. package/dist/core/cache-manager.js.map +1 -0
  61. package/dist/core/configuration.d.ts +140 -0
  62. package/dist/core/configuration.d.ts.map +1 -0
  63. package/dist/core/configuration.js +474 -0
  64. package/dist/core/configuration.js.map +1 -0
  65. package/dist/core/directory-filter.d.ts +90 -0
  66. package/dist/core/directory-filter.d.ts.map +1 -0
  67. package/dist/core/directory-filter.js +319 -0
  68. package/dist/core/directory-filter.js.map +1 -0
  69. package/dist/core/error-handler.d.ts +110 -0
  70. package/dist/core/error-handler.d.ts.map +1 -0
  71. package/dist/core/error-handler.js +392 -0
  72. package/dist/core/error-handler.js.map +1 -0
  73. package/dist/core/file-processor.d.ts +80 -0
  74. package/dist/core/file-processor.d.ts.map +1 -0
  75. package/dist/core/file-processor.js +259 -0
  76. package/dist/core/file-processor.js.map +1 -0
  77. package/dist/core/gitignore-manager.d.ts +44 -0
  78. package/dist/core/gitignore-manager.d.ts.map +1 -0
  79. package/dist/core/gitignore-manager.js +147 -0
  80. package/dist/core/gitignore-manager.js.map +1 -0
  81. package/dist/core/index.d.ts +13 -0
  82. package/dist/core/index.d.ts.map +1 -0
  83. package/dist/core/index.js +13 -0
  84. package/dist/core/index.js.map +1 -0
  85. package/dist/core/lazy-loader.d.ts +68 -0
  86. package/dist/core/lazy-loader.d.ts.map +1 -0
  87. package/dist/core/lazy-loader.js +260 -0
  88. package/dist/core/lazy-loader.js.map +1 -0
  89. package/dist/core/memory-manager.d.ts +1 -0
  90. package/dist/core/memory-manager.d.ts.map +1 -0
  91. package/dist/core/memory-manager.js +2 -0
  92. package/dist/core/memory-manager.js.map +1 -0
  93. package/dist/core/startup-optimizer.d.ts +45 -0
  94. package/dist/core/startup-optimizer.d.ts.map +1 -0
  95. package/dist/core/startup-optimizer.js +140 -0
  96. package/dist/core/startup-optimizer.js.map +1 -0
  97. package/dist/git/automation-engine.d.ts +58 -0
  98. package/dist/git/automation-engine.d.ts.map +1 -0
  99. package/dist/git/automation-engine.js +318 -0
  100. package/dist/git/automation-engine.js.map +1 -0
  101. package/dist/git/github-manager.d.ts +71 -0
  102. package/dist/git/github-manager.d.ts.map +1 -0
  103. package/dist/git/github-manager.js +226 -0
  104. package/dist/git/github-manager.js.map +1 -0
  105. package/dist/git/hook-manager.d.ts +43 -0
  106. package/dist/git/hook-manager.d.ts.map +1 -0
  107. package/dist/git/hook-manager.js +191 -0
  108. package/dist/git/hook-manager.js.map +1 -0
  109. package/dist/git/index.d.ts +4 -0
  110. package/dist/git/index.d.ts.map +1 -0
  111. package/dist/git/index.js +5 -0
  112. package/dist/git/index.js.map +1 -0
  113. package/dist/index.d.ts +8 -0
  114. package/dist/index.d.ts.map +1 -0
  115. package/dist/index.js +9 -0
  116. package/dist/index.js.map +1 -0
  117. package/dist/parsers/feature-validator.d.ts +60 -0
  118. package/dist/parsers/feature-validator.d.ts.map +1 -0
  119. package/dist/parsers/feature-validator.js +483 -0
  120. package/dist/parsers/feature-validator.js.map +1 -0
  121. package/dist/parsers/index.d.ts +8 -0
  122. package/dist/parsers/index.d.ts.map +1 -0
  123. package/dist/parsers/index.js +9 -0
  124. package/dist/parsers/index.js.map +1 -0
  125. package/dist/parsers/parser-manager.d.ts +103 -0
  126. package/dist/parsers/parser-manager.d.ts.map +1 -0
  127. package/dist/parsers/parser-manager.js +321 -0
  128. package/dist/parsers/parser-manager.js.map +1 -0
  129. package/dist/parsers/parser.d.ts +23 -0
  130. package/dist/parsers/parser.d.ts.map +1 -0
  131. package/dist/parsers/parser.js +6 -0
  132. package/dist/parsers/parser.js.map +1 -0
  133. package/dist/parsers/react-parser.d.ts +22 -0
  134. package/dist/parsers/react-parser.d.ts.map +1 -0
  135. package/dist/parsers/react-parser.js +307 -0
  136. package/dist/parsers/react-parser.js.map +1 -0
  137. package/dist/parsers/svelte-parser.d.ts +33 -0
  138. package/dist/parsers/svelte-parser.d.ts.map +1 -0
  139. package/dist/parsers/svelte-parser.js +408 -0
  140. package/dist/parsers/svelte-parser.js.map +1 -0
  141. package/dist/parsers/vanilla-parser.d.ts +31 -0
  142. package/dist/parsers/vanilla-parser.d.ts.map +1 -0
  143. package/dist/parsers/vanilla-parser.js +590 -0
  144. package/dist/parsers/vanilla-parser.js.map +1 -0
  145. package/dist/parsers/vue-parser.d.ts +9 -0
  146. package/dist/parsers/vue-parser.d.ts.map +1 -0
  147. package/dist/parsers/vue-parser.js +16 -0
  148. package/dist/parsers/vue-parser.js.map +1 -0
  149. package/dist/terminal-header.d.ts +12 -0
  150. package/dist/terminal-header.js +45 -0
  151. package/dist/types/index.d.ts +83 -0
  152. package/dist/types/index.d.ts.map +1 -0
  153. package/dist/types/index.js +5 -0
  154. package/dist/types/index.js.map +1 -0
  155. package/dist/ui/components.d.ts +133 -0
  156. package/dist/ui/components.d.ts.map +1 -0
  157. package/dist/ui/components.js +482 -0
  158. package/dist/ui/components.js.map +1 -0
  159. package/dist/ui/help.d.ts +11 -0
  160. package/dist/ui/help.d.ts.map +1 -0
  161. package/dist/ui/help.js +161 -0
  162. package/dist/ui/help.js.map +1 -0
  163. package/dist/ui/index.d.ts +5 -0
  164. package/dist/ui/index.d.ts.map +1 -0
  165. package/dist/ui/index.js +5 -0
  166. package/dist/ui/index.js.map +1 -0
  167. package/dist/ui/prompts.d.ts +63 -0
  168. package/dist/ui/prompts.d.ts.map +1 -0
  169. package/dist/ui/prompts.js +611 -0
  170. package/dist/ui/prompts.js.map +1 -0
  171. package/dist/ui/terminal-header.d.ts +13 -0
  172. package/dist/ui/terminal-header.d.ts.map +1 -0
  173. package/dist/ui/terminal-header.js +46 -0
  174. package/dist/ui/terminal-header.js.map +1 -0
  175. package/package.json +80 -0
  176. package/src/ai/__tests__/gemini-analyzer.test.ts +181 -0
  177. package/src/ai/fix-manager.ts +362 -0
  178. package/src/ai/gemini-analyzer.ts +671 -0
  179. package/src/ai/index.ts +4 -0
  180. package/src/ai/jules-implementer.ts +459 -0
  181. package/src/commands/automation.ts +344 -0
  182. package/src/commands/check.ts +299 -0
  183. package/src/commands/config.ts +365 -0
  184. package/src/commands/fix.ts +234 -0
  185. package/src/commands/index.ts +6 -0
  186. package/src/commands/init.ts +142 -0
  187. package/src/commands/status.ts +0 -0
  188. package/src/core/api-key-manager.ts +298 -0
  189. package/src/core/baseguard.ts +742 -0
  190. package/src/core/baseline-checker.ts +563 -0
  191. package/src/core/cache-manager.ts +270 -0
  192. package/src/core/configuration-recovery.ts +676 -0
  193. package/src/core/configuration.ts +559 -0
  194. package/src/core/debug-logger.ts +590 -0
  195. package/src/core/directory-filter.ts +421 -0
  196. package/src/core/error-handler.ts +517 -0
  197. package/src/core/file-processor.ts +331 -0
  198. package/src/core/gitignore-manager.ts +169 -0
  199. package/src/core/graceful-degradation-manager.ts +596 -0
  200. package/src/core/index.ts +13 -0
  201. package/src/core/lazy-loader.ts +307 -0
  202. package/src/core/logger.ts +0 -0
  203. package/src/core/memory-manager.ts +294 -0
  204. package/src/core/startup-optimizer.ts +173 -0
  205. package/src/core/system-error-handler.ts +746 -0
  206. package/src/git/automation-engine.ts +361 -0
  207. package/src/git/github-manager.ts +260 -0
  208. package/src/git/hook-manager.ts +210 -0
  209. package/src/git/index.ts +4 -0
  210. package/src/index.ts +8 -0
  211. package/src/parsers/feature-validator.ts +559 -0
  212. package/src/parsers/index.ts +8 -0
  213. package/src/parsers/parser-manager.ts +419 -0
  214. package/src/parsers/parser.ts +26 -0
  215. package/src/parsers/react-parser-optimized.ts +161 -0
  216. package/src/parsers/react-parser.ts +359 -0
  217. package/src/parsers/svelte-parser.ts +506 -0
  218. package/src/parsers/vanilla-parser.ts +682 -0
  219. package/src/parsers/vue-parser.ts +472 -0
  220. package/src/types/index.ts +92 -0
  221. package/src/ui/components.ts +567 -0
  222. package/src/ui/help.ts +193 -0
  223. package/src/ui/index.ts +4 -0
  224. package/src/ui/prompts.ts +688 -0
  225. package/src/ui/terminal-header.ts +59 -0
  226. package/test-config-commands.js +56 -0
  227. package/test-header-simple.js +33 -0
  228. package/test-terminal-header.js +12 -0
  229. package/test-ui.js +29 -0
  230. package/tests/e2e/baseguard.e2e.test.ts +516 -0
  231. package/tests/e2e/cross-platform.e2e.test.ts +420 -0
  232. package/tests/e2e/git-integration.e2e.test.ts +487 -0
  233. package/tests/fixtures/react-project/package.json +14 -0
  234. package/tests/fixtures/react-project/src/App.css +76 -0
  235. package/tests/fixtures/react-project/src/App.tsx +77 -0
  236. package/tests/fixtures/svelte-project/package.json +11 -0
  237. package/tests/fixtures/svelte-project/src/App.svelte +369 -0
  238. package/tests/fixtures/vanilla-project/index.html +76 -0
  239. package/tests/fixtures/vanilla-project/script.js +331 -0
  240. package/tests/fixtures/vanilla-project/styles.css +359 -0
  241. package/tests/fixtures/vue-project/package.json +12 -0
  242. package/tests/fixtures/vue-project/src/App.vue +216 -0
  243. package/tsconfig.json +36 -0
  244. 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';