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

opencode-wsl-notify

v0.1.6

Published

Windows toast notifications for OpenCode (V2) running inside WSL. No Windows-side setup required.

Readme

opencode-wsl-notify

Windows toast notifications for OpenCode (V2) running inside WSL — with no Windows-side setup.

No PowerShell modules to install. No BurntToast. No scripts on the Windows side. Just an npm install.

npm install opencode-wsl-notify

Why this exists

OpenCode runs inside WSL, where process.platform === "linux". Every cross-platform notifier therefore picks a Linux backend (notify-send), which does nothing in WSL without a notification daemon. The usual workarounds ask you to install a PowerShell module or hand-write a bridge script on the Windows side.

This package instead invokes the Windows toast executable that ships inside the npm dependency. WSL can run Windows binaries directly, so nothing needs to be installed on Windows.

It is built against the OpenCode V2 plugin API (@opencode/plugin), not the V1 API, which V2 does not run.


Install

Just add it to your OpenCode config — no npm install needed. OpenCode installs npm plugins itself:

{
  "$schema": "https://opencode.ai/config.json",
  "plugins": ["opencode-wsl-notify"]
}

Restart OpenCode. You should get Windows toasts when a session finishes, errors, or needs permission.

If you prefer to manage the dependency yourself, npm install opencode-wsl-notify in your config directory also works, and local plugins are loaded from ~/.config/opencode/plugins/.

Configuration

Options are passed through the object form of a plugin entry:

{
  "plugins": [
    {
      "package": "opencode-wsl-notify",
      "options": {
        "debug": true,
        "minDuration": 5,
        "appID": "OpenCode",
        "events": {
          "subagent_complete": { "enabled": true },
          "complete": { "message": "{project}" }
        }
      }
    }
  ]
}

| Option | Type | Default | Description | | --- | --- | --- | --- | | executablePath | string | auto | Explicit path to ntfytoast.exe. Linux (/mnt/c/...) or Windows (C:\...) form. | | appID | string | OpenCode | Application name shown above the toast. | | wslOnly | boolean | true | Only notify when running inside WSL. Set false to force on other platforms. | | events | object | see below | Per-event enabled, title, and message. | | minDuration | number | 0 | Skip complete notifications for sessions shorter than this many seconds. | | debug | boolean | false | Log diagnostics to stderr. |

Events

| Event | Default | Fires on | | --- | --- | --- | | complete | on | session.idle / session.execution.succeeded | | error | on | session.execution.failed | | permission | on | permission.asked | | subagent_complete | off | a subagent session finishing |

The toast title names the event; the body carries the project and session:

| Event | Title | Message | | --- | --- | --- | | complete | Session complete | {project}\n{session} | | error | Session error | {project}\n{session} | | permission | Waiting for permission | {project}\n{session} | | subagent_complete | Subagent finished | {project} |

Message placeholders

| Placeholder | Resolves to | | --- | --- | | {project} | Project folder name, taken from the project root directory. Falls back to the project id when no directory is known. | | {session} | Session title, read from the session record when the notification fires. Falls back to the first 8 characters of the session id when the session has no title. |

Titles are captured from session.created and session.renamed, and refreshed from the session record when a notification fires, so a toast names the session even when the title is generated after the plugin subscribes.

Messages may contain \n for a line break in the toast body; the default puts the project and session on separate lines.

Placeholders that resolve to empty are removed along with their adjacent separator, so the default "{project}\n{session}" degrades cleanly to just the project, or just the session when the project is unknown. To drop a placeholder entirely, remove it from the message:

{ "events": { "complete": { "message": "{project}" } } }

How it works

  1. OpenCode V2 calls the plugin's setup(ctx).
  2. The plugin resolves the bundled ntfytoast.exe from the toasted-notifier dependency.
  3. It subscribes to ctx.event.subscribe().
  4. Matching events map to toasts, which run as a Windows process from WSL.

OpenCode delivers every event to every location's plugin instance, and the plugin is loaded once per location (a project can have several, such as a worktree). Notification events carry no location field, so the plugin resolves each event's owning location from its session and ignores events that are not its own. One event therefore produces one toast rather than one per open location.

The plugin is deliberately inert outside WSL, since native Linux has a real notification daemon and OpenCode's built-in attention settings cover it. On Windows 11 with WSLg, try the built-in attention.notifications setting first — it may already do what you need.

WSL path translation

Windows processes cannot read /mnt/c/..., so paths are translated before use:

| WSL path | Windows path | | --- | --- | | /mnt/c/Users/me/x.exe | C:\Users\me\x.exe | | /home/me/x.exe | \\wsl.localhost\<distro>\home\me\x.exe |

The distro name comes from WSL_DISTRO_NAME.


Troubleshooting

No notifications appear.

Enable debug and check stderr:

{ "plugins": [{ "package": "opencode-wsl-notify", "options": { "debug": true } }] }

If it reports the binary could not be located, the vendored ntfytoast.exe is missing or could not be made executable. Set executablePath to an explicit copy.

Do I need to run npm install or fix permissions manually?

No. The plugin makes the binary executable at runtime, because OpenCode's Bun-based installer blocks postinstall scripts and npm does not reliably preserve the execute bit from WSL. There is no manual permission step.

Duplicate toasts.

A finished turn can surface as more than one event (session.execution.succeeded and the deprecated session.idle), and a reconnecting event stream can replay durable events. The plugin coalesces completions per execution, so one finished turn produces one toast.

Each event is also scoped to the session's own location, so opening the same project at more than one location (for example a worktree) does not toast once per location. Subagent sessions are detected from their session record's parentID, so they do not toast as top-level sessions while subagent_complete is disabled.

Set debug: true to log which events are dispatched and which duplicates are skipped.

Toasts show "NtfyToast" instead of "OpenCode".

The appID is passed through to the toast binary, but Windows only honors an application name for an appID that is registered on the system. Without registration the label falls back to the toast vendor's name.

To make the branding stick, register a Start Menu shortcut once:

node_modules/toasted-notifier/vendor/ntfyToast/ntfytoast.exe \
  -install "OpenCode\OpenCode.lnk" \
  "C:\Windows\System32\cmd.exe" \
  "OpenCode"

Then the default appID resolves to a registered name. Set a custom appID if you registered a different one.

"Session error" notifications never fire.

V2 emits session.execution.failed, which this plugin handles. If you are on a transitional release that still emits V1's session.error, that is handled too.


Development

npm install
npm run build        # tsc -> dist/
npm test             # unit tests: path/event/render/dedupe logic
npm run verify       # end-to-end: real setup() against a fake toast binary
npm run typecheck

The unit tests cover Windows path translation, event classification against real V2 event shapes, placeholder rendering, and completion coalescing. The end-to-end check exercises the real setup() and asserts on the toasts produced.


Credits

This package is a thin OpenCode integration layer standing on other people's work. The actual Windows toast rendering and the cross-platform notification plumbing come from:

| Project | Author | License | Role | | --- | --- | --- | --- | | toasted-notifier | Aetherinox | MIT | Cross-platform Node notification library this package depends on | | ntfy-toast | Aetherinox | MIT | The bundled ntfytoast.exe that renders the Windows toast | | SnoreToast | KDE | LGPL-3.0 | Original project ntfy-toast is based on | | node-notifier | Mikael Brevik | MIT | Original library that toasted-notifier forked |

ntfy-toast is a fork of SnoreToast with fixes and additional features. Thank you to these maintainers — this plugin would be a pile of PowerShell scripts without them.

License

MIT