// popup.js — Dashboard UI for Agent Police Department document.addEventListener('DOMContentLoaded', async () => { await loadStats(); await loadViolations(); setupTabs(); setupSearch(); setupPolicyEditor(); setupFooter(); }); async function loadStats() { try { const response = await chrome.runtime.sendMessage({ type: 'GET_STATS' }); if (!response?.success) return; const stats = response.stats; document.getElementById('risk-score').textContent = stats.riskScore ?? 0; const statusEl = document.getElementById('compliance-status'); statusEl.textContent = stats.complianceStatus || 'unknown'; statusEl.className = 'stat-badge ' + (stats.complianceStatus || ''); document.getElementById('active-count').textContent = stats.activeCount ?? 0; document.getElementById('violation-count').textContent = stats.totalViolations ?? 0; document.getElementById('event-count').textContent = stats.recentEvents ?? 0; } catch (err) { console.error('Stats load error:', err); } } async function loadViolations() { try { const { violations = [] } = await chrome.storage.local.get(['violations']); renderList(violations.slice(0, 50).reverse(), 'violations-list', formatViolation); } catch (err) { console.error('Violations load error:', err); } } async function loadActivity() { try { const response = await chrome.runtime.sendMessage({ type: 'GET_AUDIT_LOG', limit: 50 }); if (!response?.success) return; renderList(response.log || [], 'activity-list', formatEvent); } catch (err) { console.error('Activity load error:', err); } } function renderList(items, containerId, formatter) { const container = document.getElementById(containerId); if (!container) return; if (items.length === 0) { container.innerHTML = '
No items found
'; return; } container.innerHTML = items.map(formatter).join(''); } function formatViolation(v) { const time = new Date(v.timestamp).toLocaleTimeString(); return `
${v.detector.replace(/_/g, ' ')} ${v.severity}
${time} • ${v.rule_triggered || 'system'}
${v.message}
`; } function formatEvent(e) { const time = new Date(e.timestamp).toLocaleTimeString(); return `
${e.type} ${e.tool ? '(' + e.tool + ')' : ''} ${e.severity || 'info'}
${time} • ${e.agent || 'unknown'} • ${e.url || 'unknown'}
${e.target || e.context || 'No details'}
`; } function setupTabs() { const tabs = document.querySelectorAll('.tab-btn'); tabs.forEach(tab => { tab.addEventListener('click', async () => { tabs.forEach(t => t.classList.remove('active')); tab.classList.add('active'); const tabName = tab.dataset.tab; document.querySelectorAll('.tab-content').forEach(c => c.classList.add('hidden')); document.getElementById(tabName + '-tab').classList.remove('hidden'); if (tabName === 'activity') await loadActivity(); if (tabName === 'policy') await loadPolicyUI(); }); }); } function setupSearch() { const vSearch = document.getElementById('violation-search'); if (vSearch) { vSearch.addEventListener('input', async (e) => { const q = e.target.value.toLowerCase(); const { violations = [] } = await chrome.storage.local.get(['violations']); const filtered = violations.filter(v => v.detector.includes(q) || v.message.toLowerCase().includes(q) || v.severity.includes(q) ); renderList(filtered.slice(0, 50).reverse(), 'violations-list', formatViolation); }); } const aSearch = document.getElementById('activity-search'); if (aSearch) { aSearch.addEventListener('input', async (e) => { const q = e.target.value.toLowerCase(); const response = await chrome.runtime.sendMessage({ type: 'GET_AUDIT_LOG', limit: 100 }); if (!response?.success) return; const filtered = (response.log || []).filter(item => (item.agent || '').toLowerCase().includes(q) || (item.type || '').toLowerCase().includes(q) || (item.tool || '').toLowerCase().includes(q) || (item.target || '').toLowerCase().includes(q) ); renderList(filtered, 'activity-list', formatEvent); }); } } async function loadPolicyUI() { const { policy } = await chrome.storage.local.get(['policy']); if (!policy) return; const container = document.getElementById('policy-rules'); if (!container) return; container.innerHTML = policy.rules.map(rule => `
${rule.id}
${rule.type}
`).join(''); } function setupPolicyEditor() { document.getElementById('save-policy')?.addEventListener('click', async () => { const { policy } = await chrome.storage.local.get(['policy']); if (!policy) return; const toggles = document.querySelectorAll('#policy-rules input[type="checkbox"]'); toggles.forEach(toggle => { const rule = policy.rules.find(r => r.id === toggle.dataset.ruleId); if (rule) rule.enabled = toggle.checked; }); await chrome.storage.local.set({ policy }); showStatus('Policy saved'); }); document.getElementById('reset-policy')?.addEventListener('click', async () => { await chrome.storage.local.remove(['policy']); showStatus('Policy reset to default'); await loadPolicyUI(); }); } function setupFooter() { document.getElementById('export-btn')?.addEventListener('click', async () => { const response = await chrome.runtime.sendMessage({ type: 'EXPORT_AUDIT' }); if (!response?.success) return; const blob = new Blob([JSON.stringify(response.data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `agent-police-audit-${new Date().toISOString().slice(0, 10)}.json`; a.click(); URL.revokeObjectURL(url); showStatus('Audit log exported'); }); document.getElementById('verify-btn')?.addEventListener('click', async () => { const { verifyIntegrity } = await import('./lib/audit.js'); const result = await verifyIntegrity(); showStatus(result.valid ? 'Integrity verified ✓' : 'Integrity check failed ✗'); }); } function showStatus(msg) { const el = document.createElement('div'); el.className = 'status-message'; el.textContent = msg; document.body.appendChild(el); setTimeout(() => el.remove(), 2000); }