Harden Hermes wrapper ownership

This commit is contained in:
Spencer Bull committed 2026-08-27 01:09:45 -05:00
1 parent a12a21c02f
commit d56c1ba972
6 files changed
+295 -9

No files matched your search

+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"