scripts/install-report-server.sh
#!/bin/bash
# Install / remove an always-on web server for ~/ts03-reports (macOS launchd).
# Usage: scripts/install-report-server.sh # install + start
# scripts/install-report-server.sh --uninstall
set -euo pipefail
LABEL="com.ts03.reports"
PLIST="$HOME/Library/LaunchAgents/$LABEL.plist"
PORT="${TS03_PORT:-8765}"
REPORTS="$HOME/ts03-reports"
if [[ "${1:-}" == "--uninstall" ]]; then
launchctl unload "$PLIST" 2>/dev/null || true
rm -f "$PLIST"
echo "Removed $LABEL"
exit 0
fi
mkdir -p "$REPORTS" "$HOME/Library/LaunchAgents"
# Use the real interpreter, not the /usr/bin/python3 shim (the shim can fail under launchd)
PY="$(python3 -c 'import sys; print(sys.executable)')"
# A manually started server on the same port blocks launchd from starting
if lsof -tiTCP:"$PORT" -sTCP:LISTEN >/dev/null 2>&1; then
echo "Port $PORT is in use by PID(s): $(lsof -tiTCP:$PORT -sTCP:LISTEN | tr '\n' ' ')"
echo "Stop it first (e.g. Ctrl+C in that terminal, or: kill <PID>), then re-run."
exit 1
fi
cat > "$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>Label</key><string>$LABEL</string>
<key>ProgramArguments</key><array>
<string>$PY</string><string>-m</string><string>http.server</string><string>$PORT</string>
<string>--bind</string><string>0.0.0.0</string>
<string>--directory</string><string>$REPORTS</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardErrorPath</key><string>/tmp/ts03-reports.log</string>
</dict></plist>
PLIST
launchctl unload "$PLIST" 2>/dev/null || true
launchctl load "$PLIST"
sleep 2
if launchctl list | awk -v l="$LABEL" '$3==l && $1!="-" {ok=1} END{exit !ok}'; then
HOST="$(scutil --get LocalHostName).local"
IP="$(ipconfig getifaddr en0 2>/dev/null || true)"
echo "✅ $LABEL running on port $PORT"
echo " iPhone (same Wi-Fi): http://$HOST:$PORT/latest.html"
[[ -n "$IP" ]] && echo " or by IP: http://$IP:$PORT/latest.html"
else
echo "❌ $LABEL did not start. Check: launchctl list | grep ts03 ; cat /tmp/ts03-reports.log"
exit 1
fi
Questions or corrections: [email protected]