#!/bin/bash # Installs or updates Bevel on a Mac. Run it again to update. # curl -fsSL https://keeno.dev/install.sh | bash # BEVEL_DIR: where the code goes (default ~/Projects/paprika-recorder). # BEVEL_TARBALL_URL: a release tarball to install from (default: the latest release on keeno.dev). # BEVEL_SKIP_SETUP=1: stop before `bevel setup` (for testing; setup changes Claude Code's and Blender's config). set -euo pipefail DEFAULT_TARBALL_URL="https://keeno.dev/bevel.tar.gz" REPO_URL="https://github.com/jcreeno77/Paprika-Bevel.git" DIR="${BEVEL_DIR:-$HOME/Projects/paprika-recorder}" say() { printf '\n==> %s\n' "$*"; } # Everything runs from main, so a download cut off halfway runs nothing. main() { if [ "$(uname -s)" != "Darwin" ]; then echo "Bevel runs only on macOS." >&2 exit 1 fi cat </dev/null 2>&1; then say "Installing Xcode's command-line tools. Click Install in the window that opens." xcode-select --install || true until xcode-select -p >/dev/null 2>&1; do sleep 5; done fi if ! command -v brew >/dev/null 2>&1 && [ ! -x /opt/homebrew/bin/brew ] && [ ! -x /usr/local/bin/brew ]; then say "Installing Homebrew (it asks for your Mac password)" # Under `curl | bash` stdin is this script, so Homebrew's questions read from the terminal instead. /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" /dev/null 2>&1 && [ ! -x "$HOME/.bun/bin/bun" ]; then say "Installing Bun" curl -fsSL https://bun.sh/install | bash fi export PATH="$HOME/.bun/bin:$PATH" local missing=() for t in exiftool zstd c2patool gh; do command -v "$t" >/dev/null 2>&1 || missing+=("$t"); done if [ ${#missing[@]} -gt 0 ]; then say "Installing ${missing[*]}" brew install "${missing[@]}" fi get_code say "Installing Bevel's packages" cd "$DIR" bun install --frozen-lockfile bun link if [ "${BEVEL_SKIP_SETUP:-}" = 1 ]; then say "Stopped before setup (BEVEL_SKIP_SETUP=1). Bevel's code is in $DIR." exit 0 fi say "Running Bevel setup" if command -v bevel >/dev/null 2>&1; then bevel setup --yes; else bun run src/cli.ts setup --yes; fi cat <<'EOF' ==> Bevel is installed. Three things only you can do: 1. If macOS asks, allow "bevel-input" in System Settings > Privacy & Security > Input Monitoring. Bevel records only whether input came from a person or a program, never which keys. 2. If setup's checks said "cannot read" a folder, allow it in System Settings > Privacy & Security > Files and Folders, then run `bevel setup` again. 3. Restart Claude Code, Claude Desktop and Blender. Then open http://127.0.0.1:4747 to see what Bevel recorded. EOF } # A git checkout (a developer's) updates with git; otherwise the release tarball, then git clone for people with access. get_code() { if [ -d "$DIR/.git" ]; then say "Updating $DIR with git" git -C "$DIR" pull --ff-only return fi if [ -e "$DIR" ] && ! grep -qs '"name": "paprika-recorder"' "$DIR/package.json"; then echo "$DIR exists and isn't Bevel. Set BEVEL_DIR to another folder." >&2 exit 1 fi mkdir -p "$(dirname "$DIR")" local tmp tmp="$(mktemp -d "$(dirname "$DIR")/.bevel-XXXXXX")" if curl -fsSL "${BEVEL_TARBALL_URL:-$DEFAULT_TARBALL_URL}" -o "$tmp/bevel.tar.gz"; then say "Unpacking Bevel into $DIR" # Unpack beside the old copy, then swap, so files removed in a new release don't linger. mkdir "$tmp/new" tar -xzf "$tmp/bevel.tar.gz" -C "$tmp/new" --strip-components=1 rm -rf "$DIR" mv "$tmp/new" "$DIR" elif [ -n "${BEVEL_TARBALL_URL:-}" ]; then rm -rf "$tmp" echo "Couldn't download $BEVEL_TARBALL_URL." >&2 exit 1 else say "No release found; cloning $REPO_URL" rm -rf "$tmp" GIT_TERMINAL_PROMPT=0 git clone "$REPO_URL" "$DIR" || { echo "Couldn't download Bevel. Ask for a release link and run: BEVEL_TARBALL_URL= bash install.sh" >&2 exit 1 } return fi rm -rf "$tmp" } main "$@"