From 5e4a73b02f456fa897845b413ad1508ba4d9f752 Mon Sep 17 00:00:00 2001 From: YoneRai12 Date: Thu, 18 Jun 2026 13:31:11 +0900 Subject: [PATCH] fix: allow CLI config theme setting --- clients/cli/yonerai_cli/commands/config.py | 2 ++ clients/cli/yonerai_cli/config.py | 6 +++++ tests/test_cli_theme.py | 31 +++++++++++++++++++++- 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/clients/cli/yonerai_cli/commands/config.py b/clients/cli/yonerai_cli/commands/config.py index b1fc0fda..b08dd9bb 100644 --- a/clients/cli/yonerai_cli/commands/config.py +++ b/clients/cli/yonerai_cli/commands/config.py @@ -14,6 +14,7 @@ class ConfigCommandError(Exception): CONFIG_KEY_CHOICES = ( "language", "lang", + "theme", "command_display", "command_display_mode", "command_aliases", @@ -109,6 +110,7 @@ def format_config_pretty(report: dict[str, Any], *, lang: str = "ja", color: Col boundary_title = "Boundary" rows = ( CliRow("language", config.get("language") or "ja", "ok"), + CliRow("theme", config.get("theme") or "auto", "ok"), CliRow("command_display", config.get("command_display_mode") or "ja_only", "ok"), CliRow("provider", config.get("provider_preference"), "ok"), CliRow("model", config.get("model_preference"), "ok"), diff --git a/clients/cli/yonerai_cli/config.py b/clients/cli/yonerai_cli/config.py index 5f3f72c6..f51e841d 100644 --- a/clients/cli/yonerai_cli/config.py +++ b/clients/cli/yonerai_cli/config.py @@ -206,6 +206,11 @@ def parse_config_value(key: str, value: str) -> object: if raw not in LANGUAGES: raise ConfigError("language must be ja or en.") return raw + if key == "theme": + normalized = raw.lower() + if normalized not in THEMES: + raise ConfigError("theme must be auto, dark, light, or mono.") + return normalized if key == "provider_preference": if raw not in PROVIDER_PREFERENCES: raise ConfigError("provider must be auto, mock, local, openai-compatible, anthropic, or gemini.") @@ -312,6 +317,7 @@ def build_config_report(config: Mapping[str, object], *, exists: bool) -> dict[s "secrets_supported": False, "config": { "language": validated["language"], + "theme": validated["theme"], "command_display_mode": validated["command_display_mode"], "provider_preference": validated["provider_preference"], "model_preference": validated["model_preference"], diff --git a/tests/test_cli_theme.py b/tests/test_cli_theme.py index 5744fe16..bcb9864a 100644 --- a/tests/test_cli_theme.py +++ b/tests/test_cli_theme.py @@ -8,6 +8,7 @@ from __future__ import annotations import io +import json import sys from pathlib import Path from typing import Any @@ -21,7 +22,15 @@ if str(path) not in sys.path: sys.path.insert(0, str(path)) -from yonerai_cli.config import DEFAULT_CONFIG, ConfigError, THEMES, save_cli_config, validate_cli_config +from yonerai_cli.config import ( + DEFAULT_CONFIG, + THEMES, + ConfigError, + save_cli_config, + set_cli_config_value, + validate_cli_config, +) +from yonerai_cli.commands.config import CONFIG_KEY_CHOICES from yonerai_cli.startup_home import render_startup_home_header from yonerai_cli.tui.themes import normalize_theme, theme_from_input, theme_palette, theme_uses_truecolor @@ -58,6 +67,26 @@ def test_invalid_theme_rejected() -> None: validate_cli_config(cfg) +def test_config_setter_persists_theme(tmp_path: Path) -> None: + config_path = tmp_path / "config.json" + + updated = set_cli_config_value("theme", "DARK", config_path) + + assert updated["theme"] == "dark" + assert json.loads(config_path.read_text(encoding="utf-8"))["theme"] == "dark" + + +def test_config_setter_rejects_invalid_theme(tmp_path: Path) -> None: + config_path = tmp_path / "config.json" + + with pytest.raises(ConfigError, match="theme must be auto, dark, light, or mono"): + set_cli_config_value("theme", "neon", config_path) + + +def test_config_command_choices_include_theme() -> None: + assert "theme" in CONFIG_KEY_CHOICES + + # --- palette / rendering ---