mac: name the laptop build a profile, and derive it like the others

Renamed for parity now that Linux has a light profile too:
  scripts/setup_mac.sh       -> scripts/setup_mac_light.sh
  ecosystem.mac.config.cjs   -> ecosystem.mac.light.config.cjs

The macOS process list was still a hand-copied subset, which is the shape that
broke it: written 2026-07-28, within days it was running the Anthropic proxy
under the name officer-claude with nothing spawning `claude`, and pointing at a
pty entry point that had moved. Both silent. It now declares names and reasons
and reads script/args from ecosystem.config.cjs, so a launch change on the host
reaches it for free.

The include/exclude checks moved into ecosystem.profile.cjs rather than being
copied into the second profile — duplicating the guard rails would have repeated
the mistake they exist to catch. Both profiles were re-tested against a mutated
host ecosystem: renaming an included app and adding an unclassified sidecar each
throw in both, and an unmodified host loads five apps in both.

Kept as two files rather than collapsed into one, even though they currently
produce identical output. The exclusions do not mean the same thing: on macOS
officer-vnc CANNOT run, there being no Xorg; on a Linux light install it could
run fine and you have chosen not to. Merging them would lose that, and they
diverge the moment one profile gains something the other cannot have.

setup_mac_light.sh's verification loop now reads app names with node instead of
grepping for `name:` — the derived profile has no literal keys, so the grep
would have silently listed no services at all, which reads the same as a healthy
install with nothing configured.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-04 12:47:27 +00:00
co-authored by Claude Opus 5
parent 1f4dbbb810
commit 0a1766768d
5 changed files with 170 additions and 160 deletions
@@ -8,7 +8,7 @@
#
# EVERY STEP IS OPTIONAL. Each one prompts before doing anything, and can be preset non-interactively:
#
# SETUP_POSTGRES=0 SETUP_OPENCODE=0 bash scripts/setup_mac.sh
# SETUP_POSTGRES=0 SETUP_OPENCODE=0 bash scripts/setup_mac_light.sh
#
# SETUP_PACKAGES brew node@22 / bun / ffmpeg SETUP_CLAUDE claude code CLI
# SETUP_POSTGRES brew postgresql@18 + createdb SETUP_OPENCODE opencode CLI
@@ -22,7 +22,7 @@
# This script never calls sudo itself — everything lands under the Homebrew prefix or $HOME. Note
# that Homebrew's own installer does ask for an administrator password on a fresh Mac.
#
# Usage: bash scripts/setup_mac.sh
# Usage: bash scripts/setup_mac_light.sh
set -euo pipefail
@@ -54,7 +54,7 @@ PG_FORMULA="postgresql@18"
PG_DATABASE="officer_dev"
NODE_FORMULA="node@22"
ENV_FILE="$PROJECT_DIR/.env"
ECOSYSTEM="$PROJECT_DIR/ecosystem.mac.config.cjs"
ECOSYSTEM="$PROJECT_DIR/ecosystem.mac.light.config.cjs"
# Ask, unless the matching SETUP_* variable already decided. $1 = variable name, $2 = prompt,
# $3 = default (y|n) used for a bare Enter and for non-interactive runs.
@@ -430,7 +430,7 @@ fi
step "Services (pm2)"
if ! has pm2 || [ ! -f "$ECOSYSTEM" ]; then
skip "services (pm2 or ecosystem.mac.config.cjs missing)"
skip "services (pm2 or ecosystem.mac.light.config.cjs missing)"
elif [ ! -f "$ENV_FILE" ]; then
# Starting without .env gives a server on port 5000 with no database and a JWT_SECRET throw.
skip "services (.env missing — they would crash-loop)"
@@ -497,7 +497,13 @@ check pm2
if has pm2 && [ -f "$ECOSYSTEM" ]; then
echo ""
echo "Services:"
for app in $(grep -oE "name: *'[^']+'" "$ECOSYSTEM" | sed "s/.*'\(.*\)'/\1/" || true); do
# Read the names with node rather than grepping for `name:`. The profile derives its apps from
# ecosystem.config.cjs and has no literal name keys to match, so a grep silently lists nothing —
# which looks identical to "no services configured". Loading it also exercises the profile's own
# consistency checks, which is exactly the moment you want to hear about a drifted include list.
ECOSYSTEM_APPS=$(node -e "require('$ECOSYSTEM').apps.forEach(a=>console.log(a.name))" 2>/dev/null) \
|| fail "$(basename "$ECOSYSTEM") could not be loaded — run: node -e \"require('./$(basename "$ECOSYSTEM")')\" to see why"
for app in $ECOSYSTEM_APPS; do
if [ -n "$(pm2 pid "$app" 2>/dev/null | tr -d '[:space:]' || true)" ]; then
ok "$app"
else
@@ -519,11 +525,11 @@ echo "════════════════════════
echo ""
echo "Notes:"
echo " • Open ${ENV_PUBLIC_URL:-http://localhost:9010} — the first-run screen creates the owner account"
echo " • Logs: pm2 logs Restart: pm2 restart ecosystem.mac.config.cjs"
echo " • Logs: pm2 logs Restart: pm2 restart ecosystem.mac.light.config.cjs"
echo " • Postgres must be running before the services start, or db:push and boot will fail"
echo " • Not run on macOS: VNC desktop, email sync, music indexer, cliamp audio, and the sidecars"
echo " that front a container or an external service — vault, slskd, headscale, transmission,"
echo " invoiceshelf, memos, photos, caldav, notify, wallet. See ecosystem.mac.config.cjs."
echo " invoiceshelf, memos, photos, caldav, notify, wallet. See ecosystem.mac.light.config.cjs."
echo " • Pin a specific Claude CLI with CLAUDE_BIN=/path/to/claude in .env if you need to"
echo " • Re-run any single step with e.g. SETUP_OPENCODE=1 bash scripts/setup_mac.sh"
echo " • Re-run any single step with e.g. SETUP_OPENCODE=1 bash scripts/setup_mac_light.sh"
echo ""