Commit Graph

40833 Commits

Author SHA1 Message Date
ethernet
00a9dbc60b fix(desktop): eslint import order + padding after the origin/main merge
The merge landed main's `minimize-to-tray` and `hud-modifier-types` modules next to
ours, leaving two `perfectionist/sort-imports` errors — the only blocking failures in
the `JS & TS checks` job (`apps/desktop :: check:lint`):

  electron/main.ts:321      ./minimize-to-tray before ./native-auth-decisions
  src/global.d.ts:6         ../electron/hud-modifier-types before ../electron/machine-profile

Resolved with the workspace's own `npm run fix` (eslint --fix + prettier), which also
pads the `padding-line-between-statements` warnings it can. Lint is 0 errors after.
2026-09-21 17:50:44 -04:00
ethernet
14b3232cbd fix(test-runner): key the scratch root by user, not a shared literal
The runner's per-run temp roots live under a fixed `/var/tmp/hermes-pytest`, chosen for
real reasons (disk-backed, not hidden, short enough for AF_UNIX sun_path). But a fixed
literal in a world-writable sticky dir belongs to whoever creates it first: a root-owned
root — a container or system-service run — makes every later `makedirs`/`mkdtemp` there
fail with EPERM for every other user on the host, with no way back that does not need
root. That is exactly what happened on luna: /var/tmp/hermes-pytest is root:root 755, so
every local suite run by the login user died at `runner crashed: PermissionError(13)`
before collecting a single test.

Key the name by uid (with the same non-/var/tmp fallback), so no run can be blocked by
another user's leftovers. Invariant test: two uids never share a scratch root, and the
root is created under the expected parent.
2026-09-21 17:24:29 -04:00
ethernet
05609d2092 merge: origin/main (19 commits) into ethie/pm-clean
Conflicts, all inside the local-runtime / local-models subsystem:

- hermes_cli/local_runtime/binaries.py, hermes_cli/web_routers/local_models.py:
  main's own transfer machinery (urllib ranged download, shutil.move publish) is
  retired here — pm/downloader owns every fetch. Took ours.
- tests/hermes_cli/test_local_runtime_downloads.py: deleted here (its subject,
  binaries._download, is gone); kept deleted.
- tests/hermes_cli/test_local_models_routes.py: ours (the pause/resume suite) plus
  main's held-finished-file contract, re-seamed onto the pm downloader.

main's fix 515412f415 ("wait out a held finished download instead of copying it and
failing") is re-homed so it fits the PM model: the Windows rename that fails while an
antivirus or indexing scan still holds a just-closed multi-gigabyte file is now handled
once, in pm/downloader.replace_when_released, which is the single publish path for PM
archives and model files alike. A cleanup that cannot remove its leftover can no longer
mask the error that left it.

Tests: helper retries a transient refusal and lands the file; gives up with the
plain-language message chained to the OS error; a download publishes through two refused
renames with nothing left behind; a stuck hold reports the rename error, not the failed
cleanup. Route-level: the job lands the file and reports done.
2026-09-21 17:24:14 -04:00
ethernet
acb82a62d0 fix some bundle issues 2026-09-21 16:45:34 -04:00
Jeffrey Quesnelle
7b3c7aef31 Merge pull request #117926 from NousResearch/fix/local-model-download-rename
Local models: wait out a held finished download instead of copying it and failing
2026-09-21 16:40:12 -04:00
kshitijk4poor
4a75fad06a fix(website): keep the compact selects from overrunning their column
At 601px the select columns were squeezed to 89/103/113px while the selects
are floored at 120px, so each control overran its neighbour (row scrollWidth
603 vs 569 clientWidth). Hold the same floor on the column, letting the
search field absorb the shrink instead.

The plugins panel had the same viewport-drift the drawer had: leaving the
mobile band left `filtersOpen` true, so `aria-expanded` stayed "true" on the
hidden toggle. Reset it from the same media query.
2026-09-22 02:02:30 +05:30
kshitijk4poor
6c91f1b8ba chore(website): drop the unreachable Categories toggle and dead control CSS
The new compact controls hid `.sidebarToggle` at every width — the 1024px
block's `.layout > .sidebarToggle` rule outranks the later 900px
`display: flex` — so its button, `activeCatBadge` and three CSS blocks were
unreachable, and the drawer's `onKeyDown` was shadowed by the focus trap's
capture-phase listener. Delete them.

Also drop declarations that cannot paint under `display: contents`
(`padding`/`border-bottom`/`backdrop-filter`/`background !important` on
`.controlsBar` at <=600px), the redundant `.compactSort` hide (its parent is
already hidden), and the empty effect left over on the plugins page.

