samayly.com is live. Hosted plans open soon. Join the waitlist →
bash90 linescopy and edit

scripts/install-bot.sh

Copy this file into your setup and edit the marked values. Do not use it as-is.

scripts/install-bot.sh
#!/bin/bash
# Run ts03-bot as an always-on launchd service (and optionally a daily digest).
# Usage:
#   scripts/install-bot.sh telegram                 # install + start
#   scripts/install-bot.sh whatsapp --digest 08:00  # also send /brief daily at 08:00
#   scripts/install-bot.sh whatsapp --digest 08:00,22:00  # twice a day (Mac local time, 24h)
#   scripts/install-bot.sh telegram --uninstall
set -euo pipefail

PLATFORM="${1:-}"; shift || true
[[ "$PLATFORM" == "telegram" || "$PLATFORM" == "whatsapp" ]] || { echo "Usage: $0 telegram|whatsapp [--digest HH:MM] [--uninstall]"; exit 1; }

LABEL="com.ts03.bot.$PLATFORM"
DLABEL="com.ts03.bot.$PLATFORM.digest"
AGENTS="$HOME/Library/LaunchAgents"
BOT="$HOME/.local/bin/ts03-bot"
ENVF="$HOME/.config/ts03-bot.env"
DIGEST=""

while [[ $# -gt 0 ]]; do
  case "$1" in
    --uninstall)
      for l in "$LABEL" "$DLABEL"; do launchctl unload "$AGENTS/$l.plist" 2>/dev/null || true; rm -f "$AGENTS/$l.plist"; done
      echo "Removed $LABEL (and digest if present)"; exit 0 ;;
    --digest) DIGEST="${2:?HH:MM}"; shift 2 ;;
    *) echo "Unknown option: $1"; exit 1 ;;
  esac
done

[[ -f "$ENVF" ]] || { echo "Missing $ENVF. Copy templates/ts03-bot.env.example there and fill it in."; exit 1; }
chmod 600 "$ENVF"
mkdir -p "$HOME/.local/bin" "$AGENTS" "$HOME/Library/Logs"
SRC="$(cd "$(dirname "$0")" && pwd)/ts03-bot"
cp "$SRC" "$BOT" && chmod +x "$BOT"
PY="$(python3 -c 'import sys; print(sys.executable)')"     # real interpreter, not the shim

write_plist() {  # $1 label, $2 extra args, $3 schedule xml, $4 keepalive true/false
cat > "$AGENTS/$1.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>$1</string>
  <key>ProgramArguments</key><array>
    <string>$PY</string><string>$BOT</string><string>$PLATFORM</string>$2
  </array>
  <key>EnvironmentVariables</key><dict>
    <key>PATH</key><string>$HOME/.local/bin:/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
    <key>HOME</key><string>$HOME</string>
  </dict>
  $3
  <key>KeepAlive</key><$4/>
  <key>StandardOutPath</key><string>$HOME/Library/Logs/$1.out</string>
  <key>StandardErrorPath</key><string>$HOME/Library/Logs/$1.err</string>
</dict></plist>
PLIST
  launchctl unload "$AGENTS/$1.plist" 2>/dev/null || true
  launchctl load "$AGENTS/$1.plist"
}

SCHED=""
if [[ -n "$DIGEST" ]]; then
  # validate every time BEFORE touching the running service
  TIME_RE='^([01]?[0-9]|2[0-3]):([0-5][0-9])$'
  IFS=',' read -r -a TIMES <<< "$DIGEST"
  for t in "${TIMES[@]}"; do
    t="${t// /}"
    if ! [[ "$t" =~ $TIME_RE ]]; then
      echo "Invalid digest time '$t'. Use 24h HH:MM, comma-separated, e.g. --digest 08:00,22:00"; exit 1
    fi
    H=$((10#${BASH_REMATCH[1]})); M=$((10#${BASH_REMATCH[2]}))
    SCHED+="<dict><key>Hour</key><integer>$H</integer><key>Minute</key><integer>$M</integer></dict>"
  done
fi

write_plist "$LABEL" "" "<key>RunAtLoad</key><true/>" true

if [[ -n "$DIGEST" ]]; then
  write_plist "$DLABEL" "<string>--digest</string>" \
    "<key>StartCalendarInterval</key><array>$SCHED</array>" false
  echo "📅 Digest scheduled at $DIGEST (Mac local time)"
fi

sleep 2
if launchctl list | awk -v l="$LABEL" '$3==l && $1!="-" {ok=1} END{exit !ok}'; then
  echo "✅ $LABEL running. Logs: ~/Library/Logs/ts03-bot.log"
else
  echo "❌ $LABEL not running. Check: launchctl list | grep ts03.bot ; cat ~/Library/Logs/$LABEL.err"
  exit 1
fi

Questions or corrections: [email protected]