@landienzla/claude-code-notify 1.0.5 → 1.1.2
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/README.md +17 -7
- package/bin/cli.js +40 -22
- package/hooks/scripts/notify.sh +32 -7
- package/package.json +7 -1
package/README.md
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
# claude-code-notify
|
|
2
2
|
|
|
3
|
+
[](https://github.com/Landienzla/claude-code-notify/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@landienzla/claude-code-notify)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
3
7
|
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
8
|
|
|
5
9
|
Works as a **Claude Code plugin** (zero config) or as a **CLI setup tool**.
|
|
6
10
|
|
|
7
11
|
## Platforms
|
|
8
12
|
|
|
9
|
-
| Platform | Method |
|
|
10
|
-
|
|
11
|
-
| Windows | Toast notification (slides in from right) |
|
|
12
|
-
| macOS | Native notification center |
|
|
13
|
-
| Linux | `notify-send` (libnotify) |
|
|
14
|
-
| WSL | Windows toast via PowerShell |
|
|
13
|
+
| Platform | Method |
|
|
14
|
+
|----------|--------|
|
|
15
|
+
| Windows | Toast notification (slides in from right) |
|
|
16
|
+
| macOS | Native notification center |
|
|
17
|
+
| Linux | `notify-send` (libnotify) |
|
|
18
|
+
| WSL | Windows toast via PowerShell |
|
|
19
|
+
|
|
20
|
+
Notifications are **silent by default**. Use `--sound` to enable sound. Use `--name` to give your Claude a name.
|
|
15
21
|
|
|
16
22
|
## Quick Start
|
|
17
23
|
|
|
@@ -53,12 +59,16 @@ Plugin mode requires no changes to your `settings.json` — the hook is loaded a
|
|
|
53
59
|
|
|
54
60
|
| Command | Description |
|
|
55
61
|
|---------|-------------|
|
|
56
|
-
| `claude-code-notify setup` | Install notification hook
|
|
62
|
+
| `claude-code-notify setup` | Install notification hook (silent) |
|
|
63
|
+
| `claude-code-notify setup --sound` | Install with sound enabled |
|
|
64
|
+
| `claude-code-notify setup --name "Jarvis"` | Install with a custom name |
|
|
57
65
|
| `claude-code-notify dry-run` | Preview what setup will change (no writes) |
|
|
58
66
|
| `claude-code-notify test` | Send a test notification |
|
|
59
67
|
| `claude-code-notify uninstall` | Remove notification hook and script |
|
|
60
68
|
| `claude-code-notify help` | Show usage info |
|
|
61
69
|
|
|
70
|
+
Options can be combined: `claude-code-notify setup --sound --name "Jarvis"`
|
|
71
|
+
|
|
62
72
|
Run `dry-run` first to see exactly what files will be created/modified before committing.
|
|
63
73
|
|
|
64
74
|
## How It Works
|
package/bin/cli.js
CHANGED
|
@@ -13,20 +13,30 @@ const NOTIFY_DEST = path.join(SCRIPTS_DIR, 'notify.sh');
|
|
|
13
13
|
const PACKAGE_ROOT = path.resolve(__dirname, '..');
|
|
14
14
|
const NOTIFY_SRC = path.join(PACKAGE_ROOT, 'hooks', 'scripts', 'notify.sh');
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
16
|
+
// Parse flags
|
|
17
|
+
const args = process.argv.slice(3);
|
|
18
|
+
const sound = args.includes('--sound');
|
|
19
|
+
const nameIdx = args.indexOf('--name');
|
|
20
|
+
const name = nameIdx !== -1 && args[nameIdx + 1] ? args[nameIdx + 1] : null;
|
|
21
|
+
const soundFlag = sound ? ' --sound' : '';
|
|
22
|
+
const nameFlag = name ? ` --name "${name}"` : '';
|
|
23
|
+
|
|
24
|
+
function hookConfig() {
|
|
25
|
+
return {
|
|
26
|
+
Notification: [
|
|
27
|
+
{
|
|
28
|
+
matcher: '',
|
|
29
|
+
hooks: [
|
|
30
|
+
{
|
|
31
|
+
type: 'command',
|
|
32
|
+
command: `bash "${NOTIFY_DEST.replace(/\\/g, '/')}"${soundFlag}${nameFlag}`,
|
|
33
|
+
timeout: 10
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
};
|
|
39
|
+
}
|
|
30
40
|
|
|
31
41
|
function dryRun() {
|
|
32
42
|
console.log('Dry run — no changes will be made.\n');
|
|
@@ -36,7 +46,7 @@ function dryRun() {
|
|
|
36
46
|
console.log(` 2. Add Notification hook to:`);
|
|
37
47
|
console.log(` ${SETTINGS_PATH}\n`);
|
|
38
48
|
console.log(' Hook config:');
|
|
39
|
-
console.log(JSON.stringify(
|
|
49
|
+
console.log(JSON.stringify(hookConfig(), null, 2).split('\n').map(l => ' ' + l).join('\n'));
|
|
40
50
|
|
|
41
51
|
if (fs.existsSync(SETTINGS_PATH)) {
|
|
42
52
|
try {
|
|
@@ -82,11 +92,12 @@ function setup() {
|
|
|
82
92
|
}
|
|
83
93
|
|
|
84
94
|
if (!settings.hooks) settings.hooks = {};
|
|
85
|
-
settings.hooks.Notification =
|
|
95
|
+
settings.hooks.Notification = hookConfig().Notification;
|
|
86
96
|
|
|
87
97
|
fs.writeFileSync(SETTINGS_PATH, JSON.stringify(settings, null, 2) + '\n');
|
|
88
98
|
console.log(` Updated ${SETTINGS_PATH}`);
|
|
89
99
|
|
|
100
|
+
if (name) console.log(` Notifications will appear as "${name}".`);
|
|
90
101
|
console.log('\nDone! Restart Claude Code for notifications to take effect.');
|
|
91
102
|
}
|
|
92
103
|
|
|
@@ -119,7 +130,10 @@ function test() {
|
|
|
119
130
|
const input = JSON.stringify({ notification_message: 'Test notification from claude-code-notify' });
|
|
120
131
|
try {
|
|
121
132
|
const { spawnSync } = require('child_process');
|
|
122
|
-
const
|
|
133
|
+
const scriptArgs = [NOTIFY_SRC];
|
|
134
|
+
if (sound) scriptArgs.push('--sound');
|
|
135
|
+
if (name) scriptArgs.push('--name', name);
|
|
136
|
+
const result = spawnSync('bash', scriptArgs, {
|
|
123
137
|
input,
|
|
124
138
|
stdio: ['pipe', 'inherit', 'inherit'],
|
|
125
139
|
timeout: 15000
|
|
@@ -137,11 +151,15 @@ function help() {
|
|
|
137
151
|
claude-code-notify - Desktop notifications for Claude Code
|
|
138
152
|
|
|
139
153
|
Usage:
|
|
140
|
-
claude-code-notify setup
|
|
141
|
-
claude-code-notify dry-run
|
|
142
|
-
claude-code-notify uninstall
|
|
143
|
-
claude-code-notify test
|
|
144
|
-
claude-code-notify help
|
|
154
|
+
claude-code-notify setup [options] Install notification hook into ~/.claude/
|
|
155
|
+
claude-code-notify dry-run [options] Preview what setup will change (no writes)
|
|
156
|
+
claude-code-notify uninstall Remove notification hook from ~/.claude/
|
|
157
|
+
claude-code-notify test [options] Send a test notification
|
|
158
|
+
claude-code-notify help Show this help
|
|
159
|
+
|
|
160
|
+
Options:
|
|
161
|
+
--sound Enable notification sound (default: silent)
|
|
162
|
+
--name <name> Give your Claude a name (e.g. --name "Jarvis")
|
|
145
163
|
|
|
146
164
|
Plugin mode (no setup needed):
|
|
147
165
|
claude --plugin-dir /path/to/node_modules/claude-code-notify
|
package/hooks/scripts/notify.sh
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
# Cross-platform desktop notification for Claude Code
|
|
3
3
|
# Reads hook JSON from stdin, extracts notification message, sends native OS notification
|
|
4
4
|
|
|
5
|
+
# Parse flags
|
|
6
|
+
SILENT=true
|
|
7
|
+
NAME="Claude Code"
|
|
8
|
+
while [ $# -gt 0 ]; do
|
|
9
|
+
case "$1" in
|
|
10
|
+
--sound) SILENT=false ;;
|
|
11
|
+
--silent) SILENT=true ;;
|
|
12
|
+
--name) shift; NAME="$1" ;;
|
|
13
|
+
esac
|
|
14
|
+
shift
|
|
15
|
+
done
|
|
16
|
+
|
|
5
17
|
INPUT=$(cat)
|
|
6
18
|
|
|
7
19
|
# Parse JSON and sanitize for safe shell usage
|
|
@@ -17,9 +29,14 @@ let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{
|
|
|
17
29
|
});
|
|
18
30
|
" 2>/dev/null)
|
|
19
31
|
|
|
20
|
-
# Fallback if python3 parsing fails
|
|
21
32
|
MESSAGE="${MESSAGE:-Needs your attention}"
|
|
22
33
|
|
|
34
|
+
# Build audio XML for Windows toast
|
|
35
|
+
AUDIO_XML=""
|
|
36
|
+
if [ "$SILENT" = true ]; then
|
|
37
|
+
AUDIO_XML='<audio silent="true"/>'
|
|
38
|
+
fi
|
|
39
|
+
|
|
23
40
|
# Detect OS and send notification
|
|
24
41
|
case "$(uname -s)" in
|
|
25
42
|
Linux*)
|
|
@@ -29,18 +46,26 @@ case "$(uname -s)" in
|
|
|
29
46
|
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > \$null
|
|
30
47
|
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] > \$null
|
|
31
48
|
\$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
|
|
32
|
-
\$xml.LoadXml('<toast><visual><binding template=\"ToastText01\"><text id=\"1\">$MESSAGE</text></binding></visual
|
|
49
|
+
\$xml.LoadXml('<toast><visual><binding template=\"ToastText01\"><text id=\"1\">$MESSAGE</text></binding></visual>$AUDIO_XML</toast>')
|
|
33
50
|
\$toast = New-Object Windows.UI.Notifications.ToastNotification \$xml
|
|
34
|
-
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('
|
|
51
|
+
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('$NAME').Show(\$toast)
|
|
35
52
|
" 2>/dev/null
|
|
36
53
|
else
|
|
37
54
|
# Native Linux
|
|
38
|
-
|
|
55
|
+
if [ "$SILENT" = true ]; then
|
|
56
|
+
notify-send "$NAME" "$MESSAGE" --app-name="$NAME" -h string:suppress-sound:true 2>/dev/null || true
|
|
57
|
+
else
|
|
58
|
+
notify-send "$NAME" "$MESSAGE" --app-name="$NAME" 2>/dev/null || true
|
|
59
|
+
fi
|
|
39
60
|
fi
|
|
40
61
|
;;
|
|
41
62
|
Darwin*)
|
|
42
63
|
# macOS
|
|
43
|
-
|
|
64
|
+
if [ "$SILENT" = true ]; then
|
|
65
|
+
osascript -e "display notification \"$MESSAGE\" with title \"$NAME\"" 2>/dev/null || true
|
|
66
|
+
else
|
|
67
|
+
osascript -e "display notification \"$MESSAGE\" with title \"$NAME\" sound name \"default\"" 2>/dev/null || true
|
|
68
|
+
fi
|
|
44
69
|
;;
|
|
45
70
|
CYGWIN*|MINGW*|MSYS*)
|
|
46
71
|
# Native Windows (Git Bash / MSYS2)
|
|
@@ -48,9 +73,9 @@ case "$(uname -s)" in
|
|
|
48
73
|
[Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > \$null
|
|
49
74
|
[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] > \$null
|
|
50
75
|
\$xml = New-Object Windows.Data.Xml.Dom.XmlDocument
|
|
51
|
-
\$xml.LoadXml('<toast><visual><binding template=\"ToastText01\"><text id=\"1\">$MESSAGE</text></binding></visual
|
|
76
|
+
\$xml.LoadXml('<toast><visual><binding template=\"ToastText01\"><text id=\"1\">$MESSAGE</text></binding></visual>$AUDIO_XML</toast>')
|
|
52
77
|
\$toast = New-Object Windows.UI.Notifications.ToastNotification \$xml
|
|
53
|
-
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('
|
|
78
|
+
[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('$NAME').Show(\$toast)
|
|
54
79
|
" 2>/dev/null
|
|
55
80
|
;;
|
|
56
81
|
esac
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@landienzla/claude-code-notify",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Cross-platform desktop notifications for Claude Code — plugin and CLI setup tool",
|
|
5
5
|
"author": "Talha <landienzla@gmail.com>",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "node --test test/cli.test.js test/notify.test.js"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=18"
|
|
11
|
+
},
|
|
6
12
|
"license": "MIT",
|
|
7
13
|
"repository": {
|
|
8
14
|
"type": "git",
|