fix(tools): fold ~/.local/bin into the POSIX PATH completion siblings, tests + docs
Slim follow-up to the salvaged #111790: the helper becomes a list-returning sibling of _managed_runtime_path_entries (same shape, same "only when it exists" convention) and loses the Windows check the caller already performs. Why here and not in the Electron remote spawn: propagating the login-shell PATH that locateHermes discovered into `exec env HERMES_DESKTOP=1 … hermes serve` would fix only the Desktop SSH surface; the terminal environment's PATH completion is the seam every thin-PATH launcher (SSH, systemd, launchd, cron) already goes through, so the class closes once. Windows twin out of scope. Tests move to the mirror dir tests/tools/environments/ with an absent-dir control; FAQ documents the terminal PATH composition. Fixes #111778
This commit is contained in:
+12
-15
@@ -552,30 +552,27 @@ def _managed_runtime_path_entries() -> list[str]:
|
||||
return []
|
||||
|
||||
|
||||
def _existing_user_local_bin_dir() -> str | None:
|
||||
"""Return the POSIX user's ``~/.local/bin`` only when it exists."""
|
||||
if _IS_WINDOWS:
|
||||
return None
|
||||
candidate = Path.home() / ".local" / "bin"
|
||||
return str(candidate) if candidate.is_dir() else None
|
||||
def _user_local_bin_entries() -> list[str]:
|
||||
"""``~/.local/bin`` when it exists — the pip --user / pipx / uv-tool install
|
||||
target. A backend launched by a non-interactive SSH session, systemd or a GUI
|
||||
launcher inherits a PATH without it (only the login shell adds it), so CLIs
|
||||
installed there were ``command not found`` from the terminal tool (#111778)."""
|
||||
local_bin = Path.home() / ".local" / "bin"
|
||||
return [str(local_bin)] if local_bin.is_dir() else []
|
||||
|
||||
|
||||
def _append_missing_sane_path_entries(existing_path: str) -> str:
|
||||
"""Normalised POSIX PATH with missing sane entries appended: empty entries
|
||||
dropped (shells read them as cwd), duplicates collapsed (first wins), then
|
||||
missing ``_SANE_PATH``, managed-runtime dirs, and an existing user-local bin
|
||||
dir appended so inherited/login-shell entries keep precedence. Windows is a
|
||||
no-op passthrough (native ``;`` PATH untouched)."""
|
||||
missing ``_SANE_PATH`` / managed-runtime / ``~/.local/bin`` dirs appended so
|
||||
user entries keep precedence. Windows is a no-op passthrough (native ``;``
|
||||
PATH untouched)."""
|
||||
if _IS_WINDOWS:
|
||||
return existing_path
|
||||
# dict preserves first-occurrence order; empty entries dropped.
|
||||
ordered = dict.fromkeys(entry for entry in existing_path.split(":") if entry)
|
||||
user_local_bin = _existing_user_local_bin_dir()
|
||||
ordered.update(dict.fromkeys([
|
||||
*_SANE_PATH.split(":"),
|
||||
*_managed_runtime_path_entries(),
|
||||
*([user_local_bin] if user_local_bin else []),
|
||||
]))
|
||||
ordered.update(dict.fromkeys([*_SANE_PATH.split(":"), *_managed_runtime_path_entries(),
|
||||
*_user_local_bin_entries()]))
|
||||
return ":".join(ordered)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user