#!/usr/bin/env bash # Bootstrap: installs Homebrew + gh, authenticates with GitHub (2FA), clones # the private personal-config repo, then hands off to setup_mac.sh. # With AGENT_FILES_ONLY=1, skips the full guided setup and instead installs # Claude Code + syncs agent skill files only (scripts/update_agent_files.sh). # Prerequisites: Install Xcode from the App Store before running this. set -euo pipefail if [[ "${EUID:-$(id -u)}" == "0" ]]; then echo "Do not run this setup with sudo. Run it as your macOS user so GitHub SSH keys are created under your account." exit 1 fi SSH_KEY="${SSH_KEY:-$HOME/.ssh/id_ed25519}" REPO="$HOME/.personal-config" AGENT_FILES_ONLY="${AGENT_FILES_ONLY:-0}" note() { printf '==> %s\n' "$*" } fail_repo_sync() { cat <&1 \ | awk -F"'" '/Token scopes:/ { print $2 }' \ | tr ',' '\n' \ | sed 's/^[[:space:]]*//; s/[[:space:]]*$//' \ | grep -Fxq "$scope" } github_ssh_access_works() { local output output="$(ssh -o BatchMode=yes -o ConnectTimeout=10 -T git@github.com 2>&1 || true)" grep -q "successfully authenticated" <<<"$output" } ensure_github_auth() { gh auth status >/dev/null 2>&1 || \ gh auth login --hostname github.com --web gh config set git_protocol ssh >/dev/null } ensure_github_key_management_scope() { if github_auth_has_scope "admin:public_key"; then note "GitHub auth already has SSH key upload scope" else note "Refreshing GitHub auth scopes for SSH key upload" gh auth refresh --hostname github.com --scopes admin:public_key || true fi } ensure_github_ssh_config() { local ssh_config marker_begin marker_end ssh_config="$HOME/.ssh/config" marker_begin="# personal-config github.com begin" marker_end="# personal-config github.com end" mkdir -p "$HOME/.ssh" chmod 700 "$HOME/.ssh" if [[ -f "$ssh_config" ]] && grep -qF "$marker_begin" "$ssh_config"; then return 0 fi cat >> "$ssh_config" </dev/null 2>&1 || ssh-add "$SSH_KEY" >/dev/null 2>&1 || true if [[ -f "$SSH_KEY.pub" ]]; then key_material="$(awk '{print $2}' "$SSH_KEY.pub")" if ! gh ssh-key list 2>/dev/null | grep -qF "$key_material"; then gh ssh-key add "$SSH_KEY.pub" --title "$(scutil --get ComputerName 2>/dev/null || hostname)" || true fi fi } sync_repo() { if [[ -d "$REPO/.git" ]]; then note "Updating existing personal-config clone at $REPO" git -C "$REPO" pull --ff-only || fail_repo_sync else note "Cloning personal-config into $REPO" gh repo clone shaunporwal/personal-config "$REPO" fi } run_full_setup() { note "Running guided Mac setup from $REPO" exec "$REPO/scripts/setup_mac.sh" } run_agent_files_only() { command -v jq >/dev/null 2>&1 || brew install jq if command -v claude >/dev/null 2>&1; then note "Claude Code is already installed" else note "Installing Claude Code" curl -fsSL https://claude.ai/install.sh | bash fi note "Syncing agent skill files from $REPO" exec "$REPO/scripts/update_agent_files.sh" } note "Checking Xcode Command Line Tools" xcode-select -p >/dev/null 2>&1 || { echo "Install Xcode from the App Store first."; exit 1; } ORIGINAL_PATH="$PATH" note "Ensuring Homebrew is available" command -v brew >/dev/null 2>&1 || \ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" eval "$(/opt/homebrew/bin/brew shellenv 2>/dev/null)" 2>/dev/null || \ eval "$(/usr/local/bin/brew shellenv 2>/dev/null)" export PATH="$ORIGINAL_PATH:$PATH" note "Ensuring GitHub CLI is available" command -v gh >/dev/null 2>&1 || brew install gh note "Authenticating GitHub CLI" ensure_github_auth if github_ssh_access_works; then note "GitHub SSH access already works" else ensure_github_key_management_scope note "Preparing GitHub SSH key" ensure_github_ssh_key fi sync_repo if [[ "$AGENT_FILES_ONLY" == "1" ]]; then run_agent_files_only else run_full_setup fi