Files
antidrift/internal/notify/notify.go
T

46 lines
1.5 KiB
Go

// internal/notify/notify.go
// Package notify is Keel's desktop-notification effector: a best-effort
// "interrupt the user" primitive behind a Notifier port. On Linux with
// notify-send installed it pops a toast; everywhere else it is a silent nop.
// Mirrors internal/enforce: a pure OS primitive, all policy lives in callers.
package notify
import (
"context"
"fmt"
"os/exec"
)
// Notifier shows a desktop notification. Best-effort: it returns an error for
// diagnostics, but callers never block on it and treat failure as "no toast."
type Notifier interface {
Notify(ctx context.Context, title, body string) error
}
// NewNotifier returns the notify-send adapter when that binary is on PATH, else
// a nop. This makes a missing binary (or a non-Linux host) degrade to silence
// rather than an error.
func NewNotifier() Notifier {
if path, err := exec.LookPath("notify-send"); err == nil {
return sendNotifier{bin: path}
}
return nopNotifier{}
}
// sendNotifier shells out to notify-send. The app name groups Keel's toasts.
type sendNotifier struct{ bin string }
func (s sendNotifier) Notify(ctx context.Context, title, body string) error {
cmd := exec.CommandContext(ctx, s.bin, "--app-name=Keel", title, body)
if err := cmd.Run(); err != nil {
return fmt.Errorf("notify: notify-send: %w", err)
}
return nil
}
// nopNotifier is the silent fallback.
type nopNotifier struct{}
func (nopNotifier) Notify(context.Context, string, string) error { return nil }