Major changes:
- Add StyleConfig dataclass with independent color, width, opacity,
duration, pulse_speed, sound, and volume per mode (running/completed)
- Replace flat flash_*/sound_*/play_on config with running: and
completed: YAML sections
- Replace CGEventTap (silently fails in forked daemon) with
CGEventSourceSecondsSinceLastEventType polling for reliable
input-based pulse dismissal when Cursor is already frontmost
- Update overlay, sound, and daemon to pass StyleConfig per call
- Rewrite tests for new config shape and dismiss mechanism
Made-with: Cursor
State machine no longer transitions directly from IDLE to WAITING_FOR_USER
on approval signals. Must see AGENT_WORKING first — this prevents stale
buttons like "Run this time only" persisting in chat history from
triggering the flash when no agent task is active.
Also removed "Continue" and "Resume" from approval keywords (too generic,
appear in normal chat text).
Made-with: Cursor
Detector now walks each AXWindow subtree independently and returns
both aggregate signals (for state machine) and a list of AXWindow
element refs for windows with active approval signals.
Overlay reads position/size directly from AXWindow elements via
AXValueGetValue, eliminating the CGWindowList dependency (which
returned empty names for Electron windows anyway).
Daemon passes only the active AXWindow refs to the overlay, so
only the specific window(s) waiting for user input get flashed.
Made-with: Cursor
Adapted from plan to match real a11y tree structure: Electron web
content exposes in-app buttons as AXStaticText values, not AXButton
titles. Detects via exact matches and regex patterns. Uses correct
Cursor bundle ID for process lookup.
Made-with: Cursor