Documentation
¶
Overview ¶
Package notify implements a small persistent notification queue used by the projmux status bar. Entries are stored until explicit ack or the bounded reconcile policy evicts expired-gone or hard-cap overflow rows.
Note: the click handler in the status bar will call `projmux internal focus --target=... --source=os-notification` — but this package does NOT call focus itself. It is pure storage.
Index ¶
- Constants
- Variables
- func FormatTarget(t Target) string
- func ValidateSeverity(value string) error
- func ValidateSource(value string) error
- type Clock
- type Notification
- type PushInput
- type PushResult
- type ReconcileResult
- type Store
- func (s *Store) Ack(id string) error
- func (s *Store) AckAll() (int, error)
- func (s *Store) List() ([]Notification, error)
- func (s *Store) Path() string
- func (s *Store) Push(in PushInput) (Notification, PushResult, error)
- func (s *Store) Reconcile(targetExists TargetExistsFunc) (ReconcileResult, error)
- func (s *Store) SetClock(c Clock)
- type Target
- type TargetExistsFunc
Constants ¶
const ( SeverityInfo = "info" SeverityWarn = "warn" SeverityCritical = "critical" )
Severity values accepted on push.
const ( SourceAI = "ai" SourceK8s = "k8s" SourceGit = "git" SourceExternal = "external" )
Source values accepted on push.
const ( MetaAgent = "agent" MetaTopic = "topic" MetaEvent = "event" MetaCategory = "category" MetaState = "state" )
Metadata keys shared by the notify produce/consume/reconcile sites.
const DefaultTTL = 600 * time.Second
DefaultTTL is the default freshness window applied when the caller does not supply --ttl. Expiration alone does not remove a pending entry; reconcile requires both expiration and a gone target unless the hard cap is exceeded.
const MaxQueueEntries = 256
MaxQueueEntries is the hard upper bound applied by Reconcile. Push remains append/replace-only so producer and explicit-ack semantics do not change; the queue is trimmed to its most recent entries only during reconciliation.
const MaxTextLength = 80
MaxTextLength caps the stored Text on push. Longer text is truncated (preserving leading content). v0 keeps no extension field; the truncation is destructive.
const NotifyFileName = "notify.json"
NotifyFileName is the basename of the queue file inside StateDir.
Variables ¶
var ErrInvalidSeverity = errors.New("invalid severity")
ErrInvalidSeverity indicates a severity value outside the allowed set.
var ErrInvalidSource = errors.New("invalid source")
ErrInvalidSource indicates a source value outside the allowed set.
var ErrInvalidTTL = errors.New("invalid ttl")
ErrInvalidTTL indicates a non-positive TTL was supplied.
var ErrInvalidTarget = errors.New("invalid target")
ErrInvalidTarget indicates the target string could not be parsed or the session field was empty.
var ErrInvalidText = errors.New("invalid text")
ErrInvalidText indicates the supplied text was empty after trimming.
var ErrNotFound = errors.New("notification not found")
ErrNotFound indicates an ack was requested for an unknown id.
Functions ¶
func FormatTarget ¶
FormatTarget renders a Target as SESSION[:WINDOW[.PANE]].
func ValidateSeverity ¶
ValidateSeverity returns nil if value is one of the accepted severities.
func ValidateSource ¶
ValidateSource returns nil if value is one of the accepted sources.
Types ¶
type Notification ¶
type Notification struct {
ID string `json:"id"`
Text string `json:"text"`
Severity string `json:"severity"`
Socket string `json:"socket,omitempty"`
Session string `json:"session"`
Window string `json:"window,omitempty"`
Pane string `json:"pane,omitempty"`
Source string `json:"source"`
Metadata map[string]string `json:"metadata,omitempty"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt time.Time `json:"expires_at"`
}
Notification is a single queued status-bar entry.
type PushInput ¶
type PushInput struct {
ID string
Text string
Severity string
Source string
Metadata map[string]string
TTL time.Duration
Target Target
}
PushInput captures the user-provided fields for a push call. CreatedAt is supplied by the store at write time so callers can leave it zero.
type PushResult ¶
type PushResult struct {
ID string
QueueLen int
Replaced bool // true if the push replaced an entry with the same ID.
WasExpired bool // true if the existing entry had already expired.
}
PushResult is returned to callers after a successful Push.
type ReconcileResult ¶ added in v0.8.0
ReconcileResult summarizes automatic queue eviction.
func (ReconcileResult) Removed ¶ added in v0.8.0
func (r ReconcileResult) Removed() int
Removed returns the total number of entries evicted.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store persists notifications to a JSON file inside StateDir.
func NewDefaultStore ¶
NewDefaultStore builds a Store that uses the canonical notify.json under the supplied projmux paths.
func (*Store) Ack ¶
Ack removes a single entry by id and returns ErrNotFound if absent. Note that an entry whose ttl already expired still counts as "found" because users may ack a stale id without first listing.
func (*Store) List ¶
func (s *Store) List() ([]Notification, error)
List returns all pending entries in recency-desc order. It is read-only: expiration metadata never causes List itself to remove an entry.
func (*Store) Push ¶
func (s *Store) Push(in PushInput) (Notification, PushResult, error)
Push appends or replaces a notification. Validation is performed first so invalid input does not contend for the lock.
func (*Store) Reconcile ¶ added in v0.8.0
func (s *Store) Reconcile(targetExists TargetExistsFunc) (ReconcileResult, error)
Reconcile applies the queue's bounded-retention policy atomically. It removes only expired entries whose tmux target no longer exists, then keeps at most MaxQueueEntries of the remaining entries, evicting oldest first. Live expired entries are retained unless they fall into the hard-cap overflow. This is the only automatic removal path; Push and List never evict.
type Target ¶
Target groups the routing fields of a notification.
func ParseTarget ¶
ParseTarget parses a SESSION[:WINDOW[.PANE]] string. The SESSION segment is required and must be non-empty after trimming.
type TargetExistsFunc ¶ added in v0.8.0
type TargetExistsFunc func(Notification) bool
TargetExistsFunc reports whether a notification's tmux target is still present. A nil function means target inventory is unavailable, so reconciliation skips TTL-based removal and only enforces the hard cap.