Set canJoinAllSpaces + fullScreenAuxiliary on overlay windows so the
border renders regardless of which Space or fullscreen app is active.
In window mode, fall back to screen-edge border when Cursor isn't
frontmost to avoid a floating rectangle on other Spaces.
Made-with: Cursor
Register for NSApplicationDidChangeScreenParametersNotification and
NSWorkspaceDidWakeNotification so the daemon refreshes NSScreen.screens()
after external monitors connect/disconnect or the system wakes from sleep.
Made-with: Cursor
Interacting with one Cursor window no longer dismisses overlays from
other windows. The overlay manager now tracks panels by tag (workspace),
the daemon maintains per-workspace pending/active/cooldown state, and
dismiss logic identifies the focused window via AXFocusedWindow to
target only that workspace's pulse.
Made-with: Cursor
Config now uses top-level dark/light sections (each with running/completed
styles) and a theme option ("dark", "light", "auto"). The daemon resolves
the active theme at flash time via NSApp.effectiveAppearance().
Made-with: Cursor
- Add MIT LICENSE
- Polish README: tagline, permissions docs, clone URL
- Add license, authors, readme, and repository URL to pyproject.toml
- Remove stale docs/plans/ (relocated to .cursor/) and requirements.txt
- Deduplicate and clean up .gitignore
Made-with: Cursor
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
- Added pyobjc-framework-ApplicationServices to dependencies (was
implicitly available via pyenv's system packages but missing in
clean venvs)
- Added `cursor-flasher check` command that verifies Cursor is running
and accessibility permissions are working
- Detector now logs a warning when a11y tree reads fail (previously
failed silently, making permission issues invisible)
- Switched to uv for dependency management: `uv sync` + `uv run`
- Updated README with uv-based workflow and accessibility
troubleshooting guide
Made-with: Cursor
- Added "Resume" and "Continue" to approval keywords
- Added state transition logging to daemon for observability
- Guarded signal handler against duplicate SIGTERM delivery
- Verified end-to-end: daemon detects approval prompt, transitions
to waiting_for_user, overlays 1 window, plays sound
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
Renamed OverlayWindow to OverlayManager. Now discovers all on-screen
windows for the Cursor PID and creates/reuses/hides overlay windows
dynamically to match. Filters out tiny windows (<100px).
Verified: detects 3 windows across monitors.
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
Findings: Cursor uses bundle ID com.todesktop.230313mzl4w4u92.
Electron web content exposed as AXStaticText values within AXWebArea,
not AXButton titles. Detector must search AXStaticText elements.
Made-with: Cursor
Defines the approach for a macOS daemon that monitors Cursor's
accessibility tree and shows a pulsing border overlay when the
agent is waiting for user input.
Made-with: Cursor