diff --git a/hermes_cli/main_dashboard.py b/hermes_cli/main_dashboard.py index 7313ef75f9..c4d0cbf977 100644 --- a/hermes_cli/main_dashboard.py +++ b/hermes_cli/main_dashboard.py @@ -70,8 +70,7 @@ _SYSTEMCTL_ERRORS = (FileNotFoundError, subprocess.TimeoutExpired, OSError) def _run_probe(cmd: list[str], *, timeout: int) -> subprocess.CompletedProcess: """Captured, text-decoded ``subprocess.run`` for short local probes (systemctl, ps).""" return subprocess.run( - cmd, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout - ) + cmd, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout) def _restart_managed_dashboard_service(reason: str, unit: str = _DASHBOARD_SYSTEMD_UNIT) -> bool: @@ -263,8 +262,7 @@ def _respawn_dashboard_processes(commands: list[list[str]]) -> list[list[str]]: with open(log_path, "ab") as log_f: subprocess.Popen( command, stdin=subprocess.DEVNULL, stdout=log_f, stderr=subprocess.STDOUT, - start_new_session=True, close_fds=True, - ) + start_new_session=True, close_fds=True) respawned.append(command) except (OSError, ValueError) as exc: failed.append((command, str(exc))) @@ -335,8 +333,7 @@ def _install_hangup_protection(gateway_mode: bool = False): (stdio wrapped in ``_UpdateOutputStream``). SIGINT/SIGTERM are left alone — legitimate cancels. No-op in gateway mode (already detached). Returns state for ``_finalize_update_output``.""" state = { - "prev_stdout": sys.stdout, "prev_stderr": sys.stderr, "log_file": None, "installed": False - } + "prev_stdout": sys.stdout, "prev_stderr": sys.stderr, "log_file": None, "installed": False} if gateway_mode: return state @@ -700,8 +697,7 @@ def _route_named_profile_dashboard(args, _headless_backend: bool, _ssh_owner_non "serve" if _headless_backend else "dashboard", "--port", str(args.port), "--host", args.host, - "--open-profile", _launch_profile, - ] + "--open-profile", _launch_profile] if _ssh_owner_nonce: reexec_argv.extend(["--ssh-owner-nonce", _ssh_owner_nonce]) if _token_file: diff --git a/hermes_cli/main_desktop.py b/hermes_cli/main_desktop.py index 28fbe1d6f2..2188926b87 100644 --- a/hermes_cli/main_desktop.py +++ b/hermes_cli/main_desktop.py @@ -122,8 +122,7 @@ def _write_desktop_build_stamp(project_root: Path, *, source_mode: bool) -> None from hermes_cli.main import _desktop_stamp_path _write_build_stamp( _desktop_stamp_path(), "desktop", - lambda: _compute_desktop_content_hash(project_root), sourceMode=source_mode, - ) + lambda: _compute_desktop_content_hash(project_root), sourceMode=source_mode) def _desktop_packaged_executable(desktop_dir: Path) -> Optional[Path]: @@ -242,15 +241,13 @@ def _windows_native_machine_from_iswow64() -> Optional[str]: kernel32.GetCurrentProcess.restype = wintypes.HANDLE kernel32.GetCurrentProcess.argtypes = [] kernel32.IsWow64Process2.argtypes = [ - wintypes.HANDLE, ctypes.POINTER(wintypes.USHORT), ctypes.POINTER(wintypes.USHORT), - ] + wintypes.HANDLE, ctypes.POINTER(wintypes.USHORT), ctypes.POINTER(wintypes.USHORT)] kernel32.IsWow64Process2.restype = wintypes.BOOL process_machine = wintypes.USHORT(0) native_machine = wintypes.USHORT(0) if not kernel32.IsWow64Process2( - kernel32.GetCurrentProcess(), ctypes.byref(process_machine), ctypes.byref(native_machine) - ): + kernel32.GetCurrentProcess(), ctypes.byref(process_machine), ctypes.byref(native_machine)): return None return _PE_MACHINE_TO_NAME.get(native_machine.value) @@ -547,8 +544,7 @@ def _electron_pkg_staged_missing_dist(project_root: Path) -> bool: return ( (electron_dir / "package.json").is_file() and (electron_dir / "install.js").is_file() - and not _electron_dist_ok(project_root) - ) + and not _electron_dist_ok(project_root)) def _redownload_electron_dist(project_root: Path, env: dict, *, mirror: Optional[str] = None) -> bool: @@ -652,8 +648,7 @@ def _desktop_macos_bundle_id(bundle: Path) -> Optional[str]: info = bundle / "Contents" / "Info.plist" if not info.exists() and bundle.suffix == ".framework": candidates = list(bundle.glob("Versions/*/Resources/Info.plist")) + list( - bundle.glob("Resources/Info.plist") - ) + bundle.glob("Resources/Info.plist")) if candidates: info = candidates[0] if not info.exists(): @@ -690,8 +685,7 @@ def _desktop_macos_local_signing_identity() -> Optional[str]: def _codesign_verify(codesign: str, app: Path, **kwargs) -> subprocess.CompletedProcess: return subprocess.run( - [codesign, "--verify", "--deep", "--strict", str(app)], capture_output=True, **kwargs - ) + [codesign, "--verify", "--deep", "--strict", str(app)], capture_output=True, **kwargs) def _desktop_macos_has_valid_real_signature(app: Path) -> bool: @@ -702,8 +696,7 @@ def _desktop_macos_has_valid_real_signature(app: Path) -> bool: return False try: info = subprocess.run( - [codesign, "-dv", str(app)], check=False, capture_output=True, text=True - ) + [codesign, "-dv", str(app)], check=False, capture_output=True, text=True) output = f"{info.stdout}\n{info.stderr}" if info.returncode != 0 or "TeamIdentifier=" not in output or "TeamIdentifier=not set" in output: return False @@ -731,8 +724,7 @@ def _desktop_macos_local_codesign(app: Path, *, desktop_dir: Path, identity: str def sign_path( path: Path, *, entitlements: Optional[Path] = None, identifier: Optional[str] = None, - runtime: bool = True, - ) -> None: + runtime: bool = True) -> None: args = [codesign, "--force", "--sign", identity, "--timestamp=none"] if runtime: args += ["--options", "runtime"] @@ -808,8 +800,7 @@ def _macos_legacy_adhoc_resign(codesign: str, app: Path) -> bool: def _desktop_macos_relaunchable_fixup( desktop_dir: Path, *, publisher_signing_configured: Optional[bool] = None, - release_dir: Optional[Path] = None, -) -> bool: + release_dir: Optional[Path] = None) -> bool: """Re-sign a locally-built macOS app so in-place self-update doesn't reset TCC grants. A rebuilt ad-hoc bundle (new cdhash, no stable Designated Requirement) reports @@ -825,8 +816,7 @@ def _desktop_macos_relaunchable_fixup( return True if publisher_signing_configured is None: publisher_signing_configured = bool( - os.environ.get("CSC_LINK") or os.environ.get("APPLE_SIGNING_IDENTITY") - ) + os.environ.get("CSC_LINK") or os.environ.get("APPLE_SIGNING_IDENTITY")) if publisher_signing_configured: return True exe = _desktop_packaged_executable_in(release_dir or (desktop_dir / "release")) @@ -872,8 +862,7 @@ def _macos_codesigning_identity_valid(security: str, identity: str) -> bool: def _macos_create_signing_identity( - openssl: str, security: str, codesign: str, keychain: str, identity: str -) -> bool: + openssl: str, security: str, codesign: str, keychain: str, identity: str) -> bool: """Create a self-signed code-signing cert (10 years), import it with codesign access, trust it for codeSign.""" tmp_dir = Path(tempfile.mkdtemp(prefix="hermes-tcc-")) try: @@ -890,8 +879,7 @@ def _macos_create_signing_identity( "-addext", "keyUsage=critical,digitalSignature,keyCertSign", "-addext", "extendedKeyUsage=codeSigning", ], - capture_output=True, check=True, - ) + capture_output=True, check=True) # OpenSSL 3 defaults to AES/SHA-2 PKCS#12 that `security import` rejects # with "MAC verification failed". `-legacy` restores the accepted @@ -904,8 +892,7 @@ def _macos_create_signing_identity( "-inkey", str(key), "-in", str(crt), "-out", str(p12), "-passout", "pass:hermeslocal", ], - capture_output=True, check=True, - ) + capture_output=True, check=True) def _import_p12(): return subprocess.run( @@ -914,8 +901,7 @@ def _macos_create_signing_identity( "-P", "hermeslocal", "-T", codesign, "-T", "/usr/bin/codesign_allocate", ], - capture_output=True, text=True, check=False, - ) + capture_output=True, text=True, check=False) _export_p12([]) imported = _import_p12() @@ -935,8 +921,7 @@ def _macos_create_signing_identity( # command exists to front-load. trusted = subprocess.run( [security, "add-trusted-cert", "-r", "trustRoot", "-p", "codeSign", "-k", keychain, str(crt)], - capture_output=True, text=True, check=False, - ) + capture_output=True, text=True, check=False) if trusted.returncode != 0: print( " (could not trust the certificate for code signing: " @@ -1062,8 +1047,7 @@ def _desktop_linux_userns_sandbox_available() -> bool: [unshare, "--user", "--map-root-user", "true"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=5, check=False, ).returncode - == 0 - ) + == 0) except (OSError, subprocess.TimeoutExpired): return False @@ -1159,8 +1143,7 @@ def _detect_linux_password_store() -> str | None: "org.freedesktop.DBus.Peer.Ping", ], capture_output=True, - timeout=5, - ) + timeout=5) if result.returncode == 0: return "gnome-libsecret" except Exception: @@ -1285,8 +1268,7 @@ def _run_desktop_pack_with_recovery( build_result.returncode != 0 and staging_dir is not None and not env.get("ELECTRON_MIRROR") - and _staged_exe() is None - ): + and _staged_exe() is None): print(" ⚠ Desktop build still failing; the Electron download from " "GitHub looks blocked. Re-downloading via a public mirror " "(npmmirror.com)... (set ELECTRON_MIRROR to use another mirror)") @@ -1396,8 +1378,7 @@ def _desktop_launch_env(args: argparse.Namespace) -> tuple[dict, list[str]]: env["HERMES_DESKTOP_CWD"] = os.getcwd() config_electron_flags, config_disable_gpu, config_password_store, config_ozone_hint = ( - _desktop_launch_options() - ) + _desktop_launch_options()) if config_disable_gpu != "auto" and "HERMES_DESKTOP_DISABLE_GPU" not in os.environ: env["HERMES_DESKTOP_DISABLE_GPU"] = config_disable_gpu if config_ozone_hint != "auto" and "ELECTRON_OZONE_PLATFORM_HINT" not in os.environ: diff --git a/hermes_cli/main_tui_launch.py b/hermes_cli/main_tui_launch.py index 8454273835..a314e0ca75 100644 --- a/hermes_cli/main_tui_launch.py +++ b/hermes_cli/main_tui_launch.py @@ -54,8 +54,7 @@ def _print_tui_exit_summary(session_id: Optional[str], active_session_file: Opti return # No real conversation — don't show resume info tokens = { k: int(session.get(f"{k}_tokens") or 0) - for k in ("input", "output", "cache_read", "cache_write", "reasoning") - } + for k in ("input", "output", "cache_read", "cache_write", "reasoning")} except Exception: return finally: @@ -99,8 +98,7 @@ def _workspace_root(dir: Path) -> Path: if ( (dir / "package.json").is_file() and not (dir / "package-lock.json").is_file() - and (dir.parent / "package-lock.json").is_file() - ): + and (dir.parent / "package-lock.json").is_file()): return dir.parent return dir @@ -340,8 +338,7 @@ def _ensure_tui_node() -> None: result = subprocess.run( ["bash", "-c", f'source "{helper}" >&2 && ensure_node >&2 && command -v node'], env={**os.environ, "HERMES_HOME": hermes_home}, - capture_output=True, text=True, encoding="utf-8", errors="replace", check=False, - ) + capture_output=True, text=True, encoding="utf-8", errors="replace", check=False) except (OSError, subprocess.SubprocessError): return @@ -378,8 +375,7 @@ def _restore_tui_workspace(tui_dir: Path) -> bool: try: subprocess.run( [git, "restore", "--", tui_dir.name], cwd=str(tui_dir.parent), capture_output=True, - text=True, encoding="utf-8", errors="replace", check=False, - ) + text=True, encoding="utf-8", errors="replace", check=False) except OSError: return False return tui_dir.is_dir() @@ -405,8 +401,7 @@ def _ensure_tui_workspace(tui_dir: Path) -> None: " 2. Run `npm install --silent --no-fund --no-audit --progress=false`\n" " 3. Retry `hermes --tui`\n" "If the checkout is still inconsistent, run `hermes update --force`.", - file=sys.stderr, - ) + file=sys.stderr) sys.exit(1) @@ -457,8 +452,7 @@ def _run_tui_npm_build(npm: str, cwd: Path, failure_message: str) -> None: """``npm run build`` in *cwd*; exit with *failure_message* + output tail on failure.""" result = subprocess.run( [npm, "run", "build"], cwd=str(cwd), capture_output=True, text=True, encoding="utf-8", - errors="replace", env=_npm_lifecycle_env(), - ) + errors="replace", env=_npm_lifecycle_env()) _exit_on_npm_failure(result, failure_message, sep="") @@ -489,8 +483,7 @@ def _install_tui_dependencies(tui_dir: Path, *, termux_startup: bool) -> None: return subprocess.run( npm_install_cmd, cwd=str(npm_cwd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, encoding="utf-8", errors="replace", - env=_npm_lifecycle_env(with_hermes_node_path()), - ) + env=_npm_lifecycle_env(with_hermes_node_path())) result = _run_tui_install() if result.returncode != 0: @@ -517,8 +510,7 @@ def _make_tui_argv(tui_dir: Path, tui_dev: bool) -> tuple[list[str], Path]: f"Error: --dev is incompatible with HERMES_TUI_DIR={ext_dir}\n" f"The prebuilt TUI has no source code to hot-reload.\n" f"Unset HERMES_TUI_DIR (e.g. `unset HERMES_TUI_DIR`) to use --dev from a checkout.", - file=sys.stderr, - ) + file=sys.stderr) sys.exit(1) # 1. Prebuilt bundle (nix / packaged release / Docker image): just run it. @@ -700,8 +692,7 @@ def _launch_tui( provider: Optional[str] = None, toolsets: object = None, skills: object = None, verbose: Optional[bool] = None, quiet: bool = False, query: Optional[str] = None, image: Optional[str] = None, worktree: bool = False, checkpoints: bool = False, - pass_session_id: bool = False, max_turns: Optional[int] = None, accept_hooks: bool = False, -): + pass_session_id: bool = False, max_turns: Optional[int] = None, accept_hooks: bool = False): """Replace current process with the TUI.""" from hermes_cli.main import PROJECT_ROOT, _apply_tui_python_env, _make_tui_argv, _resolve_tui_heap_mb tui_dir = PROJECT_ROOT / "ui-tui" @@ -748,8 +739,7 @@ def _launch_tui( ("HERMES_TUI_PASS_SESSION_ID", "1" if pass_session_id else None), ("HERMES_TUI_MAX_TURNS", str(max_turns) if max_turns is not None else None), ("HERMES_TUI_TOOL_PROGRESS", "verbose" if verbose else "off" if quiet else None), - ("HERMES_ACCEPT_HOOKS", "1" if accept_hooks else None), - ): + ("HERMES_ACCEPT_HOOKS", "1" if accept_hooks else None)): if value: env[key] = value # Generous V8 heap (8GB target; default cap can fatal-OOM on long sessions), diff --git a/hermes_cli/main_web_build.py b/hermes_cli/main_web_build.py index ba152938d9..1b99040ddd 100644 --- a/hermes_cli/main_web_build.py +++ b/hermes_cli/main_web_build.py @@ -20,8 +20,7 @@ import time as _time from pathlib import Path from typing import Callable from hermes_cli.main_tui_launch import ( - _npm_lifecycle_env, _termux_workspace_install_context, _workspace_root -) + _npm_lifecycle_env, _termux_workspace_install_context, _workspace_root) # Log-record parity with the origin module. logger = logging.getLogger("hermes_cli.main") @@ -178,8 +177,7 @@ def _web_ui_build_needed(web_dir: Path) -> bool: if not sentinel.exists(): return True return not _stamp_is_current( - _web_ui_stamp_path(), lambda: _compute_web_ui_content_hash(project_root, web_dir) - ) + _web_ui_stamp_path(), lambda: _compute_web_ui_content_hash(project_root, web_dir)) def _compute_web_ui_content_hash(project_root: Path, web_dir: Path) -> str: @@ -196,8 +194,7 @@ def _web_ui_stamp_path() -> Path: def _write_web_ui_build_stamp(project_root: Path, web_dir: Path) -> None: """Write the web UI build stamp after a successful build.""" _write_build_stamp( - _web_ui_stamp_path(), "web UI", lambda: _compute_web_ui_content_hash(project_root, web_dir) - ) + _web_ui_stamp_path(), "web UI", lambda: _compute_web_ui_content_hash(project_root, web_dir)) def _console_print(text: str) -> None: @@ -211,8 +208,7 @@ def _console_print(text: str) -> None: def _run_with_idle_timeout( cmd: list[str], cwd: Path, *, idle_timeout_seconds: int = 180, indent: str = " ", - env: dict[str, str] | None = None, -) -> subprocess.CompletedProcess: + env: dict[str, str] | None = None) -> subprocess.CompletedProcess: """Stream a subprocess, killing it after *idle_timeout_seconds* of silence (a silent captured Vite build on a low-memory host looks like a hang and users reboot mid-install). Returns merged stdout, empty stderr, rc 124 if terminate raced a clean exit; never raises on idle timeout.""" @@ -223,8 +219,7 @@ def _run_with_idle_timeout( try: proc = subprocess.Popen( cmd, cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - text=True, encoding="utf-8", errors="replace", bufsize=1, env=env, - ) + text=True, encoding="utf-8", errors="replace", bufsize=1, env=env) except OSError as exc: # E.g. npm not on PATH between the which() check and now. return subprocess.CompletedProcess(cmd, 127, stdout="", stderr=str(exc)) @@ -309,8 +304,7 @@ def _nixos_build_env() -> dict[str, str] | None: def _run_npm_install_deterministic( npm: str, cwd: Path, *, extra_args: tuple[str, ...] = (), capture_output: bool = True, - env: dict[str, str] | None = None, -) -> subprocess.CompletedProcess: + env: dict[str, str] | None = None) -> subprocess.CompletedProcess: """Deterministic npm install that never mutates ``package-lock.json``. ``npm ci`` when a lockfile exists, else/on failure ``npm install --no-save``