From 059004b6f25fe15c54d1ba31792dc16dbe7a74df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Guti=C3=A9rrez?= <35082514+alezmad@users.noreply.github.com> Date: Sat, 28 Feb 2026 16:46:20 +0000 Subject: [PATCH] fix: space after pane status icons, prevent repeated idle notification sounds - Add space between status icon and project name in pane list for readability - Add notifiedIdle set to checkTransitions to prevent re-triggering sound after busySessions fluctuations during the same idle period Co-Authored-By: Claude Opus 4.6 --- src/components/direct-grid.ts | 8 ++++---- src/data/monitor.ts | 27 +++++++++++++++++---------- src/ui/panels.ts | 6 +++--- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/components/direct-grid.ts b/src/components/direct-grid.ts index 724311d..3a35ec8 100644 --- a/src/components/direct-grid.ts +++ b/src/components/direct-grid.ts @@ -753,9 +753,9 @@ export class DirectGridRenderer { // Status icon: ● green=running, ◉ yellow=idle, ○ dim=unknown let statusIcon: string - if (pane.status === "busy") statusIcon = `${hexFg("#9ece6a")}●${RESET}` - else if (pane.status === "idle") statusIcon = `${hexFg("#e0af68")}◉${RESET}` - else statusIcon = `${DIM}○${RESET}` + if (pane.status === "busy") statusIcon = `${hexFg("#9ece6a")}● ${RESET}` + else if (pane.status === "idle") statusIcon = `${hexFg("#e0af68")}◉ ${RESET}` + else statusIcon = `${DIM}○ ${RESET}` const startCol = col if (isFocused) { @@ -763,7 +763,7 @@ export class DirectGridRenderer { } else { out += `${statusIcon}${DIM}${short}${RESET}` } - col += 1 + short.length // icon + name + col += 2 + short.length // icon + space + name this.paneListHitRegions.push({ tabId: tab.id, paneIndex: pi, startCol, endCol: col - 1 }) if (pi < tabPanes.length - 1) { diff --git a/src/data/monitor.ts b/src/data/monitor.ts index f9c6a67..a5c8ed0 100644 --- a/src/data/monitor.ts +++ b/src/data/monitor.ts @@ -314,6 +314,7 @@ export function updateProjectSessions(projects: Project[], sessions: Map() // path → timestamp when first went idle +const notifiedIdle = new Set() // paths already notified — prevents re-trigger export function checkTransitions( projects: Project[], @@ -325,20 +326,26 @@ export function checkTransitions( const prev = prevBusy.get(project.path) || 0 const isIdle = project.busySessions === 0 && project.activeSessions > 0 - if (prev > 0 && isIdle && !pendingIdle.has(project.path)) { + if (!isIdle) { + // Not idle — clear notification state so next idle transition can fire + notifiedIdle.delete(project.path) + pendingIdle.delete(project.path) + continue + } + + // Already notified for this idle period — skip + if (notifiedIdle.has(project.path)) continue + + if (prev > 0 && !pendingIdle.has(project.path)) { // Just transitioned busy→idle — start the delay timer pendingIdle.set(project.path, now) } - if (pendingIdle.has(project.path)) { - if (!isIdle) { - // Went busy again — false alarm, cancel - pendingIdle.delete(project.path) - } else if (now - pendingIdle.get(project.path)! >= IDLE_SOUND_DELAY_MS) { - // Confirmed idle for 10+ seconds - transitioned.push(project.name) - pendingIdle.delete(project.path) - } + if (pendingIdle.has(project.path) && now - pendingIdle.get(project.path)! >= IDLE_SOUND_DELAY_MS) { + // Confirmed idle for 10+ seconds — notify once + transitioned.push(project.name) + pendingIdle.delete(project.path) + notifiedIdle.add(project.path) } } return transitioned diff --git a/src/ui/panels.ts b/src/ui/panels.ts index 56c8ad2..3d5692d 100644 --- a/src/ui/panels.ts +++ b/src/ui/panels.ts @@ -96,9 +96,9 @@ export function updatePaneList() { const isFocused = app.directGrid!.activeTabId === tab.id && app.directGrid!.focusIndex === pi // Status icon: ● green=running, ◉ yellow=idle, ○ dim=unknown - const statusIcon = pane.status === "busy" ? green("●") - : pane.status === "idle" ? yellow("◉") - : dim("○") + const statusIcon = pane.status === "busy" ? green("● ") + : pane.status === "idle" ? yellow("◉ ") + : dim("○ ") if (!first) parts.push(dim(" · ")) parts.push(statusIcon)