Commit Graph

9 Commits

Author SHA1 Message Date
Teknium 2c7f5d12b5 refactor(hclib): cron/update/install lifecycle — cron status, update_* receipts and recovery, install repair, service manager 2026-09-02 14:45:25 -07:00
liuhao1024 46ac31e84c fix(desktop): sanitized deferral evidence for ledgered manual serve blockers
The Desktop venv-blocker scan (since #99724) defers ledger-verified
serve/dashboard holders to the CLI updater's stop+relaunch rungs, but the
scan output only carried an opaque deferred_backends count — nothing
explained WHICH holders the deferral consumed or why they vanished from
processes.

Add sanitized decision evidence (#98350): deferred_backend_evidence lists
structured ledger identity only (pid, purpose, recorded port) — never the
command line, which can carry tokens or private endpoints. Adds a desktop
parser contract fixture proving the consumer tolerates the diagnostics
while keeping blocked/processes authoritative.

Salvaged from PR #98350; the exemption half of that PR was independently
consolidated on main via #99724 (_is_updater_owned_backend).
2026-09-01 01:30:09 -07:00
Teknium 3783fd9ffe fix(update): defer ledger-verified serve/dashboard holders to the updater instead of dead-ending the Desktop hand-off
On Windows, the Desktop update preflight scan (hermes_cli._scan_venv_blockers)
classified only python -m http.server as a stoppable blocker. A hermes serve
or dashboard backend that survived the Desktop teardown (or was launched
manually) either dead-ended the hand-off with venv-blocked, or slipped past
it and kept venv\Scripts\hermes.exe mapped, so the updater quarantine
failed with os error 32 (#98336).

The CLI updater downstream already owns exactly this holder class with
positive-identity rungs: _ledger_reapable_backend_pids reaps dead-spawner
orphans and _ledger_manual_serve_holders stops manual serves and relaunches
them on their recorded host/port. Mirror the existing pausable-gateway
exemption: defer ledger-verified serve/dashboard holders to those rungs
instead of reporting them as blockers.

Identity is positive-only, per the #99558 guard contract: token-parsed
subcommand (never substring, #90778) + live-verified (pid, create_time)
ledger entry with matching purpose + provable ownership (spawner dead,
unrecorded, or the hand-off Desktop itself — an ancestor of the scan,
verified by pid+create_time). A backend supervised by any other live
process keeps blocking; ledger unreadable fails closed.

Fixes #98336
2026-08-31 13:11:54 -07:00
Ryan Hart 7af27c65ab fix(desktop): close safe preview blockers before update 2026-08-16 02:03:22 -07:00
HexLab98 18b442cdeb fix(install): abort Windows venv recreate when rename-aside fails
When Rename-Item on the live venv is denied, do not fall back to an
in-place Remove-Item that can gut site-packages and leave no rollback.
Also mark venv-blocker probe failures with probe_failed so they cannot
be read as a clear scan (#83149).
2026-08-14 21:58:09 -07:00
Teknium 0b33ee88e4 fix(update): don't truncate cmdlines in the venv-blocker scan — it broke the gateway exemption
_detect_venv_python_processes() returned cmdline_raw[:120]. Gateways
autostarted via the managed-runtime interpreter carry a >120-char exe path
(.hermes-runtime\python\generation-...\cpython-3.11-...), so the truncated
cmdline ended inside the exe path, before '-m hermes_cli.main gateway run'.
The Desktop preflight's pausable-gateway exemption
(_scan_venv_blockers._is_pausable_gateway) therefore never matched, the
gateway was reported as a blocker, and every Desktop update aborted with
'Update didn't finish' even with all windows closed — the updater's own
gateway pause never got a chance to run.

Fix: return the full cmdline from the detector and truncate only at
display time (_format_venv_python_holders_message and the scan's JSON
cmdline field, after redaction).

Reproduced live on Windows 11: scan reported blocked=true for
'...cpython-3.1' (truncated); after the fix the same gateway pair scans
clear with pausable_gateways=2.
2026-08-08 18:58:06 -07:00
iso2kx f3edd0e538 fix(desktop): use the canonical gateway matcher for the preflight exemption
_is_pausable_gateway() hand-rolled a second gateway parser and regressed
a valid form: in `--profile gateway gateway run` the profile VALUE
shadowed the subcommand token, so the scan reported that gateway as a
fatal preflight holder. Delegate to
gateway.status.looks_like_gateway_command_line() - profile-selector
aware, shlex-tokenizing, run-only - so the preflight exemption, the
pause discovery, and the updater's guard fallback share one parser.
Non-run gateway subcommands, serve backends, and REPLs still block; the
bare-`gateway` form now classifies as a running gateway, mirroring the
canonical matcher's contract.
2026-07-31 22:34:28 -07:00
iso2kx 0bec37aefc fix(desktop): don't report pausable gateways as venv-update blockers
The Desktop update preflight (`scanVenvBlockers` -> `python -m
hermes_cli._scan_venv_blockers`) reports every venv-side python as a
blocker and aborts the handoff:

    main.ts: scanVenvBlockers(...)                  <- aborts HERE
             return { ok:false, error:'venv-blocked' }
             spawnUpdaterProcess(hermes-setup ...)  <- never reached

But a *gateway* is not a dead-end holder. `hermes-setup` invokes
`hermes update --yes --gateway`, and the CLI updater's
`_pause_windows_gateways_for_update()` gracefully drains and stops
running gateways before touching the venv — machinery added for exactly
these processes (#50090 and follow-ups). The preflight replicated the
CLI's *guard* without its *pause*, so a Windows service-mode gateway
(e.g. a Scheduled Task running `gateway run`) made every Desktop update
abort forever with

    [updates] venv-blocked: N process(es) hold the install
      PID ... python.exe ... -m hermes_cli.main gateway run --replace

while the component one layer down was never allowed to run and handle
it. The abort points at a process the updater knows how to stop.

Fix: `_is_pausable_gateway()` exempts `hermes_cli.main ... gateway run`
invocations (both halves of the venv-shim launcher/worker chain match,
since the uv-side worker re-runs the same argv). Everything else keeps
blocking — the Desktop `serve` backend, other `gateway` subcommands,
operator REPLs and stray scripts have no pause machinery downstream.
The CLI updater's own post-pause venv guard is untouched, so a pause
that genuinely fails still aborts before any .pyd mutation.

The JSON gains a diagnostic `pausable_gateways` count. The TS consumer
validates only `ok`/`blocked`/`processes` and ignores unknown keys, so
old and new Desktop builds both accept the new document; no Electron
rebuild is required for the fix to take effect (the scan runs from the
repo's Python).
2026-07-31 22:34:28 -07:00
atakan g d210500b54 fix(desktop): surface external venv update blockers 2026-07-28 14:47:36 -07:00