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>
This commit is contained in:
authored and GitHub committed 2026-10-02 03:34:05 +02:00
1 parent f45461a38f
commit 821ae58905
17 files changed
+446 -120

No files matched your search

+2 -3
View File
@@ -192,13 +192,12 @@ OMARCHY_TEST_DEFAULT_AGENT="" omarchy-agent-account-add grok </dev/null >/dev/nu
fail "a first Grok sign-in lands in ~/.grok through the normal browser"
pass "Grok signs in its first account"
mkdir -p "$HOME/.grok/bin" && touch "$HOME/.grok/bin/grok"
OMARCHY_TEST_LOGIN_UUID=u-grok-2 OMARCHY_TEST_LOGIN_EMAIL=side@example.com \
omarchy-agent-account-add grok Side </dev/null >/dev/null
[[ $(omarchy-agent-account-list grok --json | jq -c '.[0].accounts[1] | {id, email, plan}') == '{"id":"side","email":"side@example.com","plan":"SuperGrok"}' ]] ||
fail "a Grok account reads its identity and plan from its own home" "$(omarchy-agent-account-list grok --json)"
[[ $(readlink "$accounts/grok/side/bin") == "$HOME/.grok/bin" && $(readlink "$accounts/grok/side/sessions") == "$HOME/.grok/sessions" ]] ||
fail "a Grok account shares the CLI and sessions with the primary"
[[ $(readlink "$accounts/grok/side/sessions") == "$HOME/.grok/sessions" ]] ||
fail "a Grok account shares sessions with the primary"
grep -qx -- "--private https://auth.x.ai/oauth/authorize" "$OMARCHY_TEST_BROWSER_LOG" ||
fail "a second Grok login opens in a private window" "$(cat "$OMARCHY_TEST_BROWSER_LOG")"
omarchy-agent-account-use grok side >/dev/null
+21 -5
View File
@@ -102,17 +102,25 @@ record=$(collect)
fail "every Grok account reports its own plan and credits" "$record"
pass "every Grok account reports its own plan and credits"
# Prompts and sessions come from each session's summary; no tokens are claimed.
# Sessions come from each session's summary; tokens and today's prompts from
# its usage.json, one entry per finished turn, with cached input kept apart.
sessions="$HOME/.grok/sessions/%2Fhome%2Fme"
now=$(python3 -c 'import datetime as dt; print(dt.datetime.now(dt.timezone.utc).isoformat())')
mkdir -p "$sessions/today-1" "$sessions/today-2" "$sessions/old"
jq -n --arg at "$now" '{last_active_at: $at, num_messages: 3, current_model_id: "grok-4.7"}' >"$sessions/today-1/summary.json"
jq -n --arg at "$now" '{last_active_at: $at, num_messages: 3}' >"$sessions/today-1/summary.json"
jq -n --arg at "$now" '{last_active_at: $at, num_messages: 2}' >"$sessions/today-2/summary.json"
jq -n '{last_active_at: "2026-01-02T10:00:00Z", num_messages: 5}' >"$sessions/old/summary.json"
jq -n --arg at "$now" '{turns: [
{endedAt: $at, modelUsage: {"grok-4.7-build": {inputTokens: 1000, cachedReadTokens: 800, outputTokens: 50, cacheCreationTokens: 0, totalTokens: 1050}}},
{endedAt: $at, modelUsage: {"grok-4.7-build": {inputTokens: 200, cachedReadTokens: 100, outputTokens: 10, cacheCreationTokens: 5, totalTokens: 210}}}
]}' >"$sessions/today-1/usage.json"
jq -n '{turns: [{endedAt: "2026-01-02T10:00:00Z", modelUsage: {"grok-4.6": {inputTokens: 500, cachedReadTokens: 0, outputTokens: 20, cacheCreationTokens: 0, totalTokens: 520}}}]}' >"$sessions/old/usage.json"
record=$(collect)
[[ $(jq -c '{hasLocalStats, todaySessions, totalPrompts, totalSessions, activeDays, claimed: (has("todayTotalTokens") or has("todayPrompts"))}' <<<"$record") == '{"hasLocalStats":true,"todaySessions":2,"totalPrompts":10,"totalSessions":3,"activeDays":2,"claimed":false}' ]] ||
fail "Grok counts prompts and sessions from its session summaries" "$record"
pass "Grok counts prompts and sessions from its session summaries"
[[ $(jq -c '{hasLocalStats, todayPrompts, todaySessions, totalPrompts, totalSessions, activeDays, todayTotalTokens, todayTokensByModel, today: .recentDays[6].messageCount}' <<<"$record") == '{"hasLocalStats":true,"todayPrompts":2,"todaySessions":2,"totalPrompts":10,"totalSessions":3,"activeDays":2,"todayTotalTokens":1265,"todayTokensByModel":{"grok-4.7-build":1265},"today":1265}' ]] ||
fail "Grok counts sessions, prompts, and tokens from its session files" "$record"
[[ $(jq -cS '.modelUsage' <<<"$record") == '{"grok-4.6":{"cacheCreationInputTokens":0,"cacheReadInputTokens":0,"inputTokens":500,"outputTokens":20},"grok-4.7-build":{"cacheCreationInputTokens":5,"cacheReadInputTokens":900,"inputTokens":300,"outputTokens":60}}' ]] ||
fail "Grok's tokens by model keep cached input apart" "$record"
pass "Grok counts sessions, prompts, and tokens from its session files"
# A limits-only refresh reuses the last scan rather than reading every summary.
mkdir -p "$sessions/later"
@@ -120,3 +128,11 @@ jq -n --arg at "$now" '{last_active_at: $at, num_messages: 1}' >"$sessions/later
record=$(COLLECT_ARGS="--limits-only" collect)
[[ $(jq -r '.totalSessions' <<<"$record") == 3 ]] || fail "a limits-only refresh reuses the session scan" "$record"
pass "a limits-only refresh reuses the session scan"
# A scan from another day is never reused, so yesterday's sessions don't
# count as today's after midnight.
jq '.day = "2000-01-01"' "$XDG_CACHE_HOME/omarchy/agent-usage/grok-stats.json" >"$test_tmp/stats.json"
mv "$test_tmp/stats.json" "$XDG_CACHE_HOME/omarchy/agent-usage/grok-stats.json"
record=$(COLLECT_ARGS="--limits-only" collect)
[[ $(jq -r '.totalSessions' <<<"$record") == 4 ]] || fail "a scan from another day is made again" "$record"
pass "a scan from another day is made again"
+7
View File
@@ -33,4 +33,11 @@ assert(!/t === "a" \|\| t === "A"/.test(panelSource), 'adding an account has no
assert(/if \(!accounts\[a\]\.active\) \{/.test(panelSource) && /if \(row\.length > 0\) rows\.push\(row\)/.test(panelSource), 'the active account with nothing to fix is not a keyboard stop')
const mainSource = fs.readFileSync(root + '/shell/plugins/agents/Main.qml', 'utf8')
assert(/var from = Math\.min\(0\.8, \(threshold - 15\) \/ 100\)/.test(mainSource), 'faster checks start 15 points below the switch threshold')
assert(/rows\.push\(\[\{ kind: "provider", index: p \}\]\)/.test(panelSource), "every agent's header is a keyboard stop")
assert(/reorderable: root\.addStage === "" && !root\.renaming/.test(panelSource) && /onEditingChanged: root\.renaming = editing/.test(panelSource) && /onReorderRequested: function\(dy\) \{ root\.reorderProvider\(dy\) \}/.test(panelSource), 'Ctrl+Up/Down moves the agent the cursor is in')
assert(/onReleased: root\.dropProvider\(\)/.test(panelSource), 'an agent can be dragged by its mark')
assert(/function moveProvider\(id, to\)/.test(mainSource) && /return orderedProviders\(result\)/.test(mainSource), 'the agents keep the order they were moved into')
const catcherSource = fs.readFileSync(root + '/shell/Ui/PanelKeyCatcher.qml', 'utf8')
assert(/if \(reorderable && \(event\.modifiers & Qt\.ControlModifier\)\)/.test(catcherSource), 'only panels that ask for it turn Ctrl+Up/Down into a reorder')
assert(/if \(\["account", "autoswitch", "signin"\]\.indexOf\(target\.kind\) < 0\) return -1/.test(panelSource), 'Ctrl+Up/Down does nothing outside an agent')
JS
+116 -3
View File
@@ -71,6 +71,11 @@ if [[ $1 == "where" ]]; then
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
@@ -120,7 +125,8 @@ export OMARCHY_TEST_AGENT_MENU_LOG="$menu_log"
export OMARCHY_TEST_MUSE_LOGIN_LOG="$muse_login_log"
export OMARCHY_PATH="$ROOT"
grok_package="npm:@xai-official/grok"
grok_package="grok"
legacy_grok_package="npm:@xai-official/grok"
omp_package="github:can1357/oh-my-pi"
crush_package="crush"
agy_package="antigravity-cli"
@@ -151,7 +157,7 @@ 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 grok" "$stub_log" >/dev/null || fail "user setup creates the Grok 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"
@@ -202,7 +208,7 @@ 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 "$grok_package grok" "$stub_log" >/dev/null || fail "agent migration creates the Grok 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"
@@ -302,8 +308,115 @@ source "$ROOT/migrations/1785846769.sh" >/dev/null
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
-46
View File
@@ -1,46 +0,0 @@
#!/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
export HOME="$test_tmp/home"
mkdir -p "$HOME/.grok/bin" "$test_tmp/bin" "$test_tmp/installs/npm-xai-official-grok/1.0.44"
# mise reports the installed release by its directory; running grok under it
# stands in for the npm launcher unpacking that release.
cat >"$test_tmp/bin/mise" <<SH
#!/bin/bash
case "\$1" in
up) ;;
where) echo "$test_tmp/installs/npm-xai-official-grok/1.0.44" ;;
x) echo ran >"$test_tmp/grok-ran"; touch "\$HOME/.grok/bin/grok-1.0.44"; ln -sfn grok-1.0.44 "\$HOME/.grok/bin/grok" ;;
esac
SH
chmod +x "$test_tmp/bin/mise"
echo old >"$HOME/.grok/bin/grok-1.0.30"
ln -s grok-1.0.30 "$HOME/.grok/bin/grok"
PATH="$test_tmp/bin:$ROOT/bin:$PATH" "$ROOT/bin/omarchy-update-mise" >/dev/null
[[ $(readlink "$HOME/.grok/bin/grok") == "grok-1.0.44" && ! -e $HOME/.grok/bin/grok-1.0.30 ]] ||
fail "an update points Grok at the installed release and drops the old one" "$(ls -la "$HOME/.grok/bin")"
pass "an update points Grok at the installed release and drops the old one"
rm -f "$test_tmp/grok-ran"
PATH="$test_tmp/bin:$ROOT/bin:$PATH" "$ROOT/bin/omarchy-update-mise" >/dev/null
[[ ! -e $test_tmp/grok-ran ]] || fail "a current Grok is left alone"
pass "a current Grok is left alone"
# An unpack that never arrives leaves the old release running.
rm -f "$HOME/.grok/bin/grok" "$HOME/.grok/bin/grok-1.0.44"
echo old >"$HOME/.grok/bin/grok-1.0.30"
ln -s grok-1.0.30 "$HOME/.grok/bin/grok"
sed -i 's/^ x) .*/ x) exit 1 ;;/' "$test_tmp/bin/mise"
PATH="$test_tmp/bin:$ROOT/bin:$PATH" "$ROOT/bin/omarchy-update-mise" >/dev/null
[[ $(readlink "$HOME/.grok/bin/grok") == "grok-1.0.30" && -e $HOME/.grok/bin/grok-1.0.30 ]] ||
fail "a failed unpack keeps the old Grok release" "$(ls -la "$HOME/.grok/bin")"
pass "a failed unpack keeps the old Grok release"