Skip to content

Commit 328784f

Browse files
committed
added element selector and screenshot tool
1 parent 2733e83 commit 328784f

File tree

7 files changed

+424
-25
lines changed

7 files changed

+424
-25
lines changed

chrome-extension/devtools.js

Lines changed: 136 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ let settings = {
88
maxLogSize: 20000,
99
showRequestHeaders: false,
1010
showResponseHeaders: false,
11+
screenshotPath: "", // Add new setting for screenshot path
1112
};
1213

1314
// Keep track of debugger state
@@ -368,17 +369,144 @@ chrome.devtools.panels.create("Browser Logs", "", "panel.html", (panel) => {
368369
// Initial attach - we'll keep the debugger attached as long as DevTools is open
369370
attachDebugger();
370371

371-
// Remove the panel show/hide listeners since we want to stay attached
372-
// panel.onShown.addListener(() => {
373-
// attachDebugger();
374-
// });
375-
//
376-
// panel.onHidden.addListener(() => {
377-
// detachDebugger();
378-
// });
372+
// Add message passing to panel.js
373+
panel.onShown.addListener((panelWindow) => {
374+
panelWindow.postMessage({ type: "initializeSelectionButton" }, "*");
375+
});
379376
});
380377

381378
// Clean up only when the entire DevTools window is closed
382379
window.addEventListener("unload", () => {
383380
detachDebugger();
384381
});
382+
383+
// Function to capture and send element data
384+
function captureAndSendElement() {
385+
chrome.devtools.inspectedWindow.eval(
386+
`(function() {
387+
const el = $0; // $0 is the currently selected element in DevTools
388+
if (!el) return null;
389+
390+
const rect = el.getBoundingClientRect();
391+
392+
return {
393+
tagName: el.tagName,
394+
id: el.id,
395+
className: el.className,
396+
textContent: el.textContent?.substring(0, 100),
397+
attributes: Array.from(el.attributes).map(attr => ({
398+
name: attr.name,
399+
value: attr.value
400+
})),
401+
dimensions: {
402+
width: rect.width,
403+
height: rect.height,
404+
top: rect.top,
405+
left: rect.left
406+
},
407+
innerHTML: el.innerHTML.substring(0, 500)
408+
};
409+
})()`,
410+
(result, isException) => {
411+
if (isException || !result) return;
412+
413+
console.log("Element selected:", result);
414+
415+
// Send to browser connector
416+
sendToBrowserConnector({
417+
type: "selected-element",
418+
timestamp: Date.now(),
419+
element: result,
420+
});
421+
}
422+
);
423+
}
424+
425+
// Listen for element selection in the Elements panel
426+
chrome.devtools.panels.elements.onSelectionChanged.addListener(() => {
427+
captureAndSendElement();
428+
});
429+
430+
// WebSocket connection management
431+
let ws = null;
432+
let wsReconnectTimeout = null;
433+
const WS_RECONNECT_DELAY = 5000; // 5 seconds
434+
435+
function setupWebSocket() {
436+
if (ws) {
437+
ws.close();
438+
}
439+
440+
ws = new WebSocket("ws://localhost:3025/extension-ws");
441+
442+
ws.onopen = () => {
443+
console.log("WebSocket connected");
444+
if (wsReconnectTimeout) {
445+
clearTimeout(wsReconnectTimeout);
446+
wsReconnectTimeout = null;
447+
}
448+
};
449+
450+
ws.onmessage = async (event) => {
451+
try {
452+
const message = JSON.parse(event.data);
453+
454+
if (message.type === "take-screenshot") {
455+
if (!settings.screenshotPath) {
456+
ws.send(
457+
JSON.stringify({
458+
type: "screenshot-error",
459+
error: "Screenshot path not configured",
460+
})
461+
);
462+
return;
463+
}
464+
465+
// Capture screenshot of the current tab
466+
chrome.tabs.captureVisibleTab(null, { format: "png" }, (dataUrl) => {
467+
if (chrome.runtime.lastError) {
468+
ws.send(
469+
JSON.stringify({
470+
type: "screenshot-error",
471+
error: chrome.runtime.lastError.message,
472+
})
473+
);
474+
return;
475+
}
476+
477+
ws.send(
478+
JSON.stringify({
479+
type: "screenshot-data",
480+
data: dataUrl,
481+
path: settings.screenshotPath,
482+
})
483+
);
484+
});
485+
}
486+
} catch (error) {
487+
console.error("Error processing WebSocket message:", error);
488+
}
489+
};
490+
491+
ws.onclose = () => {
492+
console.log("WebSocket disconnected, attempting to reconnect...");
493+
wsReconnectTimeout = setTimeout(setupWebSocket, WS_RECONNECT_DELAY);
494+
};
495+
496+
ws.onerror = (error) => {
497+
console.error("WebSocket error:", error);
498+
};
499+
}
500+
501+
// Initialize WebSocket connection when DevTools opens
502+
setupWebSocket();
503+
504+
// Clean up WebSocket when DevTools closes
505+
window.addEventListener("unload", () => {
506+
if (ws) {
507+
ws.close();
508+
}
509+
if (wsReconnectTimeout) {
510+
clearTimeout(wsReconnectTimeout);
511+
}
512+
});

