fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428)
On Windows with Chinese locale (GBK), subprocess.run(text=True) without explicit encoding causes UnicodeDecodeError crashes. This fix adds encoding='utf-8', errors='replace' to all subprocess.run() and subprocess.Popen() calls that use text=True across 76 non-test Python files. Fixes #53428 (master tracker for Windows GBK locale crash). Note: credential_pool.py and electron changes excluded per reviewer request — those will be submitted as separate focused PRs.
This commit is contained in:
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
+1
-1
@@ -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 {
|
||||
|
||||
+1
-1
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
+3
-3
@@ -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"):
|
||||
|
||||
+4
-4
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 {}
|
||||
|
||||
+2
-2
@@ -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:
|
||||
|
||||
+21
-21
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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})")
|
||||
|
||||
@@ -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),
|
||||
)
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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, ""
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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...")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
|
||||
@@ -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 []:
|
||||
|
||||
@@ -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 []
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:")
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
+4
-4
@@ -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(),
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
+1
-1
@@ -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(),
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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"))
|
||||
|
||||
+2
-2
@@ -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:
|
||||
|
||||
+3
-3
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user