Commit Graph

4 Commits

Author SHA1 Message Date
ethernet
bbec973514 refactor(pm): pm owns the dependency-environment layout and interpreter paths
hermes_cli.runtime_paths (venv generations, selection, activation) moves to
pm.environments, and gains venv_bin_dir / venv_python / project_python. Every
in-tree caller asks pm for an interpreter now; pm no longer reaches back into
hermes_cli for its own environment layout (pm.packages, pm.extras, pm.ensure,
pm.paths imported hermes_cli.runtime_paths). The three open-coded
"Scripts/python.exe or bin/python" ladders in pm collapse onto venv_python.

hermes_constants.venv_python_path / venv_bin_dir and hermes_cli.runtime_paths
stay as frozen-updater-surface shims only (tests/compat/old_updater_surface.json).

To keep the boot path light, pm/__init__ resolves its facade lazily (PEP 562)
and pm.registry loads the built-in package definitions on first read instead of
at import: `import hermes_bootstrap` now loads pm + pm.environments only (25ms,
was 37ms with the eager facade dragging in the downloader). The stripped-payload
fixtures that ship only pre-import files keep working for the same reason.

Also restores two frozen-surface re-exports the F401 sweep dropped
(banner._github_compare_behind, cua_backend.resolve_cua_driver_cmd).
2026-09-18 20:02:36 -04:00
ethernet
dbe4bfbc06 fix(update): keep --finish-update through the completion self re-exec
source_completion.py re-execs itself into PM's selected interpreter before
touching any product, and the passthrough argv only carried --desktop. So
the startup heal's --finish-update was dropped, and the prepared invocation
fell through to the install tail: an update reported itself as an install.

    ✓ Install complete! [main @ c4056e3d6b]

Every flag that decides WHICH tail runs has to survive that boundary.

Verified with a stub that captures the bootstrap command instead of running
it: --finish-update present in the re-exec, --desktop still passed, and
without the flag the install path is unchanged. File compiles.
2026-09-18 17:34:14 -04:00
ethernet
225fd5bcd6 fix(update): finish the whole source-update tail when a startup completes it
prepare_launch is the startup heal: it detects a stale PM generation
(pm.venv_is_current) and completes the update. But it only synced the
dependency generation and published the launchers -- so an install that
came through it landed in a different state than one that came through a
normal update or the installer.

The tail they share is complete_source_checkout (source_completion.py):
publish launchers, build the products, run the post-build maintenance.
"Its" own docstring: a fresh install and a finished update must land in the
same state, one implementation and two callers. The startup heal was a
third path taking a subset, and the e2e verifier caught exactly that -- it
requires ui-tui/dist fresh, which only build_update_products produces.

So drive the shared tail from the heal, the same way the installers do:
hand source_completion.py THIS interpreter (pre-sync, so it stays a
stdlib-only import for the old tree) and let it re-exec into PM's selected
python before touching any product. A failed tail is loud, matching
build_update_products' "a failed product aborts the update".

Verified: both files compile; the bare-3.11 pre-flip import check still
passes (bootstrap / prepare_launch / takeover_child, no third-party).
2026-09-18 14:50:06 -04:00
ethernet
dbeebaadfc refactor(install): one completion tail shared by install and update
The installer ladder stopped at node-deps/path/desktop with its own
semantics while an update ran launchers, product builds and post-build
maintenance, so a fresh install and a finished update ended in different
states: after re-running the installer at HEAD the products had no receipts
and the read-only source acceptance failed.

hermes_cli/source_completion.py now owns that tail -- publish launchers,
build the products, run the maintenance -- and update_completion's
_complete_selected calls it, so there is one implementation. install.sh and
install.ps1 keep the bootstrap stages (prerequisites, repository, venv,
python-deps, config) and hand off to it in a single `products` stage;
--include-desktop selects the desktop product inside that stage instead of
adding a second build stage, and `desktop` stays dispatchable via --stage for
external callers.

Windows keeps its installer-owned PATH publication (expose_cli answers
"windows-installer-owned" on Windows) plus the packaged-artifact probe, ACL
grant and shortcuts. The desktop stage no longer pre-syncs wake/voice: pm
lazy-installs them at first use, as the update path does.
2026-09-17 15:26:05 -04:00