#!/bin/sh
# Install feno — the single executable — and start its daemon.
#
#   curl -fsSL https://unpkg.com/@openmono/core/install.sh | sh
#
# To add a computer to your existing devices, pass the pairing link one of them
# shows (the dashboard's Pair device button, or `feno pair`):
#
#   curl -fsSL https://unpkg.com/@openmono/core/install.sh | FENO_JOIN='feno://pair?d=…' sh
#
# Environment:
#   FENO_JOIN          pairing link: join that cluster instead of starting a new one
#   FENO_CHANNEL       update channel: stable (default) or nightly; the device
#                      keeps following it (`feno update channel`)
#   FENO_NPM_REGISTRY  npm registry or mirror, default: https://registry.npmjs.org
#   FENO_INSTALL_DIR   where the binary goes, default: ~/.feno/bin
#   FENO_NO_START=1    install only: no setup, no join, no daemon, no shell profile edit
#
# The binary comes from the @openmono/feno-<os>-<cpu> npm package; its tarball
# must match the registry's sha512 integrity hash.
set -eu

channel="${FENO_CHANNEL:-stable}"
registry="${FENO_NPM_REGISTRY:-https://registry.npmjs.org}"
registry="${registry%/}"
install_dir="${FENO_INSTALL_DIR:-$HOME/.feno/bin}"

say() { printf 'feno: %s\n' "$*"; }
die() { printf 'feno: error: %s\n' "$*" >&2; exit 1; }
need() { command -v "$1" >/dev/null 2>&1 || die "$1 is required"; }

case "$channel" in
  stable) dist_tag=latest ;;
  nightly) dist_tag=nightly ;;
  *) die "FENO_CHANNEL must be stable or nightly, not $channel" ;;
esac

need curl
need tar
need openssl

case "$(uname -s)" in
  Darwin) os=darwin ;;
  Linux) os=linux ;;
  *) die "unsupported OS: $(uname -s) (feno ships for macOS and Linux)" ;;
esac
case "$(uname -m)" in
  arm64 | aarch64) cpu=arm64 ;;
  x86_64 | amd64) cpu=x64 ;;
  *) die "unsupported CPU: $(uname -m)" ;;
esac
if [ "$os" = linux ] && ldd --version 2>&1 | grep -qi musl; then
  die "musl-based Linux (e.g. Alpine) is not supported yet"
fi

package="@openmono/feno-$os-$cpu"
say "looking up $package@$dist_tag on $registry"
manifest="$(curl -fsSL "$registry/@openmono%2ffeno-$os-$cpu/$dist_tag")" || die "no $channel release of $package"
# The registry answers compact JSON; pull the three fields without a JSON tool.
field() { printf '%s' "$manifest" | sed -n "s/.*\"$1\":\"\([^\"]*\)\".*/\1/p"; }
version="$(field version)"
tarball="$(field tarball)"
integrity="$(field integrity)"
[ -n "$version" ] && [ -n "$tarball" ] && [ -n "$integrity" ] || die "malformed registry answer for $package@$dist_tag"
case "$integrity" in sha512-*) ;; *) die "unexpected integrity format: $integrity" ;; esac

tmp="$(mktemp -d)"
trap 'rm -rf "$tmp"' EXIT INT TERM
say "downloading feno $version"
curl -fL --progress-bar -o "$tmp/feno.tgz" "$tarball" || die "download failed: $tarball"
actual="sha512-$(openssl dgst -sha512 -binary "$tmp/feno.tgz" | openssl base64 -A)"
[ "$actual" = "$integrity" ] || die "integrity mismatch for $tarball — refusing to install"
tar -xzf "$tmp/feno.tgz" -C "$tmp" package/bin/feno

mkdir -p "$install_dir"
binary="$install_dir/feno"
mv "$tmp/package/bin/feno" "$tmp/feno"
chmod 755 "$tmp/feno"
# Apple Silicon refuses unsigned code; a binary cross-compiled for macOS may
# carry no signature, so sign it ad hoc.
if [ "$os" = darwin ]; then
  codesign --force --sign - "$tmp/feno" >/dev/null 2>&1 || die "codesign failed"
fi
[ "$("$tmp/feno" --version)" = "$version" ] || die "the downloaded binary does not report version $version"
mv -f "$tmp/feno" "$binary"
say "installed feno $version → $binary"

if [ "${FENO_NO_START:-}" = 1 ]; then
  exit 0
fi

# Put the install dir on PATH for future shells.
case ":$PATH:" in
  *":$install_dir:"*) ;;
  *)
    line="export PATH=\"$install_dir:\$PATH\""
    case "$(basename "${SHELL:-sh}")" in
      zsh) profile="$HOME/.zshrc" ;;
      bash) if [ "$os" = darwin ]; then profile="$HOME/.bash_profile"; else profile="$HOME/.bashrc"; fi ;;
      fish)
        profile="$HOME/.config/fish/config.fish"
        line="fish_add_path \"$install_dir\""
        ;;
      *) profile="$HOME/.profile" ;;
    esac
    mkdir -p "$(dirname "$profile")"
    if ! grep -qsF "$line" "$profile"; then
      printf '\n# feno\n%s\n' "$line" >>"$profile"
      say "added $install_dir to PATH in $profile"
    fi
    ;;
esac

if [ -n "${FENO_JOIN:-}" ]; then
  # `join` starts the daemon service with the link when none runs (redeeming
  # it writes this device's config), or hands it to the running daemon.
  say "joining your devices — confirm this device on the one that showed the link"
  "$binary" join "$FENO_JOIN" || die "could not join with that link — create a new one and run this again"
else
  # First run writes ~/.feno/config.json; `start -d` installs the launchd /
  # systemd service, so the daemon also comes back after a reboot.
  if [ ! -f "${FENO_STATE_DIR:-$HOME/.feno}/config.json" ]; then
    "$binary" setup --yes
  fi
  "$binary" start -d
fi
# The device follows its install's channel from now on (stable is the default).
if [ "$channel" != stable ]; then
  "$binary" update channel "$channel" >/dev/null
fi
# The dashboard signs a browser in with a one-time code (`feno open`).
if "$binary" open >/dev/null 2>&1; then
  say "feno is running — the dashboard opened in your browser"
else
  say "feno is running — run \`feno open\` to sign in to the dashboard"
fi
cat <<'NEXT'

Next:
  - Sign in to Claude Code or Codex on this device if you have not; the dashboard shows what is missing.
  - Add another computer: Pair device (the QR icon in the dashboard sidebar) or `feno pair` shows a command to run there.
  - Use your phone: `feno setup phone` shows a QR code to scan.
  - Rename this device or change network access: `feno setup`. Something wrong: `feno doctor`.
NEXT
case ":$PATH:" in
  *":$install_dir:"*) ;;
  *) printf '\nOpen a new terminal to use `feno` (or run %s).\n' "$binary" ;;
esac
