@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,411 @@
1
+ // DOM Tracker for Chrome Debug Full Data Recording
2
+ // Tracks DOM mutations using MutationObserver with performance optimization
3
+
4
+ class DOMTracker {
5
+ constructor() {
6
+ this.isTracking = false;
7
+ this.observer = null;
8
+ this.eventBuffer = [];
9
+ this.bufferFlushDelay = 1000; // Flush buffer every 1 second
10
+ this.flushTimer = null;
11
+ this.maxBufferSize = 100; // Max mutations before forced flush
12
+ this.recordingId = null;
13
+
14
+ // Performance optimization settings
15
+ this.mutationThrottle = 50; // Max mutations per second
16
+ this.lastMutationTime = 0;
17
+ this.mutationCount = 0;
18
+
19
+ // Callbacks
20
+ this.onDataReady = null; // Callback when data is ready to upload
21
+ this.piiRedactor = null;
22
+ this.performanceMonitor = null;
23
+ }
24
+
25
+ init(options = {}) {
26
+ this.recordingId = options.recordingId || 'default';
27
+ this.onDataReady = options.onDataReady;
28
+ this.piiRedactor = options.piiRedactor;
29
+ this.performanceMonitor = options.performanceMonitor;
30
+
31
+ // Override default settings
32
+ if (options.bufferFlushDelay) this.bufferFlushDelay = options.bufferFlushDelay;
33
+ if (options.maxBufferSize) this.maxBufferSize = options.maxBufferSize;
34
+ if (options.mutationThrottle) this.mutationThrottle = options.mutationThrottle;
35
+
36
+ console.log('[DOMTracker] Initialized with options:', {
37
+ recordingId: this.recordingId,
38
+ bufferFlushDelay: this.bufferFlushDelay,
39
+ maxBufferSize: this.maxBufferSize,
40
+ mutationThrottle: this.mutationThrottle
41
+ });
42
+ }
43
+
44
+ startTracking() {
45
+ if (this.isTracking) {
46
+ console.warn('[DOMTracker] Already tracking DOM mutations');
47
+ return;
48
+ }
49
+
50
+ try {
51
+ // Create MutationObserver
52
+ this.observer = new MutationObserver((mutations) => {
53
+ this.handleMutations(mutations);
54
+ });
55
+
56
+ // Configure observer options
57
+ const config = {
58
+ childList: true, // Track added/removed elements
59
+ attributes: true, // Track attribute changes
60
+ attributeOldValue: true, // Include old attribute values
61
+ characterData: true, // Track text content changes
62
+ characterDataOldValue: true, // Include old text values
63
+ subtree: true // Monitor entire subtree
64
+ };
65
+
66
+ // Start observing
67
+ this.observer.observe(document.body || document.documentElement, config);
68
+
69
+ this.isTracking = true;
70
+ this.startBufferFlusher();
71
+
72
+ console.log('[DOMTracker] Started DOM mutation tracking');
73
+
74
+ // Record performance event
75
+ if (this.performanceMonitor) {
76
+ this.performanceMonitor.recordEvent('dom_tracking_started', {
77
+ timestamp: Date.now(),
78
+ config: config
79
+ });
80
+ }
81
+
82
+ } catch (error) {
83
+ console.error('[DOMTracker] Failed to start tracking:', error);
84
+ }
85
+ }
86
+
87
+ stopTracking() {
88
+ if (!this.isTracking) return;
89
+
90
+ if (this.observer) {
91
+ this.observer.disconnect();
92
+ this.observer = null;
93
+ }
94
+
95
+ this.stopBufferFlusher();
96
+ this.flushBuffer(); // Flush any remaining data
97
+
98
+ this.isTracking = false;
99
+ console.log('[DOMTracker] Stopped DOM mutation tracking');
100
+
101
+ // Record performance event
102
+ if (this.performanceMonitor) {
103
+ this.performanceMonitor.recordEvent('dom_tracking_stopped', {
104
+ timestamp: Date.now(),
105
+ totalMutations: this.mutationCount
106
+ });
107
+ }
108
+ }
109
+
110
+ handleMutations(mutations) {
111
+ const now = Date.now();
112
+
113
+ // Throttle mutations for performance
114
+ if (now - this.lastMutationTime < (1000 / this.mutationThrottle)) {
115
+ return; // Skip this batch if we're over the throttle limit
116
+ }
117
+
118
+ this.lastMutationTime = now;
119
+
120
+ const processedMutations = [];
121
+
122
+ for (const mutation of mutations) {
123
+ try {
124
+ const processedMutation = this.processMutation(mutation);
125
+ if (processedMutation) {
126
+ processedMutations.push(processedMutation);
127
+ this.mutationCount++;
128
+ }
129
+ } catch (error) {
130
+ console.error('[DOMTracker] Error processing mutation:', error);
131
+ }
132
+ }
133
+
134
+ if (processedMutations.length > 0) {
135
+ this.eventBuffer.push(...processedMutations);
136
+
137
+ // Force flush if buffer is getting large
138
+ if (this.eventBuffer.length >= this.maxBufferSize) {
139
+ this.flushBuffer();
140
+ }
141
+ }
142
+ }
143
+
144
+ processMutation(mutation) {
145
+ const timestamp = Date.now();
146
+ const mutationData = {
147
+ type: 'dom_mutation',
148
+ timestamp: timestamp,
149
+ recording_id: this.recordingId,
150
+ mutation_type: mutation.type,
151
+ target_selector: this.getElementSelector(mutation.target),
152
+ target_xpath: this.getElementXPath(mutation.target)
153
+ };
154
+
155
+ // Process different mutation types
156
+ switch (mutation.type) {
157
+ case 'childList':
158
+ mutationData.added_nodes = this.processNodeList(mutation.addedNodes);
159
+ mutationData.removed_nodes = this.processNodeList(mutation.removedNodes);
160
+ break;
161
+
162
+ case 'attributes':
163
+ mutationData.attribute_name = mutation.attributeName;
164
+ mutationData.old_value = mutation.oldValue;
165
+ mutationData.new_value = mutation.target.getAttribute(mutation.attributeName);
166
+ break;
167
+
168
+ case 'characterData':
169
+ mutationData.old_value = mutation.oldValue;
170
+ mutationData.new_value = mutation.target.textContent;
171
+ break;
172
+ }
173
+
174
+ // Apply PII redaction if available
175
+ if (this.piiRedactor) {
176
+ mutationData = this.piiRedactor.redactData(mutationData, 'dom_mutation');
177
+ }
178
+
179
+ return mutationData;
180
+ }
181
+
182
+ processNodeList(nodeList) {
183
+ if (!nodeList || nodeList.length === 0) return [];
184
+
185
+ const nodes = [];
186
+
187
+ for (const node of nodeList) {
188
+ // Skip text nodes with only whitespace
189
+ if (node.nodeType === Node.TEXT_NODE && !node.textContent.trim()) {
190
+ continue;
191
+ }
192
+
193
+ const nodeData = {
194
+ nodeType: node.nodeType,
195
+ nodeName: node.nodeName.toLowerCase()
196
+ };
197
+
198
+ if (node.nodeType === Node.ELEMENT_NODE) {
199
+ nodeData.tagName = node.tagName.toLowerCase();
200
+ nodeData.className = node.className;
201
+ nodeData.id = node.id;
202
+
203
+ // Capture important attributes
204
+ if (node.attributes) {
205
+ nodeData.attributes = {};
206
+ for (const attr of node.attributes) {
207
+ nodeData.attributes[attr.name] = attr.value;
208
+ }
209
+ }
210
+ } else if (node.nodeType === Node.TEXT_NODE) {
211
+ nodeData.textContent = node.textContent.substring(0, 200); // Limit text length
212
+ }
213
+
214
+ nodes.push(nodeData);
215
+ }
216
+
217
+ return nodes;
218
+ }
219
+
220
+ getElementSelector(element) {
221
+ if (!element || element.nodeType !== Node.ELEMENT_NODE) {
222
+ return null;
223
+ }
224
+
225
+ try {
226
+ // Try to build a unique CSS selector
227
+ const parts = [];
228
+ let current = element;
229
+
230
+ while (current && current !== document.body && current !== document.documentElement) {
231
+ let selector = current.tagName.toLowerCase();
232
+
233
+ // Add ID if available
234
+ if (current.id) {
235
+ selector += `#${current.id}`;
236
+ parts.unshift(selector);
237
+ break; // ID is unique, we can stop here
238
+ }
239
+
240
+ // Add classes if available
241
+ if (current.className && typeof current.className === 'string') {
242
+ const classes = current.className.trim().split(/\s+/);
243
+ if (classes.length > 0) {
244
+ selector += '.' + classes.join('.');
245
+ }
246
+ }
247
+
248
+ // Add nth-child if needed for uniqueness
249
+ const siblings = current.parentElement ?
250
+ Array.from(current.parentElement.children).filter(el => el.tagName === current.tagName) :
251
+ [];
252
+
253
+ if (siblings.length > 1) {
254
+ const index = siblings.indexOf(current) + 1;
255
+ selector += `:nth-child(${index})`;
256
+ }
257
+
258
+ parts.unshift(selector);
259
+ current = current.parentElement;
260
+
261
+ // Limit depth to prevent overly long selectors
262
+ if (parts.length >= 5) break;
263
+ }
264
+
265
+ return parts.join(' > ');
266
+ } catch (error) {
267
+ console.error('[DOMTracker] Error generating selector:', error);
268
+ return element.tagName?.toLowerCase() || 'unknown';
269
+ }
270
+ }
271
+
272
+ getElementXPath(element) {
273
+ if (!element || element.nodeType !== Node.ELEMENT_NODE) {
274
+ return null;
275
+ }
276
+
277
+ try {
278
+ const parts = [];
279
+ let current = element;
280
+
281
+ while (current && current !== document.documentElement) {
282
+ let part = current.tagName.toLowerCase();
283
+
284
+ if (current.id) {
285
+ part += `[@id='${current.id}']`;
286
+ parts.unshift(part);
287
+ break; // ID is unique
288
+ }
289
+
290
+ // Count siblings with same tag name
291
+ const siblings = current.parentElement ?
292
+ Array.from(current.parentElement.children).filter(el => el.tagName === current.tagName) :
293
+ [];
294
+
295
+ if (siblings.length > 1) {
296
+ const index = siblings.indexOf(current) + 1;
297
+ part += `[${index}]`;
298
+ }
299
+
300
+ parts.unshift(part);
301
+ current = current.parentElement;
302
+
303
+ // Limit depth
304
+ if (parts.length >= 8) break;
305
+ }
306
+
307
+ return '/' + parts.join('/');
308
+ } catch (error) {
309
+ console.error('[DOMTracker] Error generating XPath:', error);
310
+ return null;
311
+ }
312
+ }
313
+
314
+ startBufferFlusher() {
315
+ if (this.flushTimer) return;
316
+
317
+ this.flushTimer = setInterval(() => {
318
+ if (this.eventBuffer.length > 0) {
319
+ this.flushBuffer();
320
+ }
321
+ }, this.bufferFlushDelay);
322
+ }
323
+
324
+ stopBufferFlusher() {
325
+ if (this.flushTimer) {
326
+ clearInterval(this.flushTimer);
327
+ this.flushTimer = null;
328
+ }
329
+ }
330
+
331
+ flushBuffer() {
332
+ if (this.eventBuffer.length === 0) return;
333
+
334
+ const events = [...this.eventBuffer];
335
+ this.eventBuffer = [];
336
+
337
+ console.log(`[DOMTracker] Flushing ${events.length} DOM mutations`);
338
+
339
+ // Send data via callback
340
+ if (this.onDataReady) {
341
+ this.onDataReady(events);
342
+ }
343
+
344
+ // Record performance metrics
345
+ if (this.performanceMonitor) {
346
+ this.performanceMonitor.recordEvent('dom_mutations_flushed', {
347
+ count: events.length,
348
+ timestamp: Date.now()
349
+ });
350
+ }
351
+ }
352
+
353
+ getStats() {
354
+ return {
355
+ isTracking: this.isTracking,
356
+ mutationCount: this.mutationCount,
357
+ bufferSize: this.eventBuffer.length,
358
+ recordingId: this.recordingId
359
+ };
360
+ }
361
+
362
+ // Advanced filtering options
363
+ setFilters(filters) {
364
+ this.filters = {
365
+ ignoredElements: filters.ignoredElements || ['script', 'style', 'meta'],
366
+ ignoredAttributes: filters.ignoredAttributes || ['data-*', 'aria-*'],
367
+ ignoredClasses: filters.ignoredClasses || ['hover', 'active', 'focus'],
368
+ maxTextLength: filters.maxTextLength || 200,
369
+ ...filters
370
+ };
371
+ }
372
+
373
+ shouldIgnoreMutation(mutation) {
374
+ if (!this.filters) return false;
375
+
376
+ const target = mutation.target;
377
+
378
+ // Ignore certain elements
379
+ if (target.tagName && this.filters.ignoredElements.includes(target.tagName.toLowerCase())) {
380
+ return true;
381
+ }
382
+
383
+ // Ignore certain attributes
384
+ if (mutation.type === 'attributes') {
385
+ const attrName = mutation.attributeName;
386
+ for (const pattern of this.filters.ignoredAttributes) {
387
+ if (pattern.includes('*')) {
388
+ const regex = new RegExp(pattern.replace('*', '.*'));
389
+ if (regex.test(attrName)) return true;
390
+ } else if (attrName === pattern) {
391
+ return true;
392
+ }
393
+ }
394
+ }
395
+
396
+ return false;
397
+ }
398
+
399
+ destroy() {
400
+ this.stopTracking();
401
+ this.eventBuffer = [];
402
+ this.onDataReady = null;
403
+ this.piiRedactor = null;
404
+ this.performanceMonitor = null;
405
+ }
406
+ }
407
+
408
+ // Export for use in content script
409
+ if (typeof module !== 'undefined' && module.exports) {
410
+ module.exports = DOMTracker;
411
+ }
@@ -0,0 +1,78 @@
1
+ // Auto-generated configuration from Chrome Debug config
2
+ // DO NOT EDIT MANUALLY - Run 'npm run update-extension-config' to regenerate
3
+
4
+ const CHROMEDEBUG_CONFIG = {
5
+ ports: [
6
+ 3000,
7
+ 3001,
8
+ 3002,
9
+ 3028,
10
+ 3029,
11
+ 3030,
12
+ 3031,
13
+ 3032,
14
+ 3033,
15
+ 3034,
16
+ 3035,
17
+ 3036,
18
+ 8080,
19
+ 8081,
20
+ 8082,
21
+ 8083,
22
+ 8084,
23
+ 8085,
24
+ 8086,
25
+ 8087,
26
+ 8088,
27
+ 8089,
28
+ 8090,
29
+ 9000,
30
+ 9001,
31
+ 9002,
32
+ 9003,
33
+ 9004,
34
+ 9005,
35
+ 9006,
36
+ 9007,
37
+ 9008,
38
+ 9009,
39
+ 9010,
40
+ 3023,
41
+ 3003,
42
+ 3004,
43
+ 3005,
44
+ 3006,
45
+ 3007,
46
+ 3008,
47
+ 3009,
48
+ 3010,
49
+ 3011,
50
+ 3012,
51
+ 3013,
52
+ 3014,
53
+ 3015,
54
+ 3016,
55
+ 3017,
56
+ 3018,
57
+ 3019,
58
+ 3020,
59
+ 3021,
60
+ 3022,
61
+ 3024,
62
+ 3025,
63
+ 3026,
64
+ 3027
65
+ ],
66
+ discoveryTimeout: 3000,
67
+ lastGenerated: '2025-10-01T22:12:24.724Z'
68
+ };
69
+
70
+ // Export for use in extension scripts
71
+ if (typeof module !== 'undefined' && module.exports) {
72
+ module.exports = CHROMEDEBUG_CONFIG;
73
+ }
74
+
75
+ // For browser environments
76
+ if (typeof window !== 'undefined') {
77
+ window.CHROMEDEBUG_CONFIG = CHROMEDEBUG_CONFIG;
78
+ }