#!/bin/sh # Rhei installer - https://rhei.team # Usage: curl -fsS https://rhei.team/install | bash # # Local-first: this script runs the Rhei MCP installer on your machine. # It does not send your code anywhere. See https://rhei.team/data-use set -eu MANIFEST_URL="${RHEI_MCP_MANIFEST_URL:-https://rhei.team/.well-known/rhei-mcp-update.json}" DEFAULT_PACKAGE="${RHEI_MCP_INSTALL_PACKAGE:-@rhei-team/rhei}" APP_CLI_URL="${RHEI_APP_CLI_URL:-https://rhei.team/cli}" TARGET="${RHEI_INSTALL_TARGET:-auto}" LOCATION="${RHEI_INSTALL_LOCATION:-global}" INDEX="${RHEI_INSTALL_INDEX:-1}" PRO="${RHEI_INSTALL_PRO:-}" say() { printf '%s\n' "$*"; } fail() { printf 'rhei: %s\n' "$*" >&2; exit 1; } have() { command -v "$1" >/dev/null 2>&1; } # --- platform --------------------------------------------------------------- os="$(uname -s 2>/dev/null || echo unknown)" case "$os" in Darwin|Linux) ;; MINGW*|MSYS*|CYGWIN*) fail "Windows is supported via WSL. Run this installer inside a WSL shell." ;; *) fail "Unsupported platform: $os. Supported: macOS, Linux, Windows (WSL)." ;; esac # --- prerequisites ---------------------------------------------------------- runner="" if have bun; then runner="bunx" elif have pnpm; then runner="pnpm" elif have npm; then have node || fail "npm was found, but node was not. Install Node 18+ or Bun, then re-run." node_major="$(node -e 'process.stdout.write(String(process.versions.node.split(".")[0]))' 2>/dev/null || echo 0)" [ "$node_major" -ge 18 ] 2>/dev/null || fail "Node 18+ is required (found $(node --version 2>/dev/null || echo none)). Install Node 18+ or Bun, then re-run." runner="npx" else fail "Bun, pnpm, or Node 18+ with npm is required. Install one, then re-run." fi have git || say "note: git not found - Rhei works best inside git repositories." # --- resolve package from the update manifest -------------------------------- pkg="$DEFAULT_PACKAGE" version="" if have curl; then manifest="$(curl -fsS --max-time 10 "$MANIFEST_URL" 2>/dev/null || true)" if [ -n "${manifest:-}" ]; then m_pkg="$(printf '%s' "$manifest" | sed -n 's/.*"npmPackage"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')" version="$(printf '%s' "$manifest" | sed -n 's/.*"latestVersion"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')" [ -n "$m_pkg" ] && pkg="$m_pkg" fi fi is_registry_package() { case "$1" in ./*|../*|/*|http://*|https://*|git+*|*.tgz) return 1 ;; *) return 0 ;; esac } # --- check the package is published ------------------------------------------ if is_registry_package "$pkg" && have curl; then encoded_pkg="$(printf '%s' "$pkg" | sed 's|/|%2F|g')" registry_status="$(curl -fsS -o /dev/null -w '%{http_code}' --max-time 10 "https://registry.npmjs.org/$encoded_pkg" 2>/dev/null || echo 000)" if [ "$registry_status" != "200" ]; then say "" say " Rhei is in closed beta." say "" say " The public package is not on the npm registry yet." say " To get access:" say "" say " 1. Open $APP_CLI_URL" say " 2. Sign in with the current Rhei auth flow" say " 3. Follow the CLI setup steps shown after sign-in" say "" say " Questions or early access for your team: team@rhei.team" say "" exit 1 fi fi # --- run MCP installer ------------------------------------------------------- spec="$pkg" if is_registry_package "$pkg" && [ -n "$version" ]; then spec="$pkg@$version" fi pro_flag_from_env() { case "$1" in 1|true|TRUE|yes|YES|y|Y|on|ON|pro|PRO) printf '%s\n' "--pro" ;; 0|false|FALSE|no|NO|n|N|off|OFF|no-pro|NO-PRO) printf '%s\n' "--no-pro" ;; *) fail "RHEI_INSTALL_PRO must be 1/0, yes/no, true/false, pro/no-pro, or on/off." ;; esac } pro_flag="" prompt_after_index=0 if [ -n "$PRO" ]; then pro_flag="$(pro_flag_from_env "$PRO")" elif [ "${CI:-}" = "1" ] || [ "${CI:-}" = "true" ] || [ "${CI:-}" = "TRUE" ]; then pro_flag="--no-pro" say "" say " Rhei Pro: off for this install (CI/non-interactive environment)." say " To approve in automation, rerun with RHEI_INSTALL_PRO=1." elif ( : <> /dev/tty ) 2>/dev/null; then prompt_after_index=1 say "" say " Rhei Pro choice will appear after the local scan." say " Automation override: RHEI_INSTALL_PRO=1 or RHEI_INSTALL_PRO=0." else pro_flag="--no-pro" say "" say " Rhei Pro: off for this install (no TTY to ask)." say " To approve in automation, rerun with RHEI_INSTALL_PRO=1." fi say "Installing Rhei MCP from $spec ..." say "Target: $TARGET; location: $LOCATION" if [ "$runner" = "bunx" ]; then rhei_cmd="bunx --package $spec rhei" if [ "$INDEX" = "0" ]; then if [ "$prompt_after_index" = "1" ]; then RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=1 bunx --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes ${pro_flag:+"$pro_flag"} < /dev/tty else RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=0 bunx --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes ${pro_flag:+"$pro_flag"} fi else if [ "$prompt_after_index" = "1" ]; then RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=1 bunx --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes --index ${pro_flag:+"$pro_flag"} < /dev/tty else RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=0 bunx --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes --index ${pro_flag:+"$pro_flag"} fi fi elif [ "$runner" = "pnpm" ]; then rhei_cmd="pnpm dlx --silent --package $spec rhei" if [ "$INDEX" = "0" ]; then if [ "$prompt_after_index" = "1" ]; then RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=1 pnpm dlx --silent --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes ${pro_flag:+"$pro_flag"} < /dev/tty else RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=0 pnpm dlx --silent --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes ${pro_flag:+"$pro_flag"} fi else if [ "$prompt_after_index" = "1" ]; then RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=1 pnpm dlx --silent --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes --index ${pro_flag:+"$pro_flag"} < /dev/tty else RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=0 pnpm dlx --silent --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes --index ${pro_flag:+"$pro_flag"} fi fi else rhei_cmd="npx -y --package $spec rhei" if [ "$INDEX" = "0" ]; then if [ "$prompt_after_index" = "1" ]; then RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=1 npx -y --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes ${pro_flag:+"$pro_flag"} < /dev/tty else RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=0 npx -y --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes ${pro_flag:+"$pro_flag"} fi else if [ "$prompt_after_index" = "1" ]; then RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=1 npx -y --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes --index ${pro_flag:+"$pro_flag"} < /dev/tty else RHEI_MCP_INSTALL_PACKAGE="$pkg" RHEI_CLI_COMMAND_HINT="$rhei_cmd" RHEI_PRO_PROMPT_AFTER_INDEX=0 npx -y --package "$spec" rhei install --target "$TARGET" --location "$LOCATION" --yes --index ${pro_flag:+"$pro_flag"} fi fi fi say "" say " Rhei MCP is installed." say "" say " Next:" say " 1. Restart or reconnect your MCP client." say " 2. Run: $rhei_cmd doctor" say "" say " Local-first: your code stays on this machine. https://rhei.team/data-use" say ""