Files
omarchy/bin/omarchy-agent-account-add
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

224 lines
7.3 KiB
Bash
Executable File

#!/bin/bash
# omarchy:summary=Sign in to a Claude, Codex, or Grok subscription
# omarchy:args=[--check] [--events] [--reauth <account>] [claude|codex|grok] [label]
# omarchy:examples=omarchy agent account add claude | omarchy agent account add Work | omarchy agent account add codex Side
set -uo pipefail
# --check prints, per provider, whether adding one now would be its first
# sign-in, an additional account, or not possible yet. --events is for the
# agents panel: progress arrives as `@@omarchy <event> <detail>` lines mixed
# into the CLI's own output (which carries codes the panel shows), nothing
# waits on a terminal, and the result also lands as a notification in case
# the panel has closed.
# --reauth <account> signs an account that's already here in again, in its
# own home, for when its sign-in has lapsed.
check=false
events=false
reauth=""
while [[ ${1:-} == --* ]]; do
case "$1" in
--check) check=true ;;
--events) events=true ;;
--reauth)
reauth="${2:-}"
shift
;;
*) break ;;
esac
shift
done
# Whether a provider's own home (~/.claude, ~/.codex, ~/.grok) is signed in.
primary_signed_in() {
omarchy-agent-account-state list "$1" | jq -e '.[0].accounts | any(.primary and .signedIn)' >/dev/null
}
if [[ $check == "true" ]]; then
for p in claude codex grok; do
if primary_signed_in "$p"; then
echo "$p additional"
else
echo "$p first"
fi
done
exit 0
fi
# The provider can be left out when it's your default agent:
# `omarchy agent account add Work`.
if [[ ${1:-} != "claude" && ${1:-} != "codex" && ${1:-} != "grok" ]]; then
default=$(omarchy-default-agent)
[[ $default == "claude" || $default == "codex" || $default == "grok" ]] && set -- "$default" "$@"
fi
case "${1:-}" in
claude) provider="claude"; name="Claude"; site="claude.ai"; package="claude"; home_env="CLAUDE_CONFIG_DIR" ;;
codex) provider="codex"; name="Codex"; site="chatgpt.com"; package="codex"; home_env="CODEX_HOME" ;;
grok) provider="grok"; name="Grok"; site="x.ai"; package="grok"; home_env="GROK_HOME" ;;
*)
echo "Usage: omarchy-agent-account-add [--check] [--events] [--reauth <account>] [claude|codex|grok] [label]" >&2
exit 1
;;
esac
label="${2:-}"
say() {
if [[ $events == "true" ]]; then
printf '@@omarchy status %s\n' "$*"
else
echo "$*"
fi
}
finish() {
if [[ $events == "true" ]]; then
printf '@@omarchy done %s\n' "$1"
omarchy-notification-send -g 󰚩 "$1"
else
echo
echo "$1"
fi
}
fail() {
if [[ $events == "true" ]]; then
printf '@@omarchy error %s\n' "$1"
omarchy-notification-send -g 󰚩 -u critical "Couldn't add the $name account" "$1"
else
echo "$1" >&2
fi
exit 1
}
# Cancelling from the panel stops the CLI's login too, and leaves no
# half-made home behind.
home=""
browser=""
cleanup() {
[[ -n $browser ]] && rm -f "$browser"
[[ -n $home && -d $home && $home == */.pending/* ]] && rm -rf "$home"
}
trap cleanup EXIT
trap 'pkill -TERM -P $$; exit 130' TERM INT
# Bash holds a trap until a foreground command finishes, and a login waits on
# the browser for as long as it takes. Running it in the background behind a
# `wait` lets Cancel stop it at once. It keeps this script's stdin, where the
# panel sends a pasted code.
interruptible() {
"$@" <&0 &
wait $!
}
if omarchy-cmd-missing "$provider"; then
say "Installing the $name CLI…"
if [[ $events == "true" ]]; then
mise use -g "$package" >/dev/null 2>&1 || fail "Installing the $name CLI didn't finish."
else
mise use -g "$package" || exit 1
fi
fi
# Your main browser is almost certainly signed in to the account you already
# have, and a login would quietly reuse it. The CLIs open their login page
# through $BROWSER, so this points it at a private window instead.
private_browser() {
browser=$(mktemp "${XDG_RUNTIME_DIR:-/tmp}/omarchy-account-browser.XXXXXX")
printf '#!/bin/bash\nexec omarchy-launch-browser --private "$1"\n' >"$browser"
chmod +x "$browser"
}
case "$provider" in
claude) login_command=(claude auth login) ;;
codex) login_command=(codex login) ;;
grok) login_command=(grok login) ;;
esac
# The CLI's own home, whatever this shell has pointed it at.
login() {
interruptible env -u CLAUDE_CONFIG_DIR -u CODEX_HOME -u GROK_HOME "${login_command[@]}"
}
# Signing an account that's already here in again, where it lives: the
# primary home through the normal browser, an added one through a private
# window. Its home is never recreated or removed.
if [[ -n $reauth ]]; then
if [[ $reauth == ":primary" ]]; then
account_home="$HOME/.$provider"
else
account_home=$(omarchy-agent-account-state homes "$provider" | awk -F'\t' -v id="$reauth" '$1 == id { print $2 }')
fi
[[ -n $account_home ]] || fail "No $name account named $reauth."
if [[ $account_home == "$HOME/.$provider" ]]; then
say "Sign in to $name again in the browser window that opens."
login || fail "The $name sign-in didn't finish."
else
say "Sign in again as this account in the private window that opens."
private_browser
interruptible env BROWSER="$browser" "$home_env=$account_home" "${login_command[@]}" || fail "The $name sign-in didn't finish."
fi
omarchy-agent-usage-update --force "$provider" >/dev/null 2>&1 &
finish "Signed in to $name again."
exit 0
fi
# The first subscription signs in where the CLI always looks, through your
# normal browser: nothing is signed in there yet that it could be mistaken for.
if ! primary_signed_in "$provider"; then
say "Sign in to $name in the browser window that opens."
if login && primary_signed_in "$provider"; then
# The first agent signed in on a machine with none chosen becomes the
# default, so `omarchy agent` and the panel's starter prompts have one to
# run. A default someone already picked is never touched.
if [[ -z $(omarchy-default-agent) ]]; then
mkdir -p "$HOME/.config/omarchy/defaults"
printf '%s\n' "$provider" >"$HOME/.config/omarchy/defaults/agent"
fi
omarchy-agent-usage-update --force "$provider" >/dev/null 2>&1 &
finish "Signed in to $name."
else
fail "The $name sign-in didn't finish."
fi
else
if [[ -z $label && $events == "false" && -t 0 ]]; then
label=$(gum input --placeholder "Work" --prompt "Name this $name account: ") || exit 130
fi
if [[ $events == "true" ]]; then
say "Sign in as the account you're adding in the private window that opens."
else
cat <<EOF
Sign in as the account you're adding in the private window that opens.
If a private window was already open, close it first, or $site may reuse whoever it has signed in.
Don't log out of the $name CLI to do this: logging out revokes the saved sign-in.
EOF
fi
home=$(omarchy-agent-account-state begin "$provider") || fail "Couldn't set up a home for the new account."
private_browser
interruptible env BROWSER="$browser" "$home_env=$home" "${login_command[@]}"
if account=$(omarchy-agent-account-state register "$provider" "$label" "$home" 2>&1); then
home=""
added=$(jq -r '.label + (if .email != "" then " (" + .email + ")" else "" end)' <<<"$account")
omarchy-agent-usage-update --force "$provider" >/dev/null 2>&1 &
if [[ $events == "true" ]]; then
finish "Added $added."
else
finish "Added $added."
echo "Switch to it with: omarchy agent account use $provider $(jq -r .id <<<"$account")"
fi
else
home=""
fail "$account"
fi
fi