#!/bin/sh # vitro installer — the desktop app plus the headless `vitro` command. # # curl -fsSL https://vitro.run/install.sh | sh # # vitro.run serves this script; GitHub Releases holds the bytes, and every one # is checked against the `.sha256` published beside it. The address is ours on # purpose — see `Dashboard.Releases` — so the command above keeps working if # the binaries ever move. # # On macOS `brew tap vitro-run/tap https://vitro.run/brew && brew install # --cask vitro` does the same job and can upgrade itself afterwards. This # script stays the answer for Linux, for CI, and for anyone who would rather # not tap. # # Environment overrides: # VITRO_VERSION — install a specific tag (e.g. "0.2.0") # VITRO_BIN — where to put the CLI (default: /usr/local/bin) # set -e REPO="vitro-run/vitro" OS="$(uname -s)" ARCH="$(uname -m)" BIN_DIR="${VITRO_BIN:-/usr/local/bin}" case "${OS}-${ARCH}" in Darwin-arm64) CLI_TARGET="aarch64-apple-darwin" ;; Darwin-x86_64) CLI_TARGET="x86_64-apple-darwin" ;; Linux-x86_64) CLI_TARGET="x86_64-linux-gnu" ;; *) printf 'error: unsupported platform %s-%s\n' "${OS}" "${ARCH}" >&2 printf 'build from source instead: https://github.com/%s\n' "${REPO}" >&2 exit 1 ;; esac # ── Resolve the release ────────────────────────────────────────────────────── if [ -n "${VITRO_VERSION:-}" ]; then API="https://api.github.com/repos/${REPO}/releases/tags/v${VITRO_VERSION}" else API="https://api.github.com/repos/${REPO}/releases/latest" fi printf 'Fetching release metadata…\n' if ! RELEASE_JSON="$(curl -fsSL "${API}")"; then printf 'error: no published release found.\n' >&2 printf 'vitro has not cut one yet — build from source:\n' >&2 printf ' git clone https://github.com/%s && cd vitro && mix ex_tauri.dev\n' "${REPO}" >&2 exit 1 fi asset_url() { printf '%s\n' "${RELEASE_JSON}" \ | grep '"browser_download_url"' \ | sed 's/.*"browser_download_url": *"\([^"]*\)".*/\1/' \ | grep -iE "$1" \ | grep -v '\.sha256$' \ | head -1 } # A download nobody verified is a download nobody should run. No checksum # published means the release is malformed, not that we should shrug and carry on. verify_sha() { EXPECTED="$(curl -fsSL "$1.sha256" 2>/dev/null | awk '{print $1}')" if [ -z "${EXPECTED}" ]; then printf 'error: no .sha256 published for %s\n' "$1" >&2 exit 1 fi if command -v sha256sum >/dev/null 2>&1; then ACTUAL="$(sha256sum "$2" | awk '{print $1}')" else ACTUAL="$(shasum -a 256 "$2" | awk '{print $1}')" fi if [ "${EXPECTED}" != "${ACTUAL}" ]; then printf 'error: checksum mismatch for %s\n' "$2" >&2 exit 1 fi } TMP="$(mktemp -d)" trap 'rm -rf "${TMP}"' EXIT # ── The CLI ────────────────────────────────────────────────────────────────── CLI_URL="$(asset_url "vitro-cli-.*${CLI_TARGET}\.tar\.gz")" if [ -n "${CLI_URL}" ]; then printf 'Downloading the vitro command…\n' curl -fsSL "${CLI_URL}" -o "${TMP}/cli.tar.gz" verify_sha "${CLI_URL}" "${TMP}/cli.tar.gz" mkdir -p "${TMP}/cli" && tar -xzf "${TMP}/cli.tar.gz" -C "${TMP}/cli" # The release unpacks to a directory; the launcher inside it needs its # siblings, so install the whole tree and symlink the entry point. DEST="${HOME}/.vitro/cli" rm -rf "${DEST}" && mkdir -p "${DEST}" cp -R "${TMP}/cli/." "${DEST}/" if [ -w "${BIN_DIR}" ]; then ln -sf "${DEST}/bin/vitro" "${BIN_DIR}/vitro" printf 'Installed vitro → %s/vitro\n' "${BIN_DIR}" else printf 'Installed the CLI to %s\n' "${DEST}" printf 'Add it to your PATH, or run with sudo to link it into %s:\n' "${BIN_DIR}" printf ' sudo ln -sf %s/bin/vitro %s/vitro\n' "${DEST}" "${BIN_DIR}" fi fi # ── The app ────────────────────────────────────────────────────────────────── if [ "${OS}" = "Darwin" ]; then DMG_URL="$(asset_url "\.dmg$")" if [ -n "${DMG_URL}" ]; then printf 'Downloading Vitro.app…\n' curl -fsSL "${DMG_URL}" -o "${TMP}/vitro.dmg" verify_sha "${DMG_URL}" "${TMP}/vitro.dmg" MOUNT="$(hdiutil attach -nobrowse -quiet "${TMP}/vitro.dmg" | awk '/\/Volumes\//{print $NF; exit}')" cp -R "${MOUNT}/Vitro.app" /Applications/ 2>/dev/null \ || printf 'note: could not write /Applications — copy Vitro.app yourself from %s\n' "${MOUNT}" hdiutil detach -quiet "${MOUNT}" || true # Downloads carry a quarantine flag; without this the first launch is a # dialog about an unidentified developer rather than an app. xattr -dr com.apple.quarantine /Applications/Vitro.app 2>/dev/null || true printf 'Installed /Applications/Vitro.app\n' fi else APPIMAGE_URL="$(asset_url "\.AppImage$")" if [ -n "${APPIMAGE_URL}" ]; then printf 'Downloading the AppImage…\n' mkdir -p "${HOME}/.local/bin" curl -fsSL "${APPIMAGE_URL}" -o "${HOME}/.local/bin/vitro-app" verify_sha "${APPIMAGE_URL}" "${HOME}/.local/bin/vitro-app" chmod +x "${HOME}/.local/bin/vitro-app" printf 'Installed %s/.local/bin/vitro-app\n' "${HOME}" fi fi cat <<'DONE' Done. Next: open -a Vitro start it (the app IS the daemon) vitro mcp install print the registration for your AI CLI npx skills add vitro-run/vitro teach your agent how to use it DONE