A non-elevated Windows ARM64 install threw "run setup-hermes.ps1 in an
Administrator PowerShell" whenever Visual Studio ARM64 C++/Clang were
missing. Interactive runs now launch the signed VS installer through a
UAC prompt; CI, ssh and scheduled runs keep the explicit instruction.
Browser tools find agent-browser only in PM's store or on PATH and their
readiness check never installs it, so a fresh install silently had no
browser_* tools. Package.default marks an optional package that a bare
`pm install` also carries; a failed download of it warns instead of
failing the install. `pm install --without NAME` records the opt-out in
declined-packages.json beside PM's install state, and naming the package
explicitly clears it. agent-browser and chromium gain a Termux gap: Termux
owns its browser stack and there is no bionic Chromium.
Contributors had to run `python -m pm.build_env --source . --lock-only`, then
re-source activate, then call sync_venv for opt-in extras, while `hermes pm
lock` only pinned tool artifacts in pm/lock.json. Now `hermes pm lock` with no
arguments is the one step: it runs the same PM check_project_lock /
lock_project operations as build_env's --check-lock / --lock-only (same
exclude-newer quarantine), writes nothing when the lock is current, changes
no environment, and prints the activate command to run next. Activation
syncs [all] plus recorded extras only, and --test-extras replaces the
default, so a newly added extra outside [all] gets
`source ./activate --test-extras all,NAME` (`-TestExtras` on PowerShell).
`hermes pm lock --bump NAME VERSION` keeps writing pm/lock.json; NAME and
VERSION are now only accepted together. build_env --lock-only is unchanged
for scripts. Contributor docs, AGENTS.md, CONTRIBUTING.es.md, the pyproject
comment, and the uv.lock CI remediation text point at `hermes pm lock`.
cryptography ships no win_arm64 wheel, so every Windows ARM64 venv sync
compiles it from the sdist and needs MSVC, Clang, Rust and static OpenSSL.
Only setup-hermes.ps1 (and so activate.ps1) prepared that environment,
between a `pm install --tools-only` and the real sync. install.ps1,
`hermes update` and repair ran the same sync without it and failed in
openssl-sys.
PM owns the sync, so PM prepares it. pm/native_build.py holds the adapter
(moved from scripts/build/windows_deps.py) plus source_build_environment(),
which prepares only on win32-arm64 when the synced project carries the
provider script. A payload has prebuilt dependencies and needs no compiler.
VenvPackage.apply and build_environment pass the result to uv children
only. It carries the bridged pip index settings, which managed_environment
applies only to the ambient environment. The state root stays the store
parent, so existing vcpkg/OpenSSL builds are reused.
setup-hermes.ps1 collapses to one `pm install`: the tools-only split existed
only for this preparation, and pm install already puts its tools on PATH
before the venv sync (pm/cli.py activate check).
Not yet verified live on Windows ARM64.
source ./activate and . .\activate.ps1 always run setup, and setup always
runs `python -m pm.cli install`. An explicit install re-hashes every
published tool entry so it can repair a corrupted one. On this machine
that hash reads about 550 MiB and takes 6.0 of the 6.6 seconds, even
when nothing changed.
Shell activation now passes --trust-recorded and trusts the digest the
install recorded, the same check startup already uses. A missing tool
is still installed and a stale venv is still rebuilt. `hermes pm
install` and `hermes update` keep the byte check, and the flag refuses
names, --extra, and --target so it cannot narrow an install someone
asked for by name.
Measured on this machine, already up to date: the activation path drops
from 6.6 s to 0.9 s. A bare `python -m pm.cli install` stays at 7.2 s.
The remaining 0.9 s is process startup and imports, not hashing.
Windows PowerShell 5.1 returns every match from Get-Command. .Source on
that array joins the paths with a space, and the call operator then treats
the joined string as one program name. Git for Windows ships git.exe in
cmd\ and bin\, so setup died with CommandNotFoundException before pm
install ran.
setup-hermes.ps1 now installs the tool closure first (`pm install
--tools-only`), then prepares the ARM64 compiler environment, then syncs
the venv. The sync inherits that compiler environment. A bare `pm install`
and the update takeover path publish tools and put them on PATH before
uv sync. A missing tool stops the sync. A missing venv does not.
Verified: scripts/run_tests.sh on test_install_default_closure.py,
test_install_extra.py, and test_windows_build_deps.py — 13 passed.
Activation defined PATH and PYTHONPATH, but `hermes` still resolved to a
global command or an MSIX alias. The shell now defines `hermes` as a
function for this worktree. It runs this checkout's CLI only while the
shell is inside the tree, and it refuses outside it. The prompt gains a
branch prefix and drops it outside the tree. `deactivate` removes the
function and the prefix.
The five pages moved from docs/ into website/docs/developer-guide were
never added to sidebars.ts, so the site did not link them, and they kept
repo-relative links (../tests/..., ../scripts/..., ../website/docs/...)
that only resolved from the old docs/ location. Register them under a
Packaging & Releases category and point the repo-file links at GitHub;
package-management.md now links the moved completion note in place.
The termux-main pool deletes a package's previous archive when it rebuilds, so
the runtime-lib pin table and the bionic lock rows rot without warning. The last
rotation broke a build on eight rows at once, and the stager's concurrent
downloads only surfaced whichever 404 won the race.
pm now owns the pin table it repairs: scripts/termux/runtime_libs.json moves to
pm/termux_runtime_libs.json, so pins live in pm/ and scripts consume them — the
direction scripts/ci/archive_inputs.py already reads pm/lock.json in.
`hermes pm update --termux` repins exactly the rows whose archive the pool has
replaced, hashing each replacement against the index SHA256 before writing
url/version/hash together. `--check` reports without writing and exits 1, so a
retired pin can fail a cheap preflight instead of a payload build.
It is a repair, not an update: an alive pin is never moved, because a repin can
land a rebuilt library under a moved soname and the table is the payload's
recursive DT_NEEDED closure. A pin whose package the pool has dropped outright
is reported and left alone. `--termux` runs alone — names/--target/--uv/--npm
are ignored, since repairing foreign-target pins is not a version resolution.
Verified: `pm update --termux --check` against the live pool reports 89 rows
served; a table deliberately pinned to the retired libiconv 1.18-1 repins to
1.19 with the pool's hash through the real network path; 19 new tests; the
tests/pm, tests/ci and tests/scripts suites have the same failure set as the
base commit (91 pre-existing Windows environment failures, none new).
Dependency acquisition during packaging left native wheels and packager
inputs outside the pre-build cache save. Compose PM and existing providers
into a preparation phase, then require builds to consume admitted inputs.
Share native preparation with PM Bundle. Keep path-bound environments and
signing outputs separate from reusable caches. Use read-only cache tokens
for commit builds and preserve the one-command local build path.
Verify pinned tools through PM, probe PTYs under the prepared Electron,
and supply dmgbuild through a build-only PM package. Resolve bundled tool
stores from their payload manifest so relocation preserves discovery.
Validation: focused Python and JS tests, checkJs, Ruff, Windows checks,
anti-slop, cache relocation, and network-denied Linux AppImage builds.
Relocated runtime smoke passed with NixOS host libraries supplied.
Native Windows/macOS signing and live GitHub cache behavior remain untested.
Run historical updater completion in a fresh interpreter so cached imports
cannot revive retired dependency installers. Share Git and ZIP completion,
carry receipt and recovery state, and preserve child exit status.
Route plugin admission, binary acquisition, desktop launch and build paths
through PM. Replace redundant helpers and tests with real worker, package,
publication and launch checks. Keep the shipped compatibility surface fixed.
Targeted Python and desktop checks pass. Native update journeys and fresh
production image qualification remain pending. This is a checkpoint before
those acceptance runs.
Enable verbose uv output whenever PM streams a command so long native dependency builds expose package activity and backend stdout/stderr before failure.
Verify both sync and requirements installs with real offline uv builds that wait for their output to reach the parent. Both cases fail on the base and pass with this change.
PM owns Python dependency generations. Shared frontend builders own Node
preparation and compilation. Route source updates and launchers through
these owners instead of separate repair ladders.
Remove obsolete live-venv holder gates and soft build-failure plumbing.
Preserve source validation, staged publication, fleet outcomes, and
historical relaunch hooks.
Verification: 956 tests passed in the combined focused run, with 43 skips.
After the final ZIP exit fix, 583 focused tests passed. Shared JavaScript
builder tests, Ruff, and diff checks passed. Native Windows/macOS and full
packaged-app builds were not run.
Old updaters keep running after the checkout changes. Returning None
from their removed uv helpers enables a pip fallback against the new tree.
Keep the historical imports as inert shims and stop dependency entrypoints
with a relaunch message instead. Do not call PM or write recovery markers
from that mixed-version process.
Self-managed source launches use PM's successful input stamp to decide
when dependencies need a sync. Restart on the managed interpreter before
activating the selected generation. Preserve launcher forms and options,
and do not sync while a live updater owns the installation.
Targeted runtime batch: 225 passed, 8 platform skips. Real PM worker tests
build and publish disposable dependency generations, retain prior state on
failure, and exercise fresh-process relaunch before dependency activation.
The final launch guard test also passes. Full suite and native Windows
execution were not run locally.
Direct package installs bypass PM's dependency selection and do not survive
new generations. Document explicit runtime extras, recorded repair, fresh
build outputs, and lock generation through PM instead.
Keep the prepared-interpreter prerequisite and explicit removal requirement
for disposable test environments. Preserve Nix and external-project package
manager ownership. Correct platform and Python-marker claims where the
manifest contradicts the installation hints.
Checked the public CLI help, literal PM calls against public signatures and
extra declarations, fenced blocks, and whitespace. No dependency build or
site build ran. The docs toolchain is not installed in this checkout.
Standalone Python cannot locate the system CA bundle on this NixOS host.
Use the shell-staged uv to prepare the independent PM runtime before PM
fetches managed Python. Declare and lock truststore in that runtime, then
activate it before CLI and worker imports construct HTTPS clients.
Make setup's awk pin reader follow object nesting rather than indentation.
Use the same reader for tool versions and artifact fields.
Verified cold activation with CA overrides removed, pinned Python and uv
downloads, pm doctor, and a public worker HTTPS install. The targeted suite
passed 56 tests with one Windows-only skip. The TLS regression fails when
truststore is installed but entrypoint activation is removed. Bash syntax
and Ruff checks passed. The full suite was not run.
Two additional setup-toolchain tests fail on unchanged HEAD because their
fixtures reach the real home before home isolation. CI bootstrap unification
is not part of this change.
Source activation could not build cryptography because the setup shell
could not discover the installed OpenSSL development libraries.
Configure Visual Studio ARM64, Clang, Rust, and static OpenSSL before PM
runs. Reuse installed tools and install missing prerequisites. Select a
classic vcpkg with a ports tree and use an explicit installation root.
Report damaged shared libraries without deleting the shared installation.
Verified native PowerShell activation and deactivation on Promise, then
warm activation with no new dependency generation. Cryptography imported
with static OpenSSL. Real vcpkg checks covered installation into a path
with spaces, warm reuse, manifest mode, and damaged-package rejection.
The canonical Windows runner passed the helper and output-encoding tests.
Fresh Visual Studio and Rust installation were not exercised because
Promise already had those toolchains installed.
Activation reaches plugin discovery before the application dependencies
exist. Give PM its own locked Python project and runtime so it can install
or repair the application without importing that dependency tree.
Keep PM outside the application workspace. A shared uv workspace resolves
the application graph and cannot provide this isolation. Route mutations
through an isolated worker and preserve transaction callbacks, cancellation,
custom package registrations, and correlated receipts.
Use the same runtime builder for source installs and packaged payloads.
Keep offline wheelhouse support in that builder. Nix builds the independent
PM lock as a separate derivation. Refuse lazy-disabled bootstrap before
installing tools or dependencies.
Move first-party YAML readers and writers to ruamel. Keep the application
lock's transitive PyYAML requirements for third-party packages.
Verification:
- Focused canonical Python suite: 177 passed, 1 host-gated skip.
- Electron backend probes: 12 passed. Electron typecheck passed.
- Both uv locks, scoped lint, Bash syntax, and whitespace checks passed.
- Cold activation, corrupt-app repair, offline staging, and relocation ran.
- Built and exercised the Nix PM runtime and standalone YAML merge script.
Six broader caller test files retain the same 24 failing test IDs as an
archive of HEAD. The existing real-home guard blocks those tests before
they can exercise the affected paths. No full-suite pass is claimed.
Native Windows signing and full Bionic package execution remain unverified.
Keep the retry branch's bounded network policy under installation.
Preserve destination-local atomic publication, partial ownership,
representation checks, aggregate progress and operation-owned pause.
Keep the serial CDN fallback active across subsequent retry attempts.
Retain exact-origin authorization for index reads and safe redirects.
The retry policy does not retry hash, disk or certificate failures.
Verified with canonical native Windows ARM64 tests for both branches,
local-model download consumers, PM core and update resolution.
The commit-build draft remains uncommitted and unchanged.
Keep downloads bound to their remote representation and publish through
atomic destination-local staging. Serialize shared partial ownership.
Keep explicit CA trust scoped to provider probes. Preserve checkpoint
history and edited files, validate all profile inputs before dependency
publication, and separate data removal from installed runtime ownership.
Exclude machine-specific PM state from portable transfers. Keep plugin
files and nested skill tools intact. Preserve native test isolation.
Focused native Windows receipts cover the individual repairs and their
integration. This commit does not claim a full-suite or release build.
A transient HTTP 500 during the range probe aborted bundle staging.
Retry PM-owned requests and body transfers with one bounded policy,
instead of retrying complete installs or stacking caller retry loops.
Keep partial ranges across attempts and interrupt backoff on pause.
Keep the CDN serial fallback active until its source finishes. Do not
retry permanent HTTP errors, certificate failures, bad hashes or disk
errors. Use the same policy for metadata reads and artifact hashing.
Verified: 217 focused tests passed, 1 skipped, and Ruff passed on the
changed Python files. The pinned Windows ARM64 uv archive also survived
an injected HTTP 500 through the PM CLI and its installed binary ran.
The full suite and desktop release build were not run.
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.
Finish bootstrap uv before PM replaces its store entry. Keep failure
receipts stdlib-only and align the cryptography requirement and override
with the locked version.
Let bundle builders declare launch paths and update ownership. Remove
payload discovery, Store probing, and the unused develop command.
Derive Nix Python from the PM lock and share its provenance stamp.
Document setup, activation, optional dependencies, and distribution
ownership. Targeted Windows tests, relocated runtime launches, Electron
bundling, and bilingual docs builds pass. Native Nix and signed-package
acceptance remain CI gates.