Enabling a plugin with Python dependencies, and `hermes pm install`, failed
in the packaged Windows app: uv lock/sync/pip check exit 101 with "Unable to
create process using ...\venv\Scripts\python.exe".
uv queries a venv by running its Scripts\python.exe. That redirector lives
outside the package and CreateProcess's the interpreter named by
pyvenv.cfg `home`. 6a031bf1b3 moved generations onto the packaged
interpreter, so `home` names a file under WindowsApps that a process without
package identity may not start (exit 101 is the redirector's
RC_CREATE_PROCESS). Restore the verified writable copy of the pinned Python
in the user store as the build interpreter for sealed Windows payloads.
venv_command (also from 6a031bf1b3) stays: Hermes still enters those venvs
on the packaged interpreter, so its own children keep package access to the
bundled git, rg and PM worker.
A sealed Windows payload copied its pinned Python to %LOCALAPPDATA% so
uv-built venvs had a reachable redirector target. Every process started
from that copy then sat outside the package and could not start the
package's executables (WinError 5): bundled git, rg, the PM worker.
Build generations on the bundled interpreter instead and never run a
venv's own executables there. pm.environments.venv_command returns the
argv that enters a venv: on a sealed payload, the payload Python with -S
plus pm/_venv_entry.py, which attaches the venv's site-packages (and its
.pth files) and runs a script, -c or -m; elsewhere the venv interpreter.
Recovery's startup validation and the plugin capability probe use it.
A sealed payload's venv Scripts dir stays off PATH.
Verified (macOS): new venv_command contract tests run scripts, -c and -m
through a payload layout whose venv interpreter is a trap that exits 99.
tests/pm + plugin/source/update-completion suites: 1175 passed; the 5
failures also fail on origin/main in this environment.
Not verified: a real MSIX. uv execs the venv interpreter to query it
during sync/pip (confirmed on macOS by trapping venv/bin/python), so
plugin installs depend on uv, a child of the in-package PM worker,
keeping package access to that redirector.
The long-path commits now on onboarding/next spell PM's store root extended-length (\\?\) on Windows, and _toolchain returned uv and Python under that root. Its callers run and compare those paths outside PM's own file calls, and on main they got the ordinary path. tests/pm/test_uv_python.py::test_bundled_uv_uses_a_verified_writable_python_without_changing_runtime fails on both Windows lanes for that reason. Return native() spellings; the existence checks inside still use the store's.
(cherry picked from commit acad756e33)
Some PM code reaches a store root from paths.store_root() or
writable_store_root() directly instead of through Store, so its file
calls kept the ordinary spelling and stay cut at MAX_PATH on Windows
with LongPathsEnabled=0. Worse, its comparisons against a Store root
(now \\?\-spelled) never matched.
Each such root now gets long_root() once, where the variable is born:
- Facts.refresh_digests digests whole payload tool trees;
- verified_tools walks and digests the source store's tool trees;
- the uv cache seed copies the payload's deep uv-cache tree out;
- _toolchain's writable store, so `location.root != writable` compares
like with like and the copy store is built from the same spelling;
- _installed_location passes store.root to Facts.installed;
- ensure() picks the shipped facts by comparing two Store roots;
- the corrupt-facts guard compares both sides spelled long.
Returned and exported paths stay ordinary (previous commit).
`import pm.ensure` bound the submodule onto the package, shadowing the facade's
`pm.ensure()` function for every later caller in the process (photon's sidecar
start hit `'module' object is not callable`). The module is pm.install now; the
function keeps its name. The facade resolves through `__import__` rather than
`importlib.import_module` so a test that patches import_module globally does not
break attribute access on pm.
tools/lazy_deps.py returns to the 16-line stop_for_relaunch shim the branch wrote
(an origin/main merge had replaced it with main's 775-line implementation); the
project-metadata tests follow. update_cmd re-exports the four old_updater_deps
names the shim tests resolve through hermes_cli.update_cmd.