#!/bin/sh
# Install the Orchestra CLI, or upgrade it: run it again for a newer version.
#
#   curl -fsSL https://get.orchestrahq.ai | sh
#
# What this does, in order, and nothing else:
#   1. works out your platform (macOS or Linux, Apple Silicon/arm64 or x86-64);
#   2. asks https://get.orchestrahq.ai which version is the newest;
#   3. downloads that version's archive and its published SHA-256 checksum,
#      and stops without installing anything if they do not match;
#   4. puts one file, the `orchestra` executable, in ~/.orchestra/bin,
#      replacing the one there in a single step if you are upgrading;
#   5. if ~/.orchestra/bin is not on your PATH, adds one line to your shell's
#      startup file saying so (set ORCHESTRA_NO_MODIFY_PATH=1 to skip this);
#   6. if an older Orchestra is running in the background, starts the new one
#      in its place.
#
# It needs no administrator rights and never uses sudo. Nothing is sent
# anywhere until you run `orchestra login`. Windows is not supported.
#
# Settings, all optional:
#   ORCHESTRA_VERSION=0.1.2       install this version instead of the newest
#   ORCHESTRA_INSTALL_DIR=<dir>   install here instead of ~/.orchestra/bin
#   ORCHESTRA_NO_MODIFY_PATH=1    never edit a shell startup file

set -eu

BASE="${ORCHESTRA_DOWNLOAD_BASE:-https://get.orchestrahq.ai}"
INSTALL_DIR="${ORCHESTRA_INSTALL_DIR:-$HOME/.orchestra/bin}"
UPGRADE_COMMAND="curl -fsSL https://get.orchestrahq.ai | sh"

say() { printf '%s\n' "$*"; }
fail() { printf 'orchestra install: %s\n' "$*" >&2; exit 1; }

# Our host over HTTPS only. Plain http is accepted for this machine alone,
# which is how the installer's own tests serve it.
case "$BASE" in
  https://*) CURL_PROTO="--proto =https --tlsv1.2" ;;
  http://127.0.0.1:* | http://localhost:*) CURL_PROTO="" ;;
  *) fail "refusing to download from $BASE: only https is allowed" ;;
esac

command -v curl >/dev/null 2>&1 || fail "curl is needed to download Orchestra"
command -v tar >/dev/null 2>&1 || fail "tar is needed to unpack Orchestra"
if command -v shasum >/dev/null 2>&1; then
  sha256() { shasum -a 256 "$1" | cut -d ' ' -f 1; }
elif command -v sha256sum >/dev/null 2>&1; then
  sha256() { sha256sum "$1" | cut -d ' ' -f 1; }
else
  fail "shasum or sha256sum is needed to check the download"
fi

# Redirects are not followed (no -L): every file comes from $BASE itself.
fetch() { curl $CURL_PROTO -fsS --retry 2 -o "$2" "$1" || fail "could not download $1"; }

os="$(uname -s)"
arch="$(uname -m)"
case "$os" in
  Darwin) os=darwin ;;
  Linux) os=linux ;;
  *) fail "Orchestra runs on macOS and Linux; $os is not supported" ;;
esac
case "$arch" in
  arm64 | aarch64) arch=arm64 ;;
  x86_64 | amd64) arch=x64 ;;
  *) fail "no Orchestra build for $arch processors" ;;
esac
# A shell running under Rosetta reports x86_64 on Apple Silicon: install the native build.
if [ "$os" = darwin ] && [ "$arch" = x64 ] && [ "$(sysctl -n sysctl.proc_translated 2>/dev/null || echo 0)" = 1 ]; then
  arch=arm64
fi
if [ "$os" = darwin ]; then
  macos="$(sw_vers -productVersion 2>/dev/null || echo 0)"
  [ "${macos%%.*}" -ge 13 ] 2>/dev/null || fail "Orchestra needs macOS 13 (Ventura) or newer; this Mac has macOS $macos"
fi
target="$os-$arch"

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT INT TERM

if [ -n "${ORCHESTRA_VERSION:-}" ]; then
  version="${ORCHESTRA_VERSION#v}"
