#!/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 Modes.js; do [ -f "$SRC/$f" ] || { fail "missing from payload: $f"; exit 1; } done # Every QML and JS file, not a fixed list: the panel is split into one file per # stage. The old ones are cleared first, so a file removed from the source does # not linger in the plugin directory, where QML would still find it by name. rm -f "$DEST_DIR"/*.qml "$DEST_DIR"/*.js for f in "$SRC"/manifest.json "$SRC"/*.qml "$SRC"/*.js; do install -m 0644 "$f" "$DEST_DIR/$(basename "$f")" done green "plugin files copied ($(ls "$SRC"/*.qml | wc -l | tr -d ' ') QML files)" # --- 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'