Files
clawdmeter/install-mac.sh
T
512039e740 Add macOS host support
Cherry-picks the macOS-specific pieces from PR #5: Python daemon using
bleak (CoreBluetooth backend), LaunchAgent template, flash-mac.sh, and
install-mac.sh. Token is read from the macOS Keychain ("Claude
Code-credentials" service); Linux behavior is unchanged. README split
into "macOS installation" and "Linux installation" sections with
parallel Flash / Pair / Install subsections.

Co-Authored-By: Chris Davidson <36679917+lorddavidson@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-14 18:39:13 +00:00

86 lines
3.0 KiB
Bash
Executable File

#!/bin/bash
# macOS installer for Clawdmeter daemon (Python + bleak + launchd).
# Mirrors install.sh but uses LaunchAgents instead of systemd user units.
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
SERVICE_LABEL="com.user.claude-usage-daemon"
PLIST_SRC="$SCRIPT_DIR/daemon/$SERVICE_LABEL.plist"
PLIST_DST="$HOME/Library/LaunchAgents/$SERVICE_LABEL.plist"
VENV_DIR="$SCRIPT_DIR/daemon/.venv"
DAEMON_PY="$SCRIPT_DIR/daemon/claude_usage_daemon.py"
LOG_DIR="$HOME/Library/Logs"
LOG_OUT="$LOG_DIR/claude-usage-daemon.out.log"
LOG_ERR="$LOG_DIR/claude-usage-daemon.err.log"
echo "=== Clawdmeter macOS install ==="
echo ""
echo "[1/5] Checking prerequisites..."
for cmd in python3 curl; do
command -v "$cmd" >/dev/null || { echo "Error: $cmd is required"; exit 1; }
done
if [ ! -f "$HOME/.claude/.credentials.json" ]; then
echo "Warning: ~/.claude/.credentials.json not found."
echo " Sign in via Claude Code first, then re-run this installer."
echo " Continuing anyway — the daemon will retry on each poll."
fi
echo " OK"
echo ""
echo "[2/5] Creating Python virtualenv at daemon/.venv ..."
if [ ! -d "$VENV_DIR" ]; then
python3 -m venv "$VENV_DIR"
fi
"$VENV_DIR/bin/pip" install --quiet --upgrade pip
"$VENV_DIR/bin/pip" install --quiet "bleak>=0.22" "httpx>=0.27"
PYTHON_BIN="$VENV_DIR/bin/python"
echo " OK ($PYTHON_BIN)"
echo ""
echo "[3/5] Rendering launchd plist..."
mkdir -p "$HOME/Library/LaunchAgents" "$LOG_DIR"
sed \
-e "s|__PYTHON_BIN__|${PYTHON_BIN}|g" \
-e "s|__DAEMON_PATH__|${DAEMON_PY}|g" \
-e "s|__REPO_DIR__|${SCRIPT_DIR}|g" \
-e "s|__LOG_OUT__|${LOG_OUT}|g" \
-e "s|__LOG_ERR__|${LOG_ERR}|g" \
-e "s|__HOME__|${HOME}|g" \
"$PLIST_SRC" > "$PLIST_DST"
echo " Installed: $PLIST_DST"
echo ""
echo "[4/5] Bluetooth permission check..."
echo " On first run the daemon will trigger a Bluetooth permission prompt."
echo " macOS only prompts for foreground processes — so we'll run it"
echo " interactively once below. Press Ctrl+C after you see 'Scanning...'"
echo " and grant permission when prompted. Then re-run this installer"
echo " (or just continue) to enable launchd autostart."
echo ""
read -r -p "Run a permission-priming scan now? [Y/n] " ans
if [[ ! "$ans" =~ ^[Nn]$ ]]; then
"$PYTHON_BIN" "$DAEMON_PY" || true
fi
echo ""
echo "[5/5] Loading launchd service..."
launchctl unload "$PLIST_DST" 2>/dev/null || true
launchctl load -w "$PLIST_DST"
echo " Loaded."
echo ""
echo "=== Done ==="
echo ""
echo "First-time Bluetooth pairing (after firmware is flashed):"
echo " 1. Power on the device."
echo " 2. Open System Settings → Bluetooth."
echo " 3. Click 'Connect' next to 'Claude Controller'."
echo " 4. The daemon will discover it within ~30 s and start polling."
echo ""
echo "Useful commands:"
echo " launchctl list | grep claude-usage # check it's running"
echo " tail -F $LOG_OUT # live logs"
echo " launchctl unload $PLIST_DST # stop"
echo " launchctl load -w $PLIST_DST # start"