#!/bin/bash # Curtain installer — builds the app, installs it as a login menu-bar agent, # and sets up the (optional) root helper that disconnects a Screen Sharing session. set -euo pipefail REPO="$(cd "$(dirname "$0")/.." && pwd)" APP="/Applications/Curtain.app" AGENT="$HOME/Library/LaunchAgents/io.acamarata.curtain.plist" HELPER="/usr/local/bin/curtain-endsession" SUDOERS="/etc/sudoers.d/curtain-endsession" echo "==> Building (release)…" cd "$REPO" swift build -c release BIN="$REPO/.build/release/Curtain" echo "==> Installing $APP …" rm -rf "$APP" mkdir -p "$APP/Contents/MacOS" "$APP/Contents/Resources" cp "$BIN" "$APP/Contents/MacOS/Curtain" cat > "$APP/Contents/Info.plist" < CFBundleNameCurtain CFBundleIdentifierio.acamarata.curtain CFBundleExecutableCurtain CFBundlePackageTypeAPPL CFBundleShortVersionString1.0.0 LSUIElement LSMinimumSystemVersion13.0 PLIST # Ad-hoc sign so TCC (Accessibility) can pin a stable identity. codesign --force --deep --sign - "$APP" 2>/dev/null || true echo "==> Installing root helper (disconnect Screen Sharing on idle/unlock)…" TMP_HELPER="$(mktemp)" cat > "$TMP_HELPER" <<'HELPER' #!/bin/bash # Ends the active Screen Sharing session. launchd respawns the listener, # so Screen Sharing stays available for the next connection. pkill -f ScreenSharingSubscriber 2>/dev/null pkill -x screensharingd 2>/dev/null pkill -f "RemoteManagement.*[Ss]creen" 2>/dev/null exit 0 HELPER osascript -e "do shell script \"install -m 755 '$TMP_HELPER' '$HELPER' && printf 'admin ALL=(root) NOPASSWD: $HELPER\n' > '$SUDOERS' && chmod 440 '$SUDOERS' && visudo -cf '$SUDOERS'\" with administrator privileges" rm -f "$TMP_HELPER" echo "==> Installing login agent…" mkdir -p "$HOME/Library/LaunchAgents" cat > "$AGENT" < Labelio.acamarata.curtain ProgramArguments$APP/Contents/MacOS/Curtain RunAtLoad KeepAlive LimitLoadToSessionTypeAqua PLIST launchctl unload "$AGENT" 2>/dev/null || true launchctl load -w "$AGENT" cat <