chrome-extension/panel.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,14 @@ <h3>Log Settings</h3>
103103
</div>
104104
</div>
105105

106+
<div class="settings-section">
107+
<h3>Screenshot Settings</h3>
108+
<div class="form-group">
109+
<label for="screenshot-path">Screenshot Save Path</label>
110+
<input type="text" id="screenshot-path" placeholder="/path/to/screenshots">
111+
</div>
112+
</div>
113+
106114
<script src="panel.js"></script>
107115
</body>
108116
</html>

chrome-extension/panel.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ let settings = {
66
showRequestHeaders: false,
77
showResponseHeaders: false,
88
maxLogSize: 20000,
9+
screenshotPath: "",
910
};
1011

1112
// Load saved settings on startup
@@ -27,6 +28,7 @@ const showResponseHeadersCheckbox = document.getElementById(
2728
"show-response-headers"
2829
);
2930
const maxLogSizeInput = document.getElementById("max-log-size");
31+
const screenshotPathInput = document.getElementById("screenshot-path");
3032

3133
// Update UI from settings
3234
function updateUIFromSettings() {
@@ -36,6 +38,7 @@ function updateUIFromSettings() {
3638
showRequestHeadersCheckbox.checked = settings.showRequestHeaders;
3739
showResponseHeadersCheckbox.checked = settings.showResponseHeaders;
3840
maxLogSizeInput.value = settings.maxLogSize;
41+
screenshotPathInput.value = settings.screenshotPath;
3942
}
4043

4144
// Save settings
@@ -78,3 +81,8 @@ maxLogSizeInput.addEventListener("change", (e) => {
7881
settings.maxLogSize = parseInt(e.target.value, 10);
7982
saveSettings();
8083
});
84+
85+
screenshotPathInput.addEventListener("change", (e) => {
86+
settings.screenshotPath = e.target.value;
87+
saveSettings();
88+
});

mcp-server/package-lock.json

Lines changed: 32 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mcp-server/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717
"body-parser": "^1.20.3",
1818
"cors": "^2.8.5",
1919
"express": "^4.21.2",
20-
"llm-cost": "^1.0.5"
20+
"llm-cost": "^1.0.5",
21+
"ws": "^8.18.0"
2122
},
2223
"devDependencies": {
24+
"@types/ws": "^8.5.14",
2325
"@types/body-parser": "^1.19.5",
2426
"@types/cors": "^2.8.17",
2527
"@types/express": "^5.0.0",

0 commit comments

Comments
 (0)