52 lines
1.7 KiB
Python
Executable File
52 lines
1.7 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Notification hook: a desktop notification when Claude is waiting on you.
|
|
|
|
settings.json wires it to `idle_prompt|permission_prompt` (the Notification matcher is the
|
|
`notification_type`). Push notifications are off in this setup, so this is the local
|
|
counterpart of pi's notify.ts. Uses notify-send where present (the Wayland/GUI hosts) and
|
|
silently no-ops on a headless box or without a session bus. Payload fields are read
|
|
defensively -- the docs do not pin the Notification input schema: `message`, `title`,
|
|
`notification_type`, `cwd`.
|
|
"""
|
|
import json
|
|
import os
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
|
|
TITLES = {
|
|
"idle_prompt": "Claude Code is waiting for you",
|
|
"permission_prompt": "Claude Code needs a permission",
|
|
}
|
|
|
|
|
|
def main():
|
|
try:
|
|
data = json.load(sys.stdin)
|
|
except Exception:
|
|
return
|
|
exe = shutil.which("notify-send")
|
|
if not exe:
|
|
return
|
|
kind = data.get("notification_type") or "notification"
|
|
title = data.get("title") or TITLES.get(kind, "Claude Code")
|
|
body = (data.get("message") or "").strip() or kind
|
|
cwd = data.get("cwd") or ""
|
|
if cwd:
|
|
home = os.path.expanduser("~")
|
|
body += "\n" + (("~" + cwd[len(home):]) if cwd.startswith(home) else cwd)
|
|
try:
|
|
subprocess.run(
|
|
[exe, "--app-name=Claude Code", "--urgency=normal", "--expire-time=8000",
|
|
# same tag -> a newer notification replaces the previous one instead of stacking
|
|
f"--hint=string:x-canonical-private-synchronous:claude-code-{kind}",
|
|
title, body],
|
|
timeout=5, capture_output=True,
|
|
)
|
|
except Exception:
|
|
pass
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|