From cf798f3f7e7c3ece9e6d0220604a3c7dfe486aed Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Thu, 2 Apr 2026 20:04:09 -0700 Subject: [PATCH] fix: replace 40+ silent catch blocks with debug logging MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every empty catch {} in sidepanel.js, sidebar-agent.ts now logs with [gstack sidebar] or [sidebar-agent] prefix. Chat poll 401s, stop agent, tab poll, clear chat, SSE parse, refs fetch, stream JSON parse, queue read/parse, process kill — all now visible in console. Co-Authored-By: Claude Opus 4.6 (1M context) --- browse/src/sidebar-agent.ts | 38 +++++++++++++++++------ extension/sidepanel.js | 60 +++++++++++++++++++++++++++---------- 2 files changed, 73 insertions(+), 25 deletions(-) diff --git a/browse/src/sidebar-agent.ts b/browse/src/sidebar-agent.ts index 22f0f53b..d4826535 100644 --- a/browse/src/sidebar-agent.ts +++ b/browse/src/sidebar-agent.ts @@ -30,7 +30,8 @@ function getGitRoot(): string | null { try { const { execSync } = require('child_process'); return execSync('git rev-parse --show-toplevel', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim(); - } catch { + } catch (err: any) { + console.debug('[sidebar-agent] Not in a git repo:', err.message); return null; } } @@ -74,7 +75,8 @@ async function refreshToken(): Promise { const data = JSON.parse(fs.readFileSync(stateFile, 'utf-8')); authToken = data.token || null; return authToken; - } catch { + } catch (err: any) { + console.error('[sidebar-agent] Failed to refresh auth token:', err.message); return null; } } @@ -234,7 +236,10 @@ async function askClaude(queueEntry: any): Promise { // Validate cwd exists — queue may reference a stale worktree let effectiveCwd = cwd || process.cwd(); - try { fs.accessSync(effectiveCwd); } catch { effectiveCwd = process.cwd(); } + try { fs.accessSync(effectiveCwd); } catch (err: any) { + console.warn('[sidebar-agent] Worktree path inaccessible, falling back to cwd:', effectiveCwd, err.message); + effectiveCwd = process.cwd(); + } const proc = spawn('claude', claudeArgs, { stdio: ['pipe', 'pipe', 'pipe'], @@ -264,7 +269,9 @@ async function askClaude(queueEntry: any): Promise { buffer = lines.pop() || ''; for (const line of lines) { if (!line.trim()) continue; - try { handleStreamEvent(JSON.parse(line), tid); } catch {} + try { handleStreamEvent(JSON.parse(line), tid); } catch (err: any) { + console.error(`[sidebar-agent] Tab ${tid}: Failed to parse stream line:`, line.slice(0, 100), err.message); + } } }); @@ -275,7 +282,9 @@ async function askClaude(queueEntry: any): Promise { proc.on('close', (code) => { if (buffer.trim()) { - try { handleStreamEvent(JSON.parse(buffer), tid); } catch {} + try { handleStreamEvent(JSON.parse(buffer), tid); } catch (err: any) { + console.error(`[sidebar-agent] Tab ${tid}: Failed to parse final buffer:`, buffer.slice(0, 100), err.message); + } } const doneEvent: Record = { type: 'agent_done' }; if (code !== 0 && stderrBuffer.trim()) { @@ -300,7 +309,9 @@ async function askClaude(queueEntry: any): Promise { // Timeout (default 300s / 5 min — multi-page tasks need time) const timeoutMs = parseInt(process.env.SIDEBAR_AGENT_TIMEOUT || '300000', 10); setTimeout(() => { - try { proc.kill(); } catch {} + try { proc.kill(); } catch (killErr: any) { + console.warn(`[sidebar-agent] Tab ${tid}: Failed to kill timed-out process:`, killErr.message); + } const timeoutMsg = stderrBuffer.trim() ? `Timed out after ${timeoutMs / 1000}s\nstderr: ${stderrBuffer.trim().slice(-500)}` : `Timed out after ${timeoutMs / 1000}s`; @@ -317,14 +328,20 @@ async function askClaude(queueEntry: any): Promise { function countLines(): number { try { return fs.readFileSync(QUEUE, 'utf-8').split('\n').filter(Boolean).length; - } catch { return 0; } + } catch (err: any) { + console.error('[sidebar-agent] Failed to read queue file:', err.message); + return 0; + } } function readLine(n: number): string | null { try { const lines = fs.readFileSync(QUEUE, 'utf-8').split('\n').filter(Boolean); return lines[n - 1] || null; - } catch { return null; } + } catch (err: any) { + console.error(`[sidebar-agent] Failed to read queue line ${n}:`, err.message); + return null; + } } async function poll() { @@ -337,7 +354,10 @@ async function poll() { if (!line) continue; let entry: any; - try { entry = JSON.parse(line); } catch { continue; } + try { entry = JSON.parse(line); } catch (err: any) { + console.warn(`[sidebar-agent] Skipping malformed queue entry at line ${lastLine}:`, line.slice(0, 80), err.message); + continue; + } if (!entry.message && !entry.prompt) continue; const tid = entry.tabId ?? 0; diff --git a/extension/sidepanel.js b/extension/sidepanel.js index 888f9d35..c0f1d8c1 100644 --- a/extension/sidepanel.js +++ b/extension/sidepanel.js @@ -375,7 +375,10 @@ async function pollChat() { headers: authHeaders(), signal: AbortSignal.timeout(3000), }); - if (!resp.ok) return; + if (!resp.ok) { + console.warn(`[gstack sidebar] Chat poll failed: ${resp.status} ${resp.statusText}`); + return; + } const data = await resp.json(); // Detect tab switch from server — swap chat context @@ -417,7 +420,9 @@ async function pollChat() { // Show/hide stop button based on agent status updateStopButton(data.agentStatus === 'processing'); - } catch {} + } catch (err) { + console.error('[gstack sidebar] Chat poll error:', err.message); + } } /** Switch the sidebar to show a different tab's chat context */ @@ -464,8 +469,11 @@ function updateStopButton(agentRunning) { async function stopAgent() { if (!serverUrl) return; try { - await fetch(`${serverUrl}/sidebar-agent/stop`, { method: 'POST', headers: authHeaders() }); - } catch {} + const resp = await fetch(`${serverUrl}/sidebar-agent/stop`, { method: 'POST', headers: authHeaders() }); + if (!resp.ok) console.warn(`[gstack sidebar] Stop agent failed: ${resp.status}`); + } catch (err) { + console.error('[gstack sidebar] Stop agent error:', err.message); + } // Immediately clean up UI const thinking = document.getElementById('agent-thinking'); if (thinking) thinking.remove(); @@ -511,13 +519,18 @@ async function pollTabs() { try { const chromeTabs = await chrome.tabs.query({ active: true, currentWindow: true }); activeTabUrl = chromeTabs?.[0]?.url || null; - } catch {} + } catch (err) { + console.debug('[gstack sidebar] Failed to get active tab URL:', err.message); + } const resp = await fetch(`${serverUrl}/sidebar-tabs${activeTabUrl ? '?activeUrl=' + encodeURIComponent(activeTabUrl) : ''}`, { headers: authHeaders(), signal: AbortSignal.timeout(2000), }); - if (!resp.ok) return; + if (!resp.ok) { + console.warn(`[gstack sidebar] Tab poll failed: ${resp.status} ${resp.statusText}`); + return; + } const data = await resp.json(); if (!data.tabs) return; @@ -527,7 +540,9 @@ async function pollTabs() { lastTabJson = json; renderTabBar(data.tabs); - } catch {} + } catch (err) { + console.error('[gstack sidebar] Tab poll error:', err.message); + } } function renderTabBar(tabs) { @@ -573,7 +588,9 @@ async function switchBrowserTab(tabId) { // Switch chat context + re-poll tabs switchChatTab(tabId); pollTabs(); - } catch {} + } catch (err) { + console.error('[gstack sidebar] Failed to switch browser tab:', err.message); + } } // ─── Clear Chat ───────────────────────────────────────────────── @@ -581,8 +598,11 @@ async function switchBrowserTab(tabId) { document.getElementById('clear-chat').addEventListener('click', async () => { if (!serverUrl) return; try { - await fetch(`${serverUrl}/sidebar-chat/clear`, { method: 'POST', headers: authHeaders() }); - } catch {} + const resp = await fetch(`${serverUrl}/sidebar-chat/clear`, { method: 'POST', headers: authHeaders() }); + if (!resp.ok) console.warn(`[gstack sidebar] Clear chat failed: ${resp.status}`); + } catch (err) { + console.error('[gstack sidebar] Clear chat error:', err.message); + } // Reset local state chatLineCount = 0; renderedEntryIds.clear(); @@ -734,7 +754,9 @@ function connectSSE() { eventSource = new EventSource(url); eventSource.addEventListener('activity', (e) => { - try { addEntry(JSON.parse(e.data)); } catch {} + try { addEntry(JSON.parse(e.data)); } catch (err) { + console.error('[gstack sidebar] Failed to parse activity event:', err.message); + } }); eventSource.addEventListener('gap', (e) => { @@ -745,7 +767,9 @@ function connectSSE() { banner.className = 'gap-banner'; banner.textContent = `Missed ${data.availableFrom - data.gapFrom} events`; feed.appendChild(banner); - } catch {} + } catch (err) { + console.error('[gstack sidebar] Failed to parse gap event:', err.message); + } }); } @@ -780,7 +804,9 @@ async function fetchRefs() { `).join(''); footer.textContent = `${data.refs.length} refs`; - } catch {} + } catch (err) { + console.error('[gstack sidebar] Failed to fetch refs:', err.message); + } } // ─── Inspector Tab ────────────────────────────────────────────── @@ -1292,15 +1318,17 @@ function connectInspectorSSE() { try { const data = JSON.parse(e.data); inspectorShowData(data); - } catch {} + } catch (err) { + console.error('[gstack sidebar] Failed to parse inspectResult:', err.message); + } }); inspectorSSE.addEventListener('error', () => { // SSE connection failed — inspector works without it (basic mode) if (inspectorSSE) { inspectorSSE.close(); inspectorSSE = null; } }); - } catch { - // SSE not available — that's fine + } catch (err) { + console.debug('[gstack sidebar] Inspector SSE not available:', err.message); } }