fix(cli): don't resolve venv python into Linux desktop Exec= - #97992
flowersjus wants to merge 1 commit into
Conversation
Path(sys.executable).resolve() follows venv/bin/python to the base interpreter (/usr/bin/python3.N or the uv store). The .desktop entry then launches that interpreter, dies on ModuleNotFoundError: hermes_cli, and shows nothing because Terminal=false. Also stop substring-matching the interpreter dir against the shebang: /usr/bin sits inside #!/usr/bin/env python3 and would skip the NousResearch#90292 prefix. Treat env shebangs as always needing the running interpreter.
andrexibiza
left a comment
There was a problem hiding this comment.
Reviewed exact head 9d268ffe5224ee8176b82c450d4daa7dbed2c189 against main@3f36c87e1ebdfbf7d14a88229dc9be222c12ea89.
Keeping sys.executable lexical rather than resolving through the venv symlink is the correct repair for the reported uv escape, and the new symlink regression binds that positive case. One runtime blocker remains in the broadened shebang classification; I left it inline.
Fresh-state adversarial receipt, using real interpreters and a clean desktop-style environment:
uv symlink positive control: candidate needs prefix = False
env -S absolute-venv shebang: baseline needs prefix = False
env -S absolute-venv shebang: candidate needs prefix = True
direct valid shebang under env -i: exit 0, stdout = venv-ok
candidate-emitted /usr/bin/python3 <script>: exit 1, ModuleNotFoundError
The parser must distinguish PATH-dependent #!/usr/bin/env python... from env -S forms that already pin an absolute interpreter, preserve path case, and retain interpreter flags. Add the executable regression, not only a rendered-string assertion.
Before merge, consolidate the existing implementation graph rather than landing another synonymous repair. Prior work by GitTradWang in #94058/#94051, jackulau in #92090, and gokhanyildirimlar in #94874 already covers parts of this exact parser and verification matrix; mojtabazn's #97983 is the new duplicate report. Preserve those credits and add the repo-template closing interlock to the selected canonical issue.
Exact-head CI is not green evidence yet: the CI run is action_required with zero jobs executed: https://github.com/NousResearch/hermes-agent/actions/runs/33261474514
| # it. Do not substring-match the interpreter dir against the shebang: | ||
| # ``/usr/bin`` is inside ``/usr/bin/env python3`` and would skip the | ||
| # prefix (#90292) *and* is the follow-symlink target of venv/bin/python. | ||
| if Path(prog).name == "env": |
There was a problem hiding this comment.
Blocker — this blanket env branch converts a valid launcher into a broken one. env does not always mean PATH-dependent env python3: GNU env -S can pin an absolute venv interpreter and its required flags, e.g. #!/usr/bin/env -S /opt/hermes/venv/bin/python -I.
At this head, with sys.executable == /usr/bin/python3, the baseline classifier leaves that launcher direct, but this branch returns True solely because prog is env and emits /usr/bin/python3 <script>. In an isolated executable repro, the direct shebang exits 0 and imports a dependency installed only in the pinned venv; the emitted command exits 1 with ModuleNotFoundError. It also discards -I because Python is now handed the script as an argument.
Parse the original-case shebang tokens. Prefix only PATH-dependent env python* forms; for env -S with an absolute Python target, compare that target by path components/environment identity and preserve its flags. Add the clean-environment subprocess regression.
Bug Description
After
hermes desktop(and after every rebuild/update), the Linux menu entry is rewritten with anExec=that launches system Python. The icon does nothing.hermes desktopfrom a TTY still works.Reproduced on EndeavourOS / Hyprland, git install,
venv/bin/python -> /usr/bin/python3.11:That command exits 1 with
ModuleNotFoundError: No module named 'hermes_cli'.Terminal=false, so the DE shows nothing.Related: #90292 (partially addressed by #90492), #92095, #94110, #94058.
There are already open PRs on the same class of bug (#92090, #94051, #96685). This one is the smallest delta that also closes a
#90292hole the others still have: substring-matching the interpreter dir against the shebang, so/usr/binmatches#!/usr/bin/env python3and skips the venv prefix.Root Cause
Path(sys.executable).resolve()followsvenv/bin/python(symlink) to/usr/bin/python3.Nor the uv store. CPython only activates a venv via the unresolved argv[0] +pyvenv.cfg._needs_interpreterusedexe_dir not in shebang. After (1),exe_diris/usr/bin, which is not in#!…/venv/bin/python3, so a correct venv console-script was classified as foreign and got the system interpreter prefixed. The same substring also matches#!/usr/bin/env python3, which would skip the Linux desktop entry generated with non-runnable Exec; icon launch always fails #90292 prefix.Fix
sys.executablewithout following the symlink.envshebangs as always needing that prefix.How to Verify
venv/bin/pythonis a symlink to a base interpreter.hermes desktoponce from a TTY.awk -F= '/^Exec=/{print substr($0,6)}' ~/.local/share/applications/hermes.desktop/usr/bin/pythonor~/.local/share/uv/python/……/venv/bin/hermes desktopor~/.local/bin/hermes desktopor…/venv/bin/python …/hermes desktopTest Plan
Exec=tests/hermes_cli/test_linux_desktop_entry.py: 16 passed, 2 skipped)~/.local/bin/hermes --versionworks)Risk Assessment
Low — Linux
.desktopwriter only. macOS/Windows unchanged. Shell-wrapper launchers still left alone.#90292env-shebang prefix still applied, now with the venv path instead of the base interpreter.