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 <noreply@anthropic.com>
This commit is contained in:
Alejandro Gutiérrez
2026-02-28 16:46:20 +00:00
parent c2e8fcaa94
commit 059004b6f2
3 changed files with 24 additions and 17 deletions

View File

@@ -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) {

View File

@@ -314,6 +314,7 @@ export function updateProjectSessions(projects: Project[], sessions: Map<string,
const IDLE_SOUND_DELAY_MS = 10_000
const pendingIdle = new Map<string, number>() // path → timestamp when first went idle
const notifiedIdle = new Set<string>() // 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
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

View File

@@ -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)