@dynamicu/chromedebug-mcp 2.6.7 → 2.7.1
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/CLAUDE.md +17 -1
- package/README.md +1 -1
- package/chrome-extension/activation-manager.js +10 -10
- package/chrome-extension/background.js +1045 -736
- package/chrome-extension/browser-recording-manager.js +1 -1
- package/chrome-extension/chrome-debug-logger.js +168 -0
- package/chrome-extension/chrome-session-manager.js +5 -5
- package/chrome-extension/console-interception-library.js +430 -0
- package/chrome-extension/content.css +16 -16
- package/chrome-extension/content.js +739 -221
- package/chrome-extension/data-buffer.js +5 -5
- package/chrome-extension/dom-tracker.js +9 -9
- package/chrome-extension/extension-config.js +1 -1
- package/chrome-extension/firebase-client.js +13 -13
- package/chrome-extension/frame-capture.js +20 -38
- package/chrome-extension/license-helper.js +33 -7
- package/chrome-extension/manifest.free.json +3 -6
- package/chrome-extension/network-tracker.js +9 -9
- package/chrome-extension/options.html +10 -0
- package/chrome-extension/options.js +21 -8
- package/chrome-extension/performance-monitor.js +17 -17
- package/chrome-extension/popup.html +230 -193
- package/chrome-extension/popup.js +146 -458
- package/chrome-extension/pro/enhanced-capture.js +406 -0
- package/chrome-extension/pro/frame-editor.html +433 -0
- package/chrome-extension/pro/frame-editor.js +1567 -0
- package/chrome-extension/pro/function-tracker.js +843 -0
- package/chrome-extension/pro/jszip.min.js +13 -0
- package/chrome-extension/upload-manager.js +7 -7
- package/dist/chromedebug-extension-free.zip +0 -0
- package/package.json +3 -1
- package/scripts/webpack.config.free.cjs +8 -8
- package/scripts/webpack.config.pro.cjs +2 -0
- package/src/cli.js +2 -2
- package/src/database.js +55 -7
- package/src/index.js +9 -6
- package/src/mcp/server.js +2 -2
- package/src/services/process-manager.js +10 -6
- package/src/services/process-tracker.js +10 -5
- package/src/services/profile-manager.js +17 -2
- package/src/validation/schemas.js +12 -11
- package/src/index-direct.js +0 -157
- package/src/index-modular.js +0 -219
- package/src/index-monolithic-backup.js +0 -2230
- package/src/legacy/chrome-controller-old.js +0 -1406
- package/src/legacy/index-express.js +0 -625
- package/src/legacy/index-old.js +0 -977
- package/src/legacy/routes.js +0 -260
- package/src/legacy/shared-storage.js +0 -101
|
@@ -24,7 +24,7 @@ class DataBuffer {
|
|
|
24
24
|
|
|
25
25
|
request.onsuccess = () => {
|
|
26
26
|
this.db = request.result;
|
|
27
|
-
console.log('[DataBuffer] IndexedDB initialized');
|
|
27
|
+
// console.log('[DataBuffer] IndexedDB initialized');
|
|
28
28
|
this.calculateCurrentSize();
|
|
29
29
|
resolve();
|
|
30
30
|
};
|
|
@@ -304,7 +304,7 @@ class DataBuffer {
|
|
|
304
304
|
async checkBufferLimits() {
|
|
305
305
|
// Implement FIFO circular buffer strategy
|
|
306
306
|
if (this.currentSize > this.maxBufferSize) {
|
|
307
|
-
console.log('[DataBuffer] Buffer limit exceeded, removing oldest batches');
|
|
307
|
+
// console.log('[DataBuffer] Buffer limit exceeded, removing oldest batches');
|
|
308
308
|
await this.removeOldestBatches();
|
|
309
309
|
}
|
|
310
310
|
}
|
|
@@ -329,7 +329,7 @@ class DataBuffer {
|
|
|
329
329
|
cursor.continue();
|
|
330
330
|
} else {
|
|
331
331
|
this.currentSize -= deletedSize;
|
|
332
|
-
console.log(`[DataBuffer] Freed ${deletedSize} bytes`);
|
|
332
|
+
// console.log(`[DataBuffer] Freed ${deletedSize} bytes`);
|
|
333
333
|
resolve();
|
|
334
334
|
}
|
|
335
335
|
};
|
|
@@ -367,7 +367,7 @@ class DataBuffer {
|
|
|
367
367
|
}
|
|
368
368
|
|
|
369
369
|
this.currentSize = totalSize;
|
|
370
|
-
console.log(`[DataBuffer] Current buffer size: ${(totalSize / 1024 / 1024).toFixed(2)}MB`);
|
|
370
|
+
// console.log(`[DataBuffer] Current buffer size: ${(totalSize / 1024 / 1024).toFixed(2)}MB`);
|
|
371
371
|
};
|
|
372
372
|
}
|
|
373
373
|
|
|
@@ -400,7 +400,7 @@ class DataBuffer {
|
|
|
400
400
|
return new Promise((resolve) => {
|
|
401
401
|
transaction.oncomplete = () => {
|
|
402
402
|
this.currentSize = 0;
|
|
403
|
-
console.log('[DataBuffer] Buffer cleared');
|
|
403
|
+
// console.log('[DataBuffer] Buffer cleared');
|
|
404
404
|
resolve();
|
|
405
405
|
};
|
|
406
406
|
});
|
|
@@ -33,12 +33,12 @@ class DOMTracker {
|
|
|
33
33
|
if (options.maxBufferSize) this.maxBufferSize = options.maxBufferSize;
|
|
34
34
|
if (options.mutationThrottle) this.mutationThrottle = options.mutationThrottle;
|
|
35
35
|
|
|
36
|
-
console.log('[DOMTracker] Initialized with options:', {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
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
42
|
}
|
|
43
43
|
|
|
44
44
|
startTracking() {
|
|
@@ -69,7 +69,7 @@ class DOMTracker {
|
|
|
69
69
|
this.isTracking = true;
|
|
70
70
|
this.startBufferFlusher();
|
|
71
71
|
|
|
72
|
-
console.log('[DOMTracker] Started DOM mutation tracking');
|
|
72
|
+
// console.log('[DOMTracker] Started DOM mutation tracking');
|
|
73
73
|
|
|
74
74
|
// Record performance event
|
|
75
75
|
if (this.performanceMonitor) {
|
|
@@ -96,7 +96,7 @@ class DOMTracker {
|
|
|
96
96
|
this.flushBuffer(); // Flush any remaining data
|
|
97
97
|
|
|
98
98
|
this.isTracking = false;
|
|
99
|
-
console.log('[DOMTracker] Stopped DOM mutation tracking');
|
|
99
|
+
// console.log('[DOMTracker] Stopped DOM mutation tracking');
|
|
100
100
|
|
|
101
101
|
// Record performance event
|
|
102
102
|
if (this.performanceMonitor) {
|
|
@@ -334,7 +334,7 @@ class DOMTracker {
|
|
|
334
334
|
const events = [...this.eventBuffer];
|
|
335
335
|
this.eventBuffer = [];
|
|
336
336
|
|
|
337
|
-
console.log(`[DOMTracker] Flushing ${events.length} DOM mutations`);
|
|
337
|
+
// console.log(`[DOMTracker] Flushing ${events.length} DOM mutations`);
|
|
338
338
|
|
|
339
339
|
// Send data via callback
|
|
340
340
|
if (this.onDataReady) {
|
|
@@ -12,7 +12,7 @@ class FirebaseLicenseClient {
|
|
|
12
12
|
this.functionsUrl = FUNCTIONS_URL;
|
|
13
13
|
this.cacheKey = 'chromedebug_license_cache';
|
|
14
14
|
this.instanceIdKey = 'chromedebug_instance_id';
|
|
15
|
-
console.log('[License] Initialized with FUNCTIONS_URL:', this.functionsUrl);
|
|
15
|
+
// console.log('[License] Initialized with FUNCTIONS_URL:', this.functionsUrl);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
/**
|
|
@@ -101,8 +101,8 @@ class FirebaseLicenseClient {
|
|
|
101
101
|
const deviceInfo = this.getDeviceInfo();
|
|
102
102
|
|
|
103
103
|
try {
|
|
104
|
-
console.log(`[License] Activating license ${licenseKey} with device ${deviceId}`);
|
|
105
|
-
console.log('[License] Device info:', deviceInfo);
|
|
104
|
+
// console.log(`[License] Activating license ${licenseKey} with device ${deviceId}`);
|
|
105
|
+
// console.log('[License] Device info:', deviceInfo);
|
|
106
106
|
|
|
107
107
|
const response = await fetch(`${this.functionsUrl}/activateLicense`, {
|
|
108
108
|
method: 'POST',
|
|
@@ -125,7 +125,7 @@ class FirebaseLicenseClient {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
const data = await response.json();
|
|
128
|
-
console.log('[License] Activation response:', data);
|
|
128
|
+
// console.log('[License] Activation response:', data);
|
|
129
129
|
|
|
130
130
|
// If activation successful, save the LemonSqueezy instance ID
|
|
131
131
|
if (data.activated && data.instance) {
|
|
@@ -134,7 +134,7 @@ class FirebaseLicenseClient {
|
|
|
134
134
|
'ls_license_key': licenseKey.trim(),
|
|
135
135
|
'activated_at': Date.now()
|
|
136
136
|
});
|
|
137
|
-
console.log(`[License] Saved LS instance ID: ${data.instance.id}`);
|
|
137
|
+
// console.log(`[License] Saved LS instance ID: ${data.instance.id}`);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
return data;
|
|
@@ -161,7 +161,7 @@ class FirebaseLicenseClient {
|
|
|
161
161
|
|
|
162
162
|
// If no instance ID yet, this license needs activation first
|
|
163
163
|
if (!instanceId) {
|
|
164
|
-
console.log('[License] No instance ID found - activating license first');
|
|
164
|
+
// console.log('[License] No instance ID found - activating license first');
|
|
165
165
|
const activationResult = await this.activateLicense(licenseKey);
|
|
166
166
|
|
|
167
167
|
if (!activationResult.activated) {
|
|
@@ -197,7 +197,7 @@ class FirebaseLicenseClient {
|
|
|
197
197
|
* @returns {Promise<{valid: boolean, tier?: string}>}
|
|
198
198
|
*/
|
|
199
199
|
async validateWithInstanceId(licenseKey, instanceId) {
|
|
200
|
-
console.log(`[License] Validating ${licenseKey} with instance ${instanceId}`);
|
|
200
|
+
// console.log(`[License] Validating ${licenseKey} with instance ${instanceId}`);
|
|
201
201
|
|
|
202
202
|
const response = await fetch(`${this.functionsUrl}/validateLicense`, {
|
|
203
203
|
method: 'POST',
|
|
@@ -210,7 +210,7 @@ class FirebaseLicenseClient {
|
|
|
210
210
|
}
|
|
211
211
|
|
|
212
212
|
const data = await response.json();
|
|
213
|
-
console.log('[License] Validation response:', data);
|
|
213
|
+
// console.log('[License] Validation response:', data);
|
|
214
214
|
|
|
215
215
|
// Map LemonSqueezy response to our format
|
|
216
216
|
const result = {
|
|
@@ -249,7 +249,7 @@ class FirebaseLicenseClient {
|
|
|
249
249
|
|
|
250
250
|
const url = `${this.functionsUrl}/checkUsageLimit`;
|
|
251
251
|
try {
|
|
252
|
-
console.log('[License] Calling checkUsageLimit at:', url);
|
|
252
|
+
// console.log('[License] Calling checkUsageLimit at:', url);
|
|
253
253
|
const response = await fetch(url, {
|
|
254
254
|
method: 'POST',
|
|
255
255
|
headers: {'Content-Type': 'application/json'},
|
|
@@ -351,7 +351,7 @@ class FirebaseLicenseClient {
|
|
|
351
351
|
*/
|
|
352
352
|
async listActivations(licenseKey) {
|
|
353
353
|
try {
|
|
354
|
-
console.log(`[License] Listing activations for ${licenseKey}`);
|
|
354
|
+
// console.log(`[License] Listing activations for ${licenseKey}`);
|
|
355
355
|
|
|
356
356
|
const response = await fetch(`${this.functionsUrl}/listActivations`, {
|
|
357
357
|
method: 'POST',
|
|
@@ -365,7 +365,7 @@ class FirebaseLicenseClient {
|
|
|
365
365
|
}
|
|
366
366
|
|
|
367
367
|
const data = await response.json();
|
|
368
|
-
console.log('[License] Activations:', data);
|
|
368
|
+
// console.log('[License] Activations:', data);
|
|
369
369
|
|
|
370
370
|
return data;
|
|
371
371
|
} catch (error) {
|
|
@@ -382,7 +382,7 @@ class FirebaseLicenseClient {
|
|
|
382
382
|
*/
|
|
383
383
|
async deactivateInstance(licenseKey, instanceId) {
|
|
384
384
|
try {
|
|
385
|
-
console.log(`[License] Deactivating instance ${instanceId}`);
|
|
385
|
+
// console.log(`[License] Deactivating instance ${instanceId}`);
|
|
386
386
|
|
|
387
387
|
const response = await fetch(`${this.functionsUrl}/deactivateInstance`, {
|
|
388
388
|
method: 'POST',
|
|
@@ -399,7 +399,7 @@ class FirebaseLicenseClient {
|
|
|
399
399
|
}
|
|
400
400
|
|
|
401
401
|
const data = await response.json();
|
|
402
|
-
console.log('[License] Deactivation result:', data);
|
|
402
|
+
// console.log('[License] Deactivation result:', data);
|
|
403
403
|
|
|
404
404
|
return data;
|
|
405
405
|
} catch (error) {
|
|
@@ -30,7 +30,6 @@ class FrameCapture {
|
|
|
30
30
|
this.mode = 'server';
|
|
31
31
|
} else {
|
|
32
32
|
this.mode = mode;
|
|
33
|
-
console.log('[FrameCapture] Mode set to:', this.mode);
|
|
34
33
|
}
|
|
35
34
|
}
|
|
36
35
|
|
|
@@ -46,8 +45,15 @@ class FrameCapture {
|
|
|
46
45
|
this.isCapturing = true;
|
|
47
46
|
this.tabId = tabId;
|
|
48
47
|
|
|
49
|
-
// Initialize lease tracking -
|
|
50
|
-
this.lastLeaseCheck =
|
|
48
|
+
// Initialize lease tracking - set to now so first check happens after interval
|
|
49
|
+
this.lastLeaseCheck = Date.now();
|
|
50
|
+
|
|
51
|
+
// Emergency max duration timer (belt and suspenders - 1 hour hard stop)
|
|
52
|
+
this.emergencyMaxDuration = 60 * 60 * 1000; // 1 hour absolute max
|
|
53
|
+
this.emergencyTimer = setTimeout(() => {
|
|
54
|
+
console.error('[FrameCapture] EMERGENCY: Absolute max duration (1 hour) reached - force stopping');
|
|
55
|
+
this.stopCapture();
|
|
56
|
+
}, this.emergencyMaxDuration);
|
|
51
57
|
|
|
52
58
|
// Update settings with passed values or apply mode-specific defaults
|
|
53
59
|
if (this.mode === 'browser-only') {
|
|
@@ -66,17 +72,11 @@ class FrameCapture {
|
|
|
66
72
|
};
|
|
67
73
|
}
|
|
68
74
|
|
|
69
|
-
console.log('Starting frame capture session:', this.sessionId);
|
|
70
|
-
console.log('Frame capture scheduled to start at:', new Date(scheduledStartTime));
|
|
71
|
-
console.log('Frame capture settings:', this.settings);
|
|
72
|
-
|
|
73
75
|
// Trigger visual feedback system start
|
|
74
76
|
chrome.runtime.sendMessage({
|
|
75
77
|
type: 'start-screen-capture-tracking',
|
|
76
78
|
sessionId: this.sessionId
|
|
77
|
-
}).catch(() => {
|
|
78
|
-
console.log('[FrameCapture] Could not start visual feedback tracking');
|
|
79
|
-
});
|
|
79
|
+
}).catch(() => {});
|
|
80
80
|
|
|
81
81
|
// Create a synthetic first frame at scheduled start time to catch early logs
|
|
82
82
|
const syntheticFrame = {
|
|
@@ -87,7 +87,6 @@ class FrameCapture {
|
|
|
87
87
|
};
|
|
88
88
|
this.frames.push(syntheticFrame);
|
|
89
89
|
this.totalFramesCaptured++;
|
|
90
|
-
console.log('Created synthetic first frame at scheduled start time');
|
|
91
90
|
|
|
92
91
|
// Get the media stream with resolution based on mode
|
|
93
92
|
const videoConstraints = this.mode === 'browser-only'
|
|
@@ -142,10 +141,8 @@ class FrameCapture {
|
|
|
142
141
|
|
|
143
142
|
// Wait until scheduled start time before beginning frame capture
|
|
144
143
|
const waitTime = Math.max(0, this.scheduledStartTime - Date.now());
|
|
145
|
-
console.log(`Frame capture will wait ${waitTime}ms until scheduled start time`);
|
|
146
144
|
|
|
147
145
|
setTimeout(() => {
|
|
148
|
-
console.log('Frame capture starting at scheduled time');
|
|
149
146
|
|
|
150
147
|
// Capture frames at intervals (e.g., 1 frame per second)
|
|
151
148
|
this.captureInterval = setInterval(async () => {
|
|
@@ -155,7 +152,6 @@ class FrameCapture {
|
|
|
155
152
|
if (this.lastLeaseCheck && (Date.now() - this.lastLeaseCheck) > this.leaseCheckInterval) {
|
|
156
153
|
const leaseValid = await this.checkLease();
|
|
157
154
|
if (!leaseValid) {
|
|
158
|
-
console.log('[FrameCapture] Lease expired, stopping capture');
|
|
159
155
|
this.stopCapture();
|
|
160
156
|
return;
|
|
161
157
|
}
|
|
@@ -181,15 +177,11 @@ class FrameCapture {
|
|
|
181
177
|
|
|
182
178
|
this.frames.push(frameData);
|
|
183
179
|
this.totalFramesCaptured++;
|
|
184
|
-
|
|
185
|
-
console.log(`Captured frame ${this.totalFramesCaptured}, size: ${blob.size} bytes`);
|
|
186
180
|
|
|
187
181
|
// Trigger visual feedback for frame captured
|
|
188
182
|
chrome.runtime.sendMessage({
|
|
189
183
|
type: 'show-screen-capture-flash'
|
|
190
|
-
}).catch(() => {
|
|
191
|
-
console.log('[FrameCapture] Could not trigger frame capture flash');
|
|
192
|
-
});
|
|
184
|
+
}).catch(() => {});
|
|
193
185
|
|
|
194
186
|
// Send frame immediately to keep memory usage low
|
|
195
187
|
if (this.frames.length % 5 === 0) { // Every 5 frames
|
|
@@ -207,9 +199,6 @@ class FrameCapture {
|
|
|
207
199
|
}
|
|
208
200
|
}, this.settings.frameRate * 1000); // Use configurable frame rate
|
|
209
201
|
|
|
210
|
-
console.log(`Frame capture interval set to ${this.settings.frameRate * 1000}ms (${this.settings.frameRate}s)`);
|
|
211
|
-
console.log(`Image quality set to ${this.settings.imageQuality}%`);
|
|
212
|
-
|
|
213
202
|
// Store the media stream for cleanup
|
|
214
203
|
this.mediaStream = media;
|
|
215
204
|
this.videoElement = video;
|
|
@@ -219,8 +208,6 @@ class FrameCapture {
|
|
|
219
208
|
|
|
220
209
|
// Check lease validity with background script
|
|
221
210
|
async checkLease() {
|
|
222
|
-
console.log('[FrameCapture] Lease check starting - SessionId:', this.sessionId);
|
|
223
|
-
|
|
224
211
|
try {
|
|
225
212
|
const response = await Promise.race([
|
|
226
213
|
chrome.runtime.sendMessage({
|
|
@@ -235,7 +222,6 @@ class FrameCapture {
|
|
|
235
222
|
)
|
|
236
223
|
]);
|
|
237
224
|
|
|
238
|
-
console.log('[FrameCapture] Lease response - Success:', response?.success);
|
|
239
225
|
return response?.success === true;
|
|
240
226
|
|
|
241
227
|
} catch (error) {
|
|
@@ -251,6 +237,12 @@ class FrameCapture {
|
|
|
251
237
|
|
|
252
238
|
this.isCapturing = false;
|
|
253
239
|
|
|
240
|
+
// Clear emergency max duration timer
|
|
241
|
+
if (this.emergencyTimer) {
|
|
242
|
+
clearTimeout(this.emergencyTimer);
|
|
243
|
+
this.emergencyTimer = null;
|
|
244
|
+
}
|
|
245
|
+
|
|
254
246
|
// Stop interval
|
|
255
247
|
if (this.captureInterval) {
|
|
256
248
|
clearInterval(this.captureInterval);
|
|
@@ -275,9 +267,7 @@ class FrameCapture {
|
|
|
275
267
|
// Stop visual feedback system
|
|
276
268
|
chrome.runtime.sendMessage({
|
|
277
269
|
type: 'stop-screen-capture-tracking'
|
|
278
|
-
}).catch(() => {
|
|
279
|
-
console.log('[FrameCapture] Could not stop visual feedback tracking');
|
|
280
|
-
});
|
|
270
|
+
}).catch(() => {});
|
|
281
271
|
|
|
282
272
|
// Notify completion
|
|
283
273
|
chrome.runtime.sendMessage({
|
|
@@ -290,7 +280,6 @@ class FrameCapture {
|
|
|
290
280
|
}
|
|
291
281
|
});
|
|
292
282
|
|
|
293
|
-
console.log('Frame capture stopped');
|
|
294
283
|
}
|
|
295
284
|
|
|
296
285
|
// Flash indicator method to show when frames are captured
|
|
@@ -315,9 +304,7 @@ class FrameCapture {
|
|
|
315
304
|
if (!this.videoElement || !this.videoElement.videoWidth) {
|
|
316
305
|
throw new Error('Video element not ready for manual snapshot');
|
|
317
306
|
}
|
|
318
|
-
|
|
319
|
-
console.log('Taking manual snapshot...');
|
|
320
|
-
|
|
307
|
+
|
|
321
308
|
// Create a temporary canvas for the manual snapshot
|
|
322
309
|
const canvas = document.createElement('canvas');
|
|
323
310
|
const ctx = canvas.getContext('2d');
|
|
@@ -348,15 +335,11 @@ class FrameCapture {
|
|
|
348
335
|
|
|
349
336
|
this.frames.push(frameData);
|
|
350
337
|
this.totalFramesCaptured++;
|
|
351
|
-
|
|
352
|
-
console.log(`Manual snapshot captured: frame ${this.totalFramesCaptured}, size: ${blob.size} bytes`);
|
|
353
338
|
|
|
354
339
|
// Trigger visual feedback for manual snapshot
|
|
355
340
|
chrome.runtime.sendMessage({
|
|
356
341
|
type: 'show-screen-capture-flash'
|
|
357
|
-
}).catch(() => {
|
|
358
|
-
console.log('[FrameCapture] Could not trigger manual snapshot flash');
|
|
359
|
-
});
|
|
342
|
+
}).catch(() => {});
|
|
360
343
|
|
|
361
344
|
// Flash indicator for manual snapshot
|
|
362
345
|
if (this.settings.frameFlash) {
|
|
@@ -395,7 +378,6 @@ class FrameCapture {
|
|
|
395
378
|
});
|
|
396
379
|
|
|
397
380
|
const batch = this.frames.splice(0, 5); // Send up to 5 frames at a time
|
|
398
|
-
console.log(`[FrameCapture] Sending batch of ${batch.length} frames, ${this.frames.length} remaining`);
|
|
399
381
|
|
|
400
382
|
chrome.runtime.sendMessage({
|
|
401
383
|
type: 'frame-batch-ready',
|
|
@@ -12,12 +12,27 @@ const LicenseHelper = {
|
|
|
12
12
|
instanceIdKey: 'chromedebug_instance_id',
|
|
13
13
|
userIdKey: 'chromedebug_user_id',
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Check if this is the PRO version by checking the manifest
|
|
17
|
+
* @returns {boolean} True if PRO version
|
|
18
|
+
*/
|
|
19
|
+
isProVersion() {
|
|
20
|
+
const manifest = chrome.runtime.getManifest();
|
|
21
|
+
return manifest.name.includes('PRO');
|
|
22
|
+
},
|
|
23
|
+
|
|
15
24
|
/**
|
|
16
25
|
* Check if user can start a recording (license + usage limit check)
|
|
17
26
|
* @returns {Promise<{allowed: boolean, message?: string, tier?: string}>}
|
|
18
27
|
*/
|
|
19
28
|
async checkLicenseBeforeRecording() {
|
|
20
29
|
try {
|
|
30
|
+
// PRO version: always allow, no restrictions
|
|
31
|
+
if (this.isProVersion()) {
|
|
32
|
+
// console.log('[License] PRO version - bypassing all license checks');
|
|
33
|
+
return {allowed: true, tier: 'pro', proVersion: true};
|
|
34
|
+
}
|
|
35
|
+
|
|
21
36
|
// Get userId
|
|
22
37
|
const stored = await chrome.storage.local.get(this.userIdKey);
|
|
23
38
|
let userId = stored[this.userIdKey];
|
|
@@ -26,7 +41,7 @@ const LicenseHelper = {
|
|
|
26
41
|
// First time user - allow recording, create userId
|
|
27
42
|
userId = crypto.randomUUID();
|
|
28
43
|
await chrome.storage.local.set({[this.userIdKey]: userId});
|
|
29
|
-
console.log('[License] New user created:', userId);
|
|
44
|
+
// console.log('[License] New user created:', userId);
|
|
30
45
|
return {allowed: true, firstTime: true, userId: userId};
|
|
31
46
|
}
|
|
32
47
|
|
|
@@ -34,13 +49,13 @@ const LicenseHelper = {
|
|
|
34
49
|
const licenseStatus = await this.getCachedLicenseStatus();
|
|
35
50
|
|
|
36
51
|
if (licenseStatus.valid && licenseStatus.tier === 'pro') {
|
|
37
|
-
console.log('[License] Pro user - allowing recording');
|
|
52
|
+
// console.log('[License] Pro user - allowing recording');
|
|
38
53
|
return {allowed: true, tier: 'pro', userId: userId};
|
|
39
54
|
}
|
|
40
55
|
|
|
41
56
|
// Free tier - check usage limit
|
|
42
57
|
const usage = await this.checkUsageLimit(userId);
|
|
43
|
-
console.log('[License] Usage check:', usage);
|
|
58
|
+
// console.log('[License] Usage check:', usage);
|
|
44
59
|
|
|
45
60
|
// Handle both API response format (withinLimit) and offline format (allowed)
|
|
46
61
|
const withinLimit = usage.withinLimit ?? usage.allowed ?? true;
|
|
@@ -70,6 +85,12 @@ const LicenseHelper = {
|
|
|
70
85
|
*/
|
|
71
86
|
async trackUsageAfterRecording(userId) {
|
|
72
87
|
try {
|
|
88
|
+
// PRO version: skip all usage tracking
|
|
89
|
+
if (this.isProVersion()) {
|
|
90
|
+
// console.log('[License] PRO version - skipping usage tracking');
|
|
91
|
+
return {success: true, tier: 'pro', proVersion: true, skipped: true};
|
|
92
|
+
}
|
|
93
|
+
|
|
73
94
|
if (!userId) {
|
|
74
95
|
const stored = await chrome.storage.local.get(this.userIdKey);
|
|
75
96
|
userId = stored[this.userIdKey];
|
|
@@ -83,13 +104,13 @@ const LicenseHelper = {
|
|
|
83
104
|
// Check if pro user (don't increment for pro)
|
|
84
105
|
const licenseStatus = await this.getCachedLicenseStatus();
|
|
85
106
|
if (licenseStatus.valid && licenseStatus.tier === 'pro') {
|
|
86
|
-
console.log('[License] Pro user - skipping usage increment');
|
|
107
|
+
// console.log('[License] Pro user - skipping usage increment');
|
|
87
108
|
return {success: true, tier: 'pro', skipped: true};
|
|
88
109
|
}
|
|
89
110
|
|
|
90
111
|
// Increment usage for free tier
|
|
91
112
|
await this.incrementUsage(userId);
|
|
92
|
-
console.log('[License] Usage incremented for user:', userId);
|
|
113
|
+
// console.log('[License] Usage incremented for user:', userId);
|
|
93
114
|
|
|
94
115
|
return {success: true};
|
|
95
116
|
} catch (error) {
|
|
@@ -106,8 +127,8 @@ const LicenseHelper = {
|
|
|
106
127
|
async checkUsageLimit(userId) {
|
|
107
128
|
try {
|
|
108
129
|
const url = `${FUNCTIONS_URL}/checkUsageLimit`;
|
|
109
|
-
console.log('[License Helper] FUNCTIONS_URL:', FUNCTIONS_URL);
|
|
110
|
-
console.log('[License Helper] Full URL:', url);
|
|
130
|
+
// console.log('[License Helper] FUNCTIONS_URL:', FUNCTIONS_URL);
|
|
131
|
+
// console.log('[License Helper] Full URL:', url);
|
|
111
132
|
const response = await fetch(url, {
|
|
112
133
|
method: 'POST',
|
|
113
134
|
headers: {'Content-Type': 'application/json'},
|
|
@@ -155,6 +176,11 @@ const LicenseHelper = {
|
|
|
155
176
|
* @returns {Promise<{valid: boolean, tier?: string}>}
|
|
156
177
|
*/
|
|
157
178
|
async getCachedLicenseStatus() {
|
|
179
|
+
// PRO version: always return pro tier
|
|
180
|
+
if (this.isProVersion()) {
|
|
181
|
+
return {valid: true, tier: 'pro', proVersion: true};
|
|
182
|
+
}
|
|
183
|
+
|
|
158
184
|
const result = await chrome.storage.local.get(this.cacheKey);
|
|
159
185
|
const cached = result[this.cacheKey];
|
|
160
186
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"manifest_version": 3,
|
|
3
|
-
"name": "ChromeDebug MCP Assistant FREE
|
|
4
|
-
"version": "2.
|
|
5
|
-
"description": "
|
|
3
|
+
"name": "ChromeDebug MCP Assistant FREE",
|
|
4
|
+
"version": "2.7.1",
|
|
5
|
+
"description": "AI-powered browser debugging with visual element selection and screen recording for developers",
|
|
6
6
|
"permissions": [
|
|
7
7
|
"activeTab",
|
|
8
8
|
"scripting",
|
|
@@ -12,9 +12,6 @@
|
|
|
12
12
|
"notifications",
|
|
13
13
|
"offscreen"
|
|
14
14
|
],
|
|
15
|
-
"host_permissions": [
|
|
16
|
-
"https://*.cloudfunctions.net/*"
|
|
17
|
-
],
|
|
18
15
|
"action": {
|
|
19
16
|
"default_popup": "popup.html",
|
|
20
17
|
"default_icon": {
|
|
@@ -36,12 +36,12 @@ class NetworkTracker {
|
|
|
36
36
|
if (options.maxBodySize) this.maxBodySize = options.maxBodySize;
|
|
37
37
|
if (options.bufferFlushDelay) this.bufferFlushDelay = options.bufferFlushDelay;
|
|
38
38
|
|
|
39
|
-
console.log('[NetworkTracker] Initialized with options:', {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
});
|
|
39
|
+
// console.log('[NetworkTracker] Initialized with options:', {
|
|
40
|
+
// recordingId: this.recordingId,
|
|
41
|
+
// captureRequestBody: this.captureRequestBody,
|
|
42
|
+
// captureResponseBody: this.captureResponseBody,
|
|
43
|
+
// maxBodySize: this.maxBodySize
|
|
44
|
+
// });
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
startTracking() {
|
|
@@ -57,7 +57,7 @@ class NetworkTracker {
|
|
|
57
57
|
this.isTracking = true;
|
|
58
58
|
this.startBufferFlusher();
|
|
59
59
|
|
|
60
|
-
console.log('[NetworkTracker] Started network request tracking');
|
|
60
|
+
// console.log('[NetworkTracker] Started network request tracking');
|
|
61
61
|
|
|
62
62
|
// Record performance event
|
|
63
63
|
if (this.performanceMonitor) {
|
|
@@ -81,7 +81,7 @@ class NetworkTracker {
|
|
|
81
81
|
this.flushBuffer(); // Flush any remaining data
|
|
82
82
|
|
|
83
83
|
this.isTracking = false;
|
|
84
|
-
console.log('[NetworkTracker] Stopped network request tracking');
|
|
84
|
+
// console.log('[NetworkTracker] Stopped network request tracking');
|
|
85
85
|
|
|
86
86
|
// Record performance event
|
|
87
87
|
if (this.performanceMonitor) {
|
|
@@ -472,7 +472,7 @@ class NetworkTracker {
|
|
|
472
472
|
const events = [...this.eventBuffer];
|
|
473
473
|
this.eventBuffer = [];
|
|
474
474
|
|
|
475
|
-
console.log(`[NetworkTracker] Flushing ${events.length} network requests`);
|
|
475
|
+
// console.log(`[NetworkTracker] Flushing ${events.length} network requests`);
|
|
476
476
|
|
|
477
477
|
// Send data via callback
|
|
478
478
|
if (this.onDataReady) {
|
|
@@ -152,6 +152,16 @@
|
|
|
152
152
|
Leave empty for automatic port discovery. The server typically runs on port 3000.
|
|
153
153
|
</div>
|
|
154
154
|
</div>
|
|
155
|
+
|
|
156
|
+
<div class="setting-group">
|
|
157
|
+
<h3>Recording Safety</h3>
|
|
158
|
+
<label for="inactivity-timeout">Auto-Stop After Inactivity (seconds)</label>
|
|
159
|
+
<input type="number" id="inactivity-timeout" min="5" max="3600" value="10">
|
|
160
|
+
<div class="help-text">
|
|
161
|
+
Screen recording will automatically stop if no mouse or keyboard activity is detected.
|
|
162
|
+
Default: 10 seconds. Increase for long demo recordings or presentations.
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
155
165
|
|
|
156
166
|
<div class="setting-group">
|
|
157
167
|
<label>Server Status</label>
|
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
const DEFAULT_PORTS = CHROMEDEBUG_CONFIG?.ports?.slice(0, 8) || [3001, 3000, 3002, 3028];
|
|
5
5
|
|
|
6
6
|
// Load saved settings
|
|
7
|
-
chrome.storage.sync.get(['serverPort', 'chromePilotMode', 'chromePilotAllowedSites', 'chromePilotRestrictedSites'], (data) => {
|
|
7
|
+
chrome.storage.sync.get(['serverPort', 'chromePilotMode', 'chromePilotAllowedSites', 'chromePilotRestrictedSites', 'inactivityTimeout'], (data) => {
|
|
8
8
|
if (data.serverPort) {
|
|
9
9
|
document.getElementById('server-port').value = data.serverPort;
|
|
10
10
|
}
|
|
11
|
+
|
|
12
|
+
// Load inactivity timeout (default 10 seconds)
|
|
13
|
+
document.getElementById('inactivity-timeout').value = data.inactivityTimeout || 10;
|
|
11
14
|
|
|
12
15
|
// Load site restriction settings
|
|
13
16
|
const mode = data.chromePilotMode || 'whitelist';
|
|
@@ -32,7 +35,15 @@ document.getElementById('save').addEventListener('click', async () => {
|
|
|
32
35
|
showStatus('error', 'Port must be between 1024 and 65535');
|
|
33
36
|
return;
|
|
34
37
|
}
|
|
35
|
-
|
|
38
|
+
|
|
39
|
+
// Get inactivity timeout
|
|
40
|
+
const inactivityTimeoutInput = document.getElementById('inactivity-timeout');
|
|
41
|
+
const inactivityTimeout = parseInt(inactivityTimeoutInput.value) || 10;
|
|
42
|
+
if (inactivityTimeout < 5 || inactivityTimeout > 3600) {
|
|
43
|
+
showStatus('error', 'Inactivity timeout must be between 5 and 3600 seconds');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
36
47
|
// Get site restriction settings
|
|
37
48
|
const mode = document.querySelector('input[name="site-mode"]:checked').value;
|
|
38
49
|
const allowedSites = document.getElementById('allowed-sites').value
|
|
@@ -44,24 +55,26 @@ document.getElementById('save').addEventListener('click', async () => {
|
|
|
44
55
|
.map(s => s.trim())
|
|
45
56
|
.filter(s => s.length > 0);
|
|
46
57
|
|
|
47
|
-
await chrome.storage.sync.set({
|
|
58
|
+
await chrome.storage.sync.set({
|
|
48
59
|
serverPort: port,
|
|
49
60
|
chromePilotMode: mode,
|
|
50
61
|
chromePilotAllowedSites: allowedSites,
|
|
51
|
-
chromePilotRestrictedSites: restrictedSites
|
|
62
|
+
chromePilotRestrictedSites: restrictedSites,
|
|
63
|
+
inactivityTimeout: inactivityTimeout
|
|
52
64
|
});
|
|
53
|
-
showStatus('success', 'Settings saved successfully. Reload tabs to apply
|
|
65
|
+
showStatus('success', 'Settings saved successfully. Reload tabs to apply changes.');
|
|
54
66
|
});
|
|
55
67
|
|
|
56
68
|
// Reset to default
|
|
57
69
|
document.getElementById('reset').addEventListener('click', async () => {
|
|
58
70
|
document.getElementById('server-port').value = '';
|
|
71
|
+
document.getElementById('inactivity-timeout').value = '10';
|
|
59
72
|
document.querySelector('input[value="whitelist"]').checked = true;
|
|
60
73
|
document.getElementById('allowed-sites').value = 'localhost:*\n127.0.0.1:*\n*.local\n*.test\n*.dev';
|
|
61
74
|
document.getElementById('blocked-sites').value = 'youtube.com\n*.youtube.com\ngoogle.com\n*.google.com\nfacebook.com\ntwitter.com\nx.com';
|
|
62
75
|
updateSiteMode();
|
|
63
|
-
|
|
64
|
-
await chrome.storage.sync.remove(['serverPort', 'chromePilotMode', 'chromePilotAllowedSites', 'chromePilotRestrictedSites']);
|
|
76
|
+
|
|
77
|
+
await chrome.storage.sync.remove(['serverPort', 'chromePilotMode', 'chromePilotAllowedSites', 'chromePilotRestrictedSites', 'inactivityTimeout']);
|
|
65
78
|
showStatus('info', 'Settings reset to default');
|
|
66
79
|
});
|
|
67
80
|
|
|
@@ -217,7 +230,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
217
230
|
|
|
218
231
|
const a = document.createElement('a');
|
|
219
232
|
a.href = url;
|
|
220
|
-
a.download = 'chrome-
|
|
233
|
+
a.download = 'chrome-debug-site-settings.json';
|
|
221
234
|
a.click();
|
|
222
235
|
|
|
223
236
|
URL.revokeObjectURL(url);
|