diff --git a/hermes_cli/auth.py b/hermes_cli/auth.py index 1cdbadc79..2025bbcc8 100644 --- a/hermes_cli/auth.py +++ b/hermes_cli/auth.py @@ -37,7 +37,7 @@ from typing import Any, Dict, List, Optional import httpx import yaml -from hermes_cli.config import get_hermes_home, get_config_path +from hermes_cli.config import get_hermes_home, get_config_path, read_raw_config from hermes_constants import OPENROUTER_BASE_URL logger = logging.getLogger(__name__) @@ -2214,14 +2214,7 @@ def _update_config_for_provider( config_path = get_config_path() config_path.parent.mkdir(parents=True, exist_ok=True) - config: Dict[str, Any] = {} - if config_path.exists(): - try: - loaded = yaml.safe_load(config_path.read_text()) or {} - if isinstance(loaded, dict): - config = loaded - except Exception: - config = {} + config = read_raw_config() current_model = config.get("model") if isinstance(current_model, dict): @@ -2258,12 +2251,8 @@ def _reset_config_provider() -> Path: if not config_path.exists(): return config_path - try: - config = yaml.safe_load(config_path.read_text()) or {} - except Exception: - return config_path - - if not isinstance(config, dict): + config = read_raw_config() + if not config: return config_path model = config.get("model") diff --git a/hermes_cli/commands.py b/hermes_cli/commands.py index ecf4d0d6b..39dc4569c 100644 --- a/hermes_cli/commands.py +++ b/hermes_cli/commands.py @@ -293,14 +293,8 @@ def _resolve_config_gates() -> set[str]: if not gated: return set() try: - import yaml - from hermes_constants import get_hermes_home - config_path = str(get_hermes_home() / "config.yaml") - if os.path.exists(config_path): - with open(config_path, encoding="utf-8") as f: - cfg = yaml.safe_load(f) or {} - else: - cfg = {} + from hermes_cli.config import read_raw_config + cfg = read_raw_config() except Exception: return set() result: set[str] = set() diff --git a/tools/browser_tool.py b/tools/browser_tool.py index 10004b089..7e52ed78d 100644 --- a/tools/browser_tool.py +++ b/tools/browser_tool.py @@ -146,15 +146,11 @@ def _get_command_timeout() -> int: ``DEFAULT_COMMAND_TIMEOUT`` (30s) if unset or unreadable. """ try: - hermes_home = get_hermes_home() - config_path = hermes_home / "config.yaml" - if config_path.exists(): - import yaml - with open(config_path) as f: - cfg = yaml.safe_load(f) or {} - val = cfg.get("browser", {}).get("command_timeout") - if val is not None: - return max(int(val), 5) # Floor at 5s to avoid instant kills + from hermes_cli.config import read_raw_config + cfg = read_raw_config() + val = cfg.get("browser", {}).get("command_timeout") + if val is not None: + return max(int(val), 5) # Floor at 5s to avoid instant kills except Exception as e: logger.debug("Could not read command_timeout from config: %s", e) return DEFAULT_COMMAND_TIMEOUT @@ -259,23 +255,19 @@ def _get_cloud_provider() -> Optional[CloudBrowserProvider]: _cloud_provider_resolved = True try: - hermes_home = get_hermes_home() - config_path = hermes_home / "config.yaml" - if config_path.exists(): - import yaml - with open(config_path) as f: - cfg = yaml.safe_load(f) or {} - browser_cfg = cfg.get("browser", {}) - provider_key = None - if isinstance(browser_cfg, dict) and "cloud_provider" in browser_cfg: - provider_key = normalize_browser_cloud_provider( - browser_cfg.get("cloud_provider") - ) - if provider_key == "local": - _cached_cloud_provider = None - return None - if provider_key and provider_key in _PROVIDER_REGISTRY: - _cached_cloud_provider = _PROVIDER_REGISTRY[provider_key]() + from hermes_cli.config import read_raw_config + cfg = read_raw_config() + browser_cfg = cfg.get("browser", {}) + provider_key = None + if isinstance(browser_cfg, dict) and "cloud_provider" in browser_cfg: + provider_key = normalize_browser_cloud_provider( + browser_cfg.get("cloud_provider") + ) + if provider_key == "local": + _cached_cloud_provider = None + return None + if provider_key and provider_key in _PROVIDER_REGISTRY: + _cached_cloud_provider = _PROVIDER_REGISTRY[provider_key]() except Exception as e: logger.debug("Could not read cloud_provider from config: %s", e) @@ -326,13 +318,9 @@ def _allow_private_urls() -> bool: _allow_private_urls_resolved = True _cached_allow_private_urls = False # safe default try: - hermes_home = get_hermes_home() - config_path = hermes_home / "config.yaml" - if config_path.exists(): - import yaml - with open(config_path) as f: - cfg = yaml.safe_load(f) or {} - _cached_allow_private_urls = bool(cfg.get("browser", {}).get("allow_private_urls")) + from hermes_cli.config import read_raw_config + cfg = read_raw_config() + _cached_allow_private_urls = bool(cfg.get("browser", {}).get("allow_private_urls")) except Exception as e: logger.debug("Could not read allow_private_urls from config: %s", e) return _cached_allow_private_urls @@ -1626,14 +1614,10 @@ def _maybe_start_recording(task_id: str): if task_id in _recording_sessions: return try: + from hermes_cli.config import read_raw_config hermes_home = get_hermes_home() - config_path = hermes_home / "config.yaml" - record_enabled = False - if config_path.exists(): - import yaml - with open(config_path) as f: - cfg = yaml.safe_load(f) or {} - record_enabled = cfg.get("browser", {}).get("record_sessions", False) + cfg = read_raw_config() + record_enabled = cfg.get("browser", {}).get("record_sessions", False) if not record_enabled: return diff --git a/tools/credential_files.py b/tools/credential_files.py index eafd5ea23..3092b75e9 100644 --- a/tools/credential_files.py +++ b/tools/credential_files.py @@ -137,40 +137,36 @@ def _load_config_files() -> List[Dict[str, str]]: result: List[Dict[str, str]] = [] try: + from hermes_cli.config import read_raw_config hermes_home = _resolve_hermes_home() - config_path = hermes_home / "config.yaml" - if config_path.exists(): - import yaml - - with open(config_path) as f: - cfg = yaml.safe_load(f) or {} - cred_files = cfg.get("terminal", {}).get("credential_files") - if isinstance(cred_files, list): - hermes_home_resolved = hermes_home.resolve() - for item in cred_files: - if isinstance(item, str) and item.strip(): - rel = item.strip() - if os.path.isabs(rel): - logger.warning( - "credential_files: rejected absolute config path %r", rel, - ) - continue - host_path = (hermes_home / rel).resolve() - try: - host_path.relative_to(hermes_home_resolved) - except ValueError: - logger.warning( - "credential_files: rejected config path traversal %r " - "(resolves to %s, outside HERMES_HOME %s)", - rel, host_path, hermes_home_resolved, - ) - continue - if host_path.is_file(): - container_path = f"/root/.hermes/{rel}" - result.append({ - "host_path": str(host_path), - "container_path": container_path, - }) + cfg = read_raw_config() + cred_files = cfg.get("terminal", {}).get("credential_files") + if isinstance(cred_files, list): + hermes_home_resolved = hermes_home.resolve() + for item in cred_files: + if isinstance(item, str) and item.strip(): + rel = item.strip() + if os.path.isabs(rel): + logger.warning( + "credential_files: rejected absolute config path %r", rel, + ) + continue + host_path = (hermes_home / rel).resolve() + try: + host_path.relative_to(hermes_home_resolved) + except ValueError: + logger.warning( + "credential_files: rejected config path traversal %r " + "(resolves to %s, outside HERMES_HOME %s)", + rel, host_path, hermes_home_resolved, + ) + continue + if host_path.is_file(): + container_path = f"/root/.hermes/{rel}" + result.append({ + "host_path": str(host_path), + "container_path": container_path, + }) except Exception as e: logger.debug("Could not read terminal.credential_files from config: %s", e) diff --git a/tools/env_passthrough.py b/tools/env_passthrough.py index 0e883babd..d931f1503 100644 --- a/tools/env_passthrough.py +++ b/tools/env_passthrough.py @@ -66,18 +66,13 @@ def _load_config_passthrough() -> frozenset[str]: result: set[str] = set() try: - from hermes_constants import get_hermes_home - config_path = get_hermes_home() / "config.yaml" - if config_path.exists(): - import yaml - - with open(config_path) as f: - cfg = yaml.safe_load(f) or {} - passthrough = cfg.get("terminal", {}).get("env_passthrough") - if isinstance(passthrough, list): - for item in passthrough: - if isinstance(item, str) and item.strip(): - result.add(item.strip()) + from hermes_cli.config import read_raw_config + cfg = read_raw_config() + passthrough = cfg.get("terminal", {}).get("env_passthrough") + if isinstance(passthrough, list): + for item in passthrough: + if isinstance(item, str) and item.strip(): + result.add(item.strip()) except Exception as e: logger.debug("Could not read tools.env_passthrough from config: %s", e) diff --git a/tools/transcription_tools.py b/tools/transcription_tools.py index 9a79cdfba..d8d0f3643 100644 --- a/tools/transcription_tools.py +++ b/tools/transcription_tools.py @@ -98,12 +98,8 @@ def get_stt_model_from_config() -> Optional[str]: Silently returns ``None`` on any error (missing file, bad YAML, etc.). """ try: - import yaml - cfg_path = get_hermes_home() / "config.yaml" - if cfg_path.exists(): - with open(cfg_path) as f: - data = yaml.safe_load(f) or {} - return data.get("stt", {}).get("model") + from hermes_cli.config import read_raw_config + return read_raw_config().get("stt", {}).get("model") except Exception: pass return None