A Quickshell plugin for the Omarchy shell (v4's bar is Quickshell, not Waybar). The icon is the mode; clicking it opens a panel that switches. State comes from watching health.json rather than polling the CLI, so the widget costs nothing while idle and a switch made in a terminal shows up in the bar on its own. state.json is the fallback, because it exists from install onward where health.json only appears once claude-mode has run. The marks are the providers' real logos, drawn as vector paths through QtQuick.Shapes rather than set as font glyphs - three of the four have no Nerd Font pictograph at all, and paths take the bar's foreground colour and follow the theme. Claude, OpenRouter and LM Studio from simple-icons, Z.AI from lobe-icons; trademarks belong to their owners. Zhipu's mark was rejected for Z.AI: it is a dense lattice that is unreadable below ~40px. Rendering them at 13px took three fixes. A layer rasterises the Shape at its own size and then scales the texture, so a 24px buffer minified to 13 resampled two pixels into one and the Claude burst lost rays; without the layer the scale is a transform on the geometry and rasterisation happens once, at final resolution. CurveRenderer replaces the tessellating default. And the size is forced odd, because a radially symmetric mark puts its vertical and horizontal arms on the centre line, which is a pixel centre at odd sizes and the seam between two pixels at even ones, where each arm splits its coverage and greys out. Measured against a cairo render at the same size, the result is now identical. Sizing is measured rather than guessed. Every stock glyph in this bar paints 11px of ink; the marks fill their box instead of carrying a font's padding, so the box is the smaller number. Each mark also carries an optical scale from two measurements of a 200px render - LM Studio's filled container covers 69% of its box against ~38% for the others, and Z.AI and OpenRouter are wide-but-short marks spanning ~84% of the box height. Choosing a target does not switch immediately. It runs the CLI's own preflight, and if that refuses, the panel names what is missing and offers the fix - a terminal for the hidden key prompt, a re-check once a server is up, or the server form. If sessions are running it lists them by terminal and directory, marks any mid-request, and asks whether to restart them, close them, or leave them. The session action is applied strictly after the write, since restarting first would only bring them back up on the provider just left. The server form edits an LM Studio preset's base URL and whether it needs an API key, reachable from the gear on any LM Studio preset row - per row, because two presets can point at two different machines - and from the failure card. The shipped local default is untouched unless it is changed.
92 lines
3.3 KiB
Bash
Executable File
92 lines
3.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Installs the claude-mode bar widget into the Omarchy shell.
|
|
#
|
|
# Two steps: drop the plugin into ~/.config/omarchy/plugins/, and add its id to
|
|
# the bar layout in ~/.config/omarchy/shell.json. Both are idempotent, and the
|
|
# shell hot-reloads each of them, so nothing has to be restarted.
|
|
#
|
|
# Only ~/.config is touched. /usr/share/omarchy is owned by the package and is
|
|
# rewritten by `omarchy update`, so nothing may be installed there.
|
|
|
|
set -euo pipefail
|
|
|
|
PLUGIN_ID="smoido.claude-mode"
|
|
SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$PLUGIN_ID"
|
|
DEST_DIR="$HOME/.config/omarchy/plugins/$PLUGIN_ID"
|
|
SHELL_JSON="$HOME/.config/omarchy/shell.json"
|
|
|
|
# Where in the bar the widget lands, and which existing widget it sits before.
|
|
# The AI-adjacent group on the right is the natural neighbourhood for it.
|
|
SECTION="${CM_BAR_SECTION:-right}"
|
|
BEFORE="${CM_BAR_BEFORE:-omarchy.agents}"
|
|
|
|
green() { printf ' \033[32mok \033[0m %s\n' "$*"; }
|
|
warn() { printf ' \033[33mwarn\033[0m %s\n' "$*"; }
|
|
fail() { printf ' \033[31mFAIL\033[0m %s\n' "$*"; }
|
|
|
|
printf '\ninstalling %s -> %s\n' "$PLUGIN_ID" "$DEST_DIR"
|
|
|
|
[ -d "$SRC" ] || { fail "plugin source not found: $SRC"; exit 1; }
|
|
command -v python3 >/dev/null 2>&1 || { fail 'python3 required'; exit 1; }
|
|
|
|
if [ ! -d "$HOME/.config/omarchy" ]; then
|
|
fail 'no ~/.config/omarchy - this does not look like an Omarchy system'
|
|
exit 1
|
|
fi
|
|
|
|
# --- payload ---------------------------------------------------------------
|
|
mkdir -p "$DEST_DIR"
|
|
for f in manifest.json BarWidget.qml Panel.qml BrandIcon.qml Modes.js; do
|
|
[ -f "$SRC/$f" ] || { fail "missing from payload: $f"; exit 1; }
|
|
install -m 0644 "$SRC/$f" "$DEST_DIR/$f"
|
|
done
|
|
green 'plugin files copied'
|
|
|
|
# --- bar layout ------------------------------------------------------------
|
|
# shell.json is the user's own file and may carry unrelated customisation, so
|
|
# it is read, minimally amended, and written back rather than templated over.
|
|
if [ ! -f "$SHELL_JSON" ]; then
|
|
warn "no $SHELL_JSON - add the widget yourself once the shell writes one"
|
|
exit 0
|
|
fi
|
|
|
|
cp "$SHELL_JSON" "$SHELL_JSON.bak.$(date +%s)"
|
|
|
|
python3 - "$SHELL_JSON" "$PLUGIN_ID" "$SECTION" "$BEFORE" <<'PYEOF'
|
|
import json, sys
|
|
|
|
path, plugin_id, section, before = sys.argv[1:5]
|
|
with open(path, encoding="utf-8") as fh:
|
|
cfg = json.load(fh)
|
|
|
|
layout = cfg.setdefault("bar", {}).setdefault("layout", {})
|
|
entries = layout.setdefault(section, [])
|
|
|
|
def has(entry_list):
|
|
return any(isinstance(e, dict) and e.get("id") == plugin_id for e in entry_list)
|
|
|
|
# Already placed anywhere in the bar: leave the user's chosen position alone.
|
|
for name, items in layout.items():
|
|
if isinstance(items, list) and has(items):
|
|
print(" already in bar layout (%s) - position left as-is" % name)
|
|
raise SystemExit(0)
|
|
|
|
idx = len(entries)
|
|
for i, e in enumerate(entries):
|
|
if isinstance(e, dict) and e.get("id") == before:
|
|
idx = i
|
|
break
|
|
|
|
entries.insert(idx, {"id": plugin_id})
|
|
|
|
with open(path, "w", encoding="utf-8") as fh:
|
|
json.dump(cfg, fh, indent=2)
|
|
fh.write("\n")
|
|
print(" added to bar.layout.%s at position %d" % (section, idx))
|
|
PYEOF
|
|
|
|
green 'shell.json updated (hot-reloads; no restart needed)'
|
|
|
|
printf '\ndone. The icon shows the active mode; click it to switch.\n'
|
|
printf 'If it does not appear: omarchy-shell shell rescanPlugins\n'
|