Harden Hermes wrapper ownership

This commit is contained in:
Spencer Bull
2026-08-27 01:09:45 -05:00
parent a12a21c02f
commit d56c1ba972
6 changed files with 295 additions and 9 deletions
+44 -2
View File
@@ -30,6 +30,10 @@ mode=${1:-}
tool='pipx:hermes-agent[extras=all]'
python='3.13'
# The line that identifies the stub as this installer's; matched whole, so a
# wrapper that merely mentions the command is not mistaken for ours.
marker='# Written by omarchy-install-hermes-cli.'
# The package, not the runtime directory: it is installed before the app has
# ever run, and that is exactly when we must not start building a second copy.
desktop_owns_hermes() {
@@ -55,12 +59,38 @@ installed() {
[[ -d "$(mise where "$tool" 2>/dev/null)/hermes-agent/lib/python$python" ]]
}
# The stub is the only thing this installer owns. Anything else at that path
# -- Hermes' official installer, a hand-rolled wrapper, even a dangling link
# -- was put there by the user and is never deleted or overwritten here.
# Symlinks count as foreign even when they resolve to a marked file: the stub
# is written as a regular file, so a link is someone else's arrangement.
ours() {
[[ -f $HOME/.local/bin/hermes && ! -L $HOME/.local/bin/hermes ]] &&
grep -qxF "$marker" "$HOME/.local/bin/hermes"
}
foreign_hermes() {
[[ -e $HOME/.local/bin/hermes || -L $HOME/.local/bin/hermes ]] && ! ours
}
# A foreign path is usable when it is a command: a regular file that runs.
# A directory passes -x on search permission alone, and is no more a command
# than a dangling link is.
foreign_hermes_runs() {
[[ -f $HOME/.local/bin/hermes && -x $HOME/.local/bin/hermes ]]
}
# --check lets callers tell a cold stub from a working one before they commit
# to a path that assumes Hermes is ready.
if [[ $mode == "--check" ]]; then
if desktop_owns_hermes; then
if desktop_hermes_ready; then exit 0; else exit 1; fi
fi
# A foreign command is ready when it runs; a broken one is not, and since it
# is not ours to replace, nothing this installer does will make it ready.
if foreign_hermes; then
if foreign_hermes_runs; then exit 0; else exit 1; fi
fi
if installed; then exit 0; else exit 1; fi
fi
@@ -79,7 +109,7 @@ if desktop_owns_hermes; then
# Our own stub has to go with it. Left in place it still answers `hermes`
# until the app's bootstrap overwrites it, and answering means building the
# second Hermes this whole arrangement exists to avoid.
if [[ -f $HOME/.local/bin/hermes ]] && grep -q omarchy-install-hermes-cli "$HOME/.local/bin/hermes"; then
if ours; then
rm -f "$HOME/.local/bin/hermes"
fi
@@ -92,13 +122,25 @@ if desktop_owns_hermes; then
exit 1
fi
# The user already has a hermes of their own. Leave it be: a working one is
# what the default agent will run, and a broken one is theirs to fix.
if foreign_hermes; then
if foreign_hermes_runs; then
exit 0
fi
echo "~/.local/bin/hermes exists but is not runnable, and it was not installed by Omarchy." >&2
echo "Fix or remove it, then run omarchy-install-hermes-cli again." >&2
exit 1
fi
mkdir -p "$HOME/.local/bin"
rm -f "$HOME/.local/bin/hermes"
cat >"$HOME/.local/bin/hermes" <<EOF
#!/bin/bash
# Written by omarchy-install-hermes-cli.
$marker
export UV_PYTHON="$python"
+6 -3
View File
@@ -17,9 +17,12 @@ if gum confirm "Are you sure you want to remove all preinstalled web apps, TUI w
~/.local/bin/gh ~/.local/bin/opencode ~/.local/bin/playwright ~/.local/bin/playwright-cli ~/.local/bin/pi \
~/.local/bin/omp ~/.local/bin/ori ~/.local/bin/grok ~/.local/bin/crush ~/.local/bin/ghui ~/.local/bin/hunk
# Hermes Desktop owns this path once installed, and its own CLI is not a
# preinstall to sweep away.
omarchy-pkg-present hermes-desktop || rm -f ~/.local/bin/hermes
# Only the wrapper omarchy-install-hermes-cli wrote is a preinstall. Hermes
# Desktop's command, an official install, or anything else at that path is
# the user's, so it is the marker that decides, not which packages are around.
if [[ -f ~/.local/bin/hermes && ! -L ~/.local/bin/hermes ]] && grep -qxF '# Written by omarchy-install-hermes-cli.' ~/.local/bin/hermes; then
rm -f ~/.local/bin/hermes
fi
omarchy-pkg-drop \
aether \