#!/bin/sh # Ork Meter installer for macOS and Linux. # # curl -fsSL https://orkmeter.com/install.sh | sh # # Installs the Ork Meter plugin for each agent it finds on your PATH: # Claude Code (2.1.280 or later) via `claude plugin ...` # Codex (the Codex CLI) via `codex plugin ...`, then setup, # which needs Python 3.11, 3.12 or 3.13 # # This script downloads nothing itself. Claude Code and Codex fetch the # plugins, and every release they fetch is pinned by SHA-256: the Claude # marketplace file names the plugin zip's digest, and the Codex installer's # release.json names the wheel's. Run it again at any time to update in place. # It never uses sudo and writes only through the agents' own plugin commands. # Source and support: https://orkmeter.com/install set -u CLAUDE_MIN=2.1.280 CLAUDE_MARKETPLACE=https://orkmeter.com/releases/claude/marketplace.json CLAUDE_PLUGIN=ork-meter@edos CODEX_MARKETPLACE=EDOS-Engineering/ork-meter-codex CODEX_PLUGIN=ork-meter-codex@edos-codex # What to do after the Claude Code install. Becomes "Open Claude Code; Ork # Meter connects on first start" once the plugin connects by itself. CLAUDE_NEXT_STEP="Claude Code: open Claude Code and run /ork-meter:connect, then restart Claude Code once." say() { printf '%s\n' "$*"; } fail() { printf 'ork-meter: %s\n' "$*" >&2; exit 1; } # version_at_least 2.1.316 2.1.280 -> true when $1 >= $2 (numeric x.y.z). version_at_least() { awk -v a="$1" -v b="$2" 'BEGIN { split(a, x, "."); split(b, y, ".") for (i = 1; i <= 3; i++) { if (x[i] + 0 > y[i] + 0) exit 0; if (x[i] + 0 < y[i] + 0) exit 1 } exit 0 }' } # --- Claude Code ----------------------------------------------------------- install_claude() { say "Claude Code: installing Ork Meter" version=$(claude --version 2>/dev/null | awk '{print $1; exit}') if [ -z "$version" ] || ! version_at_least "$version" "$CLAUDE_MIN"; then say " Claude Code ${version:-(unknown version)} is older than $CLAUDE_MIN. Update it with: claude update" return 1 fi # Adding is a no-op when the marketplace is already there; update refreshes # it so a re-run picks up the newest release, then install and update. claude plugin marketplace add "$CLAUDE_MARKETPLACE" /dev/null 2>&1; then command -v "python$v"; return 0; fi done if command -v python3 >/dev/null 2>&1; then case $(python3 -c 'import sys; print("%d.%d" % sys.version_info[:2])' 2>/dev/null) in 3.11 | 3.12 | 3.13) command -v python3; return 0 ;; esac fi if command -v uv >/dev/null 2>&1; then for v in 3.13 3.12 3.11; do found=$(uv python find --no-project "$v" 2>/dev/null | tail -n 1) [ -n "$found" ] && { say "$found"; return 0; } done fi return 1 } # The whole Codex install is this one function: add the marketplace, add the # plugin, then run the plugin's setup, which pairs in the browser. install_codex() { say "Codex: installing Ork Meter" python=$(codex_python) || { say " Codex needs Python 3.11, 3.12 or 3.13. Install one (for example: brew install python@3.13, or uv python install 3.13), then run this again." return 1 } codex plugin marketplace add "$CODEX_MARKETPLACE" /dev/null; then "$python" -I -B "$setup" setup /dev/null 2>&1; then found=1 install_claude || { failed=1; say "Claude Code: install did not finish (see above)."; } fi if command -v codex >/dev/null 2>&1; then found=1 install_codex || { failed=1; say "Codex: install did not finish (see above)."; } fi [ -n "$found" ] || fail "neither claude (Claude Code) nor codex (Codex CLI) is on your PATH. Install one, then run this again. Help: https://orkmeter.com/install" say "" [ -n "$CLAUDE_NEXT" ] && say "$CLAUDE_NEXT" [ -n "$CODEX_NEXT" ] && say "$CODEX_NEXT" [ -z "$failed" ] || exit 1 say "Your dashboard: https://orkmeter.com/" } # Everything above only defines functions, so a partial download runs nothing. main "$@"