From 1672a3de86f79bd262cd38d1b453d526a154affb Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:27:37 -0700 Subject: [PATCH] =?UTF-8?q?refactor(hermes=5Fcli):=20doctor=20=E2=80=94=20?= =?UTF-8?q?=5Flogin=5Frow=20show=5Ferror,=20packed=20DOCTOR=5FCHECKS=20tab?= =?UTF-8?q?le,=20dump=20helper=20ternaries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hermes_cli/doctor.py | 58 ++++++++++++------------------- hermes_cli/doctor_connectivity.py | 3 +- hermes_cli/dump.py | 12 +++---- 3 files changed, 27 insertions(+), 46 deletions(-) diff --git a/hermes_cli/doctor.py b/hermes_cli/doctor.py index 4ad707b8eb..6b3609b9c0 100644 --- a/hermes_cli/doctor.py +++ b/hermes_cli/doctor.py @@ -79,14 +79,10 @@ def _check_auth_providers(should_fix: bool) -> Finding: from hermes_cli.auth import get_nous_auth_status_local, get_codex_auth_status, get_minimax_oauth_auth_status # Read-only display: refresh-free snapshot — doctor must never trigger an OAuth refresh. _login_row("Nous Portal auth", get_nous_auth_status_local()) - codex_status = get_codex_auth_status() - if not _login_row("OpenAI Codex auth", codex_status): - if codex_status.get("error"): - check_info(codex_status["error"]) - # Native OAuth uses Hermes' own device-code flow — the Codex CLI only imports existing tokens from - # ~/.codex/auth.json. Hint sits under the Codex row so it doesn't read as another provider's remedy. - if not _safe_which("codex"): - check_info("codex CLI not installed (optional — only required to import tokens from an existing Codex CLI login)") + # Native OAuth uses Hermes' own device-code flow — the Codex CLI only imports existing tokens from + # ~/.codex/auth.json. Hint sits under the Codex row so it doesn't read as another provider's remedy. + if not _login_row("OpenAI Codex auth", get_codex_auth_status(), show_error=True) and not _safe_which("codex"): + check_info("codex CLI not installed (optional — only required to import tokens from an existing Codex CLI login)") minimax_status = get_minimax_oauth_auth_status() _login_row("MiniMax OAuth", minimax_status, f"(logged in, region={minimax_status.get('region', 'global')})") except Exception as e: @@ -94,16 +90,18 @@ def _check_auth_providers(should_fix: bool) -> Finding: # xAI OAuth — separate try/except so an import failure cannot disrupt the already-printed rows above. try: from hermes_cli.auth import get_xai_oauth_auth_status - xai_oauth_status = get_xai_oauth_auth_status() or {} - if not _login_row("xAI OAuth", xai_oauth_status) and xai_oauth_status.get("error"): - check_info(xai_oauth_status["error"]) + _login_row("xAI OAuth", get_xai_oauth_auth_status() or {}, show_error=True) except Exception: pass return f -def _login_row(label: str, status: dict, ok_detail: str = "(logged in)") -> bool: - return check_bool(status.get("logged_in"), (label, ok_detail), (label, "(not logged in)")) +def _login_row(label: str, status: dict, ok_detail: str = "(logged in)", show_error: bool = False) -> bool: + """ok/warn row for an OAuth status dict; with show_error, its ``error`` hint prints under a not-logged-in row.""" + logged_in = check_bool(status.get("logged_in"), (label, ok_detail), (label, "(not logged in)")) + if not logged_in and show_error and status.get("error"): + check_info(status["error"]) + return logged_in def _check_api_connectivity(should_fix: bool) -> Finding: @@ -124,29 +122,17 @@ def _check_api_connectivity(should_fix: bool) -> Finding: # Ordered (section title, check). None title = check prints its own header (or none); order is user-visible. DOCTOR_CHECKS = ( - ('Security Advisories', _check_security_advisories), - ('MCP Server Security', _check_mcp_security), - ('Python Environment', _check_python_environment), - ('SSL / CA Certificates', _check_certificates), - ('Required Packages', _check_required_packages), - ('Configuration Files', _check_env_file), - (None, _check_config_file), - (None, _check_config_drift), - ('xAI Model Retirement (May 15, 2026)', _check_xai_retirement), - ('Auth Providers', _check_auth_providers), - ('Directory Structure', _check_directory_structure), - (None, _check_state_db), - (None, _check_gateway_supervision), - (None, _check_command_installation), - ('External Tools', _check_git_and_rg), - (None, _check_terminal_backend), - (None, _check_node_and_browser), - (None, _check_npm_audit), - ('API Connectivity', _check_api_connectivity), - ('Tool Availability', _check_tool_availability), - ('Skills Hub', _check_skills_hub), - ('Memory Provider', _check_memory_provider), - (None, _check_profiles), + ('Security Advisories', _check_security_advisories), ('MCP Server Security', _check_mcp_security), + ('Python Environment', _check_python_environment), ('SSL / CA Certificates', _check_certificates), + ('Required Packages', _check_required_packages), ('Configuration Files', _check_env_file), + (None, _check_config_file), (None, _check_config_drift), + ('xAI Model Retirement (May 15, 2026)', _check_xai_retirement), ('Auth Providers', _check_auth_providers), + ('Directory Structure', _check_directory_structure), (None, _check_state_db), + (None, _check_gateway_supervision), (None, _check_command_installation), + ('External Tools', _check_git_and_rg), (None, _check_terminal_backend), (None, _check_node_and_browser), + (None, _check_npm_audit), ('API Connectivity', _check_api_connectivity), + ('Tool Availability', _check_tool_availability), ('Skills Hub', _check_skills_hub), + ('Memory Provider', _check_memory_provider), (None, _check_profiles), ) diff --git a/hermes_cli/doctor_connectivity.py b/hermes_cli/doctor_connectivity.py index 78b974afe4..638c9935fa 100644 --- a/hermes_cli/doctor_connectivity.py +++ b/hermes_cli/doctor_connectivity.py @@ -316,8 +316,7 @@ def run_probes(probes: list) -> list: try: # 8 workers is plenty — each probe is one HTTP call plus a TLS handshake. with concurrent.futures.ThreadPoolExecutor(max_workers=8, thread_name_prefix="doctor-probe") as ex: - futures = [ex.submit(fn) for _, fn in probes] - return [f.result() for f in futures] + return [f.result() for f in [ex.submit(fn) for _, fn in probes]] finally: if _imds_prev is None: os.environ.pop("AWS_EC2_METADATA_DISABLED", None) diff --git a/hermes_cli/dump.py b/hermes_cli/dump.py index 91c9bfd49c..e8947abfe9 100644 --- a/hermes_cli/dump.py +++ b/hermes_cli/dump.py @@ -28,10 +28,8 @@ def _dotenv_key_names() -> set[str]: if line.lower().startswith("export "): line = line[len("export "):].lstrip() name, _, value = line.partition("=") - name = name.strip() - # A bare `KEY=` (empty value) is effectively unset for the backend. - if name and value.strip().strip("'\""): - names.add(name) + if name.strip() and value.strip().strip("'\""): # a bare `KEY=` is effectively unset for the backend + names.add(name.strip()) return names @@ -40,11 +38,9 @@ def _git_output(project_root: Path, *args: str) -> str: try: result = subprocess.run(["git", *args], capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, cwd=str(project_root)) - if result.returncode == 0: - return result.stdout.strip() + return result.stdout.strip() if result.returncode == 0 else "" except Exception: - pass - return "" + return "" def _get_git_commit(project_root: Path) -> str: