watcher

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 26, 2026 License: Apache-2.0 Imports: 5 Imported by: 0

Documentation

Overview

Package watcher emits debounced events when files under the active .baifo/ directory change. The App subscribes once at boot, registers per-file callbacks, and the watcher takes care of the rest: native inotify/kqueue events come in noisy (editors write+rename+rename, some atomic-save dance, ...), so we debounce by 250ms before firing the callback.

The package is intentionally small: it does not understand baifo's own config schema, it just routes events by absolute path. The App owns the "if baifo.yaml changed, reload providers + mcps" mapping.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Handler

type Handler func(path string)

Handler is invoked when one of the watched paths changes. The path is the absolute path as returned by fsnotify.

type Watcher

type Watcher struct {
	// contains filtered or unexported fields
}

Watcher fans fsnotify events into per-path Handlers with debouncing. Construct one with New, register paths with OnChange, then Start. Close releases the underlying fsnotify watcher.

func New

func New() (*Watcher, error)

New creates a Watcher. The underlying fsnotify.Watcher is created eagerly so configuration errors (e.g. inotify exhaustion) surface at construction, not at Start.

func (*Watcher) Close

func (w *Watcher) Close() error

Close stops the watcher and releases the underlying resources. Safe to call multiple times.

func (*Watcher) OnChange

func (w *Watcher) OnChange(absPath string, h Handler) error

OnChange registers a Handler for the exact absolute path.

We watch the file's PARENT DIRECTORY, not just the file inode. This is the fix for the classic fsnotify footgun: editors (vim with backups, VSCode, and basically every "atomic save" scheme) write to a temp file and rename it over the target, so baifo.yaml becomes a brand-new inode on every save. An inode-level watch on the old file goes permanently deaf the instant that rename lands — which is why hot-reload silently stopped firing after the first edit. A directory watch survives the swap because the directory inode is stable, and fsnotify reports child events with their full path, so dispatch still routes them by exact path match.

We additionally add the file inode directly when it exists. That is redundant for correctness (the dir watch already covers it) but lets plain in-place writes fire without depending on directory-event delivery; a missing file is fine since the dir watch catches its creation.

func (*Watcher) OnChangeInDir

func (w *Watcher) OnChangeInDir(absDir string, h Handler) error

OnChangeInDir registers a Handler that fires for any file change inside absDir (recursive coverage is limited to the immediate directory — fsnotify itself is not recursive). Use this for directories like .baifo/skills/ where each skill is a sub-folder.

func (*Watcher) Start

func (w *Watcher) Start()

Start launches the event loop. Returns immediately; events arrive on the goroutine spawned here. Call Close to stop.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL