* 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>
941 lines
42 KiB
Bash
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"
|