Files
omarchy/bin/omarchy-remove-ai-hermes
T
Shane PoppletonandClaude Opus 5 f917ffe37d Use the command helper in the AI app removers
test/shell.d/bin-style-test.sh has been failing on quattro: the OpenClaw
remover checks for gum with a raw `command -v`, which the style rule
reserves for the helpers themselves.

The Hermes remover does the same thing. It was invisible because the test
fails on the first offending file, so fixing OpenClaw alone just moves the
failure along.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013p9Qh6dX4FuwBJAWhNPVbn
2026-09-06 20:26:55 +10:00

100 lines
4.6 KiB
Bash
Executable File

#!/bin/bash
# omarchy:summary=Remove the Hermes desktop app along with the Hermes runtime it installed.
# omarchy:requires-sudo=true
# -u so an unset HOME is an error rather than a set of rm -rf paths rooted at /.
set -euo pipefail
omarchy-pkg-drop hermes-desktop
# The installer leaves a unit waiting to hand the app the Omarchy theme.
systemctl --user stop omarchy-hermes-theme.service 2>/dev/null || true
# The mise CLI is the app's predecessor, not the app itself: Hermes Desktop takes
# it over on install and runs its own runtime instead, so a copy still here is one
# the app never superseded -- an interrupted install, or the terminal CLI from
# before the app existed. Remove Hermes clears that too, scoped by the installer
# to what Omarchy owns so a hermes the user set up themselves is left alone.
# Tolerated here rather than fatal, so the ~/.hermes handling below still runs;
# the failure is answered for at the end instead of being swallowed.
cli_removed=true
omarchy-install-hermes-cli --remove || cli_removed=false
# The app writes this when the runtime it provisions under ~/.hermes has landed,
# and it is the only thing that tells that runtime apart from one the user
# installed themselves -- the paths are the same either way. Without it the app
# never got that far: a machine where it was installed but never launched still
# has whatever was there before, and none of it is ours to delete unasked.
if [[ -f $HOME/.hermes/hermes-agent/.hermes-bootstrap-complete ]]; then
# The checkout and venv, its own uv, its own node. None of it is any use once
# the app is gone, so it goes without asking; what the user made with the app
# is a different question, answered below.
rm -rf \
"$HOME/.hermes/hermes-agent" \
"$HOME/.hermes/bootstrap-cache" \
"$HOME/.hermes/bin" \
"$HOME/.hermes/node"
# Only the wrappers pointing into ~/.hermes, matched as a plain string: the
# path carries a dot, so an unanchored pattern would also claim a wrapper
# pointing at a sibling like ~/xhermes.
for command in hermes hermes-agent hermes-acp; do
wrapper="$HOME/.local/bin/$command"
if [[ -f $wrapper && ! -L $wrapper ]] && grep -qF "$HOME/.hermes" "$wrapper"; then
rm -f "$wrapper"
fi
done
# When Hermes brought its own Node it symlinked these next to its own commands,
# and they point at what we just deleted. Only the links into ~/.hermes: a
# system Node, or someone else's, lives somewhere else entirely.
for command in node npm npx; do
link="$HOME/.local/bin/$command"
if [[ -L $link && $(readlink "$link") == "$HOME/.hermes"/* ]]; then
rm -f "$link"
fi
done
fi
# What survives to here is the user's: the chats, memories and skills in
# ~/.hermes, the connections and their encrypted tokens in ~/.config/Hermes.
# Keeping them stays the default -- they are small, and finding them intact
# after a reinstall is the better surprise -- but a removal meant to be
# complete should not leave credentials behind either, so the choice is put in
# front of the user with the size, default no. Asked whenever the directories
# exist, marker or no marker: on a machine where the marker never appeared the
# data came from the terminal CLI or an install the app never finished, and it
# is still what removal is asked to clean up. Naming the paths keeps the
# question honest there too -- ~/.hermes may still carry a runtime the app
# never owned, a yes takes that with it, and saying so is the prompt's job.
# Without a terminal to ask in, keeping everything is the answer.
data_removed=false
if [[ -d $HOME/.hermes || -d $HOME/.config/Hermes ]] && [[ -t 0 ]] && omarchy-cmd-present gum; then
# du answers non-zero when either directory is missing, and pipefail would
# turn that into an aborted removal; the size is worth no such thing.
size=$(du -shc "$HOME/.hermes" "$HOME/.config/Hermes" 2>/dev/null | tail -1 | cut -f1 || true)
if gum confirm --default=false "Also delete ~/.hermes and ~/.config/Hermes ($size: chats, memories, skills, connections and tokens)?"; then
rm -rf "$HOME/.hermes" "$HOME/.config/Hermes"
data_removed=true
fi
fi
echo ""
echo "Hermes Desktop has been removed."
if [[ $data_removed == true ]]; then
echo "Its chats, memories, and settings in ~/.hermes and ~/.config/Hermes are gone too."
elif [[ -d $HOME/.hermes || -d $HOME/.config/Hermes ]]; then
echo "Your chats, memories, and skills are still in ~/.hermes,"
echo "and your connections and settings in ~/.config/Hermes."
fi
# The messages above still hold -- the app and its runtime are gone -- but a CLI
# teardown that failed already said so on stderr, and that stands.
if [[ $cli_removed == "false" ]]; then
exit 1
fi