Skip to content

Commit 7cd7c85

Browse files
committed
release 1.6.9
1 parent e36ea72 commit 7cd7c85

File tree

14 files changed

+647
-45
lines changed

14 files changed

+647
-45
lines changed

README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,19 @@ Desktop notifications for AI coding tools - get alerts when tasks complete or in
1313
<img src="assets/multi-tools-support-02.png" width="48%" alt="All tools enabled"/>
1414
</p>
1515

16-
[![Version](https://img.shields.io/badge/version-1.6.8-blue.svg)](https://github.com/mylee04/code-notify/releases)
16+
[![Version](https://img.shields.io/badge/version-1.6.9-blue.svg)](https://github.com/mylee04/code-notify/releases)
1717
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
1818
[![macOS](https://img.shields.io/badge/macOS-supported-green.svg)](https://www.apple.com/macos)
1919
[![Linux](https://img.shields.io/badge/Linux-supported-green.svg)](https://www.linux.org/)
2020
[![Windows](https://img.shields.io/badge/Windows-supported-green.svg)](https://www.microsoft.com/windows)
2121

2222
---
2323

24-
## What's New in v1.6.8
24+
## What's New in v1.6.9
2525

26-
- **npm is now a first-class install path**: `npm install -g code-notify` now provides `code-notify`, `cn`, and `cnp` on macOS, Linux, and Windows
27-
- **Repeated idle/input alerts are deduped**: repeated `idle_prompt`-style notification events are suppressed so sound playback does not keep firing while Claude stays idle
28-
- **`cn update` understands npm installs**: npm users now get the correct `npm install -g code-notify@latest` update path, including on Windows
26+
- **Legacy Claude hooks are repaired during supported upgrades**: stale `claude-notify`-style Claude configs are migrated to the current `code-notify` hook format when users update through the supported install paths
27+
- **Claude idle dedupe now survives upgrades from older installs**: users who were still on the old blank-matcher Claude hooks no longer bypass the repeated `idle_prompt` suppression after updating
28+
- **Codex notify integration now reads Codex payload JSON directly**: completion notifications use Codex's `notify` payload format, and the docs/status output now clearly call out Codex's current completion-focused behavior
2929

3030
---
3131

@@ -60,6 +60,8 @@ cn update
6060
code-notify version
6161
```
6262

63+
If you were using the older `claude-notify` hook layout, supported upgrades now repair those Claude hooks automatically.
64+
6365
**Linux / WSL**
6466

6567
```bash
@@ -129,6 +131,9 @@ Code-Notify uses the hook systems built into AI coding tools:
129131
- **Codex**: `~/.codex/config.toml`
130132
- **Gemini CLI**: `~/.gemini/settings.json`
131133

134+
For Codex, Code-Notify configures `notify = ["/absolute/path/to/notifier.sh", "codex"]` and reads the JSON payload Codex appends on completion.
135+
Codex currently exposes completion events through `notify`; approval and `request_permissions` prompts do not currently arrive through this hook.
136+
132137
When enabled, it adds hooks that call the notification script when tasks complete:
133138

134139
```json
@@ -172,6 +177,8 @@ cn alerts reset # Back to default (idle_prompt only)
172177
| `auth_success` | Authentication success |
173178
| `elicitation_dialog` | MCP tool input needed |
174179

180+
Alert-type matching currently applies to Claude Code and Gemini CLI notification hooks. Codex currently uses completion events from `notify`, so `permission_prompt` and `idle_prompt` settings do not change Codex behavior.
181+
175182
## Troubleshooting
176183

177184
**Command not found?**

bin/code-notify

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
set -e
77

88
# Version
9-
VERSION="1.6.8"
9+
VERSION="1.6.9"
1010

1111
# Determine the directory where the script is located (resolve symlinks)
1212
SCRIPT_PATH="${BASH_SOURCE[0]}"
@@ -52,6 +52,10 @@ case "$COMMAND_NAME" in
5252
source "$LIB_DIR/commands/global.sh"
5353
handle_global_command "$@"
5454
;;
55+
"repair-hooks")
56+
shift
57+
repair_legacy_hooks_command "${1:-}"
58+
;;
5559
*)
5660
error "Unknown command: $1"
5761
echo "Try 'cn help' for usage"
@@ -73,6 +77,10 @@ case "$COMMAND_NAME" in
7377
source "$LIB_DIR/commands/global.sh"
7478
handle_global_command "$@"
7579
;;
80+
"repair-hooks")
81+
shift
82+
repair_legacy_hooks_command "${1:-}"
83+
;;
7684
"project")
7785
shift
7886
source "$LIB_DIR/commands/project.sh"

docs/installation.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
55
## Quick Overview
66

7-
Code-Notify adds desktop notifications to Claude Code. You'll get alerts when:
7+
Code-Notify adds desktop notifications to Claude Code, Codex, and Gemini CLI. You'll get alerts when:
88

99
- Tasks complete
10-
- Claude needs your input
10+
- Claude or Gemini needs your input
1111
- Voice announcements (macOS)
1212

13+
Codex currently exposes completion notifications through its `notify` hook. Approval and `request_permissions` prompts do not currently trigger Code-Notify through Codex.
14+
15+
Supported upgrade paths also repair stale `claude-notify`-style Claude hooks automatically when they are detected.
16+
1317
## For LLM Agents
1418

1519
Execute these commands to install code-notify:

lib/code-notify/commands/global.sh

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -387,6 +387,7 @@ enable_notifications_global() {
387387
enable_single_tool() {
388388
local tool="$1"
389389
local quiet="${2:-}"
390+
local needs_repair=1
390391

391392
# Check if tool is installed
392393
if ! is_tool_installed "$tool"; then
@@ -396,8 +397,12 @@ enable_single_tool() {
396397
return 1
397398
fi
398399

400+
if [[ "$tool" == "claude" ]] && claude_global_hooks_need_repair; then
401+
needs_repair=0
402+
fi
403+
399404
# Check if already enabled
400-
if is_tool_enabled "$tool"; then
405+
if [[ $needs_repair -ne 0 ]] && is_tool_enabled "$tool"; then
401406
if [[ "$quiet" != "quiet" ]]; then
402407
warning "$tool notifications already enabled"
403408
fi
@@ -406,7 +411,11 @@ enable_single_tool() {
406411

407412
# Enable the tool
408413
if [[ "$quiet" != "quiet" ]]; then
409-
info "Enabling $tool notifications..."
414+
if [[ "$tool" == "claude" ]] && [[ $needs_repair -eq 0 ]]; then
415+
info "Repairing existing $tool notification hooks..."
416+
else
417+
info "Enabling $tool notifications..."
418+
fi
410419
fi
411420

412421
if ! enable_tool "$tool"; then
@@ -519,7 +528,12 @@ show_status() {
519528

520529
# Claude Code
521530
if is_tool_installed "claude"; then
522-
if is_tool_enabled "claude"; then
531+
if claude_global_hooks_need_repair; then
532+
echo " ${WARNING} Claude Code: ${YELLOW}REPAIR NEEDED${RESET}"
533+
echo " Config: $GLOBAL_SETTINGS_FILE"
534+
echo " Current hooks still point to an older claude-notify-style configuration"
535+
echo " Run: ${CYAN}cn on claude${RESET}"
536+
elif is_tool_enabled "claude"; then
523537
echo " ${CHECK_MARK} Claude Code: ${GREEN}ENABLED${RESET}"
524538
echo " Config: $GLOBAL_SETTINGS_FILE"
525539
else
@@ -534,6 +548,7 @@ show_status() {
534548
if is_tool_enabled "codex"; then
535549
echo " ${CHECK_MARK} Codex: ${GREEN}ENABLED${RESET}"
536550
echo " Config: $CODEX_CONFIG_FILE"
551+
echo " Events: completion-only via Codex notify payloads"
537552
else
538553
echo " ${MUTE} Codex: ${DIM}DISABLED${RESET}"
539554
fi
@@ -984,6 +999,9 @@ show_alerts_status() {
984999
echo " ${CYAN}cn alerts remove permission_prompt${RESET} # Stop permission notifications"
9851000
echo " ${CYAN}cn alerts reset${RESET} # Back to idle_prompt only"
9861001
echo ""
1002+
dim "Alert-type matching currently applies to Claude Code and Gemini CLI hooks."
1003+
dim "Codex currently exposes completion events through notify, so permission_prompt/idle_prompt settings do not change Codex behavior."
1004+
echo ""
9871005
dim "After changing, run 'cn on' to apply the new settings."
9881006
}
9891007

lib/code-notify/core/config.sh

Lines changed: 111 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,115 @@ has_claude_notify_hooks() {
239239
json_has "$file" '(.hooks.Notification != null) or (.hooks.Stop != null)' '"(Notification|Stop)"'
240240
}
241241

242+
get_global_claude_notify_command() {
243+
printf '%s notification claude\n' "$(get_notify_script)"
244+
}
245+
246+
get_global_claude_stop_command() {
247+
printf '%s stop claude\n' "$(get_notify_script)"
248+
}
249+
250+
has_current_global_claude_hooks() {
251+
local file="$1"
252+
local matcher notify_cmd stop_cmd
253+
254+
if [[ ! -f "$file" ]]; then
255+
return 1
256+
fi
257+
258+
matcher=$(get_notify_matcher)
259+
notify_cmd=$(get_global_claude_notify_command)
260+
stop_cmd=$(get_global_claude_stop_command)
261+
262+
if has_jq; then
263+
jq -e \
264+
--arg matcher "$matcher" \
265+
--arg notify "$notify_cmd" \
266+
--arg stop "$stop_cmd" \
267+
'
268+
(.hooks.Notification | type == "array" and length > 0) and
269+
(.hooks.Stop | type == "array" and length > 0) and
270+
.hooks.Notification[0].matcher == $matcher and
271+
.hooks.Notification[0].hooks[0].type == "command" and
272+
.hooks.Notification[0].hooks[0].command == $notify and
273+
.hooks.Stop[0].matcher == "" and
274+
.hooks.Stop[0].hooks[0].type == "command" and
275+
.hooks.Stop[0].hooks[0].command == $stop
276+
' "$file" >/dev/null 2>&1
277+
return $?
278+
fi
279+
280+
if has_python3; then
281+
python3 - "$file" "$matcher" "$notify_cmd" "$stop_cmd" << 'PYTHON'
282+
import json
283+
import sys
284+
285+
file_path, matcher, notify_cmd, stop_cmd = sys.argv[1:5]
286+
287+
with open(file_path, "r") as fh:
288+
settings = json.load(fh)
289+
290+
notification = settings.get("hooks", {}).get("Notification", [])
291+
stop = settings.get("hooks", {}).get("Stop", [])
292+
293+
assert isinstance(notification, list) and notification
294+
assert isinstance(stop, list) and stop
295+
assert notification[0].get("matcher", "") == matcher
296+
assert notification[0].get("hooks", [{}])[0].get("type") == "command"
297+
assert notification[0].get("hooks", [{}])[0].get("command") == notify_cmd
298+
assert stop[0].get("matcher", "") == ""
299+
assert stop[0].get("hooks", [{}])[0].get("type") == "command"
300+
assert stop[0].get("hooks", [{}])[0].get("command") == stop_cmd
301+
PYTHON
302+
return $?
303+
fi
304+
305+
grep -qF "\"matcher\": \"$matcher\"" "$file" &&
306+
grep -qF "\"command\": \"$notify_cmd\"" "$file" &&
307+
grep -qF "\"command\": \"$stop_cmd\"" "$file"
308+
}
309+
310+
has_legacy_global_claude_hooks() {
311+
local file="${1:-$GLOBAL_SETTINGS_FILE}"
312+
313+
if [[ ! -f "$file" ]]; then
314+
return 1
315+
fi
316+
317+
grep -q 'claude-notify' "$file" ||
318+
grep -qE 'notifier\.sh (notification|stop)"' "$file" ||
319+
grep -q 'notifier.sh PreToolUse' "$file"
320+
}
321+
322+
claude_global_hooks_need_repair() {
323+
has_legacy_global_claude_hooks "$GLOBAL_SETTINGS_FILE"
324+
}
325+
326+
repair_legacy_hooks_command() {
327+
local quiet="${1:-}"
328+
local repaired=0
329+
330+
if claude_global_hooks_need_repair; then
331+
if ! enable_hooks_in_settings; then
332+
if [[ "$quiet" != "--quiet" ]]; then
333+
echo "Failed to repair legacy Claude hooks" >&2
334+
fi
335+
return 1
336+
fi
337+
repaired=1
338+
339+
if [[ "$quiet" != "--quiet" ]]; then
340+
echo "Repaired legacy Claude hooks in $GLOBAL_SETTINGS_FILE"
341+
fi
342+
fi
343+
344+
if [[ $repaired -eq 0 ]] && [[ "$quiet" != "--quiet" ]]; then
345+
echo "No legacy hooks required repair"
346+
fi
347+
348+
return 0
349+
}
350+
242351
# Check if file has any hooks
243352
has_any_hooks() {
244353
local file="$1"
@@ -686,7 +795,7 @@ enable_codex_hooks() {
686795
mkdir -p "$CODEX_HOME"
687796

688797
escaped_notify_script=$(toml_escape_string "$notify_script")
689-
notify_line="notify = [\"bash\", \"-c\", \"$escaped_notify_script stop codex\"]"
798+
notify_line="notify = [\"$escaped_notify_script\", \"codex\"]"
690799

691800
# Check if config.toml exists
692801
if [[ -f "$CODEX_CONFIG_FILE" ]]; then
@@ -701,7 +810,7 @@ enable_codex_hooks() {
701810
# https://developers.openai.com/codex/config-reference/
702811
703812
# Code-Notify: Desktop notifications
704-
notify = ["bash", "-c", "$escaped_notify_script stop codex"]
813+
notify = ["$escaped_notify_script", "codex"]
705814
EOF
706815
fi
707816
}

0 commit comments

Comments
 (0)