Install Hermes for the default agent as the desktop app's self-updating runtime
Choosing Hermes as the default agent built it through mise: a pipx environment with no checkout, so `hermes update` had nothing to move, and the only Hermes that could update itself was the one Hermes Desktop set up. Both paths now run the same setup. omarchy-install-hermes-cli installs the hermes-desktop package and runs upstream's installer from it, pinned to the packaged release and started on main, exactly as Install > AI did; omarchy-install-ai-hermes is that plus opening the app. The terminal, the default agent and the app share one runtime, and it updates itself. --check answers whether --now has anything left to do, not merely whether a hermes runs: choosing Hermes from the menu asks first and opens a terminal only on a no, so a yes has to mean no minutes-long step would run where nobody can see it. With the app installed that means the runtime's own command, its completion marker and the seeded packaged app; a finished runtime whose command is gone, somebody else's, or its own but unable to run gets it back from upstream's path stage without bootstrapping again. Either way the command has to be the one PATH finds, because omarchy-agent runs bare `hermes` and Omarchy puts mise's shims ahead of ~/.local/bin; a command in the way is named rather than installed over. The modes are named outright because the app's launcher used to call this command with no arguments to reconcile a mise copy; a default of --now would turn every launch into an install. --check still refuses to run the retired wrapper, since running it built Hermes through mise, and a machine whose migration is pending can still have it on PATH. Provisioning no longer writes the wrapper, Remove Preinstalls no longer looks for it, and the wrapper, the environment it built and what proves them Omarchy's are known to the installer alone: --retire-mise is the migration's whole job, and --now runs the same removal once the runtime installer has saved the wrapper aside, so a user who chose Hermes before their migration ran is not left with mise's shim answering `hermes`. Only the wrapper proves the environment is Omarchy's, at its path or in that saved copy, so the environment goes first and the wrapper last, judged by mise neither having it installed nor still requesting it; a removal that leaves either behind, or a listing that cannot be read, mise missing included, stops with the commands to finish by hand and leaves the migration pending. The migration that once installed the wrapper is kept as a no-op for late updaters, and one whose default agent was Hermes is told to choose it again. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Co-Authored-By: Codex XHigh <noreply@openai.com>
This commit is contained in:
1 parent
b8c382da9e
commit
7eb818e37b
16 files changed
+1211
-1204
No files matched your search
@@ -53,20 +53,39 @@ chmod 4755 "$test_tmp/package/chrome-sandbox"
|
||||
cat >"$test_tmp/share/install.sh" <<'MOCK'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
printf 'bootstrap\n' >>"$OMARCHY_TEST_ROOT/events"
|
||||
printf '%s\n' "$@" >"$OMARCHY_TEST_ROOT/install-args"
|
||||
[[ ${OMARCHY_TEST_INSTALL_FAIL:-0} != 1 ]] || exit 7
|
||||
commit=$OMARCHY_TEST_RELEASE_COMMIT
|
||||
force=false
|
||||
stage=""
|
||||
while (( $# )); do
|
||||
case "$1" in
|
||||
--dir) runtime=$2; shift ;;
|
||||
--commit) commit=$2; shift ;;
|
||||
--force-commit) force=true ;;
|
||||
--stage) stage=$2; shift ;;
|
||||
--hermes-home) [[ $2 == "$HERMES_HOME" ]] ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
# The commands upstream writes last: shims for the two side commands and, for
|
||||
# hermes, a launcher into the runtime's venv the way the real one is written.
|
||||
write_commands() {
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
for command in hermes hermes-agent hermes-acp; do
|
||||
rm -f "$HOME/.local/bin/$command"
|
||||
printf 'native runtime shim\n' >"$HOME/.local/bin/$command"
|
||||
done
|
||||
printf '#!/bin/bash\nexec "%s/venv/bin/hermes" "$@"\n' "$runtime" >"$HOME/.local/bin/hermes"
|
||||
chmod +x "$HOME/.local/bin/hermes"
|
||||
}
|
||||
# The path stage writes the commands alone, without touching the checkout.
|
||||
if [[ $stage == "path" ]]; then
|
||||
printf 'path\n' >>"$OMARCHY_TEST_ROOT/events"
|
||||
write_commands
|
||||
exit 0
|
||||
fi
|
||||
printf 'bootstrap\n' >>"$OMARCHY_TEST_ROOT/events"
|
||||
mkdir -p -- "${runtime%/*}"
|
||||
if [[ ! -d $runtime ]]; then
|
||||
git clone -q --depth 1 "file://$OMARCHY_TEST_ROOT/seed" "$runtime"
|
||||
@@ -80,33 +99,38 @@ if [[ $force == true ]] || ! git -C "$runtime" merge-base --is-ancestor "$commit
|
||||
fi
|
||||
mkdir -p "$runtime/venv/bin"
|
||||
git -C "$runtime" rev-parse HEAD >"$runtime/venv/dependency-commit"
|
||||
printf '#!/bin/bash\nexit 0\n' >"$runtime/venv/bin/hermes"
|
||||
# The venv command answers the readiness probes the way the real one does: the
|
||||
# installer runs the command it leaves on PATH before calling Hermes ready.
|
||||
cat >"$runtime/venv/bin/hermes" <<'SH'
|
||||
#!/bin/bash
|
||||
if [[ ${1:-} == "chat" && ${2:-} == "--help" ]]; then
|
||||
echo "[-q QUERY, --query QUERY] [--tui]"
|
||||
else
|
||||
echo "hermes-agent 0.0.0-test"
|
||||
fi
|
||||
SH
|
||||
chmod +x "$runtime/venv/bin/hermes"
|
||||
printf '#!/bin/bash\nexec /usr/bin/python3 "$@"\n' >"$runtime/venv/bin/python"
|
||||
chmod +x "$runtime/venv/bin/python"
|
||||
[[ ${OMARCHY_TEST_NO_MARKER:-0} == 1 ]] || touch "$runtime/.hermes-bootstrap-complete"
|
||||
mkdir -p "$HOME/.local/bin"
|
||||
for command in hermes hermes-agent hermes-acp; do
|
||||
rm -f "$HOME/.local/bin/$command"
|
||||
printf 'native runtime shim\n' >"$HOME/.local/bin/$command"
|
||||
done
|
||||
write_commands
|
||||
MOCK
|
||||
|
||||
cat >"$test_tmp/bin/omarchy-pkg-add" <<'MOCK'
|
||||
#!/bin/bash
|
||||
printf 'package %s\n' "$*" >>"$OMARCHY_TEST_ROOT/events"
|
||||
[[ ${OMARCHY_TEST_PACKAGE_FAIL:-0} != 1 ]]
|
||||
[[ ${OMARCHY_TEST_PACKAGE_FAIL:-0} != 1 ]] || exit 1
|
||||
touch "$OMARCHY_TEST_ROOT/package-installed"
|
||||
MOCK
|
||||
cat >"$test_tmp/bin/omarchy-pkg-present" <<'MOCK'
|
||||
#!/bin/bash
|
||||
[[ -e $OMARCHY_TEST_ROOT/package-installed ]]
|
||||
MOCK
|
||||
cat >"$test_tmp/bin/git" <<'MOCK'
|
||||
#!/bin/bash
|
||||
if [[ ${OMARCHY_TEST_FETCH_FAIL:-0} == 1 && " $* " == *" --unshallow "* ]]; then exit 8; fi
|
||||
exec /usr/bin/git "$@"
|
||||
MOCK
|
||||
cat >"$test_tmp/bin/omarchy-install-hermes-cli" <<'MOCK'
|
||||
#!/bin/bash
|
||||
printf 'handoff\n' >>"$OMARCHY_TEST_ROOT/events"
|
||||
exit 1
|
||||
MOCK
|
||||
cat >"$test_tmp/bin/setsid" <<'MOCK'
|
||||
#!/bin/bash
|
||||
exec "$@"
|
||||
@@ -149,28 +173,28 @@ MOCK
|
||||
cat >"$test_tmp/bin/systemd-run" <<'MOCK'
|
||||
#!/bin/bash
|
||||
printf 'theme-start\n' >>"$OMARCHY_TEST_ROOT/events"
|
||||
# Join the mock asynchronous launch so every test owns its full lifetime.
|
||||
for (( attempt=0; attempt<100; attempt++ )); do
|
||||
if grep -q '^launch' "$OMARCHY_TEST_ROOT/events"; then exit 0; fi
|
||||
sleep 0.01
|
||||
done
|
||||
exit 1
|
||||
MOCK
|
||||
chmod +x "$test_tmp/bin/"*
|
||||
|
||||
# Substitute only system package paths in a scratch copy of the actual script.
|
||||
python3 - "$ROOT/bin/omarchy-install-ai-hermes" "$test_tmp" <<'PY'
|
||||
# Substitute only system package paths in scratch copies of the actual scripts.
|
||||
# The runtime setup lives in omarchy-install-hermes-cli, which the desktop
|
||||
# installer finds on PATH under its own name.
|
||||
python3 - "$ROOT/bin" "$test_tmp" <<'PY'
|
||||
from pathlib import Path
|
||||
import sys
|
||||
source, scratch = Path(sys.argv[1]), Path(sys.argv[2])
|
||||
script = source.read_text()
|
||||
for original, replacement in {
|
||||
substitutions = {
|
||||
'/opt/hermes-desktop': str(scratch / 'package'),
|
||||
'/usr/share/hermes-desktop': str(scratch / 'share'),
|
||||
'/usr/bin/hermes-desktop': str(scratch / 'bin/hermes-desktop'),
|
||||
}.items():
|
||||
script = script.replace(original, replacement)
|
||||
(scratch / 'installer').write_text(script)
|
||||
}
|
||||
for name, target in (('omarchy-install-ai-hermes', scratch / 'installer'),
|
||||
('omarchy-install-hermes-cli', scratch / 'bin/omarchy-install-hermes-cli')):
|
||||
script = (source / name).read_text()
|
||||
for original, replacement in substitutions.items():
|
||||
script = script.replace(original, replacement)
|
||||
target.write_text(script)
|
||||
target.chmod(0o755)
|
||||
PY
|
||||
|
||||
new_home() {
|
||||
@@ -179,11 +203,24 @@ new_home() {
|
||||
runtime="$hermes_home/hermes-agent"
|
||||
native="$runtime/apps/desktop/release/linux-unpacked"
|
||||
mkdir -p "$test_home"
|
||||
rm -f "$test_tmp/package-installed"
|
||||
: >"$test_tmp/events"
|
||||
}
|
||||
# The app opens in the background, so a run that got that far is joined to it
|
||||
# before anything is asserted; one that stopped earlier started nothing.
|
||||
run_installer() {
|
||||
HOME="$test_home" HERMES_HOME="${OMARCHY_TEST_HOME:-$hermes_home}" PATH="$test_tmp/bin:$PATH" \
|
||||
bash "$test_tmp/installer" >"$test_tmp/output" 2>&1
|
||||
HOME="$test_home" HERMES_HOME="${OMARCHY_TEST_HOME:-$hermes_home}" PATH="$test_tmp/bin:$test_home/.local/bin:$PATH" \
|
||||
bash "$test_tmp/installer" >"$test_tmp/output" 2>&1 || return
|
||||
for (( attempt=0; attempt<200; attempt++ )); do
|
||||
if grep -q '^launch' "$test_tmp/events"; then return 0; fi
|
||||
sleep 0.01
|
||||
done
|
||||
return 1
|
||||
}
|
||||
# ~/.local/bin is on PATH the way Omarchy puts it there, after the mocks.
|
||||
run_cli() {
|
||||
HOME="$test_home" HERMES_HOME="${OMARCHY_TEST_HOME:-$hermes_home}" PATH="$test_tmp/bin:$test_home/.local/bin:$PATH" \
|
||||
bash "$test_tmp/bin/omarchy-install-hermes-cli" "$@" >"$test_tmp/output" 2>&1
|
||||
}
|
||||
assert_stopped() {
|
||||
if grep -Eq '^(launch|theme-|build-stamp)' "$test_tmp/events"; then fail "$1"; fi
|
||||
@@ -193,9 +230,10 @@ new_home fresh
|
||||
run_installer || fail "fresh setup succeeds" "$(cat "$test_tmp/output")"
|
||||
expected=$(printf '%s\n' --skip-setup --branch main --commit "$release_commit" --force-commit --dir "$runtime" --hermes-home "$hermes_home")
|
||||
[[ $(cat "$test_tmp/install-args") == "$expected" ]] || fail "upstream installer receives the pinned main arguments"
|
||||
[[ $(head -3 "$test_tmp/events") == $'package hermes-desktop\nhandoff\nbootstrap' ]] || fail "package and CLI handoff precede runtime bootstrap"
|
||||
grep -qx launch "$test_tmp/events" || fail "native app is copied before launch"
|
||||
[[ $(sed -n '4p' "$test_tmp/events") == build-stamp ]] || fail "upstream build stamp follows the app copy and precedes launch"
|
||||
[[ $(head -2 "$test_tmp/events") == $'package hermes-desktop\nbootstrap' ]] || fail "the package precedes runtime bootstrap" "$(cat "$test_tmp/events")"
|
||||
[[ $(sed -n '3p' "$test_tmp/events") == build-stamp ]] || fail "upstream build stamp follows the app copy" "$(cat "$test_tmp/events")"
|
||||
[[ $(tail -1 "$test_tmp/events") == launch ]] || fail "the app opens only once setup and the theme hand-over are in place" "$(cat "$test_tmp/events")"
|
||||
grep -qx theme-start "$test_tmp/events" || fail "setup hands Hermes the theme"
|
||||
[[ $(cat "$hermes_home/desktop-build-stamp.json") == 'upstream build stamp' ]] || fail "the upstream helper records the completed packaged build"
|
||||
[[ $(cat "$runtime/runtime.txt") == after ]] || fail "the release runtime receives its patch"
|
||||
[[ $(stat -c %a "$native/chrome-sandbox") == 755 ]] || fail "the user sandbox is not setuid"
|
||||
@@ -284,8 +322,10 @@ run_installer && fail "incomplete existing app requires repair"
|
||||
assert_stopped "incomplete native app prevents launch"
|
||||
pass "an incomplete existing native app is preserved"
|
||||
|
||||
# A runtime already at the release, edited where the patch lands, before Omarchy
|
||||
# has prepared it: the conflict is reported and nothing is touched.
|
||||
new_home patch-conflict
|
||||
run_installer || fail "patch conflict fixture sets up"
|
||||
HOME="$test_home" HERMES_HOME="$hermes_home" bash "$test_tmp/share/install.sh" --dir "$runtime" --hermes-home "$hermes_home"
|
||||
printf 'local edit\n' >"$runtime/runtime.txt"
|
||||
: >"$test_tmp/events"
|
||||
run_installer && fail "unexpected patch conflict stops setup"
|
||||
@@ -297,6 +337,17 @@ run_installer && fail "incomplete modified runtime cannot be reset by upstream i
|
||||
! grep -qx bootstrap "$test_tmp/events" || fail "modified runtime never reaches upstream installer"
|
||||
pass "patch conflicts and incomplete modified runtimes retain local changes and stop safely"
|
||||
|
||||
# Once set up, a runtime is the user's to edit; a finished install is not
|
||||
# re-patched or re-verified, only opened.
|
||||
new_home finished-edit
|
||||
run_installer || fail "finished-edit fixture sets up" "$(cat "$test_tmp/output")"
|
||||
printf 'local edit\n' >"$runtime/runtime.txt"
|
||||
: >"$test_tmp/events"
|
||||
run_installer || fail "a finished install with local edits is accepted" "$(cat "$test_tmp/output")"
|
||||
[[ $(cat "$runtime/runtime.txt") == 'local edit' ]] || fail "local edits to a finished runtime are preserved"
|
||||
[[ $(cat "$test_tmp/events") == $'package hermes-desktop\nlaunch' ]] || fail "a finished install is only opened" "$(cat "$test_tmp/events")"
|
||||
pass "a finished install is left as the user has it"
|
||||
|
||||
new_home full-history-retry
|
||||
git clone -q "$test_tmp/seed" "$runtime"
|
||||
git -C "$runtime" checkout -q --detach "$release_commit"
|
||||
@@ -305,6 +356,10 @@ run_installer || fail "clean incomplete full-history release checkout is repaire
|
||||
[[ $(git -C "$runtime" rev-parse HEAD) == "$release_commit" && -f $native/resources/app.asar ]] || fail "full-history retry seeds the matching release"
|
||||
pass "full-history retries force the guarded release pin before dependency setup"
|
||||
|
||||
# A main that is neither the release nor origin/main is kept under another name
|
||||
# and main still starts at the release: a user's own commits stay reachable,
|
||||
# and a clone whose main is off origin/main only because upstream rewrote its
|
||||
# history is not refused for work it never did.
|
||||
new_home local-main
|
||||
git clone -q "$test_tmp/seed" "$runtime"
|
||||
printf 'local branch work\n' >"$runtime/keep"
|
||||
@@ -312,10 +367,70 @@ git -C "$runtime" add keep
|
||||
git -C "$runtime" -c user.name=Test -c user.email=test@example.invalid commit -qm local-work
|
||||
local_main=$(git -C "$runtime" rev-parse main)
|
||||
git -C "$runtime" checkout -q --detach "$release_commit"
|
||||
run_installer && fail "local main commits cannot be reset by upstream installation"
|
||||
! grep -qx bootstrap "$test_tmp/events" || fail "local main is checked before upstream installer"
|
||||
[[ $(git -C "$runtime" rev-parse main) == "$local_main" ]] || fail "local main commit stays referenced"
|
||||
pass "detached release checkouts do not hide local main work from the installer guard"
|
||||
run_installer || fail "a runtime whose main carries other work still sets up" "$(cat "$test_tmp/output")"
|
||||
[[ $(git -C "$runtime" rev-parse main) == "$release_commit" ]] || fail "main starts at the release"
|
||||
kept=$(git -C "$runtime" for-each-ref --format='%(objectname)' 'refs/heads/main-before-omarchy-*')
|
||||
[[ $kept == "$local_main" ]] || fail "what main pointed at is kept under another name" "$kept"
|
||||
grep -q 'main-before-omarchy-' "$test_tmp/output" || fail "the kept branch is named in the output"
|
||||
[[ -f $native/resources/app.asar ]] || fail "setup carries on to seed the app"
|
||||
pass "work on main is kept under another name rather than refused"
|
||||
|
||||
# A shallow.lock nothing has touched for a minute is what a probe that killed
|
||||
# Hermes mid-fetch leaves behind; it must not stop the history fetch for good.
|
||||
new_home stale-lock
|
||||
HOME="$test_home" HERMES_HOME="$hermes_home" bash "$test_tmp/share/install.sh" --dir "$runtime" --hermes-home "$hermes_home"
|
||||
printf 'stale\n' >"$runtime/.git/shallow.lock"
|
||||
touch -d '5 minutes ago' "$runtime/.git/shallow.lock"
|
||||
run_installer || fail "a stale shallow.lock does not stop setup" "$(cat "$test_tmp/output")"
|
||||
[[ ! -e $runtime/.git/shallow.lock ]] || fail "the stale lock is cleared"
|
||||
[[ $(git -C "$runtime" rev-parse --is-shallow-repository) == false ]] || fail "the history fetch went ahead after the stale lock"
|
||||
pass "a stale shallow.lock is cleared rather than left to block every history fetch"
|
||||
|
||||
# The same old lock with a git still working in the runtime is somebody's: it
|
||||
# is waited for, not taken. Each way a live git is found gets its own run: a
|
||||
# stand-in git that lives until this test releases it, only after setup has
|
||||
# said it is waiting, and that says if its lock was stolen while it lived; it
|
||||
# then leaves the lock behind orphaned the way a killed fetch would.
|
||||
live_lock_case() {
|
||||
local name=$1 where=$2 output_line='Waiting for Hermes' attempt
|
||||
shift 2
|
||||
new_home "$name"
|
||||
ln -s "$test_home" "$test_tmp/$name-link"
|
||||
HOME="$test_home" HERMES_HOME="$hermes_home" bash "$test_tmp/share/install.sh" --dir "$runtime" --hermes-home "$hermes_home"
|
||||
printf 'live\n' >"$runtime/.git/shallow.lock"
|
||||
touch -d '5 minutes ago' "$runtime/.git/shallow.lock"
|
||||
rm -f "$test_tmp/lock-stolen" "$test_tmp/release-git"
|
||||
(cd "$where" && { if (( $# )); then export "$@"; fi; } && export LOCK="$runtime/.git/shallow.lock" && exec -a git bash -c 'for (( i = 0; i < 900; i++ )); do [[ -e "$1" ]] && exit; [[ -e $LOCK ]] || { touch "$2"; exit; }; sleep 0.1; done' _ "$test_tmp/release-git" "$test_tmp/lock-stolen") &
|
||||
fake_git=$!
|
||||
: >"$test_tmp/output"
|
||||
# The runtime is reached through a link, as a symlinked home would, since
|
||||
# /proc reports canonical paths and the runtime path keeps links.
|
||||
OMARCHY_TEST_HOME="$test_tmp/$name-link/.hermes" run_installer &
|
||||
installer=$!
|
||||
for (( attempt = 0; attempt < 300; attempt++ )); do
|
||||
grep -q "$output_line" "$test_tmp/output" 2>/dev/null && break
|
||||
sleep 0.1
|
||||
done
|
||||
if ! grep -q "$output_line" "$test_tmp/output"; then
|
||||
touch "$test_tmp/release-git"; wait "$installer" || true
|
||||
fail "setup says it is waiting for the live git ($name)" "$(cat "$test_tmp/output")"
|
||||
fi
|
||||
[[ ! -e $test_tmp/lock-stolen ]] || fail "the lock was cleared while a git still worked in the runtime ($name)"
|
||||
touch "$test_tmp/release-git"
|
||||
wait "$installer" || fail "setup goes ahead once the git is gone ($name)" "$(cat "$test_tmp/output")"
|
||||
wait "$fake_git" 2>/dev/null || true
|
||||
[[ ! -e $test_tmp/lock-stolen ]] || fail "the lock was cleared while a git still worked in the runtime ($name)"
|
||||
[[ ! -e $runtime/.git/shallow.lock ]] || fail "the orphaned lock is cleared once nothing holds it ($name)"
|
||||
[[ $(git -C "$runtime" rev-parse --is-shallow-repository) == false ]] || fail "the history fetch went ahead after the wait ($name)"
|
||||
}
|
||||
# Found by its working directory.
|
||||
live_lock_case live-lock-cwd "$test_tmp/live-lock-cwd/.hermes/hermes-agent"
|
||||
pass "a lock a live git holds is waited for, not taken, through a linked runtime path"
|
||||
# Found by GIT_DIR alone, with a trailing slash, from elsewhere, with a large
|
||||
# environment: read whole and NUL-delimited, or it would go unseen.
|
||||
big_env=$(head -c 120000 /dev/zero | tr '\0' 'x')
|
||||
live_lock_case live-lock-env "$test_tmp" BIG_ENV="$big_env" GIT_DIR="$test_tmp/live-lock-env/.hermes/hermes-agent/.git/"
|
||||
pass "a git working from elsewhere with GIT_DIR naming the runtime is found by its environment"
|
||||
|
||||
new_home deepen-retry
|
||||
OMARCHY_TEST_FETCH_FAIL=1 run_installer && fail "history fetch failure stops setup"
|
||||
@@ -345,10 +460,88 @@ new_home old-package
|
||||
mv "$test_tmp/package/resources/install-stamp.json" "$test_tmp/saved-install-stamp.json"
|
||||
run_installer && fail "an old installed package cannot bootstrap"
|
||||
grep -q 'omarchy update' "$test_tmp/output" || fail "old package has actionable upgrade guidance"
|
||||
! grep -qx handoff "$test_tmp/events" || fail "old package is rejected before CLI handoff"
|
||||
! grep -qx bootstrap "$test_tmp/events" || fail "old package never reaches upstream installer"
|
||||
mv "$test_tmp/saved-install-stamp.json" "$test_tmp/package/resources/install-stamp.json"
|
||||
pass "old package fails with upgrade guidance before changing the runtime or CLI"
|
||||
pass "old package fails with upgrade guidance before changing the runtime"
|
||||
|
||||
# Choosing Hermes as the default agent runs the same setup, short of opening
|
||||
# the app: the package, the runtime, the seeded app and the theme hand-over.
|
||||
new_home terminal-agent
|
||||
run_cli --now || fail "the default agent path sets Hermes up" "$(cat "$test_tmp/output")"
|
||||
[[ $(cat "$test_tmp/events") == $'package hermes-desktop\nbootstrap\nbuild-stamp\ntheme-stop\ntheme-start' ]] ||
|
||||
fail "the default agent path installs the app's runtime without opening the app" "$(cat "$test_tmp/events")"
|
||||
[[ -x $test_home/.local/bin/hermes && -f $native/resources/app.asar ]] || fail "the default agent path leaves the command and the seeded app in place"
|
||||
: >"$test_tmp/events"
|
||||
run_cli --now || fail "a finished install is accepted by the default agent path" "$(cat "$test_tmp/output")"
|
||||
[[ ! -s $test_tmp/events ]] || fail "a finished install is set up again" "$(cat "$test_tmp/events")"
|
||||
run_cli --check || fail "--check follows the installed runtime"
|
||||
pass "choosing Hermes as the default agent installs the app's runtime without opening the app"
|
||||
|
||||
# A Hermes the user set up themselves is what the default agent runs, and
|
||||
# nothing is installed beside it. Asked for the app by name, Omarchy installs
|
||||
# the package first, and then the runtime supersedes it with the command saved.
|
||||
new_home own-hermes
|
||||
mkdir -p "$test_home/.local/bin"
|
||||
cat >"$test_home/.local/bin/hermes" <<'SH'
|
||||
#!/bin/bash
|
||||
if [[ ${1:-} == "chat" && ${2:-} == "--help" ]]; then
|
||||
echo "[-q QUERY, --query QUERY] [--tui]"
|
||||
else
|
||||
echo "hermes-agent 0.0.0-user"
|
||||
fi
|
||||
SH
|
||||
chmod +x "$test_home/.local/bin/hermes"
|
||||
own_hermes=$(cat "$test_home/.local/bin/hermes")
|
||||
run_cli --now || fail "the default agent path accepts the user's own Hermes" "$(cat "$test_tmp/output")"
|
||||
[[ ! -s $test_tmp/events ]] || fail "a working Hermes of the user's own has the app installed beside it" "$(cat "$test_tmp/events")"
|
||||
[[ $(cat "$test_home/.local/bin/hermes") == "$own_hermes" ]] || fail "the user's own hermes command is left alone"
|
||||
run_installer || fail "the app installs over the user's own Hermes" "$(cat "$test_tmp/output")"
|
||||
grep -qx bootstrap "$test_tmp/events" || fail "the app sets up its own runtime"
|
||||
backups=("$test_home/.local/bin/".hermes-before-desktop.*)
|
||||
[[ ${#backups[@]} == 1 && $(cat "${backups[0]}/hermes") == "$own_hermes" ]] || fail "the user's own hermes command is saved aside"
|
||||
pass "the default agent path stands aside for the user's own Hermes; the app supersedes it"
|
||||
|
||||
# A finished runtime whose command is gone, or not its own, gets its command
|
||||
# back from upstream's path stage alone: no bootstrap, the runtime untouched,
|
||||
# and what held the name saved aside. Until then --check says no, so the menu
|
||||
# opens a terminal for the repair rather than running the agent on the wrong
|
||||
# Hermes.
|
||||
new_home command-repair
|
||||
run_cli --now || fail "command-repair fixture sets up" "$(cat "$test_tmp/output")"
|
||||
rm "$test_home/.local/bin/hermes"
|
||||
run_cli --check && fail "--check calls a runtime installed without its command"
|
||||
: >"$test_tmp/events"
|
||||
run_cli --now || fail "a missing command is restored" "$(cat "$test_tmp/output")"
|
||||
[[ $(cat "$test_tmp/events") == path ]] || fail "a missing command is restored without bootstrapping again" "$(cat "$test_tmp/events")"
|
||||
run_cli --check || fail "--check follows the restored command"
|
||||
printf '%s\n' "#!/bin/bash" "exec /usr/local/bin/somebody-elses-hermes \"\$@\"" >"$test_home/.local/bin/hermes"
|
||||
chmod +x "$test_home/.local/bin/hermes"
|
||||
run_cli --check && fail "--check calls the app installed while the terminal is on another Hermes"
|
||||
: >"$test_tmp/events"
|
||||
run_cli --now || fail "a foreign command beside the app's runtime is replaced" "$(cat "$test_tmp/output")"
|
||||
[[ $(cat "$test_tmp/events") == path ]] || fail "a foreign command is replaced without bootstrapping again" "$(cat "$test_tmp/events")"
|
||||
grep -lF somebody-elses-hermes "$test_home/.local/bin/".hermes-before-desktop.*/hermes >/dev/null 2>&1 || fail "the foreign command is saved aside"
|
||||
grep -qF "$hermes_home/" "$test_home/.local/bin/hermes" || fail "the runtime's own command is back"
|
||||
run_cli --check || fail "--check follows the runtime's own command"
|
||||
chmod -x "$test_home/.local/bin/hermes"
|
||||
run_cli --check && fail "--check calls the runtime's own command installed when it cannot run"
|
||||
: >"$test_tmp/events"
|
||||
run_cli --now || fail "the runtime's own command is rewritten when it cannot run" "$(cat "$test_tmp/output")"
|
||||
[[ $(cat "$test_tmp/events") == path && -x $test_home/.local/bin/hermes ]] || fail "a command that cannot run is rewritten by the path stage alone" "$(cat "$test_tmp/events")"
|
||||
pass "a finished runtime gets its own command back without bootstrapping again"
|
||||
|
||||
# A hermes ahead of ~/.local/bin on PATH is what the default agent would run,
|
||||
# so a finished install behind it is not installed, and --now names it rather
|
||||
# than setting anything up again.
|
||||
cp "$test_home/.local/bin/hermes" "$test_tmp/bin/hermes"
|
||||
run_cli --check && fail "--check calls a shadowed install installed"
|
||||
: >"$test_tmp/events"
|
||||
run_cli --now && fail "--now reports a shadowed install as ready"
|
||||
grep -qF "$test_tmp/bin/hermes" "$test_tmp/output" || fail "--now names the command in the way" "$(cat "$test_tmp/output")"
|
||||
[[ ! -s $test_tmp/events ]] || fail "a shadowed install is set up again" "$(cat "$test_tmp/events")"
|
||||
rm -f "$test_tmp/bin/hermes"
|
||||
run_cli --check || fail "--check follows the install once nothing shadows it"
|
||||
pass "a hermes ahead of ~/.local/bin on PATH is reported, not set up over"
|
||||
|
||||
new_home custom-profile
|
||||
hermes_home="$test_home/custom home"
|
||||
|
||||
Reference in new issue
Block a user