1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
#!/usr/bin/env bash
# Repoint the com.humdrum.ticktock.autotrack launchd agent at `tt autotrack`.
#
# Rollback: the Python daemon in ticktock-old is untouched — re-run
# ~/Developer/Home/ticktock-old/daemon/install-daemon.sh
# (note: it installs under the old com.ticktock.autotrack label; bootout the
# com.humdrum one first) or hand-edit the plist back to autotrack.py.
set -euo pipefail
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
TT="$REPO/bin/tt"
LABEL="com.humdrum.ticktock.autotrack"
PLIST="${HOME}/Library/LaunchAgents/${LABEL}.plist"
[ -x "$TT" ] || { echo "missing $TT — run: make build helpers" >&2; exit 1; }
mkdir -p "${HOME}/.local/share/ticktock" "${HOME}/Library/LaunchAgents"
# Prove the new binary actually runs before we touch the live agent. If this
# fails we bail out here, with the Python daemon still installed and running.
echo "smoke-testing ${TT} autotrack --once ..."
if ! "$TT" autotrack --once >/dev/null 2>&1; then
echo "✗ ${TT} autotrack --once failed — aborting, Python daemon left running" >&2
exit 1
fi
sed -e "s#@TT@#${TT}#g" -e "s#@HOME@#${HOME}#g" \
"$REPO/deploy/autotrack.plist.template" > "$PLIST"
launchctl bootout "gui/$(id -u)/${LABEL}" 2>/dev/null || true
launchctl bootstrap "gui/$(id -u)" "$PLIST"
# bootout/bootstrap can race: bootout can return before the old job is fully
# torn down, making bootstrap report success while the new job never reaches
# "running". Give it a moment, then confirm and force a (re)start if needed
# rather than silently leaving no daemon in place.
sleep 1
state="$(launchctl print "gui/$(id -u)/${LABEL}" 2>/dev/null | awk '/state = /{print $3; exit}')"
if [ "$state" != "running" ]; then
echo " ${LABEL} not running yet (state: ${state:-unknown}) — kickstarting..." >&2
launchctl kickstart -k "gui/$(id -u)/${LABEL}" 2>/dev/null || true
sleep 1
state="$(launchctl print "gui/$(id -u)/${LABEL}" 2>/dev/null | awk '/state = /{print $3; exit}')"
fi
if [ "$state" != "running" ]; then
echo "✗ ${LABEL} did not reach 'running' state (state: ${state:-unknown})." >&2
echo " Check: launchctl print gui/$(id -u)/${LABEL}" >&2
echo " Rollback: see the header of this script." >&2
exit 1
fi
echo "✓ ${LABEL} → ${TT} autotrack (${PLIST})"
echo " verify: launchctl print gui/$(id -u)/${LABEL} | grep -E 'state|program'"
echo " logs: tail -f ~/.local/share/ticktock/autotrack.err"
echo
echo "IMPORTANT — macOS permissions do NOT carry over from the old daemon:"
echo " ${TT} is a new binary, so Accessibility, Automation (System Events /"
echo " browser control), and Calendar access must be re-granted in System"
echo " Settings → Privacy & Security for ${TT} (and its winctx helper)."
echo " Until granted, autotrack degrades silently instead of erroring."
echo " Trigger the permission prompts now from Terminal:"
echo " \"$TT\" autotrack --once"
echo " \"$TT\" autotrack --list-calendars"
|