Commit Graph

44905 Commits

Author SHA1 Message Date
teknium1
029445545c fix(gateway): keep the update restart watcher stdlib-only so it survives the bare store Python
After the package-manager handoff, hermes update finishes on the bare store
interpreter and spawns the detached restart watcher as sys.executable -c.
The watcher imported gateway.status (utils -> hermes_yaml -> ruamel) and
hermes_cli.config, died with ModuleNotFoundError before relaunching, and
left every manually started gateway down after the update (gated on #124649).

Move the stdlib liveness probe (zombie-aware POSIX kill(0), Windows
OpenProcess) into hermes_cli._subprocess_compat, have gateway.status's
fallback delegate to it, and import only stdlib-backed modules in the
watcher.

Fixes #124649.
2026-09-27 03:37:09 -07:00
teknium1
07be7d47ed fix(bootstrap-installer): write the shared receipt schema and resolve the commit without git
Hermes-Setup.exe replaced install.ps1's .hermes-bootstrap-complete with its
own copy: completedAtUnix instead of the completedAt every other writer and
reader uses (install.ps1, Electron main, hermes_cli/source_stamp.py,
scripts/verify-bootstrap-version-stamp.py), and a pinnedCommit from a bare
`git rev-parse HEAD`, which is null on a machine where git exists only as
the PM-staged binary install.ps1 uses.

The receipt now carries completedAt (UTC ISO-8601, milliseconds), and the
commit resolves like install.ps1's Stage-Complete: the pinned commit, else
the checkout HEAD read from its ref files (loose ref or packed-refs), else
the full sha install.ps1 already recorded (read BOM-tolerant).

Fixes #124949
2026-09-27 03:35:26 -07:00
teknium1
80512c90dc fix(website): batch the plugin stars probe at 100 repos per GraphQL request
A single request for all 317 catalog repos now exceeds GitHub's per-query
resource limit: the reply carries partial data plus an error, the script
prints 'Probed 317', and every repo past the limit keeps its stale count
(hindsight showed 26.5k stars while GitHub had 34.5k). Batch at 100; probed
live: 317/317 repos in 4 requests, no errors.
2026-09-27 03:34:56 -07:00
teknium1
e2abb460b6 fix(website): put the repo root on sys.path before importing hermes_yaml in the stars probe
The scheduled Build Skills Index run executes
`python website/scripts/fetch-plugin-stars.py --probe`, so sys.path[0] is
website/scripts and the repo-root `hermes_yaml` shim it now imports is not
importable. Every scheduled probe since 2026-09-24 died with
ModuleNotFoundError, the live plugin-stars.json froze at that date, and the
41 catalog entries added since have no star count: they sort to the bottom of
'Most starred' and show no star pill regardless of real stars.

extract-plugins.py already inserts REPO_ROOT; do the same here.
2026-09-27 03:34:56 -07:00
teknium1
afc05274a2 website: keep the plugin name whole; tier/version pills move to the chip row, tools as one ellipsized list
With Community + version + stars pinned beside the title at 3 columns the name
collapsed to 'hermes-r…' — the one element a card must never lose. The title
now owns its row (stars stay right-aligned); tier and version pills lead the
chip row. The Tools row renders the first three names as one comma-separated
run that ellipsizes as a whole plus '+N', instead of three shrinking chips that
read 'mnemosyn… mnemosyn… mnemosyn…' for same-prefix tools.
2026-09-27 03:34:51 -07:00
teknium1
97a3607838 feat(website): uniform plugin catalog cards (clamped text, capped tool list)
Every card in a Plugin Catalog grid now renders at one height, so rows line
up instead of staggering by description length, banner presence and tool
count (the Desktop section had 28 distinct card heights, 412px to 1485px).

- grid-auto-rows: 1fr + column-flex card; the detail block (facts, install
  box, links) sinks to the bottom edge of every card
- banner slot is always 120px: entries without an image get a placeholder
  (tier tint gradient + large muted category glyph); a broken image URL
  swaps to the placeholder instead of collapsing the slot
- title row is one line (ellipsis), description clamps to 3 lines with an
  ellipsis and reserves 3 lines when shorter; full text stays in `title`
- chip row and dates row are one fixed line each (right-edge fade mask on
  chips); dates row renders empty when undated
- facts block is exactly three fixed-height rows: Maintainer, Pinned (with
  `Requires` folded in as `· hermes >=x`), Tools — first 3 tool names as
  chips plus a dashed `+N` chip (full list in `title`), or a muted dash
- install command truncates with an ellipsis instead of scrolling

`capToolChips` in PluginCatalog/catalog.ts is the cap helper (first 3 + N).
Desktop picker embed (`?embed=picker`) uses the same card and stays uniform.
2026-09-27 03:34:51 -07:00
teknium1
a3f454a287 fix(build): keep scripts/build/inputs.py free of pm imports; accept musl targets in its grammar
The Nix agent derivation builds scripts/build/*.py from a fileset that
does not include pm/, so importing pm.store.ALL_TARGETS there failed
nix flake check with ModuleNotFoundError. Extend the local target
regex with linux-(x64|arm64)-musl instead.
2026-09-27 03:24:39 -07:00
teknium1
aba7deac48 test(e2e): musl host cell passes; drop its #123682 known_failure gate
On Alpine the installer now stages musl uv/Python/Node (a full install
completes once libstdc++ is present) and, on the stock bash/git/curl
image, refuses up front naming musl and libstdc++.
2026-09-27 03:24:39 -07:00
teknium1
842f162f7d fix(installer): refuse musl hosts without libstdc++ up front, naming it
PM's musl Node is the unofficial-builds musl archive, which links the
system libstdc++. On a stock Alpine (bash, git, curl) node and npm then
fail staged verification with raw relocation errors after the clone and
downloads. Check in the prerequisites stage and name the package.
2026-09-27 03:24:39 -07:00
teknium1
5cbca02510 test(pm): keep FFmpeg's musl gaps when the re-pin test narrows its gap table
The test replaced FFmpeg's gaps with only the bionic entry, which now
turns the musl targets back on and asks BtbN for a glibc build that
FFmpeg.fetch_url refuses on musl. Extend the real table instead.
2026-09-27 03:24:39 -07:00
teknium1
f5c3c7d70a test: trim musl coverage to two invariants
Keep one PM invariant (a musl ELF userland resolves to linux-<arch>-musl
and the default closure is satisfiable with musl-native artifacts) and
one installer invariant (uv_bootstrap_target picks musl uv from a musl
ELF interpreter even when ldd says glibc). Drop the lock-content and
URL-shape change-detectors.
2026-09-27 03:24:39 -07:00
teknium1
34d52883cb fix(installer): ELF interpreter decides musl in uv_bootstrap_target, as in pm/store
install.sh consulted ldd before the ELF interpreter while pm/store.py's
_is_musl_libc reads the native userland's ELF interpreter first, so a
glibc ldd (secondary toolchain, gcompat) could make the bootstrap stage
a different libc than PM later resolves. Read /bin/sh (then /bin/ls)
PT_INTERP first in both; ldd and the loader glob are fallbacks only.
2026-09-27 03:24:39 -07:00
teknium1
ee0ad5adb2 refactor(pm): expose MUSL_TARGETS publicly; drop the per-URL pin hash cache
packages.py and security_packages.py imported the private _MUSL_TARGETS
across modules; make it a public store constant next to ALL_TARGETS.
The _pin_tool hash memo is an unrelated optimisation, out of scope here.
2026-09-27 03:24:39 -07:00
teknium1
79e6f1960d fix(installer): restore executable bits on install.sh and gen-bootstrap-pins.py
The salvaged commits dropped both scripts from 100755 to 100644.
2026-09-27 03:24:39 -07:00
JoaoMarcos44
666c65c552 fix(build): accept PM musl targets in bundle inputs 2026-09-27 03:24:39 -07:00
JoaoMarcos44
87d1243623 fix(installer): detect musl uv when ldd is unavailable
Fall back to the musl loader if ldd cannot identify libc, while honoring
an explicit GNU libc report on hosts with a secondary musl toolchain.
Cover both paths against the pinned uv URL and digest.

Refs: #123682
2026-09-27 03:24:39 -07:00
JoaoMarcos44
24487f3db6 fix(pm): keep musl installs on compatible runtime artifacts
Skip glibc-linked FFmpeg on musl in both default install and update roots.
Select musl uv during the standalone shell bootstrap, and let the native
userland resolve libc before bootstrap Python build metadata.

Add regression checks for the closure, target precedence, and installer pins.
2026-09-27 03:24:39 -07:00
teknium1
5cdfa0bde6 fix(pm): import _MUSL_TARGETS where IronProxy resolves musl targets
security_packages.py referenced _MUSL_TARGETS without importing it, so
IronProxy.fetch_url raised NameError on linux-*-musl (the PR's own
test_portable_go_tools_resolve_the_generic_linux_archives caught it).
Review fix pushed to the contributor branch.
2026-09-27 03:24:39 -07:00
JoaoMarcos44
8371dd17f6 fix(pm): select native musl artifacts on Linux 2026-09-27 03:24:39 -07:00
teknium1
60e531cb52 fix(gateway): read every Hermes inline bootstrap's argv as its identity, on all OSes
The #107002 guard keeps an inline ``-c`` program's trailing argv as data. Every
Hermes launcher runs the entry point IN the ``-c`` process, so the guard hid
real gateways on every OS (#124318, #124588):

- the store launcher / Windows updater relaunch (_launchers.runtime_command)
- the published launcher script (POSIX shell launcher: every PM-install
  systemd/launchd gateway) and its Windows .cmd base64 wrapper
- the venv_sync re-entry, whose argv is assigned inside the source

gateway.status.inline_bootstrap_argv recognises exactly those emitted source
shapes, anchored at both ends so a program merely CARRYING one (the restart
watcher's respawn argv) still never matches, and rewrites the process to the
equivalent ``python -m <entry> <argv>``. /proc, psutil and ``ps`` space-join
argv, which splits the source across tokens; the shortest token run ending
in a recognised tail is the source whichever reader joined it. Both
canonical matchers (looks_like_gateway_command_line and
update_cmd_windows._hermes_holder_subcommand) use it.

Live on a real PM install (Linux, bwrap): a gateway started through the
installed launcher script or runtime_command read "Gateway is not running"
on main; with this change both read running, find_gateway_pids and
get_running_pid see them. Drops the four #124318 known_failure gates in
tests/e2e/core/windows_update.

Co-authored-by: Hermes Agent <dmyou@users.noreply.github.com>
Co-authored-by: JoaoMarcos44 <joaomarcosdias444@gmail.com>
Co-authored-by: DianaBudin <dianabudin0307@gmail.com>
2026-09-27 02:57:28 -07:00
dgpcboy
02cf40d99e fix(gateway): recognise the Windows launcher's inline-bootstrap gateway form 2026-09-27 02:57:28 -07:00
teknium1
878d902147 fix(update): judge Windows gateway ownership by home, warn on unreadable ones
Rework of the #124676 salvage onto the canonical fleet scope instead of a
second path heuristic:

- the pause, the cold-start guard and the post-relaunch readiness poll all
  filter the host-wide find_gateway_pids(all_profiles=True) scan through
  update_cmd_fleet._scoped_manual_gateway_pids, the same home scope the
  POSIX fleet restart uses (#93349). A PM install's venv lives under
  installs/, so exe-under-PROJECT_ROOT rarely proved an own gateway; its
  live HERMES_HOME (or the LOCALAPPDATA default) always does.
- a foreign gateway with no HERMES_HOME resolves to its own default home and
  no longer blocks this install's cold start (#124659, second bullet).
- a gateway whose home cannot be read is named in the pause output instead
  of skipped silently; the spawn ledger's verified (pid, create_time) entry
  proves an own gateway whose environment is unreadable.
- tests trimmed to two invariants on real processes; a real-Windows journey
  (two installs, one updates while the other serves) replaces the harness
  comment that documented the bug.
2026-09-27 02:57:28 -07:00
JoaoMarcos44
46fba4c9a4 fix(update): scope Windows gateway lifecycle to current install 2026-09-27 02:57:28 -07:00
teknium1
5b27d6c2c2 test(e2e/desktop): let the build-fail updater finish its launch acceptance before asserting it exited
On the error path posix.sh writes the result, relaunches the app, and then
sleeps 1.5 s to confirm the launch took. A relaunched app that boots fast logs
`detached update FAILED` inside that window, and the spec checked for a live
posix.sh right away. On #124878 the app logged at 08:34:06.565, about 0.5 s
after it launched, the check ran at 08:34:07.16, and posix.sh was still in
`sleep 1.5`. The spec now polls for up to 30 s.
2026-09-27 02:56:08 -07:00
teknium1
388c63e24e test(e2e/pm): drop the #124668 gate; both generation_gc cells pass
hermes update and hermes pm repair now run the generation collector, so test_repeated_updates_collect_superseded_generations and test_repeated_repairs_collect_superseded_generations assert plainly again.
2026-09-27 02:55:39 -07:00
teknium1
ccff8eb3ce test(pm): keep the takeover generation assert; drop call-order checks
Trim the salvaged tests to one invariant: after a takeover rebuild, the
superseded generation built two days ago is gone. The update-completion
event-order asserts and the repair_dependencies `events == [sync,
collect]` test pin the call sequence, not the outcome; the update and
repair outcomes are covered live by
tests/e2e/core/upgrade/pm/test_generation_gc.py. The fake venv_sync in
the completion-process fixture keeps its collect_superseded_generations
stub so the module still imports.
2026-09-27 02:55:39 -07:00
JoaoMarcos44
c11a6bc0b2 fix(pm): collect generations after maintenance syncs 2026-09-27 02:55:39 -07:00
teknium1
3c9c224e6c test(e2e): the symlinked per-task home cell is no longer a known failure
The PM runtime identity now canonicalizes the store directories, so a launch
from a per-task HERMES_HOME whose tools/ links back to the main home is current.
Drop the #123798 known_failure wrap and its "gated" wording.
2026-09-27 02:55:05 -07:00
teknium1
6a17705227 fix(pm): canonicalize the store only in the PM runtime identity
Narrow the salvaged fix: keep store_root() returning $HERMES_HOME/tools as
spelled, and resolve the interpreter's directories only where
pm/runtime.py::_inputs hashes them. Resolving store_root() itself moves every
path built from store_root().parent (features.json, the native-build state dir,
writable_store_root's manifest probe), so after the update a symlinked tools
dir would read no feature selections and every install under a symlinked
parent would re-key.

Only directories resolve: the pinned CPython's bin/python3 is itself a symlink
to python3.X, so a full resolve() would re-key every install. A selected.json
written before this change (spelled path) is still accepted, so installs that
were current stay current; only per-task homes that were already re-staging
every launch re-stage once more and then converge.

Tests: the salvaged store_root alias tests are replaced by one invariant through
prepare_runtime (home, per-task home and real path share one generation; a
pre-fix record is not re-staged). Red on origin/main.
2026-09-27 02:55:05 -07:00
funky-xamarin
f7317b344f test(pm): prove runtime alias reuse retains a real lease 2026-09-27 02:55:05 -07:00
funky-xamarin
42b1f19887 fix(pm): canonicalize default store before runtime identity 2026-09-27 02:55:05 -07:00
teknium1
e8704ebded chore: map journeydan's commit email for attribution 2026-09-27 02:54:35 -07:00
teknium1
c1e4d4d274 test(e2e): the managed-environment pm cell is a plain assertion again
The generation workspace now carries pm/uv.lock, so
test_pm_commands_run_from_the_managed_environment passes; drop its
known_failure wrap as tests/e2e/core/_pending_fixes.py asks.

Refs #124075
2026-09-27 02:54:35 -07:00
teknium1
9fa34cfb28 fix(pm): keep bundled plugins' dashboard dist/ in the build snapshot
`dist` sat in the same every-depth exclusion set, so the generation
workspace lost the tracked `plugins/kanban/dashboard/dist/` and
`plugins/hermes-achievements/dashboard/dist/` bundles. The managed
environment's editable install runs from that snapshot, so
`get_bundled_plugins_dir()` resolves into it and
`dashboard_ui.py::serve_plugin_asset` 404s both tabs' entry bundles.

Keep `dist` excluded at the root (build output) and copy it below a
package root.

Refs #124075

Co-authored-by: Rafsanjani Castro Satria Chandra <330302617+oswaldvalois@users.noreply.github.com>
2026-09-27 02:54:35 -07:00
Daniel Bader
7523696fb6 fix(pm): keep a workspace member's own uv.lock in the build snapshot
`_copy_core_inputs` listed `uv.lock` in the names its copytree `ignore`
drops, and copytree applies that callback at every depth, so the member
lock `pm/uv.lock` never reached the generation workspace.
`pm/runtime.py::_inputs()` hashes `<workspace>/pm/{pyproject.toml,uv.lock}`
to key the PM runtime, so every `hermes pm` command run by the managed
environment's `hermes` died at preflight:

    FileNotFoundError: .../workspace/pm/uv.lock

Drop `uv.lock` from the exclusion set. The root lock is unaffected: the
root pass copies only the explicit `files` set (never `uv.lock`), and
`lock_and_sync` seeds or resolves the root lock itself.

Refs #124075
2026-09-27 02:54:35 -07:00
teknium1
95fdcf92b0 test(e2e): enforce the Windows update cells the PM git fix flips
The fresh-install update and the partial-clone update no longer fail with
[WinError 2] on a machine without system Git (#124634), so their
known_failure gates come off.
2026-09-27 02:54:03 -07:00
teknium1
2270d3511d fix(update): expose PM's git only for git checkouts, and record the installer's copy
A git-less Windows ZIP install has no .git and never runs git, yet
_prepare_git_command called expose_pm_git() before it checked
use_zip_update: offline or with no pin, pm.ensure raised and aborted an
update that never needed git. expose_pm_git now takes the project root
and does nothing unless it is a git checkout (both callers).

When install.ps1 runs as one process, the git it staged into PM's store
is on the inherited PATH, so expose_pm_git returned early and PM's facts
never recorded it; plain hermes processes (plugin git installs, doctor,
version info) had no git until the first `hermes update`. A git found
under PM's store is now treated as that unrecorded copy and ensured, so
the source completion writes the git fact at install time.

Co-authored-by: JoaoMarcos44 <joaomarcosdias444@gmail.com>
2026-09-27 02:54:03 -07:00
teknium1
e5ccf4a26c fix(update): look up git through the hermes_platform resolver
expose_pm_git() probed with a bare shutil.which, which the managed-runtime
resolution guard rejects outside hermes_platform/. Route the lookup through
hermes_platform.resolver.locate_command instead.
2026-09-27 02:54:03 -07:00
teknium1
305072f4a6 fix(update): give git-less Windows installs PM's git for update and source completion
On a Windows machine with no git, scripts/install.ps1 stages the pinned Git
for Windows into the pm store for its own process only, and pm's facts
never record it. Every later product process that ran a bare `git` failed:

- `hermes update` died before its first step:
  "✗ Update failed: [WinError 2] The system cannot find the file specified"
- the source completion that finishes an installer re-run or an update
  found no commit, deleted the install stamp, and the next boot wrote an
  adoption stamp that names no commit. It also printed
  "Could not refresh release history ([WinError 2] ...)".

expose_pm_git(): when Windows resolves no git, ensure PM's git explicitly
(both callers are user-initiated, like ensure_tools_for_sync) and put its
composed PATH (cmd and usr\bin) on the process, so children inherit it.
The update calls it before its first git, and the source completion calls it
before its builds and stamp. A machine with a working git is untouched.
main_desktop already ensures PM's git for its build for the same reason.
2026-09-27 02:54:03 -07:00
teknium1
679a7a7314 test(e2e): enforce the untracked-collision cell the autostash fix flips
An untracked file at a path upstream adds is now kept in the parked stash
(#124641), so its known_failure gate comes off.
2026-09-27 02:53:32 -07:00
teknium1
20dabfa869 fix(update): health-check a restore that parks the stash for replaced untracked files
When the update replaced a user's untracked file, _apply_stash returned
False after the tracked changes and the other untracked files were
already in the tree, so _restore_stashed_changes skipped the syntax,
critical-import and reject path: a restore that broke Hermes finished
the update instead of resetting the tree and exiting 1. _apply_stash now
returns the replaced paths; the restore validates the tree as before and
only skips the stash drop, recording it as parked.

A refused path counts as replaced only when HEAD tracks it
(git cat-file -e HEAD:<path>), so a file that was undeletable at stash
time and changed since (#70127) is no longer reported as the update's.
2026-09-27 02:53:32 -07:00
teknium1
78ee5e96db fix(update): keep the autostash when the update replaced a user's untracked file (#124641) 2026-09-27 02:53:32 -07:00
ymat19
5cd9dbc261 fix(install): recognize bare PATH= assignments and keep the appended line idempotent
wire_shell_path's existing-setup regex required a character before PATH=, so it missed bare assignments such as Fedora's ~/.bashrc (    PATH="$HOME/.local/bin:$HOME/bin:$PATH") and Debian's ~/.profile. The installer then appended its own line to .bashrc, .profile and .bash_profile, and because Fedora's .bash_profile sources .bashrc, login shells got ~/.local/bin on PATH several times.

Match bare assignments too, and make the appended line a no-op when PATH already contains ~/.local/bin.
2026-09-27 02:50:10 -07:00
kshitijk4poor
009699b8a0 fix(cron): a missing dependency interpreter fails the script run
_posix_cron_script_argv fell back to sys.executable when the selected venv's
interpreter was gone. On a managed-store install that is the bare store Python,
so the run logged a warning and then died with the same ModuleNotFoundError as
#123044. A half-deleted venv reaches this branch because _recorded_venv only
checks pyvenv.cfg. Raise instead; _run_job_script's try reports it as a failed
run naming the missing interpreter, matching how a broken PM record is handled.
The existing broken-selection test is parametrized over both causes.
2026-09-27 15:04:50 +05:30
kshitijk4poor
4d4aed0f98 fix(cron): POSIX script bootstrap keeps plain-run __main__ semantics
Review follow-up on the live-checkout bootstrap.

- runpy.run_path runs the script under a temporary __main__ that is
  swapped back once the body returns, so atexit handlers or non-daemon
  threads that pickle script-defined classes failed ("not found as
  __main__.Foo") where a plain `python script.py` works. The bootstrap
  now installs a real __main__ module (SourceFileLoader, __cached__ as
  in a plain run) and execs the compiled script in it. Tracebacks keep
  one bootstrap frame instead of runpy's three.
- Under -P / PYTHONSAFEPATH there is no cwd entry to replace, so the
  repo is prepended instead of overwriting a stdlib path.
- Interpreter via pm.environments.project_python (the existing
  venv_python(selected_venv()) helper).
- A missing venv interpreter still falls back to the caller's Python
  but now logs a warning naming it, like the Windows bootstrap fallback.
- Docstrings: the lazy-install gate's real reason (a script importing
  hermes_bootstrap could complete a source update and execv itself onto
  the bare store Python via sys.orig_argv); _script_argv no longer
  claims "else sys.executable".
2026-09-27 15:04:50 +05:30
kshitijk4poor
f4057533aa test(cron): keep script-run tests off the host's PM store
POSIX cron scripts now consult the managed store. Without isolation, a
test run from a PM-managed checkout (the standard ~/.hermes/hermes-agent)
reads the host's store and install records, trips the home I/O guard,
and would run scripts on the host's dependency venv. Point
HERMES_RUNTIME_DIR at an empty per-test dir for tests/cron.
2026-09-27 15:04:50 +05:30
kshitijk4poor
3cdb0c80a6 fix(cron): POSIX cron scripts import the live checkout; broken PM selection fails the run
Follow-up to the venv-interpreter change above.

- The selected venv resolves Hermes from its generation's workspace
  snapshot, which only a dependency change (uv.lock / extras / Python /
  plugins, pm/packages.py::expected_stamp) rebuilds. After a code-only
  update, scripts imported older Hermes code than the gateway runs. A
  `python -c` bootstrap now puts the live checkout right after the
  script's directory, in-process, so nothing is inherited by the
  script's children (no PYTHONPATH, #123440).
- POSIX dispatch moves into _script_argv (platform branch), so
  _windows_cron_python_invocation is Windows-only again and the
  PYTHONPATH-keyed bootstrap gate goes back to its original form.
- The interpreter path comes from pm.environments.venv_python.
- _script_argv now runs inside _run_job_script's try. PM record reads
  (store manifest, facts, selection) can raise ValueError/KeyError as
  well as RuntimeError; before, those escaped the runner and stranded
  the execution row, and on POSIX the local fallback handed the script
  to the bare store interpreter (the #123044 symptom). A broken
  selection is now a failed run with the PM error, per
  selected_venv's contract. This also covers the same pre-existing
  gap on the Windows committed_venv path.
- Tests: two invariant tests replace the three change-detector tests
  (live checkout beats a snapshot on sys.path, venv site-packages
  resolve, script-dir sys.path[0], no PYTHONPATH; broken selection
  fails the run instead of escaping).
2026-09-27 15:04:50 +05:30
liuhao1024
03156afc7b fix(cron): degrade to the caller's interpreter when selected_venv raises
_posix_cron_python_invocation called selected_venv(repo) unguarded; the
four RuntimeError cases it is documented to raise would escape through
_script_argv (which runs before _run_job_script's try), crash the tick,
and leave the execution row in running forever — the exact half-migrated
install the test docstring already claimed was supported. Mirror the
Windows bootstrap's degrade-don't-crash contract: warn and run on the
caller's interpreter. Adds the raising-selection case to the POSIX
invocation test (red on the previous head), a sealed-payload caveat on
the e2e test's hand-written .pth, and a pointer from the Windows
invocation docstring to its POSIX counterpart.

(cherry picked from commit 8d5b3b5e9727d612d91b2a7485e0f4bb245358f3)
2026-09-27 15:04:50 +05:30
liuhao1024
cb11c994f7 fix(cron): run POSIX .py job scripts on the selected venv interpreter
On managed-store installs the gateway's store Python carries the repo and
the managed site-packages only in-process; cron .py scripts spawned with
sys.executable re-resolve imports from scratch and die with
ModuleNotFoundError (#123044). Run them on the selected dependency venv's
interpreter instead — its pyvenv.cfg site-packages (editable installs
included) need no PYTHONPATH overlay, so children the script spawns never
inherit the store's paths and import CPython-3.14 extension modules on a
foreign interpreter (#123440). Lazy installs are disabled for script
children so hermes_bootstrap imports off the store-record venv cannot
republish launchers. The .pth bootstrap routing in _script_argv is
tightened to PYTHONPATH-carrying overlays, which the POSIX path no
longer produces.

(cherry picked from commit 2d6976c3d6d8b877ccf73672fda2e963025ec30b)
2026-09-27 15:04:50 +05:30
austinpickett
516535b542 fix(agent): name an exhausted (402) provider pool, not "No LLM provider configured"
Fixes #94785
2026-09-27 04:59:47 -04:00