1#!/usr/bin/env bash
2# Build the Clover Recorder capture engine and wrap it in a minimal .app bundle.
3#
4# macOS only grants and reliably lists *app bundles* (stable bundle id) under
5# Privacy → Screen Recording, so even the headless capture core ships as an app.
6#
7# Usage: ./build.sh (run on the Mac that will do the recording)
8set -euo pipefail
9
10HERE="$(cd "$(dirname "$0")" && pwd)"
11ENGINE="$HERE/engine"
12DIST="$HERE/dist"
13APP="$DIST/Clover Recorder.app"
14BUNDLE_ID="org.clover.recorder"
15VERSION="0.1.0"
16
17echo "==> swift build (release)"
18( cd "$ENGINE" && swift build -c release )
19BIN="$ENGINE/.build/release/recorder"
20
21echo "==> assembling $APP"
22rm -rf "$APP"
23mkdir -p "$APP/Contents/MacOS"
24cp "$BIN" "$APP/Contents/MacOS/recorder"
25
26echo "==> compiling uvc-powerline helper"
27clang -O2 -o "$APP/Contents/MacOS/uvc-powerline" "$HERE/uvc/uvc-powerline.c" \
28 -framework IOKit -framework CoreFoundation
29
30echo "==> bundling dictation scripts"
31mkdir -p "$APP/Contents/Resources"
32cp "$HERE"/dictation/*.py "$APP/Contents/Resources/"
33
34cat > "$APP/Contents/Info.plist" <<EOF
35<?xml version="1.0" encoding="UTF-8"?>
36<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
37<plist version="1.0"><dict>
38 <key>CFBundleIdentifier</key><string>$BUNDLE_ID</string>
39 <key>CFBundleName</key><string>Clover Recorder</string>
40 <key>CFBundleExecutable</key><string>recorder</string>
41 <key>CFBundlePackageType</key><string>APPL</string>
42 <key>CFBundleShortVersionString</key><string>$VERSION</string>
43 <key>CFBundleVersion</key><string>$VERSION</string>
44 <key>LSMinimumSystemVersion</key><string>14.0</string>
45 <key>LSUIElement</key><true/>
46 <key>NSMicrophoneUsageDescription</key><string>Clover Recorder records your microphone for journaling and improv sessions.</string>
47 <key>NSCameraUsageDescription</key><string>Clover Recorder records your webcam for journaling and improv sessions.</string>
48</dict></plist>
49EOF
50
51# Sign with the stable self-signed identity from the dedicated Clover keychain
52# (see setup-signing.sh). This keeps the same designated requirement across
53# rebuilds, so the Screen Recording grant survives. Falls back to ad-hoc.
54CN="Clover Code Signing"
55KC="$HOME/Library/Keychains/clover-signing.keychain-db"
56KCPW="${CLOVER_KEYCHAIN_PW:-clover}"
57
58if [[ -f "$KC" ]] && security find-identity -p codesigning "$KC" 2>/dev/null | grep -q "$CN"; then
59 security unlock-keychain -p "$KCPW" "$KC" 2>/dev/null || true
60 echo "==> codesign with stable identity '$CN'"
61 codesign --force --keychain "$KC" --sign "$CN" --timestamp=none "$APP"
62else
63 echo "==> codesign ad-hoc (run setup-signing.sh once for a stable identity)"
64 codesign --force --sign - "$APP"
65fi
66
67codesign -dv "$APP" 2>&1 | sed -n '1,4p' || true
68echo "==> built: $APP"
69echo " binary: $APP/Contents/MacOS/recorder"