pwsh has no Get-WmiObject; it proxies the cmdlet through a Windows
PowerShell compat session, and the ManagementClass comes back
deserialized with its methods stripped, so Win32_ShadowCopy.Create
failed ("does not contain a method named 'Create'") and Delete would
have too. Invoke-CimMethod / Get-CimInstance / Remove-CimInstance are
native in both 5.1 and 7. Under CIM, Win32_ShadowStorage.Volume is a
CimInstance reference, so match on its DeviceID instead of the WMI
path string.
The smoke preferred powershell.exe over pwsh, so it never ran the kit
under pwsh; it now runs the kit under the host running the smoke.
cp -c clones file by file: 21.5s for a real 148k-entry HERMES_HOME. APFS
clones a whole directory tree in a single clonefileat(2), which a stock Mac
can call through /usr/bin/perl: 5.9s for the same home, identical in name,
type, size, mode, mtime and link target. The kernel stamps cloned
directories with the current time, so a second pass restores each
directory's atime/mtime. On any failure the entry is removed and cloned
with cp -c instead, with a warning the smoke test asserts is absent.
pre tarred the entire HERMES_HOME and post extracted it over an emptied
home: two full copies of a tree that is mostly node_modules and venvs.
pre now takes a `hermes backup` of the user's data, then clones every
top-level entry of HERMES_HOME except cache/ (and the Electron userData)
into the backup dir: copy-on-write where the filesystem can (clonefile on
APFS, reflink on btrfs/xfs), a plain copy elsewhere. post moves the live
entries aside and the clones in, by rename only, so the home directory
itself never moves (it may be a mountpoint or symlink target) and cache/
stays where it is. It then deletes the moved-aside post-update trees;
hermes-backup.zip is never deleted.
Windows deletes a VSS snapshot once the old copies of rewritten blocks
exceed the volume's shadow-storage cap, which defaults to ~1% of the disk
(17.8 GB on a 1.8 TB drive). A long rehearsal with other disk activity can
blow that and cost the tester the rollback.
pre now raises the cap to 128 GB (a ceiling, not a reservation) right after
taking the snapshot, recording the exact original in shadowstorage.txt; post
puts it back, also on the snapshot-gone path. An already-larger cap is left
alone.
pre tarred the entire HERMES_HOME, which is slow on a real home (hundreds of
thousands of files) and silently left out files other processes held open:
on a live 33GB home the tar came out at 4.7GB with no error.
pre now takes a `hermes backup` of the user's data, then a Volume Shadow
Copy snapshot of the volume(s) holding HERMES_HOME and the Electron userData.
The snapshot is copy-on-write: 2s, nothing copied, locked files included.
post checks every snapshot still exists before touching anything, then
robocopy /MIR's both trees back from it (only changed files are copied,
files the update added are deleted; HERMES_HOME\cache is left alone), and
deletes the snapshot. If Windows dropped the snapshot, post changes nothing
and points at the hermes backup zip instead.
pre and post now need an elevated PowerShell.
The script's .EXAMPLE and HANDOFF.md told Windows users to pass --source,
--ref and --yes, which PowerShell rejects as extra positional arguments.
Use -Source, -Ref and -Yes.
A checkout-sized tar sits silent for a minute plus, which reads like a
hang. bsdtar (macOS) and GNU tar disagree on progress options, so poll
the growing archive and overwrite the line every 2s; the loop doubles
as a liveness signal and the final wait still propagates tar's exit.
The backup root is typically the same internal disk, so the size saving
buys nothing; measured on an M1 over a 3.3G checkout, gzip made the
backup 5x slower (74s vs 14s). Store hermes-home.tar and
electron-userdata.tar uncompressed.
Hand-off kit for proving an existing source install can move to a
branch through the real update surfaces: pre (backup + arm a
transport-level insteadOf redirect at a serve.git of the target ref),
then 'hermes update', then post (rollback + restore-exactness report).
PLAN.md holds the design; smoke-test.* is the maintainer self-check.