fix(pm): own interpreter selection and dependency recovery

Pin uv and uvx to the PM interpreter instead of ambient Python discovery.
A matching dependency stamp cannot prove that installed files still exist.
Repair now rebuilds the recorded workspace and lock in a fresh generation,
checks startup imports, and publishes the selection only after success.

Run startup recovery before dependency activation. Keep manual PM repair
reachable when the selected environment is damaged. Preserve plugin
selection, retry ownership, and the previous generation on failure.
Remove the separate pip, ensurepip, per-extra, and install-time quarantine
ladders. Keep orphan launcher restoration.

Verification: 717 targeted tests passed on native Windows ARM64, with
56 skipped. Ruff, diff checks, and the source-scoped compat check passed.
A disposable real Hermes install recovered deleted YAML and dotenv files,
then printed CLI help with exit 0. Its lock and stamp stayed unchanged.
The full suite and a release build were not run for this change.
This commit is contained in:
ethernet
2026-09-08 23:39:55 -04:00
parent f6db54ddf2
commit 8b7eae99ef
55 changed files with 1100 additions and 3441 deletions

View File

@@ -7,7 +7,6 @@ import logging
import os
import shutil
import subprocess
import sys
import uuid
from pathlib import Path
from typing import Any
@@ -141,11 +140,6 @@ def _uv_bridge(venv: Path) -> tuple[str, dict[str, str]]:
def _run_uv(uv_bin: str, env: dict[str, str], args: list[str], timeout: float) -> None:
# Pin the interpreter explicitly: pm's sanitized env strips UV_PYTHON, and
# without a pin uv's chooser can pick a different (e.g. PBS 3.14) runtime.
# sys.executable is the Hermes venv python — the side venv is fully
# isolated (own site-packages); this only fixes the BASE interpreter.
env = {**env, "UV_PYTHON": sys.executable}
result = subprocess.run( # noqa: S603 — fixed argv, no shell
[uv_bin, *args], env=env, capture_output=True, text=True,
encoding="utf-8", errors="replace", timeout=timeout,