#!/bin/sh # (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. # Meta VR CLI (metavr) installer for macOS and Linux # # metavr is the new name for the CLI formerly known as hzdb. This installer sets # up the `metavr` command and links the legacy `hzdb` command to it. # # Usage: # curl -fsSL https://developers.meta.com/vr/install-cli/ | sh # # Environment variables: # METAVR_HOME - Installation directory (default: $HOME/.metavr). # The legacy HZDB_HOME is honored as a fallback. # METAVR_NO_PATH - Set to 1 to skip PATH modification (legacy HZDB_NO_PATH # honored as a fallback). # Wrap everything in a function so the script doesn't partially execute # if the download is interrupted (e.g., curl | sh with a truncated pipe). _install_metavr() { set -eu # --- Configuration --- CORE_APP_ID_MAC="26345008975148693" CORE_APP_ID_LINUX="26339444969052064" DOWNLOAD_BASE_URL="https://www.oculus.com/download_app/" INFO_BASE_URL="https://www.oculus.com/binary-info/" # Install to ~/.metavr. METAVR_HOME overrides; the legacy HZDB_HOME is still # honored for anyone who set it before the rename. if [ -n "${METAVR_HOME:-}" ]; then HOME_DIR="$METAVR_HOME" elif [ -n "${HZDB_HOME:-}" ]; then HOME_DIR="$HZDB_HOME" else HOME_DIR="$HOME/.metavr" fi INSTALL_DIR="$HOME_DIR/bin" # --- Platform Detection --- OS="$(uname -s)" ARCH="$(uname -m)" case "$OS" in Darwin) CORE_APP_ID="$CORE_APP_ID_MAC" ;; Linux) CORE_APP_ID="$CORE_APP_ID_LINUX" ;; *) echo "Error: Unsupported operating system: $OS" echo "metavr direct download is available for macOS and Linux." return 1 ;; esac # macOS ships a universal binary (arm64 + x86_64); Linux is x86_64 only, so # Linux-on-ARM must fail here rather than download a binary it cannot run. case "$OS/$ARCH" in Darwin/x86_64|Darwin/arm64|Darwin/aarch64|Linux/x86_64) ;; *) echo "Error: Unsupported architecture: $ARCH on $OS" echo "metavr ships x86_64 and arm64 for macOS, and x86_64 only for Linux." return 1 ;; esac # --- Download --- DOWNLOAD_URL="${DOWNLOAD_BASE_URL}?id=${CORE_APP_ID}" INFO_URL="${INFO_BASE_URL}${CORE_APP_ID}/latest/" # --- Fetch integrity metadata (best-effort) --- # # The binary-info feed publishes the expected sha256 (and version) for the # artifact served by download_app. We verify the bytes we download from # download_app against this sha256, but keep downloading from download_app # (a proven tokenless redirect) rather than the feed's own url. If the feed # is unreachable or omits sha256 (e.g. an older feed during rollout), we # proceed silently without verification so installs don't break. INFO_JSON="" if command -v curl >/dev/null 2>&1; then INFO_JSON="$(curl -fsSL --proto '=https' --proto-redir '=https' "$INFO_URL" 2>/dev/null || true)" elif command -v wget >/dev/null 2>&1; then INFO_JSON="$(wget -qO- --https-only "$INFO_URL" 2>/dev/null || true)" fi EXPECTED_SHA256="$(printf '%s' "$INFO_JSON" | grep -o '"sha256"[[:space:]]*:[[:space:]]*"[0-9a-fA-F]\{64\}"' | grep -o '[0-9a-fA-F]\{64\}' | head -1)" METAVR_VERSION="$(printf '%s' "$INFO_JSON" | grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed -e 's/.*"version"[[:space:]]*:[[:space:]]*"//' -e 's/"$//')" echo "Meta VR CLI (metavr) installer" echo "" if [ -n "$METAVR_VERSION" ]; then echo "Downloading metavr $METAVR_VERSION..." else echo "Downloading metavr..." fi mkdir -p "$INSTALL_DIR" TEMP_FILE="$(mktemp)" trap 'rm -f "$TEMP_FILE"' EXIT if command -v curl >/dev/null 2>&1; then curl -fSL --proto '=https' --proto-redir '=https' --progress-bar "$DOWNLOAD_URL" -o "$TEMP_FILE" elif command -v wget >/dev/null 2>&1; then wget -q --https-only --show-progress "$DOWNLOAD_URL" -O "$TEMP_FILE" else echo "Error: curl or wget is required to download metavr" return 1 fi if [ ! -s "$TEMP_FILE" ]; then echo "Error: Downloaded file is empty" return 1 fi # Verify the download is a binary, not an HTML error page if head -c 5 "$TEMP_FILE" | grep -q '<'; then echo "Error: Download returned an HTML page instead of a binary." echo "The metavr binary may not be published yet for this platform." echo "Visit https://developers.meta.com/vr/downloads/ for alternatives." return 1 fi # --- Integrity verification --- # # Verify the downloaded artifact (the zip/raw bytes) against the feed's # sha256 BEFORE extracting or installing. If we have no expected sha256 # (feed unreachable or older feed without the field) or no sha256 tool, # proceed without verification rather than blocking the install. if [ -n "$EXPECTED_SHA256" ]; then if command -v shasum >/dev/null 2>&1; then ACTUAL_SHA256="$(shasum -a 256 "$TEMP_FILE" | awk '{print $1}')" elif command -v sha256sum >/dev/null 2>&1; then ACTUAL_SHA256="$(sha256sum "$TEMP_FILE" | awk '{print $1}')" else ACTUAL_SHA256="" fi if [ -n "$ACTUAL_SHA256" ]; then EXPECTED_SHA256_LC="$(printf '%s' "$EXPECTED_SHA256" | tr 'A-F' 'a-f')" ACTUAL_SHA256_LC="$(printf '%s' "$ACTUAL_SHA256" | tr 'A-F' 'a-f')" if [ "$EXPECTED_SHA256_LC" != "$ACTUAL_SHA256_LC" ]; then echo "Error: Downloaded metavr failed integrity verification." echo " expected sha256: $EXPECTED_SHA256_LC" echo " actual sha256: $ACTUAL_SHA256_LC" echo "Aborting install. Please try again or report this issue." return 1 fi echo "Verified download integrity (sha256)." fi fi # The Mac/Linux Core Apps store the binary inside a zip wrapper # (mimeType=application/zip). The signed artifact inside is still named # hzdb (the build pipeline name is unchanged); we install it as metavr. # If the download is a zip (PK magic bytes), extract the binary; otherwise # treat the download as a raw binary. if head -c 2 "$TEMP_FILE" | LC_ALL=C grep -q '^PK'; then EXTRACT_DIR="$(mktemp -d)" if ! unzip -q -o "$TEMP_FILE" -d "$EXTRACT_DIR" 2>/dev/null; then echo "Error: Could not extract downloaded zip archive" rm -rf "$EXTRACT_DIR" return 1 fi EXTRACTED_BIN="$EXTRACT_DIR/metavr" if [ ! -f "$EXTRACTED_BIN" ]; then EXTRACTED_BIN="$EXTRACT_DIR/hzdb" fi if [ ! -f "$EXTRACTED_BIN" ]; then EXTRACTED_BIN="$(find "$EXTRACT_DIR" -type f \( -name 'metavr' -o -name 'hzdb' \) | head -1)" fi if [ -z "$EXTRACTED_BIN" ] || [ ! -f "$EXTRACTED_BIN" ]; then echo "Error: metavr binary not found inside downloaded archive" rm -rf "$EXTRACT_DIR" return 1 fi mv "$EXTRACTED_BIN" "$INSTALL_DIR/metavr" rm -rf "$EXTRACT_DIR" rm -f "$TEMP_FILE" else mv "$TEMP_FILE" "$INSTALL_DIR/metavr" fi chmod +x "$INSTALL_DIR/metavr" trap - EXIT # Link the legacy hzdb command to the metavr binary so existing scripts keep # working. The CLI presents under whichever name it is invoked as, so hzdb # launched via this symlink still shows up as hzdb. ln -sf metavr "$INSTALL_DIR/hzdb" echo "Installed metavr to $INSTALL_DIR/metavr" # --- PATH Setup --- if [ "${METAVR_NO_PATH:-${HZDB_NO_PATH:-0}}" = "1" ]; then echo "" echo "metavr is installed. To get started, run:" echo " metavr init Set up the MCP server + skills for your AI agent" echo "" echo " metavr --help See all commands" echo " metavr update Update metavr to the latest version" return 0 fi case ":${PATH}:" in *":${INSTALL_DIR}:"*) ;; *) EXPORT_LINE="export PATH=\"${INSTALL_DIR}:\$PATH\"" SHELL_NAME="$(basename "${SHELL:-/bin/sh}")" case "$SHELL_NAME" in bash) RC_FILE="$HOME/.bashrc" [ -f "$HOME/.bash_profile" ] && RC_FILE="$HOME/.bash_profile" ;; zsh) RC_FILE="$HOME/.zshrc" ;; fish) FISH_DIR="$HOME/.config/fish/conf.d" mkdir -p "$FISH_DIR" FISH_FILE="$FISH_DIR/metavr.fish" if [ ! -f "$FISH_FILE" ] || ! grep -qF "$INSTALL_DIR" "$FISH_FILE" 2>/dev/null; then echo "fish_add_path $INSTALL_DIR" >> "$FISH_FILE" echo "Added metavr to fish PATH (restart shell or run: source $FISH_FILE)" fi # Drop a stale legacy conf.d/hzdb.fish left by an older # install so it can't keep a defunct PATH entry alive. LEGACY_FISH_FILE="$FISH_DIR/hzdb.fish" if [ "$LEGACY_FISH_FILE" != "$FISH_FILE" ] && [ -f "$LEGACY_FISH_FILE" ]; then rm -f "$LEGACY_FISH_FILE" fi RC_FILE="" ;; *) RC_FILE="$HOME/.profile" ;; esac if [ -n "$RC_FILE" ]; then # Idempotent: skip if INSTALL_DIR is already on PATH in this file. if ! { [ -f "$RC_FILE" ] && grep -qF "$INSTALL_DIR" "$RC_FILE" 2>/dev/null; }; then { echo "" echo "# metavr" echo "$EXPORT_LINE" } >> "$RC_FILE" echo "Added metavr to PATH in $RC_FILE." echo "To use metavr in this terminal now, run: . \"$RC_FILE\"" echo "(or open a new terminal / reload your shell)" fi fi ;; esac echo "" echo "metavr is installed. Open a new terminal (or reload your shell), then run:" echo " metavr init Set up the MCP server + skills for your AI agent" echo "" echo "Other commands:" echo " metavr --help See all commands" echo " metavr update Update metavr to the latest version" } _install_metavr