prospector/scripts/make-tray.sh
Natalie aa3e6eacda feat(tray): replace executable stub bin (MacOS/Prospector) with featureful dispatcher
The previous dumb stub just execd the applescript. Now the bin (still used as the bundle executable and for double-click) supports CLI features/subcommands while preserving default tray UI behavior:

- no arg / tray / menu: launch tray UI (status item + menu)
- launch / open / app: start services (delegates to launch.sh, matches menu "Open Prospector")
- stop: stop services (matches menu "Stop services")
- help: list features

Updated post-build messaging, tray.applescript header comment, scripts/README.md table, and ./run usage. Tested via TRAY_DEST=/tmp/... build + direct bin help invocation (and full make-tray success).
2026-06-29 23:23:51 -04:00

144 lines
5.5 KiB
Bash
Executable file

#!/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 (with features) — default launches tray UI; subcommands provide
# CLI features for the services (matching menu actions). Replaces the prior
# dumb stub with a small dispatcher so the bin itself has features.
cat > "$DEST/Contents/MacOS/Prospector" <<'STUB'
#!/bin/bash
set -euo pipefail
RES="$(cd "$(dirname "$0")/../Resources" && pwd)"
cmd="${1:-}"
case "$cmd" in
""|tray|menu|default)
# Launch the tray UI (AppleScript-ObjC status item + menu). This is the
# default when the .app bundle is opened/double-clicked.
exec /usr/bin/osascript "$RES/tray.applescript" "$RES"
;;
open|launch|app|open-prospector)
# Feature: start the services (web + API) detached, like the "Open Prospector" menu item.
exec "$RES/launch.sh"
;;
stop|stop-services)
# Feature: stop the running services, like the "Stop services" menu item.
exec "$RES/stop.sh"
;;
help|--help|-h)
cat <<EOF
Prospector tray (MacOS/Prospector bin with features)
Usage: $(basename "$0") [feature]
Features (CLI subcommands):
(no arg) Start tray UI / menu bar (default for bundle)
tray Same as default
launch Start services (API + panel) — same as menu "Open Prospector"
open Alias for launch
stop Stop services — same as menu "Stop services"
help This message
The tray process (when running) provides the persistent ❖ menu.
You can also invoke this bin directly for the above features.
EOF
exit 0
;;
*)
echo "Unknown feature: $cmd" >&2
echo "Try: $(basename "$0") help" >&2
exit 1
;;
esac
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."
echo " The bin now supports features directly:"
echo " $DEST/Contents/MacOS/Prospector # start tray UI (default)"
echo " $DEST/Contents/MacOS/Prospector launch # start services (like menu Open)"
echo " $DEST/Contents/MacOS/Prospector stop # stop services (like menu Stop)"
echo " $DEST/Contents/MacOS/Prospector help # list features"