else
  fetch "$BASE/cli/latest.json" "$tmp/latest.json"
  version="$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)".*/\1/p' "$tmp/latest.json" | head -n 1)"
  [ -n "$version" ] || fail "could not read the newest version from $BASE/cli/latest.json"
fi
case "$version" in
  *[!0-9.]* | "") fail "not a version: $version" ;;
esac

archive="orchestra-$version-$target.tar.gz"
url="$BASE/cli/v$version/$archive"
bin="$INSTALL_DIR/orchestra"

if [ -x "$bin" ]; then
  current="$("$bin" --version 2>/dev/null | sed -n 's/^orchestra \([0-9.]*\).*/\1/p')"
  say "Upgrading Orchestra ${current:-(unknown version)} to $version for $target."
else
  say "Installing Orchestra $version for $target."
fi
say "  from  $url"
say "  into  $bin"

fetch "$url" "$tmp/$archive"
fetch "$url.sha256" "$tmp/$archive.sha256"
expected="$(cut -d ' ' -f 1 "$tmp/$archive.sha256")"
actual="$(sha256 "$tmp/$archive")"
if [ -z "$expected" ] || [ "$expected" != "$actual" ]; then
  fail "the download does not match its published checksum (expected ${expected:-nothing}, got $actual); nothing was installed"
fi
say "  checksum  sha256:$actual (matches)"

mkdir -p "$tmp/unpacked"
tar -xzf "$tmp/$archive" -C "$tmp/unpacked" orchestra
"$tmp/unpacked/orchestra" --version >/dev/null 2>&1 || fail "the downloaded Orchestra does not run on this machine; nothing was installed"

# Replace in one step: a rename within the directory, so anything holding the
# path (a login item, Claude Code's hooks) never sees a half-written file, and
# a running copy keeps the file it already opened.
mkdir -p "$INSTALL_DIR"
cp "$tmp/unpacked/orchestra" "$INSTALL_DIR/.orchestra.new.$$"
chmod 755 "$INSTALL_DIR/.orchestra.new.$$"
mv -f "$INSTALL_DIR/.orchestra.new.$$" "$bin"
printf '{"v":1,"method":"script","upgrade":"%s"}\n' "$UPGRADE_COMMAND" > "$INSTALL_DIR/install-method.json"
say "Installed $("$bin" --version)."

# A background Orchestra from before this upgrade hands over to this one.
restarted="$("$bin" capture-tailer --if-older 2>/dev/null || true)"
[ -n "$restarted" ] && say "$restarted"

case ":$PATH:" in
  *":$INSTALL_DIR:"*) on_path=1 ;;
  *) on_path=0 ;;
esac
if [ "$on_path" = 0 ]; then
  line="export PATH=\"$INSTALL_DIR:\$PATH\""
  case "${SHELL:-}" in
    */zsh) rc="$HOME/.zshrc" ;;
    */bash) if [ "$os" = darwin ]; then rc="$HOME/.bash_profile"; else rc="$HOME/.bashrc"; fi ;;
    */fish) rc="$HOME/.config/fish/conf.d/orchestra.fish"; line="fish_add_path \"$INSTALL_DIR\"" ;;
    *) rc="$HOME/.profile" ;;
  esac
  if [ "${ORCHESTRA_NO_MODIFY_PATH:-}" = 1 ]; then
    say ""
    say "$INSTALL_DIR is not on your PATH. Add it with:"
    say "  $line"
  elif [ -f "$rc" ] && grep -F "$INSTALL_DIR" "$rc" >/dev/null 2>&1; then
    say ""
    say "$rc already adds $INSTALL_DIR to your PATH: open a new terminal to use orchestra."
  else
    mkdir -p "$(dirname "$rc")"
    printf '\n# Orchestra CLI\n%s\n' "$line" >> "$rc"
    say ""
    say "Added $INSTALL_DIR to your PATH in $rc: open a new terminal to use orchestra."
  fi
fi

say ""
say "Next:"
say "  orchestra login     sign in, in your browser"
say "  orchestra enable    save this machine's coding agent sessions to your workspace"
