@landienzla/claude-code-notify 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +7 -0
- package/LICENSE +21 -0
- package/README.md +124 -0
- package/bin/cli.js +127 -0
- package/hooks/hooks.json +17 -0
- package/hooks/scripts/notify.sh +56 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Talha (landienzla@gmail.com)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# claude-code-notify
|
|
2
|
+
|
|
3
|
+
Cross-platform desktop notifications for [Claude Code](https://docs.anthropic.com/en/docs/claude-code). Get notified when Claude Code needs your attention — permission approval, task completion, idle prompts, and more.
|
|
4
|
+
|
|
5
|
+
Works as a **Claude Code plugin** (zero config) or as a **CLI setup tool**.
|
|
6
|
+
|
|
7
|
+
## Platforms
|
|
8
|
+
|
|
9
|
+
| Platform | Method | Sound |
|
|
10
|
+
|----------|--------|-------|
|
|
11
|
+
| Windows | Toast notification (slides in from right) | Silent |
|
|
12
|
+
| macOS | Native notification center | Default |
|
|
13
|
+
| Linux | `notify-send` (libnotify) | Default |
|
|
14
|
+
| WSL | Windows toast via PowerShell | Silent |
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx @landienzla/claude-code-notify setup
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Done. Restart Claude Code and you'll get desktop notifications.
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
### Option 1: CLI Setup
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx @landienzla/claude-code-notify setup
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
This installs the notification script to `~/.claude/scripts/` and adds a `Notification` hook to `~/.claude/settings.json`. Your existing settings are preserved.
|
|
33
|
+
|
|
34
|
+
### Option 2: Plugin Mode
|
|
35
|
+
|
|
36
|
+
Install globally:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install -g @landienzla/claude-code-notify
|
|
40
|
+
claude --plugin-dir $(npm root -g)/@landienzla/claude-code-notify
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Or per-project:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npm install @landienzla/claude-code-notify
|
|
47
|
+
claude --plugin-dir ./node_modules/@landienzla/claude-code-notify
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Plugin mode requires no changes to your `settings.json` — the hook is loaded automatically via the plugin system.
|
|
51
|
+
|
|
52
|
+
## CLI Commands
|
|
53
|
+
|
|
54
|
+
| Command | Description |
|
|
55
|
+
|---------|-------------|
|
|
56
|
+
| `claude-code-notify setup` | Install notification hook into `~/.claude/` |
|
|
57
|
+
| `claude-code-notify test` | Send a test notification |
|
|
58
|
+
| `claude-code-notify uninstall` | Remove notification hook and script |
|
|
59
|
+
| `claude-code-notify help` | Show usage info |
|
|
60
|
+
|
|
61
|
+
## How It Works
|
|
62
|
+
|
|
63
|
+
Claude Code fires a [`Notification`](https://docs.anthropic.com/en/docs/claude-code/hooks) hook whenever it needs your attention. This package provides a handler that:
|
|
64
|
+
|
|
65
|
+
1. Reads the notification context (JSON via stdin)
|
|
66
|
+
2. Extracts the message (e.g. "Waiting for permission to edit file.py")
|
|
67
|
+
3. Detects your OS
|
|
68
|
+
4. Sends a native desktop notification with the contextual message
|
|
69
|
+
|
|
70
|
+
### Notification Events
|
|
71
|
+
|
|
72
|
+
The hook fires on all notification types:
|
|
73
|
+
|
|
74
|
+
- **Permission prompts** — Claude needs approval to run a tool
|
|
75
|
+
- **Idle prompts** — Claude is done and waiting for input
|
|
76
|
+
- **Auth events** — Authentication completed
|
|
77
|
+
- **Elicitation dialogs** — Claude is asking a question
|
|
78
|
+
|
|
79
|
+
## Requirements
|
|
80
|
+
|
|
81
|
+
- **Python 3** — used for JSON parsing (available by default on macOS/Linux)
|
|
82
|
+
- **Linux:** `libnotify-bin` for `notify-send`
|
|
83
|
+
```bash
|
|
84
|
+
# Debian/Ubuntu
|
|
85
|
+
sudo apt install libnotify-bin
|
|
86
|
+
|
|
87
|
+
# Fedora
|
|
88
|
+
sudo dnf install libnotify
|
|
89
|
+
|
|
90
|
+
# Arch
|
|
91
|
+
sudo pacman -S libnotify
|
|
92
|
+
```
|
|
93
|
+
- **macOS:** Your terminal app may need notification permission in System Settings > Notifications
|
|
94
|
+
- **Windows/WSL:** PowerShell (included with Windows)
|
|
95
|
+
|
|
96
|
+
## Uninstall
|
|
97
|
+
|
|
98
|
+
**CLI mode:**
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npx @landienzla/claude-code-notify uninstall
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**Plugin mode:** Remove the `--plugin-dir` flag from your Claude Code command.
|
|
105
|
+
|
|
106
|
+
## Troubleshooting
|
|
107
|
+
|
|
108
|
+
**Notifications not appearing on Windows/WSL:**
|
|
109
|
+
- Ensure Focus Assist / Do Not Disturb is off
|
|
110
|
+
- Check Windows Settings > System > Notifications
|
|
111
|
+
|
|
112
|
+
**Notifications not appearing on macOS:**
|
|
113
|
+
- Go to System Settings > Notifications > [Your Terminal App] > Allow Notifications
|
|
114
|
+
|
|
115
|
+
**Notifications not appearing on Linux:**
|
|
116
|
+
- Install `libnotify-bin` (see Requirements)
|
|
117
|
+
- Ensure a notification daemon is running (e.g. `dunst`, `mako`, GNOME/KDE built-in)
|
|
118
|
+
|
|
119
|
+
**Generic "Needs your attention" message instead of context:**
|
|
120
|
+
- Ensure Python 3 is installed and on your PATH
|
|
121
|
+
|
|
122
|
+
## License
|
|
123
|
+
|
|
124
|
+
[MIT](LICENSE)
|
package/bin/cli.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const os = require('os');
|
|
6
|
+
const { execSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
const CLAUDE_DIR = path.join(os.homedir(), '.claude');
|
|
9
|
+
const SETTINGS_PATH = path.join(CLAUDE_DIR, 'settings.json');
|
|
10
|
+
const SCRIPTS_DIR = path.join(CLAUDE_DIR, 'scripts');
|
|
11
|
+
const NOTIFY_DEST = path.join(SCRIPTS_DIR, 'notify.sh');
|
|
12
|
+
|
|
13
|
+
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
14
|
+
const NOTIFY_SRC = path.join(PACKAGE_ROOT, 'hooks', 'scripts', 'notify.sh');
|
|
15
|
+
|
|
16
|
+
const HOOK_CONFIG = {
|
|
17
|
+
Notification: [
|
|
18
|
+
{
|
|
19
|
+
matcher: '',
|
|
20
|
+
hooks: [
|
|
21
|
+
{
|
|
22
|
+
type: 'command',
|
|
23
|
+
command: `bash "${NOTIFY_DEST.replace(/\\/g, '/')}"`,
|
|
24
|
+
timeout: 10
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
function setup() {
|
|
32
|
+
if (!fs.existsSync(CLAUDE_DIR)) {
|
|
33
|
+
console.error(`Error: ${CLAUDE_DIR} does not exist. Is Claude Code installed?`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Copy notify.sh
|
|
38
|
+
fs.mkdirSync(SCRIPTS_DIR, { recursive: true });
|
|
39
|
+
fs.copyFileSync(NOTIFY_SRC, NOTIFY_DEST);
|
|
40
|
+
fs.chmodSync(NOTIFY_DEST, 0o755);
|
|
41
|
+
console.log(` Copied notify.sh -> ${NOTIFY_DEST}`);
|
|
42
|
+
|
|
43
|
+
// Merge hook into settings.json
|
|
44
|
+
let settings = {};
|
|
45
|
+
if (fs.existsSync(SETTINGS_PATH)) {
|
|
46
|
+
try {
|
|
47
|
+
settings = JSON.parse(fs.readFileSync(SETTINGS_PATH, 'utf8'));
|
|
48
|
+
} catch (e) {
|
|
49
|
+
const backup = SETTINGS_PATH + '.backup.' + Date.now();
|
|
50
|
+
fs.copyFileSync(SETTINGS_PATH, backup);
|
|
51
|
+
console.log(` Warning: settings.json was invalid, backup saved to ${backup}`);
|
|
52
|
+
settings = {};
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!settings.hooks) settings.hooks = {};
|
|
57
|
+
settings.hooks.Notification = HOOK_CONFIG.Notification;
|
|
58
|
+
|
|
59
|
+
fs.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + '\n');
|
|
60
|
+
console.log(` Updated ${SETTINGS_PATH}`);
|
|
61
|
+
|
|
62
|
+
console.log('\nDone! Restart Claude Code for notifications to take effect.');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function uninstall() {
|
|
66
|
+
if (fs.existsSync(SETTINGS_PATH)) {
|
|
67
|
+
try {
|
|
68
|
+
const settings = JSON.parse(fs.readFileSync(SETTINGS_PATH, 'utf8'));
|
|
69
|
+
if (settings.hooks && settings.hooks.Notification) {
|
|
70
|
+
delete settings.hooks.Notification;
|
|
71
|
+
if (Object.keys(settings.hooks).length === 0) delete settings.hooks;
|
|
72
|
+
fs.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + '\n');
|
|
73
|
+
console.log(` Removed Notification hook from ${SETTINGS_PATH}`);
|
|
74
|
+
} else {
|
|
75
|
+
console.log(' No Notification hook found in settings.');
|
|
76
|
+
}
|
|
77
|
+
} catch (e) {
|
|
78
|
+
console.error(` Error reading ${SETTINGS_PATH}: ${e.message}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (fs.existsSync(NOTIFY_DEST)) {
|
|
83
|
+
fs.unlinkSync(NOTIFY_DEST);
|
|
84
|
+
console.log(` Removed ${NOTIFY_DEST}`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log('\nDone! Restart Claude Code to apply changes.');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function test() {
|
|
91
|
+
const input = JSON.stringify({ notification_message: 'Test notification from claude-code-notify' });
|
|
92
|
+
try {
|
|
93
|
+
execSync(`echo '${input}' | bash "${NOTIFY_SRC}"`, { stdio: 'inherit', timeout: 15000 });
|
|
94
|
+
console.log('Test notification sent!');
|
|
95
|
+
} catch (e) {
|
|
96
|
+
console.error('Test failed:', e.message);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function help() {
|
|
102
|
+
console.log(`
|
|
103
|
+
claude-code-notify - Desktop notifications for Claude Code
|
|
104
|
+
|
|
105
|
+
Usage:
|
|
106
|
+
claude-code-notify setup Install notification hook into ~/.claude/
|
|
107
|
+
claude-code-notify uninstall Remove notification hook from ~/.claude/
|
|
108
|
+
claude-code-notify test Send a test notification
|
|
109
|
+
claude-code-notify help Show this help
|
|
110
|
+
|
|
111
|
+
Plugin mode (no setup needed):
|
|
112
|
+
claude --plugin-dir /path/to/node_modules/claude-code-notify
|
|
113
|
+
`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const command = process.argv[2];
|
|
117
|
+
|
|
118
|
+
switch (command) {
|
|
119
|
+
case 'setup': setup(); break;
|
|
120
|
+
case 'uninstall': uninstall(); break;
|
|
121
|
+
case 'test': test(); break;
|
|
122
|
+
case 'help': case '--help': case '-h': case undefined: help(); break;
|
|
123
|
+
default:
|
|
124
|
+
console.error(`Unknown command: ${command}`);
|
|
125
|
+
help();
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
package/hooks/hooks.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Desktop notification hook — sends native OS notifications when Claude Code needs attention",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"Notification": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "bash \"${CLAUDE_PLUGIN_ROOT}/hooks/scripts/notify.sh\"",
|
|
11
|
+
"timeout": 10
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Cross-platform desktop notification for Claude Code
|
|
3
|
+
# Reads hook JSON from stdin, extracts notification message, sends native OS notification
|
|
4
|
+
|
|
5
|
+
INPUT=$(cat)
|
|
6
|
+
|
|
7
|
+
# Parse JSON with python3 to extract the notification message
|
|
8
|
+
MESSAGE=$(echo "$INPUT" | python3 -c "
|
|
9
|
+
import sys, json
|
|
10
|
+
data = json.load(sys.stdin)
|
|
11
|
+
message = data.get('notification_message', data.get('message', 'Needs your attention'))
|
|
12
|
+
for old, new in [('&','&'),('<','<'),('>','>'),('\"','"')]:
|
|
13
|
+
message = message.replace(old, new)
|
|
14
|
+
print(message)
|
|
15
|
+
" 2>/dev/null)
|
|
16
|
+
|
|
17
|
+
# Fallback if python3 parsing fails
|
|
18
|
+
MESSAGE="${MESSAGE:-Needs your attention}"
|
|
19
|
+
|
|
20
|
+
# Detect OS and send notification
|
|
21
|
+
case "$(uname -s)" in
|
|
22
|
+
Linux*)
|
|
23
|
+
if grep -qi microsoft /proc/version 2>/dev/null; then
|
|
24
|
+
# WSL — use Windows toast notification
|
|
25
|
+
powershell.exe -Command "
|
|
26
|
+
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > \$null
|
|
27
|
+
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] > \$null
|
|
28
|
+
\$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
|
|
29
|
+
\$xml.LoadXml('<toast><visual><binding template=\"ToastText01\"><text id=\"1\">$MESSAGE</text></binding></visual><audio silent=\"true\"/></toast>')
|
|
30
|
+
\$toast = New-Object Windows.UI.Notifications.ToastNotification \$xml
|
|
31
|
+
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('Claude Code').Show(\$toast)
|
|
32
|
+
" 2>/dev/null
|
|
33
|
+
else
|
|
34
|
+
# Native Linux
|
|
35
|
+
notify-send "Claude Code" "$MESSAGE" --app-name="Claude Code" 2>/dev/null || true
|
|
36
|
+
fi
|
|
37
|
+
;;
|
|
38
|
+
Darwin*)
|
|
39
|
+
# macOS
|
|
40
|
+
ESCAPED=$(echo "$MESSAGE" | sed 's/\\/\\\\/g; s/"/\\"/g')
|
|
41
|
+
osascript -e "display notification \"$ESCAPED\" with title \"Claude Code\"" 2>/dev/null || true
|
|
42
|
+
;;
|
|
43
|
+
CYGWIN*|MINGW*|MSYS*)
|
|
44
|
+
# Native Windows (Git Bash / MSYS2)
|
|
45
|
+
powershell.exe -Command "
|
|
46
|
+
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > \$null
|
|
47
|
+
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] > \$null
|
|
48
|
+
\$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
|
|
49
|
+
\$xml.LoadXml('<toast><visual><binding template=\"ToastText01\"><text id=\"1\">$MESSAGE</text></binding></visual><audio silent=\"true\"/></toast>')
|
|
50
|
+
\$toast = New-Object Windows.UI.Notifications.ToastNotification \$xml
|
|
51
|
+
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('Claude Code').Show(\$toast)
|
|
52
|
+
" 2>/dev/null
|
|
53
|
+
;;
|
|
54
|
+
esac
|
|
55
|
+
|
|
56
|
+
exit 0
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@landienzla/claude-code-notify",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cross-platform desktop notifications for Claude Code — plugin and CLI setup tool",
|
|
5
|
+
"author": "Talha <landienzla@gmail.com>",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/landienzla/claude-code-notify"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/landienzla/claude-code-notify/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/landienzla/claude-code-notify#readme",
|
|
15
|
+
"bin": {
|
|
16
|
+
"claude-code-notify": "./bin/cli.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
".claude-plugin/",
|
|
20
|
+
"hooks/",
|
|
21
|
+
"bin/",
|
|
22
|
+
"README.md",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [
|
|
26
|
+
"claude-code",
|
|
27
|
+
"claude",
|
|
28
|
+
"plugin",
|
|
29
|
+
"notifications",
|
|
30
|
+
"desktop-notifications",
|
|
31
|
+
"hooks",
|
|
32
|
+
"toast",
|
|
33
|
+
"macos",
|
|
34
|
+
"windows",
|
|
35
|
+
"linux",
|
|
36
|
+
"wsl"
|
|
37
|
+
]
|
|
38
|
+
}
|