150 lines
5.5 KiB
JavaScript
150 lines
5.5 KiB
JavaScript
(function() {
|
|
'use strict';
|
|
|
|
if (window.__agentPDInjected) return;
|
|
window.__agentPDInjected = true;
|
|
|
|
const AGENT_PATTERNS = {
|
|
'claude.ai': 'claude-code',
|
|
'chatgpt.com': 'chatgpt',
|
|
'chat.openai.com': 'chatgpt',
|
|
'github.com': 'github-copilot',
|
|
'cursor.sh': 'cursor'
|
|
};
|
|
|
|
function detectAgent() {
|
|
const hostname = location.hostname;
|
|
for (const [domain, agent] of Object.entries(AGENT_PATTERNS)) {
|
|
if (hostname.includes(domain)) return agent;
|
|
}
|
|
return 'unknown';
|
|
}
|
|
|
|
function sendEvent(type, tool, target, extra = {}) {
|
|
const event = {
|
|
type: 'AGENT_EVENT',
|
|
payload: {
|
|
agent: detectAgent(),
|
|
type: type,
|
|
tool: tool,
|
|
target: target,
|
|
url: location.href,
|
|
timestamp: new Date().toISOString(),
|
|
id: crypto.randomUUID(),
|
|
...extra
|
|
}
|
|
};
|
|
chrome.runtime.sendMessage(event).catch(() => {});
|
|
}
|
|
|
|
function observeClaude() {
|
|
const observer = new MutationObserver((mutations) => {
|
|
for (const mutation of mutations) {
|
|
for (const node of mutation.addedNodes) {
|
|
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
const text = node.textContent || '';
|
|
if (text.includes('Using tool') || text.includes('tool use')) {
|
|
const toolMatch = text.match(/Using tool[:\s]+(\w+)/i) || text.match(/tool\s+use[:\s]+(\w+)/i);
|
|
const toolName = toolMatch ? toolMatch[1] : 'unknown';
|
|
sendEvent('tool_use', toolName, location.href, { context: text.slice(0, 200) });
|
|
}
|
|
if (text.includes('I\'ll help you') || text.includes('I can help')) {
|
|
sendEvent('session_start', 'chat', location.href, { context: text.slice(0, 100) });
|
|
}
|
|
if (text.includes('file') || node.querySelector?.('[data-testid="file"]')) {
|
|
const fileNodes = node.querySelectorAll?.('[data-testid="file"], .file-name, [class*="file"]') || [];
|
|
for (const fn of fileNodes) {
|
|
const path = fn.textContent || fn.getAttribute('data-path') || 'unknown';
|
|
sendEvent('file_access', 'read_file', path, { context: text.slice(0, 100) });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
observer.observe(document.body, { childList: true, subtree: true });
|
|
}
|
|
|
|
function observeGitHub() {
|
|
const observer = new MutationObserver((mutations) => {
|
|
for (const mutation of mutations) {
|
|
for (const node of mutation.addedNodes) {
|
|
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
const text = node.textContent || '';
|
|
if (text.includes('GitHub Copilot') || text.includes('Copilot')) {
|
|
sendEvent('tool_use', 'github_copilot', location.href, { context: text.slice(0, 100) });
|
|
}
|
|
if (text.includes('suggested') && text.includes('change')) {
|
|
sendEvent('code_generation', 'copilot_suggestion', location.href, { context: text.slice(0, 200) });
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (document.body) observer.observe(document.body, { childList: true, subtree: true });
|
|
}
|
|
|
|
function observeChatGPT() {
|
|
const observer = new MutationObserver((mutations) => {
|
|
for (const mutation of mutations) {
|
|
for (const node of mutation.addedNodes) {
|
|
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
const text = node.textContent || '';
|
|
if (text.includes('```') || text.includes('code')) {
|
|
sendEvent('code_generation', 'code_block', location.href, { context: text.slice(0, 200) });
|
|
}
|
|
if (text.includes('browsing') || text.includes('search')) {
|
|
sendEvent('tool_use', 'web_search', location.href, { context: text.slice(0, 100) });
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (document.body) observer.observe(document.body, { childList: true, subtree: true });
|
|
}
|
|
|
|
function observeCursor() {
|
|
const observer = new MutationObserver((mutations) => {
|
|
for (const mutation of mutations) {
|
|
for (const node of mutation.addedNodes) {
|
|
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
const text = node.textContent || '';
|
|
if (text.includes('Cursor') || text.includes('AI')) {
|
|
sendEvent('tool_use', 'cursor_ai', location.href, { context: text.slice(0, 100) });
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (document.body) observer.observe(document.body, { childList: true, subtree: true });
|
|
}
|
|
|
|
function init() {
|
|
const agent = detectAgent();
|
|
if (agent === 'claude-code') observeClaude();
|
|
else if (agent === 'github-copilot') observeGitHub();
|
|
else if (agent === 'chatgpt') observeChatGPT();
|
|
else if (agent === 'cursor') observeCursor();
|
|
|
|
sendEvent('page_visit', 'page_load', location.href, { agent });
|
|
|
|
const originalFetch = window.fetch;
|
|
window.fetch = async function(...args) {
|
|
const url = args[0] instanceof Request ? args[0].url : String(args[0]);
|
|
const method = args[0] instanceof Request ? args[0].method : (args[1]?.method || 'GET');
|
|
try {
|
|
const response = await originalFetch.apply(this, args);
|
|
if (url.includes('api') || url.includes('completion') || url.includes('chat')) {
|
|
sendEvent('api_call', method, url, { status: response.status });
|
|
}
|
|
return response;
|
|
} catch (err) {
|
|
sendEvent('api_call', method, url, { error: err.message, status: 0 });
|
|
throw err;
|
|
}
|
|
};
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', init);
|
|
} else {
|
|
init();
|
|
}
|
|
})();
|