feat: add --theme flag to preselect TUI theme#2933
Conversation
Validate explicit --theme values early with a new validateTheme helper so typos fail fast with a helpful message listing available themes, instead of silently falling back at TUI startup. Update flag help text to clarify the theme is ignored outside the interactive TUI. Add tests for validateTheme, applyTheme precedence, and theme completion.
docker-agent
left a comment
There was a problem hiding this comment.
Assessment: 🟡 NEEDS ATTENTION
This PR adds a --theme flag to preselect TUI themes. The implementation is generally clean with good validation and completion support. Two issues were found:
- Theme validation fires in
--execmode (CONFIRMED): contradicts the flag's own help text saying it's ignored outside TUI - Missing precedence test (LIKELY): user config theme + flag override interaction is not covered by tests
The core logic (precedence order, error messages, shell completion) is correct.
| // Validate an explicit --theme value early so a typo fails fast with a | ||
| // helpful message instead of silently falling back to the default theme | ||
| // once the TUI starts. | ||
| if f.theme != "" { |
There was a problem hiding this comment.
[MEDIUM] --theme validation fires in --exec mode, contradicting "ignored outside TUI" docs
The flag's help text says the --theme flag is "ignored outside the interactive TUI", but validateTheme is called unconditionally from runRunCommand — the shared entry point for both interactive and --exec (non-TUI) modes.
This means:
docker agent run --exec --theme does-not-exist config.yaml
…will error out with unknown theme "does-not-exist"; available themes: … instead of silently ignoring the flag as the documentation promises.
Suggested fix: Gate the validation on whether the command is actually launching the interactive TUI (e.g. skip validation when --exec is set):
if f.theme != "" && !f.exec {
if err := validateTheme(f.theme); err != nil {
return err
}
}Or update the flag's help text to say the flag is validated even in exec mode (even if the theme is not applied).
| }) | ||
| } | ||
|
|
||
| func TestApplyThemePrecedence(t *testing.T) { |
There was a problem hiding this comment.
[MEDIUM] TestApplyThemePrecedence missing test for user-config theme + --theme flag precedence
TestApplyThemePrecedence never sets a user config theme (userSettings.Theme != ""), so the critical precedence path — where both a user config theme and the --theme flag override are present — is never exercised.
The applyTheme logic has two layers:
- Apply user config theme if set (overrides default)
- Apply
--themeflag override if set (overrides user config)
If this ordering were accidentally swapped in a future refactor (user config checked after flag instead of before), the existing tests would not catch the regression because they only test the flag override against an empty user config.
Suggested addition to TestApplyThemePrecedence:
t.Run("flag override wins over user config theme", func(t *testing.T) {
// Write a user config that pins a different theme
userConfigPath := filepath.Join(dir, "config.json")
_ = os.WriteFile(userConfigPath, []byte(`{"theme":"dracula"}`), 0o600)
applyTheme("nord") // --theme flag should override the config's "dracula"
assert.Equal(t, "nord", styles.CurrentTheme().Ref)
})
Users often prefer a consistent visual theme across all agents and environments. Rather than repeatedly selecting a theme from the TUI menu, a
--themeflag ondocker agent runlets them preselect a theme by name at launch.The implementation maintains a clear precedence: explicit
--themeflag wins, falling back to any theme configured in the agent config, then to the built-in default. An invalid theme name is caught early with a helpful "unknown theme; available themes: ..." error instead of silently falling back. The flag is registered with shell completion via a newcompleteThemefunction backed bystyles.ListThemeRefs(), and its help text clarifies that it only applies in interactive TUI mode.Tests cover validation, precedence (including interactions with isolated config/data directories), and shell completion.