prospector/scripts/make-tray.sh

96 lines
3.7 KiB
Bash
Raw Permalink Normal View History

#!/usr/bin/env bash
# Build (and install) the Prospector menu-bar tray app: a macOS .app bundle that
# shows a status-bar icon with Open / Stop / Quit, launching the local app via
# ./run. No Swift, no deps — AppleScript-ObjC + built-in icon tooling.
#
# scripts/make-tray.sh build into ~/Applications/Prospector.app
# TRAY_DEST=/path/Prospector.app override install location
# ./run tray (preferred entrypoint)
set -euo pipefail
. "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
DEST="${TRAY_DEST:-$HOME/Applications/Prospector.app}"
SVG="$REPO_ROOT/web/public/icon.svg"
[[ -f "$SVG" ]] || die "icon not found at $SVG"
NODE_BIN="$(dirname "$(command -v node)")"
[[ -n "$NODE_BIN" ]] || die "node not found on PATH"
WORK="$(mktemp -d)"
trap 'rm -rf "$WORK"' EXIT
# 1. Rasterize the SVG (qlmanage renders crisply at 1024; sips is the fallback).
BASE="$WORK/base.png"
if qlmanage -t -s 1024 -o "$WORK" "$SVG" >/dev/null 2>&1 && [[ -f "$WORK/icon.svg.png" ]]; then
mv "$WORK/icon.svg.png" "$BASE"
else
sips -s format png "$SVG" --out "$BASE" >/dev/null
fi
# 2. Assemble the bundle skeleton.
info "building $DEST"
rm -rf "$DEST"
mkdir -p "$DEST/Contents/MacOS" "$DEST/Contents/Resources"
RES="$DEST/Contents/Resources"
# 3. AppIcon.icns (full iconset) + tray.png (menu-bar size).
ICONSET="$WORK/AppIcon.iconset"; mkdir -p "$ICONSET"
for s in 16 32 128 256 512; do
sips -z "$s" "$s" "$BASE" --out "$ICONSET/icon_${s}x${s}.png" >/dev/null
d=$(( s * 2 )); sips -z "$d" "$d" "$BASE" --out "$ICONSET/icon_${s}x${s}@2x.png" >/dev/null
done
iconutil -c icns "$ICONSET" -o "$RES/AppIcon.icns"
sips -z 36 36 "$BASE" --out "$RES/tray.png" >/dev/null
# 4. Info.plist (LSUIElement = menu-bar only, no Dock icon).
cat > "$DEST/Contents/Info.plist" <<'PLIST'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleName</key><string>Prospector</string>
<key>CFBundleDisplayName</key><string>Prospector</string>
<key>CFBundleIdentifier</key><string>com.transquinnftw.prospector.tray</string>
<key>CFBundleVersion</key><string>0.1.0</string>
<key>CFBundleShortVersionString</key><string>0.1.0</string>
<key>CFBundlePackageType</key><string>APPL</string>
<key>CFBundleExecutable</key><string>Prospector</string>
<key>CFBundleIconFile</key><string>AppIcon</string>
<key>LSUIElement</key><true/>
<key>LSMinimumSystemVersion</key><string>10.15</string>
</dict>
</plist>
PLIST
# 5. Executable stub — runs the tray AppleScript, passing it its Resources dir.
cat > "$DEST/Contents/MacOS/Prospector" <<'STUB'
#!/bin/bash
RES="$(cd "$(dirname "$0")/../Resources" && pwd)"
exec /usr/bin/osascript "$RES/tray.applescript" "$RES"
STUB
chmod +x "$DEST/Contents/MacOS/Prospector"
# 6. Tray script + the menu's launch/stop helpers (node bin baked onto PATH, since
# `do shell script` runs with a minimal PATH that lacks Homebrew node).
cp "$REPO_ROOT/scripts/tray.applescript" "$RES/tray.applescript"
cat > "$RES/launch.sh" <<SH
#!/usr/bin/env bash
export PATH="$NODE_BIN:\$PATH"
exec "$REPO_ROOT/run" app --detach
SH
cat > "$RES/stop.sh" <<SH
#!/usr/bin/env bash
export PATH="$NODE_BIN:\$PATH"
exec "$REPO_ROOT/run" stop
SH
chmod +x "$RES/launch.sh" "$RES/stop.sh"
# 7. Validate before declaring success.
plutil -lint "$DEST/Contents/Info.plist" >/dev/null || die "Info.plist failed validation"
osacompile -o "$WORK/syntax-check.scpt" "$RES/tray.applescript" >/dev/null || die "tray.applescript failed to compile"
ok "tray app built → $DEST"
echo " Open it once (double-click in ~/Applications or 'open \"$DEST\"') to put the"
echo " ❖ icon in your menu bar. It survives logout via Login Items if you add it."