Skip to content

Commit 30eef70

Browse files
esaruohoclaude
andcommitted
stickies-claude: single-instance lock kills duplicate-dispatch race
AppleToolbox fires the watcher from BOTH a 1.5s poll AND an FSEvents source on the Stickies dir. FSEvents fires multiple times for a single sticky save (one event per file inside the .rtfd bundle), so two watcher processes can race the same uuid: both read the sticky, both compute the same hash, both see "hash != state_file", both dispatch → two iTerm windows. Add an mkdir-based atomic lock at $STATE_DIR/.lock with a 60s stale-lock steal. Verified with 10 parallel invocations: 1 runs, 9 log "already running; skipping" and exit cleanly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 9c84364 commit 30eef70

1 file changed

Lines changed: 20 additions & 0 deletions

File tree

bin/stickies-claude-watcher

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,26 @@ mkdir -p "$STATE_DIR" "$(dirname "$LOG")"
3232

3333
log() { printf '[%s] %s\n' "$(date '+%F %T')" "$*" >> "$LOG"; }
3434

35+
# Single-instance lock. AppleToolbox fires the watcher from BOTH a 1.5s
36+
# poll AND an FSEvents source on the Stickies dir; the FSEvents source can
37+
# fire several times for a single sticky save (one event per file inside
38+
# the .rtfd bundle). Without this lock, two concurrent watcher processes
39+
# both see "hash != state_file" and both dispatch → two iTerm windows.
40+
# mkdir is the atomic primitive bash 3.2 has on macOS (no flock).
41+
LOCK_DIR="$STATE_DIR/.lock"
42+
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
43+
# Stale-lock guard: if the lock is older than 60s, the previous
44+
# watcher crashed before cleanup — steal it.
45+
if [[ -d "$LOCK_DIR" ]] && [[ -n "$(find "$LOCK_DIR" -maxdepth 0 -mmin +1 2>/dev/null)" ]]; then
46+
log "stealing stale lock (>60s old) pid=$$"
47+
rm -rf "$LOCK_DIR" && mkdir "$LOCK_DIR" 2>/dev/null || exit 0
48+
else
49+
log "watcher already running; skipping pid=$$"
50+
exit 0
51+
fi
52+
fi
53+
trap 'rmdir "$LOCK_DIR" 2>/dev/null' EXIT
54+
3555
log "watcher fired pid=$$ ppid=$PPID"
3656

3757
lookup_cwd() {

0 commit comments

Comments
 (0)