#!/bin/sh # Rinzo CLI installer: rinzo 0.4.2. curl -fsSL https://rinzo.ai/install.sh | sh # Downloads the CLI wheel from https://rinzo.ai, checks its SHA-256 and installs it with uv, pipx or a # private Python environment; `rinzo` ends up in ~/.local/bin. RINZO_INSTALL_ORIGIN overrides the origin. # Rinzo was called Topaz: a uv or pipx install of the topaz CLI (topaz-tel) is replaced, and rinzo # copies its login and settings on first use. set -eu VERSION='0.4.2' WHEEL='rinzo-0.4.2-py3-none-any.whl' SHA256='fa7d1e4754e84ac11883a0a567e4f69553ec453fdaf2b1c5a5e10da003f09265' ORIGIN="${RINZO_INSTALL_ORIGIN:-${TOPAZ_INSTALL_ORIGIN:-https://rinzo.ai}}" say() { printf '%s\n' "$@"; } fail() { printf 'rinzo install: %s\n' "$*" >&2; exit 1; } sha256() { if command -v sha256sum >/dev/null 2>&1; then sha256sum "$1" | cut -d' ' -f1 elif command -v shasum >/dev/null 2>&1; then shasum -a 256 "$1" | cut -d' ' -f1 else python3 -c 'import hashlib, sys; print(hashlib.sha256(open(sys.argv[1], "rb").read()).hexdigest())' "$1" fi } # listed OUTPUT NAME: whether a line of a tool listing starts with "NAME ". listed() { printf '%s\n' "$1" | ( while IFS= read -r line; do case "$line" in "$2 "*) exit 0 ;; esac done exit 1 ) } # The topaz CLI's package owns the `topaz` command; rinzo installs its own (deprecated) `topaz` alias. remove_topaz_tel() { if command -v uv >/dev/null 2>&1 && listed "$(uv tool list 2>/dev/null || true)" topaz-tel; then say "Removing the topaz CLI (uv tool topaz-tel): rinzo replaces it and keeps its login" uv tool uninstall topaz-tel || say "Could not remove it; run: uv tool uninstall topaz-tel" fi if command -v pipx >/dev/null 2>&1 && listed "$(pipx list --short 2>/dev/null || true)" topaz-tel; then say "Removing the topaz CLI (pipx package topaz-tel): rinzo replaces it and keeps its login" pipx uninstall topaz-tel || say "Could not remove it; run: pipx uninstall topaz-tel" fi } main() { command -v python3 >/dev/null 2>&1 || fail "Python 3.10 or newer is required (python3 was not found)" python3 -c 'import sys; sys.exit(sys.version_info < (3, 10))' || fail "Python 3.10 or newer is required (found $(python3 -c 'import platform; print(platform.python_version())'))" tmp=$(mktemp -d 2>/dev/null || mktemp -d -t rinzo) trap 'rm -rf "$tmp"' EXIT trap 'exit 1' INT TERM url="${ORIGIN%/}/downloads/$WHEEL" say "Downloading $url" if command -v curl >/dev/null 2>&1; then curl -fsSL -o "$tmp/$WHEEL" "$url" || fail "download failed: $url" elif command -v wget >/dev/null 2>&1; then wget -q -O "$tmp/$WHEEL" "$url" || fail "download failed: $url" else fail "curl or wget is required" fi actual=$(sha256 "$tmp/$WHEEL") [ "$actual" = "$SHA256" ] || fail "checksum mismatch for $WHEEL (expected $SHA256, got $actual); nothing was installed" remove_topaz_tel bin="$HOME/.local/bin" data="${XDG_DATA_HOME:-$HOME/.local/share}" if command -v uv >/dev/null 2>&1; then say "Installing with uv" uv tool install --force "$tmp/$WHEEL" elif command -v pipx >/dev/null 2>&1; then say "Installing with pipx" pipx install --force "$tmp/$WHEEL" else venv="$data/rinzo/venv" say "Installing into $venv" python3 -m venv --clear "$venv" || fail "could not create a Python environment (Debian/Ubuntu: sudo apt install python3-venv)" "$venv/bin/python" -m pip install --quiet --disable-pip-version-check --no-index --no-deps "$tmp/$WHEEL" mkdir -p "$bin" ln -sf "$venv/bin/rinzo" "$bin/rinzo" ln -sf "$venv/bin/topaz" "$bin/topaz" fi if [ -d "$data/topaz/venv" ]; then say "" "The topaz CLI's old environment is no longer used; remove it with: rm -rf '$data/topaz/venv'" fi case ":$PATH:" in *":$bin:"*) ;; *) say "" "$bin is not on your PATH. Add it, e.g.: export PATH=\"\$HOME/.local/bin:\$PATH\"" ;; esac say "" "Installed rinzo $VERSION. Next:" \ " rinzo login # approve in the browser as an account administrator" \ " rinzo skill install # the rinzo skill for Claude Code (--agent codex for Codex)" if [ -d "${XDG_CONFIG_HOME:-$HOME/.config}/topaz" ]; then say "Used the topaz CLI before? rinzo copies its login on first use: try rinzo whoami" fi } main "$@"