Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions internal/ui/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -452,12 +452,12 @@ func (m *AppModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
// Task just became blocked - ring bell and show notification
m.notification = fmt.Sprintf("⚠ Task #%d needs input: %s", t.ID, t.Title)
m.notifyUntil = time.Now().Add(10 * time.Second)
fmt.Print("\a") // Ring terminal bell
RingBell() // Ring terminal bell (writes to /dev/tty to bypass TUI)
} else if t.Status == db.StatusDone && db.IsInProgress(prevStatus) {
// Task completed - ring bell and show notification
m.notification = fmt.Sprintf("✓ Task #%d complete: %s", t.ID, t.Title)
m.notifyUntil = time.Now().Add(5 * time.Second)
fmt.Print("\a") // Ring terminal bell
RingBell() // Ring terminal bell (writes to /dev/tty to bypass TUI)
}
}
m.prevStatuses[t.ID] = t.Status
Expand Down Expand Up @@ -567,11 +567,11 @@ func (m *AppModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if event.Task.Status == db.StatusBlocked {
m.notification = fmt.Sprintf("⚠ Task #%d needs input: %s", event.TaskID, event.Task.Title)
m.notifyUntil = time.Now().Add(10 * time.Second)
fmt.Print("\a") // Ring terminal bell
RingBell() // Ring terminal bell (writes to /dev/tty to bypass TUI)
} else if event.Task.Status == db.StatusDone && db.IsInProgress(prevStatus) {
m.notification = fmt.Sprintf("✓ Task #%d complete: %s", event.TaskID, event.Task.Title)
m.notifyUntil = time.Now().Add(5 * time.Second)
fmt.Print("\a") // Ring terminal bell
RingBell() // Ring terminal bell (writes to /dev/tty to bypass TUI)
} else if db.IsInProgress(event.Task.Status) {
m.notification = fmt.Sprintf("▶ Task #%d started: %s", event.TaskID, event.Task.Title)
m.notifyUntil = time.Now().Add(3 * time.Second)
Expand Down
23 changes: 23 additions & 0 deletions internal/ui/bell.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package ui

import (
"os"
)

// RingBell sends the BEL character (\a) to the terminal to trigger an audible bell.
// It writes directly to /dev/tty to bypass any stdout buffering that might occur
// when running inside a TUI framework like Bubble Tea.
func RingBell() {
// Open /dev/tty directly to write to the actual terminal
// This bypasses Bubble Tea's alternate screen buffer and stdout capture
tty, err := os.OpenFile("/dev/tty", os.O_WRONLY, 0)
if err != nil {
// Fallback to stderr if /dev/tty is not available
// (stderr is less likely to be captured than stdout)
os.Stderr.WriteString("\a")
return
}
defer tty.Close()

tty.WriteString("\a")
}