@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
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Console Interception Library
|
|
3
|
+
* Shared code for both Screen Recording and Workflow Recording
|
|
4
|
+
*
|
|
5
|
+
* This library provides console log interception and cleanup functionality
|
|
6
|
+
* that is used identically by both recording systems.
|
|
7
|
+
*
|
|
8
|
+
* DRY Principle: Don't Repeat Yourself
|
|
9
|
+
* - Reduces code duplication from 600+ lines to reusable functions
|
|
10
|
+
* - Single source of truth for console interception logic
|
|
11
|
+
* - Easier to maintain and update
|
|
12
|
+
*
|
|
13
|
+
* Usage Example:
|
|
14
|
+
* ```javascript
|
|
15
|
+
* // Screen recording config
|
|
16
|
+
* const screenConfig = {
|
|
17
|
+
* overrideFlagName: '__chromePilotConsoleOverridden',
|
|
18
|
+
* originalConsoleName: '__chromePilotOriginalConsole',
|
|
19
|
+
* relayFlagName: '__chromePilotConsoleRelay',
|
|
20
|
+
* messageType: 'chrome-debug-console-log',
|
|
21
|
+
* backgroundAction: 'consoleLog'
|
|
22
|
+
* };
|
|
23
|
+
*
|
|
24
|
+
* // Start interception
|
|
25
|
+
* await startConsoleInterception(tabId, screenConfig);
|
|
26
|
+
*
|
|
27
|
+
* // Stop interception
|
|
28
|
+
* await stopConsoleInterception(tabId, screenConfig);
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
// Console Interception Library - Direct function definitions for importScripts compatibility
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Injectable function for MAIN world console interception
|
|
36
|
+
* This function will be serialized and injected into the page's MAIN execution context
|
|
37
|
+
*
|
|
38
|
+
* @param {string} overrideFlagName - Window property to track if already overridden
|
|
39
|
+
* @param {string} originalConsoleName - Window property to store original console methods
|
|
40
|
+
* @param {string} messageType - The postMessage type for log relay
|
|
41
|
+
* @returns {string} Status message
|
|
42
|
+
*/
|
|
43
|
+
function injectConsoleInterceptor(overrideFlagName, originalConsoleName, messageType) {
|
|
44
|
+
// Check if we've already overridden console methods
|
|
45
|
+
if (window[overrideFlagName]) {
|
|
46
|
+
console.log('[Chrome Debug] Console already overridden, skipping');
|
|
47
|
+
return 'already_installed';
|
|
48
|
+
}
|
|
49
|
+
window[overrideFlagName] = true;
|
|
50
|
+
console.log('[Chrome Debug] Installing console interceptor');
|
|
51
|
+
|
|
52
|
+
// CRITICAL: Store original console methods in window for later restoration
|
|
53
|
+
window[originalConsoleName] = {
|
|
54
|
+
log: console.log,
|
|
55
|
+
error: console.error,
|
|
56
|
+
warn: console.warn,
|
|
57
|
+
info: console.info,
|
|
58
|
+
debug: console.debug,
|
|
59
|
+
trace: console.trace,
|
|
60
|
+
table: console.table,
|
|
61
|
+
dir: console.dir,
|
|
62
|
+
group: console.group,
|
|
63
|
+
groupEnd: console.groupEnd,
|
|
64
|
+
time: console.time,
|
|
65
|
+
timeEnd: console.timeEnd,
|
|
66
|
+
count: console.count
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Duck-type check for Error-like objects (handles cross-realm errors)
|
|
70
|
+
const isErrorLike = (obj) => {
|
|
71
|
+
if (obj instanceof Error) return true;
|
|
72
|
+
// Duck-type check for cross-realm errors (e.g., from iframes, web workers)
|
|
73
|
+
return obj !== null &&
|
|
74
|
+
typeof obj === 'object' &&
|
|
75
|
+
typeof obj.message === 'string' &&
|
|
76
|
+
(typeof obj.stack === 'string' || typeof obj.name === 'string');
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Serialize Error objects properly (message, stack, name are non-enumerable)
|
|
80
|
+
const serializeError = (err, depth = 0) => {
|
|
81
|
+
if (depth > 3) return '[Error: max depth reached]';
|
|
82
|
+
|
|
83
|
+
const result = {
|
|
84
|
+
name: err.name || 'Error',
|
|
85
|
+
message: err.message || '',
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// Capture stack trace with intelligent truncation
|
|
89
|
+
if (err.stack) {
|
|
90
|
+
const stackLines = err.stack.split('\n');
|
|
91
|
+
let truncatedStack = [];
|
|
92
|
+
for (let i = 0; i < stackLines.length && i < 10; i++) {
|
|
93
|
+
truncatedStack.push(stackLines[i]);
|
|
94
|
+
// Stop at node_modules to reduce noise
|
|
95
|
+
if (stackLines[i].includes('node_modules')) {
|
|
96
|
+
truncatedStack.push(' ... (truncated at node_modules)');
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
result.stack = truncatedStack.join('\n');
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Capture custom enumerable properties (e.g., Firebase error.code)
|
|
104
|
+
for (const key of Object.keys(err)) {
|
|
105
|
+
if (!['name', 'message', 'stack'].includes(key)) {
|
|
106
|
+
try {
|
|
107
|
+
if (err[key] instanceof Error || isErrorLike(err[key])) {
|
|
108
|
+
result[key] = serializeError(err[key], depth + 1);
|
|
109
|
+
} else {
|
|
110
|
+
result[key] = JSON.parse(JSON.stringify(err[key]));
|
|
111
|
+
}
|
|
112
|
+
} catch (e) {
|
|
113
|
+
result[key] = '[Could not serialize]';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ES2022 error.cause support
|
|
119
|
+
if (err.cause) {
|
|
120
|
+
if (err.cause instanceof Error || isErrorLike(err.cause)) {
|
|
121
|
+
result.cause = serializeError(err.cause, depth + 1);
|
|
122
|
+
} else {
|
|
123
|
+
try {
|
|
124
|
+
result.cause = JSON.parse(JSON.stringify(err.cause));
|
|
125
|
+
} catch (e) {
|
|
126
|
+
result.cause = '[Could not serialize cause]';
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return result;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Create sendLog function with truncation logic
|
|
135
|
+
const sendLog = (level, args) => {
|
|
136
|
+
try {
|
|
137
|
+
// Pre-serialize arguments to strings to avoid structured clone errors
|
|
138
|
+
const serializedArgs = args.map(arg => {
|
|
139
|
+
try {
|
|
140
|
+
if (arg === null) return 'null';
|
|
141
|
+
if (arg === undefined) return 'undefined';
|
|
142
|
+
if (typeof arg === 'function') return '[Function: ' + (arg.name || 'anonymous') + ']';
|
|
143
|
+
|
|
144
|
+
// IMPORTANT: Check for Error objects BEFORE generic object handler
|
|
145
|
+
// Error properties (message, stack, name) are non-enumerable and JSON.stringify returns "{}"
|
|
146
|
+
if (arg instanceof Error || isErrorLike(arg)) {
|
|
147
|
+
const errorObj = serializeError(arg);
|
|
148
|
+
return JSON.stringify(errorObj, null, 2);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Note: Element check removed - service workers have no DOM access, so this will never trigger
|
|
152
|
+
if (typeof arg === 'object') {
|
|
153
|
+
// Custom replacer to handle nested errors in objects
|
|
154
|
+
const errorReplacer = (key, value) => {
|
|
155
|
+
if (value instanceof Error || (value && isErrorLike(value))) {
|
|
156
|
+
return serializeError(value);
|
|
157
|
+
}
|
|
158
|
+
return value;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
// Try to stringify, but limit depth to avoid circular references
|
|
162
|
+
let stringified = JSON.stringify(arg, errorReplacer, 2);
|
|
163
|
+
|
|
164
|
+
// Check if this looks like a base64 image and truncate it
|
|
165
|
+
if (stringified.includes('data:image/') && stringified.length > 1000) {
|
|
166
|
+
const match = stringified.match(/data:image\/([^;]+);base64,(.{0,100})/);
|
|
167
|
+
if (match) {
|
|
168
|
+
return `[Base64 Image: ${match[1]}, ${stringified.length} bytes total, truncated...]`;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Truncate any extremely large strings
|
|
173
|
+
const maxLength = 5000;
|
|
174
|
+
if (stringified.length > maxLength) {
|
|
175
|
+
return stringified.substring(0, maxLength) + `... [TRUNCATED: ${stringified.length} total bytes]`;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return stringified;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Also check for base64 strings directly
|
|
182
|
+
const strValue = String(arg);
|
|
183
|
+
if (strValue.includes('data:image/') && strValue.length > 1000) {
|
|
184
|
+
const match = strValue.match(/data:image\/([^;]+);base64,(.{0,100})/);
|
|
185
|
+
if (match) {
|
|
186
|
+
return `[Base64 Image: ${match[1]}, ${strValue.length} bytes total, truncated...]`;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Truncate any extremely large strings
|
|
191
|
+
if (strValue.length > 5000) {
|
|
192
|
+
return strValue.substring(0, 5000) + `... [TRUNCATED: ${strValue.length} total bytes]`;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return strValue;
|
|
196
|
+
} catch (e) {
|
|
197
|
+
return '[Object: could not serialize]';
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Build the message string
|
|
202
|
+
const messageString = serializedArgs.join(' ');
|
|
203
|
+
|
|
204
|
+
// Filter out internal Chrome Debug/ChromePilot logs
|
|
205
|
+
// These are internal debugging messages that should not be captured in recordings
|
|
206
|
+
if (messageString.startsWith('[Chrome Debug]') ||
|
|
207
|
+
messageString.startsWith('[ChromePilot]') ||
|
|
208
|
+
messageString.startsWith('[Console Injection]') ||
|
|
209
|
+
messageString.startsWith('[Console Cleanup]')) {
|
|
210
|
+
return; // Skip internal logs
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Post message to content script
|
|
214
|
+
window.postMessage({
|
|
215
|
+
type: messageType,
|
|
216
|
+
log: {
|
|
217
|
+
level,
|
|
218
|
+
message: messageString,
|
|
219
|
+
timestamp: Date.now()
|
|
220
|
+
}
|
|
221
|
+
}, '*');
|
|
222
|
+
} catch (e) {
|
|
223
|
+
// Ignore errors when sending logs
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
// Override console methods
|
|
228
|
+
const methods = ['log', 'error', 'warn', 'info', 'debug', 'trace', 'table', 'dir', 'group', 'groupEnd', 'time', 'timeEnd', 'count'];
|
|
229
|
+
methods.forEach(method => {
|
|
230
|
+
const original = window[originalConsoleName][method];
|
|
231
|
+
console[method] = (...args) => {
|
|
232
|
+
sendLog(method, args);
|
|
233
|
+
original.apply(console, args);
|
|
234
|
+
};
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
return 'console_installed';
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Injectable function for content script console relay
|
|
242
|
+
* Forwards console logs from MAIN world to background script
|
|
243
|
+
*
|
|
244
|
+
* @param {string} relayFlagName - Window property to track if relay is active
|
|
245
|
+
* @param {string} messageType - The postMessage type to listen for
|
|
246
|
+
* @param {string} backgroundAction - The action name to send to background script
|
|
247
|
+
*/
|
|
248
|
+
function injectConsoleRelay(relayFlagName, messageType, backgroundAction) {
|
|
249
|
+
// Check if relay is already active
|
|
250
|
+
if (window[relayFlagName]) {
|
|
251
|
+
console.log('[Chrome Debug] Console relay already active, skipping');
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Create and store the message handler
|
|
256
|
+
const messageHandler = (event) => {
|
|
257
|
+
if (event.data && event.data.type === messageType) {
|
|
258
|
+
// Forward to background script
|
|
259
|
+
chrome.runtime.sendMessage({
|
|
260
|
+
action: backgroundAction,
|
|
261
|
+
log: event.data.log
|
|
262
|
+
}).catch(() => {
|
|
263
|
+
// Background might not be available - that's OK
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
// Store reference for later removal
|
|
269
|
+
window[relayFlagName] = messageHandler;
|
|
270
|
+
|
|
271
|
+
// Listen for messages from main world
|
|
272
|
+
window.addEventListener('message', messageHandler);
|
|
273
|
+
console.log('[Chrome Debug] Console relay installed');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Injectable function for MAIN world console cleanup
|
|
278
|
+
* Restores original console methods
|
|
279
|
+
*
|
|
280
|
+
* @param {string} overrideFlagName - Window property that tracks override status
|
|
281
|
+
* @param {string} originalConsoleName - Window property with stored original methods
|
|
282
|
+
* @returns {object} Status object
|
|
283
|
+
*/
|
|
284
|
+
function cleanupConsoleInterceptor(overrideFlagName, originalConsoleName) {
|
|
285
|
+
console.log('[Chrome Debug] ===== CLEANUP SCRIPT EXECUTING IN MAIN WORLD =====');
|
|
286
|
+
console.log('[Chrome Debug] ' + originalConsoleName + ' exists:', !!window[originalConsoleName]);
|
|
287
|
+
console.log('[Chrome Debug] ' + overrideFlagName + ':', window[overrideFlagName]);
|
|
288
|
+
|
|
289
|
+
if (window[originalConsoleName] && window[overrideFlagName]) {
|
|
290
|
+
console.log('[Chrome Debug] RESTORING original console methods');
|
|
291
|
+
|
|
292
|
+
// Restore all original console methods
|
|
293
|
+
Object.assign(console, window[originalConsoleName]);
|
|
294
|
+
|
|
295
|
+
// Clean up stored references
|
|
296
|
+
delete window[originalConsoleName];
|
|
297
|
+
delete window[overrideFlagName];
|
|
298
|
+
|
|
299
|
+
console.log('[Chrome Debug] ✅ Console methods restored successfully');
|
|
300
|
+
return { success: true, message: 'Console restored' };
|
|
301
|
+
} else {
|
|
302
|
+
console.warn('[Chrome Debug] ⚠️ No console override to restore');
|
|
303
|
+
return { success: false, message: 'No override found' };
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Injectable function for content script relay cleanup
|
|
309
|
+
* Removes the message event listener
|
|
310
|
+
*
|
|
311
|
+
* @param {string} relayFlagName - Window property with stored message handler
|
|
312
|
+
* @returns {object} Status object
|
|
313
|
+
*/
|
|
314
|
+
function cleanupConsoleRelay(relayFlagName) {
|
|
315
|
+
console.log('[Chrome Debug] ===== CLEANUP SCRIPT EXECUTING IN CONTENT SCRIPT =====');
|
|
316
|
+
console.log('[Chrome Debug] ' + relayFlagName + ' exists:', !!window[relayFlagName]);
|
|
317
|
+
|
|
318
|
+
if (window[relayFlagName]) {
|
|
319
|
+
console.log('[Chrome Debug] REMOVING console relay listener');
|
|
320
|
+
window.removeEventListener('message', window[relayFlagName]);
|
|
321
|
+
delete window[relayFlagName];
|
|
322
|
+
console.log('[Chrome Debug] ✅ Console relay removed successfully');
|
|
323
|
+
return { success: true, message: 'Relay removed' };
|
|
324
|
+
} else {
|
|
325
|
+
console.warn('[Chrome Debug] ⚠️ No relay to remove');
|
|
326
|
+
return { success: false, message: 'No relay found' };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* High-level API for starting console interception
|
|
332
|
+
*
|
|
333
|
+
* @param {number} tabId - Chrome tab ID
|
|
334
|
+
* @param {object} config - Configuration object
|
|
335
|
+
* @param {string} config.overrideFlagName - Window property for override tracking
|
|
336
|
+
* @param {string} config.originalConsoleName - Window property for original methods
|
|
337
|
+
* @param {string} config.relayFlagName - Window property for relay handler
|
|
338
|
+
* @param {string} config.messageType - PostMessage type for log relay
|
|
339
|
+
* @param {string} config.backgroundAction - Background script action name
|
|
340
|
+
* @returns {Promise<boolean>} True if successful, false otherwise
|
|
341
|
+
*/
|
|
342
|
+
async function startConsoleInterception(tabId, config) {
|
|
343
|
+
try {
|
|
344
|
+
// Check if this tab allows content script injection
|
|
345
|
+
const tab = await chrome.tabs.get(tabId);
|
|
346
|
+
if (!tab.url || tab.url.startsWith('chrome://') || tab.url.startsWith('chrome-extension://') || tab.url.startsWith('moz-extension://')) {
|
|
347
|
+
console.log('Cannot inject console logger into restricted URL:', tab.url);
|
|
348
|
+
console.warn('WARNING: Console logs cannot be captured on restricted pages');
|
|
349
|
+
return false;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
// Inject MAIN world console interceptor
|
|
353
|
+
const results = await chrome.scripting.executeScript({
|
|
354
|
+
target: { tabId: tabId },
|
|
355
|
+
world: 'MAIN',
|
|
356
|
+
func: injectConsoleInterceptor,
|
|
357
|
+
args: [config.overrideFlagName, config.originalConsoleName, config.messageType]
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
console.log('[Console Injection] MAIN world script injected:', results);
|
|
361
|
+
|
|
362
|
+
// Inject content script relay
|
|
363
|
+
await chrome.scripting.executeScript({
|
|
364
|
+
target: { tabId: tabId },
|
|
365
|
+
func: injectConsoleRelay,
|
|
366
|
+
args: [config.relayFlagName, config.messageType, config.backgroundAction]
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
console.log('[Console Injection] Content script relay injected successfully');
|
|
370
|
+
return true;
|
|
371
|
+
} catch (error) {
|
|
372
|
+
console.error('[Console Injection] Failed:', error);
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* High-level API for stopping console interception and cleanup
|
|
379
|
+
*
|
|
380
|
+
* @param {number} tabId - Chrome tab ID
|
|
381
|
+
* @param {object} config - Configuration object (same as startConsoleInterception)
|
|
382
|
+
* @returns {Promise<boolean>} True if successful, false otherwise
|
|
383
|
+
*/
|
|
384
|
+
async function stopConsoleInterception(tabId, config) {
|
|
385
|
+
try {
|
|
386
|
+
console.log('[Console Cleanup] Starting cleanup for tab:', tabId);
|
|
387
|
+
|
|
388
|
+
// Check if this tab allows content script injection
|
|
389
|
+
const tab = await chrome.tabs.get(tabId);
|
|
390
|
+
if (!tab.url || tab.url.startsWith('chrome://') || tab.url.startsWith('chrome-extension://')) {
|
|
391
|
+
console.warn('[Console Cleanup] Cannot inject into restricted URL:', tab.url);
|
|
392
|
+
return false;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// Restore console methods in MAIN world
|
|
396
|
+
const mainWorldResult = await chrome.scripting.executeScript({
|
|
397
|
+
target: { tabId: tabId },
|
|
398
|
+
world: 'MAIN',
|
|
399
|
+
func: cleanupConsoleInterceptor,
|
|
400
|
+
args: [config.overrideFlagName, config.originalConsoleName]
|
|
401
|
+
});
|
|
402
|
+
console.log('[Console Cleanup] MAIN world result:', mainWorldResult[0]?.result);
|
|
403
|
+
|
|
404
|
+
// Remove relay in content script
|
|
405
|
+
const contentScriptResult = await chrome.scripting.executeScript({
|
|
406
|
+
target: { tabId: tabId },
|
|
407
|
+
func: cleanupConsoleRelay,
|
|
408
|
+
args: [config.relayFlagName]
|
|
409
|
+
});
|
|
410
|
+
console.log('[Console Cleanup] Content script result:', contentScriptResult[0]?.result);
|
|
411
|
+
|
|
412
|
+
console.log('[Console Cleanup] Cleanup complete');
|
|
413
|
+
return true;
|
|
414
|
+
} catch (error) {
|
|
415
|
+
console.error('[Console Cleanup] Failed:', error);
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Export for use in Chrome extension background script (service worker context)
|
|
421
|
+
// Direct assignment without wrapper to avoid importScripts NetworkError
|
|
422
|
+
self.ConsoleInterceptionLibrary = {
|
|
423
|
+
injectConsoleInterceptor,
|
|
424
|
+
injectConsoleRelay,
|
|
425
|
+
cleanupConsoleInterceptor,
|
|
426
|
+
cleanupConsoleRelay,
|
|
427
|
+
startConsoleInterception,
|
|
428
|
+
stopConsoleInterception
|
|
429
|
+
};
|
|
430
|
+
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
.chrome-
|
|
1
|
+
.chrome-debug-hover {
|
|
2
2
|
outline: 2px solid #4A90E2 !important;
|
|
3
3
|
outline-offset: 2px !important;
|
|
4
4
|
cursor: pointer !important;
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
.chrome-
|
|
7
|
+
.chrome-debug-selected {
|
|
8
8
|
outline: 3px solid #E91E63 !important;
|
|
9
9
|
outline-offset: 2px !important;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
.chrome-
|
|
12
|
+
.chrome-debug-overlay {
|
|
13
13
|
position: fixed;
|
|
14
14
|
bottom: 20px;
|
|
15
15
|
right: 20px;
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
color: #e0e0e0;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
.chrome-
|
|
27
|
+
.chrome-debug-overlay h3 {
|
|
28
28
|
margin: 0 0 10px 0;
|
|
29
29
|
font-size: 16px;
|
|
30
30
|
color: #ffffff;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
.chrome-
|
|
33
|
+
.chrome-debug-overlay .element-info {
|
|
34
34
|
background: #2a2a2a;
|
|
35
35
|
padding: 10px;
|
|
36
36
|
border-radius: 4px;
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
border: 1px solid #3a3a3a;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
.chrome-
|
|
44
|
+
.chrome-debug-overlay .react-info {
|
|
45
45
|
background: #1a2332;
|
|
46
46
|
padding: 10px;
|
|
47
47
|
border-radius: 4px;
|
|
@@ -51,13 +51,13 @@
|
|
|
51
51
|
color: #e0e0e0;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
.chrome-
|
|
54
|
+
.chrome-debug-overlay .react-info h4 {
|
|
55
55
|
margin: 0 0 8px 0;
|
|
56
56
|
font-size: 14px;
|
|
57
57
|
font-weight: 600;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
.chrome-
|
|
60
|
+
.chrome-debug-overlay textarea {
|
|
61
61
|
width: 100%;
|
|
62
62
|
padding: 10px;
|
|
63
63
|
border: 1px solid #ddd;
|
|
@@ -68,13 +68,13 @@
|
|
|
68
68
|
font-size: 14px;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
.chrome-
|
|
71
|
+
.chrome-debug-overlay .button-group {
|
|
72
72
|
display: flex;
|
|
73
73
|
gap: 10px;
|
|
74
74
|
margin-top: 15px;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
.chrome-
|
|
77
|
+
.chrome-debug-overlay button {
|
|
78
78
|
flex: 1;
|
|
79
79
|
padding: 10px 20px;
|
|
80
80
|
border: none;
|
|
@@ -85,31 +85,31 @@
|
|
|
85
85
|
transition: background-color 0.2s;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
.chrome-
|
|
88
|
+
.chrome-debug-overlay .submit-btn {
|
|
89
89
|
background: #4A90E2;
|
|
90
90
|
color: white;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
.chrome-
|
|
93
|
+
.chrome-debug-overlay .submit-btn:hover {
|
|
94
94
|
background: #357ABD;
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
.chrome-
|
|
97
|
+
.chrome-debug-overlay .cancel-btn {
|
|
98
98
|
background: #f0f0f0;
|
|
99
99
|
color: #333;
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
.chrome-
|
|
102
|
+
.chrome-debug-overlay .cancel-btn:hover {
|
|
103
103
|
background: #e0e0e0;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
.chrome-
|
|
106
|
+
.chrome-debug-overlay .loading {
|
|
107
107
|
text-align: center;
|
|
108
108
|
color: #a0a0a0;
|
|
109
109
|
padding: 20px;
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
.chrome-
|
|
112
|
+
.chrome-debug-status {
|
|
113
113
|
position: fixed;
|
|
114
114
|
top: 20px;
|
|
115
115
|
right: 20px;
|