Disable shell execution hooks to fix broken notifications

beforeShellExecution in hooks.json required a JSON response we never
provided, likely causing Cursor to silently break the entire hook
pipeline. Commenting out those entries (and afterShellExecution) from
HOOKS_CONFIG restores reliable preToolUse/postToolUse delivery. All
Python handler code is retained as dead code for reference.

Also reverts the is_cursor_frontmost() gate in _check_pending — pulses
should fire unconditionally when the approval delay expires.

Made-with: Cursor
This commit is contained in:
cottongin
2026-03-11 15:24:43 -04:00
parent 6610919a58
commit 392183692e
5 changed files with 156 additions and 6 deletions

View File

@@ -1,9 +1,15 @@
#!/usr/bin/env python3
"""Cursor hook script that notifies the cursor-flasher daemon via Unix socket.
Installed as a Cursor hook (preToolUse, stop) to trigger a window flash
when the agent needs user attention. Reads hook JSON from stdin, extracts
workspace and event info, and sends it to the daemon's socket.
Installed as a Cursor hook to trigger a window flash when the agent needs
user attention. Reads hook JSON from stdin, extracts workspace and event
info, and sends it to the daemon's socket.
Shell-specific hook mapping (beforeShellExecution -> shellApproved,
afterShellExecution -> shellCompleted) is retained but currently dead
code — those hooks are disabled in HOOKS_CONFIG / hooks.json because
beforeShellExecution fires pre-approval and Cursor expects a JSON
response we don't provide.
"""
import json
import os
@@ -12,6 +18,11 @@ import sys
SOCKET_PATH = os.path.expanduser("~/.cursor-flasher/flasher.sock")
_SHELL_EVENT_MAP = {
"beforeShellExecution": "shellApproved",
"afterShellExecution": "shellCompleted",
}
def main() -> None:
try:
@@ -22,9 +33,13 @@ def main() -> None:
workspace_roots = data.get("workspace_roots") or []
workspace = workspace_roots[0] if workspace_roots else ""
event = data.get("hook_event_name", "")
tool = data.get("tool_name", "")
msg = json.dumps({"workspace": workspace, "event": event, "tool": tool})
mapped_event = _SHELL_EVENT_MAP.get(event)
if mapped_event:
msg = json.dumps({"workspace": workspace, "event": mapped_event, "tool": "Shell"})
else:
tool = data.get("tool_name", "")
msg = json.dumps({"workspace": workspace, "event": event, "tool": tool})
try:
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)