@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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "name": "@landienzla/claude-code-notify",
3
+ "version": "1.0.0",
4
+ "description": "Cross-platform desktop notifications when Claude Code needs your attention",
5
+ "license": "MIT",
6
+ "keywords": ["notifications", "desktop", "hooks", "cross-platform"]
7
+ }
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
+ }
@@ -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 [('&','&amp;'),('<','&lt;'),('>','&gt;'),('\"','&quot;')]:
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
+ }