Add feed curator to daemon for activity feed curation (gt-38doh)
Implements the feed daemon goroutine that: - Tails ~/gt/.events.jsonl for raw events - Filters by visibility tag (keeps feed/both, drops audit) - Deduplicates repeated done events from same actor - Aggregates sling events when multiple occur in window - Writes curated events to ~/gt/.feed.jsonl with summaries The curator runs as a goroutine in the gt daemon, starting when the daemon starts and stopping gracefully on shutdown. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/steveyegge/gastown/internal/beads"
|
||||
"github.com/steveyegge/gastown/internal/constants"
|
||||
"github.com/steveyegge/gastown/internal/feed"
|
||||
"github.com/steveyegge/gastown/internal/keepalive"
|
||||
"github.com/steveyegge/gastown/internal/polecat"
|
||||
"github.com/steveyegge/gastown/internal/tmux"
|
||||
@@ -25,11 +26,12 @@ import (
|
||||
// This is recovery-focused: normal wake is handled by feed subscription (bd activity --follow).
|
||||
// The daemon is the safety net for dead sessions, GUPP violations, and orphaned work.
|
||||
type Daemon struct {
|
||||
config *Config
|
||||
tmux *tmux.Tmux
|
||||
logger *log.Logger
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
config *Config
|
||||
tmux *tmux.Tmux
|
||||
logger *log.Logger
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
curator *feed.Curator
|
||||
}
|
||||
|
||||
// New creates a new daemon instance.
|
||||
@@ -90,6 +92,14 @@ func (d *Daemon) Run() error {
|
||||
|
||||
d.logger.Printf("Daemon running, initial heartbeat interval %v", nextInterval)
|
||||
|
||||
// Start feed curator goroutine
|
||||
d.curator = feed.NewCurator(d.config.TownRoot)
|
||||
if err := d.curator.Start(); err != nil {
|
||||
d.logger.Printf("Warning: failed to start feed curator: %v", err)
|
||||
} else {
|
||||
d.logger.Println("Feed curator started")
|
||||
}
|
||||
|
||||
// Initial heartbeat
|
||||
d.heartbeat(state)
|
||||
|
||||
@@ -392,6 +402,12 @@ func (d *Daemon) processLifecycleRequests() {
|
||||
func (d *Daemon) shutdown(state *State) error {
|
||||
d.logger.Println("Daemon shutting down")
|
||||
|
||||
// Stop feed curator
|
||||
if d.curator != nil {
|
||||
d.curator.Stop()
|
||||
d.logger.Println("Feed curator stopped")
|
||||
}
|
||||
|
||||
state.Running = false
|
||||
if err := SaveState(d.config.TownRoot, state); err != nil {
|
||||
d.logger.Printf("Warning: failed to save final state: %v", err)
|
||||
|
||||
Reference in New Issue
Block a user