Files
omarchy/test/shell.d/default-agent-test.sh
T
821ae58905 Reorder the agents in the panel, count Grok's tokens, and install Grok through mise (#14004)
* Let the agents in the panel be put in any order

Drag an agent by its mark to move its section; the header it will land
on lights up, and the move happens on release. Each agent's header is
now a keyboard stop with its own highlight, and Ctrl+Up/Down moves the
agent the cursor is in. The order is kept in agents/order.json beside
the usage records. The key catcher turns Ctrl+Up/Down into a reorder
only for panels that opt in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Light only an agent's mark when the cursor or a drag is on it

The mark is the handle the agent moves by, so the keyboard cursor and
the drop spot while dragging box it alone rather than the header line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep a lit agent mark's box from being clipped at the panel's edge

The box overhangs the content's left edge, which the scrolling area
clipped. The scrolling area now reaches a little into the panel's
padding with the content shifted back, so nothing moves and the box
draws whole.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Reuse a Grok session scan only on the day it was made

A limits-only refresh just after midnight reused a scan from the evening
before, which counted yesterday's sessions as today's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Keep Ctrl+Up/Down from moving an agent when the cursor is outside one

The hero's buttons and the starter tiles carry indices too, and the
lookup read them as accounts, so with several accounts Ctrl+Up/Down on
one of them moved an unrelated agent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Report a failed mise update even after the Grok upkeep runs

The Grok block ran after `mise up` and its last command set the script's
status, so a failed tool update could read as a success to callers that
warn about it. The update's own status is now the script's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Unpack a Grok update into ~/.grok whatever GROK_HOME says

The upkeep replaces ~/.grok's link, but the npm launcher unpacks into
GROK_HOME when it's set, so with a custom home the link never came back
at the new release and the old one was restored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Hold off reordering agents while an account name is being edited

Ctrl+Up/Down reached the key catcher during an inline rename, and moving
the agent rebuilt its section, dropping the unfinished name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Install Grok through mise's first-party package

The npm launcher keeps an old ~/.grok/bin binary because mise skips its
postinstall. Use mise's grok tool, and drop the npm tool so its shim
does not stay ahead of the stub.

* Drop the npm Grok workarounds now that mise installs Grok itself

With Grok installed through mise's first-party package, the CLI is the
binary mise manages, so the update upkeep that repointed ~/.grok/bin and
the shared bin directory for added Grok accounts have nothing left to do.
omarchy-update-mise is back to running mise up and nothing else, and
adding a first Grok account installs the same package.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Count Grok's tokens and prompts from its usage ledger

Each Grok session keeps a usage.json, the ledger `grok usage` prints, with
every finished turn's end time and tokens by model. The collector now
reads it for tokens today, by day for the last week, and by model, with
cached input kept apart, and counts today's prompts by the turns that
ended today. Found in #12352's research.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Count cache writes in Grok's daily token totals

Grok's totalTokens leaves cache writes out while the per-model buckets
count them, so a turn with cache writes added less to its day than to
its model. The day's total is now the sum of those same buckets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Remove the npm launcher's old Grok binaries when moving to mise's Grok

Omarchy's npm wrapper ran the binary the launcher unpacked into
~/.grok/bin, where x.ai's installer also puts a copy with a PATH entry
ahead of mise. Once the wrapper is replaced, a binary left there would
keep shadowing the mise tool, so the migration removes it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Jesse Miller <jmiller@jmiller.com>
2026-10-02 03:34:05 +02:00

941 lines
42 KiB
Bash

