# cursor-flasher: Full Implementation **Date:** 2026-03-10 **Branch:** feat/cursor-flasher → merged to master (14 commits) ## Task Build a macOS daemon that monitors Cursor IDE's accessibility tree and shows a pulsing border overlay + plays a sound when the AI agent is waiting for user input. ## Changes Made ### Core Modules (src/cursor_flasher/) - **config.py** — Dataclass-based config with YAML loading from `~/.cursor-flasher/config.yaml` - **state.py** — State machine: IDLE → AGENT_WORKING → WAITING_FOR_USER with cooldown logic - **detector.py** — Per-window accessibility tree scanning; detects approval prompts (Accept, Reject, Run, etc.) and agent-working indicators (Stop, Cancel) via AXStaticText values and AXButton titles - **overlay.py** — Native macOS overlay using NSWindow + PulseBorderView with sine-wave opacity animation; reads position directly from AXWindow elements - **sound.py** — System sound playback via NSSound - **daemon.py** — Main loop wiring detection → state machine → overlay + sound; NSRunLoop-based event loop - **cli.py** — `cursor-flasher start/stop/status` CLI with PID file management and fork-based daemonization ### Dev Tools (scripts/) - **dump_a11y_tree.py** — Dumps Cursor's full accessibility tree for debugging detection patterns - **test_overlay.py** — Manual overlay test with `--per-window` flag ### Tests (31 passing) - test_config.py (7), test_state.py (10), test_detector.py (12), test_sound.py (2) ## Key Decisions & Discoveries - Cursor's bundle ID is `com.todesktop.230313mzl4w4u92` (not matchable by app name alone) - Electron web content exposes UI as AXStaticText values, not AXButton titles - CGWindowList returns empty names for Electron windows; position tracking uses AXWindow AXPosition/AXSize via AXValueGetValue instead - Per-window detection: only the specific window(s) with active approval prompts get flashed - pyproject.toml build-backend corrected from plan's `setuptools.backends._legacy:_Backend` to `setuptools.build_meta` - NSRect.insetBy doesn't exist in pyobjc; used NSInsetRect instead ## Follow-up Items - Detection patterns may need tuning as Cursor UI evolves - No menu bar icon (out of MVP scope) - No auto-start on login - No multi-monitor awareness beyond what CGWindow/AXWindow coordinates provide