Tidy repo for public release

- 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
This commit is contained in:
cottongin
2026-03-10 08:03:22 -04:00
parent d71bac7b93
commit eefb908268
7 changed files with 32 additions and 1489 deletions

2
.gitignore vendored
View File

@@ -8,7 +8,7 @@ build/
.venv/ .venv/
a11y_dump.txt a11y_dump.txt
agent-tools/ agent-tools/
.pytest_cache/
.cursor/ .cursor/
docs/
chat-summaries/ chat-summaries/

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 cottongin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,6 +1,6 @@
# cursor-flasher # cursor-flasher
Flash a colored border on the Cursor IDE window when the AI agent needs your attention — tool approval, questions, or task completion. 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 ## How It Works
@@ -16,13 +16,14 @@ Only tools in the `approval_tools` list trigger the pulse (default: `Shell`, `Wr
- macOS - macOS
- [uv](https://docs.astral.sh/uv/) - [uv](https://docs.astral.sh/uv/)
- Cursor IDE - Cursor IDE
- Accessibility permission for your terminal (System Settings → Privacy & Security → Accessibility) - **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 ## Installation
```bash ```bash
# Clone and install # Clone and install
git clone <repo-url> && cd cursor-flasher git clone https://code.cottongin.xyz/cursor-flasher && cd cursor-flasher
uv sync uv sync
# Install Cursor hooks (global, applies to all projects) # Install Cursor hooks (global, applies to all projects)

View File

@@ -1,102 +0,0 @@
# Cursor Flasher — Design Document
**Date:** 2026-03-10
**Status:** Approved
## Problem
When Cursor's AI agent finishes its turn and is waiting for user input (approval, answering a question, or continuing the conversation), there's no visual or audible signal. The user has to keep checking the window manually.
## Solution
A macOS background daemon that monitors Cursor's accessibility tree and displays a pulsing border overlay around the Cursor window when the agent is waiting for user input. Optionally plays a system sound.
## Architecture
### Detection: Accessibility Tree Polling
A Python process using `pyobjc` polls Cursor's accessibility tree every ~500ms via `AXUIElement` APIs.
**Detection signals:**
- **Approval needed:** Accept/Reject button elements appear in the a11y tree
- **Agent turn complete:** Stop/Cancel button disappears, or thinking indicator goes away
- **Chat input active:** Chat text area becomes the focused element after being inactive
**State machine:**
- `IDLE` — not monitoring (Cursor not in chat or not running)
- `AGENT_WORKING` — agent is generating (Stop button visible, thinking indicator present)
- `WAITING_FOR_USER` — agent is done, user hasn't interacted yet → **trigger flash**
- `USER_INTERACTING` — user started typing/clicking → dismiss flash, return to IDLE
The detection heuristics will be tuned during development after dumping Cursor's full a11y tree.
### Visual Effect: Native macOS Overlay
- A borderless, transparent, non-interactive `NSWindow` positioned over Cursor's window frame
- Draws only a pulsing border (interior is fully click-through)
- Core Animation drives the pulse: opacity oscillates between configurable min/max
- Default: ~4px amber border, 1.5s cycle
**Dismissal triggers:**
- Keyboard input to Cursor (via accessibility or `CGEventTap`)
- Mouse click in Cursor's chat area
- Timeout (default 5 minutes)
- Agent starts working again (Stop button reappears)
### Sound
On transition to `WAITING_FOR_USER`, optionally plays a macOS system sound (default: "Glass"). Configurable sound name, volume, and on/off toggle.
### Configuration
File: `~/.cursor-flasher/config.yaml`
```yaml
pulse:
color: "#FF9500"
width: 4
speed: 1.5
opacity_min: 0.3
opacity_max: 1.0
sound:
enabled: true
name: "Glass"
volume: 0.5
detection:
poll_interval: 0.5
cooldown: 3.0
timeout:
auto_dismiss: 300
```
### Process Management
- CLI: `cursor-flasher start`, `cursor-flasher stop`, `cursor-flasher status`
- Runs as a background daemon
- No menu bar icon (MVP scope)
## Tech Stack
- Python 3.10+
- `pyobjc-framework-Cocoa` — NSWindow, NSApplication, Core Animation
- `pyobjc-framework-Quartz` — AXUIElement, CGEventTap, window management
- `PyYAML` — configuration file parsing
## Installation
- `pip install -e .` from the project directory
- Requires Accessibility permission: System Settings > Privacy & Security > Accessibility (grant to Terminal or Python)
## Scope / Non-goals
- **In scope:** Detection, overlay, sound, CLI, config file
- **Not in scope (MVP):** Menu bar icon, auto-start on login, multi-monitor awareness, Linux/Windows support
## Risks
- **A11y tree fragility:** Cursor UI updates could change element names/structure, breaking detection. Mitigation: make detection patterns configurable, log warnings on detection failures.
- **Accessibility permissions:** Users must grant permission manually. Mitigation: clear error message and instructions on first run.
- **Performance:** Polling a11y tree every 500ms could have CPU cost. Mitigation: only poll when Cursor is the frontmost app or recently active.

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,9 @@ build-backend = "setuptools.build_meta"
name = "cursor-flasher" name = "cursor-flasher"
version = "0.2.0" version = "0.2.0"
description = "Flash Cursor's window when the AI agent needs attention" description = "Flash Cursor's window when the AI agent needs attention"
readme = "README.md"
license = "MIT"
authors = [{ name = "cottongin" }]
requires-python = ">=3.10" requires-python = ">=3.10"
dependencies = [ dependencies = [
"pyobjc-framework-applicationservices>=12.1", "pyobjc-framework-applicationservices>=12.1",
@@ -17,6 +20,9 @@ dependencies = [
[project.optional-dependencies] [project.optional-dependencies]
dev = ["pytest", "pytest-mock"] dev = ["pytest", "pytest-mock"]
[project.urls]
Repository = "https://code.cottongin.xyz/cursor-flasher"
[project.scripts] [project.scripts]
cursor-flasher = "cursor_flasher.cli:main" cursor-flasher = "cursor_flasher.cli:main"

View File

@@ -1,6 +0,0 @@
pyobjc-framework-ApplicationServices
pyobjc-framework-Cocoa
pyobjc-framework-Quartz
PyYAML
pytest
pytest-mock