npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@claude-code-hooks/notification

v0.1.10

Published

Zero-dependency Claude Code hook handler that sends OS-level notifications (macOS, Linux, Windows).

Readme

@claude-code-hooks/notification

Part of the claude-code-hooks monorepo.

Zero-dependency CLI that sends OS-level notifications from Claude Code hooks.

  • macOS: osascript (display notification)
  • Linux: notify-send (libnotify)
  • Windows: PowerShell toast via Windows Runtime types (no external modules)

Falls back to stdout when no GUI environment is detected (SSH, headless, CI).

Install / run

# One-shot via npx (no install needed)
npx --yes @claude-code-hooks/notification@latest --event Stop

# Or install globally
npm install -g @claude-code-hooks/notification
claude-code-hooks-notification --event Stop

CLI options

claude-code-hooks-notification [options]

Options:
  --title <text>     Notification title (default: derived from --event or "Claude Code")
  --message <text>   Notification body  (default: derived from --event or stdin JSON)
  --event <name>     Hook event name (e.g. Stop, Notification, TaskCompleted)
  --dry-run          Build the command but don't execute it (prints JSON to stdout)
  -h, --help         Show this help

Usage as a Claude Code hook

Add to your Claude Code settings.json (global ~/.claude/settings.json or project .claude/settings.json):

Notify on task completion

{
  "hooks": {
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "npx --yes @claude-code-hooks/notification@latest --event Stop",
            "timeout": 8
          }
        ]
      }
    ]
  }
}

Notify on the Notification event

The Notification event fires when Claude wants to get your attention (e.g., waiting for input, task complete). The hook payload includes a message field that gets used automatically:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "npx --yes @claude-code-hooks/notification@latest --event Notification",
            "timeout": 8
          }
        ]
      }
    ]
  }
}

Multiple events

{
  "hooks": {
    "Stop": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "npx --yes @claude-code-hooks/notification@latest --event Stop",
            "timeout": 8
          }
        ]
      }
    ],
    "TaskCompleted": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "npx --yes @claude-code-hooks/notification@latest --event TaskCompleted",
            "timeout": 8
          }
        ]
      }
    ],
    "PostToolUseFailure": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "npx --yes @claude-code-hooks/notification@latest --event PostToolUseFailure",
            "timeout": 8
          }
        ]
      }
    ],
    "Notification": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "npx --yes @claude-code-hooks/notification@latest --event Notification",
            "timeout": 8
          }
        ]
      }
    ]
  }
}

Custom title and message

{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "npx --yes @claude-code-hooks/notification@latest --title 'Claude Ready' --message 'New session started!'",
            "timeout": 8
          }
        ]
      }
    ]
  }
}

Hook event types and matchers

Claude Code supports these hook events. Each event fires with a JSON payload on stdin:

| Event | Matcher applies to | Description | |---|---|---| | SessionStart | — | Session begins | | UserPromptSubmit | — | User submits a prompt | | PreToolUse | tool name | Before a tool is invoked | | PermissionRequest | tool name | Permission dialog shown | | PostToolUse | tool name | After a tool completes | | PostToolUseFailure | tool name | After a tool fails | | Notification | — | Claude wants your attention | | SubagentStart | — | Sub-agent launched | | SubagentStop | — | Sub-agent finished | | Stop | stop reason | Claude stops generating | | TeammateIdle | — | Teammate agent is idle | | TaskCompleted | — | Task is complete | | PreCompact | — | About to compact context | | SessionEnd | — | Session ends |

Matcher patterns

The matcher field in hook config filters when the hook runs:

  • "*" — match all (most common for notifications)
  • "Write" — match only the Write tool (for PreToolUse, PostToolUse, etc.)
  • "Bash" — match only the Bash/shell tool
  • "end_turn" — match the end_turn stop reason (for Stop)

Stdin JSON payload

When invoked as a hook, Claude Code pipes a JSON payload via stdin. Example for a Stop event:

{
  "hook_event_name": "Stop",
  "stop_hook_reason": "end_turn",
  "transcript_messages": []
}

Example for a Notification event:

{
  "hook_event_name": "Notification",
  "message": "I've finished the refactoring. Please review the changes."
}

The CLI automatically extracts hook_event_name, message, and tool_name to build a meaningful notification.

Safety

  • No shell=true: All OS commands use child_process.spawn with explicit argument arrays — no shell interpretation.
  • Input sanitization: Title and message are stripped of control characters and truncated (256 / 1024 chars).
  • Injection prevention: macOS uses AppleScript string escaping. Windows encodes strings as base64 and decodes inside PowerShell, bypassing any escaping issues. Linux passes arguments directly to notify-send.
  • Non-GUI fallback: In SSH/headless/CI environments (no $DISPLAY or $WAYLAND_DISPLAY), the notification is printed to stdout instead.

Platform support

| Platform | Method | Requirements | |----------|--------|-------------| | macOS | osascript | Built-in, no setup needed | | Linux | notify-send | Install libnotify-bin (apt) or libnotify (pacman/dnf). Needs X11 or Wayland. | | Windows | PowerShell toast | Built-in PowerShell 5+. Uses Windows.UI.Notifications WinRT types. | | Other/Headless | stdout | Prints [notification] Title: Message to stdout |

Dry-run

Use --dry-run to inspect what OS command would be executed without actually sending a notification:

claude-code-hooks-notification --event Stop --dry-run

Output (macOS example):

{
  "sent": false,
  "method": "dry-run",
  "command": "osascript",
  "args": ["-e", "display notification \"Claude Code has finished its task.\" with title \"Task Complete\""]
}

Programmatic API

import { sendNotification } from '@claude-code-hooks/notification';

const result = await sendNotification({
  title: 'Build Done',
  message: 'All 42 tests passed.',
  dryRun: false
});

console.log(result);
// { sent: true, method: 'osascript', command: 'osascript', args: [...] }