`.filterPanel.filterPanelOpen` keeps the open panel working regardless of
source order instead of relying on the 600px block coming last.
2026-09-22 02:02:30 +05:30
kshitijk4poor
c125b005a6 fix(website): stop the filters panel from jumping the page
Tapping Filters scrolled 391px even when the panel was already on screen,
because the handler called `scrollIntoView({ block: "start" })` on every
open. Reveal it from an effect instead, with `block: "nearest"`, and keep the
click handler a plain state toggle (the cancelled rAF no longer rides along
on the handler).
2026-09-22 02:02:30 +05:30
kshitijk4poor
e2ee6c7be3 fix(website): drop the drawer state when the viewport leaves mobile
Opening the filters drawer at <=600px and then resizing to a wider viewport
left `sidebarOpen` true: the hidden toggle kept `aria-expanded="true"`, and
coming back to mobile silently reopened the drawer and re-locked body scroll.

Reset it in the matchMedia sync, and name the query constant so it stays in
step with the `max-width: 600px` CSS blocks it mirrors.
2026-09-22 02:02:30 +05:30
kshitijk4poor
e4b05b0ef5 fix(website): keep the compact bar pinned inside the picker embed
`?embed=picker` hides the navbar and pins the controls bar to the frame top,
but that override still names `.controlsBar` — which is `display: contents`
at <=600px, so the sticky element (`.controlsTopRow`) kept its 60px navbar
offset and left a dead 60px gap with cards sliding under it. Extend the
override to the row, and add the same rule to the skills page, which had no
picker offset at all.
2026-09-22 02:02:30 +05:30
kshitijk4poor
c846b2a4e7 fix(website): give compact filter selects room for their own value
Between 601px and ~870px the compact selects were squeezed to as little as
13px of text area (SOURCE needed 64px), so the control displayed no
readable value while the pills it replaced were hidden — the band had no
way to see the active filter.

Floor the selects at 7.5rem, let the search field shrink to 8rem instead of
12rem, and drop the uppercase labels below 820px where they leave no room.
2026-09-22 02:02:30 +05:30
kshitijk4poor
bf84ba4a24 fix(website): keep the compact directory bar legible in light theme
The new sticky control bar hardcoded the dark surface
(`rgba(7, 7, 13, 0.94)` plus gold borders and a gold-on-gold count badge),
but the site respects `prefers-color-scheme`, so light-mode users got dark
text on a near-black bar: the Filters label measured 1.00 contrast (1.5 by
pixel sample) and the skills search input dropped from 3.34 to 1.12.

Use the theme tokens instead — `--ifm-navbar-background-color` and
`--ifm-hr-border-color` resolve to the previous dark values exactly — and
scope the gold gem/border accents to the dark theme, with
`--ifm-color-emphasis-*` for light mode.
2026-09-22 02:02:30 +05:30
unsupportedpastels
df3e62457b fix(website): compact plugin and skill directory headers
(cherry picked from commit 38ef7b7784e8561f04105fcd0fd7d30bbea6674c)
2026-09-22 02:02:30 +05:30
rob-maron
0f9fc3434e add xiaomi mimo v2.6 2026-09-21 13:28:28 -07:00
teknium1
e7c5141f1c chore(contributors): map robchristiansen13 noreply email 2026-09-21 13:14:22 -07:00
teknium1
977a4f7265 test(mcp): fold the constraint-fragment tests into two invariants
One test pins the contract (if/then/else + oneOf/not fragments survive
normalization and validate with the intended semantics, using the NBX
set_effects shape from #107141), one pins the guard (root and declared
nested objects still get the #4651 dangling-required repair).
2026-09-21 13:14:22 -07:00
chelsealong
dc0915ce35 fix(moonshot): stop stamping a synthetic type on if/then/else nodes
_repair_schema didn't recurse into if/then/else, so a bare conditional
wrapper (e.g. an allOf branch expressing "when goal is set, mode must be
one of ...") fell through _fill_missing_type's default and was stamped
with type: "string". That corrupts the schema: the wrapper's actual
instance is an object, so Moonshot (and any strict validator) now
rejects every real argument against it.

if/then/else are added to the recursed node keys, and _fill_missing_type
leaves a bare conditional node untyped instead of defaulting to "string"
since it constrains the parent instance rather than describing its own
shape.
2026-09-21 13:14:22 -07:00
Rob Christiansen
070c7cf00a fix(mcp): keep required-only constraint fragments in tool schemas
_repair_object_shape() treated every dict carrying `required` as an object
declaration. A constraint fragment — {"required": ["chain"]} inside an
allOf/oneOf/anyOf/if branch, with no properties and no type — is not one.
Repairing it synthesised `properties: {}` and then pruned every name out of
`required`, so sibling branches collapsed into identical always-true schemas
and the enclosing oneOf had two matches: the tool appeared in the catalog and
every call failed validation.

Only the parameters-schema root still receives the dangling-`required` repair,
which is the single node handed to providers as the argument object.
2026-09-21 13:14:22 -07:00
brooklyn!
fca3221df4 fix(desktop): give HUD gestures their own keybindings page 2026-09-21 14:42:45 -05:00
brooklyn!
d00c951523 fix(desktop): remove persistent HUD gesture status chrome 2026-09-21 14:42:45 -05:00
ethernet
4efb36f81e merge: integrate upstream desktop features through PM preparation
Merge origin/main at 8e806ae1b2. Keep native helper compilation in
prepareDesktopNativeDependencies and keep bundling/beforePack consume-only.
Bind helper sources and headers into preparation identities and cache keys;
copy admitted executable resources beside node_modules and preserve signing
semantics in product freshness checks.

Verified desktop typecheck, focused native/packaging/UI and gateway/cache
tests, and the real Linux preparation/copy/Xvfb execution path. Incoming
upstream anti-slop findings remain unchanged; no baseline was raised.
2026-09-21 15:17:44 -04:00
686f6c61
1a90fad0f5 fix(gateway): retain partial answers after returned errors
Carry the partial-answer flag on failed completion frames and retain a replay body when no text deltas arrived. Preserve streamed segments and keep error-only, successful, and interrupted results out of this path.

Adapted from https://github.com/NousResearch/hermes-agent/pull/76112. The OpenCode terminal-stream reproductions in https://github.com/NousResearch/hermes-agent/pull/85724 are covered by existing routing and usage handling; leave those safeguards unchanged.

Co-authored-by: Jeffgithub0029 <gxalong@gmail.com>
Co-authored-by: brooklyn! <brooklyn.bb.nicholson@gmail.com>
2026-09-21 13:58:56 -05:00
hermes-seaeye[bot]
d82832eb3d fmt(js): npm run fix on merge (#118451)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-21 18:51:47 +00:00
ethernet
e34c0316a2 fix(api): queue terminal events after worker commentary 2026-09-21 14:50:22 -04:00
ethernet
980a70dd74 test(install-e2e): navigate historical updates and permit unattended quit 2026-09-21 14:49:33 -04:00
ethernet
b265e87678 test: synchronize observable state and reuse prepared PM fixtures 2026-09-21 14:49:05 -04:00
ethernet
b22c8add14 fix(pm): stream bootstrap output on Windows Python 3.11 2026-09-21 14:49:05 -04:00
ethernet
3ed2c245d3 fix(update): detect Desktop when historical takeover has no observation 2026-09-21 14:49:05 -04:00
brooklyn!
8e806ae1b2 feat(desktop): opt in to modifier-tap HUD summoning from Keyboard Shortcuts 2026-09-21 13:44:49 -05:00
brooklyn!
9ff6e071fa feat(desktop): detect clean modifier taps with passive native listeners 2026-09-21 13:44:49 -05:00
brooklyn!
f87577193c refactor(desktop): share the native gesture process lifecycle 2026-09-21 13:44:49 -05:00
brooklyn!
5100e9c328 feat(desktop): expose the device-local tray preference in Appearance 2026-09-21 13:44:40 -05:00
brooklyn!
92be0f8ed1 feat(desktop): minimize windows to tray without changing Close or Quit 2026-09-21 13:44:40 -05:00
ethernet
034c3fdb02 ci: update ty to avoid full-tree allocation failure 2026-09-21 14:43:35 -04:00
teknium1
a6bab19ab7 test(docker): a named profile's gateway start refuses without --force; --force still drives its slot
The container harness pinned the pre-multiplex-only contract (a named profile brings up its
own s6-supervised gateway). Under #118273 + this PR that start is refused: the slot stays
registered (DOWN) so `--force` has something to drive, and the refusal names `--force` and
`migrate --multiplex`. Split into the refusal invariant and the `--force` start/stop control.
2026-09-21 11:40:48 -07:00
teknium1
91d1339a8d docs: multi-profile gateway pages match the multiplex-only topology
Every line still promising that `gateway.multiplex_profiles: false` keeps
per-profile gateways, or documenting the deleted `migrate --standalone`
rollback, now describes the shipped behaviour: one gateway per host serves
every profile; `false` no-ops with a warning; `hermes update` folds a fleet
unless a real boundary (different UNIX user, HERMES_HOME outside profiles/)
holds; a blocked fleet keeps `--force` per profile; re-running
`migrate --multiplex` converges a half-migrated host; a manifest on disk is the
resume record, never a rollback. Adds the new "No new per-profile gateways"
section with the exact refusal `hermes -p <name> gateway install` prints.

Files: website/docs/user-guide/multi-profile-gateways.md,
website/docs/reference/cli-commands.md (migrate row),
website/docs/developer-guide/multiplexing-gateway.md (eager activation no
longer honours `false`), hermes_cli/AGENTS.md (migrate + refusal seams).

Completes #118273 (docs item). Part of #109417
2026-09-21 11:40:48 -07:00
teknium1
d27ba15669 fix(gateway): a named profile cannot install a new standalone gateway without --force
`hermes -p <name> gateway install|start` (and `run`, `restart`, the setup flows
through `ensure_gateway_service`) refused only while a live multiplexer already
served the profile. On a host with no multiplexer running -- or one that had not
rescanned yet -- the same command wrote a brand-new per-profile unit: a fleet
member the multiplex-only topology (#118273) no longer supports.

`_named_profile_refused_under_multiplexer` now refuses every
`<root>/profiles/<name>` home that has no service of its own: the served form
keeps naming the owner PID and `gateway restart`; the new form points at
`hermes gateway install` (default profile) and `hermes gateway migrate
--multiplex`. `--force` stays the single escape (UNIX-user / out-of-tree
HERMES_HOME fleets), and a `--force`-installed service stays startable without
it so its supervisor (ExecStart carries no --force) keeps relaunching it. The
dashboard `/api/gateway/start` twin (`multiplexed_profile_refusal`) applies the
same rule and text; `stop` is unchanged.

Tests: red on base for the no-multiplexer refusal (exit 78, no unit written,
A->B->A over two profile homes, dashboard shape); controls for the default's own
install, the served-by-PID form, and the --force path; the #111958 setup test
now asserts the unserved named profile gets no unit either.

Completes #118273 (item B). Part of #109417
2026-09-21 11:40:48 -07:00
ethernet
efaa819ee9 merge: refresh desktop fixes without reviving retired update checks 2026-09-21 14:37:01 -04:00
ethernet
8e80f37aad fix(meet): make inherited interactive stdin explicit 2026-09-21 14:36:47 -04:00
hermes-seaeye[bot]
c7c2df1a53 fmt(js): npm run fix on merge (#118435)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-09-21 18:24:39 +00:00
Gille
6a4d5e33ce fix(desktop): hide stale group activity stop controls 2026-09-21 11:18:17 -07:00
ethernet
e22809bb9e merge: retain PM branch version across upstream release 2026-09-21 14:13:41 -04:00
ethernet
77987dba8e test(install-e2e): match historical inputs and preserve authored profile state 2026-09-21 14:13:07 -04:00
ethernet
e7f9b865f9 test: isolate PM plugin fixtures and remove timing and thread contention 2026-09-21 14:13:07 -04:00
ethernet
5093154cef fix(windows): create protected token descriptors on ARM64 2026-09-21 14:13:07 -04:00
teknium1
d337b736aa chore(release): v0.21.4 (v2026.9.21)
Some checks failed
Install & Update E2E / Pick release tags (push) Has been cancelled
Install & Update E2E / Upload leg player (push) Has been cancelled
Install & Update E2E / Expand combinations (push) Has been cancelled
Install & Update E2E / ${{ matrix.name }} (push) Has been cancelled
Install & Update E2E / Result chart (push) Has been cancelled
Patch rollup of the ~1,800 PRs merged since v0.21.3 so downstream consumers
(Docker images, Hermes Cloud) get a stable tag. Full curated notes ship with v0.22.0.
v2026.9.21
2026-09-21 11:10:32 -07:00
ethernet
d2c60dbdf8 fix(test-runner): preserve PATHEXT for native PowerShell children 2026-09-21 14:03:12 -04:00
ethernet
c69ccc3bf1 merge: refresh upstream models, notification expiry, and desktop controls 2026-09-21 14:01:47 -04:00
ethernet
003b33c606 ci: prepare Bedrock schema tests and keep smoke tool requirements additive 2026-09-21 14:00:56 -04:00
teknium1
4b8a813400 docs(portal): relative profiles link so the docs link check passes on main
f50d4b3423 (a docs revert) restored a route-style /user-guide/profiles link in
nous-portal.md (en + zh-Hans); website/scripts/check_doc_links.py rejects those, so
the Docs Site check has been red on main since. Rewritten with the script's --fix.
2026-09-21 10:51:01 -07:00