Agent Police Department v1.0.0 MVP
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
(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();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user