diff --git a/hermes_cli/main_install_repair.py b/hermes_cli/main_install_repair.py index 22a73b9066..5db1acb0ff 100644 --- a/hermes_cli/main_install_repair.py +++ b/hermes_cli/main_install_repair.py @@ -452,16 +452,16 @@ def _run_install_with_heartbeat( t = threading.Thread(target=_heartbeat, daemon=True) t.start() try: - # stderr=STDOUT: uv/pip write progress to stderr. The desktop - # hand-off (scripts/desktop-update.ps1) only drains the child's - # stdout while the child runs, so a full stderr pipe (~64KB) - # blocks the installer forever. Merged into stdout, the output - # rides the pipe that IS drained. This module is imported when - # `hermes update` starts, so an update running from an old base - # executes the old copy regardless of the git reset — this - # protects updates initiated from bases that already ship it. - # (managed_uv.py gets the same fix AND is imported lazily after - # the reset, so its sync is protected even on old bases.) + # stderr=STDOUT: uv/pip write progress to stderr. Legacy desktop + # hand-offs (pre scripts/desktop-update/windows.ps1, which drains + # both pipes) only drain the child's stdout, so a full stderr + # pipe (~64KB) blocks the installer forever. Merged into stdout, + # the output rides the pipe old hand-offs DO drain. This module + # is imported when `hermes update` starts, so an update running + # from an old base executes the old copy regardless of the git + # reset — this protects updates initiated from bases that ship + # it. (managed_uv.py gets the same fix AND is imported lazily + # after the reset, so its sync is protected even on old bases.) subprocess.run(cmd, cwd=PROJECT_ROOT, check=True, env=env, stderr=subprocess.STDOUT) finally: done.set() diff --git a/hermes_cli/managed_uv.py b/hermes_cli/managed_uv.py index 223f0ece58..937e847acf 100644 --- a/hermes_cli/managed_uv.py +++ b/hermes_cli/managed_uv.py @@ -588,15 +588,15 @@ def _stage_candidate_venv( # and uv 0.12+ refuses --locked. sync_env = dict(env) sync_env.pop("UV_NO_CONFIG", None) - # stderr=STDOUT: uv writes progress to stderr. When the desktop - # hand-off (scripts/desktop-update.ps1) runs `hermes update`, it only - # drains the child's stdout while the child runs; a full stderr pipe - # (~64KB) blocks uv forever. Run 31453853006 hung 43 minutes in this - # exact call. Merging into stdout keeps the output streaming through - # the pipe that IS drained. This module is imported lazily by - # update_cmd AFTER the git reset, so even an update running from an - # old base executes THIS copy — unlike main.py, which is imported at - # startup and only protects bases that already ship its twin fix. + # stderr=STDOUT: uv writes progress to stderr. Legacy desktop + # hand-offs (pre scripts/desktop-update/windows.ps1, which drains + # both pipes) only drain the child's stdout while the child runs; a + # full stderr pipe (~64KB) blocks uv forever. Merging into stdout + # keeps the output streaming through the pipe old hand-offs DO + # drain. This module is imported lazily by update_cmd AFTER the git + # reset, so even an update running from an old base executes THIS + # copy — unlike the heartbeat helper (main_install_repair.py), which + # is imported at startup and only protects bases that ship its twin. synced = subprocess.run( [uv_bin, "sync", "--extra", "all", "--locked", "--python", str(_venv_python(candidate))], cwd=project_root, env=sync_env, stderr=subprocess.STDOUT, check=False)