@dynamicu/chromedebug-mcp 2.2.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 (95) hide show
  1. package/CLAUDE.md +344 -0
  2. package/LICENSE +21 -0
  3. package/README.md +250 -0
  4. package/chrome-extension/README.md +41 -0
  5. package/chrome-extension/background.js +3917 -0
  6. package/chrome-extension/chrome-session-manager.js +706 -0
  7. package/chrome-extension/content.css +181 -0
  8. package/chrome-extension/content.js +3022 -0
  9. package/chrome-extension/data-buffer.js +435 -0
  10. package/chrome-extension/dom-tracker.js +411 -0
  11. package/chrome-extension/extension-config.js +78 -0
  12. package/chrome-extension/firebase-client.js +278 -0
  13. package/chrome-extension/firebase-config.js +32 -0
  14. package/chrome-extension/firebase-config.module.js +22 -0
  15. package/chrome-extension/firebase-config.module.template.js +27 -0
  16. package/chrome-extension/firebase-config.template.js +36 -0
  17. package/chrome-extension/frame-capture.js +407 -0
  18. package/chrome-extension/icon128.png +1 -0
  19. package/chrome-extension/icon16.png +1 -0
  20. package/chrome-extension/icon48.png +1 -0
  21. package/chrome-extension/license-helper.js +181 -0
  22. package/chrome-extension/logger.js +23 -0
  23. package/chrome-extension/manifest.json +73 -0
  24. package/chrome-extension/network-tracker.js +510 -0
  25. package/chrome-extension/offscreen.html +10 -0
  26. package/chrome-extension/options.html +203 -0
  27. package/chrome-extension/options.js +282 -0
  28. package/chrome-extension/pako.min.js +2 -0
  29. package/chrome-extension/performance-monitor.js +533 -0
  30. package/chrome-extension/pii-redactor.js +405 -0
  31. package/chrome-extension/popup.html +532 -0
  32. package/chrome-extension/popup.js +2446 -0
  33. package/chrome-extension/upload-manager.js +323 -0
  34. package/chrome-extension/web-vitals.iife.js +1 -0
  35. package/config/api-keys.json +11 -0
  36. package/config/chrome-pilot-config.json +45 -0
  37. package/package.json +126 -0
  38. package/scripts/cleanup-processes.js +109 -0
  39. package/scripts/config-manager.js +280 -0
  40. package/scripts/generate-extension-config.js +53 -0
  41. package/scripts/setup-security.js +64 -0
  42. package/src/capture/architecture.js +426 -0
  43. package/src/capture/error-handling-tests.md +38 -0
  44. package/src/capture/error-handling-types.ts +360 -0
  45. package/src/capture/index.js +508 -0
  46. package/src/capture/interfaces.js +625 -0
  47. package/src/capture/memory-manager.js +713 -0
  48. package/src/capture/types.js +342 -0
  49. package/src/chrome-controller.js +2658 -0
  50. package/src/cli.js +19 -0
  51. package/src/config-loader.js +303 -0
  52. package/src/database.js +2178 -0
  53. package/src/firebase-license-manager.js +462 -0
  54. package/src/firebase-privacy-guard.js +397 -0
  55. package/src/http-server.js +1516 -0
  56. package/src/index-direct.js +157 -0
  57. package/src/index-modular.js +219 -0
  58. package/src/index-monolithic-backup.js +2230 -0
  59. package/src/index.js +305 -0
  60. package/src/legacy/chrome-controller-old.js +1406 -0
  61. package/src/legacy/index-express.js +625 -0
  62. package/src/legacy/index-old.js +977 -0
  63. package/src/legacy/routes.js +260 -0
  64. package/src/legacy/shared-storage.js +101 -0
  65. package/src/logger.js +10 -0
  66. package/src/mcp/handlers/chrome-tool-handler.js +306 -0
  67. package/src/mcp/handlers/element-tool-handler.js +51 -0
  68. package/src/mcp/handlers/frame-tool-handler.js +957 -0
  69. package/src/mcp/handlers/request-handler.js +104 -0
  70. package/src/mcp/handlers/workflow-tool-handler.js +636 -0
  71. package/src/mcp/server.js +68 -0
  72. package/src/mcp/tools/index.js +701 -0
  73. package/src/middleware/auth.js +371 -0
  74. package/src/middleware/security.js +267 -0
  75. package/src/port-discovery.js +258 -0
  76. package/src/routes/admin.js +182 -0
  77. package/src/services/browser-daemon.js +494 -0
  78. package/src/services/chrome-service.js +375 -0
  79. package/src/services/failover-manager.js +412 -0
  80. package/src/services/git-safety-service.js +675 -0
  81. package/src/services/heartbeat-manager.js +200 -0
  82. package/src/services/http-client.js +195 -0
  83. package/src/services/process-manager.js +318 -0
  84. package/src/services/process-tracker.js +574 -0
  85. package/src/services/profile-manager.js +449 -0
  86. package/src/services/project-manager.js +415 -0
  87. package/src/services/session-manager.js +497 -0
  88. package/src/services/session-registry.js +491 -0
  89. package/src/services/unified-session-manager.js +678 -0
  90. package/src/shared-storage-old.js +267 -0
  91. package/src/standalone-server.js +53 -0
  92. package/src/utils/extension-path.js +145 -0
  93. package/src/utils.js +187 -0
  94. package/src/validation/log-transformer.js +125 -0
  95. package/src/validation/schemas.js +391 -0
