diff --git a/browse/src/server.ts b/browse/src/server.ts index 30cbe642..2124cc4d 100644 --- a/browse/src/server.ts +++ b/browse/src/server.ts @@ -1873,7 +1873,11 @@ async function start() { const activeTab = browserManager?.getActiveTabId?.() ?? 0; // Return per-tab agent status so the sidebar shows the right state per tab const tabAgentStatus = tabId !== null ? getTabAgentStatus(tabId) : agentStatus; - return new Response(JSON.stringify({ entries, total: chatNextId, agentStatus: tabAgentStatus, activeTabId: activeTab }), { + // Piggyback security state on the existing 300ms poll. Cheap: + // getSecurityStatus reads ~/.gstack/security/session-state.json. + // Sidepanel uses this to flip the shield icon when classifier + // warmup completes after initial connect. + return new Response(JSON.stringify({ entries, total: chatNextId, agentStatus: tabAgentStatus, activeTabId: activeTab, security: getSecurityStatus() }), { status: 200, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': 'http://127.0.0.1' }, }); diff --git a/extension/sidepanel.js b/extension/sidepanel.js index 28821bc6..cb11d244 100644 --- a/extension/sidepanel.js +++ b/extension/sidepanel.js @@ -557,6 +557,12 @@ async function pollChat() { if (data.total === 0 && welcome) welcome.style.display = ''; } + // Shield icon state rides the chat poll (every 300ms in fast mode, + // slower when idle). When the ML classifier finishes warming after + // initial connect — typically 30s on first run — the shield flips + // from 'off' to 'protected' without the user needing to reload. + if (data.security) updateSecurityShield(data.security); + if (data.entries && data.entries.length > 0) { // Hide welcome on first real entry const welcome = document.getElementById('chat-welcome');