diff --git a/agent/anthropic_adapter.py b/agent/anthropic_adapter.py index e4d1d5ac125e..9809d0e3d0f7 100644 --- a/agent/anthropic_adapter.py +++ b/agent/anthropic_adapter.py @@ -359,7 +359,7 @@ def _detect_claude_code_version() -> str: try: result = _sp.run( [cmd, "--version"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) if result.returncode == 0 and result.stdout.strip(): # Output is like "2.1.74 (Claude Code)" or just "2.1.74" @@ -890,7 +890,7 @@ def _read_claude_code_credentials_from_keychain() -> Optional[Dict[str, Any]]: "-s", "Claude Code-credentials", "-w"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, stdin=subprocess.DEVNULL, ) diff --git a/agent/coding_context.py b/agent/coding_context.py index 8fb51a0b04d6..2ecb21268aaf 100644 --- a/agent/coding_context.py +++ b/agent/coding_context.py @@ -654,7 +654,7 @@ def _git(cwd: Path, *args: str) -> str: out = subprocess.run( ["git", "-C", str(cwd), *args], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=_GIT_TIMEOUT, **_popen_kwargs, ) diff --git a/agent/context_references.py b/agent/context_references.py index d77857584a77..03981384b50d 100644 --- a/agent/context_references.py +++ b/agent/context_references.py @@ -297,7 +297,7 @@ def _expand_git_reference( ["git", *args], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, stdin=subprocess.DEVNULL, **_popen_kwargs, @@ -492,7 +492,7 @@ def _rg_files(path: Path, cwd: Path, limit: int) -> list[Path] | None: ["rg", "--files", str(path.relative_to(cwd))], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, stdin=subprocess.DEVNULL, **_popen_kwargs, diff --git a/agent/copilot_acp_client.py b/agent/copilot_acp_client.py index ce3ec2c5c400..9454d9fe2c48 100644 --- a/agent/copilot_acp_client.py +++ b/agent/copilot_acp_client.py @@ -508,7 +508,7 @@ def _run_prompt(self, prompt_text: str, *, timeout_seconds: float) -> tuple[str, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - text=True, + text=True, encoding='utf-8', errors='replace', bufsize=1, cwd=self._acp_cwd, env=_build_subprocess_env(), diff --git a/agent/lsp/install.py b/agent/lsp/install.py index 418cc510c709..03f845ef007b 100644 --- a/agent/lsp/install.py +++ b/agent/lsp/install.py @@ -260,7 +260,7 @@ def _install_npm( [npm, "install", "--prefix", str(staging), "--silent", "--no-fund", "--no-audit", *install_targets], check=False, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=300, stdin=subprocess.DEVNULL, ) @@ -308,7 +308,7 @@ def _install_go(pkg: str, bin_name: str) -> Optional[str]: [go, "install", pkg], check=False, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=600, env=env, stdin=subprocess.DEVNULL, @@ -347,7 +347,7 @@ def _install_pip(pkg: str, bin_name: str) -> Optional[str]: [sys.executable, "-m", "pip", "install", "--target", str(pip_target), "--quiet", pkg], check=False, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=300, stdin=subprocess.DEVNULL, ) diff --git a/agent/secret_sources/bitwarden.py b/agent/secret_sources/bitwarden.py index e025a0ca9b4e..3ff04e39a791 100644 --- a/agent/secret_sources/bitwarden.py +++ b/agent/secret_sources/bitwarden.py @@ -272,7 +272,7 @@ def _platform_asset_name() -> str: res = subprocess.run( ["ldd", "--version"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=2, stdin=subprocess.DEVNULL, ) @@ -524,7 +524,7 @@ def _run_bws_list( cmd, env=env, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=_BWS_RUN_TIMEOUT, stdin=subprocess.DEVNULL, ) diff --git a/agent/shell_hooks.py b/agent/shell_hooks.py index a48bab42bb8a..20a3dba58a0e 100644 --- a/agent/shell_hooks.py +++ b/agent/shell_hooks.py @@ -450,7 +450,7 @@ def _spawn(spec: ShellHookSpec, stdin_json: str) -> Dict[str, Any]: input=stdin_json, capture_output=True, timeout=spec.timeout, - text=True, + text=True, encoding='utf-8', errors='replace', shell=False, **_popen_kwargs, ) diff --git a/agent/skill_preprocessing.py b/agent/skill_preprocessing.py index bd0386d58058..19c6eeb80fb3 100644 --- a/agent/skill_preprocessing.py +++ b/agent/skill_preprocessing.py @@ -74,7 +74,7 @@ def run_inline_shell(command: str, cwd: Path | None, timeout: int) -> str: ["bash", "-c", command], cwd=str(cwd) if cwd else None, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=max(1, int(timeout)), check=False, stdin=subprocess.DEVNULL, diff --git a/agent/transports/codex_app_server.py b/agent/transports/codex_app_server.py index dff16e971da6..29f3b121e359 100644 --- a/agent/transports/codex_app_server.py +++ b/agent/transports/codex_app_server.py @@ -376,7 +376,7 @@ def check_codex_binary( proc = subprocess.run( [codex_bin, "--version"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, stdin=subprocess.DEVNULL, ) diff --git a/batch_runner.py b/batch_runner.py index 289361989550..a00471d39099 100644 --- a/batch_runner.py +++ b/batch_runner.py @@ -282,7 +282,7 @@ def _process_single_prompt( print(f" Prompt {prompt_index}: Pulling docker image {container_image}...", flush=True) pull = _sp.run( ["docker", "pull", container_image], - capture_output=True, text=True, timeout=600, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=600, ) if pull.returncode != 0: return { diff --git a/cli.py b/cli.py index e209c48eecf9..e809d161dd41 100644 --- a/cli.py +++ b/cli.py @@ -1229,7 +1229,7 @@ def _git_repo_root() -> Optional[str]: try: result = subprocess.run( ["git", "rev-parse", "--show-toplevel"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) if result.returncode == 0: return _normalize_git_bash_path(result.stdout.strip()) @@ -1276,7 +1276,7 @@ def _resolve_worktree_base(repo_root: str) -> tuple: def _git(args, timeout=20): return subprocess.run( ["git", *args], - capture_output=True, text=True, timeout=timeout, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=timeout, cwd=repo_root, ) # 1. Current branch's upstream, if it tracks one. @@ -1375,7 +1375,7 @@ def _setup_worktree(repo_root: str = None, sync_base: bool = True) -> Optional[D try: result = subprocess.run( ["git", "worktree", "add", str(wt_path), "-b", branch_name, base_ref], - capture_output=True, text=True, timeout=30, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=30, cwd=repo_root, ) if result.returncode != 0: # If branching from the resolved remote ref failed for any reason @@ -1389,7 +1389,7 @@ def _setup_worktree(repo_root: str = None, sync_base: bool = True) -> Optional[D base_ref, base_label = "HEAD", "HEAD (fallback — remote base failed)" result = subprocess.run( ["git", "worktree", "add", str(wt_path), "-b", branch_name, base_ref], - capture_output=True, text=True, timeout=30, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=30, cwd=repo_root, ) if result.returncode != 0: print(f"\033[31m✗ Failed to create worktree: {result.stderr.strip()}\033[0m") @@ -1470,7 +1470,7 @@ def _setup_worktree(repo_root: str = None, sync_base: bool = True) -> Optional[D try: subprocess.run( ["git", "worktree", "lock", "--reason", f"hermes pid={os.getpid()}", str(wt_path)], - capture_output=True, text=True, timeout=10, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, cwd=repo_root, ) logger.debug("Worktree locked: %s (pid=%s)", wt_path, os.getpid()) except Exception as e: @@ -1503,7 +1503,7 @@ def _worktree_has_unpushed_commits(worktree_path: str, timeout: int = 10) -> boo try: remote_refs = subprocess.run( ["git", "for-each-ref", "--format=%(refname)", "refs/remotes"], - capture_output=True, text=True, timeout=timeout, cwd=worktree_path, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=timeout, cwd=worktree_path, ) if remote_refs.returncode != 0: return True @@ -1512,7 +1512,7 @@ def _worktree_has_unpushed_commits(worktree_path: str, timeout: int = 10) -> boo result = subprocess.run( ["git", "log", "--oneline", "HEAD", "--not", "--remotes"], - capture_output=True, text=True, timeout=timeout, cwd=worktree_path, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=timeout, cwd=worktree_path, ) if result.returncode != 0: return True @@ -1558,7 +1558,7 @@ def _cleanup_worktree(info: Dict[str, str] = None) -> None: try: subprocess.run( ["git", "worktree", "unlock", wt_path], - capture_output=True, text=True, timeout=10, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, cwd=repo_root, ) except Exception as e: logger.debug("git worktree unlock failed (non-fatal): %s", e) @@ -1566,7 +1566,7 @@ def _cleanup_worktree(info: Dict[str, str] = None) -> None: try: subprocess.run( ["git", "worktree", "remove", wt_path, "--force"], - capture_output=True, text=True, timeout=15, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=15, cwd=repo_root, ) except Exception as e: logger.debug("Failed to remove worktree: %s", e) @@ -1575,7 +1575,7 @@ def _cleanup_worktree(info: Dict[str, str] = None) -> None: try: subprocess.run( ["git", "branch", "-D", branch], - capture_output=True, text=True, timeout=10, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, cwd=repo_root, ) except Exception as e: logger.debug("Failed to delete branch %s: %s", branch, e) @@ -1708,18 +1708,18 @@ def _prune_stale_worktrees(repo_root: str, max_age_hours: int = 24) -> None: try: branch_result = subprocess.run( ["git", "branch", "--show-current"], - capture_output=True, text=True, timeout=5, cwd=str(entry), + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, cwd=str(entry), ) branch = branch_result.stdout.strip() subprocess.run( ["git", "worktree", "remove", str(entry), "--force"], - capture_output=True, text=True, timeout=15, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=15, cwd=repo_root, ) if branch: subprocess.run( ["git", "branch", "-D", branch], - capture_output=True, text=True, timeout=10, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, cwd=repo_root, ) logger.debug("Pruned stale worktree: %s (force=%s)", entry.name, force) except Exception as e: @@ -1740,7 +1740,7 @@ def _prune_orphaned_branches(repo_root: str) -> None: try: result = subprocess.run( ["git", "branch", "--format=%(refname:short)"], - capture_output=True, text=True, timeout=10, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, cwd=repo_root, ) if result.returncode != 0: return @@ -1753,7 +1753,7 @@ def _prune_orphaned_branches(repo_root: str) -> None: try: wt_result = subprocess.run( ["git", "worktree", "list", "--porcelain"], - capture_output=True, text=True, timeout=10, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, cwd=repo_root, ) for line in wt_result.stdout.split("\n"): if line.startswith("branch refs/heads/"): @@ -1765,7 +1765,7 @@ def _prune_orphaned_branches(repo_root: str) -> None: try: head_result = subprocess.run( ["git", "branch", "--show-current"], - capture_output=True, text=True, timeout=5, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, cwd=repo_root, ) current = head_result.stdout.strip() if current: @@ -1789,7 +1789,7 @@ def _prune_orphaned_branches(repo_root: str) -> None: try: subprocess.run( ["git", "branch", "-D"] + batch, - capture_output=True, text=True, timeout=30, cwd=repo_root, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=30, cwd=repo_root, ) except Exception as e: logger.debug("Failed to prune orphaned branches: %s", e) @@ -8578,7 +8578,7 @@ def process_command(self, command: str) -> bool: # shell snippets from config.yaml — not agent/LLM controlled. result = subprocess.run( exec_cmd, shell=True, capture_output=True, - text=True, timeout=30 + text=True, encoding='utf-8', errors='replace', timeout=30 ) output = result.stdout.strip() or result.stderr.strip() if output: diff --git a/cron/scheduler.py b/cron/scheduler.py index 410e9d7dc777..0fd5e2067012 100644 --- a/cron/scheduler.py +++ b/cron/scheduler.py @@ -1634,7 +1634,7 @@ def _run_job_script(script_path: str) -> tuple[bool, str]: result = subprocess.run( argv, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=script_timeout, cwd=str(path.parent), env=_sanitize_subprocess_env(os.environ.copy()), diff --git a/gateway/platforms/base.py b/gateway/platforms/base.py index de7ec492329f..a605c2a262fa 100644 --- a/gateway/platforms/base.py +++ b/gateway/platforms/base.py @@ -229,7 +229,7 @@ def _detect_macos_system_proxy() -> str | None: return None try: out = subprocess.check_output( - ["scutil", "--proxy"], timeout=3, text=True, stderr=subprocess.DEVNULL, + ["scutil", "--proxy"], timeout=3, text=True, encoding='utf-8', errors='replace', stderr=subprocess.DEVNULL, ) except Exception: return None diff --git a/gateway/platforms/webhook.py b/gateway/platforms/webhook.py index 9d236f2198bc..b4aa26782f39 100644 --- a/gateway/platforms/webhook.py +++ b/gateway/platforms/webhook.py @@ -972,7 +972,7 @@ async def _deliver_github_comment( content, ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, ) if result.returncode == 0: diff --git a/gateway/run.py b/gateway/run.py index 04b67d2bae22..e6768495dc61 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -5640,7 +5640,7 @@ def _launch_systemd_restart_shortcut(self) -> None: "--value", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=2, ) if (show.stdout or "").strip() != str(current_pid): diff --git a/gateway/shutdown_forensics.py b/gateway/shutdown_forensics.py index 0a52ce14f094..34836cc6fb17 100644 --- a/gateway/shutdown_forensics.py +++ b/gateway/shutdown_forensics.py @@ -368,7 +368,7 @@ def check_systemd_timing_alignment(drain_timeout: float) -> Optional[Dict[str, A try: result = subprocess.run( ["systemctl", *flag, "show", unit_name, "--property=TimeoutStopUSec"], - capture_output=True, text=True, timeout=2.0, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=2.0, ) except (FileNotFoundError, subprocess.TimeoutExpired, OSError): continue diff --git a/gateway/status.py b/gateway/status.py index 9b8a1b6f83c2..cf3a501f62b2 100644 --- a/gateway/status.py +++ b/gateway/status.py @@ -90,7 +90,7 @@ def terminate_pid(pid: int, *, force: bool = False) -> None: result = subprocess.run( ["taskkill", "/PID", str(pid), "/T", "/F"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, creationflags=windows_hide_flags(), ) @@ -176,7 +176,7 @@ def _read_process_cmdline(pid: int) -> Optional[str]: result = subprocess.run( ["ps", "-p", str(pid), "-o", "command="], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) if result.returncode == 0 and result.stdout.strip(): @@ -626,7 +626,7 @@ def _pid_exists(pid: int) -> bool: r = subprocess.run( ["ps", "-o", "state=", "-p", str(int(pid))], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) if r.returncode == 0 and r.stdout.strip().startswith("Z"): diff --git a/hermes_cli/banner.py b/hermes_cli/banner.py index 217eb2bb9656..40668495022a 100644 --- a/hermes_cli/banner.py +++ b/hermes_cli/banner.py @@ -160,7 +160,7 @@ def _git_stdout(args: list[str], *, cwd: Path, timeout: int = 5) -> Optional[str result = subprocess.run( ["git", *args], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=timeout, cwd=str(cwd), ) @@ -180,7 +180,7 @@ def _check_via_rev(local_rev: str) -> Optional[int]: try: result = subprocess.run( ["git", "ls-remote", _UPSTREAM_REPO_URL, "refs/heads/main"], - capture_output=True, text=True, timeout=10, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, ) except Exception: return None @@ -242,7 +242,7 @@ def _check_via_local_git(repo_dir: Path) -> Optional[int]: try: result = subprocess.run( ["git", "rev-list", "--count", "HEAD..origin/main"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, cwd=str(repo_dir), ) if result.returncode == 0: @@ -390,7 +390,7 @@ def _git_short_hash(repo_dir: Path, rev: str) -> Optional[str]: result = subprocess.run( ["git", "rev-parse", "--short=8", rev], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, cwd=str(repo_dir), ) @@ -446,7 +446,7 @@ def get_git_banner_state(repo_dir: Optional[Path] = None) -> Optional[dict]: result = subprocess.run( ["git", "rev-list", "--count", "origin/main..HEAD"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, cwd=str(repo_dir), ) @@ -482,7 +482,7 @@ def get_latest_release_tag(repo_dir: Optional[Path] = None) -> Optional[tuple]: result = subprocess.run( ["git", "describe", "--tags", "--abbrev=0"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=3, cwd=str(repo_dir), ) diff --git a/hermes_cli/claw.py b/hermes_cli/claw.py index 792e35c1683b..8f58d9520e69 100644 --- a/hermes_cli/claw.py +++ b/hermes_cli/claw.py @@ -68,7 +68,7 @@ def _detect_openclaw_processes() -> list[str]: try: result = subprocess.run( ["systemctl", "--user", "is-active", "openclaw-gateway.service"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) if result.stdout.strip() == "active": found.append("systemd service: openclaw-gateway.service") @@ -81,7 +81,7 @@ def _detect_openclaw_processes() -> list[str]: for exe in ("openclaw.exe", "clawd.exe"): result = subprocess.run( ["tasklist", "/FI", f"IMAGENAME eq {exe}"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) if exe in result.stdout.lower(): found.append(f"process: {exe}") @@ -95,7 +95,7 @@ def _detect_openclaw_processes() -> list[str]: ) result = subprocess.run( ["powershell", "-NoProfile", "-Command", ps_cmd], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) if result.stdout.strip(): found.append(f"node.exe process with openclaw in command line (PID {result.stdout.strip()})") @@ -105,7 +105,7 @@ def _detect_openclaw_processes() -> list[str]: try: result = subprocess.run( ["pgrep", "-f", "openclaw"], - capture_output=True, text=True, timeout=3, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=3, ) if result.returncode == 0: pids = result.stdout.strip().split() diff --git a/hermes_cli/clipboard.py b/hermes_cli/clipboard.py index a6b6da7c06aa..78a9a43c3d75 100644 --- a/hermes_cli/clipboard.py +++ b/hermes_cli/clipboard.py @@ -67,7 +67,7 @@ def _macos_has_image() -> bool: try: info = subprocess.run( ["osascript", "-e", "clipboard info"], - capture_output=True, text=True, timeout=3, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=3, ) return "«class PNGf»" in info.stdout or "«class TIFF»" in info.stdout except Exception: @@ -109,7 +109,7 @@ def _macos_osascript(dest: Path) -> bool: try: r = subprocess.run( ["osascript", "-e", script], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) if r.returncode == 0 and "fail" not in r.stdout and dest.exists() and dest.stat().st_size > 0: return True @@ -200,7 +200,7 @@ def _macos_osascript(dest: Path) -> bool: def _run_powershell(exe: str, script: str, timeout: int) -> subprocess.CompletedProcess: return subprocess.run( [exe, "-NoProfile", "-NonInteractive", "-Command", script], - capture_output=True, text=True, timeout=timeout, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=timeout, ) @@ -258,7 +258,7 @@ def _find_powershell() -> str | None: try: r = subprocess.run( [name, "-NoProfile", "-NonInteractive", "-Command", "echo ok"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) if r.returncode == 0 and "ok" in r.stdout: return name @@ -333,7 +333,7 @@ def _wayland_has_image() -> bool: try: r = subprocess.run( ["wl-paste", "--list-types"], - capture_output=True, text=True, timeout=3, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=3, ) return r.returncode == 0 and any( t.startswith("image/") for t in r.stdout.splitlines() @@ -351,7 +351,7 @@ def _wayland_save(dest: Path) -> bool: # Check available MIME types types_r = subprocess.run( ["wl-paste", "--list-types"], - capture_output=True, text=True, timeout=3, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=3, ) if types_r.returncode != 0: return False @@ -453,7 +453,7 @@ def _xclip_has_image() -> bool: try: r = subprocess.run( ["xclip", "-selection", "clipboard", "-t", "TARGETS", "-o"], - capture_output=True, text=True, timeout=3, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=3, ) return r.returncode == 0 and "image/png" in r.stdout except FileNotFoundError: @@ -469,7 +469,7 @@ def _xclip_save(dest: Path) -> bool: try: targets = subprocess.run( ["xclip", "-selection", "clipboard", "-t", "TARGETS", "-o"], - capture_output=True, text=True, timeout=3, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=3, ) if "image/png" not in targets.stdout: return False diff --git a/hermes_cli/commands.py b/hermes_cli/commands.py index bdba0af1cfa5..0f0dd03c9e95 100644 --- a/hermes_cli/commands.py +++ b/hermes_cli/commands.py @@ -1584,7 +1584,7 @@ def _get_project_files(self) -> list[str]: continue try: proc = subprocess.run( - cmd, capture_output=True, text=True, timeout=2, + cmd, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=2, cwd=cwd, encoding="utf-8", errors="replace", ) if proc.returncode == 0 and proc.stdout and proc.stdout.strip(): diff --git a/hermes_cli/copilot_auth.py b/hermes_cli/copilot_auth.py index dd4643d2425b..10b1846a3a03 100644 --- a/hermes_cli/copilot_auth.py +++ b/hermes_cli/copilot_auth.py @@ -141,7 +141,7 @@ def _try_gh_cli_token() -> Optional[str]: result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, env=clean_env, **_popen_kwargs, diff --git a/hermes_cli/doctor.py b/hermes_cli/doctor.py index 496f7e90742e..97597fcabb07 100644 --- a/hermes_cli/doctor.py +++ b/hermes_cli/doctor.py @@ -1478,7 +1478,7 @@ def run_doctor(args): result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=15 ) except subprocess.TimeoutExpired: @@ -1642,7 +1642,7 @@ def run_doctor(args): audit_result = subprocess.run( [_npm_bin, "audit", "--json", *audit_extra], cwd=str(npm_dir), - capture_output=True, text=True, timeout=30, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=30, ) import json as _json audit_data = _json.loads(audit_result.stdout) if audit_result.stdout.strip() else {} diff --git a/hermes_cli/dump.py b/hermes_cli/dump.py index 82a49b03f1c2..eb2eaf67de80 100644 --- a/hermes_cli/dump.py +++ b/hermes_cli/dump.py @@ -32,7 +32,7 @@ def _get_git_commit(project_root: Path) -> str: try: result = subprocess.run( ["git", "rev-parse", "--short=8", "HEAD"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, cwd=str(project_root), ) if result.returncode == 0: @@ -67,7 +67,7 @@ def _get_git_commit_date(project_root: Path) -> str: try: result = subprocess.run( ["git", "log", "-1", "--format=%cd", "--date=short", "HEAD"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, cwd=str(project_root), ) if result.returncode == 0: diff --git a/hermes_cli/gateway.py b/hermes_cli/gateway.py index a39ef54ad56f..d42553aaad25 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -105,7 +105,7 @@ def _get_service_pids() -> set: "--no-pager", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) for line in result.stdout.strip().splitlines(): @@ -117,7 +117,7 @@ def _get_service_pids() -> set: show = subprocess.run( scope_args + ["show", svc, "--property=MainPID", "--value"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) pid = int(show.stdout.strip()) @@ -135,7 +135,7 @@ def _get_service_pids() -> set: result = subprocess.run( ["launchctl", "list", label], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) if result.returncode == 0: @@ -191,7 +191,7 @@ def _get_parent_pid(pid: int) -> int | None: result = subprocess.run( ["ps", "-o", "ppid=", "-p", str(pid)], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) except (FileNotFoundError, subprocess.TimeoutExpired): @@ -408,7 +408,7 @@ def _matches_gateway_runtime(command: str) -> bool: "/FORMAT:LIST", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="ignore", timeout=10, @@ -434,7 +434,7 @@ def _matches_gateway_runtime(command: str) -> bool: result = subprocess.run( [powershell, "-NoProfile", "-Command", ps_cmd], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="ignore", timeout=15, @@ -491,7 +491,7 @@ def _matches_gateway_runtime(command: str) -> bool: result = subprocess.run( ["ps", "-A", "eww", "-o", "pid=,command="], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) if result.returncode != 0: @@ -882,7 +882,7 @@ def _probe_systemd_service_running(system: bool = False) -> tuple[bool, bool]: ["is-active", get_service_name()], system=selected_system, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) except (RuntimeError, subprocess.TimeoutExpired): @@ -909,7 +909,7 @@ def _read_systemd_unit_environment(system: bool = False) -> dict[str, str]: ], system=selected_system, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) except (RuntimeError, subprocess.TimeoutExpired, OSError): @@ -973,7 +973,7 @@ def _read_systemd_unit_properties( ], system=selected_system, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) except (RuntimeError, subprocess.TimeoutExpired, OSError): @@ -1230,7 +1230,7 @@ def _probe_launchd_service_running() -> bool: result = subprocess.run( ["launchctl", "list", get_launchd_label()], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) except subprocess.TimeoutExpired: @@ -1588,7 +1588,7 @@ def _systemd_operational(system: bool = False) -> bool: ["is-system-running"], system=system, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) # "running", "degraded", "starting" all mean systemd is PID 1 @@ -1897,7 +1897,7 @@ def _preflight_user_systemd(*, auto_enable_linger: bool = True) -> None: result = subprocess.run( ["loginctl", "enable-linger", username], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=False, timeout=30, ) @@ -2374,7 +2374,7 @@ def get_systemd_linger_status() -> tuple[bool | None, str]: result = subprocess.run( ["loginctl", "show-user", username, "--property=Linger", "--value"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=False, timeout=10, ) @@ -2972,7 +2972,7 @@ def _ensure_linger_enabled() -> None: result = subprocess.run( ["loginctl", "enable-linger", username], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=False, timeout=30, ) @@ -3341,7 +3341,7 @@ def systemd_status(deep: bool = False, system: bool = False, full: bool = False) ["is-active", get_service_name()], system=system, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) @@ -3489,7 +3489,7 @@ def _launchd_domain() -> str: result = subprocess.run( ["launchctl", "managername"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) if "Aqua" in (result.stdout or ""): @@ -4121,7 +4121,7 @@ def launchd_status(deep: bool = False): result = subprocess.run( ["launchctl", "list", label], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) service_listed = result.returncode == 0 @@ -5187,7 +5187,7 @@ def _is_service_running() -> bool: ["is-active", get_service_name()], system=False, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) if result.stdout.strip() == "active": @@ -5201,7 +5201,7 @@ def _is_service_running() -> bool: ["is-active", get_service_name()], system=True, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) if result.stdout.strip() == "active": @@ -5215,7 +5215,7 @@ def _is_service_running() -> bool: result = subprocess.run( ["launchctl", "list", get_launchd_label()], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) return result.returncode == 0 diff --git a/hermes_cli/gateway_windows.py b/hermes_cli/gateway_windows.py index 55ed976433da..15673a140326 100644 --- a/hermes_cli/gateway_windows.py +++ b/hermes_cli/gateway_windows.py @@ -160,7 +160,7 @@ def _exec_schtasks(args: list[str]) -> tuple[int, str, str]: proc = subprocess.run( [schtasks, *args], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', # Localized Windows emits schtasks output in the console code page, # not UTF-8. Decode with the locale encoding and replace undecodable # bytes so a non-UTF-8 status line never surfaces a UnicodeDecodeError diff --git a/hermes_cli/kanban_db.py b/hermes_cli/kanban_db.py index 6150b141537b..07697ca5b2cf 100644 --- a/hermes_cli/kanban_db.py +++ b/hermes_cli/kanban_db.py @@ -4372,7 +4372,7 @@ def _cleanup_worker_tmux(conn: sqlite3.Connection, task_id: str) -> None: # Check if session exists and pane is dead before killing out = subprocess.run( ["tmux", "list-panes", "-t", session, "-F", "#{pane_dead}"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) if out.stdout.strip() == "1": subprocess.run( @@ -5289,7 +5289,7 @@ def _git_toplevel(path: Path) -> Optional[Path]: result = subprocess.run( ["git", "-C", str(path), "rev-parse", "--show-toplevel"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, check=False, ) @@ -5311,7 +5311,7 @@ def _git_branch_exists(repo_root: Path, branch_name: str) -> bool: result = subprocess.run( ["git", "-C", str(repo_root), "show-ref", "--verify", f"refs/heads/{branch_name}"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, check=False, ) @@ -5325,7 +5325,7 @@ def _git_common_dir(path: Path) -> Optional[Path]: result = subprocess.run( ["git", "-C", str(path), "rev-parse", "--path-format=absolute", "--git-common-dir"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, check=False, ) @@ -5344,7 +5344,7 @@ def _git_dir(path: Path) -> Optional[Path]: result = subprocess.run( ["git", "-C", str(path), "rev-parse", "--path-format=absolute", "--git-dir"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, check=False, ) @@ -5363,7 +5363,7 @@ def _git_current_branch(path: Path) -> Optional[str]: result = subprocess.run( ["git", "-C", str(path), "branch", "--show-current"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, check=False, ) @@ -5420,7 +5420,7 @@ def _ensure_git_worktree(repo_root: Path, target: Path, branch_name: str) -> Non result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=60, check=False, ) @@ -5898,7 +5898,7 @@ def _pid_alive(pid: Optional[int]) -> bool: ["ps", "-o", "stat=", "-p", str(int(pid))], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=1, check=False, ) diff --git a/hermes_cli/main.py b/hermes_cli/main.py index 5f76c1fc8d4f..10d3bc1cbeb0 100644 --- a/hermes_cli/main.py +++ b/hermes_cli/main.py @@ -1163,7 +1163,7 @@ def _probe_container(cmd: list, backend: str, via_sudo: bool = False): all other exceptions propagate naturally. """ try: - return subprocess.run(cmd, capture_output=True, text=True, timeout=15) + return subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=15) except subprocess.TimeoutExpired: label = f"sudo {backend}" if via_sudo else backend print( @@ -1625,7 +1625,7 @@ def _ensure_tui_node() -> None: ], env={**os.environ, "HERMES_HOME": hermes_home}, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", check=False, @@ -1676,7 +1676,7 @@ def _restore_tui_workspace(tui_dir: Path) -> bool: [git, "restore", "--", tui_dir.name], cwd=str(tui_dir.parent), capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=False, ) except OSError: @@ -1812,7 +1812,7 @@ def _node_bin(bin: str) -> str: cwd=str(npm_cwd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", env={**os.environ, "CI": "1"}, @@ -1838,7 +1838,7 @@ def _node_bin(bin: str) -> str: [npm, "run", "build"], cwd=str(ink_dir), capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", ) @@ -1868,7 +1868,7 @@ def _node_bin(bin: str) -> str: [npm, "run", "build"], cwd=str(tui_dir), capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", ) @@ -2556,7 +2556,7 @@ def cmd_whatsapp(args): cwd=str(bridge_dir), stdout=subprocess.DEVNULL, stderr=subprocess.PIPE, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", env=with_hermes_node_path(), @@ -4462,7 +4462,7 @@ def _capture_head_sha(git_cmd, cwd) -> str | None: git_cmd + ["rev-parse", "HEAD"], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=True, ) return result.stdout.strip() or None @@ -4642,7 +4642,7 @@ def _run_with_idle_timeout( cwd=cwd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", bufsize=1, @@ -4748,7 +4748,7 @@ def _nixos_build_env() -> dict[str, str] | None: try: result = subprocess.run( ["nix-shell", "-p", "python3", "--run", "which python3"], - capture_output=True, text=True, check=False, timeout=15, + capture_output=True, text=True, encoding='utf-8', errors='replace', check=False, timeout=15, ) if result.returncode == 0: python3_path = result.stdout.strip() @@ -4788,7 +4788,7 @@ def _run_npm_install_deterministic( cwd=cwd, env=run_env, capture_output=capture_output, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", check=False, @@ -4803,7 +4803,7 @@ def _run_npm_install_deterministic( cwd=cwd, env=run_env, capture_output=capture_output, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", check=False, @@ -5845,7 +5845,7 @@ def _find_stale_dashboard_pids( result = subprocess.run( ["wmic", "process", "get", "ProcessId,CommandLine", "/FORMAT:LIST"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, encoding="utf-8", errors="ignore", @@ -5878,7 +5878,7 @@ def _find_stale_dashboard_pids( result = subprocess.run( ["ps", "-A", "-o", "pid=,command="], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) if result.returncode == 0: @@ -6088,7 +6088,7 @@ def _kill_stale_dashboard_processes( result = subprocess.run( ["taskkill", "/PID", str(pid), "/F"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) if result.returncode == 0: @@ -6396,7 +6396,7 @@ def _stash_local_changes_if_needed(git_cmd: list[str], cwd: Path) -> Optional[st git_cmd + ["status", "--porcelain"], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=True, ) if not status.stdout.strip(): @@ -6410,7 +6410,7 @@ def _stash_local_changes_if_needed(git_cmd: list[str], cwd: Path) -> Optional[st git_cmd + ["ls-files", "--unmerged"], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if unmerged.stdout.strip(): print("→ Clearing unmerged index entries from a previous conflict...") @@ -6431,7 +6431,7 @@ def _stash_local_changes_if_needed(git_cmd: list[str], cwd: Path) -> Optional[st git_cmd + ["rev-parse", "--verify", "refs/stash"], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=True, ).stdout.strip() return stash_ref @@ -6444,7 +6444,7 @@ def _resolve_stash_selector( git_cmd + ["stash", "list", "--format=%gd %H"], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=True, ) for line in stash_list.stdout.splitlines(): @@ -6499,7 +6499,7 @@ def _restore_stashed_changes( git_cmd + ["stash", "apply", stash_ref], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) # Check for unmerged (conflicted) files — can happen even when returncode is 0 @@ -6507,7 +6507,7 @@ def _restore_stashed_changes( git_cmd + ["diff", "--name-only", "--diff-filter=U"], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) has_conflicts = bool(unmerged.stdout.strip()) @@ -6557,7 +6557,7 @@ def _restore_stashed_changes( git_cmd + ["stash", "drop", stash_selector], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if drop.returncode != 0: print( @@ -6609,7 +6609,7 @@ def _discard_stashed_changes( git_cmd + ["stash", "drop", stash_selector], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if drop.returncode != 0: print( @@ -6646,7 +6646,7 @@ def _get_origin_url(git_cmd: list[str], cwd: Path) -> Optional[str]: git_cmd + ["remote", "get-url", "origin"], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if result.returncode == 0: return result.stdout.strip() @@ -6679,7 +6679,7 @@ def _has_upstream_remote(git_cmd: list[str], cwd: Path) -> bool: git_cmd + ["remote", "get-url", "upstream"], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) return result.returncode == 0 except Exception: @@ -6693,7 +6693,7 @@ def _add_upstream_remote(git_cmd: list[str], cwd: Path) -> bool: git_cmd + ["remote", "add", "upstream", OFFICIAL_REPO_URL], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) return result.returncode == 0 except Exception: @@ -6707,7 +6707,7 @@ def _count_commits_between(git_cmd: list[str], cwd: Path, base: str, head: str) git_cmd + ["rev-list", "--count", f"{base}..{head}"], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if result.returncode == 0: return int(result.stdout.strip()) @@ -6743,7 +6743,7 @@ def _sync_fork_with_upstream(git_cmd: list[str], cwd: Path) -> bool: git_cmd + ["push", "origin", "main", "--force-with-lease"], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) return result.returncode == 0 except Exception: @@ -7874,7 +7874,7 @@ def _missing_deps() -> list[str]: result = subprocess.run( [str(venv_python), "-c", check_script, *applicable], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=False, env=env, ) @@ -8318,7 +8318,7 @@ def _run_logged_subprocess(cmd, *, cwd=None, env=None): check=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", ) @@ -8422,7 +8422,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False): git_cmd + ["rev-parse", "--is-shallow-repository"], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ).stdout.strip() == "true" ) @@ -8434,7 +8434,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False): git_cmd + ["fetch"] + depth_args + ["upstream", branch], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if fetch_result.returncode != 0: # Fallback to origin if upstream doesn't exist @@ -8443,7 +8443,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False): git_cmd + ["fetch"] + depth_args + ["origin", branch], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) upstream_exists = False compare_branch = f"origin/{branch}" @@ -8457,7 +8457,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False): git_cmd + ["fetch"] + depth_args + ["origin", branch], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) upstream_exists = False compare_branch = f"origin/{branch}" @@ -8482,7 +8482,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False): git_cmd + ["rev-parse", "--verify", "--quiet", compare_branch], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if verify_result.returncode != 0: print(f"✗ Branch '{branch}' not found on {compare_branch.split('/', 1)[0]}.") @@ -8493,11 +8493,11 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False): # report presence-only (mirrors the banner's _check_via_local_git). head_sha = subprocess.run( git_cmd + ["rev-parse", "HEAD"], - cwd=PROJECT_ROOT, capture_output=True, text=True, + cwd=PROJECT_ROOT, capture_output=True, text=True, encoding='utf-8', errors='replace', ).stdout.strip() target_sha = subprocess.run( git_cmd + ["rev-parse", compare_branch], - cwd=PROJECT_ROOT, capture_output=True, text=True, + cwd=PROJECT_ROOT, capture_output=True, text=True, encoding='utf-8', errors='replace', ).stdout.strip() if head_sha and target_sha and head_sha == target_sha: print("✓ Already up to date.") @@ -8512,7 +8512,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False): git_cmd + ["rev-list", f"HEAD..{compare_branch}", "--count"], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=True, ) behind = int(rev_result.stdout.strip()) @@ -8573,7 +8573,7 @@ def _ensure_fhs_path_guard() -> None: "command -v hermes", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) except (FileNotFoundError, subprocess.TimeoutExpired): @@ -9028,7 +9028,7 @@ def _discard_lockfile_churn(git_cmd, repo_root): git_cmd + ["diff", "--name-only"], cwd=repo_root, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if diff.returncode != 0: return @@ -9049,7 +9049,7 @@ def _discard_lockfile_churn(git_cmd, repo_root): git_cmd + ["checkout", "--", *dirty], cwd=repo_root, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=False, ) print(f"→ Discarded npm lockfile churn ({len(dirty)} file(s))") @@ -9315,7 +9315,7 @@ def _cmd_update_impl(args, gateway_mode: bool): git_cmd + ["fetch", "origin", branch], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if fetch_result.returncode != 0: stderr = fetch_result.stderr.strip() @@ -9339,7 +9339,7 @@ def _cmd_update_impl(args, gateway_mode: bool): git_cmd + ["rev-parse", "--abbrev-ref", "HEAD"], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=True, ) current_branch = result.stdout.strip() @@ -9362,7 +9362,7 @@ def _cmd_update_impl(args, gateway_mode: bool): git_cmd + ["checkout", branch], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if checkout_result.returncode != 0: # Local checkout doesn't have this branch yet. Try to set @@ -9373,7 +9373,7 @@ def _cmd_update_impl(args, gateway_mode: bool): git_cmd + ["checkout", "-B", branch, f"origin/{branch}"], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if track_result.returncode != 0: # Restore the user's prior branch + stash before bailing @@ -9404,7 +9404,7 @@ def _cmd_update_impl(args, gateway_mode: bool): git_cmd + ["rev-list", f"HEAD..origin/{branch}", "--count"], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=True, ) commit_count = int(result.stdout.strip()) @@ -9430,7 +9430,7 @@ def _cmd_update_impl(args, gateway_mode: bool): git_cmd + ["checkout", current_branch], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=False, ) print("✓ Already up to date!") @@ -9469,7 +9469,7 @@ def _cmd_update_impl(args, gateway_mode: bool): git_cmd + ["pull", "--ff-only", "origin", branch], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if pull_result.returncode != 0: # ff-only failed — local and remote have diverged (e.g. upstream @@ -9482,7 +9482,7 @@ def _cmd_update_impl(args, gateway_mode: bool): git_cmd + ["reset", "--hard", f"origin/{branch}"], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if reset_result.returncode != 0: print(f"✗ Failed to reset to origin/{branch}.") @@ -9518,7 +9518,7 @@ def _cmd_update_impl(args, gateway_mode: bool): git_cmd + ["reset", "--hard", pre_pull_sha], cwd=PROJECT_ROOT, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if rollback_result.returncode == 0: print(" ✓ Rollback complete — your install is unchanged.") @@ -10052,7 +10052,7 @@ def _wait_for_service_active( _verify = subprocess.run( scope_cmd_ + ["is-active", svc_name_], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) if _verify.stdout.strip() == "active": @@ -10086,7 +10086,7 @@ def _service_restart_sec( "--value", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) except (FileNotFoundError, subprocess.TimeoutExpired): @@ -10233,7 +10233,7 @@ def _resolve_manage_cmd(scope_: str, scope_cmd_: list, svc_name_: str): "--no-pager", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) for line in result.stdout.strip().splitlines(): @@ -10250,7 +10250,7 @@ def _resolve_manage_cmd(scope_: str, scope_cmd_: list, svc_name_: str): check = subprocess.run( scope_cmd + ["is-active", svc_name], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) if check.stdout.strip() != "active": @@ -10283,7 +10283,7 @@ def _resolve_manage_cmd(scope_: str, scope_cmd_: list, svc_name_: str): "--value", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) _main_pid = int((_show.stdout or "").strip() or 0) @@ -10336,13 +10336,13 @@ def _resolve_manage_cmd(scope_: str, scope_cmd_: list, svc_name_: str): subprocess.run( _manage_cmd + ["reset-failed", svc_name], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) subprocess.run( _manage_cmd + ["start", svc_name], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=15, ) # Short poll: the gateway should be up @@ -10425,13 +10425,13 @@ def _resolve_manage_cmd(scope_: str, scope_cmd_: list, svc_name_: str): subprocess.run( _manage_cmd + ["reset-failed", svc_name], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) restart = subprocess.run( _manage_cmd + ["restart", svc_name], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=15, ) if restart.returncode == 0: @@ -10457,13 +10457,13 @@ def _resolve_manage_cmd(scope_: str, scope_cmd_: list, svc_name_: str): subprocess.run( _manage_cmd + ["reset-failed", svc_name], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) subprocess.run( _manage_cmd + ["restart", svc_name], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=15, ) if _wait_for_service_active( @@ -10513,7 +10513,7 @@ def _resolve_manage_cmd(scope_: str, scope_cmd_: list, svc_name_: str): check = subprocess.run( ["launchctl", "list", get_launchd_label()], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) if check.returncode == 0: @@ -12997,7 +12997,7 @@ def cmd_computer_use(args): from hermes_cli.tools_config import _cua_driver_env version = subprocess.run( [path, "--version"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, env=_cua_driver_env(), ).stdout.strip() except Exception: diff --git a/hermes_cli/managed_uv.py b/hermes_cli/managed_uv.py index 78c8f469003a..c66494864ced 100644 --- a/hermes_cli/managed_uv.py +++ b/hermes_cli/managed_uv.py @@ -115,7 +115,7 @@ def _ensure_uv_path() -> Optional[str]: version = subprocess.run( [result, "--version"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=False, ).stdout.strip() print(f" ✓ Managed uv installed ({version})") @@ -170,14 +170,14 @@ def update_managed_uv() -> Optional[str]: result = subprocess.run( [existing, "self", "update"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=False, ) if result.returncode == 0: version = subprocess.run( [existing, "--version"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', check=False, ).stdout.strip() print(f" ✓ Managed uv updated ({version})") diff --git a/hermes_cli/plugins_cmd.py b/hermes_cli/plugins_cmd.py index 0a5aa8c0fd03..2b27ae3695b8 100644 --- a/hermes_cli/plugins_cmd.py +++ b/hermes_cli/plugins_cmd.py @@ -471,7 +471,7 @@ def _install_plugin_core(identifier: str, *, force: bool) -> tuple[Path, dict, s result = subprocess.run( [git_exe, "clone", "--depth", "1", git_url, str(tmp_clone)], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=60, ) except FileNotFoundError as e: @@ -1767,7 +1767,7 @@ def _git_pull_plugin_dir(target: Path) -> tuple[bool, str]: result = subprocess.run( [git_exe, "pull", "--ff-only"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=60, cwd=str(target), ) diff --git a/hermes_cli/profiles.py b/hermes_cli/profiles.py index 7f7f3b262e5a..47c37975a403 100644 --- a/hermes_cli/profiles.py +++ b/hermes_cli/profiles.py @@ -387,7 +387,7 @@ def check_alias_collision(name: str) -> Optional[str]: try: result = subprocess.run( ["where" if is_windows else "which", canon], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) if result.returncode == 0: existing_path = result.stdout.strip().splitlines()[0] @@ -1186,7 +1186,7 @@ def seed_profile_skills(profile_dir: Path, quiet: bool = False) -> Optional[dict "r = sync_skills(quiet=True); print(json.dumps(r))"], env={**os.environ, "HERMES_HOME": str(profile_dir)}, cwd=str(project_root), - capture_output=True, text=True, timeout=60, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=60, ) if result.returncode == 0 and result.stdout.strip(): return json.loads(result.stdout.strip()) diff --git a/hermes_cli/secrets_cli.py b/hermes_cli/secrets_cli.py index cc31cb331609..4a7f75bd1f19 100644 --- a/hermes_cli/secrets_cli.py +++ b/hermes_cli/secrets_cli.py @@ -452,7 +452,7 @@ def _bws_version(binary: Path) -> str: res = subprocess.run( [str(binary), "--version"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) if res.returncode == 0: @@ -476,7 +476,7 @@ def _list_projects( [str(binary), "project", "list", "--output", "json"], env=env, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=15, ) except (OSError, subprocess.TimeoutExpired) as exc: diff --git a/hermes_cli/service_manager.py b/hermes_cli/service_manager.py index 3cfa67309876..198166f47355 100644 --- a/hermes_cli/service_manager.py +++ b/hermes_cli/service_manager.py @@ -838,7 +838,7 @@ def _run_svc(self, action_flag: str, action_label: str, name: str) -> None: try: subprocess.run( [f"{_S6_BIN_DIR}/s6-svc", action_flag, str(service_dir)], - check=True, capture_output=True, text=True, timeout=5, + check=True, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) except subprocess.CalledProcessError as exc: raise S6CommandError( @@ -873,7 +873,7 @@ def _supervised_pid(self, name: str) -> int | None: try: result = subprocess.run( [f"{_S6_BIN_DIR}/s6-svstat", str(self.scandir / name)], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) except (OSError, subprocess.SubprocessError): return None @@ -926,7 +926,7 @@ def is_running(self, name: str) -> bool: import subprocess result = subprocess.run( [f"{_S6_BIN_DIR}/s6-svstat", str(self.scandir / name)], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) return result.returncode == 0 and "up " in result.stdout @@ -1029,7 +1029,7 @@ def register_profile_gateway( # Trigger rescan so s6-svscan picks up the new service. result = subprocess.run( [f"{_S6_BIN_DIR}/s6-svscanctl", "-a", str(self.scandir)], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) if result.returncode != 0: # Clean up: rescan failed, leave the directory in place would @@ -1066,13 +1066,13 @@ def unregister_profile_gateway(self, profile: str) -> None: # Stop the service (best effort — service may already be down). subprocess.run( [f"{_S6_BIN_DIR}/s6-svc", "-d", str(svc_dir)], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, check=False, ) # Wait for it to actually go down (up to 10s). subprocess.run( [f"{_S6_BIN_DIR}/s6-svwait", "-D", "-t", "10000", str(svc_dir)], - capture_output=True, text=True, timeout=15, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=15, check=False, ) @@ -1084,7 +1084,7 @@ def unregister_profile_gateway(self, profile: str) -> None: # files inside the slot, so the upcoming rmtree doesn't race. subprocess.run( [f"{_S6_BIN_DIR}/s6-svscanctl", "-an", str(self.scandir)], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, check=False, ) # Give s6-svscan a moment to reap. There's no synchronous diff --git a/hermes_cli/setup.py b/hermes_cli/setup.py index a178c0b5ca9e..18489c196952 100644 --- a/hermes_cli/setup.py +++ b/hermes_cli/setup.py @@ -1310,13 +1310,13 @@ def setup_terminal_backend(config: dict): "modal", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) else: result = subprocess.run( [sys.executable, "-m", "pip", "install", "modal"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if result.returncode == 0: print_success("modal SDK installed") @@ -1363,13 +1363,13 @@ def setup_terminal_backend(config: dict): result = subprocess.run( [uv_bin, "pip", "install", "--python", sys.executable, "daytona"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) else: result = subprocess.run( [sys.executable, "-m", "pip", "install", "daytona"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if result.returncode == 0: print_success("daytona SDK installed") @@ -1440,7 +1440,7 @@ def setup_terminal_backend(config: dict): ssh_cmd.extend(["-p", port]) ssh_cmd.append(f"{user}@{host}" if user else host) ssh_cmd.append("echo ok") - result = subprocess.run(ssh_cmd, capture_output=True, text=True, timeout=10) + result = subprocess.run(ssh_cmd, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10) if result.returncode == 0: print_success(" SSH connection successful!") else: diff --git a/hermes_cli/uninstall.py b/hermes_cli/uninstall.py index 9b53500734be..3b7c0259a585 100644 --- a/hermes_cli/uninstall.py +++ b/hermes_cli/uninstall.py @@ -465,7 +465,7 @@ def _uninstall_profile(profile) -> None: subprocess.run( hermes_invocation + ["gateway", subcmd], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=60, check=False, ) diff --git a/hermes_cli/web_git.py b/hermes_cli/web_git.py index 292f6c811443..91c7bf2490b7 100644 --- a/hermes_cli/web_git.py +++ b/hermes_cli/web_git.py @@ -37,7 +37,7 @@ def _git(cwd: str, args: list[str], *, timeout: int = _GIT_TIMEOUT) -> tuple[int ["git", *args], cwd=cwd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=timeout, ) except (OSError, subprocess.SubprocessError): @@ -421,7 +421,7 @@ def _gh(cwd: str, args: list[str]) -> tuple[bool, str]: return False, "" try: proc = subprocess.run( - ["gh", *args], cwd=cwd, capture_output=True, text=True, timeout=_GH_TIMEOUT + ["gh", *args], cwd=cwd, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=_GH_TIMEOUT ) except (OSError, subprocess.SubprocessError): return False, "" diff --git a/hermes_cli/web_server.py b/hermes_cli/web_server.py index 09dacecb9f98..7ed8ce4dd6c9 100644 --- a/hermes_cli/web_server.py +++ b/hermes_cli/web_server.py @@ -2956,7 +2956,7 @@ def _recent_upstream_commits(n: int = 20) -> List[Dict[str, Any]]: f"-n{int(n)}", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, ) if out.returncode != 0: diff --git a/hermes_cli/webhook.py b/hermes_cli/webhook.py index 754701287073..9587ac72c35d 100644 --- a/hermes_cli/webhook.py +++ b/hermes_cli/webhook.py @@ -59,7 +59,7 @@ def _save_subscriptions(subs: Dict[str, dict]) -> None: prefix=f".{path.name}.", suffix=".tmp", dir=path.parent, - text=True, + text=True, encoding='utf-8', errors='replace', ) tmp_path = Path(tmp_name) try: diff --git a/optional-skills/creative/kanban-video-orchestrator/scripts/monitor.py b/optional-skills/creative/kanban-video-orchestrator/scripts/monitor.py index fb6fddc5bfe8..dc3c11845b7a 100755 --- a/optional-skills/creative/kanban-video-orchestrator/scripts/monitor.py +++ b/optional-skills/creative/kanban-video-orchestrator/scripts/monitor.py @@ -36,7 +36,7 @@ def kanban_list(tenant: str) -> list[dict]: try: out = subprocess.run( ["hermes", "kanban", "list", "--tenant", tenant, "--json"], - capture_output=True, text=True, check=False, + capture_output=True, text=True, encoding='utf-8', errors='replace', check=False, ) if out.returncode == 0 and out.stdout.strip().startswith("["): return json.loads(out.stdout) @@ -45,7 +45,7 @@ def kanban_list(tenant: str) -> list[dict]: # Fallback: textual parse of `hermes kanban list` out = subprocess.run( ["hermes", "kanban", "list", "--tenant", tenant], - capture_output=True, text=True, check=False, + capture_output=True, text=True, encoding='utf-8', errors='replace', check=False, ) rows = [] for line in out.stdout.splitlines(): @@ -69,7 +69,7 @@ def kanban_list(tenant: str) -> list[dict]: def kanban_show(task_id: str) -> dict | None: out = subprocess.run( ["hermes", "kanban", "show", task_id, "--json"], - capture_output=True, text=True, check=False, + capture_output=True, text=True, encoding='utf-8', errors='replace', check=False, ) if out.returncode != 0: return None diff --git a/plugins/google_meet/audio_bridge.py b/plugins/google_meet/audio_bridge.py index 9f13aebb4c6c..4028a83cf766 100644 --- a/plugins/google_meet/audio_bridge.py +++ b/plugins/google_meet/audio_bridge.py @@ -111,7 +111,7 @@ def _setup_linux(self) -> dict: ], check=True, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', stdin=subprocess.DEVNULL, ) except FileNotFoundError as exc: @@ -136,7 +136,7 @@ def _setup_linux(self) -> dict: ], check=True, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', stdin=subprocess.DEVNULL, ) except subprocess.CalledProcessError as exc: @@ -172,7 +172,7 @@ def _setup_darwin(self) -> dict: try: out = subprocess.check_output( ["system_profiler", "SPAudioDataType"], - text=True, + text=True, encoding='utf-8', errors='replace', stderr=subprocess.STDOUT, ) except FileNotFoundError as exc: diff --git a/plugins/google_meet/cli.py b/plugins/google_meet/cli.py index e721c037c814..73e47086fada 100644 --- a/plugins/google_meet/cli.py +++ b/plugins/google_meet/cli.py @@ -294,7 +294,7 @@ def _confirm(prompt: str) -> bool: elif system == "Darwin": have_bh = False try: - out = _sp.check_output(["system_profiler", "SPAudioDataType"], text=True) + out = _sp.check_output(["system_profiler", "SPAudioDataType"], text=True, encoding='utf-8', errors='replace') have_bh = "BlackHole" in out except Exception: pass diff --git a/plugins/google_meet/meet_bot.py b/plugins/google_meet/meet_bot.py index 211e08d4c698..0396d039490a 100644 --- a/plugins/google_meet/meet_bot.py +++ b/plugins/google_meet/meet_bot.py @@ -425,7 +425,7 @@ def _mac_audio_device_index(device_name: str) -> str: out = _sp.run( ["ffmpeg", "-f", "avfoundation", "-list_devices", "true", "-i", ""], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) except Exception: diff --git a/plugins/memory/byterover/__init__.py b/plugins/memory/byterover/__init__.py index 5161bacf4130..dd5cf3b2b883 100644 --- a/plugins/memory/byterover/__init__.py +++ b/plugins/memory/byterover/__init__.py @@ -140,7 +140,7 @@ def _run_brv(args: List[str], timeout: int = _QUERY_TIMEOUT, try: result = subprocess.run( - cmd, capture_output=True, text=True, + cmd, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=timeout, cwd=effective_cwd, env=env, stdin=subprocess.DEVNULL, ) diff --git a/plugins/memory/honcho/cli.py b/plugins/memory/honcho/cli.py index 8fc37448fd46..062e7ca391c7 100644 --- a/plugins/memory/honcho/cli.py +++ b/plugins/memory/honcho/cli.py @@ -520,7 +520,7 @@ def _ensure_sdk_installed() -> bool: result = subprocess.run( [sys.executable, "-m", "pip", "install", "honcho-ai>=2.0.1"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', stdin=subprocess.DEVNULL, ) if result.returncode == 0: diff --git a/plugins/memory/honcho/client.py b/plugins/memory/honcho/client.py index 271eea63e22b..b0cc09877dbd 100644 --- a/plugins/memory/honcho/client.py +++ b/plugins/memory/honcho/client.py @@ -627,7 +627,7 @@ def _git_repo_name(cwd: str) -> str | None: try: root = subprocess.run( ["git", "rev-parse", "--show-toplevel"], - capture_output=True, text=True, cwd=cwd, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', cwd=cwd, timeout=5, stdin=subprocess.DEVNULL, ) if root.returncode == 0: diff --git a/plugins/memory/mem0/_setup.py b/plugins/memory/mem0/_setup.py index 4fd9795b32d9..2d0cee80b9e9 100644 --- a/plugins/memory/mem0/_setup.py +++ b/plugins/memory/mem0/_setup.py @@ -407,7 +407,7 @@ def _ensure_pgvector(host: str = "localhost", port: int = 5432) -> dict | None: try: result = subprocess.run( ["docker", "inspect", _PGVECTOR_CONTAINER, "--format", "{{.State.Status}}"], - capture_output=True, text=True, timeout=10, stdin=subprocess.DEVNULL, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, stdin=subprocess.DEVNULL, ) if result.returncode == 0 and "exited" in result.stdout: print(f" Found stopped container '{_PGVECTOR_CONTAINER}', restarting...") diff --git a/plugins/platforms/matrix/adapter.py b/plugins/platforms/matrix/adapter.py index 7cc4cd8aec4b..7b64b010e3cc 100644 --- a/plugins/platforms/matrix/adapter.py +++ b/plugins/platforms/matrix/adapter.py @@ -4391,12 +4391,12 @@ def interactive_setup() -> None: if uv_bin: result = subprocess.run( [uv_bin, "pip", "install", "--python", _sys.executable, matrix_pkg], - capture_output=True, text=True, + capture_output=True, text=True, encoding='utf-8', errors='replace', ) else: result = subprocess.run( [_sys.executable, "-m", "pip", "install", matrix_pkg], - capture_output=True, text=True, + capture_output=True, text=True, encoding='utf-8', errors='replace', ) if result.returncode == 0: print_success(f"{matrix_pkg} installed") diff --git a/plugins/platforms/photon/adapter.py b/plugins/platforms/photon/adapter.py index d6e627f667bc..dbec58f9090c 100644 --- a/plugins/platforms/photon/adapter.py +++ b/plugins/platforms/photon/adapter.py @@ -751,7 +751,7 @@ def _find_listener_pids(port: int) -> List[int]: try: out = subprocess.run( # noqa: S603, S607 ["lsof", "-ti", f"tcp:{port}", "-sTCP:LISTEN"], - capture_output=True, text=True, timeout=5.0, check=False, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5.0, check=False, ) except (OSError, subprocess.TimeoutExpired): return [] @@ -763,7 +763,7 @@ def _pid_is_sidecar(pid: int) -> bool: try: out = subprocess.run( # noqa: S603, S607 ["ps", "-p", str(pid), "-o", "command="], - capture_output=True, text=True, timeout=5.0, check=False, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5.0, check=False, ) except (OSError, subprocess.TimeoutExpired): return False @@ -862,7 +862,7 @@ async def _start_sidecar(self) -> None: str(_SIDECAR_DIR), ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, check=False, ) diff --git a/plugins/platforms/whatsapp/adapter.py b/plugins/platforms/whatsapp/adapter.py index cebb129e3998..258b6af0171f 100644 --- a/plugins/platforms/whatsapp/adapter.py +++ b/plugins/platforms/whatsapp/adapter.py @@ -50,7 +50,7 @@ def _listener_pids_on_port(port: int) -> list: try: result = subprocess.run( ["lsof", "-ti", f"tcp:{port}", "-sTCP:LISTEN"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) for line in result.stdout.strip().splitlines(): try: @@ -65,7 +65,7 @@ def _listener_pids_on_port(port: int) -> list: try: result = subprocess.run( ["ss", "-ltnHp", f"sport = :{port}"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, ) for m in re.finditer(r"pid=(\d+)", result.stdout): pids.append(int(m.group(1))) @@ -83,7 +83,7 @@ def _kill_port_process(port: int) -> None: # Use netstat to find the PID bound to this port, then taskkill result = subprocess.run( ["netstat", "-ano", "-p", "TCP"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, creationflags=windows_hide_flags(), ) for line in result.stdout.splitlines(): @@ -218,7 +218,7 @@ def _terminate_bridge_process(proc, *, force: bool = False) -> None: result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, ) except FileNotFoundError: @@ -332,7 +332,7 @@ def check_whatsapp_requirements() -> bool: result = subprocess.run( [_node, "--version"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5 ) return result.returncode == 0 @@ -530,7 +530,7 @@ async def connect(self, *, is_reconnect: bool = False) -> bool: [_npm_bin, "install", "--silent"], cwd=str(bridge_dir), capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=npm_install_timeout, env=with_hermes_node_path(), ) diff --git a/plugins/web/exa/provider.py b/plugins/web/exa/provider.py index 0fea6fb5a8b7..b972a826d7be 100644 --- a/plugins/web/exa/provider.py +++ b/plugins/web/exa/provider.py @@ -166,7 +166,7 @@ def extract(self, urls: List[str], **kwargs: Any) -> List[Dict[str, Any]]: ] logger.info("Exa extract: %d URL(s)", len(urls)) - response = _get_exa_client().get_contents(urls, text=True) + response = _get_exa_client().get_contents(urls, text=True, encoding='utf-8', errors='replace') results: List[Dict[str, Any]] = [] for result in response.results or []: diff --git a/scripts/check-windows-footguns.py b/scripts/check-windows-footguns.py index 7ae7ca50c4e7..b1c667cc74e5 100644 --- a/scripts/check-windows-footguns.py +++ b/scripts/check-windows-footguns.py @@ -492,7 +492,7 @@ def get_staged_files() -> list[Path]: ["git", "diff", "--cached", "--name-only", "--diff-filter=ACMR"], cwd=REPO_ROOT, stderr=subprocess.DEVNULL, - text=True, + text=True, encoding='utf-8', errors='replace', ) except (subprocess.CalledProcessError, FileNotFoundError): return [] @@ -506,7 +506,7 @@ def get_diff_files(ref: str) -> list[Path]: ["git", "diff", f"{ref}...HEAD", "--name-only", "--diff-filter=ACMR"], cwd=REPO_ROOT, stderr=subprocess.DEVNULL, - text=True, + text=True, encoding='utf-8', errors='replace', ) except (subprocess.CalledProcessError, FileNotFoundError): return [] diff --git a/scripts/contributor_audit.py b/scripts/contributor_audit.py index 2a6e5901c80b..f68d6cce0467 100644 --- a/scripts/contributor_audit.py +++ b/scripts/contributor_audit.py @@ -81,7 +81,7 @@ def git(*args, cwd=None): result = subprocess.run( ["git"] + list(args), capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', cwd=cwd or str(REPO_ROOT), ) if result.returncode != 0: @@ -106,7 +106,7 @@ def gh_pr_list(): "--limit", "300", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=60, ) if result.returncode != 0: diff --git a/scripts/profile-tui.py b/scripts/profile-tui.py index 788fd464bc9b..a85573a6f762 100755 --- a/scripts/profile-tui.py +++ b/scripts/profile-tui.py @@ -572,7 +572,7 @@ def collect_mtimes() -> dict[str, float]: ["npm", "run", "build"], cwd=tui_dir, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if result.returncode != 0: print("✗ build failed:") diff --git a/scripts/release.py b/scripts/release.py index c2de7f6701db..25ab8d451b07 100755 --- a/scripts/release.py +++ b/scripts/release.py @@ -1743,7 +1743,7 @@ def git(*args, cwd=None): """Run a git command and return stdout.""" result = subprocess.run( ["git"] + list(args), - capture_output=True, text=True, + capture_output=True, text=True, encoding='utf-8', errors='replace', cwd=cwd or str(REPO_ROOT), ) if result.returncode != 0: @@ -1757,7 +1757,7 @@ def git_result(*args, cwd=None): return subprocess.run( ["git"] + list(args), capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', cwd=cwd or str(REPO_ROOT), ) @@ -1896,7 +1896,7 @@ def build_release_artifacts(semver: str) -> list[Path]: cmd, cwd=str(REPO_ROOT), capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', ) if result.returncode != 0: print(" ⚠ Could not build Python release artifacts.") @@ -2312,7 +2312,7 @@ def main(): if gh_bin: result = subprocess.run( gh_cmd, - capture_output=True, text=True, + capture_output=True, text=True, encoding='utf-8', errors='replace', cwd=str(REPO_ROOT), ) else: diff --git a/skills/creative/comfyui/scripts/auto_fix_deps.py b/skills/creative/comfyui/scripts/auto_fix_deps.py index 788bf8e9e3bf..79689972b06a 100755 --- a/skills/creative/comfyui/scripts/auto_fix_deps.py +++ b/skills/creative/comfyui/scripts/auto_fix_deps.py @@ -51,7 +51,7 @@ def run_cmd(cmd: list[str], *, dry_run: bool = False) -> tuple[int, str]: if dry_run: return 0, "[dry-run]" log(f"$ {' '.join(cmd)}") - proc = subprocess.run(cmd, capture_output=True, text=True, check=False) + proc = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8', errors='replace', check=False) out = (proc.stdout or "") + (proc.stderr or "") return proc.returncode, out diff --git a/skills/creative/comfyui/scripts/hardware_check.py b/skills/creative/comfyui/scripts/hardware_check.py index 083d018acc64..a89b66dc6851 100755 --- a/skills/creative/comfyui/scripts/hardware_check.py +++ b/skills/creative/comfyui/scripts/hardware_check.py @@ -54,7 +54,7 @@ def _run(cmd: list[str], timeout: int = 8) -> str: try: out = subprocess.run( - cmd, capture_output=True, text=True, timeout=timeout, check=False + cmd, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=timeout, check=False ) return (out.stdout or "") + (out.stderr or "") except (FileNotFoundError, subprocess.TimeoutExpired, OSError): diff --git a/skills/productivity/google-workspace/scripts/google_api.py b/skills/productivity/google-workspace/scripts/google_api.py index 27855a5158eb..a4b0451b6ae4 100644 --- a/skills/productivity/google-workspace/scripts/google_api.py +++ b/skills/productivity/google-workspace/scripts/google_api.py @@ -108,7 +108,7 @@ def _run_gws(parts: list[str], *, params: dict | None = None, body: dict | None result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', env=_gws_env(), ) if result.returncode != 0: diff --git a/tools/browser_tool.py b/tools/browser_tool.py index ec587cc16978..5890132a7e4a 100644 --- a/tools/browser_tool.py +++ b/tools/browser_tool.py @@ -4241,7 +4241,7 @@ def _maybe_autoinstall_chromium() -> bool: proc = subprocess.run( install_cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=600, env=_build_browser_env(), ) diff --git a/tools/checkpoint_manager.py b/tools/checkpoint_manager.py index f256ec7c3d30..1f56d4b81d4a 100644 --- a/tools/checkpoint_manager.py +++ b/tools/checkpoint_manager.py @@ -327,7 +327,7 @@ def _run_git( result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=timeout, env=env, cwd=str(normalized_working_dir), @@ -453,7 +453,7 @@ def _init_store(store: Path, working_dir: str) -> Optional[str]: try: result = subprocess.run( ["git", "init", "--bare", str(store)], - capture_output=True, text=True, + capture_output=True, text=True, encoding='utf-8', errors='replace', env=init_env, timeout=_GIT_TIMEOUT, stdin=subprocess.DEVNULL, creationflags=windows_hide_flags(), diff --git a/tools/computer_use/cua_backend.py b/tools/computer_use/cua_backend.py index a8077204f97e..a564a027976f 100644 --- a/tools/computer_use/cua_backend.py +++ b/tools/computer_use/cua_backend.py @@ -162,7 +162,7 @@ def _resolve_mcp_invocation( try: proc = subprocess.run( [driver_cmd, "manifest"], - capture_output=True, text=True, timeout=timeout, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=timeout, stdin=subprocess.DEVNULL, ) except Exception: @@ -233,7 +233,7 @@ def cua_driver_update_check(*, timeout: float = 8.0) -> Optional[Dict[str, Any]] try: proc = subprocess.run( [_CUA_DRIVER_CMD, "check-update", "--json"], - capture_output=True, text=True, timeout=timeout, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=timeout, # Some older drivers don't have the verb and fall through to a # stdin-reading mode rather than erroring — DEVNULL gives them EOF # so they exit fast instead of blocking until the timeout. diff --git a/tools/computer_use/doctor.py b/tools/computer_use/doctor.py index 1d557cd7d98f..618dc8caf47a 100644 --- a/tools/computer_use/doctor.py +++ b/tools/computer_use/doctor.py @@ -83,7 +83,7 @@ def _drive_health_report( stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", bufsize=1, diff --git a/tools/computer_use/permissions.py b/tools/computer_use/permissions.py index ab97b60ee662..a27b6b6d0753 100644 --- a/tools/computer_use/permissions.py +++ b/tools/computer_use/permissions.py @@ -60,7 +60,7 @@ def _run(binary: str, *args: str, timeout: float) -> subprocess.CompletedProcess return subprocess.run( [binary, *args], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=timeout, env=_child_env(), stdin=subprocess.DEVNULL, diff --git a/tools/env_probe.py b/tools/env_probe.py index 4b156b06edb1..219967c266fc 100644 --- a/tools/env_probe.py +++ b/tools/env_probe.py @@ -62,7 +62,7 @@ def _run(cmd: list[str], timeout: float = 3.0) -> tuple[int, str, str]: result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=timeout, check=False, stdin=subprocess.DEVNULL, diff --git a/tools/environments/docker.py b/tools/environments/docker.py index cd4a3fcd86ae..f707b6cb57c1 100644 --- a/tools/environments/docker.py +++ b/tools/environments/docker.py @@ -176,7 +176,7 @@ def reap_orphan_containers( try: listing = subprocess.run( [docker, "ps", "-a", *filters, "--format", "{{.ID}}"], - capture_output=True, text=True, timeout=15, check=False, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=15, check=False, stdin=subprocess.DEVNULL, ) except (subprocess.TimeoutExpired, OSError) as e: @@ -210,7 +210,7 @@ def reap_orphan_containers( try: result = subprocess.run( [docker, "rm", "-f", cid], - capture_output=True, text=True, timeout=30, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=30, stdin=subprocess.DEVNULL, ) if result.returncode == 0: @@ -240,7 +240,7 @@ def _container_finished_at(docker_exe: str, container_id: str): try: result = subprocess.run( [docker_exe, "inspect", "--format", "{{.State.FinishedAt}}", container_id], - capture_output=True, text=True, timeout=10, check=False, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, check=False, stdin=subprocess.DEVNULL, ) except (subprocess.TimeoutExpired, OSError) as e: @@ -391,7 +391,7 @@ def _image_uses_init_entrypoint(docker_exe: str, image: str) -> bool: [docker_exe, "image", "inspect", image, "--format", "{{json .Config.Entrypoint}}"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=15, stdin=subprocess.DEVNULL, ) @@ -474,7 +474,7 @@ def _cgroup_limits_available(image: str) -> bool: "--cpus", "0.5", "--memory", "64m", "--pids-limit", "32", image, "sleep", "0"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=60, stdin=subprocess.DEVNULL, ) @@ -517,7 +517,7 @@ def _ensure_docker_available() -> None: result = subprocess.run( [docker_exe, "version"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, stdin=subprocess.DEVNULL, ) @@ -902,7 +902,7 @@ def __init__( subprocess.run( [self._docker_exe, "start", container_id], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, check=True, stdin=subprocess.DEVNULL, @@ -941,7 +941,7 @@ def __init__( result = subprocess.run( run_cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=120, # image pull may take a while check=True, stdin=subprocess.DEVNULL, @@ -1071,7 +1071,7 @@ def _recreate_container(self) -> bool: try: subprocess.run( [self._docker_exe, "start", cid], - capture_output=True, text=True, timeout=30, check=True, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=30, check=True, stdin=subprocess.DEVNULL, ) self._container_id = cid @@ -1102,7 +1102,7 @@ def _recreate_container(self) -> bool: "sleep", "infinity", ] result = subprocess.run( - run_cmd, capture_output=True, text=True, timeout=120, check=True, + run_cmd, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=120, check=True, stdin=subprocess.DEVNULL, ) self._container_id = result.stdout.strip() @@ -1157,7 +1157,7 @@ def _storage_opt_supported() -> bool: docker = find_docker() or "docker" result = subprocess.run( [docker, "info", "--format", "{{.Driver}}"], - capture_output=True, text=True, timeout=10, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, stdin=subprocess.DEVNULL, ) driver = result.stdout.strip().lower() @@ -1168,7 +1168,7 @@ def _storage_opt_supported() -> bool: # Probe by attempting a dry-ish run — the fastest reliable check. probe = subprocess.run( [docker, "create", "--storage-opt", "size=1m", "hello-world"], - capture_output=True, text=True, timeout=15, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=15, stdin=subprocess.DEVNULL, ) if probe.returncode == 0: @@ -1209,7 +1209,7 @@ def _find_reusable_container(self, task_label: str, profile_label: str) -> Optio "--format", "{{.ID}}\t{{.State}}", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, check=False, stdin=subprocess.DEVNULL, diff --git a/tools/environments/local.py b/tools/environments/local.py index 50a2522a5a22..46a2530e49e0 100644 --- a/tools/environments/local.py +++ b/tools/environments/local.py @@ -836,7 +836,7 @@ def _run_bash(self, cmd_string: str, *, login: bool = False, proc = subprocess.Popen( args, - text=True, + text=True, encoding='utf-8', errors='replace', env=run_env, encoding="utf-8", errors="replace", diff --git a/tools/environments/singularity.py b/tools/environments/singularity.py index 666d908b2568..169937096bd3 100644 --- a/tools/environments/singularity.py +++ b/tools/environments/singularity.py @@ -45,7 +45,7 @@ def _ensure_singularity_available() -> str: exe = _find_singularity_executable() try: result = subprocess.run( - [exe, "version"], capture_output=True, text=True, timeout=10, + [exe, "version"], capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=10, stdin=subprocess.DEVNULL, ) except FileNotFoundError: @@ -136,7 +136,7 @@ def _get_or_build_sif(image: str, executable: str = "apptainer") -> str: try: result = subprocess.run( [executable, "build", str(sif_path), image], - capture_output=True, text=True, timeout=600, env=env, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=600, env=env, stdin=subprocess.DEVNULL, ) if result.returncode != 0: @@ -220,7 +220,7 @@ def _start_instance(self): cmd.extend([str(self.image), self.instance_id]) try: - result = subprocess.run(cmd, capture_output=True, text=True, timeout=120, stdin=subprocess.DEVNULL) + result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=120, stdin=subprocess.DEVNULL) if result.returncode != 0: raise RuntimeError(f"Failed to start instance: {result.stderr}") self._instance_started = True @@ -251,7 +251,7 @@ def cleanup(self): try: subprocess.run( [self.executable, "instance", "stop", self.instance_id], - capture_output=True, text=True, timeout=30, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=30, stdin=subprocess.DEVNULL, ) logger.info("Singularity instance %s stopped", self.instance_id) diff --git a/tools/environments/ssh.py b/tools/environments/ssh.py index 1a06ad9b82c0..f3e4d5561df7 100644 --- a/tools/environments/ssh.py +++ b/tools/environments/ssh.py @@ -104,7 +104,7 @@ def _establish_connection(self): result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=15, stdin=subprocess.DEVNULL, ) @@ -122,7 +122,7 @@ def _detect_remote_home(self) -> str: result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, stdin=subprocess.DEVNULL, ) @@ -149,7 +149,7 @@ def _ensure_remote_dirs(self) -> None: subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, stdin=subprocess.DEVNULL, ) @@ -164,7 +164,7 @@ def _scp_upload(self, host_path: str, remote_path: str) -> None: subprocess.run( mkdir_cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, stdin=subprocess.DEVNULL, ) @@ -178,7 +178,7 @@ def _scp_upload(self, host_path: str, remote_path: str) -> None: result = subprocess.run( scp_cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, stdin=subprocess.DEVNULL, ) @@ -207,7 +207,7 @@ def _ssh_bulk_upload(self, files: list[tuple[str, str]]) -> None: result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, stdin=subprocess.DEVNULL, ) @@ -325,7 +325,7 @@ def _ssh_delete(self, remote_paths: list[str]) -> None: result = subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, stdin=subprocess.DEVNULL, ) diff --git a/tools/lazy_deps.py b/tools/lazy_deps.py index 0bf3424c0941..5c53b7c6bcd1 100644 --- a/tools/lazy_deps.py +++ b/tools/lazy_deps.py @@ -632,7 +632,7 @@ def _venv_pip_install(specs: tuple[str, ...], *, timeout: int = 300) -> _Install try: r = subprocess.run( [uv_bin, "pip", "install", *target_args, *constraint_args, *specs], - capture_output=True, text=True, timeout=timeout, env=uv_env, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=timeout, env=uv_env, stdin=subprocess.DEVNULL, ) if r.returncode == 0: @@ -648,7 +648,7 @@ def _venv_pip_install(specs: tuple[str, ...], *, timeout: int = 300) -> _Install try: probe = subprocess.run( pip_cmd + ["--version"], - capture_output=True, text=True, timeout=15, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=15, stdin=subprocess.DEVNULL, ) if probe.returncode != 0: @@ -657,7 +657,7 @@ def _venv_pip_install(specs: tuple[str, ...], *, timeout: int = 300) -> _Install try: subprocess.run( [sys.executable, "-m", "ensurepip", "--upgrade", "--default-pip"], - capture_output=True, text=True, timeout=120, check=True, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=120, check=True, stdin=subprocess.DEVNULL, ) except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e: @@ -667,7 +667,7 @@ def _venv_pip_install(specs: tuple[str, ...], *, timeout: int = 300) -> _Install try: r = subprocess.run( pip_cmd + ["install", *target_args, *constraint_args, *specs], - capture_output=True, text=True, timeout=timeout, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=timeout, stdin=subprocess.DEVNULL, ) if r.returncode == 0 and target is not None: diff --git a/tools/process_registry.py b/tools/process_registry.py index dd887374ec29..53e53dfd4b8d 100644 --- a/tools/process_registry.py +++ b/tools/process_registry.py @@ -593,7 +593,7 @@ def _terminate_host_pid(cls, pid: int, expected_start: Optional[int] = None) -> subprocess.run( ["taskkill", "/PID", str(pid), "/T", "/F"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, creationflags=windows_hide_flags(), stdin=subprocess.DEVNULL, @@ -763,7 +763,7 @@ def spawn_local( proc = subprocess.Popen( [user_shell, "-lic", f"set +m; {command}"], - text=True, + text=True, encoding='utf-8', errors='replace', cwd=session.cwd, env=bg_env, encoding="utf-8", diff --git a/tools/skills_hub.py b/tools/skills_hub.py index 0827545ae722..4064065064f3 100644 --- a/tools/skills_hub.py +++ b/tools/skills_hub.py @@ -301,7 +301,7 @@ def _try_gh_cli(self) -> Optional[str]: try: result = subprocess.run( ["gh", "auth", "token"], - capture_output=True, text=True, timeout=5, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=5, stdin=subprocess.DEVNULL, creationflags=windows_hide_flags(), ) diff --git a/tools/tirith_security.py b/tools/tirith_security.py index 93509604131d..a07d3f817df3 100644 --- a/tools/tirith_security.py +++ b/tools/tirith_security.py @@ -315,7 +315,7 @@ def _verify_cosign(checksums_path: str, sig_path: str, cert_path: str) -> bool | "--certificate-oidc-issuer", _COSIGN_ISSUER, checksums_path], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=15, stdin=subprocess.DEVNULL, ) @@ -776,7 +776,7 @@ def check_command_security(command: str) -> dict: [tirith_path, "check", "--json", "--non-interactive", "--shell", "posix", "--", command], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=timeout, stdin=subprocess.DEVNULL, ) diff --git a/tools/transcription_tools.py b/tools/transcription_tools.py index 49f8cbaca226..20cf0d67f448 100644 --- a/tools/transcription_tools.py +++ b/tools/transcription_tools.py @@ -1188,7 +1188,7 @@ def _prepare_local_audio(file_path: str, work_dir: str) -> tuple[Optional[str], command = [ffmpeg, "-y", "-i", file_path, converted_path] try: - subprocess.run(command, check=True, capture_output=True, text=True, timeout=300, stdin=subprocess.DEVNULL, creationflags=windows_hide_flags()) + subprocess.run(command, check=True, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=300, stdin=subprocess.DEVNULL, creationflags=windows_hide_flags()) return converted_path, None except subprocess.TimeoutExpired: logger.error("ffmpeg conversion timed out for %s", file_path) @@ -1234,9 +1234,9 @@ def _transcribe_local_command(file_path: str, model_name: str) -> Dict[str, Any] # User-provided templates (env var) may contain shell syntax; auto-detected commands are safe for list mode. use_shell = bool(os.getenv(LOCAL_STT_COMMAND_ENV, "").strip()) if use_shell: - subprocess.run(command, shell=True, check=True, capture_output=True, text=True, timeout=300, stdin=subprocess.DEVNULL, creationflags=windows_hide_flags()) + subprocess.run(command, shell=True, check=True, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=300, stdin=subprocess.DEVNULL, creationflags=windows_hide_flags()) else: - subprocess.run(shlex.split(command), check=True, capture_output=True, text=True, timeout=300, stdin=subprocess.DEVNULL, creationflags=windows_hide_flags()) + subprocess.run(shlex.split(command), check=True, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=300, stdin=subprocess.DEVNULL, creationflags=windows_hide_flags()) txt_files = sorted(Path(output_dir).glob("*.txt")) diff --git a/tools/tts_tool.py b/tools/tts_tool.py index b71ebfa82750..2f2bc35e6c8c 100644 --- a/tools/tts_tool.py +++ b/tools/tts_tool.py @@ -1861,7 +1861,7 @@ def _generate_neutts(text: str, output_path: str, tts_config: Dict[str, Any]) -> "--device", device, ] - result = subprocess.run(cmd, capture_output=True, text=True, timeout=120, stdin=subprocess.DEVNULL) + result = subprocess.run(cmd, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=120, stdin=subprocess.DEVNULL) if result.returncode != 0: stderr = result.stderr.strip() # Filter out the "OK:" line from stderr @@ -1943,7 +1943,7 @@ def _resolve_piper_voice_path(voice: str, download_dir: Path) -> str: result = subprocess.run( [_sys.executable, "-m", "piper.download_voices", voice, "--download-dir", str(download_dir)], - capture_output=True, text=True, timeout=300, + capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=300, stdin=subprocess.DEVNULL, ) except subprocess.TimeoutExpired as exc: diff --git a/tools/voice_mode.py b/tools/voice_mode.py index d000e29d59d9..5a5f60d0194b 100644 --- a/tools/voice_mode.py +++ b/tools/voice_mode.py @@ -72,7 +72,7 @@ def _termux_api_app_installed() -> bool: result = subprocess.run( ["pm", "list", "packages", "com.termux.api"], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=5, check=False, stdin=subprocess.DEVNULL, @@ -389,7 +389,7 @@ def start(self, on_silence_stop=None) -> None: "-c", str(CHANNELS), ] try: - subprocess.run(command, capture_output=True, text=True, timeout=15, check=True, stdin=subprocess.DEVNULL) + subprocess.run(command, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=15, check=True, stdin=subprocess.DEVNULL) except subprocess.CalledProcessError as e: details = (e.stderr or e.stdout or str(e)).strip() raise RuntimeError(f"Termux microphone start failed: {details}") from e @@ -406,7 +406,7 @@ def _stop_termux_recording(self) -> None: mic_cmd = _termux_microphone_command() if not mic_cmd: return - subprocess.run([mic_cmd, "-q"], capture_output=True, text=True, timeout=15, check=False, stdin=subprocess.DEVNULL) + subprocess.run([mic_cmd, "-q"], capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=15, check=False, stdin=subprocess.DEVNULL) def stop(self) -> Optional[str]: with self._lock: diff --git a/tui_gateway/git_probe.py b/tui_gateway/git_probe.py index 72582ebf5dc5..158e24e3654d 100644 --- a/tui_gateway/git_probe.py +++ b/tui_gateway/git_probe.py @@ -52,7 +52,7 @@ def run_git(cwd: str, *args: str) -> str: result = subprocess.run( ["git", "-C", cwd, *args], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="replace", timeout=_GIT_TIMEOUT, diff --git a/tui_gateway/server.py b/tui_gateway/server.py index 5ac8591f0a7b..abe295a28684 100644 --- a/tui_gateway/server.py +++ b/tui_gateway/server.py @@ -285,7 +285,7 @@ def __init__(self, session_key: str, model: str): stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - text=True, + text=True, encoding='utf-8', errors='replace', bufsize=1, cwd=os.getcwd(), # slash_worker runs the Hermes agent → needs provider credentials. @@ -9206,7 +9206,7 @@ def _(rid, params: dict) -> dict: try: res = subprocess.run( - argv, capture_output=True, text=True, timeout=120, stdin=subprocess.DEVNULL, + argv, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=120, stdin=subprocess.DEVNULL, creationflags=windows_hide_flags(), ) except subprocess.TimeoutExpired: @@ -11232,7 +11232,7 @@ def _(rid, params: dict) -> dict: r = subprocess.run( [sys.executable, "-m", "hermes_cli.main", *argv], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=min(int(params.get("timeout", 240)), 600), cwd=os.getcwd(), # cli.exec runs `python -m hermes_cli.main` (can drive the agent) → @@ -11297,7 +11297,7 @@ def _(rid, params: dict) -> dict: qc.get("command", ""), shell=True, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, stdin=subprocess.DEVNULL, ) @@ -13639,7 +13639,7 @@ def _(rid, params: dict) -> dict: return _err(rid, 5001, "shell.exec unavailable: approval safety module not importable") try: r = subprocess.run( - cmd, shell=True, capture_output=True, text=True, timeout=30, cwd=os.getcwd(), + cmd, shell=True, capture_output=True, text=True, encoding='utf-8', errors='replace', timeout=30, cwd=os.getcwd(), stdin=subprocess.DEVNULL, ) return _ok(