// ClawVault Popup Script let currentUrl = ''; let currentMatches = []; // Get current tab URL async function getCurrentUrl() { const tabs = await chrome.tabs.query({ active: true, currentWindow: true }); if (tabs[0]) { currentUrl = tabs[0].url; document.getElementById('currentUrl').textContent = new URL(currentUrl).hostname; return currentUrl; } return ''; } // Load matching credentials async function loadMatches() { const url = await getCurrentUrl(); if (!url) return; const matchesDiv = document.getElementById('matches'); matchesDiv.innerHTML = '
Loading...
'; chrome.runtime.sendMessage({ action: 'getMatches', url }, (response) => { if (chrome.runtime.lastError || !response || !response.success) { matchesDiv.innerHTML = '
Not connected to vault. Check settings.
'; return; } currentMatches = response.matches; if (!currentMatches || currentMatches.length === 0) { matchesDiv.innerHTML = '
No matching credentials
'; return; } let html = ''; currentMatches.forEach((entry, idx) => { const hasL2 = entry.data && entry.data.fields && entry.data.fields.some(f => f.l2); html += `
${escapeHtml(entry.title)}
${entry.type} ${hasL2 ? '🔒 L2' : ''}
`; }); matchesDiv.innerHTML = html; // Add click handlers document.querySelectorAll('.entry').forEach(el => { el.addEventListener('click', () => fillEntry(parseInt(el.dataset.idx))); }); }); } // Fill an entry into the page async function fillEntry(idx) { const entry = currentMatches[idx]; if (!entry || !entry.data || !entry.data.fields) return; // Get form fields from page chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => { chrome.tabs.sendMessage(tabs[0].id, { action: 'getFormFields' }, (response) => { if (chrome.runtime.lastError || !response || !response.success) { // Fallback: try simple fill simpleFill(entry); return; } // Request LLM mapping chrome.runtime.sendMessage({ action: 'mapFields', data: { entry_id: entry.entry_id, page_fields: response.fields } }, (mapResponse) => { if (mapResponse && mapResponse.success && mapResponse.mapping) { // Convert mapping to actual values const fields = {}; Object.entries(mapResponse.mapping).forEach(([label, selector]) => { const field = entry.data.fields.find(f => f.label === label); if (field && !field.l2) { fields[selector] = field.value; } }); chrome.runtime.sendMessage({ action: 'fill', fields }); } else { simpleFill(entry); } }); }); }); window.close(); } // Simple fill without LLM mapping function simpleFill(entry) { const fields = {}; entry.data.fields.forEach(f => { if (f.l2) return; if (f.label.toLowerCase().includes('user') || f.label.toLowerCase().includes('email')) { fields['input[type="email"], input[type="text"], input[name*="user"], input[name*="email"]'] = f.value; } if (f.label.toLowerCase().includes('password') || f.kind === 'password') { fields['input[type="password"]'] = f.value; } }); chrome.runtime.sendMessage({ action: 'fill', fields }); } // Settings handlers document.getElementById('settingsLink').addEventListener('click', (e) => { e.preventDefault(); document.getElementById('matchView').style.display = 'none'; document.getElementById('settingsView').classList.add('active'); loadSettings(); }); document.getElementById('backToMatches').addEventListener('click', () => { document.getElementById('settingsView').classList.remove('active'); document.getElementById('matchView').style.display = 'block'; }); document.getElementById('saveSettings').addEventListener('click', saveSettings); async function loadSettings() { chrome.runtime.sendMessage({ action: 'getSettings' }, (response) => { if (response && response.success) { document.getElementById('vaultUrl').value = response.settings.vaultUrl || ''; document.getElementById('apiToken').value = response.settings.apiToken || ''; } }); } async function saveSettings() { const vaultUrl = document.getElementById('vaultUrl').value.trim(); const apiToken = document.getElementById('apiToken').value.trim(); chrome.runtime.sendMessage({ action: 'saveSettings', vaultUrl, apiToken }, (response) => { const status = document.getElementById('settingsStatus'); if (response && response.success) { status.className = 'status success'; status.textContent = 'Settings saved!'; setTimeout(() => { document.getElementById('settingsView').classList.remove('active'); document.getElementById('matchView').style.display = 'block'; loadMatches(); }, 1000); } else { status.className = 'status error'; status.textContent = 'Failed to save settings'; } }); } function escapeHtml(str) { if (!str) return ''; return str.replace(/&/g, '&').replace(//g, '>'); } // Initialize loadMatches();