# dsh-session-notify

DSH web plugin: session-stop alerts — a **finished output** (running → stopped) or a **waiting-for-you** stop (approval / plan review / question) — delivered as desktop notifications, a chime, and a title flash while the page is in the background. Click a notification to jump to that session.

Pure plugin-layer implementation; no DSH source changes.

## Alert matrix

| Page state | Stopped session | Effect |
|---|---|---|
| Background (another window) | any session | notification + chime (if on) + title flash (if on) |
| Foreground | a non-current session | notification + chime (when "foreground" pref is on) |
| Foreground | the session you are watching | silent by design |

**Notifications are clickable**: click → focus the window → switch to that session.

## Install

Official bundle channel (one command installs AND mounts):

```bash
dsh plugin --profile web add dsh-session-notify
```

Manual/dev install:

```bash
node build.mjs        # needs esbuild
cp -R lib cordis.patch.yml package.json ~/.dsh/profiles/web/node_modules/dsh-session-notify/
# then add to ~/.dsh/profiles/web/cordis.patch.yml:
# - insert:
#     - id: session-notify
#       name: 'dsh-session-notify'
```

Restart `dsh web`; hard-refresh the page after a bundle update.

## Behavior notes

- Watches the client runtime's `ctx.sessions.list` store (same data source as the sidebar status dots: `host/session-status` frames + the `pendingInteraction` projection).
- Each alert uses a UNIQUE notification tag and explicitly closes the previous live notification for that session: macOS silently swallows re-deliveries of an identifier still present in Notification Center, so a stable per-session tag would drop every alert after the first.
- Preferences persist in localStorage (`dsh-session-notify.prefs.v1`), no host service needed.
- Copy is bilingual (zh/en) through the DSH locale service.
- Reload takes a silent baseline: no replay of alerts for already-waiting sessions.

## Known limitations

- No alerts when the browser tab is closed (a client plugin lives in the page).
- Browser notification permission required (grant once from the settings section).
- **Whether a banner appears is controlled at two levels**: after the site permission is granted, macOS can still silence the browser App in System Settings → Notifications, and Focus/DND swallows banners — the JS `new Notification()` construct succeeds with no visible effect, and the plugin cannot detect this.
- The notification's origin line shows the page origin (e.g. `127.0.0.1:3080`); browsers force this label and JS cannot change it.
