mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-25 17:18:11 +00:00
fix(windows): sweep remaining unguarded text-mode subprocess sites codebase-wide
AST-driven pass over every subprocess.run/Popen/check_output/check_call/call with text=True (or universal_newlines=True) and no explicit encoding=: append encoding='utf-8', errors='replace' at the kwarg site. 136 call sites across 28 files (cli.py, hermes_cli/main.py, tools_config.py, environments, computer_use, gateway, scripts, skills helpers, agent/*). Together with the salvaged #55339/#60741 commits this closes out issue #53428's bug class; the salvaged #60751 linter rule in check-windows-footguns.py now enforces it repo-wide (verified: 807 files scanned, zero findings).
This commit is contained in:
parent
051217342b
commit
d4b867cf9f
28 changed files with 138 additions and 136 deletions
|
|
@ -267,7 +267,7 @@ def _install_npm(
|
|||
[npm, "install", "--prefix", str(staging), "--silent", "--no-fund", "--no-audit", *install_targets],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=300,
|
||||
stdin=subprocess.DEVNULL,
|
||||
creationflags=windows_hide_flags(),
|
||||
|
|
@ -316,7 +316,7 @@ def _install_go(pkg: str, bin_name: str) -> Optional[str]:
|
|||
[go, "install", pkg],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=600,
|
||||
env=env,
|
||||
stdin=subprocess.DEVNULL,
|
||||
|
|
|
|||
|
|
@ -706,7 +706,7 @@ def iron_proxy_version(binary: Path) -> str:
|
|||
res = subprocess.run( # noqa: S603
|
||||
[str(binary), "--version"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=_RUN_TIMEOUT,
|
||||
env=minimal_env,
|
||||
)
|
||||
|
|
@ -1052,7 +1052,7 @@ def _detect_docker_bridge_ip() -> Optional[str]:
|
|||
try:
|
||||
res = subprocess.run( # noqa: S603 — ip is a system binary
|
||||
["ip", "-4", "-o", "addr", "show", "docker0"],
|
||||
capture_output=True, text=True, timeout=2,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=2,
|
||||
)
|
||||
if res.returncode == 0:
|
||||
for line in res.stdout.splitlines():
|
||||
|
|
@ -1743,7 +1743,7 @@ def _pid_alive(pid: int) -> bool:
|
|||
try:
|
||||
res = subprocess.run( # noqa: S603
|
||||
["ps", "-p", str(pid), "-o", "comm="],
|
||||
capture_output=True, text=True, timeout=2,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=2,
|
||||
)
|
||||
if res.returncode == 0:
|
||||
comm = (res.stdout or "").strip()
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ def run_secret_cli(
|
|||
list(argv),
|
||||
env=env,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=timeout,
|
||||
stdin=subprocess.DEVNULL,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ def build_trace_jsonl(
|
|||
if cwd:
|
||||
r = subprocess.run(
|
||||
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
||||
capture_output=True, text=True, timeout=3, cwd=cwd,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=3, cwd=cwd,
|
||||
)
|
||||
if r.returncode == 0:
|
||||
git_branch = r.stdout.strip()
|
||||
|
|
|
|||
48
cli.py
48
cli.py
|
|
@ -1432,7 +1432,7 @@ def _git_repo_root() -> Optional[str]:
|
|||
try:
|
||||
result = subprocess.run(
|
||||
["git", "rev-parse", "--show-toplevel"],
|
||||
capture_output=True, text=True, timeout=5,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return _normalize_git_bash_path(result.stdout.strip())
|
||||
|
|
@ -1479,7 +1479,7 @@ def _resolve_worktree_base(repo_root: str) -> tuple:
|
|||
def _git(args, timeout=20):
|
||||
return subprocess.run(
|
||||
["git", *args],
|
||||
capture_output=True, text=True, timeout=timeout, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout, cwd=repo_root,
|
||||
)
|
||||
|
||||
# 1. Current branch's upstream, if it tracks one.
|
||||
|
|
@ -1578,7 +1578,7 @@ def _setup_worktree(repo_root: str = None, sync_base: bool = True) -> Optional[D
|
|||
try:
|
||||
result = subprocess.run(
|
||||
["git", "worktree", "add", str(wt_path), "-b", branch_name, base_ref],
|
||||
capture_output=True, text=True, timeout=30, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=30, cwd=repo_root,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
# If branching from the resolved remote ref failed for any reason
|
||||
|
|
@ -1592,7 +1592,7 @@ def _setup_worktree(repo_root: str = None, sync_base: bool = True) -> Optional[D
|
|||
base_ref, base_label = "HEAD", "HEAD (fallback — remote base failed)"
|
||||
result = subprocess.run(
|
||||
["git", "worktree", "add", str(wt_path), "-b", branch_name, base_ref],
|
||||
capture_output=True, text=True, timeout=30, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=30, cwd=repo_root,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
print(f"\033[31m✗ Failed to create worktree: {result.stderr.strip()}\033[0m")
|
||||
|
|
@ -1673,7 +1673,7 @@ def _setup_worktree(repo_root: str = None, sync_base: bool = True) -> Optional[D
|
|||
try:
|
||||
subprocess.run(
|
||||
["git", "worktree", "lock", "--reason", f"hermes pid={os.getpid()}", str(wt_path)],
|
||||
capture_output=True, text=True, timeout=10, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=10, cwd=repo_root,
|
||||
)
|
||||
logger.debug("Worktree locked: %s (pid=%s)", wt_path, os.getpid())
|
||||
except Exception as e:
|
||||
|
|
@ -1706,7 +1706,7 @@ def _worktree_has_unpushed_commits(worktree_path: str, timeout: int = 10) -> boo
|
|||
try:
|
||||
remote_refs = subprocess.run(
|
||||
["git", "for-each-ref", "--format=%(refname)", "refs/remotes"],
|
||||
capture_output=True, text=True, timeout=timeout, cwd=worktree_path,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout, cwd=worktree_path,
|
||||
)
|
||||
if remote_refs.returncode != 0:
|
||||
return True
|
||||
|
|
@ -1715,7 +1715,7 @@ def _worktree_has_unpushed_commits(worktree_path: str, timeout: int = 10) -> boo
|
|||
|
||||
result = subprocess.run(
|
||||
["git", "log", "--oneline", "HEAD", "--not", "--remotes"],
|
||||
capture_output=True, text=True, timeout=timeout, cwd=worktree_path,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout, cwd=worktree_path,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return True
|
||||
|
|
@ -1736,7 +1736,7 @@ def _worktree_is_dirty(worktree_path: str, timeout: int = 10) -> bool:
|
|||
try:
|
||||
result = subprocess.run(
|
||||
["git", "status", "--porcelain"],
|
||||
capture_output=True, text=True, timeout=timeout, cwd=worktree_path,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout, cwd=worktree_path,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return True
|
||||
|
|
@ -1769,7 +1769,7 @@ def _worktree_commits_all_merged_upstream(
|
|||
try:
|
||||
probe = subprocess.run(
|
||||
["git", "rev-parse", "--verify", "--quiet", candidate],
|
||||
capture_output=True, text=True, timeout=timeout, cwd=worktree_path,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout, cwd=worktree_path,
|
||||
)
|
||||
if probe.returncode == 0 and probe.stdout.strip():
|
||||
base = candidate
|
||||
|
|
@ -1782,7 +1782,7 @@ def _worktree_commits_all_merged_upstream(
|
|||
try:
|
||||
ahead = subprocess.run(
|
||||
["git", "rev-list", "--count", f"{base}..HEAD"],
|
||||
capture_output=True, text=True, timeout=timeout, cwd=worktree_path,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout, cwd=worktree_path,
|
||||
)
|
||||
if ahead.returncode != 0:
|
||||
return False
|
||||
|
|
@ -1794,7 +1794,7 @@ def _worktree_commits_all_merged_upstream(
|
|||
|
||||
cherry = subprocess.run(
|
||||
["git", "cherry", base, "HEAD"],
|
||||
capture_output=True, text=True, timeout=timeout, cwd=worktree_path,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout, cwd=worktree_path,
|
||||
)
|
||||
if cherry.returncode != 0:
|
||||
return False
|
||||
|
|
@ -1829,7 +1829,7 @@ def _worktree_lock_is_live(repo_root: str, worktree_path: str, timeout: int = 10
|
|||
try:
|
||||
result = subprocess.run(
|
||||
["git", "worktree", "list", "--porcelain"],
|
||||
capture_output=True, text=True, timeout=timeout, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout, cwd=repo_root,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return "live"
|
||||
|
|
@ -1904,7 +1904,7 @@ def _cleanup_worktree(info: Dict[str, str] = None) -> None:
|
|||
try:
|
||||
subprocess.run(
|
||||
["git", "worktree", "unlock", wt_path],
|
||||
capture_output=True, text=True, timeout=10, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=10, cwd=repo_root,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug("git worktree unlock failed (non-fatal): %s", e)
|
||||
|
|
@ -1912,7 +1912,7 @@ def _cleanup_worktree(info: Dict[str, str] = None) -> None:
|
|||
try:
|
||||
subprocess.run(
|
||||
["git", "worktree", "remove", wt_path, "--force"],
|
||||
capture_output=True, text=True, timeout=15, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=15, cwd=repo_root,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug("Failed to remove worktree: %s", e)
|
||||
|
|
@ -1921,7 +1921,7 @@ def _cleanup_worktree(info: Dict[str, str] = None) -> None:
|
|||
try:
|
||||
subprocess.run(
|
||||
["git", "branch", "-D", branch],
|
||||
capture_output=True, text=True, timeout=10, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=10, cwd=repo_root,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug("Failed to delete branch %s: %s", branch, e)
|
||||
|
|
@ -2122,7 +2122,7 @@ def _prune_stale_worktrees(repo_root: str, max_age_hours: int = 24) -> None:
|
|||
try:
|
||||
subprocess.run(
|
||||
["git", "worktree", "unlock", str(entry)],
|
||||
capture_output=True, text=True, timeout=10, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=10, cwd=repo_root,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug("Failed to unlock dead worktree %s: %s", entry.name, e)
|
||||
|
|
@ -2131,13 +2131,13 @@ def _prune_stale_worktrees(repo_root: str, max_age_hours: int = 24) -> None:
|
|||
try:
|
||||
branch_result = subprocess.run(
|
||||
["git", "branch", "--show-current"],
|
||||
capture_output=True, text=True, timeout=5, cwd=str(entry),
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5, cwd=str(entry),
|
||||
)
|
||||
branch = branch_result.stdout.strip()
|
||||
|
||||
remove_result = subprocess.run(
|
||||
["git", "worktree", "remove", str(entry), "--force"],
|
||||
capture_output=True, text=True, timeout=15, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=15, cwd=repo_root,
|
||||
)
|
||||
if remove_result.returncode != 0:
|
||||
# Removal failed — keep the branch so any commits stay
|
||||
|
|
@ -2150,7 +2150,7 @@ def _prune_stale_worktrees(repo_root: str, max_age_hours: int = 24) -> None:
|
|||
if branch:
|
||||
subprocess.run(
|
||||
["git", "branch", "-D", branch],
|
||||
capture_output=True, text=True, timeout=10, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=10, cwd=repo_root,
|
||||
)
|
||||
logger.debug("Pruned stale worktree: %s (force=%s)", entry.name, force)
|
||||
except Exception as e:
|
||||
|
|
@ -2178,7 +2178,7 @@ def _prune_orphaned_branches(repo_root: str) -> None:
|
|||
try:
|
||||
result = subprocess.run(
|
||||
["git", "branch", "--format=%(refname:short)"],
|
||||
capture_output=True, text=True, timeout=10, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=10, cwd=repo_root,
|
||||
)
|
||||
if result.returncode != 0:
|
||||
return
|
||||
|
|
@ -2191,7 +2191,7 @@ def _prune_orphaned_branches(repo_root: str) -> None:
|
|||
try:
|
||||
wt_result = subprocess.run(
|
||||
["git", "worktree", "list", "--porcelain"],
|
||||
capture_output=True, text=True, timeout=10, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=10, cwd=repo_root,
|
||||
)
|
||||
for line in wt_result.stdout.split("\n"):
|
||||
if line.startswith("branch refs/heads/"):
|
||||
|
|
@ -2203,7 +2203,7 @@ def _prune_orphaned_branches(repo_root: str) -> None:
|
|||
try:
|
||||
head_result = subprocess.run(
|
||||
["git", "branch", "--show-current"],
|
||||
capture_output=True, text=True, timeout=5, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5, cwd=repo_root,
|
||||
)
|
||||
current = head_result.stdout.strip()
|
||||
if current:
|
||||
|
|
@ -2227,7 +2227,7 @@ def _prune_orphaned_branches(repo_root: str) -> None:
|
|||
try:
|
||||
subprocess.run(
|
||||
["git", "branch", "-D"] + batch,
|
||||
capture_output=True, text=True, timeout=30, cwd=repo_root,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=30, cwd=repo_root,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.debug("Failed to prune orphaned branches: %s", e)
|
||||
|
|
@ -9528,7 +9528,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin, CLIBillingMixin):
|
|||
from hermes_cli._subprocess_compat import windows_hide_flags
|
||||
result = subprocess.run(
|
||||
exec_cmd, shell=True, capture_output=True,
|
||||
text=True, timeout=30, env=sanitized_env,
|
||||
text=True, encoding="utf-8", errors="replace", timeout=30, env=sanitized_env,
|
||||
# No console flash on Windows (#56747).
|
||||
creationflags=windows_hide_flags(),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ class WebhookRouteProcessor:
|
|||
argv,
|
||||
input=json.dumps(payload),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=self.script_timeout_seconds,
|
||||
cwd=str(path.parent),
|
||||
env=_sanitize_subprocess_env(os.environ.copy()),
|
||||
|
|
|
|||
|
|
@ -7271,7 +7271,7 @@ class GatewayRunner(GatewayAuthorizationMixin, GatewayKanbanWatchersMixin, Gatew
|
|||
out = subprocess.run(
|
||||
[systemctl, *scope_flags, "show", service_name,
|
||||
"--property=MainPID", "--value"],
|
||||
capture_output=True, text=True, timeout=2,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=2,
|
||||
)
|
||||
return (out.stdout or "").strip()
|
||||
except Exception:
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ def _run_repair_install(specs: list[str], project_root: Path) -> bool:
|
|||
[sys.executable, "-m", "pip", "install", "--force-reinstall", *specs],
|
||||
cwd=project_root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
except Exception as exc:
|
||||
print(f" ✗ Early venv repair could not run pip: {exc}", file=sys.stderr)
|
||||
|
|
|
|||
|
|
@ -1330,7 +1330,7 @@ def _probe_container(cmd: list, backend: str, via_sudo: bool = False):
|
|||
all other exceptions propagate naturally.
|
||||
"""
|
||||
try:
|
||||
return subprocess.run(cmd, capture_output=True, text=True, timeout=15)
|
||||
return subprocess.run(cmd, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=15)
|
||||
except subprocess.TimeoutExpired:
|
||||
label = f"sudo {backend}" if via_sudo else backend
|
||||
print(
|
||||
|
|
@ -1843,7 +1843,7 @@ def _restore_tui_workspace(tui_dir: Path) -> bool:
|
|||
[git, "restore", "--", tui_dir.name],
|
||||
cwd=str(tui_dir.parent),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=False,
|
||||
)
|
||||
except OSError:
|
||||
|
|
@ -4729,7 +4729,7 @@ def _capture_head_sha(git_cmd, cwd) -> str | None:
|
|||
git_cmd + ["rev-parse", "HEAD"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=True,
|
||||
)
|
||||
return result.stdout.strip() or None
|
||||
|
|
@ -5088,7 +5088,7 @@ def _nixos_build_env() -> dict[str, str] | None:
|
|||
try:
|
||||
result = subprocess.run(
|
||||
["nix-shell", "-p", "python3", "--run", "which python3"],
|
||||
capture_output=True, text=True, check=False, timeout=15,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", check=False, timeout=15,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
python3_path = result.stdout.strip()
|
||||
|
|
@ -6290,7 +6290,7 @@ def _find_stale_dashboard_pids(
|
|||
result = subprocess.run(
|
||||
["ps", "-A", "-o", "pid=,command="],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=10,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
|
|
@ -6579,7 +6579,7 @@ def _restart_managed_dashboard_service(
|
|||
return subprocess.run(
|
||||
["systemctl", *args],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
|
|
@ -6643,7 +6643,7 @@ def _restart_managed_dashboard_service(
|
|||
result = subprocess.run(
|
||||
list(command),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=60,
|
||||
)
|
||||
except (FileNotFoundError, subprocess.TimeoutExpired, OSError) as e:
|
||||
|
|
@ -6732,7 +6732,7 @@ def _kill_stale_dashboard_processes(
|
|||
result = subprocess.run(
|
||||
["taskkill", "/PID", str(pid), "/F"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=10,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
|
|
@ -7055,7 +7055,7 @@ def _stash_local_changes_if_needed(git_cmd: list[str], cwd: Path) -> Optional[st
|
|||
git_cmd + ["status", "--porcelain"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=True,
|
||||
)
|
||||
if not status.stdout.strip():
|
||||
|
|
@ -7069,7 +7069,7 @@ def _stash_local_changes_if_needed(git_cmd: list[str], cwd: Path) -> Optional[st
|
|||
git_cmd + ["ls-files", "--unmerged"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if unmerged.stdout.strip():
|
||||
print("→ Clearing unmerged index entries from a previous conflict...")
|
||||
|
|
@ -7085,13 +7085,13 @@ def _stash_local_changes_if_needed(git_cmd: list[str], cwd: Path) -> Optional[st
|
|||
git_cmd + ["rev-parse", "--verify", "refs/stash"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
).stdout.strip()
|
||||
push = subprocess.run(
|
||||
git_cmd + ["stash", "push", "--include-untracked", "-m", stash_name],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if push.stdout.strip():
|
||||
print(push.stdout.strip())
|
||||
|
|
@ -7099,7 +7099,7 @@ def _stash_local_changes_if_needed(git_cmd: list[str], cwd: Path) -> Optional[st
|
|||
git_cmd + ["rev-parse", "--verify", "refs/stash"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
stash_ref = stash_probe.stdout.strip()
|
||||
stash_created = (
|
||||
|
|
@ -7157,7 +7157,7 @@ def _resolve_stash_selector(
|
|||
git_cmd + ["stash", "list", "--format=%gd %H"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=True,
|
||||
)
|
||||
for line in stash_list.stdout.splitlines():
|
||||
|
|
@ -7242,7 +7242,7 @@ def _restore_stashed_changes(
|
|||
git_cmd + ["stash", "apply", stash_ref],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
|
||||
# Check for unmerged (conflicted) files — can happen even when returncode is 0
|
||||
|
|
@ -7250,7 +7250,7 @@ def _restore_stashed_changes(
|
|||
git_cmd + ["diff", "--name-only", "--diff-filter=U"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
has_conflicts = bool(unmerged.stdout.strip())
|
||||
|
||||
|
|
@ -7312,7 +7312,7 @@ def _restore_stashed_changes(
|
|||
git_cmd + ["stash", "drop", stash_selector],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if drop.returncode != 0:
|
||||
print(
|
||||
|
|
@ -7364,7 +7364,7 @@ def _discard_stashed_changes(
|
|||
git_cmd + ["stash", "drop", stash_selector],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if drop.returncode != 0:
|
||||
print(
|
||||
|
|
@ -7401,7 +7401,7 @@ def _get_origin_url(git_cmd: list[str], cwd: Path) -> Optional[str]:
|
|||
git_cmd + ["remote", "get-url", "origin"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
|
|
@ -7434,7 +7434,7 @@ def _has_upstream_remote(git_cmd: list[str], cwd: Path) -> bool:
|
|||
git_cmd + ["remote", "get-url", "upstream"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
return result.returncode == 0
|
||||
except Exception:
|
||||
|
|
@ -7448,7 +7448,7 @@ def _add_upstream_remote(git_cmd: list[str], cwd: Path) -> bool:
|
|||
git_cmd + ["remote", "add", "upstream", OFFICIAL_REPO_URL],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
return result.returncode == 0
|
||||
except Exception:
|
||||
|
|
@ -7462,7 +7462,7 @@ def _count_commits_between(git_cmd: list[str], cwd: Path, base: str, head: str)
|
|||
git_cmd + ["rev-list", "--count", f"{base}..{head}"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return int(result.stdout.strip())
|
||||
|
|
@ -7498,7 +7498,7 @@ def _sync_fork_with_upstream(git_cmd: list[str], cwd: Path) -> bool:
|
|||
git_cmd + ["push", "origin", "main", "--force-with-lease"],
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
return result.returncode == 0
|
||||
except Exception:
|
||||
|
|
@ -8541,7 +8541,7 @@ def _detect_broken_lazy_refresh_imports(
|
|||
result = subprocess.run(
|
||||
[str(venv_python), "-c", check_script],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=False,
|
||||
env=env,
|
||||
)
|
||||
|
|
@ -9000,7 +9000,7 @@ def _verify_core_dependencies_installed(
|
|||
result = subprocess.run(
|
||||
[str(venv_python), "-c", check_script, *applicable],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=False,
|
||||
env=env,
|
||||
)
|
||||
|
|
@ -9722,7 +9722,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False):
|
|||
git_cmd + ["rev-parse", "--is-shallow-repository"],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
).stdout.strip()
|
||||
== "true"
|
||||
)
|
||||
|
|
@ -9734,7 +9734,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False):
|
|||
git_cmd + ["fetch"] + depth_args + ["upstream", branch],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if fetch_result.returncode != 0:
|
||||
# Fallback to origin if upstream doesn't exist
|
||||
|
|
@ -9743,7 +9743,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False):
|
|||
git_cmd + ["fetch"] + depth_args + ["origin", branch],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
upstream_exists = False
|
||||
compare_branch = f"origin/{branch}"
|
||||
|
|
@ -9757,7 +9757,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False):
|
|||
git_cmd + ["fetch"] + depth_args + ["origin", branch],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
upstream_exists = False
|
||||
compare_branch = f"origin/{branch}"
|
||||
|
|
@ -9782,7 +9782,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False):
|
|||
git_cmd + ["rev-parse", "--verify", "--quiet", compare_branch],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if verify_result.returncode != 0:
|
||||
print(f"✗ Branch '{branch}' not found on {compare_branch.split('/', 1)[0]}.")
|
||||
|
|
@ -9793,11 +9793,11 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False):
|
|||
# report presence-only (mirrors the banner's _check_via_local_git).
|
||||
head_sha = subprocess.run(
|
||||
git_cmd + ["rev-parse", "HEAD"],
|
||||
cwd=PROJECT_ROOT, capture_output=True, text=True,
|
||||
cwd=PROJECT_ROOT, capture_output=True, text=True, encoding="utf-8", errors="replace",
|
||||
).stdout.strip()
|
||||
target_sha = subprocess.run(
|
||||
git_cmd + ["rev-parse", compare_branch],
|
||||
cwd=PROJECT_ROOT, capture_output=True, text=True,
|
||||
cwd=PROJECT_ROOT, capture_output=True, text=True, encoding="utf-8", errors="replace",
|
||||
).stdout.strip()
|
||||
if head_sha and target_sha and head_sha == target_sha:
|
||||
print("✓ Already up to date.")
|
||||
|
|
@ -9812,7 +9812,7 @@ def _cmd_update_check(branch: str = "main", *, branch_explicit: bool = False):
|
|||
git_cmd + ["rev-list", f"HEAD..{compare_branch}", "--count"],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=True,
|
||||
)
|
||||
behind = int(rev_result.stdout.strip())
|
||||
|
|
@ -9873,7 +9873,7 @@ def _ensure_fhs_path_guard() -> None:
|
|||
"command -v hermes",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=10,
|
||||
)
|
||||
except (FileNotFoundError, subprocess.TimeoutExpired):
|
||||
|
|
@ -10197,7 +10197,7 @@ def _venv_core_imports_healthy() -> tuple[bool, str]:
|
|||
result = subprocess.run(
|
||||
[str(venv_python), "-c", check],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=60,
|
||||
cwd=PROJECT_ROOT,
|
||||
)
|
||||
|
|
@ -10640,7 +10640,7 @@ def _discard_lockfile_churn(git_cmd, repo_root):
|
|||
git_cmd + ["diff", "--name-only"],
|
||||
cwd=repo_root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if diff.returncode != 0:
|
||||
return
|
||||
|
|
@ -10661,7 +10661,7 @@ def _discard_lockfile_churn(git_cmd, repo_root):
|
|||
git_cmd + ["checkout", "--", *dirty],
|
||||
cwd=repo_root,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=False,
|
||||
)
|
||||
print(f"→ Discarded npm lockfile churn ({len(dirty)} file(s))")
|
||||
|
|
@ -10886,7 +10886,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
git_cmd + ["fetch", "origin", branch],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if fetch_result.returncode != 0:
|
||||
stderr = fetch_result.stderr.strip()
|
||||
|
|
@ -10910,7 +10910,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
git_cmd + ["rev-parse", "--abbrev-ref", "HEAD"],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=True,
|
||||
)
|
||||
current_branch = result.stdout.strip()
|
||||
|
|
@ -10933,7 +10933,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
git_cmd + ["checkout", branch],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if checkout_result.returncode != 0:
|
||||
# Local checkout doesn't have this branch yet. Try to set
|
||||
|
|
@ -10944,7 +10944,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
git_cmd + ["checkout", "-B", branch, f"origin/{branch}"],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if track_result.returncode != 0:
|
||||
# Restore the user's prior branch + stash before bailing
|
||||
|
|
@ -10975,7 +10975,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
git_cmd + ["rev-list", f"HEAD..origin/{branch}", "--count"],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=True,
|
||||
)
|
||||
commit_count = int(result.stdout.strip())
|
||||
|
|
@ -11001,7 +11001,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
git_cmd + ["checkout", current_branch],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=False,
|
||||
)
|
||||
|
||||
|
|
@ -11073,7 +11073,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
git_cmd + ["pull", "--ff-only", "origin", branch],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if pull_result.returncode != 0:
|
||||
# ff-only failed — local and remote have diverged (e.g. upstream
|
||||
|
|
@ -11086,7 +11086,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
git_cmd + ["reset", "--hard", f"origin/{branch}"],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if reset_result.returncode != 0:
|
||||
print(f"✗ Failed to reset to origin/{branch}.")
|
||||
|
|
@ -11122,7 +11122,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
git_cmd + ["reset", "--hard", pre_pull_sha],
|
||||
cwd=PROJECT_ROOT,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if rollback_result.returncode == 0:
|
||||
print(" ✓ Rollback complete — your install is unchanged.")
|
||||
|
|
@ -11717,7 +11717,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
_verify = subprocess.run(
|
||||
scope_cmd_ + ["is-active", svc_name_],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=5,
|
||||
)
|
||||
if _verify.stdout.strip() == "active":
|
||||
|
|
@ -11751,7 +11751,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
"--value",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=5,
|
||||
)
|
||||
except (FileNotFoundError, subprocess.TimeoutExpired):
|
||||
|
|
@ -11900,7 +11900,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
"--no-pager",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=10,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
|
|
@ -11919,7 +11919,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
check = subprocess.run(
|
||||
scope_cmd + ["is-active", svc_name],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=5,
|
||||
)
|
||||
if check.stdout.strip() != "active":
|
||||
|
|
@ -11952,7 +11952,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
"--value",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=5,
|
||||
)
|
||||
_main_pid = int((_show.stdout or "").strip() or 0)
|
||||
|
|
@ -12005,13 +12005,13 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
subprocess.run(
|
||||
_manage_cmd + ["reset-failed", svc_name],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=10,
|
||||
)
|
||||
subprocess.run(
|
||||
_manage_cmd + ["start", svc_name],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=15,
|
||||
)
|
||||
# Short poll: the gateway should be up
|
||||
|
|
@ -12095,13 +12095,13 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
subprocess.run(
|
||||
_manage_cmd + ["reset-failed", svc_name],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=10,
|
||||
)
|
||||
restart = subprocess.run(
|
||||
_manage_cmd + ["restart", svc_name],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=15,
|
||||
)
|
||||
if restart.returncode == 0:
|
||||
|
|
@ -12127,13 +12127,13 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
subprocess.run(
|
||||
_manage_cmd + ["reset-failed", svc_name],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=10,
|
||||
)
|
||||
subprocess.run(
|
||||
_manage_cmd + ["restart", svc_name],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=15,
|
||||
)
|
||||
if _wait_for_service_active(
|
||||
|
|
@ -12191,7 +12191,7 @@ def _cmd_update_impl(args, gateway_mode: bool):
|
|||
check = subprocess.run(
|
||||
["launchctl", "list", get_launchd_label()],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=5,
|
||||
)
|
||||
if check.returncode == 0:
|
||||
|
|
@ -15016,7 +15016,7 @@ def main():
|
|||
from hermes_cli.tools_config import _cua_driver_env
|
||||
version = subprocess.run(
|
||||
[path, "--version"],
|
||||
capture_output=True, text=True, timeout=5,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5,
|
||||
env=_cua_driver_env(),
|
||||
).stdout.strip()
|
||||
except Exception:
|
||||
|
|
|
|||
|
|
@ -1450,7 +1450,7 @@ def setup_terminal_backend(config: dict):
|
|||
ssh_cmd.extend(["-p", port])
|
||||
ssh_cmd.append(f"{user}@{host}" if user else host)
|
||||
ssh_cmd.append("echo ok")
|
||||
result = subprocess.run(ssh_cmd, capture_output=True, text=True, timeout=10)
|
||||
result = subprocess.run(ssh_cmd, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=10)
|
||||
if result.returncode == 0:
|
||||
print_success(" SSH connection successful!")
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -708,7 +708,7 @@ def _pip_install(
|
|||
try:
|
||||
result = subprocess.run(
|
||||
[uv_bin, "pip", "install", *args],
|
||||
capture_output=capture_output, text=True, timeout=timeout,
|
||||
capture_output=capture_output, text=True, encoding="utf-8", errors="replace", timeout=timeout,
|
||||
env=uv_env,
|
||||
creationflags=_post_setup_no_window_flags(
|
||||
streams_to_console=not capture_output
|
||||
|
|
@ -726,7 +726,7 @@ def _pip_install(
|
|||
# Probe for pip; bootstrap via ensurepip if missing (uv venv lacks it).
|
||||
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,
|
||||
creationflags=_post_setup_no_window_flags(),
|
||||
)
|
||||
if probe.returncode != 0:
|
||||
|
|
@ -735,7 +735,7 @@ def _pip_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,
|
||||
creationflags=_post_setup_no_window_flags(),
|
||||
)
|
||||
except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:
|
||||
|
|
@ -747,7 +747,7 @@ def _pip_install(
|
|||
|
||||
return subprocess.run(
|
||||
pip_cmd + ["install", *args],
|
||||
capture_output=capture_output, text=True, timeout=timeout,
|
||||
capture_output=capture_output, text=True, encoding="utf-8", errors="replace", timeout=timeout,
|
||||
creationflags=_post_setup_no_window_flags(
|
||||
streams_to_console=not capture_output
|
||||
),
|
||||
|
|
@ -859,7 +859,7 @@ def install_cua_driver(upgrade: bool = False) -> bool:
|
|||
try:
|
||||
version = subprocess.run(
|
||||
[binary, "--version"],
|
||||
capture_output=True, text=True, timeout=5, env=_cua_driver_env(),
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5, env=_cua_driver_env(),
|
||||
creationflags=_post_setup_no_window_flags(),
|
||||
).stdout.strip()
|
||||
_print_success(f" {driver_cmd} already installed: {version or 'unknown version'}")
|
||||
|
|
@ -917,7 +917,7 @@ def install_cua_driver(upgrade: bool = False) -> bool:
|
|||
try:
|
||||
before = subprocess.run(
|
||||
[binary, "--version"],
|
||||
capture_output=True, text=True, timeout=5, env=_cua_driver_env(),
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5, env=_cua_driver_env(),
|
||||
creationflags=_post_setup_no_window_flags(),
|
||||
).stdout.strip()
|
||||
except Exception:
|
||||
|
|
@ -930,7 +930,7 @@ def install_cua_driver(upgrade: bool = False) -> bool:
|
|||
try:
|
||||
after = subprocess.run(
|
||||
[binary, "--version"],
|
||||
capture_output=True, text=True, timeout=5, env=_cua_driver_env(),
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5, env=_cua_driver_env(),
|
||||
creationflags=_post_setup_no_window_flags(),
|
||||
).stdout.strip()
|
||||
if after and after != before:
|
||||
|
|
@ -1075,7 +1075,7 @@ def _run_cua_driver_installer(label: str = "Installing", verbose: bool = True) -
|
|||
try:
|
||||
dl = subprocess.run(
|
||||
["curl", "-fsSL", "-o", script_path, install_url],
|
||||
capture_output=True, text=True, timeout=120,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=120,
|
||||
)
|
||||
except (subprocess.TimeoutExpired, OSError) as e:
|
||||
_print_warning(f" cua-driver installer download failed: {e}")
|
||||
|
|
@ -1243,7 +1243,7 @@ def _run_post_setup(post_setup_key: str):
|
|||
# only, avoiding the apps/* glob which would pull in
|
||||
# apps/desktop (Electron + node-pty) unnecessarily. See #38772.
|
||||
[npm_bin, "install", "--silent", "--workspaces=false"],
|
||||
capture_output=True, text=True, cwd=str(PROJECT_ROOT),
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", cwd=str(PROJECT_ROOT),
|
||||
creationflags=_post_setup_no_window_flags(),
|
||||
)
|
||||
if result.returncode == 0:
|
||||
|
|
@ -1323,7 +1323,7 @@ def _run_post_setup(post_setup_key: str):
|
|||
try:
|
||||
result = subprocess.run(
|
||||
install_cmd,
|
||||
capture_output=True, text=True, cwd=str(PROJECT_ROOT), timeout=600,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", cwd=str(PROJECT_ROOT), timeout=600,
|
||||
creationflags=_post_setup_no_window_flags(),
|
||||
)
|
||||
if result.returncode == 0:
|
||||
|
|
@ -1357,7 +1357,7 @@ def _run_post_setup(post_setup_key: str):
|
|||
result = subprocess.run(
|
||||
# --workspaces=false avoids resolving apps/desktop. See #38772.
|
||||
[_npm_bin, "install", "--silent", "--workspaces=false"],
|
||||
capture_output=True, text=True, cwd=str(PROJECT_ROOT),
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", cwd=str(PROJECT_ROOT),
|
||||
creationflags=_post_setup_no_window_flags(),
|
||||
)
|
||||
if result.returncode == 0:
|
||||
|
|
|
|||
|
|
@ -362,7 +362,7 @@ def _resolve_direct_interpreter(python_entry: str) -> tuple[str, list[str]]:
|
|||
"print(json.dumps({'base':getattr(sys,'_base_executable','') or sys.executable,"
|
||||
"'path':[p for p in sys.path if p],'root':root}))"
|
||||
)
|
||||
out = subprocess.run([python_entry, "-c", query], capture_output=True, text=True, timeout=30)
|
||||
out = subprocess.run([python_entry, "-c", query], capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=30)
|
||||
if out.returncode != 0:
|
||||
raise ValueError("could not resolve the base Python interpreter")
|
||||
info = json.loads(out.stdout.strip().splitlines()[-1])
|
||||
|
|
@ -437,8 +437,8 @@ def inspect_hermes(hermes_path: str) -> dict[str, Any]:
|
|||
path = os.path.abspath(hermes_path)
|
||||
if not os.path.isabs(hermes_path) or not os.path.isfile(path):
|
||||
raise ValueError("Hermes path is not an executable file")
|
||||
version = subprocess.run([path, "--version"], capture_output=True, text=True, timeout=20)
|
||||
help_result = subprocess.run([path, "serve", "--help"], capture_output=True, text=True, timeout=20)
|
||||
version = subprocess.run([path, "--version"], capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=20)
|
||||
help_result = subprocess.run([path, "serve", "--help"], capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=20)
|
||||
help_text = help_result.stdout + help_result.stderr
|
||||
return {
|
||||
"path": path,
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ def _reinstall_sidecar_deps() -> None:
|
|||
[npm, "ci"],
|
||||
cwd=str(_SIDECAR_DIR),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=False,
|
||||
timeout=_NPM_REINSTALL_TIMEOUT,
|
||||
creationflags=windows_hide_flags(),
|
||||
|
|
@ -196,7 +196,7 @@ def _reinstall_sidecar_deps() -> None:
|
|||
[npm, "install"],
|
||||
cwd=str(_SIDECAR_DIR),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
check=False,
|
||||
timeout=_NPM_REINSTALL_TIMEOUT,
|
||||
creationflags=windows_hide_flags(),
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ def _probe_voice_duration_seconds(path: str) -> Optional[int]:
|
|||
proc = subprocess.run(
|
||||
["ffprobe", "-v", "error", "-show_entries", "format=duration",
|
||||
"-of", "default=noprint_wrappers=1:nokey=1", path],
|
||||
capture_output=True, text=True, timeout=5,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=5,
|
||||
)
|
||||
if proc.returncode == 0:
|
||||
return _coerce_duration_seconds(proc.stdout.strip())
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ def _git_show(ref: str, path: str, repo_root: str) -> str | None:
|
|||
proc = subprocess.run(
|
||||
["git", "show", f"{ref}:{path}"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
cwd=repo_root,
|
||||
)
|
||||
return proc.stdout if proc.returncode == 0 else None
|
||||
|
|
@ -125,7 +125,7 @@ def _tracked_lockfiles(ref: str, repo_root: str) -> set[str]:
|
|||
proc = subprocess.run(
|
||||
["git", "ls-tree", "-r", "--name-only", ref],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
cwd=repo_root,
|
||||
check=True,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -246,7 +246,7 @@ def upload_evidence(
|
|||
],
|
||||
check=True,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
env=environment,
|
||||
)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ class ScratchDashboard:
|
|||
]
|
||||
self.proc = subprocess.Popen(
|
||||
cmd, cwd=str(REPO_ROOT), env=env,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1,
|
||||
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, encoding="utf-8", errors="replace", bufsize=1,
|
||||
)
|
||||
threading.Thread(target=self._drain, args=(self.proc.stdout,), name="dash-log", daemon=True).start()
|
||||
if not self._ready.wait(timeout=90.0):
|
||||
|
|
|
|||
|
|
@ -2097,7 +2097,7 @@ def git(*args, cwd=None):
|
|||
"""Run a git command and return stdout."""
|
||||
result = subprocess.run(
|
||||
["git"] + list(args),
|
||||
capture_output=True, text=True,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace",
|
||||
cwd=cwd or str(REPO_ROOT),
|
||||
)
|
||||
if result.returncode != 0:
|
||||
|
|
@ -2111,7 +2111,7 @@ def git_result(*args, cwd=None):
|
|||
return subprocess.run(
|
||||
["git"] + list(args),
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
cwd=cwd or str(REPO_ROOT),
|
||||
)
|
||||
|
||||
|
|
@ -2591,7 +2591,7 @@ def main():
|
|||
if gh_bin:
|
||||
result = subprocess.run(
|
||||
gh_cmd,
|
||||
capture_output=True, text=True,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace",
|
||||
cwd=str(REPO_ROOT),
|
||||
)
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ def _run_one_file_once(
|
|||
cwd=repo_root,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
env=os.environ,
|
||||
# POSIX: place the child at the head of its own process group so
|
||||
# _kill_tree can SIGKILL the group atomically.
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ def accept_changes(
|
|||
result = subprocess.run(
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=30,
|
||||
check=False,
|
||||
env=get_soffice_env(),
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ class RedliningValidator:
|
|||
str(modified_file),
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
|
||||
if result.stdout.strip():
|
||||
|
|
@ -229,7 +229,7 @@ class RedliningValidator:
|
|||
str(modified_file),
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
|
||||
if result.stdout.strip():
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ class RedliningValidator:
|
|||
str(modified_file),
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
|
||||
if result.stdout.strip():
|
||||
|
|
@ -229,7 +229,7 @@ class RedliningValidator:
|
|||
str(modified_file),
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
|
||||
if result.stdout.strip():
|
||||
|
|
|
|||
|
|
@ -192,6 +192,8 @@ def convert_to_images(pptx_path: Path, temp_dir: Path) -> list[Path]:
|
|||
["--headless", "--convert-to", "pdf", "--outdir", str(temp_dir), str(pptx_path)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
encoding="utf-8",
|
||||
errors="replace",
|
||||
)
|
||||
if result.returncode != 0 or not pdf_path.exists():
|
||||
detail = (result.stderr or result.stdout or "").strip()
|
||||
|
|
@ -207,7 +209,7 @@ def convert_to_images(pptx_path: Path, temp_dir: Path) -> list[Path]:
|
|||
str(temp_dir / "slide"),
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
)
|
||||
if result.returncode != 0:
|
||||
raise RuntimeError("Image conversion failed")
|
||||
|
|
|
|||
|
|
@ -189,7 +189,7 @@ def _recalc_with_profile(filename, abs_path, timeout, profile_dir: Path):
|
|||
|
||||
try:
|
||||
result = subprocess.run(
|
||||
cmd, capture_output=True, text=True, env=get_soffice_env(), timeout=timeout + 15
|
||||
cmd, capture_output=True, text=True, encoding="utf-8", errors="replace", env=get_soffice_env(), timeout=timeout + 15
|
||||
)
|
||||
except subprocess.TimeoutExpired:
|
||||
return {"error": timed_out}
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ def _linux_x11_active_window_id() -> Optional[int]:
|
|||
proc = subprocess.run(
|
||||
["xprop", "-root", "_NET_ACTIVE_WINDOW"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=2,
|
||||
check=False,
|
||||
)
|
||||
|
|
@ -379,7 +379,7 @@ def _resolve_mcp_invocation(
|
|||
from tools.environments.local import _sanitize_subprocess_env
|
||||
proc = subprocess.run(
|
||||
[driver_cmd, "manifest"],
|
||||
capture_output=True, text=True, timeout=timeout,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout,
|
||||
stdin=subprocess.DEVNULL,
|
||||
# cua-driver is a third-party binary — never hand it provider
|
||||
# API keys via inherited env (same policy as the MCP and CLI
|
||||
|
|
@ -445,7 +445,7 @@ def _cua_driver_supports_no_overlay(driver_cmd: str) -> bool:
|
|||
from tools.environments.local import _sanitize_subprocess_env
|
||||
proc = subprocess.run(
|
||||
[driver_cmd, "--help"],
|
||||
capture_output=True, text=True, timeout=3.0,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=3.0,
|
||||
stdin=subprocess.DEVNULL,
|
||||
env=_sanitize_subprocess_env(cua_driver_child_env()),
|
||||
)
|
||||
|
|
@ -576,7 +576,7 @@ def cua_driver_update_check(*, timeout: float = 8.0) -> Optional[Dict[str, Any]]
|
|||
from tools.environments.local import _sanitize_subprocess_env
|
||||
proc = subprocess.run(
|
||||
[driver_cmd, "check-update", "--json"],
|
||||
capture_output=True, text=True, timeout=timeout,
|
||||
capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=timeout,
|
||||
# Some older drivers don't have the verb and fall through to a
|
||||
# stdin-reading mode rather than erroring — DEVNULL gives them EOF
|
||||
# so they exit fast instead of blocking until the timeout.
|
||||
|
|
@ -1256,7 +1256,7 @@ class _CuaDriverSession:
|
|||
for attempt in range(attempts):
|
||||
try:
|
||||
proc = _subprocess.run(
|
||||
cmd, capture_output=True, text=True, timeout=max(15.0, timeout),
|
||||
cmd, capture_output=True, text=True, encoding="utf-8", errors="replace", timeout=max(15.0, timeout),
|
||||
env=_sanitize_subprocess_env(cua_driver_child_env()),
|
||||
)
|
||||
except Exception as e: # pragma: no cover - subprocess spawn failure
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ def _popen_bash(
|
|||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
stdin=subprocess.PIPE if stdin_data is not None else subprocess.DEVNULL,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
**kwargs,
|
||||
)
|
||||
if stdin_data is not None:
|
||||
|
|
|
|||
|
|
@ -1377,7 +1377,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
subprocess.run(
|
||||
[self._docker_exe, "rm", "-f", container_id],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=30,
|
||||
check=False,
|
||||
stdin=subprocess.DEVNULL,
|
||||
|
|
@ -1701,7 +1701,7 @@ class DockerEnvironment(BaseEnvironment):
|
|||
container_id,
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=10,
|
||||
check=False,
|
||||
stdin=subprocess.DEVNULL,
|
||||
|
|
|
|||
|
|
@ -764,7 +764,7 @@ def _mandatory_aslr_enabled() -> "bool | None":
|
|||
"(Get-ProcessMitigation -System).Aslr.ForceRelocateImages.ToString()",
|
||||
],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=10,
|
||||
creationflags=windows_hide_flags(),
|
||||
)
|
||||
|
|
@ -830,7 +830,7 @@ def _bash_starts(bash: str) -> bool:
|
|||
result = subprocess.run(
|
||||
[bash, "--noprofile", "--norc", "-c", _BASH_EXTERNAL_PROGRAM_PROBE],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
text=True, encoding="utf-8", errors="replace",
|
||||
timeout=15,
|
||||
creationflags=windows_hide_flags() if _IS_WINDOWS else 0,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue