From 408d7ef28ecb5e34880ae48137ba72e98dacde03 Mon Sep 17 00:00:00 2001 From: ethernet Date: Fri, 18 Sep 2026 13:25:12 -0400 Subject: [PATCH] fix(update): name the reason launcher publication was skipped MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit publish_launchers returned silently when a tree was sealed, external, or had no managed interpreter. A PM tree promises its launchers — the e2e driver refuses to let `hermes --version` paper over the gap — so that last case is a half-finished update, not a quiet no-op, and it currently gives no way to tell which of the three conditions fired. Keep the same three conditions and the same returns; log which one. --- hermes_cli/venv_sync.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/hermes_cli/venv_sync.py b/hermes_cli/venv_sync.py index 66beb66daf..de88da3dcf 100644 --- a/hermes_cli/venv_sync.py +++ b/hermes_cli/venv_sync.py @@ -65,13 +65,26 @@ def check_runtime(project_root: Path) -> str | None: def publish_launchers(project_root: Path, *, create: bool = True) -> None: """Refresh durable commands; bootstrap repairs only existing PATH exposure.""" + import logging + from hermes_cli._launchers import ENTRY_POINTS, ensure_install_launchers, expose_cli, resolve_store_python from hermes_cli.steward import read_install_stamp root = Path(project_root) - if (_is_sealed(root) or read_install_stamp(root).get("updateMechanism") == "external" - or resolve_store_python(root) is None): + log = logging.getLogger(__name__) + if _is_sealed(root): + log.info("launchers: sealed tree at %s keeps its own", root) return # Sealed and external/Nix interpreters retain their own launchers. + if read_install_stamp(root).get("updateMechanism") == "external": + log.info("launchers: external runtime at %s keeps its own", root) + return + if resolve_store_python(root) is None: + # A PM tree promises its launchers (tests/install/e2e-assets/ + # source-driver.sh refuses to let --version paper over the gap), so + # this skip is a half-finished update, never a quiet no-op. + log.warning("launchers: no managed interpreter under %s; %s not published", + root, root / ".hermes" / "bin") + return written = ensure_install_launchers(root, root / ".hermes" / "bin") if len(written) != len(ENTRY_POINTS): from pm.package import InstallError