Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion hermes_cli/_scan_venv_blockers.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@ def main() -> None:
{
"pid": pid,
"name": name,
"cmdline": _redact_sensitive_cmdline(cmdline),
# Truncate for display AFTER the gateway exemption has seen the
# full cmdline (long managed-runtime interpreter paths would
# otherwise swallow the `gateway run` argv).
"cmdline": _redact_sensitive_cmdline(cmdline)[:120],
}
for pid, name, cmdline in matches
if not _is_pausable_gateway(cmdline)
Expand Down
10 changes: 8 additions & 2 deletions hermes_cli/update_cmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -2926,7 +2926,13 @@ def _detect_venv_python_processes(
if not is_holder:
continue
name = info.get("name") or Path(exe).name
matches.append((int(pid), str(name), cmdline_raw[:120]))
# Return the FULL cmdline: callers match against it (the Desktop
# preflight's pausable-gateway exemption parses for `gateway run`).
# Truncating here cut long managed-runtime interpreter paths before
# the `-m hermes_cli.main gateway run` argv, so autostarted gateways
# were misreported as blockers and the update dead-ended. Truncate
# only at display time.
matches.append((int(pid), str(name), cmdline_raw))
return matches

def _format_venv_python_holders_message(matches: list[tuple[int, str, str]]) -> str:
Expand All @@ -2941,7 +2947,7 @@ def _format_venv_python_holders_message(matches: list[tuple[int, str, str]]) ->
hint = " ← Hermes Desktop backend (close the desktop app)"
elif "gateway" in low:
hint = " ← gateway"
lines.append(f" PID {pid} {name} {cmdline}{hint}")
lines.append(f" PID {pid} {name} {cmdline[:120]}{hint}")
if len(matches) > 6:
lines.append(f" ... and {len(matches) - 6} more")
lines.append("")
Expand Down
33 changes: 32 additions & 1 deletion tests/hermes_cli/test_scan_venv_blockers.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,4 +211,35 @@ def test_main_desktop_serve_backend_still_blocks(monkeypatch, capsys):
assert code == 0
assert data["blocked"] is True
assert [p["pid"] for p in data["processes"]] == [78]
assert data["pausable_gateways"] == 0
assert data["pausable_gateways"] == 0

def test_main_gateway_with_long_managed_runtime_path_is_exempt(monkeypatch, capsys):
"""Regression: the detector must hand the FULL cmdline to the exemption.

Gateways launched via the managed-runtime interpreter carry a >120-char
exe path (`.hermes-runtime\python\generation-...\cpython-3.11-...`).
The old `cmdline_raw[:120]` truncation in the detector cut the cmdline
before `-m hermes_cli.main gateway run`, so the exemption never matched
and every Desktop update aborted with 'Update didn't finish'.
Here the detector returns full cmdlines (post-fix contract); the scan
must exempt the gateway and truncate only the *displayed* cmdline.
"""
long_exe = (
r'"C:\Users\u\AppData\Local\hermes\hermes-agent\.hermes-runtime\python'
r"\generation-1785095035-66720-be29ea9c\cpython-3.11-windows-x86_64-none"
r'\python.exe"'
)
assert len(long_exe) > 120 # the truncation point was inside the exe path
gateway = (91, "python.exe", long_exe + " -m hermes_cli.main gateway run --replace")
code, data = _run_main_with_detector(monkeypatch, capsys, [gateway])
assert code == 0
assert data["blocked"] is False
assert data["processes"] == []
assert data["pausable_gateways"] == 1

# A long-path NON-gateway holder still blocks, with cmdline truncated for display.
stray = (92, "python.exe", long_exe + " -m some_other_module --serve-forever")
code, data = _run_main_with_detector(monkeypatch, capsys, [gateway, stray])
assert data["blocked"] is True
assert [p["pid"] for p in data["processes"]] == [92]
assert len(data["processes"][0]["cmdline"]) <= 120
Loading