package main import ( "context" "sync" "github.com/getlantern/systray" ) // App owns the tray icon lifecycle and the registered features. type App struct { features []Feature } // newApp assembles the feature list. New features register here — nothing else // in the tray lifecycle needs to change. func newApp(cfg Config, dotenvPath string) *App { return &App{ features: []Feature{ newBalanceFeature(cfg, dotenvPath), // The harness daemon feature registers here in a later step. }, } } // Run blocks until the tray is closed, then shuts every feature down. func (a *App) Run() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() var wg sync.WaitGroup systray.Run(func() { systray.SetIcon(appIcon) systray.SetTitle("DeepSeek") menu := &Menu{} for _, f := range a.features { f.Install(menu) } for _, f := range a.features { wg.Add(1) go func(f Feature) { defer wg.Done() f.Run(ctx) }(f) } }, func() { cancel() for _, f := range a.features { f.Stop() } wg.Wait() }) }