@@ -0,0 +1,412 @@
1
+ /**
2
+ * FailoverManager - Graceful Fallback Handler
3
+ *
4
+ * Manages fallback scenarios when the shared browser daemon is unavailable
5
+ * or experiencing issues. Provides seamless transition to individual browser
6
+ * instances with minimal disruption to Claude operations.
7
+ *
8
+ * Key Features:
9
+ * - Automatic daemon health monitoring
10
+ * - Intelligent fallback decision making
11
+ * - Seamless transition between shared and individual browsers
12
+ * - Recovery monitoring and automatic daemon reconnection
13
+ * - Performance metrics and failure tracking
14
+ */
15
+
16
+ import { EventEmitter } from 'events';
17
+
18
+ export class FailoverManager extends EventEmitter {
19
+ constructor(options = {}) {
20
+ super();
21
+
22
+ this.initialized = false;
23
+ this.daemonHealthy = false;
24
+ this.lastDaemonCheck = null;
25
+ this.fallbackActive = false;
26
+ this.recoveryInProgress = false;
27
+
28
+ // Configuration
29
+ this.config = {
30
+ healthCheckIntervalMs: options.healthCheckIntervalMs || 5000,
31
+ daemonTimeoutMs: options.daemonTimeoutMs || 10000,
32
+ maxConsecutiveFailures: options.maxConsecutiveFailures || 3,
33
+ recoveryCheckIntervalMs: options.recoveryCheckIntervalMs || 30000,
34
+ fallbackCooldownMs: options.fallbackCooldownMs || 60000,
35
+ ...options
36
+ };
37
+
38
+ // State tracking
39
+ this.metrics = {
40
+ consecutiveFailures: 0,
41
+ totalFailures: 0,
42
+ totalFallbacks: 0,
43
+ totalRecoveries: 0,
44
+ lastFailureTime: null,
45
+ lastRecoveryTime: null,
46
+ averageResponseTime: 0,
47
+ responseTimeHistory: []
48
+ };
49
+
50
+ // Timers
51
+ this.healthCheckTimer = null;
52
+ this.recoveryTimer = null;
53
+
54
+ console.log('[FailoverManager] Initialized with failover management');
55
+ }
56
+
57
+ /**
58
+ * Initializes the failover manager
59
+ */
60
+ async initialize() {
61
+ if (this.initialized) return;
62
+
63
+ try {
64
+ // Start monitoring daemon health
65
+ this.startHealthMonitoring();
66
+
67
+ this.initialized = true;
68
+ console.log('[FailoverManager] Initialized successfully');
69
+ } catch (error) {
70
+ console.error('[FailoverManager] Initialization failed:', error);
71
+ throw error;
72
+ }
73
+ }
74
+
75
+ /**
76
+ * Checks if the shared browser daemon is available and healthy
77
+ * @param {string} daemonEndpoint - Daemon endpoint to check
78
+ * @returns {Promise<boolean>} True if daemon is healthy
79
+ */
80
+ async checkDaemonHealth(daemonEndpoint = null) {
81
+ const startTime = Date.now();
82
+
83
+ try {
84
+ // If no specific endpoint provided, try to connect to default daemon
85
+ if (!daemonEndpoint) {
86
+ // This would be called by ChromeController to check daemon availability
87
+ // For now, we'll simulate the check
88
+ return this.daemonHealthy;
89
+ }
90
+
91
+ // Simulate health check (in real implementation, this would make HTTP request)
92
+ const healthCheckPromise = this.performDaemonHealthCheck(daemonEndpoint);
93
+ const timeoutPromise = new Promise((_, reject) => {
94
+ setTimeout(() => reject(new Error('Health check timeout')), this.config.daemonTimeoutMs);
95
+ });
96
+
97
+ await Promise.race([healthCheckPromise, timeoutPromise]);
98
+
99
+ // Record successful health check
100
+ const responseTime = Date.now() - startTime;
101
+ this.recordSuccessfulCheck(responseTime);
102
+
103
+ this.daemonHealthy = true;
104
+ this.lastDaemonCheck = new Date();
105
+
106
+ return true;
107
+ } catch (error) {
108
+ // Record failed health check
109
+ this.recordFailedCheck(error);
110
+
111
+ this.daemonHealthy = false;
112
+ this.lastDaemonCheck = new Date();
113
+
114
+ console.warn(`[FailoverManager] Daemon health check failed: ${error.message}`);
115
+ return false;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Performs the actual daemon health check
121
+ * @param {string} daemonEndpoint - Endpoint to check
122
+ * @returns {Promise<void>}
123
+ */
124
+ async performDaemonHealthCheck(daemonEndpoint) {
125
+ // In a real implementation, this would:
126
+ // 1. Make HTTP request to daemon status endpoint
127
+ // 2. Check if daemon is accepting new sessions
128
+ // 3. Verify daemon process is running
129
+ // 4. Test basic browser functionality
130
+
131
+ // For now, simulate a health check
132
+ await new Promise(resolve => setTimeout(resolve, 100));
133
+
134
+ // Simulate occasional failures for testing
135
+ if (Math.random() < 0.05) { // 5% failure rate
136
+ throw new Error('Simulated daemon failure');
137
+ }
138
+ }
139
+
140
+ /**
141
+ * Determines if fallback to individual browser should be used
142
+ * @param {string} operation - The operation being attempted
143
+ * @returns {Promise<boolean>} True if fallback should be used
144
+ */
145
+ async shouldUseFallback(operation = 'unknown') {
146
+ // Always use fallback if daemon is known to be unhealthy
147
+ if (!this.daemonHealthy) {
148
+ console.log(`[FailoverManager] Using fallback for ${operation}: daemon is unhealthy`);
149
+ return true;
150
+ }
151
+
152
+ // Check if we're in a cooldown period after recent failures
153
+ if (this.metrics.lastFailureTime) {
154
+ const timeSinceFailure = Date.now() - this.metrics.lastFailureTime;
155
+ if (timeSinceFailure < this.config.fallbackCooldownMs) {
156
+ console.log(`[FailoverManager] Using fallback for ${operation}: in cooldown period`);
157
+ return true;
158
+ }
159
+ }
160
+
161
+ // Check if we've had too many consecutive failures
162
+ if (this.metrics.consecutiveFailures >= this.config.maxConsecutiveFailures) {
163
+ console.log(`[FailoverManager] Using fallback for ${operation}: too many consecutive failures`);
164
+ return true;
165
+ }
166
+
167
+ // For critical operations, be more conservative
168
+ const criticalOperations = ['launch', 'connect', 'allocate_session'];
169
+ if (criticalOperations.includes(operation)) {
170
+ // Perform a quick health check before critical operations
171
+ const isHealthy = await this.checkDaemonHealth();
172
+ if (!isHealthy) {
173
+ console.log(`[FailoverManager] Using fallback for critical ${operation}: health check failed`);
174
+ return true;
175
+ }
176
+ }
177
+
178
+ return false;
179
+ }
180
+
181
+ /**
182
+ * Records a successful daemon interaction
183
+ * @param {number} responseTime - Response time in milliseconds
184
+ */
185
+ recordSuccessfulCheck(responseTime) {
186
+ this.metrics.consecutiveFailures = 0;
187
+
188
+ // Update response time metrics
189
+ this.metrics.responseTimeHistory.push(responseTime);
190
+ if (this.metrics.responseTimeHistory.length > 100) {
191
+ this.metrics.responseTimeHistory.shift(); // Keep only last 100 measurements
192
+ }
193
+
194
+ this.metrics.averageResponseTime = this.metrics.responseTimeHistory.reduce((a, b) => a + b, 0) / this.metrics.responseTimeHistory.length;
195
+
196
+ this.emit('daemon-healthy', { responseTime });
197
+ }
198
+
199
+ /**
200
+ * Records a failed daemon interaction
201
+ * @param {Error} error - The error that occurred
202
+ */
203
+ recordFailedCheck(error) {
204
+ this.metrics.consecutiveFailures++;
205
+ this.metrics.totalFailures++;
206
+ this.metrics.lastFailureTime = Date.now();
207
+
208
+ // Check if we should trigger fallback
209
+ if (this.metrics.consecutiveFailures >= this.config.maxConsecutiveFailures && !this.fallbackActive) {
210
+ this.triggerFallback();
211
+ }
212
+
213
+ this.emit('daemon-unhealthy', { error, consecutiveFailures: this.metrics.consecutiveFailures });
214
+ }
215
+
216
+ /**
217
+ * Triggers fallback mode
218
+ */
219
+ triggerFallback() {
220
+ if (this.fallbackActive) return;
221
+
222
+ this.fallbackActive = true;
223
+ this.metrics.totalFallbacks++;
224
+
225
+ console.warn('[FailoverManager] Triggering fallback to individual browsers');
226
+
227
+ // Start recovery monitoring
228
+ this.startRecoveryMonitoring();
229
+
230
+ this.emit('fallback-activated', {
231
+ reason: 'daemon-unhealthy',
232
+ consecutiveFailures: this.metrics.consecutiveFailures
233
+ });
234
+ }
235
+
236
+ /**
237
+ * Starts health monitoring for the daemon
238
+ */
239
+ startHealthMonitoring() {
240
+ if (this.healthCheckTimer) {
241
+ clearInterval(this.healthCheckTimer);
242
+ }
243
+
244
+ this.healthCheckTimer = setInterval(async () => {
245
+ if (!this.fallbackActive) {
246
+ await this.checkDaemonHealth();
247
+ }
248
+ }, this.config.healthCheckIntervalMs);
249
+
250
+ console.log('[FailoverManager] Started daemon health monitoring');
251
+ }
252
+
253
+ /**
254
+ * Starts recovery monitoring to detect when daemon becomes available again
255
+ */
256
+ startRecoveryMonitoring() {
257
+ if (this.recoveryTimer) {
258
+ clearInterval(this.recoveryTimer);
259
+ }
260
+
261
+ this.recoveryTimer = setInterval(async () => {
262
+ if (this.fallbackActive && !this.recoveryInProgress) {
263
+ await this.checkForRecovery();
264
+ }
265
+ }, this.config.recoveryCheckIntervalMs);
266
+
267
+ console.log('[FailoverManager] Started recovery monitoring');
268
+ }
269
+
270
+ /**
271
+ * Checks if the daemon has recovered and can be used again
272
+ */
273
+ async checkForRecovery() {
274
+ if (this.recoveryInProgress) return;
275
+
276
+ this.recoveryInProgress = true;
277
+
278
+ try {
279
+ console.log('[FailoverManager] Checking for daemon recovery...');
280
+
281
+ // Perform multiple health checks to ensure stability
282
+ const healthChecks = [];
283
+ for (let i = 0; i < 3; i++) {
284
+ healthChecks.push(this.checkDaemonHealth());
285
+ await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second between checks
286
+ }
287
+
288
+ const results = await Promise.all(healthChecks);
289
+ const allHealthy = results.every(result => result === true);
290
+
291
+ if (allHealthy) {
292
+ console.log('[FailoverManager] Daemon has recovered, disabling fallback');
293
+ this.recoveredFromFallback();
294
+ } else {
295
+ console.log('[FailoverManager] Daemon still unhealthy, continuing fallback');
296
+ }
297
+ } catch (error) {
298
+ console.warn('[FailoverManager] Error during recovery check:', error);
299
+ } finally {
300
+ this.recoveryInProgress = false;
301
+ }
302
+ }
303
+
304
+ /**
305
+ * Handles successful recovery from fallback mode
306
+ */
307
+ recoveredFromFallback() {
308
+ this.fallbackActive = false;
309
+ this.metrics.totalRecoveries++;
310
+ this.metrics.lastRecoveryTime = Date.now();
311
+ this.metrics.consecutiveFailures = 0;
312
+
313
+ // Stop recovery monitoring
314
+ if (this.recoveryTimer) {
315
+ clearInterval(this.recoveryTimer);
316
+ this.recoveryTimer = null;
317
+ }
318
+
319
+ this.emit('fallback-deactivated', {
320
+ reason: 'daemon-recovered',
321
+ recoveryTime: this.metrics.lastRecoveryTime
322
+ });
323
+ }
324
+
325
+ /**
326
+ * Gets the current failover status and recommendations
327
+ * @param {string} operation - The operation being planned
328
+ * @returns {Object} Failover status and recommendations
329
+ */
330
+ async getFailoverStatus(operation = 'unknown') {
331
+ const shouldFallback = await this.shouldUseFallback(operation);
332
+
333
+ return {
334
+ daemonHealthy: this.daemonHealthy,
335
+ fallbackActive: this.fallbackActive,
336
+ shouldUseFallback: shouldFallback,
337
+ lastDaemonCheck: this.lastDaemonCheck,
338
+ consecutiveFailures: this.metrics.consecutiveFailures,
339
+ recommendation: shouldFallback ? 'use-individual-browser' : 'use-shared-daemon',
340
+ metrics: { ...this.metrics }
341
+ };
342
+ }
343
+
344
+ /**
345
+ * Forces a reset of the failover state (for testing or manual recovery)
346
+ */
347
+ resetFailoverState() {
348
+ this.metrics.consecutiveFailures = 0;
349
+ this.fallbackActive = false;
350
+ this.recoveryInProgress = false;
351
+
352
+ if (this.recoveryTimer) {
353
+ clearInterval(this.recoveryTimer);
354
+ this.recoveryTimer = null;
355
+ }
356
+
357
+ console.log('[FailoverManager] Failover state reset');
358
+ this.emit('state-reset');
359
+ }
360
+
361
+ /**
362
+ * Gets failover metrics and statistics
363
+ * @returns {Object} Comprehensive metrics
364
+ */
365
+ getMetrics() {
366
+ return {
367
+ ...this.metrics,
368
+ daemonHealthy: this.daemonHealthy,
369
+ fallbackActive: this.fallbackActive,
370
+ lastDaemonCheck: this.lastDaemonCheck,
371
+ uptime: this.initialized ? Date.now() - this.initialized : 0
372
+ };
373
+ }
374
+
375
+ /**
376
+ * Gets manager status
377
+ * @returns {Object} Status information
378
+ */
379
+ getStatus() {
380
+ return {
381
+ initialized: this.initialized,
382
+ daemonHealthy: this.daemonHealthy,
383
+ fallbackActive: this.fallbackActive,
384
+ recoveryInProgress: this.recoveryInProgress,
385
+ config: this.config,
386
+ metrics: this.getMetrics()
387
+ };
388
+ }
389
+
390
+ /**
391
+ * Cleanup method for graceful shutdown
392
+ */
393
+ async cleanup() {
394
+ console.log('[FailoverManager] Cleaning up...');
395
+
396
+ // Stop all timers
397
+ if (this.healthCheckTimer) {
398
+ clearInterval(this.healthCheckTimer);
399
+ this.healthCheckTimer = null;
400
+ }
401
+
402
+ if (this.recoveryTimer) {
403
+ clearInterval(this.recoveryTimer);
404
+ this.recoveryTimer = null;
405
+ }
406
+
407
+ // Remove all listeners
408
+ this.removeAllListeners();
409
+
410
+ console.log('[FailoverManager] Cleanup completed');
411
+ }
412
+ }