diff --git a/agent/anthropic_adapter.py b/agent/anthropic_adapter.py index 38431a8c1f..6d6be638fc 100644 --- a/agent/anthropic_adapter.py +++ b/agent/anthropic_adapter.py @@ -368,7 +368,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" @@ -914,7 +914,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/context_references.py b/agent/context_references.py index eea16ae52b..dea5fd4c3a 100644 --- a/agent/context_references.py +++ b/agent/context_references.py @@ -308,7 +308,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, @@ -534,7 +534,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 662facc2df..e4990fdf5e 100644 --- a/agent/copilot_acp_client.py +++ b/agent/copilot_acp_client.py @@ -512,7 +512,7 @@ class CopilotACPClient: 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/secret_sources/bitwarden.py b/agent/secret_sources/bitwarden.py index 8b047880be..2d993f396c 100644 --- a/agent/secret_sources/bitwarden.py +++ b/agent/secret_sources/bitwarden.py @@ -200,7 +200,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, ) @@ -684,7 +684,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 c1cec81df3..45772d0578 100644 --- a/agent/shell_hooks.py +++ b/agent/shell_hooks.py @@ -464,7 +464,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 bd0386d580..19c6eeb80f 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 7f5831f2a3..c23ff836ed 100644 --- a/agent/transports/codex_app_server.py +++ b/agent/transports/codex_app_server.py @@ -394,7 +394,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 f7fc28d7a5..9e8883275a 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/cron/scheduler.py b/cron/scheduler.py index c309c59c4e..40937cf597 100644 --- a/cron/scheduler.py +++ b/cron/scheduler.py @@ -2301,7 +2301,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=env, diff --git a/gateway/platforms/base.py b/gateway/platforms/base.py index 51c9f42405..e5a5da5776 100644 --- a/gateway/platforms/base.py +++ b/gateway/platforms/base.py @@ -250,7 +250,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 315f2e7cd3..3cf306e858 100644 --- a/gateway/platforms/webhook.py +++ b/gateway/platforms/webhook.py @@ -1259,7 +1259,7 @@ class WebhookAdapter(BasePlatformAdapter): content, ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=30, ) if result.returncode == 0: diff --git a/gateway/shutdown_forensics.py b/gateway/shutdown_forensics.py index 0a52ce14f0..34836cc6fb 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 93be87ed67..d2d3c15091 100644 --- a/gateway/status.py +++ b/gateway/status.py @@ -258,7 +258,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(), ) @@ -344,7 +344,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(): @@ -827,7 +827,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/claw.py b/hermes_cli/claw.py index 792e35c168..8f58d9520e 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 a6b6da7c06..78a9a43c3d 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 @@ _POWERSHELL_EXTRACT_IMAGE_SCRIPTS = ( 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 bad2250da0..d78bbbf5fa 100644 --- a/hermes_cli/commands.py +++ b/hermes_cli/commands.py @@ -1669,7 +1669,7 @@ class SlashCommandCompleter(Completer): 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 1216254fea..d193c7cf74 100644 --- a/hermes_cli/copilot_auth.py +++ b/hermes_cli/copilot_auth.py @@ -147,7 +147,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 7d585176ef..6ada680d27 100644 --- a/hermes_cli/doctor.py +++ b/hermes_cli/doctor.py @@ -1672,7 +1672,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: @@ -1836,7 +1836,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 139be0b592..9b6685ae5e 100644 --- a/hermes_cli/dump.py +++ b/hermes_cli/dump.py @@ -64,7 +64,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: @@ -99,7 +99,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 ac95fac06d..29cc802f86 100644 --- a/hermes_cli/gateway.py +++ b/hermes_cli/gateway.py @@ -118,7 +118,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(): @@ -130,7 +130,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()) @@ -148,7 +148,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: @@ -204,7 +204,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): @@ -421,7 +421,7 @@ def _scan_gateway_pids( "/FORMAT:LIST", ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', encoding="utf-8", errors="ignore", timeout=10, @@ -447,7 +447,7 @@ def _scan_gateway_pids( 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, @@ -504,7 +504,7 @@ def _scan_gateway_pids( 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: @@ -911,7 +911,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): @@ -938,7 +938,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): @@ -1031,7 +1031,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): @@ -1288,7 +1288,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: @@ -1646,7 +1646,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 @@ -1955,7 +1955,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, ) @@ -2432,7 +2432,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, ) @@ -3115,7 +3115,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, ) @@ -3498,7 +3498,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, ) @@ -3646,7 +3646,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 ""): @@ -4479,7 +4479,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 @@ -5650,7 +5650,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": @@ -5664,7 +5664,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": @@ -5678,7 +5678,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 a55200a15d..0a0b2041a6 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 9ab82318dc..69c9a4992f 100644 --- a/hermes_cli/kanban_db.py +++ b/hermes_cli/kanban_db.py @@ -5212,7 +5212,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( @@ -6138,7 +6138,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, ) @@ -6160,7 +6160,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, ) @@ -6174,7 +6174,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, ) @@ -6193,7 +6193,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, ) @@ -6212,7 +6212,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, ) @@ -6269,7 +6269,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, ) @@ -6765,7 +6765,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/managed_uv.py b/hermes_cli/managed_uv.py index 78c8f46900..c66494864c 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 f5c57bb88f..07f2f3198a 100644 --- a/hermes_cli/plugins_cmd.py +++ b/hermes_cli/plugins_cmd.py @@ -472,7 +472,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: @@ -1969,7 +1969,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 55231104fa..1b99eca392 100644 --- a/hermes_cli/profiles.py +++ b/hermes_cli/profiles.py @@ -406,7 +406,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] @@ -1206,7 +1206,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 12710a5ca3..53f5d5b4d1 100644 --- a/hermes_cli/secrets_cli.py +++ b/hermes_cli/secrets_cli.py @@ -562,7 +562,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: @@ -618,7 +618,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 3cfa673098..198166f473 100644 --- a/hermes_cli/service_manager.py +++ b/hermes_cli/service_manager.py @@ -838,7 +838,7 @@ class S6ServiceManager: 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 @@ class S6ServiceManager: 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 @@ class S6ServiceManager: 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 @@ class S6ServiceManager: # 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 @@ class S6ServiceManager: # 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 @@ class S6ServiceManager: # 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/uninstall.py b/hermes_cli/uninstall.py index 6832d3d560..4e883f3e2b 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 0af1210674..0a00c0246c 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/webhook.py b/hermes_cli/webhook.py index 9b9de6cd5a..823347f6e1 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 fb6fddc5bf..dc3c11845b 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 7650c54f57..8159c21c17 100644 --- a/plugins/google_meet/audio_bridge.py +++ b/plugins/google_meet/audio_bridge.py @@ -111,7 +111,7 @@ class AudioBridge: ], 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 @@ class AudioBridge: ], 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 @@ class AudioBridge: 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 1ab0c0fd73..45fede0381 100644 --- a/plugins/google_meet/cli.py +++ b/plugins/google_meet/cli.py @@ -293,7 +293,7 @@ def _cmd_install(*, realtime: bool, assume_yes: bool) -> int: 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 211e08d4c6..0396d03949 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 5161bacf41..dd5cf3b2b8 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/client.py b/plugins/memory/honcho/client.py index a1b6552aba..cc1da55ffa 100644 --- a/plugins/memory/honcho/client.py +++ b/plugins/memory/honcho/client.py @@ -742,7 +742,7 @@ class HonchoClientConfig: 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 9883d8f2c1..e84308a5fb 100644 --- a/plugins/memory/mem0/_setup.py +++ b/plugins/memory/mem0/_setup.py @@ -525,7 +525,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/photon/adapter.py b/plugins/platforms/photon/adapter.py index 29f4902904..2f8cae3563 100644 --- a/plugins/platforms/photon/adapter.py +++ b/plugins/platforms/photon/adapter.py @@ -834,7 +834,7 @@ class PhotonAdapter(BasePlatformAdapter): 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 [] @@ -846,7 +846,7 @@ class PhotonAdapter(BasePlatformAdapter): 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 @@ -962,7 +962,7 @@ class PhotonAdapter(BasePlatformAdapter): str(_SIDECAR_DIR), ], capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, check=False, # Windows: suppress the brief console flash this short-lived diff --git a/plugins/platforms/whatsapp/adapter.py b/plugins/platforms/whatsapp/adapter.py index df351f4863..8736274a76 100644 --- a/plugins/platforms/whatsapp/adapter.py +++ b/plugins/platforms/whatsapp/adapter.py @@ -55,7 +55,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: @@ -70,7 +70,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))) @@ -88,7 +88,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(): @@ -223,7 +223,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: @@ -349,7 +349,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 @@ -547,7 +547,7 @@ class WhatsAppAdapter(WhatsAppBehaviorMixin, BasePlatformAdapter): [_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 17ce665dc1..60e73a3f35 100644 --- a/plugins/web/exa/provider.py +++ b/plugins/web/exa/provider.py @@ -170,7 +170,7 @@ class ExaWebSearchProvider(WebSearchProvider): ] 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 c0ca6622ec..031c7648b4 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 460bb1ca89..6bd5795672 100644 --- a/scripts/contributor_audit.py +++ b/scripts/contributor_audit.py @@ -87,7 +87,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: @@ -112,7 +112,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 788fd464bc..a85573a6f7 100755 --- a/scripts/profile-tui.py +++ b/scripts/profile-tui.py @@ -572,7 +572,7 @@ def loop_mode(args: argparse.Namespace) -> int: ["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/skills/creative/comfyui/scripts/auto_fix_deps.py b/skills/creative/comfyui/scripts/auto_fix_deps.py index 788bf8e9e3..79689972b0 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 083d018acc..a89b66dc68 100755 --- a/skills/creative/comfyui/scripts/hardware_check.py +++ b/skills/creative/comfyui/scripts/hardware_check.py @@ -54,7 +54,7 @@ _COMFY_CLI_FLAG = { 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 27855a5158..a4b0451b6a 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 bcc1455d78..c8cf751570 100644 --- a/tools/browser_tool.py +++ b/tools/browser_tool.py @@ -4687,7 +4687,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 b5ce04c6a6..cf5c1d726e 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/doctor.py b/tools/computer_use/doctor.py index 54fad06668..5e5cdf45e8 100644 --- a/tools/computer_use/doctor.py +++ b/tools/computer_use/doctor.py @@ -99,7 +99,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 4cccf2d683..541fd284c0 100644 --- a/tools/computer_use/permissions.py +++ b/tools/computer_use/permissions.py @@ -66,7 +66,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/environments/docker.py b/tools/environments/docker.py index f1470e3285..ea436f5023 100644 --- a/tools/environments/docker.py +++ b/tools/environments/docker.py @@ -181,7 +181,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: @@ -215,7 +215,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: @@ -245,7 +245,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: @@ -637,7 +637,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, ) @@ -720,7 +720,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, ) @@ -763,7 +763,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, ) @@ -1393,7 +1393,7 @@ class DockerEnvironment(BaseEnvironment): 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, @@ -1432,7 +1432,7 @@ class DockerEnvironment(BaseEnvironment): 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, @@ -1569,7 +1569,7 @@ class DockerEnvironment(BaseEnvironment): 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 @@ -1600,7 +1600,7 @@ class DockerEnvironment(BaseEnvironment): "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() @@ -1655,7 +1655,7 @@ class DockerEnvironment(BaseEnvironment): 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() @@ -1666,7 +1666,7 @@ class DockerEnvironment(BaseEnvironment): # 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: @@ -1761,7 +1761,7 @@ class DockerEnvironment(BaseEnvironment): "--format", fmt, ], 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 cce93c20b6..fe83ae2a61 100644 --- a/tools/environments/local.py +++ b/tools/environments/local.py @@ -1403,7 +1403,7 @@ class LocalEnvironment(BaseEnvironment): 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 666d908b25..169937096b 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 @@ class SingularityEnvironment(BaseEnvironment): 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 @@ class SingularityEnvironment(BaseEnvironment): 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 1a06ad9b82..f3e4d5561d 100644 --- a/tools/environments/ssh.py +++ b/tools/environments/ssh.py @@ -104,7 +104,7 @@ class SSHEnvironment(BaseEnvironment): 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 @@ class SSHEnvironment(BaseEnvironment): 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 @@ class SSHEnvironment(BaseEnvironment): subprocess.run( cmd, capture_output=True, - text=True, + text=True, encoding='utf-8', errors='replace', timeout=10, stdin=subprocess.DEVNULL, ) @@ -164,7 +164,7 @@ class SSHEnvironment(BaseEnvironment): 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 @@ class SSHEnvironment(BaseEnvironment): 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 @@ class SSHEnvironment(BaseEnvironment): 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 @@ class SSHEnvironment(BaseEnvironment): 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 9d04e13503..1c119aabca 100644 --- a/tools/lazy_deps.py +++ b/tools/lazy_deps.py @@ -668,7 +668,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, creationflags=windows_hide_flags(), ) @@ -685,7 +685,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, creationflags=windows_hide_flags(), ) @@ -695,7 +695,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, creationflags=windows_hide_flags(), ) @@ -706,7 +706,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, creationflags=windows_hide_flags(), ) diff --git a/tools/process_registry.py b/tools/process_registry.py index d7ae33d0a1..aed6be8933 100644 --- a/tools/process_registry.py +++ b/tools/process_registry.py @@ -600,7 +600,7 @@ class ProcessRegistry: 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, diff --git a/tools/skills_hub.py b/tools/skills_hub.py index aa1bcc5c01..928c212a4b 100644 --- a/tools/skills_hub.py +++ b/tools/skills_hub.py @@ -412,7 +412,7 @@ class GitHubAuth: 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 9350960413..a07d3f817d 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 6c34e714cd..1198f53d13 100644 --- a/tools/transcription_tools.py +++ b/tools/transcription_tools.py @@ -1210,7 +1210,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) @@ -1256,9 +1256,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 16320974ae..27c761e17c 100644 --- a/tools/tts_tool.py +++ b/tools/tts_tool.py @@ -2015,7 +2015,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 @@ -2097,7 +2097,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 e3162e06e5..ca35a2b2e7 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 @@ class TermuxAudioRecorder: "-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 @@ class TermuxAudioRecorder: 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: