foot only applies scrollback.multiplier to discrete wheel clicks, so
precise touchpad scrolling ignores it and crawls at the group's 1.5
factor. Split foot out at 2.0 to match how the other terminals feel.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
A failed --remove told the user to run it again, but that advice could
never work: rm -f has usually taken the marked stub by the time the
failure is judged, and a rerun that finds nothing it owns succeeds
without touching the mise environment it was asked to finish removing.
Spell out the three commands that complete the job by hand instead.
Also correct the story the probe comment told: chat never lost
--oneshot in v0.20 -- no released Hermes defined it there. It lived at
the top level until v0.21 added chat's own, so the old probe was keyed
to a flag no release ever carried under chat, and every install read
as not ready. Recorded straight so a future hermes-desktop bump to
v0.21+, which would make the old probe pass on the desktop path alone,
cannot read as the fix.
Findings from omarchybot's review (Opus 5, with Codex at xhigh).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
* Honor keepLoaded for services during plugin hot-reload
Plugin reload destroyed every service, including omarchy.lock, which drops the ext-session-lock client while Hyprland still holds the lock and surfaces the crashed-lockscreen fallback.
* Prove keepLoaded service survival with a fixture service
A fresh lock service also reports an empty lastEventAt, so comparing it
across the rescan passed whether or not the instance survived. A fixture
keepLoaded service whose in-memory marker is set before the rescan and
read back after can only pass when the same instance is still mounted.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Drop kept services whose plugin no longer declares a service
The _syncServices cleanup only asked whether the plugin was still
installed and enabled, so a kept service whose plugin dropped its
service kind or entry point kept running as a zombie until shell
restart. Apply the same eligibility checks used at creation, and hand
kept instances the refreshed manifest after a rescan.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Cover omarchy.media in keepLoaded expectations; note kept services reload on restart
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Two review follow-ups. The probe counted any mention of --tui/--query in
the help as support -- Hermes already writes "With --tui:" into --dev's
description, so a release that dropped the option while keeping the
prose would still read as ready. A flag now counts only when followed by
a shape argparse prints after a definition: the usage bracket, the gap
before same-line help text, an uppercase metavar, or the line end. Not
probed by parsing a real invocation on purpose -- a release that ignores
unknown arguments would turn the probe into a live session.
And the teardown trusted its commands: a stub rm that failed aborted
Remove Hermes under set -e before any ~/.hermes handling, while mise
failures vanished into || true. --remove now attempts every step, then
judges by what is left -- the marked stub still present, or mise still
resolving the tool -- and Remove Hermes tolerates the failure until the
runtime is handled, then carries it in its exit code.
Findings from the same codex review at xhigh, verified and proven by
mutation before landing.
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Claude <noreply@anthropic.com>
The teardown removed the Omarchy tool spec from mise unconditionally,
so removing Hermes Desktop could destroy a mise environment the user
had built against the same spec while sparing their wrapper -- the very
command the removal claims to preserve, broken behind its back. The
whole teardown now turns on the marked stub, as replacement already
does; the desktop takeover keeps its own bargain, where a second Hermes
goes whoever built it and the app still provides the command after.
Also close the probe over underscores -- _ continues a flag name just
as - does, so --tui_mode no longer answers for --tui -- and pin the
gaps review found in the tests: each flag must match on its own (either
grep could be deleted before without a failure), a foreign wrapper's
mise environment must survive --remove, and Remove Hermes must tear
down the CLI in the interrupted-install case, not only after the app's
runtime landed.
Findings from an independent codex review at xhigh, each verified
against the source and proven by mutation before landing.
Co-Authored-By: Codex <noreply@openai.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Remove Hermes dropped the desktop package and its ~/.hermes runtime but
never touched the mise CLI, on the assumption the install-time handoff
had already removed it. A CLI the app never superseded -- an interrupted
install, or the terminal CLI from before the app existed -- was left
stranded on PATH after uninstall.
Add a --remove mode to omarchy-install-hermes-cli that performs the same
teardown the desktop takeover already does (mise rm -g + mise uninstall,
and the marked stub), and call it from omarchy-remove-ai-hermes. The tool
spec and ownership marker stay defined in one place, so the takeover and
teardown paths cannot drift. Scoped to what Omarchy owns: a Hermes the
user installed themselves is left alone.
Co-Authored-By: Claude <noreply@anthropic.com>
Review follow-up on the readiness probe. The two greps were fixed-string
substring matches, so a future release listing only --tui-theme or
--query-log while dropping the bare --tui/--query omarchy-agent passes
would read as ready -- the same false verdict inverted. Anchor both to a
flag boundary.
Add a regression case pinning that a substring-only help is rejected,
and one exercising --check through a mise-installed hermes in both
capability directions: the desktop and foreign cases only covered their
own wrappers, and the mise path is what a machine without the app runs.
Co-Authored-By: Claude <noreply@anthropic.com>
Hermes v0.20 removed chat's --oneshot flag, which hermes_prompt_ready
used as its capability marker. A fully bootstrapped Hermes Desktop
install then read as not ready: --check failed forever, the default
agent flow looped back into the installer, and --now dead-ended with
"Launch Hermes Desktop once to finish installing it" on a machine
where it already had.
Probe for --tui and --query instead: the flags omarchy-agent actually
passes to seed an interactive session, rather than one that merely
shipped alongside them.
The old setup command enabled sshd before importing a key, so an aborted
run left a password-only server exposed. Skipping that machine kept the
hole Omarchy opened; close it instead by disabling sshd. Omarchy is a
desktop distro, so the console remains, and the warning explains how to
set up key-based access or deliberately re-enable password logins.
With the stakes flipped from skip to disable, "no usable key" must not
false-positive: follow an authorized_keys symlink to its key (dotfiles
setups have working key auth), and treat an unreadable file as
unverifiable rather than keyless.
Amends the unreleased 1788124236 migration in place; no released install
has run it, so every machine still gets the new behavior in one pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Validate authorized_keys line by line with the question sshd actually
asks: ssh-keygen -lf on the whole file also fingerprints a private key
copied there by mistake, which sshd cannot use, so the migration would
have disabled the only working login path.
Tighten ~/.ssh and authorized_keys the way omarchy-setup-security-sshd
does, and back off from a group-writable home directory: StrictModes
makes sshd ignore the key either way, with the same lockout.
Complete with a notice instead of failing on conditions the migration
cannot repair (a broken or pre-Include sshd_config, an overriding admin
rule, a failed reload of a valid config), so those machines keep passwords
as they were without blocking every migration queued behind this one.
Only missing privileges stay pending, since a terminal rerun fixes that.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Without a terminal sudo keys its cached credential on the parent
process of each call, so the timestamp validated by sudo -S -v in the
test shell never reached omarchy-setup-security-sshd's own sudo calls
when omarchy-iso-test drove the suite over ssh with no pty, and the
exercise died with 'a terminal is required'. Run it under script(1)
and validate the password on that pseudo-terminal first, so every sudo
underneath shares the terminal-keyed credential.
The missing-checker case dropped $ROOT/bin from PATH to make
omarchy-git-url-check unfindable, but installed machines carry the
packaged checker in /usr/bin, so it was always found and the test
failed on every 4.x machine. Shadow it with a stub that reports
command-not-found so the scenario holds regardless of the host.
The mount-boundary test tmpfs-mounts over /home before sourcing
$ROOT/bin/omarchy-windows-vm, so a checkout living under /home vanished
mid-test and set -e aborted with no output. Take a mount-safe copy of
the helper into the test tmpdir before the mounts land.
The suite verifies the finished product: VM runs never use a dev-linked
tree, so the session-environment lookup and own-checkout fallback were
needless indirection. /usr/share/omarchy is the default; a caller testing
a different tree passes OMARCHY_PATH itself.
Assert the closed session-to-root paths on an installed system — no blanket
input-group membership, no shipped asdcontrol sudoers grant — and exercise
omarchy-setup-security-sshd unattended end to end: sshd up, key authorized,
password and keyboard-interactive authentication off in the effective
config, SSH port rate limited in the firewall.
The sshd section mutates the machine, so it requires the explicit
OMARCHY_ACCEPTANCE_SUDO_PASSWORD opt-in that omarchy-iso-test passes for
its throwaway VMs; elsewhere it skips.
Tesseract routinely drops small caption text at native resolution — the
weather panel's detail labels fail the WIND assertion with the text plainly
on screen. Let the compositor upscale the capture instead.
Run over SSH with no OMARCHY_PATH, the acceptance runner defaulted it to
its own root — wrong in both sync modes omarchy-iso-test uses. With only
test/ synced, the root has no shell or install manifests: omarchy-shell
refuses every call and the package audit passes vacuously against an empty
manifest. With a full tree synced, the path disagrees with the config path
the session shell was started from, and since qs matches instances by that
path, every omarchy-shell call reads as "not running".
The suite acts on the running session, so ask the user manager for the
session's own OMARCHY_PATH first, then fall back to this checkout, then to
the installed tree.
The shell notices the bar-off flag through a FileView watch on the toggles
directory, and that watch can permanently stop delivering events after flag
changes land in quick succession — the bar then stays parked off screen
until the shell restarts. Have omarchy-toggle-bar nudge the bar's probe
over IPC after flipping the flag, so the toggle no longer depends on the
watch staying alive. The watch remains for other writers of the flag.
The Style submenu grew its Unlock entry back (d411c90a) the same day the
menu acceptance test was written, so the blind Down-key walk landed on
Font and picked a font instead of opening the Menu Bar submenu — the bar
position assertion then timed out on every run.
OpenSSH 10.x prints configuration keywords in CamelCase in its sshd -T
dump, where 9.x printed them lowercase. The case-sensitive grep in
omarchy-setup-security-sshd therefore never matched on OpenSSH 10.x, so
the hardening drop-in was always judged ineffective and removed, leaving
password authentication enabled.
pacman-rc.conf shipped with [omarchy] on pkgs.omarchy.org/edge — a
leftover from when release candidates published there. Candidates now
publish to a dedicated rc channel, so a machine switched to rc with
omarchy-refresh-pacman was pairing the rc Arch mirror with edge omarchy
packages, and omarchy-version-channel could not name the rc repository
at all (an rc install reported 'rc / unknown').
Point the conf at pkgs.omarchy.org/rc, teach omarchy-version-channel
the rc repository, and repoint existing rc-channel machines with a
migration. The migration only rewrites the shipped pairing (rc mirror +
edge [omarchy]); an administrator's deliberate combination is kept.
Apply the Omabot patch on Quattro, verify effective SSH hardening, prevent stored provisioning state from restoring the blanket input-group grant, and stop Omarchy from shipping asdcontrol authorization that belongs to the package.
Co-authored-by: David Heinemeier Hansson <david@hey.com>
* Quote install-app and install-font names like install-and-launch
* Quote the package list too, not just the display name
The display name was quoted but omarchy-pkg-add's own arguments were still interpolated into the bash -c string raw, so `omarchy install app Vim 'vim; id'` ran id. The list has to reach the helper as several words, so it cannot be quoted whole: it is split the way the unquoted expansion split it and each word is quoted on its own. Reading with -d '' keeps a newline-separated list intact instead of dropping every package after the first, which plain read -a would. install-font's package is singular and is quoted whole, and install-and-launch carried the same flaw.
Reported by acrogenesis in review of #7843.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
* Test that install-font skips font-set when pkg-add fails
The hostile-package case was asserting the family still got set, which only held because the mock always exits 0. pacman would reject that name and the && chain would skip font-set.
* Keep the installers working when errexit is inherited
read -d '' always ends at EOF rather than on its delimiter, so it reports failure on every input. Under an inherited errexit the installers exited there and built no command at all.
Reported by Codex XHigh in review of #7843.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Codex XHigh <noreply@openai.com>
---------
Co-authored-by: David Heinemeier Hansson <david@hey.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Codex XHigh <noreply@openai.com>
Catches the branch up on 94 commits so what lands here is reviewed against
current quattro, and so #8611 contributes its own five files rather than
dragging a partial catch-up in behind it.
The HUD is a frameless Electron window that paints its own per-pixel
transparency. Under the default rules it gets a compositor border and Omarchy's
window opacity on top, which turns the compact prompt into an outlined, muddy
canvas.
Scoped to the HUD by title, so the main Hermes window keeps the ordinary
treatment.
Co-authored-by: Luiz Filipe <moresco.luiz@gmail.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>