diff --git a/gateway/config.py b/gateway/config.py index 9a517f81b..127e62151 100644 --- a/gateway/config.py +++ b/gateway/config.py @@ -270,7 +270,7 @@ def load_gateway_config() -> GatewayConfig: gateway_config_path = Path.home() / ".hermes" / "gateway.json" if gateway_config_path.exists(): try: - with open(gateway_config_path, "r") as f: + with open(gateway_config_path, "r", encoding="utf-8") as f: data = json.load(f) config = GatewayConfig.from_dict(data) except Exception as e: @@ -283,7 +283,7 @@ def load_gateway_config() -> GatewayConfig: import yaml config_yaml_path = Path.home() / ".hermes" / "config.yaml" if config_yaml_path.exists(): - with open(config_yaml_path) as f: + with open(config_yaml_path, encoding="utf-8") as f: yaml_cfg = yaml.safe_load(f) or {} sr = yaml_cfg.get("session_reset") if sr and isinstance(sr, dict): @@ -441,5 +441,5 @@ def save_gateway_config(config: GatewayConfig) -> None: gateway_config_path = Path.home() / ".hermes" / "gateway.json" gateway_config_path.parent.mkdir(parents=True, exist_ok=True) - with open(gateway_config_path, "w") as f: + with open(gateway_config_path, "w", encoding="utf-8") as f: json.dump(config.to_dict(), f, indent=2) diff --git a/gateway/run.py b/gateway/run.py index 6dd1a280a..946aec0dd 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -48,7 +48,7 @@ _config_path = _hermes_home / 'config.yaml' if _config_path.exists(): try: import yaml as _yaml - with open(_config_path) as _f: + with open(_config_path, encoding="utf-8") as _f: _cfg = _yaml.safe_load(_f) or {} # Top-level simple values (fallback only — don't override .env) for _key, _val in _cfg.items(): @@ -316,7 +316,7 @@ class GatewayRunner: import yaml as _y cfg_path = _hermes_home / "config.yaml" if cfg_path.exists(): - with open(cfg_path) as _f: + with open(cfg_path, encoding="utf-8") as _f: cfg = _y.safe_load(_f) or {} file_path = cfg.get("prefill_messages_file", "") except Exception: @@ -354,7 +354,7 @@ class GatewayRunner: import yaml as _y cfg_path = _hermes_home / "config.yaml" if cfg_path.exists(): - with open(cfg_path) as _f: + with open(cfg_path, encoding="utf-8") as _f: cfg = _y.safe_load(_f) or {} return (cfg.get("agent", {}).get("system_prompt", "") or "").strip() except Exception: @@ -375,7 +375,7 @@ class GatewayRunner: import yaml as _y cfg_path = _hermes_home / "config.yaml" if cfg_path.exists(): - with open(cfg_path) as _f: + with open(cfg_path, encoding="utf-8") as _f: cfg = _y.safe_load(_f) or {} effort = str(cfg.get("agent", {}).get("reasoning_effort", "") or "").strip() except Exception: @@ -398,7 +398,7 @@ class GatewayRunner: import yaml as _y cfg_path = _hermes_home / "config.yaml" if cfg_path.exists(): - with open(cfg_path) as _f: + with open(cfg_path, encoding="utf-8") as _f: cfg = _y.safe_load(_f) or {} return cfg.get("provider_routing", {}) or {} except Exception: @@ -416,7 +416,7 @@ class GatewayRunner: import yaml as _y cfg_path = _hermes_home / "config.yaml" if cfg_path.exists(): - with open(cfg_path) as _f: + with open(cfg_path, encoding="utf-8") as _f: cfg = _y.safe_load(_f) or {} fb = cfg.get("fallback_model", {}) or {} if fb.get("provider") and fb.get("model"): @@ -931,7 +931,7 @@ class GatewayRunner: _hyg_cfg_path = _hermes_home / "config.yaml" if _hyg_cfg_path.exists(): import yaml as _hyg_yaml - with open(_hyg_cfg_path) as _hyg_f: + with open(_hyg_cfg_path, encoding="utf-8") as _hyg_f: _hyg_data = _hyg_yaml.safe_load(_hyg_f) or {} # Resolve model name (same logic as run_sync) @@ -1434,7 +1434,7 @@ class GatewayRunner: current_provider = "openrouter" try: if config_path.exists(): - with open(config_path) as f: + with open(config_path, encoding="utf-8") as f: cfg = yaml.safe_load(f) or {} model_cfg = cfg.get("model", {}) if isinstance(model_cfg, str): @@ -1525,14 +1525,14 @@ class GatewayRunner: try: user_config = {} if config_path.exists(): - with open(config_path) as f: + with open(config_path, encoding="utf-8") as f: user_config = yaml.safe_load(f) or {} if "model" not in user_config or not isinstance(user_config["model"], dict): user_config["model"] = {} user_config["model"]["default"] = new_model if provider_changed: user_config["model"]["provider"] = target_provider - with open(config_path, 'w') as f: + with open(config_path, 'w', encoding="utf-8") as f: yaml.dump(user_config, f, default_flow_style=False, sort_keys=False) except Exception as e: return f"⚠️ Failed to save model change: {e}" @@ -1569,7 +1569,7 @@ class GatewayRunner: config_path = _hermes_home / 'config.yaml' try: if config_path.exists(): - with open(config_path) as f: + with open(config_path, encoding="utf-8") as f: cfg = yaml.safe_load(f) or {} model_cfg = cfg.get("model", {}) if isinstance(model_cfg, dict): @@ -1618,7 +1618,7 @@ class GatewayRunner: try: if config_path.exists(): - with open(config_path, 'r') as f: + with open(config_path, 'r', encoding="utf-8") as f: config = yaml.safe_load(f) or {} personalities = config.get("agent", {}).get("personalities", {}) else: @@ -1647,7 +1647,7 @@ class GatewayRunner: if "agent" not in config or not isinstance(config.get("agent"), dict): config["agent"] = {} config["agent"]["system_prompt"] = new_prompt - with open(config_path, 'w') as f: + with open(config_path, 'w', encoding="utf-8") as f: yaml.dump(config, f, default_flow_style=False, sort_keys=False) except Exception as e: return f"⚠️ Failed to save personality change: {e}" @@ -1731,10 +1731,10 @@ class GatewayRunner: config_path = _hermes_home / 'config.yaml' user_config = {} if config_path.exists(): - with open(config_path) as f: + with open(config_path, encoding="utf-8") as f: user_config = yaml.safe_load(f) or {} user_config[env_key] = chat_id - with open(config_path, 'w') as f: + with open(config_path, 'w', encoding="utf-8") as f: yaml.dump(user_config, f, default_flow_style=False) # Also set in the current environment so it takes effect immediately os.environ[env_key] = str(chat_id) @@ -2410,7 +2410,7 @@ class GatewayRunner: config_path = _hermes_home / 'config.yaml' if config_path.exists(): import yaml - with open(config_path, 'r') as f: + with open(config_path, 'r', encoding="utf-8") as f: user_config = yaml.safe_load(f) or {} platform_toolsets_config = user_config.get("platform_toolsets", {}) except Exception as e: @@ -2440,7 +2440,7 @@ class GatewayRunner: _tp_cfg_path = _hermes_home / "config.yaml" if _tp_cfg_path.exists(): import yaml as _tp_yaml - with open(_tp_cfg_path) as _tp_f: + with open(_tp_cfg_path, encoding="utf-8") as _tp_f: _tp_data = _tp_yaml.safe_load(_tp_f) or {} _progress_cfg = _tp_data.get("display", {}) except Exception: @@ -2658,7 +2658,7 @@ class GatewayRunner: import yaml as _y _cfg_path = _hermes_home / "config.yaml" if _cfg_path.exists(): - with open(_cfg_path) as _f: + with open(_cfg_path, encoding="utf-8") as _f: _cfg = _y.safe_load(_f) or {} _model_cfg = _cfg.get("model", {}) if isinstance(_model_cfg, str): @@ -3140,7 +3140,7 @@ def main(): config = None if args.config: import json - with open(args.config) as f: + with open(args.config, encoding="utf-8") as f: data = json.load(f) config = GatewayConfig.from_dict(data) diff --git a/hermes_cli/config.py b/hermes_cli/config.py index 018ac6557..e00c85a04 100644 --- a/hermes_cli/config.py +++ b/hermes_cli/config.py @@ -757,9 +757,9 @@ def load_config() -> Dict[str, Any]: if config_path.exists(): try: - with open(config_path) as f: + with open(config_path, encoding="utf-8") as f: user_config = yaml.safe_load(f) or {} - + config = _deep_merge(config, user_config) except Exception as e: print(f"Warning: Failed to load config: {e}") @@ -802,7 +802,7 @@ def save_config(config: Dict[str, Any]): ensure_hermes_home() config_path = get_config_path() - with open(config_path, 'w') as f: + with open(config_path, 'w', encoding="utf-8") as f: yaml.dump(config, f, default_flow_style=False, sort_keys=False) # Append commented-out sections for features that are off by default # or only relevant when explicitly configured. Skip sections the @@ -1077,7 +1077,7 @@ def set_config_value(key: str, value: str): user_config = {} if config_path.exists(): try: - with open(config_path) as f: + with open(config_path, encoding="utf-8") as f: user_config = yaml.safe_load(f) or {} except Exception: user_config = {} @@ -1105,7 +1105,7 @@ def set_config_value(key: str, value: str): # Write only user config back (not the full merged defaults) ensure_hermes_home() - with open(config_path, 'w') as f: + with open(config_path, 'w', encoding="utf-8") as f: yaml.dump(user_config, f, default_flow_style=False, sort_keys=False) # Keep .env in sync for keys that terminal_tool reads directly from env vars. diff --git a/hermes_cli/main.py b/hermes_cli/main.py index 861cc038b..6779eb1fa 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -2356,12 +2356,12 @@ For more help on a command: if not data: print(f"Session '{args.session_id}' not found.") return - with open(args.output, "w") as f: + with open(args.output, "w", encoding="utf-8") as f: f.write(_json.dumps(data, ensure_ascii=False) + "\n") print(f"Exported 1 session to {args.output}") else: sessions = db.export_all(source=args.source) - with open(args.output, "w") as f: + with open(args.output, "w", encoding="utf-8") as f: for s in sessions: f.write(_json.dumps(s, ensure_ascii=False) + "\n") print(f"Exported {len(sessions)} sessions to {args.output}") diff --git a/hermes_cli/status.py b/hermes_cli/status.py index 12b064fea..f27824a64 100644 --- a/hermes_cli/status.py +++ b/hermes_cli/status.py @@ -263,7 +263,7 @@ def show_status(args): if jobs_file.exists(): import json try: - with open(jobs_file) as f: + with open(jobs_file, encoding="utf-8") as f: data = json.load(f) jobs = data.get("jobs", []) enabled_jobs = [j for j in jobs if j.get("enabled", True)] @@ -283,7 +283,7 @@ def show_status(args): if sessions_file.exists(): import json try: - with open(sessions_file) as f: + with open(sessions_file, encoding="utf-8") as f: data = json.load(f) print(f" Active: {len(data)} session(s)") except Exception: diff --git a/tools/terminal_tool.py b/tools/terminal_tool.py index 1c5ce751d..5791bf33e 100644 --- a/tools/terminal_tool.py +++ b/tools/terminal_tool.py @@ -194,6 +194,8 @@ def _prompt_for_sudo_password(timeout_seconds: int = 45) -> str: def read_password_thread(): """Read password with echo disabled. Uses msvcrt on Windows, /dev/tty on Unix.""" + tty_fd = None + old_attrs = None try: if platform.system() == "Windows": import msvcrt @@ -213,28 +215,29 @@ def _prompt_for_sudo_password(timeout_seconds: int = 45) -> str: new_attrs = termios.tcgetattr(tty_fd) new_attrs[3] = new_attrs[3] & ~termios.ECHO termios.tcsetattr(tty_fd, termios.TCSAFLUSH, new_attrs) - try: - chars = [] - while True: - b = os.read(tty_fd, 1) - if not b or b in (b"\n", b"\r"): - break - chars.append(b) - result["password"] = b"".join(chars).decode("utf-8", errors="replace") - finally: - try: - termios.tcsetattr(tty_fd, termios.TCSAFLUSH, old_attrs) - except Exception: - pass - try: - os.close(tty_fd) - except Exception: - pass + chars = [] + while True: + b = os.read(tty_fd, 1) + if not b or b in (b"\n", b"\r"): + break + chars.append(b) + result["password"] = b"".join(chars).decode("utf-8", errors="replace") except (EOFError, KeyboardInterrupt, OSError): result["password"] = "" except Exception: result["password"] = "" finally: + if tty_fd is not None and old_attrs is not None: + try: + import termios as _termios + _termios.tcsetattr(tty_fd, _termios.TCSAFLUSH, old_attrs) + except Exception: + pass + if tty_fd is not None: + try: + os.close(tty_fd) + except Exception: + pass result["done"] = True try: