Symptom
Docs (docs/features/tui/index.md, "Custom themes auto-reload when you save changes to the file — no restart needed") promise hot reload of ~/.cagent/themes/*.yaml, but editing a custom theme while the TUI runs does nothing until restart.
Root cause (confirmed via git history)
pkg/tui/styles/theme_watcher.go (NewThemeWatcher, fsnotify-based, debounced) and messages.ThemeFileChangedMsg still exist, and pkg/tui/tui.go still routes ThemeFileChangedMsg → handleThemeFileChanged (hot-reload handler in pkg/tui/handlers.go).
- But nothing constructs the watcher or emits the message anymore: the wiring (construct watcher with a callback emitting
ThemeFileChangedMsg via program.Send, Watch(currentTheme.Ref) on startup and after every theme change, Stop() on exit) was introduced in ad380824b ("Support for TUI themes") and dropped in 0069cadf7 ("Parallel session support with a new tab view to switch between sessions"), which rewrote pkg/tui/tui.go and kept only the message handler. NewThemeWatcher currently has no non-test caller.
Fix sketch
- Re-wire in the current appModel lifecycle: create the watcher where the model gets its
*tea.Program reference (SetProgram in cmd/root/new.go runTUIWrapped), callback → p.Send(messages.ThemeFileChangedMsg{ThemeRef: ref}).
Watch(ref) initially and re-Watch after handleChangeTheme / handleThemeFileChanged / preview-commit (the watcher already no-ops for built-in-only refs); Stop() on TUI shutdown.
- Regression test: temp themes dir (
paths.SetDataDir), start model via pkg/tui/tuitest, touch the theme file, assert a ThemeFileChangedMsg flows and styles.CurrentTheme() picks up the new color (the watcher has a 500 ms debounce — allow for it, or make the debounce injectable).
- If the fix is deferred instead: update
docs/features/tui/index.md to drop the hot-reload claim until restored.
Acceptance criteria
Symptom
Docs (
docs/features/tui/index.md, "Custom themes auto-reload when you save changes to the file — no restart needed") promise hot reload of~/.cagent/themes/*.yaml, but editing a custom theme while the TUI runs does nothing until restart.Root cause (confirmed via git history)
pkg/tui/styles/theme_watcher.go(NewThemeWatcher, fsnotify-based, debounced) andmessages.ThemeFileChangedMsgstill exist, andpkg/tui/tui.gostill routesThemeFileChangedMsg→handleThemeFileChanged(hot-reload handler inpkg/tui/handlers.go).ThemeFileChangedMsgviaprogram.Send,Watch(currentTheme.Ref)on startup and after every theme change,Stop()on exit) was introduced inad380824b("Support for TUI themes") and dropped in0069cadf7("Parallel session support with a new tab view to switch between sessions"), which rewrotepkg/tui/tui.goand kept only the message handler.NewThemeWatchercurrently has no non-test caller.Fix sketch
*tea.Programreference (SetProgramincmd/root/new.gorunTUIWrapped), callback →p.Send(messages.ThemeFileChangedMsg{ThemeRef: ref}).Watch(ref)initially and re-WatchafterhandleChangeTheme/handleThemeFileChanged/ preview-commit (the watcher already no-ops for built-in-only refs);Stop()on TUI shutdown.paths.SetDataDir), start model viapkg/tui/tuitest, touch the theme file, assert aThemeFileChangedMsgflows andstyles.CurrentTheme()picks up the new color (the watcher has a 500 ms debounce — allow for it, or make the debounce injectable).docs/features/tui/index.mdto drop the hot-reload claim until restored.Acceptance criteria
Close()called).