From 12646eb5a13809d889795de859258874825c5c67 Mon Sep 17 00:00:00 2001 From: David Heinemeier Hansson Date: Thu, 27 Aug 2026 11:45:15 +0200 Subject: [PATCH] Run the app's Hermes before calling it ready desktop_hermes_ready decided from a marker file and a text match, while a hermes the user installed themselves had to answer --version before it counted. The marker says the app's install once landed, not that it is still there, so a runtime deleted afterwards left --check reporting success: the default agent records Hermes, skips the install terminal, and the launch fails. It now runs the command, on the same 15 second budget the app itself uses. The path match is a plain string for the same reason it is in the remover -- the dot in ~/.hermes would otherwise claim a wrapper pointing at ~/xhermes. foreign_hermes_runs never tested foreignness, only that the command runs, so it is hermes_runs now and both callers share it. Co-Authored-By: Claude Opus 5 (1M context) Co-authored-by: Codex XHigh --- bin/omarchy-install-hermes-cli | 21 +++++++++++++-------- test/shell.d/hermes-cli-test.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/bin/omarchy-install-hermes-cli b/bin/omarchy-install-hermes-cli index a24f7aca..321ddac3 100755 --- a/bin/omarchy-install-hermes-cli +++ b/bin/omarchy-install-hermes-cli @@ -45,12 +45,17 @@ desktop_owns_hermes() { # marker is written last, and the command is what the agent actually runs. desktop_hermes_ready() { [[ -f $HOME/.hermes/hermes-agent/.hermes-bootstrap-complete ]] || return 1 - [[ -x $HOME/.local/bin/hermes ]] || return 1 # An executable of that name proves nothing about whose it is; the app's own # points into ~/.hermes, and anything else is not the install we are asking - # about. - grep -q "$HOME/.hermes" "$HOME/.local/bin/hermes" + # about. Matched as a plain string, because the path carries a dot and an + # unanchored pattern would also claim a wrapper pointing at ~/xhermes. + [[ -f $HOME/.local/bin/hermes ]] || return 1 + grep -qF "$HOME/.hermes" "$HOME/.local/bin/hermes" || return 1 + + # And a marker left behind by an install whose venv has since gone answers + # for nothing, so the command has to run, exactly as a foreign one must. + hermes_runs } # Whether Hermes is really installed, not merely whether the stub exists. A @@ -73,12 +78,12 @@ foreign_hermes() { [[ -e $HOME/.local/bin/hermes || -L $HOME/.local/bin/hermes ]] && ! ours } -# A foreign path is usable when it is a command that runs: a regular executable -# whose --version answers. The executable bit alone proves little -- a directory +# A hermes at that path is usable when it is a command that runs: a regular +# executable whose --version answers. The executable bit alone proves little -- a directory # passes -x on search permission, and a wrapper whose interpreter or target is # gone passes it too. The desktop app applies the same probe with the same 15 # second budget, so what passes here is what it will use. -foreign_hermes_runs() { +hermes_runs() { [[ -f $HOME/.local/bin/hermes && -x $HOME/.local/bin/hermes ]] && timeout 15 "$HOME/.local/bin/hermes" --version >/dev/null 2>&1 } @@ -92,7 +97,7 @@ if [[ $mode == "--check" ]]; then # 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 + if hermes_runs; then exit 0; else exit 1; fi fi if installed; then exit 0; else exit 1; fi fi @@ -128,7 +133,7 @@ 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 + if hermes_runs; then exit 0 fi diff --git a/test/shell.d/hermes-cli-test.sh b/test/shell.d/hermes-cli-test.sh index bfe94b95..b701eb3c 100755 --- a/test/shell.d/hermes-cli-test.sh +++ b/test/shell.d/hermes-cli-test.sh @@ -282,3 +282,29 @@ HOME="$leak_home" PATH="$leak_bin:$mock_bin:$PATH" \ [[ -z $(cat "$leak_log") ]] || fail "the interpreter pin does not follow Hermes into the commands it runs" pass "the interpreter pin does not follow Hermes into the commands it runs" + +# The app's marker says its install once landed, not that it is still there. A +# wrapper whose runtime has since gone answers for nothing, so readiness runs +# the command, exactly as it does for a hermes the user installed themselves. +ready_home="$test_tmp/ready-home" +mkdir -p "$ready_home/.hermes/hermes-agent/venv/bin" "$ready_home/.local/bin" +touch "$ready_home/.hermes/hermes-agent/.hermes-bootstrap-complete" +printf '%s\n' "#!/bin/bash" "exec $ready_home/.hermes/hermes-agent/venv/bin/hermes \"\$@\"" \ + >"$ready_home/.local/bin/hermes" +chmod +x "$ready_home/.local/bin/hermes" + +run_ready_check() { + OMARCHY_TEST_DESKTOP_INSTALLED=1 \ + OMARCHY_TEST_MISE_LOG="$mise_log" \ + HOME="$ready_home" \ + PATH="$mock_bin:$PATH" \ + bash "$ROOT/bin/omarchy-install-hermes-cli" --check >/dev/null 2>&1 +} + +run_ready_check && fail "--check rejects the app's wrapper when its runtime is gone" + +printf '%s\n' "#!/bin/bash" 'echo "hermes-agent 0.0.0-test"' \ + >"$ready_home/.hermes/hermes-agent/venv/bin/hermes" +chmod +x "$ready_home/.hermes/hermes-agent/venv/bin/hermes" +run_ready_check || fail "--check accepts the app's wrapper once it runs" +pass "readiness runs the app's command rather than trusting its marker"