- 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
106 lines
3.6 KiB
Markdown
106 lines
3.6 KiB
Markdown
# cursor-flasher
|
|
|
|
A macOS daemon that flashes a pulsing border and plays a sound when your [Cursor](https://cursor.com) AI agent needs attention.
|
|
|
|
## How It Works
|
|
|
|
Uses [Cursor hooks](https://cursor.com/docs/agent/hooks) for reliable detection:
|
|
|
|
- **`preToolUse`** — fires when the agent wants to run a shell command, write a file, or use any tool that may need approval. **Pulses** the border continuously and plays a sound until you click the Cursor window.
|
|
- **`stop`** — fires when the agent loop ends. **Flashes** the border once, briefly.
|
|
|
|
Only tools in the `approval_tools` list trigger the pulse (default: `Shell`, `Write`, `Delete`). Auto-approved tools like `Read` and `Grep` are ignored.
|
|
|
|
## Prerequisites
|
|
|
|
- macOS
|
|
- [uv](https://docs.astral.sh/uv/)
|
|
- Cursor IDE
|
|
- **Accessibility** permission for your terminal (System Settings → Privacy & Security → Accessibility) — needed for window enumeration
|
|
- **Input Monitoring** permission for the daemon process (System Settings → Privacy & Security → Input Monitoring) — needed for input-based pulse dismissal
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
# Clone and install
|
|
git clone https://code.cottongin.xyz/cursor-flasher && cd cursor-flasher
|
|
uv sync
|
|
|
|
# Install Cursor hooks (global, applies to all projects)
|
|
uv run cursor-flasher install
|
|
|
|
# Start the daemon
|
|
uv run cursor-flasher start
|
|
```
|
|
|
|
The `install` command copies the hook script to `~/.cursor/hooks/` and adds entries to `~/.cursor/hooks.json`. Cursor auto-reloads hooks.
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
uv run cursor-flasher start # background daemon
|
|
uv run cursor-flasher start --foreground # foreground (for debugging)
|
|
uv run cursor-flasher status
|
|
uv run cursor-flasher stop
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Optional config file at `~/.cursor-flasher/config.yaml`:
|
|
|
|
```yaml
|
|
running: # approval pulse (continuous until you interact)
|
|
color: "#FF9500" # border color (hex)
|
|
width: 4 # border thickness in pixels
|
|
opacity: 0.85 # max border opacity
|
|
pulse_speed: 1.5 # pulse cycle speed in seconds
|
|
sound: "Glass" # macOS system sound ("" to disable)
|
|
volume: 0.5 # 0.0 to 1.0
|
|
# sounds: Basso, Blow, Bottle, Frog, Funk, Glass, Hero,
|
|
# Morse, Ping, Pop, Purr, Sosumi, Submarine, Tink
|
|
|
|
completed: # agent stop flash (brief fade-in/out)
|
|
color: "#00FF00" # different color for completion
|
|
width: 4
|
|
opacity: 0.85
|
|
duration: 1.5 # flash duration in seconds
|
|
sound: "" # no sound by default (Cursor plays its own)
|
|
volume: 0.0
|
|
|
|
flash:
|
|
mode: "screen" # "window", "screen", or "allscreens"
|
|
|
|
# Tools that trigger the pulse + sound (approval mode).
|
|
# Others are silently ignored (e.g., Read, Grep, Glob, Task).
|
|
approval_tools:
|
|
- Shell
|
|
- Write
|
|
- Delete
|
|
|
|
general:
|
|
approval_delay: 2.5 # seconds to wait before pulsing (filters auto-approvals)
|
|
cooldown: 2.0 # minimum seconds between flashes
|
|
```
|
|
|
|
Each mode (`running` and `completed`) has its own color, border style, and sound settings. Set `sound: ""` to disable sound for a particular mode.
|
|
|
|
## Uninstall
|
|
|
|
```bash
|
|
uv run cursor-flasher uninstall
|
|
uv run cursor-flasher stop
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
**Flashing on every tool call (too noisy):**
|
|
- Edit `~/.cursor-flasher/config.yaml` and narrow down `approval_tools` to just `Shell`.
|
|
|
|
**No flash at all:**
|
|
- Check daemon: `uv run cursor-flasher status`
|
|
- Check hooks installed: `ls ~/.cursor/hooks/cursor-flasher-notify.py`
|
|
- Check Cursor Settings → Hooks tab for execution logs
|
|
|
|
**Pulse doesn't stop:**
|
|
- Click the Cursor window to bring it to focus — the pulse auto-dismisses when Cursor is the frontmost app.
|