@dynamicu/chromedebug-mcp 2.6.6 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -1
- package/README.md +1 -1
- package/chrome-extension/activation-manager.js +18 -4
- package/chrome-extension/background.js +1044 -552
- package/chrome-extension/browser-recording-manager.js +256 -0
- package/chrome-extension/chrome-debug-logger.js +168 -0
- package/chrome-extension/console-interception-library.js +430 -0
- package/chrome-extension/content.css +16 -16
- package/chrome-extension/content.js +617 -215
- package/chrome-extension/data-buffer.js +206 -17
- package/chrome-extension/extension-config.js +1 -1
- package/chrome-extension/frame-capture.js +52 -15
- package/chrome-extension/license-helper.js +26 -0
- package/chrome-extension/manifest.free.json +3 -6
- package/chrome-extension/options.js +1 -1
- package/chrome-extension/popup.html +315 -181
- package/chrome-extension/popup.js +673 -526
- package/chrome-extension/pro/enhanced-capture.js +406 -0
- package/chrome-extension/pro/frame-editor.html +410 -0
- package/chrome-extension/pro/frame-editor.js +1496 -0
- package/chrome-extension/pro/function-tracker.js +843 -0
- package/chrome-extension/pro/jszip.min.js +13 -0
- package/config/chromedebug-config.json +101 -0
- package/dist/chromedebug-extension-free.zip +0 -0
- package/package.json +3 -1
- package/scripts/package-pro-extension.js +1 -1
- package/scripts/webpack.config.free.cjs +11 -8
- package/scripts/webpack.config.pro.cjs +5 -0
- package/src/chrome-controller.js +7 -7
- package/src/cli.js +2 -2
- package/src/database.js +61 -9
- package/src/http-server.js +3 -2
- 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 +36 -6
- 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
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
class DataBuffer {
|
|
5
5
|
constructor() {
|
|
6
6
|
this.dbName = 'ChromePilotDataBuffer';
|
|
7
|
-
this.version =
|
|
7
|
+
this.version = 2; // Incremented for new object stores
|
|
8
8
|
this.db = null;
|
|
9
9
|
this.maxBufferSize = 100 * 1024 * 1024; // 100MB default
|
|
10
10
|
this.currentSize = 0;
|
|
@@ -31,30 +31,48 @@ class DataBuffer {
|
|
|
31
31
|
|
|
32
32
|
request.onupgradeneeded = (event) => {
|
|
33
33
|
const db = event.target.result;
|
|
34
|
-
|
|
34
|
+
|
|
35
35
|
// Create object stores if they don't exist
|
|
36
36
|
if (!db.objectStoreNames.contains('events')) {
|
|
37
|
-
const eventsStore = db.createObjectStore('events', {
|
|
38
|
-
keyPath: 'id',
|
|
39
|
-
autoIncrement: true
|
|
37
|
+
const eventsStore = db.createObjectStore('events', {
|
|
38
|
+
keyPath: 'id',
|
|
39
|
+
autoIncrement: true
|
|
40
40
|
});
|
|
41
41
|
eventsStore.createIndex('timestamp', 'timestamp', { unique: false });
|
|
42
42
|
eventsStore.createIndex('type', 'type', { unique: false });
|
|
43
43
|
eventsStore.createIndex('recording_id', 'recording_id', { unique: false });
|
|
44
44
|
}
|
|
45
|
-
|
|
45
|
+
|
|
46
46
|
if (!db.objectStoreNames.contains('batches')) {
|
|
47
|
-
const batchesStore = db.createObjectStore('batches', {
|
|
48
|
-
keyPath: 'id',
|
|
49
|
-
autoIncrement: true
|
|
47
|
+
const batchesStore = db.createObjectStore('batches', {
|
|
48
|
+
keyPath: 'id',
|
|
49
|
+
autoIncrement: true
|
|
50
50
|
});
|
|
51
51
|
batchesStore.createIndex('timestamp', 'timestamp', { unique: false });
|
|
52
52
|
batchesStore.createIndex('status', 'status', { unique: false });
|
|
53
53
|
}
|
|
54
|
-
|
|
54
|
+
|
|
55
55
|
if (!db.objectStoreNames.contains('metadata')) {
|
|
56
56
|
db.createObjectStore('metadata', { keyPath: 'key' });
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
// New object stores for browser-only recording mode
|
|
60
|
+
if (!db.objectStoreNames.contains('browser_recordings')) {
|
|
61
|
+
const recordingsStore = db.createObjectStore('browser_recordings', {
|
|
62
|
+
keyPath: 'sessionId'
|
|
63
|
+
});
|
|
64
|
+
recordingsStore.createIndex('timestamp', 'startTime', { unique: false });
|
|
65
|
+
recordingsStore.createIndex('status', 'status', { unique: false });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!db.objectStoreNames.contains('browser_frames')) {
|
|
69
|
+
const framesStore = db.createObjectStore('browser_frames', {
|
|
70
|
+
keyPath: 'id',
|
|
71
|
+
autoIncrement: true
|
|
72
|
+
});
|
|
73
|
+
framesStore.createIndex('sessionId', 'sessionId', { unique: false });
|
|
74
|
+
framesStore.createIndex('frameIndex', 'frameIndex', { unique: false });
|
|
75
|
+
}
|
|
58
76
|
};
|
|
59
77
|
});
|
|
60
78
|
}
|
|
@@ -390,11 +408,11 @@ class DataBuffer {
|
|
|
390
408
|
|
|
391
409
|
async getStats() {
|
|
392
410
|
if (!this.db) await this.init();
|
|
393
|
-
|
|
411
|
+
|
|
394
412
|
const transaction = this.db.transaction(['events', 'batches'], 'readonly');
|
|
395
413
|
const eventsStore = transaction.objectStore('events');
|
|
396
414
|
const batchesStore = transaction.objectStore('batches');
|
|
397
|
-
|
|
415
|
+
|
|
398
416
|
return new Promise((resolve) => {
|
|
399
417
|
let stats = {
|
|
400
418
|
eventCount: 0,
|
|
@@ -404,29 +422,200 @@ class DataBuffer {
|
|
|
404
422
|
totalSize: this.currentSize,
|
|
405
423
|
maxSize: this.maxBufferSize
|
|
406
424
|
};
|
|
407
|
-
|
|
425
|
+
|
|
408
426
|
eventsStore.count().onsuccess = (e) => {
|
|
409
427
|
stats.eventCount = e.target.result;
|
|
410
428
|
};
|
|
411
|
-
|
|
429
|
+
|
|
412
430
|
batchesStore.count().onsuccess = (e) => {
|
|
413
431
|
stats.batchCount = e.target.result;
|
|
414
432
|
};
|
|
415
|
-
|
|
433
|
+
|
|
416
434
|
const pendingIndex = batchesStore.index('status');
|
|
417
435
|
pendingIndex.count(IDBKeyRange.only('pending')).onsuccess = (e) => {
|
|
418
436
|
stats.pendingBatches = e.target.result;
|
|
419
437
|
};
|
|
420
|
-
|
|
438
|
+
|
|
421
439
|
pendingIndex.count(IDBKeyRange.only('uploaded')).onsuccess = (e) => {
|
|
422
440
|
stats.uploadedBatches = e.target.result;
|
|
423
441
|
};
|
|
424
|
-
|
|
442
|
+
|
|
425
443
|
transaction.oncomplete = () => {
|
|
426
444
|
resolve(stats);
|
|
427
445
|
};
|
|
428
446
|
});
|
|
429
447
|
}
|
|
448
|
+
|
|
449
|
+
// Browser-only recording methods
|
|
450
|
+
async addBrowserRecording(recording) {
|
|
451
|
+
if (!this.db) await this.init();
|
|
452
|
+
const transaction = this.db.transaction(['browser_recordings'], 'readwrite');
|
|
453
|
+
const store = transaction.objectStore('browser_recordings');
|
|
454
|
+
|
|
455
|
+
return new Promise((resolve, reject) => {
|
|
456
|
+
const request = store.add(recording);
|
|
457
|
+
request.onsuccess = () => resolve(request.result);
|
|
458
|
+
request.onerror = () => reject(request.error);
|
|
459
|
+
});
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
async updateBrowserRecording(sessionId, updates) {
|
|
463
|
+
if (!this.db) await this.init();
|
|
464
|
+
const transaction = this.db.transaction(['browser_recordings'], 'readwrite');
|
|
465
|
+
const store = transaction.objectStore('browser_recordings');
|
|
466
|
+
|
|
467
|
+
return new Promise((resolve, reject) => {
|
|
468
|
+
const getRequest = store.get(sessionId);
|
|
469
|
+
getRequest.onsuccess = () => {
|
|
470
|
+
const recording = getRequest.result;
|
|
471
|
+
if (recording) {
|
|
472
|
+
Object.assign(recording, updates);
|
|
473
|
+
const putRequest = store.put(recording);
|
|
474
|
+
putRequest.onsuccess = () => resolve();
|
|
475
|
+
putRequest.onerror = () => reject(putRequest.error);
|
|
476
|
+
} else {
|
|
477
|
+
reject(new Error('Recording not found'));
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
getRequest.onerror = () => reject(getRequest.error);
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
async getBrowserRecording(sessionId) {
|
|
485
|
+
if (!this.db) await this.init();
|
|
486
|
+
const transaction = this.db.transaction(['browser_recordings'], 'readonly');
|
|
487
|
+
const store = transaction.objectStore('browser_recordings');
|
|
488
|
+
|
|
489
|
+
return new Promise((resolve, reject) => {
|
|
490
|
+
const request = store.get(sessionId);
|
|
491
|
+
request.onsuccess = () => resolve(request.result);
|
|
492
|
+
request.onerror = () => reject(request.error);
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
async getAllBrowserRecordings() {
|
|
497
|
+
if (!this.db) await this.init();
|
|
498
|
+
const transaction = this.db.transaction(['browser_recordings'], 'readonly');
|
|
499
|
+
const store = transaction.objectStore('browser_recordings');
|
|
500
|
+
|
|
501
|
+
return new Promise((resolve, reject) => {
|
|
502
|
+
const request = store.getAll();
|
|
503
|
+
request.onsuccess = () => resolve(request.result || []);
|
|
504
|
+
request.onerror = () => reject(request.error);
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
async deleteBrowserRecording(sessionId) {
|
|
509
|
+
if (!this.db) await this.init();
|
|
510
|
+
|
|
511
|
+
return new Promise((resolve, reject) => {
|
|
512
|
+
const transaction = this.db.transaction(['browser_recordings'], 'readwrite');
|
|
513
|
+
const store = transaction.objectStore('browser_recordings');
|
|
514
|
+
|
|
515
|
+
// Delete the recording
|
|
516
|
+
const deleteRequest = store.delete(sessionId);
|
|
517
|
+
deleteRequest.onerror = () => reject(deleteRequest.error);
|
|
518
|
+
|
|
519
|
+
// Wait for transaction to COMPLETE (commit to disk), not just request success
|
|
520
|
+
// This prevents race condition where add() happens before delete() commits
|
|
521
|
+
transaction.oncomplete = () => resolve();
|
|
522
|
+
transaction.onerror = () => reject(transaction.error);
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
async addBrowserFrame(frame) {
|
|
527
|
+
if (!this.db) await this.init();
|
|
528
|
+
const transaction = this.db.transaction(['browser_frames'], 'readwrite');
|
|
529
|
+
const store = transaction.objectStore('browser_frames');
|
|
530
|
+
|
|
531
|
+
return new Promise((resolve, reject) => {
|
|
532
|
+
const request = store.add(frame);
|
|
533
|
+
request.onsuccess = () => resolve(request.result);
|
|
534
|
+
request.onerror = () => reject(request.error);
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
async getBrowserFrames(sessionId) {
|
|
539
|
+
if (!this.db) await this.init();
|
|
540
|
+
const transaction = this.db.transaction(['browser_frames'], 'readonly');
|
|
541
|
+
const store = transaction.objectStore('browser_frames');
|
|
542
|
+
const index = store.index('sessionId');
|
|
543
|
+
|
|
544
|
+
return new Promise((resolve, reject) => {
|
|
545
|
+
const request = index.getAll(IDBKeyRange.only(sessionId));
|
|
546
|
+
request.onsuccess = () => resolve(request.result || []);
|
|
547
|
+
request.onerror = () => reject(request.error);
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
async getBrowserFrameCount(sessionId) {
|
|
552
|
+
if (!this.db) await this.init();
|
|
553
|
+
const transaction = this.db.transaction(['browser_frames'], 'readonly');
|
|
554
|
+
const store = transaction.objectStore('browser_frames');
|
|
555
|
+
const index = store.index('sessionId');
|
|
556
|
+
|
|
557
|
+
return new Promise((resolve, reject) => {
|
|
558
|
+
const request = index.count(IDBKeyRange.only(sessionId));
|
|
559
|
+
request.onsuccess = () => resolve(request.result);
|
|
560
|
+
request.onerror = () => reject(request.error);
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
async updateBrowserFrame(frameId, updates) {
|
|
565
|
+
if (!this.db) await this.init();
|
|
566
|
+
|
|
567
|
+
return new Promise((resolve, reject) => {
|
|
568
|
+
const transaction = this.db.transaction(['browser_frames'], 'readwrite');
|
|
569
|
+
const store = transaction.objectStore('browser_frames');
|
|
570
|
+
|
|
571
|
+
// Get the existing frame
|
|
572
|
+
const getRequest = store.get(frameId);
|
|
573
|
+
getRequest.onsuccess = () => {
|
|
574
|
+
const frame = getRequest.result;
|
|
575
|
+
if (!frame) {
|
|
576
|
+
reject(new Error(`Frame ${frameId} not found`));
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Apply updates
|
|
581
|
+
Object.assign(frame, updates);
|
|
582
|
+
|
|
583
|
+
// Put the updated frame back
|
|
584
|
+
const putRequest = store.put(frame);
|
|
585
|
+
putRequest.onerror = () => reject(putRequest.error);
|
|
586
|
+
};
|
|
587
|
+
getRequest.onerror = () => reject(getRequest.error);
|
|
588
|
+
|
|
589
|
+
// Wait for transaction to complete
|
|
590
|
+
transaction.oncomplete = () => resolve();
|
|
591
|
+
transaction.onerror = () => reject(transaction.error);
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
async deleteBrowserFrames(sessionId) {
|
|
596
|
+
if (!this.db) await this.init();
|
|
597
|
+
const transaction = this.db.transaction(['browser_frames'], 'readwrite');
|
|
598
|
+
const store = transaction.objectStore('browser_frames');
|
|
599
|
+
const index = store.index('sessionId');
|
|
600
|
+
|
|
601
|
+
return new Promise((resolve, reject) => {
|
|
602
|
+
let deletedCount = 0;
|
|
603
|
+
const request = index.openCursor(IDBKeyRange.only(sessionId));
|
|
604
|
+
|
|
605
|
+
request.onsuccess = (event) => {
|
|
606
|
+
const cursor = event.target.result;
|
|
607
|
+
if (cursor) {
|
|
608
|
+
store.delete(cursor.primaryKey);
|
|
609
|
+
deletedCount++;
|
|
610
|
+
cursor.continue();
|
|
611
|
+
} else {
|
|
612
|
+
resolve(deletedCount);
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
request.onerror = () => reject(request.error);
|
|
617
|
+
});
|
|
618
|
+
}
|
|
430
619
|
}
|
|
431
620
|
|
|
432
621
|
// Export for use in background script
|
|
@@ -10,6 +10,7 @@ class FrameCapture {
|
|
|
10
10
|
this.sessionId = null;
|
|
11
11
|
this.startTime = null;
|
|
12
12
|
this.totalFramesCaptured = 0;
|
|
13
|
+
this.mode = 'server'; // 'server' or 'browser-only'
|
|
13
14
|
this.settings = {
|
|
14
15
|
frameRate: 1, // seconds between frames
|
|
15
16
|
imageQuality: 30, // JPEG quality (1-100)
|
|
@@ -23,6 +24,16 @@ class FrameCapture {
|
|
|
23
24
|
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
setMode(mode) {
|
|
28
|
+
if (mode !== 'server' && mode !== 'browser-only') {
|
|
29
|
+
console.warn('[FrameCapture] Invalid mode:', mode, '- defaulting to server');
|
|
30
|
+
this.mode = 'server';
|
|
31
|
+
} else {
|
|
32
|
+
this.mode = mode;
|
|
33
|
+
console.log('[FrameCapture] Mode set to:', this.mode);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
async startCapture(streamId, tabId, sessionId, scheduledStartTime, settings = {}, ownerId = null) {
|
|
27
38
|
if (this.isCapturing) return;
|
|
28
39
|
|
|
@@ -38,12 +49,22 @@ class FrameCapture {
|
|
|
38
49
|
// Initialize lease tracking - null forces immediate first check
|
|
39
50
|
this.lastLeaseCheck = null;
|
|
40
51
|
|
|
41
|
-
// Update settings with passed values
|
|
42
|
-
this.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
52
|
+
// Update settings with passed values or apply mode-specific defaults
|
|
53
|
+
if (this.mode === 'browser-only') {
|
|
54
|
+
// Browser-only mode: ultra-low resolution and quality for storage efficiency
|
|
55
|
+
this.settings = {
|
|
56
|
+
frameRate: settings.frameRate || 1,
|
|
57
|
+
imageQuality: settings.imageQuality || 15, // Lower quality for browser storage
|
|
58
|
+
frameFlash: settings.frameFlash !== false
|
|
59
|
+
};
|
|
60
|
+
} else {
|
|
61
|
+
// Server mode: standard settings
|
|
62
|
+
this.settings = {
|
|
63
|
+
frameRate: settings.frameRate || 1,
|
|
64
|
+
imageQuality: settings.imageQuality || 30,
|
|
65
|
+
frameFlash: settings.frameFlash !== false
|
|
66
|
+
};
|
|
67
|
+
}
|
|
47
68
|
|
|
48
69
|
console.log('Starting frame capture session:', this.sessionId);
|
|
49
70
|
console.log('Frame capture scheduled to start at:', new Date(scheduledStartTime));
|
|
@@ -68,16 +89,27 @@ class FrameCapture {
|
|
|
68
89
|
this.totalFramesCaptured++;
|
|
69
90
|
console.log('Created synthetic first frame at scheduled start time');
|
|
70
91
|
|
|
71
|
-
// Get the media stream with
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
92
|
+
// Get the media stream with resolution based on mode
|
|
93
|
+
const videoConstraints = this.mode === 'browser-only'
|
|
94
|
+
? {
|
|
95
|
+
mandatory: {
|
|
96
|
+
chromeMediaSource: 'tab',
|
|
97
|
+
chromeMediaSourceId: streamId,
|
|
98
|
+
maxWidth: 480, // Ultra-low resolution for browser storage
|
|
99
|
+
maxHeight: 270 // Ultra-low resolution for browser storage
|
|
100
|
+
}
|
|
79
101
|
}
|
|
80
|
-
|
|
102
|
+
: {
|
|
103
|
+
mandatory: {
|
|
104
|
+
chromeMediaSource: 'tab',
|
|
105
|
+
chromeMediaSourceId: streamId,
|
|
106
|
+
maxWidth: 640, // Standard resolution for server storage
|
|
107
|
+
maxHeight: 360 // Standard resolution for server storage
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const media = await navigator.mediaDevices.getUserMedia({
|
|
112
|
+
video: videoConstraints,
|
|
81
113
|
audio: false
|
|
82
114
|
});
|
|
83
115
|
|
|
@@ -382,6 +414,11 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
|
|
382
414
|
if (message.target !== 'offscreen') return;
|
|
383
415
|
|
|
384
416
|
if (message.type === 'start-frame-capture') {
|
|
417
|
+
// Set mode before starting capture
|
|
418
|
+
if (message.mode) {
|
|
419
|
+
frameCapture.setMode(message.mode);
|
|
420
|
+
}
|
|
421
|
+
|
|
385
422
|
frameCapture.startCapture(message.streamId, message.tabId, message.sessionId, message.scheduledStartTime, message.settings, message.ownerId)
|
|
386
423
|
.then(() => sendResponse({ success: true }))
|
|
387
424
|
.catch(error => {
|
|
@@ -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];
|
|
@@ -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];
|
|
@@ -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 v2.6.
|
|
4
|
-
"version": "2.6.
|
|
5
|
-
"description": "ChromeDebug MCP visual element selector [FREE Edition] [Build: 2025-10-
|
|
3
|
+
"name": "ChromeDebug MCP Assistant FREE v2.6.7",
|
|
4
|
+
"version": "2.6.7",
|
|
5
|
+
"description": "ChromeDebug MCP visual element selector [FREE Edition] [Build: 2025-11-10-v2.6.7]",
|
|
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": {
|
|
@@ -217,7 +217,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
217
217
|
|
|
218
218
|
const a = document.createElement('a');
|
|
219
219
|
a.href = url;
|
|
220
|
-
a.download = 'chrome-
|
|
220
|
+
a.download = 'chrome-debug-site-settings.json';
|
|
221
221
|
a.click();
|
|
222
222
|
|
|
223
223
|
URL.revokeObjectURL(url);
|