feat: add theme hot-reload functionality
Summary
Adds the ability to reload themes without restarting opencode. Provides multiple reload triggers to support different workflows:
| Trigger | Use Case |
|---|---|
/reload-theme command |
Manual reload when needed |
| File watchers | Auto-reload on config/theme file edits |
| Window resize | Re-detect terminal colors for "system" theme |
| SIGUSR1/SIGUSR2 | Integration point for external automation |
Also makes "system" theme background transparent to support terminal opacity.
Changes
theme.tsx | +178 Core: reloadTheme(), file watchers, signal handlers
app.tsx | -66/+9 Moved getTerminalBackgroundColor, added command
autocomplete.tsx | +5 Added /reload-theme slash command
Architecture
flowchart LR
subgraph Triggers
A[Command]
B[File change]
C[Resize]
D[Signal]
end
A & B & C & D --> E[reloadTheme]
E --> F[Re-query colors]
F --> G[Update store]
G --> H[UI re-renders]
Key Decisions
Why move getTerminalBackgroundColor to theme.tsx?
Needed by both initial detection (app.tsx) and reload (theme.tsx). Moving it eliminates duplication.
Why fs.watch() instead of @parcel/watcher?
Simpler API, no extra dependencies, sufficient for watching 2 files.
Why transparent background for "system" theme? Allows terminal opacity/blur to show through while keeping panel/menu backgrounds solid.
Why SIGWINCH handler? Event-driven color re-detection without polling. Only active for "system" theme.
Testing
# Command
/reload-theme
# File watcher
echo '{"theme":"dracula"}' > ~/.config/opencode/opencode.json
# Signal (Unix)
kill -USR1 $(pgrep opencode)
# Resize (system theme)
# Change terminal colors, then resize window
Checklist
- [x] Commands work (palette + slash)
- [x] File watchers trigger reload
- [x] Signal handlers work (Unix)
- [x] Proper cleanup on unmount
- [x] TypeScript passes
- [x] Follows AGENTS.md style
Fixes #815
Is this feature still being worked on? Hot reloading the theme would be a really nice functionality for theme switching!