#!/bin/bash # launch.command — double-click to start the Personal Dashboard and open it. # Builds on first run (or after updates), starts the local server on :4317, # waits until it's healthy, then opens the browser. Safe to run repeatedly. set -euo pipefail # Finder-launched scripts get a minimal PATH — add Homebrew + common bins. # node@22 must come first: better-sqlite3's prebuilt binary won't build under # the default Homebrew node (v26), so pin the build/run to node@22. export PATH="/opt/homebrew/opt/node@22/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:$PATH" PORT=4317 URL="http://localhost:${PORT}" # Repo = parent of this script's dir, regardless of where it's launched from. REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" cd "$REPO" echo "Personal Dashboard → $REPO" # This repo lives under ~/Documents, which iCloud syncs. iCloud churns and # evicts the rapidly-rewritten build cache (.next) and can corrupt the open # SQLite DB. Redirect those local artifacts to *.nosync dirs (iCloud ignores # any path ending in .nosync) via symlinks, so the paths stay the same. for d in .next data editions; do if [ ! -L "$d" ]; then [ -d "$d" ] && mv "$d" "$d.nosync" # preserve existing contents (e.g. the DB) mkdir -p "$d.nosync" ln -snf "$d.nosync" "$d" fi done # Already running? Just open it. if curl -sf "${URL}/api/health" >/dev/null 2>&1; then echo "Already running. Opening $URL" open "$URL" exit 0 fi # Ensure dependencies. if [ ! -d node_modules ]; then echo "Installing dependencies…" pnpm install fi # Ensure the local database exists. if [ ! -f data/dashboard.db ]; then echo "Setting up database…" pnpm db:push pnpm db:seed fi # Build if there's no production build yet (pass --rebuild to force). if [ "${1:-}" = "--rebuild" ] || [ ! -f .next/BUILD_ID ]; then echo "Building (first run / --rebuild)…" pnpm build fi echo "Starting server on :${PORT}…" pnpm start & SERVER_PID=$! # Wait for health, then open the browser. for _ in $(seq 1 60); do if curl -sf "${URL}/api/health" >/dev/null 2>&1; then echo "Ready. Opening $URL" open "$URL" break fi sleep 1 done # Keep the server in the foreground so closing this window stops it. wait "$SERVER_PID"