#!/bin/bash
set -euo pipefail
source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"
test_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp"' EXIT
mock_bin="$test_tmp/bin"
test_home="$test_tmp/home"
agent_file="$test_home/.config/omarchy/defaults/agent"
notification_history="$test_tmp/notification-history"
agent_open_log="$test_tmp/agent-open"
launch_log="$test_tmp/launch"
inline_log="$test_tmp/inline"
mise_log="$test_tmp/mise"
mise_history="$test_tmp/mise-history"
stub_log="$test_tmp/stubs"
terminal_log="$test_tmp/terminal"
menu_log="$test_tmp/menu"
muse_login_log="$test_tmp/muse-login"
mkdir -p "$mock_bin" "$test_home"
cat >"$mock_bin/omarchy-install-chromium-claude" <<'SH'
#!/bin/bash
echo claude-extension >>"$OMARCHY_TEST_STUB_LOG"
if [[ ${OMARCHY_TEST_EXTENSION_FAIL:-false} == "true" ]]; then
echo "Extension installation failed" >&2
exit 1
fi
SH
cat >"$mock_bin/omarchy-notification-send" <<'SH'
#!/bin/bash
printf '%s\0' "$@" >>"$OMARCHY_TEST_NOTIFICATION_HISTORY"
SH
cat >"$mock_bin/omarchy-cmd-missing" <<'SH'
#!/bin/bash
[[ $1 == ${OMARCHY_TEST_MISSING_COMMAND:-} ]]
SH
cat >"$mock_bin/omarchy-launch-tui" <<'SH'
#!/bin/bash
printf '%s\0' "$@" >"$OMARCHY_TEST_AGENT_LAUNCH_LOG"
SH
cat >"$mock_bin/omarchy-launch-floating-terminal-with-presentation" <<'SH'
#!/bin/bash
printf '%s\0' "$@" >"$OMARCHY_TEST_AGENT_TERMINAL_LOG"
SH
cat >"$mock_bin/opencode" <<'SH'
#!/bin/bash
printf '%s\0' opencode "$@" >"$OMARCHY_TEST_AGENT_INLINE_LOG"
SH
cat >"$mock_bin/omarchy-mise-install" <<'SH'
#!/bin/bash
printf '%s\n' "$*" >>"$OMARCHY_TEST_STUB_LOG"
SH
cat >"$mock_bin/mise" <<'SH'
#!/bin/bash
printf '%s\0' "$@" >"$OMARCHY_TEST_MISE_LOG"
printf '%s\n' "$*" >>"$OMARCHY_TEST_MISE_HISTORY"
if [[ $1 == "where" ]]; then
[[ ${OMARCHY_TEST_AGENT_INSTALLED:-false} == "true" ]]
exit
fi
if [[ $1 == "ls" && -n ${OMARCHY_TEST_MISE_HAS_NPM_GROK:-} ]]; then
printf '%s\n' "npm:@xai-official/grok 1.0.44"
exit 0
fi
[[ ${OMARCHY_TEST_MISE_FAIL:-false} != "true" ]]
SH
cat >"$mock_bin/omarchy-menu" <<'SH'
#!/bin/bash
printf '%s\0' "$@" >"$OMARCHY_TEST_AGENT_MENU_LOG"
SH
cat >"$mock_bin/omarchy-pkg-add" <<'SH'
#!/bin/bash
echo "Muse must install through mise" >&2
exit 1
SH
ln -s omarchy-pkg-add "$mock_bin/omarchy-pkg-aur-add"
cat >"$mock_bin/muse" <<'SH'
#!/bin/bash
if [[ ${1:-} == "login" ]]; then
printf 'muse %s\n' "$*" >>"$OMARCHY_TEST_MUSE_LOGIN_LOG"
else
printf '%s\0' muse "$@" >"$OMARCHY_TEST_AGENT_INLINE_LOG"
fi
SH
cat >"$mock_bin/omarchy-test-noop" <<'SH'
#!/bin/bash
exit 0
SH
for command in gum hyprctl omarchy-webapp-remove-all omarchy-tui-remove-all omarchy-pkg-drop; do
ln -s omarchy-test-noop "$mock_bin/$command"
done
chmod +x "$mock_bin"/*
export HOME="$test_home"
export PATH="$mock_bin:$ROOT/bin:$PATH"
export OMARCHY_TEST_NOTIFICATION_HISTORY="$notification_history"
export OMARCHY_TEST_AGENT_OPEN_LOG="$agent_open_log"
export OMARCHY_TEST_AGENT_LAUNCH_LOG="$launch_log"
export OMARCHY_TEST_AGENT_INLINE_LOG="$inline_log"
export OMARCHY_TEST_MISE_LOG="$mise_log"
export OMARCHY_TEST_MISE_HISTORY="$mise_history"
export OMARCHY_TEST_STUB_LOG="$stub_log"
export OMARCHY_TEST_AGENT_TERMINAL_LOG="$terminal_log"
export OMARCHY_TEST_AGENT_MENU_LOG="$menu_log"
export OMARCHY_TEST_MUSE_LOGIN_LOG="$muse_login_log"
export OMARCHY_PATH="$ROOT"
grok_package="grok"
legacy_grok_package="npm:@xai-official/grok"
omp_package="github:can1357/oh-my-pi"
crush_package="crush"
agy_package="antigravity-cli"
ori_package="github:OpenRouterLabs/ori-releases"
cursor_agent_package="cursor-agent"
muse_package="http:muse[url=https://api.meta.ai/muse-launcher.sh,bin=muse,version_list_url=https://api.meta.ai/muse-code/channels/muse-stable,version_json_path=.version]"
assert_lazy_stub() {
local package=$1
local command=$2
: >"$mise_history"
"$ROOT/bin/omarchy-mise-install" "$package" "$command"
"$test_home/.local/bin/$command" --version
mapfile -t mise_calls <"$mise_history"
[[ ${mise_calls[0]} == "use -g --quiet $package" && ${mise_calls[1]} == "x $package -- $command --version" ]] ||
fail "$command lazy stub preserves its mise package"
}
assert_lazy_stub "$grok_package" grok
assert_lazy_stub "$omp_package" omp
assert_lazy_stub "$crush_package" crush
assert_lazy_stub "$ori_package" ori
assert_lazy_stub "$cursor_agent_package" cursor-agent
assert_lazy_stub "$muse_package" muse
pass "custom agent lazy stubs preserve their mise packages"
OMARCHY_TEST_MISSING_COMMAND=cursor-agent source "$ROOT/install/user/mise.sh"
grep -Fx "$agy_package agy" "$stub_log" >/dev/null || fail "user setup creates the Antigravity lazy stub"
grep -Fx "$grok_package" "$stub_log" >/dev/null || fail "user setup creates the Grok lazy stub"
grep -Fx "$cursor_agent_package" "$stub_log" >/dev/null || fail "user setup creates the Cursor CLI lazy stub"
grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "user setup creates the Oh My Pi lazy stub"
grep -Fx "$crush_package" "$stub_log" >/dev/null || fail "user setup creates the Crush lazy stub"
grep -Fx "$ori_package ori" "$stub_log" >/dev/null || fail "user setup creates the Ori lazy stub"
OMARCHY_TEST_MISSING_COMMAND=muse source "$ROOT/install/user/mise.sh"
grep -Fx "$muse_package muse" "$stub_log" >/dev/null || fail "user setup creates the Muse lazy stub"
pass "user setup creates the custom agent lazy stubs"
: >"$stub_log"
source "$ROOT/install/user/mise.sh"
grep -Fx "$cursor_agent_package" "$stub_log" >/dev/null && fail "user setup replaces an existing cursor-agent command"
pass "user setup keeps an existing Cursor CLI install"
grep -Fx "$muse_package muse" "$stub_log" >/dev/null && fail "user setup replaces an existing Muse command"
: >"$stub_log"
OMARCHY_TEST_MISSING_COMMAND=muse source "$ROOT/migrations/1788724825.sh" >/dev/null
grep -Fx "$muse_package muse" "$stub_log" >/dev/null || fail "Muse migration creates its lazy stub"
: >"$stub_log"
source "$ROOT/migrations/1788724825.sh" >/dev/null
[[ ! -s $stub_log ]] || fail "Muse migration replaces an existing command"
mkdir -p "$test_home/.local/state/omarchy"
touch "$test_home/.local/state/omarchy/preinstalls-removed"
OMARCHY_TEST_MISSING_COMMAND=muse source "$ROOT/migrations/1788724825.sh" >/dev/null
[[ ! -s $stub_log ]] || fail "Muse migration ignores the preinstall opt-out"
rm "$test_home/.local/state/omarchy/preinstalls-removed"
pass "Muse migration preserves existing installs and the preinstall opt-out"
: >"$stub_log"
source "$ROOT/migrations/1785617047.sh" >/dev/null
grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "Oh My Pi migration creates a working lazy stub"
: >"$stub_log"
source "$ROOT/migrations/1787342993.sh" >/dev/null
grep -Fx "$ori_package ori" "$stub_log" >/dev/null || fail "Ori migration creates a working lazy stub"
: >"$stub_log"
export OMARCHY_TEST_MISSING_COMMAND=cursor-agent
source "$ROOT/migrations/1788577553.sh" >/dev/null
unset OMARCHY_TEST_MISSING_COMMAND
grep -Fx "$cursor_agent_package" "$stub_log" >/dev/null || fail "Cursor CLI migration creates a working lazy stub"
: >"$stub_log"
source "$ROOT/migrations/1788577553.sh" >/dev/null
[[ ! -s $stub_log ]] || fail "Cursor CLI migration reinstalls an existing cursor-agent command"
pass "Cursor CLI migration preserves an existing Cursor CLI install"
: >"$stub_log"
source "$ROOT/migrations/1785846769.sh" >/dev/null
grep -Fx "$omp_package omp" "$stub_log" >/dev/null || fail "agent migration repairs the Oh My Pi lazy stub"
grep -Fx "$legacy_grok_package grok" "$stub_log" >/dev/null || fail "agent migration creates the Grok lazy stub"
grep -Fx "$crush_package" "$stub_log" >/dev/null || fail "agent migration creates the Crush lazy stub"
: >"$stub_log"
mkdir -p "$(dirname "$agent_file")"
printf '%s\n' gemini >"$agent_file"
"$ROOT/bin/omarchy-mise-install" gemini
export OMARCHY_TEST_MISSING_COMMAND=agy
source "$ROOT/migrations/1786719479.sh" >/dev/null
unset OMARCHY_TEST_MISSING_COMMAND
grep -Fx "$agy_package agy" "$stub_log" >/dev/null || fail "Antigravity migration creates its lazy stub"
[[ $(<"$agent_file") == "agy" ]] || fail "Antigravity migration replaces a Gemini default"
: >"$stub_log"
printf ' %s \n' gemini >"$agent_file"
export OMARCHY_TEST_MISSING_COMMAND=agy
source "$ROOT/migrations/1786719479.sh" >/dev/null
unset OMARCHY_TEST_MISSING_COMMAND
[[ $(<"$agent_file") == "agy" ]] ||
fail "Antigravity migration replaces a padded Gemini default the launcher would still read"
pass "Antigravity migration reads the default the way the launcher does"
for obsolete_form in 'mise use -g "gemini"' 'mise use -g --quiet "gemini"'; do
printf '#!/bin/bash\n%s || exit 1\n' "$obsolete_form" >"$test_home/.local/bin/gemini"
chmod +x "$test_home/.local/bin/gemini"
source "$ROOT/migrations/1786719479.sh" >/dev/null
[[ ! -e $test_home/.local/bin/gemini ]] ||
fail "Antigravity migration removes a wrapper built on [$obsolete_form]"
done
printf '#!/bin/bash\nexec /opt/gemini "$@"\n' >"$test_home/.local/bin/gemini"
chmod +x "$test_home/.local/bin/gemini"
source "$ROOT/migrations/1786719479.sh" >/dev/null
[[ -e $test_home/.local/bin/gemini ]] || fail "Antigravity migration leaves a hand-written gemini alone"
printf '#!/bin/bash\n# replaced: mise use -g --quiet "gemini"\nexec /opt/gemini "$@"\n' >"$test_home/.local/bin/gemini"
chmod +x "$test_home/.local/bin/gemini"
source "$ROOT/migrations/1786719479.sh" >/dev/null
[[ -e $test_home/.local/bin/gemini ]] ||
fail "Antigravity migration leaves a wrapper that only mentions the installer line"
rm -f "$test_home/.local/bin/gemini"
pass "Antigravity migration only removes the Gemini wrapper Omarchy wrote"
[[ -L "$test_home/.gemini/config/skills/omarchy" && $(readlink "$test_home/.gemini/config/skills/omarchy") == "$ROOT/default/agents/skills/omarchy" ]] ||
fail "Antigravity migration provisions the omarchy skill"
[[ -L "$test_home/.gemini/config/skills/diagnose-crash" && $(readlink "$test_home/.gemini/config/skills/diagnose-crash") == "$ROOT/default/agents/skills/diagnose-crash" ]] ||
fail "Antigravity migration provisions the diagnose-crash skill"
pass "Antigravity migration provisions Antigravity skills"
: >"$stub_log"
mkdir -p "$test_home/.local/state/omarchy"
touch "$test_home/.local/state/omarchy/preinstalls-removed"
export OMARCHY_TEST_MISSING_COMMAND=agy
source "$ROOT/migrations/1786719479.sh" >/dev/null
[[ ! -s $stub_log ]] || fail "Antigravity migration preserves removed preinstalls"
pass "Antigravity migration respects removed preinstalls"
: >"$stub_log"
printf '%s\n' gemini >"$agent_file"
source "$ROOT/migrations/1786719479.sh" >/dev/null
unset OMARCHY_TEST_MISSING_COMMAND
grep -Fx "$agy_package agy" "$stub_log" >/dev/null || fail "Antigravity migration installs the agent a Gemini default now names"
[[ $(<"$agent_file") == "agy" ]] || fail "Antigravity migration replaces a Gemini default after opt-out"
pass "Antigravity migration never leaves the default naming a missing agent"
: >"$stub_log"
rm "$test_home/.local/state/omarchy/preinstalls-removed"
source "$ROOT/migrations/1786719479.sh" >/dev/null
[[ ! -s $stub_log ]] || fail "Antigravity migration reinstalls an existing Antigravity command"
pass "Antigravity migration preserves an existing Antigravity install"
mkdir -p "$test_home/.local/state/omarchy"
touch "$test_home/.local/state/omarchy/preinstalls-removed"
"$ROOT/bin/omarchy-mise-install" oh-my-pi omp
: >"$stub_log"
source "$ROOT/migrations/1785617047.sh" >/dev/null
source "$ROOT/migrations/1785846769.sh" >/dev/null
source "$ROOT/migrations/1787342993.sh" >/dev/null
OMARCHY_TEST_MISSING_COMMAND=cursor-agent source "$ROOT/migrations/1788577553.sh" >/dev/null
[[ ! -s $stub_log ]] || fail "agent migrations respect the preinstall opt-out"
[[ ! -e $test_home/.local/bin/omp ]] || fail "agent migration removes the obsolete Oh My Pi wrapper after opt-out"
# The matcher has to catch a bare oh-my-pi wrapper from either generation of the
# installer, and leave a wrapper built on the fully qualified package alone.
for obsolete_form in 'mise use -g "oh-my-pi"' 'mise use -g --quiet "oh-my-pi"'; do
printf '#!/bin/bash\n%s || exit 1\n' "$obsolete_form" >"$test_home/.local/bin/omp"
chmod +x "$test_home/.local/bin/omp"
source "$ROOT/migrations/1785846769.sh" >/dev/null
[[ ! -e $test_home/.local/bin/omp ]] ||
fail "agent migration removes a wrapper built on [$obsolete_form]"
done
printf '#!/bin/bash\nmise use -g --quiet "%s" || exit 1\n' "$omp_package" >"$test_home/.local/bin/omp"
chmod +x "$test_home/.local/bin/omp"
source "$ROOT/migrations/1785846769.sh" >/dev/null
[[ -e $test_home/.local/bin/omp ]] ||
fail "agent migration keeps a wrapper built on $omp_package"
rm -f "$test_home/.local/bin/omp"
printf '#!/bin/bash\nexport MISE_MINIMUM_RELEASE_AGE=0\nmise use -g --quiet "%s" || exit 1\nexec mise x "%s" -- "grok" "$@"\n' \
"$legacy_grok_package" "$legacy_grok_package" >"$test_home/.local/bin/grok"
chmod +x "$test_home/.local/bin/grok"
mkdir -p "$test_home/.grok/bin"
ln -s "$test_home/.grok/bin/agent" "$test_home/.local/bin/agent"
: >"$stub_log"
: >"$mise_history"
OMARCHY_TEST_MISE_HAS_NPM_GROK=1 source "$ROOT/migrations/1790863209.sh" >/dev/null
unset OMARCHY_TEST_MISE_HAS_NPM_GROK
[[ ! -s $stub_log ]] || fail "Grok registry migration respects the preinstall opt-out"
[[ ! -e $test_home/.local/bin/grok ]] || fail "Grok registry migration removes the npm wrapper after opt-out"
[[ ! -e $test_home/.local/bin/agent ]] || fail "Grok registry migration removes the curl-installer agent symlink"
grep -Fx "unuse -g $legacy_grok_package" "$mise_history" >/dev/null ||
fail "Grok registry migration drops the npm tool after opt-out"
grep -Fx "uninstall -y --all $legacy_grok_package" "$mise_history" >/dev/null ||
fail "Grok registry migration uninstalls the npm tool after opt-out"
ln -s "../../.grok/bin/agent" "$test_home/.local/bin/agent"
source "$ROOT/migrations/1790863209.sh" >/dev/null
[[ ! -e $test_home/.local/bin/agent ]] ||
fail "Grok registry migration removes a relative dangling agent symlink"
ln -s /usr/bin/true "$test_home/.local/bin/agent"
source "$ROOT/migrations/1790863209.sh" >/dev/null
[[ -L $test_home/.local/bin/agent ]] ||
fail "Grok registry migration keeps an agent symlink that is not Grok's"
rm -f "$test_home/.local/bin/agent"
rm -f "$test_home/.local/bin/grok"
: >"$stub_log"
: >"$mise_history"
OMARCHY_TEST_MISE_HAS_NPM_GROK=1 source "$ROOT/migrations/1790863209.sh" >/dev/null
unset OMARCHY_TEST_MISE_HAS_NPM_GROK
[[ ! -s $stub_log ]] || fail "Grok registry migration does not reinstall after the preinstall opt-out"
grep -Fx "unuse -g $legacy_grok_package" "$mise_history" >/dev/null &&
fail "Grok registry migration leaves a user-installed npm tool after the preinstall opt-out"
rm "$test_home/.local/state/omarchy/preinstalls-removed"
rm -f "$agent_file"
printf '#!/bin/bash\nexport MISE_MINIMUM_RELEASE_AGE=0\nmise use -g --quiet "%s" || exit 1\nexec mise x "%s" -- "grok" "$@"\n' \
"$legacy_grok_package" "$legacy_grok_package" >"$test_home/.local/bin/grok"
chmod +x "$test_home/.local/bin/grok"
: >"$stub_log"
: >"$mise_history"
mkdir -p "$test_home/.grok/bin"
touch "$test_home/.grok/bin/grok-1.0.44" "$test_home/.grok/bin/settings-keep"
ln -sfn grok-1.0.44 "$test_home/.grok/bin/grok"
OMARCHY_TEST_MISE_HAS_NPM_GROK=1 source "$ROOT/migrations/1790863209.sh" >/dev/null
unset OMARCHY_TEST_MISE_HAS_NPM_GROK
grep -Fx "$grok_package" "$stub_log" >/dev/null ||
fail "Grok registry migration rewrites the npm wrapper"
[[ ! -e $test_home/.grok/bin/grok && ! -e $test_home/.grok/bin/grok-1.0.44 && -e $test_home/.grok/bin/settings-keep ]] ||
fail "Grok registry migration removes the npm launcher's old binaries and nothing else"
rm -f "$test_home/.grok/bin/settings-keep"
grep -Fx "unuse -g $legacy_grok_package" "$mise_history" >/dev/null ||
fail "Grok registry migration drops the npm tool"
rm -f "$test_home/.local/bin/grok"
printf '#!/bin/bash\necho user-grok\n' >"$test_home/.local/bin/grok"
chmod +x "$test_home/.local/bin/grok"
: >"$stub_log"
: >"$mise_history"
OMARCHY_TEST_MISE_HAS_NPM_GROK=1 source "$ROOT/migrations/1790863209.sh" >/dev/null
unset OMARCHY_TEST_MISE_HAS_NPM_GROK
[[ $("$test_home/.local/bin/grok") == "user-grok" ]] ||
fail "Grok registry migration keeps a user-managed grok"
[[ ! -s $stub_log ]] || fail "Grok registry migration does not replace a user-managed grok"
grep -Fx "unuse -g $legacy_grok_package" "$mise_history" >/dev/null ||
fail "Grok registry migration drops the npm tool beside a user-managed grok"
cat >"$test_home/.local/bin/grok" <<'SH'
#!/bin/bash
mise use -g --quiet "grok" || exit 1
echo user-mise-grok
SH
chmod +x "$test_home/.local/bin/grok"
cp "$test_home/.local/bin/grok" "$test_tmp/user-mise-grok"
: >"$stub_log"
: >"$mise_history"
OMARCHY_TEST_MISE_HAS_NPM_GROK=1 source "$ROOT/migrations/1790863209.sh" >/dev/null
unset OMARCHY_TEST_MISE_HAS_NPM_GROK
cmp -s "$test_home/.local/bin/grok" "$test_tmp/user-mise-grok" ||
fail "Grok registry migration keeps a user script that calls mise"
[[ ! -s $stub_log ]] || fail "Grok registry migration does not replace a user script that calls mise"
grep -Fx "unuse -g $legacy_grok_package" "$mise_history" >/dev/null ||
fail "Grok registry migration drops the npm tool beside a user script"
rm -f "$test_home/.local/bin/grok"
rm -f "$test_home/.local/bin/grok"
: >"$stub_log"
: >"$mise_history"
OMARCHY_TEST_MISSING_COMMAND=grok source "$ROOT/migrations/1790863209.sh" >/dev/null
unset OMARCHY_TEST_MISSING_COMMAND
grep -Fx "$grok_package" "$stub_log" >/dev/null ||
fail "Grok registry migration installs the stub when grok is missing"
grep -Fx "unuse -g $legacy_grok_package" "$mise_history" >/dev/null &&
fail "Grok registry migration does not drop the npm tool when it is not installed"
rm -f "$test_home/.local/bin/grok"
: >"$stub_log"
: >"$mise_history"
OMARCHY_TEST_MISE_HAS_NPM_GROK=1 OMARCHY_TEST_MISSING_COMMAND=grok \
source "$ROOT/migrations/1790863209.sh" >/dev/null
unset OMARCHY_TEST_MISE_HAS_NPM_GROK OMARCHY_TEST_MISSING_COMMAND
grep -Fx "$grok_package" "$stub_log" >/dev/null ||
fail "Grok registry migration installs the stub after dropping a leftover npm tool"
grep -Fx "unuse -g $legacy_grok_package" "$mise_history" >/dev/null ||
fail "Grok registry migration drops a leftover npm tool when the wrapper is gone"
pass "agent migrations install working wrappers without overriding the preinstall opt-out"
"$ROOT/bin/omarchy-mise-install" "$muse_package" muse
touch "$test_home/.local/bin/agy" "$test_home/.local/bin/ori"
omarchy-remove-preinstalls >/dev/null
for command in agy omp ori grok crush cursor-agent muse; do
[[ ! -e $test_home/.local/bin/$command ]] || fail "Remove Preinstalls deletes the $command lazy stub"
done
pass "Remove Preinstalls deletes every optional agent lazy stub"
# Cursor's installer links the same path, so anything but the mise wrapper is
# the user's own install.
touch "$test_home/.local/bin/cursor-agent.official"
ln -s cursor-agent.official "$test_home/.local/bin/cursor-agent"
omarchy-remove-preinstalls >/dev/null
[[ -L $test_home/.local/bin/cursor-agent ]] || fail "Remove Preinstalls keeps an official Cursor CLI install"
rm -f "$test_home/.local/bin/cursor-agent" "$test_home/.local/bin/cursor-agent.official"
pass "Remove Preinstalls keeps an official Cursor CLI install"
printf '#!/bin/bash\necho user-muse\n' >"$test_home/.local/bin/muse"
chmod +x "$test_home/.local/bin/muse"
omarchy-remove-preinstalls >/dev/null
[[ $("$test_home/.local/bin/muse") == "user-muse" ]] || fail "Remove Preinstalls deletes a user-managed Muse"
rm "$test_home/.local/bin/muse"
pass "Remove Preinstalls keeps a user-managed Muse install"
[[ -z $(omarchy-default-agent) ]] || fail "default agent is unset until one is chosen"
pass "default agent is unset until one is chosen"
: >"$launch_log"
if omarchy-agent >"$test_tmp/no-agent-output" 2>&1; then
fail "agent launcher refuses to launch without a default"
fi
grep -Fq "Choose default agent with" "$test_tmp/no-agent-output" ||
fail "agent launcher explains that no default is set"
[[ ! -s $launch_log ]] || fail "agent launcher starts nothing without a default"
pass "agent launcher refuses to launch without a default"
# The keybinding uses --pick, where an error on stderr nobody sees would make
# the keypress look broken. It offers the choice instead.
: >"$launch_log"
: >"$menu_log"
omarchy-agent --pick
mapfile -d '' -t menu_args <"$menu_log"
[[ ${menu_args[*]} == "summon setup.default.agent" ]] ||
fail "--pick opens the agent defaults menu when none is set"
[[ ! -s $launch_log ]] || fail "--pick starts nothing when no agent is set"
pass "--pick opens the agent defaults menu when none is set"
source "$ROOT/default/bash/aliases"
[[ $(alias a) == "alias a='omarchy-agent --inline'" ]] ||
fail "terminal alias launches the default agent inline"
pass "terminal alias launches the default agent inline"
grep -Fq 'o.bind("SUPER + SHIFT + CTRL + A", "Agent", "omarchy-agent --pick")' \
"$ROOT/default/hypr/bindings/utilities.lua" ||
fail "agent launcher has a keyboard shortcut"
pass "agent launcher has a keyboard shortcut"
cat >"$mock_bin/omarchy-agent" <<'SH'
#!/bin/bash
printf '%s\0' omarchy-agent "$@" >"$OMARCHY_TEST_AGENT_OPEN_LOG"
SH
chmod +x "$mock_bin/omarchy-agent"
hash -r
declare -A expected_agents=(
[pi]="pi"
[omp]="omp"
[oh-my-pi]="omp"
[opencode]="opencode"
[open-code]="opencode"
[ori]="ori"
[openrouter]="ori"
[claude]="claude"
[claude-code]="claude"
[codex]="codex"
[crush]="crush"
[grok]="grok"
[agy]="agy"
[antigravity]="agy"
[antigravity-cli]="agy"
[gemini]="agy"
[gemini-cli]="agy"
[copilot]="copilot"
[github-copilot]="copilot"
[cursor]="cursor-agent"
[cursor-agent]="cursor-agent"
[muse]="muse"
[muse-code]="muse"
[musecode]="muse"
)
declare -A expected_packages=(
[pi]="pi"
[omp]="$omp_package"
[opencode]="opencode"
[ori]="$ori_package"
[claude]="claude"
[codex]="codex"
[crush]="$crush_package"
[grok]="$grok_package"
[agy]="$agy_package"
[copilot]="copilot"
[cursor-agent]="$cursor_agent_package"
[muse]="$muse_package"
)
for selection in "${!expected_agents[@]}"; do
expected=${expected_agents[$selection]}
: >"$agent_open_log"
: >"$stub_log"
OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent "$selection"
[[ $(omarchy-default-agent) == $expected ]] || fail "default agent canonicalizes $selection"
if [[ $expected == "claude" ]]; then
grep -qx claude-extension "$stub_log" || fail "Claude selection installs the browser extension"
else
[[ ! -s $stub_log ]] || fail "other agents do not install the Claude extension"
fi
mapfile -d '' -t mise_args <"$mise_log"
[[ ${mise_args[0]} == "use" && ${mise_args[1]} == "-g" ]] ||
fail "default agent installs $selection globally through mise"
case ${mise_args[2]} in
"${expected_packages[$expected]}") ;;
*) fail "default agent preserves $selection backend options" ;;
esac
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${#agent_open_args[@]} == 1 && ${agent_open_args[0]} == "omarchy-agent" ]] ||
fail "default agent opens $selection after selecting it"
done
pass "default agent selects and opens every supported provider and alias"
[[ -f $agent_file && ! -e $test_home/.local/state/omarchy/defaults/agent ]] ||
fail "default agent stores its selection in Omarchy user config"
pass "default agent stores its selection in Omarchy user config"
OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent pi
: >"$agent_open_log"
OMARCHY_TEST_AGENT_INSTALLED=true OMARCHY_TEST_EXTENSION_FAIL=true omarchy-default-agent claude >"$test_tmp/extension-failure" 2>&1
[[ $(omarchy-default-agent) == "claude" ]] || fail "extension installation failure still selects Claude"
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${agent_open_args[*]} == "omarchy-agent" ]] || fail "extension installation failure still launches Claude"
[[ ! -s $test_tmp/extension-failure ]] || fail "extension installation failure is silent"
pass "extension installation failure silently continues selecting and launching Claude"
OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent pi
: >"$notification_history"
: >"$agent_open_log"
: >"$terminal_log"
omarchy-default-agent github-copilot
mapfile -d '' -t terminal_args <"$terminal_log"
[[ ${terminal_args[0]} == "omarchy-default-agent" && ${terminal_args[1]} == "--install" && ${terminal_args[2]} == "copilot" ]] ||
fail "missing agent installation opens in a terminal"
[[ ! -s $notification_history ]] || fail "missing agent installation skips notifications"
[[ ! -s $agent_open_log ]] || fail "missing agent installation waits to open the agent"
[[ $(omarchy-default-agent) == "pi" ]] || fail "missing agent installation waits to change the selection"
omarchy-default-agent --install github-copilot >"$test_tmp/install-output"
mapfile -d '' -t mise_args <"$mise_log"
[[ ${mise_args[0]} == "use" && ${mise_args[1]} == "-g" && ${mise_args[2]} == "copilot" ]] ||
fail "visible agent installation activates the provider globally through mise"
[[ $(omarchy-default-agent) == "copilot" ]] || fail "visible agent installation changes the selection after mise succeeds"
[[ ! -s $notification_history ]] || fail "visible agent installation leaves progress to the terminal"
[[ $(<"$test_tmp/install-output") == $'\033[2J\033[3J\033[H' ]] ||
fail "visible agent installation clears its terminal before opening the agent"
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${#agent_open_args[@]} == 2 && ${agent_open_args[0]} == "omarchy-agent" && ${agent_open_args[1]} == "--inline" ]] ||
fail "newly installed agent opens in the installation terminal"
pass "missing agents install visibly and open in the same terminal"
: >"$notification_history"
: >"$agent_open_log"
: >"$terminal_log"
OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent github-copilot
[[ ! -s $terminal_log ]] || fail "installed agent selection skips the terminal"
[[ ! -s $notification_history ]] || fail "installed agent selection skips notifications"
mapfile -d '' -t mise_args <"$mise_log"
[[ ${mise_args[0]} == "use" && ${mise_args[1]} == "-g" && ${mise_args[2]} == "copilot" ]] ||
fail "default agent still activates an installed provider globally through mise"
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${#agent_open_args[@]} == 1 && ${agent_open_args[0]} == "omarchy-agent" ]] ||
fail "installed agent opens in a new terminal after selection"
pass "installed agents select and open without notifications"
# Cursor's installer links the wrapper's path, and the mise shims precede
# ~/.local/bin, so a mise copy would shadow the user's own install.
touch "$test_home/.local/bin/cursor-agent.official"
chmod +x "$test_home/.local/bin/cursor-agent.official"
ln -s cursor-agent.official "$test_home/.local/bin/cursor-agent"
: >"$terminal_log"
: >"$mise_log"
: >"$agent_open_log"
omarchy-default-agent cursor-agent
[[ ! -s $terminal_log ]] || fail "an official Cursor CLI install needs no install terminal"
[[ ! -s $mise_log ]] || fail "an official Cursor CLI install is left to itself by mise"
[[ $(<"$agent_file") == "cursor-agent" ]] || fail "an official Cursor CLI install becomes the default"
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${#agent_open_args[@]} == 1 && ${agent_open_args[0]} == "omarchy-agent" ]] ||
fail "an official Cursor CLI install opens after selection"
rm -f "$test_home/.local/bin/cursor-agent" "$test_home/.local/bin/cursor-agent.official"
printf '%s\n' copilot >"$agent_file"
pass "selecting an official Cursor CLI install skips mise"
# A file nothing can run is not an install; the wrapper is still wanted.
touch "$test_home/.local/bin/cursor-agent"
: >"$terminal_log"
omarchy-default-agent cursor-agent
mapfile -d '' -t terminal_args <"$terminal_log"
[[ ${terminal_args[*]} == "omarchy-default-agent --install cursor-agent" ]] ||
fail "a dead file at the wrapper's path still installs Cursor CLI"
rm -f "$test_home/.local/bin/cursor-agent"
pass "a dead file at the wrapper's path does not pass for an install"
: >"$agent_open_log"
if omarchy-default-agent unsupported >"$test_tmp/invalid-output" 2>&1; then
fail "default agent rejects unsupported providers"
fi
grep -F "Usage: omarchy-default-agent" "$test_tmp/invalid-output" >/dev/null ||
fail "default agent explains supported providers"
[[ $(omarchy-default-agent) == "copilot" ]] || fail "invalid selection preserves the current default agent"
[[ ! -s $agent_open_log ]] || fail "invalid selection does not open an agent"
pass "default agent rejects unsupported providers without changing the selection"
: >"$notification_history"
: >"$agent_open_log"
if OMARCHY_TEST_MISE_FAIL=true omarchy-default-agent --install codex >"$test_tmp/install-failure-output" 2>&1; then
fail "default agent rejects a failed mise installation"
fi
[[ $(omarchy-default-agent) == "copilot" ]] || fail "failed installation preserves the current default agent"
grep -F "Could not install Codex with mise" "$test_tmp/install-failure-output" >/dev/null ||
fail "default agent reports a failed mise installation in the terminal"
[[ ! -s $notification_history ]] || fail "failed visible agent installation skips notifications"
[[ ! -s $agent_open_log ]] || fail "failed installation does not open an agent"
pass "default agent opens only after mise installs the provider"
: >"$notification_history"
: >"$agent_open_log"
if OMARCHY_TEST_AGENT_INSTALLED=true OMARCHY_TEST_MISE_FAIL=true omarchy-default-agent codex >"$test_tmp/setup-failure-output" 2>&1; then
fail "default agent rejects a failed mise activation"
fi
[[ $(omarchy-default-agent) == "copilot" ]] || fail "failed activation preserves the current default agent"
grep -F "Could not set Codex as the default coding agent" "$test_tmp/setup-failure-output" >/dev/null ||
fail "default agent reports a failed activation for an installed provider"
[[ ! -s $notification_history ]] || fail "failed activation skips notifications"
[[ ! -s $agent_open_log ]] || fail "failed activation does not open an agent"
pass "default agent reports mise failures without notifications"
# Muse follows the shared mise installation and launch path.
: >"$notification_history"
: >"$agent_open_log"
: >"$terminal_log"
omarchy-default-agent muse
mapfile -d '' -t terminal_args <"$terminal_log"
[[ ${terminal_args[0]} == "omarchy-default-agent" && ${terminal_args[1]} == "--install" && ${terminal_args[2]} == "muse" ]] ||
fail "missing Muse installation opens in a terminal"
[[ ! -s $notification_history ]] || fail "missing Muse installation skips notifications"
[[ ! -s $agent_open_log ]] || fail "missing Muse installation waits to open the agent"
[[ $(omarchy-default-agent) == "copilot" ]] || fail "missing Muse installation waits to change the selection"
if OMARCHY_TEST_MISE_FAIL=true omarchy-default-agent --install muse >"$test_tmp/muse-install-failure-output" 2>&1; then
fail "missing Muse rejects a failed mise installation"
fi
[[ $(omarchy-default-agent) == "copilot" ]] || fail "failed Muse installation preserves the current default"
[[ ! -s $muse_login_log && ! -s $agent_open_log ]] || fail "failed Muse installation skips login and launch"
grep -F "Could not install Muse Code with mise" "$test_tmp/muse-install-failure-output" >/dev/null ||
fail "failed Muse installation identifies mise"
pass "failed Muse mise installation preserves the selection and skips login"
: >"$mise_history"
: >"$stub_log"
omarchy-default-agent --install muse >"$test_tmp/muse-install-output"
grep -Fx "use -g $muse_package" "$mise_history" >/dev/null || fail "visible Muse installation uses the HTTP backend"
[[ ! -s $stub_log ]] || fail "Muse selection recreates its preinstalled wrapper"
[[ ! -s $muse_login_log ]] || fail "Muse selection runs a separate login flow"
[[ $(omarchy-default-agent) == "muse" ]] || fail "visible Muse installation changes the selection"
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${#agent_open_args[@]} == 2 && ${agent_open_args[0]} == "omarchy-agent" && ${agent_open_args[1]} == "--inline" ]] ||
fail "newly installed Muse opens in the installation terminal"
pass "Muse installs visibly through mise and opens directly"
: >"$terminal_log"
: >"$muse_login_log"
: >"$agent_open_log"
OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent muse-code
[[ ! -s $terminal_log ]] || fail "installed Muse selection skips the terminal"
[[ ! -s $muse_login_log ]] || fail "installed Muse selection skips the login"
[[ $(omarchy-default-agent) == "muse" ]] || fail "default agent canonicalizes muse-code"
mapfile -d '' -t agent_open_args <"$agent_open_log"
[[ ${#agent_open_args[@]} == 1 && ${agent_open_args[0]} == "omarchy-agent" ]] ||
fail "installed Muse opens in a new terminal after selection"
pass "installed Muse selects and opens directly"
OMARCHY_TEST_AGENT_INSTALLED=true omarchy-default-agent pi
: >"$agent_open_log"
if OMARCHY_TEST_AGENT_INSTALLED=true OMARCHY_TEST_MISE_FAIL=true omarchy-default-agent musecode >"$test_tmp/muse-failure-output" 2>&1; then
fail "default agent rejects a failed Muse activation"
fi
[[ $(omarchy-default-agent) == "pi" ]] || fail "failed Muse activation preserves the current default agent"
grep -F "Could not set Muse Code as the default coding agent" "$test_tmp/muse-failure-output" >/dev/null ||
fail "default agent reports a failed Muse activation"
[[ ! -s $agent_open_log ]] || fail "failed Muse activation does not open an agent"
pass "default agent reports Muse mise failures without changing the selection"
# A manually installed launcher belongs to the user; selecting it must not
# install a second copy or replace it with the Omarchy wrapper.
printf '#!/bin/bash\necho user-muse\n' >"$test_home/.local/bin/muse"
chmod +x "$test_home/.local/bin/muse"
: >"$mise_history"
: >"$stub_log"
: >"$terminal_log"
omarchy-default-agent muse
[[ $(omarchy-default-agent) == "muse" ]] || fail "a user-installed Muse can be selected"
[[ ! -s $mise_history && ! -s $stub_log && ! -s $terminal_log ]] || fail "a user-installed Muse skips installation and wrapper creation"
[[ $("$test_home/.local/bin/muse") == "user-muse" ]] || fail "a user-installed Muse is preserved"
rm "$test_home/.local/bin/muse"
pass "selecting a user-installed Muse preserves its launcher"
rm "$mock_bin/omarchy-agent"
hash -r
assert_launched() {
local agent=$1
local description=$2
shift 2
# Every agent window launches under the same app-id, whichever agent is
# default, so window rules and themes see one class for all of them.
local expected=(--app-id=org.omarchy.agent "$@")
mapfile -d '' -t actual <"$launch_log"
(( ${#actual[@]} == ${#expected[@]} )) ||
fail "$agent launch $description" "expected: ${expected[*]}\nactual: ${actual[*]}"
for ((index = 0; index < ${#expected[@]}; index++)); do
case ${actual[$index]} in
"${expected[$index]}") ;;
*) fail "$agent launch $description" "expected: ${expected[*]}\nactual: ${actual[*]}" ;;
esac
done
}
assert_launch() {
local agent=$1
shift
printf '%s\n' "$agent" >"$agent_file"
omarchy-agent-prompt "Review this" project
assert_launched "$agent" "forwards the interactive prompt" "$@"
}
assert_bypass() {
local agent=$1
shift
printf '%s\n' "$agent" >"$agent_file"
omarchy-agent
assert_launched "$agent" "skips permission prompts" "$@"
}
assert_launch pi pi "Review this project"
assert_launch omp omp --auto-approve -- "Review this project"
assert_launch opencode opencode --auto --prompt "Review this project"
assert_launch ori ori code --interactive --prompt "Review this project"
assert_launch claude claude --permission-mode auto -- "Review this project"
assert_launch codex codex --approve-for-me -- "Review this project"
assert_launch muse muse --approval-mode never -- "Review this project"
assert_launch crush crush run "Review this project"
assert_launch grok grok --permission-mode bypassPermissions -- "Review this project"
assert_launch cursor-agent cursor-agent --yolo --trust agent -- "Review this project"
assert_launch hermes env -u HERMES_SESSION_SOURCE hermes chat --yolo --tui "--query=Review this project"
assert_launch agy agy --dangerously-skip-permissions --prompt-interactive "Review this project"
assert_launch copilot copilot --allow-all --interactive "Review this project"
pass "agent launcher adapts initial prompts for every supported agent"
literal_muse_prompt=$'--disable-sandbox !Crash {$(touch must-not-run)}\ntrailing\\ '
printf '%s\n' "muse" >"$agent_file"
omarchy-agent-prompt "$literal_muse_prompt"
assert_launched muse "separates prompt text from options" muse --approval-mode never -- "$literal_muse_prompt"
pass "Muse receives option-like prompts as one literal argument"
literal_hermes_prompt=$' --help !Crash /quit {$(touch must-not-run)}\ntrailing\\ '
printf '%s\n' "hermes" >"$agent_file"
omarchy-agent-prompt "$literal_hermes_prompt"
assert_launched hermes "binds its literal initial prompt" env -u HERMES_SESSION_SOURCE \
hermes chat --yolo --tui "--query=$literal_hermes_prompt"
pass "Hermes receives prompted launches as one literal query argument"
assert_bypass pi pi
assert_bypass omp omp --auto-approve
assert_bypass opencode opencode --auto
assert_bypass ori ori code
assert_bypass claude claude --permission-mode auto
assert_bypass codex codex --approve-for-me
assert_bypass muse muse --approval-mode never
assert_bypass crush crush --yolo
assert_bypass grok grok --permission-mode bypassPermissions
assert_bypass cursor-agent cursor-agent --yolo --trust
assert_bypass hermes hermes --yolo
assert_bypass agy agy --dangerously-skip-permissions
assert_bypass copilot copilot --allow-all
pass "agent launcher skips permission prompts for every supported agent"
printf '%s\n' "opencode" >"$agent_file"
omarchy-agent
mapfile -d '' -t launch_args <"$launch_log"
[[ ${launch_args[*]} == "--app-id=org.omarchy.agent opencode --auto" ]] ||
fail "agent launcher starts the selected agent without an initial prompt"
pass "agent launcher starts the selected agent without an initial prompt"
omarchy-agent-prompt --inline "Review this project"
mapfile -d '' -t inline_args <"$inline_log"
[[ ${inline_args[*]} == "opencode --auto --prompt Review this project" ]] ||
fail "inline agent launcher runs in the current terminal"
pass "inline agent launcher runs in the current terminal"
# The prompt route exists so the router can tell a prompt from a subcommand, so
# cover the public routes and not only the binaries behind them.
: >"$launch_log"
omarchy agent
mapfile -d '' -t launch_args <"$launch_log"
[[ ${launch_args[*]} == "--app-id=org.omarchy.agent opencode --auto" ]] ||
fail "omarchy agent routes to the launcher"
# With an agent chosen there is nothing to pick, so the keybinding launches.
: >"$launch_log"
: >"$menu_log"
omarchy-agent --pick
mapfile -d '' -t launch_args <"$launch_log"
[[ ${launch_args[*]} == "--app-id=org.omarchy.agent opencode --auto" ]] ||
fail "--pick launches once an agent is chosen"
[[ ! -s $menu_log ]] || fail "--pick opens no menu once an agent is chosen"
pass "--pick launches once an agent is chosen"
: >"$launch_log"
omarchy agent prompt "Review this project"
mapfile -d '' -t launch_args <"$launch_log"
[[ ${launch_args[*]} == "--app-id=org.omarchy.agent opencode --auto --prompt Review this project" ]] ||
fail "omarchy agent prompt routes the prompt to the launcher"
: >"$launch_log"
if omarchy agent Review this project >"$test_tmp/positional-output" 2>&1; then
fail "omarchy agent rejects a positional prompt"
fi
grep -F "omarchy agent prompt" "$test_tmp/positional-output" >/dev/null ||
fail "omarchy agent points a positional prompt at the prompt route"
[[ ! -s $launch_log ]] || fail "omarchy agent starts nothing for a positional prompt"
pass "omarchy agent keeps prompts on the prompt route"
printf '%s\n' "missing" >"$agent_file"
if OMARCHY_TEST_MISSING_COMMAND=missing omarchy-agent >"$test_tmp/missing-output" 2>&1; then
fail "agent launcher rejects a missing default command"
fi
grep -F "missing is not installed" "$test_tmp/missing-output" >/dev/null ||
fail "agent launcher explains when the default command is missing"
pass "agent launcher reports a missing default command"
# OpenClaw comes from its pacman package, not mise: choosing it must route
# through omarchy-install-openclaw-cli and never touch a mise environment.
cat >"$mock_bin/omarchy-pkg-present" <<'SH'
#!/bin/bash
[[ $1 == openclaw && ${OMARCHY_TEST_OPENCLAW_INSTALLED:-false} == "true" ]]
SH
cat >"$mock_bin/omarchy-pkg-add" <<'SH'
#!/bin/bash
printf '%s\n' "pkg-add $*" >>"$OMARCHY_TEST_STUB_LOG"
SH
cat >"$mock_bin/omarchy-launch-openclaw" <<'SH'
#!/bin/bash
printf '%s\0' omarchy-launch-openclaw "$@" >"$OMARCHY_TEST_AGENT_INLINE_LOG"
SH
cat >"$mock_bin/openclaw" <<'SH'
#!/bin/bash
exit 0
SH
chmod +x "$mock_bin/omarchy-pkg-present" "$mock_bin/omarchy-pkg-add" \
"$mock_bin/omarchy-launch-openclaw" "$mock_bin/openclaw"
: >"$launch_log"
: >"$terminal_log"
: >"$mise_history"
OMARCHY_TEST_OPENCLAW_INSTALLED=true omarchy-default-agent openclaw
read -r chosen <"$agent_file"
[[ $chosen == openclaw ]] || fail "choosing OpenClaw records it as the default agent"
mapfile -d '' -t launch_args <"$launch_log"
[[ ${launch_args[*]} == "--app-id=org.omarchy.agent omarchy-launch-openclaw --tui" ]] ||
fail "choosing OpenClaw launches its terminal UI"
[[ ! -s $terminal_log ]] || fail "an installed OpenClaw needs no install terminal"
! grep -q 'use -g openclaw' "$mise_history" || fail "OpenClaw never installs through mise"
pass "choosing OpenClaw uses the package and launches its terminal UI"
: >"$terminal_log"
OMARCHY_TEST_OPENCLAW_INSTALLED=false omarchy-default-agent openclaw
mapfile -d '' -t terminal_args <"$terminal_log"
[[ ${terminal_args[*]} == "omarchy-default-agent --install openclaw" ]] ||
fail "a missing OpenClaw routes through the install terminal"
pass "a missing OpenClaw routes through the install terminal"
: >"$stub_log"
: >"$inline_log"
OMARCHY_TEST_OPENCLAW_INSTALLED=false omarchy-default-agent --install openclaw >/dev/null
grep -Fx "pkg-add openclaw" "$stub_log" >/dev/null ||
fail "installing OpenClaw as default agent adds its package"
mapfile -d '' -t inline_args <"$inline_log"
[[ ${inline_args[*]} == "omarchy-launch-openclaw --tui" ]] ||
fail "installing OpenClaw as default agent hands over to its terminal UI"
pass "installing OpenClaw as default agent adds its package"
: >"$launch_log"
omarchy agent prompt "Review this project"
mapfile -d '' -t launch_args <"$launch_log"
# Element-wise: the prompt must travel as one argv entry, which a space-joined
# comparison could not tell apart from a prompt split into words.
[[ ${#launch_args[@]} == 5 &&
${launch_args[0]} == "--app-id=org.omarchy.agent" &&
${launch_args[1]} == "omarchy-launch-openclaw" &&
${launch_args[2]} == "--tui" &&
${launch_args[3]} == "--message" &&
${launch_args[4]} == "Review this project" ]] ||
fail "OpenClaw receives prompts through --message" "argv: ${launch_args[*]}"
pass "OpenClaw receives prompts through --message"