Notifications & Integrations

dsh-desktop-notify-afap

AFAP/dsh-desktop-notify · ★ 0

AFAP

Desktop notifications for the DeepSeek Harness web GUI: a system-level toast (via the browser Notification API) whenever the harness needs a human — tool approval, a question or plan review…

License
MIT
Added
2026-10-30
Maintenance
active
Install kind
github
Manifest details
Manifest status
Declared
Manifest path
package.json#dsh
Manifest checked
2026-10-30T09:38:20.037Z
Lifecycle scripts
None found

Static manifest checks report declarations only; they are not compatibility or security review.

安装

dsh plugin --profile web add 'github:AFAP/dsh-desktop-notify#102034f94ef9a8dcc4c516abb51872874b0d591c'

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

For install and environment setup, plus plugin development tutorials, see DSH community docs ↗

README

Source README · body: en · Read Chinese README

Table of contents
  1. 1. The problem it solves
  2. 2. Features
  3. 3. Repository layout
  4. 4. Quick start
  5. Install from a source checkout (development / preview)
  6. Verify it loaded
  7. 5. Usage
  8. 5.1 When it notifies
  9. 5.2 What the notification does
  10. 5.3 Foreground suppression and blur flush
  11. 5.4 Pending count
  12. 6. Settings
  13. 7. Troubleshooting
  14. 8. Security and compliance (read this)
  15. 9. FAQ
  16. 10. Development and implementation
  17. 10.1 Module layering
  18. 10.2 Why not hook the approval/request waterfall
  19. 10.3 What it does instead: observe the official state source
  20. 10.4 UI seat
  21. 10.5 Build and release
  22. 10.6 Local preview and self-checks
  23. 11. Compatibility
  24. 12. Related resources
  25. 13. License

A system notification the moment the harness stops and waits for you. Tool authorization, a question or plan review, a finished turn — stop staring at the page, and click the toast to jump straight back to the pending card.

License: MIT GitHub release (latest)

1. The problem it solves

DeepSeek Harness has to wait for you at three moments: a tool needs one-shot authorization, the model asks you a question or submits a plan to confirm, and a turn finishes. When you are not in front of the page, the conversation simply sits there — and staring at a tab is not a workflow.

This plugin turns those three moments into system-level notifications (real Windows toasts, raised through the browser Notification API), so you find out while you are working in another window.

┌──────────────────────── DeepSeek Harness ────────────────────────┐
│                                                                  │
│  tool authorization ─┐                                           │
│  a question         ─┼─▶ pendingInteraction ──▶ uiSession.      │
│  turn finished      ─┘        (official state source, read-only) │
│                                                  │ subscribe      │
│                                                  ▼               │
│                                    dsh-desktop-notify            │
│                                                  │               │
└──────────────────────────────────────────────────┼───────────────┘
                                                   ▼
                                   browser Notification API
                                                   │
                                                   ▼
                          Windows system toast + click focuses the GUI

The important part: read-only observation, no takeover. The official approval panel and question composer keep working exactly as before — this plugin only reads the state beside them.

2. Features

  • ✅ Three triggers: tool authorization (approval), questions and plan reviews (question / plan-review), and turn completion (a session going idle)
  • ✅ System-level notifications: raised by the browser (a system toast on Windows) — no host process, no background daemon
  • ✅ Click to jump: focuses the window and scrolls to the pending approval / question card
  • ✅ Blur flush: stays quiet while you are looking at the GUI, then flushes the suppressed notification once you switch away
  • ✅ Subagent noise control: completion is announced only for sessions you track in the host list; a subagent going idle never pings you
  • ✅ Dedupe and self-cleanup: one notification per request, and it closes itself once you answer in the UI
  • ✅ Zero sidebar cost: one section in Settings, nothing added to the sidebar
  • ✅ Four switches, persisted locally: stored in browser localStorage, never uploaded
  • ✅ Zero dependencies: no host service, no external npm package, no session-log reads, no HTTP route

3. Repository layout

dsh-desktop-notify/
├── README.md              # Chinese main document (primary)
├── README.en.md           # English full version (parallel structure)
├── LICENSE                # MIT
├── .gitignore             # secrets / build output / editor noise
├── package.json           # dsh.bundle.patch + dsh.client (platform: web)
├── cordis.patch.yml       # bundle patch: inserts the plugin row into the web profile
└── lib/
    ├── index.js           # host half: deliberately inert (see section 10)
    └── client.js          # browser half: state observation + notifications + settings page

There is no build step: the browser half is a classic script registered through window.__ModuleLoader__.load() and served by the host on request.

4. Quick start

dsh plugin --profile web add github:AFAP/dsh-desktop-notify

A page refresh is enough — no dsh web restart. Then:

  1. Open Settings → Notifications in the left nav
  2. Press Grant and allow notifications in the browser prompt
  3. Press Send a test notification to confirm the channel

Upgrade:

dsh plugin --profile web update dsh-desktop-notify

Remove:

dsh plugin --profile web remove dsh-desktop-notify

Install from a source checkout (development / preview)

dsh plugin --profile web add link:D:\path\to\dsh-desktop-notify

Verify it loaded

The Settings nav gains a Notifications section (after General, before Models); the sidebar gains nothing.

5. Usage

5.1 When it notifies

Trigger Title Body
A tool needs authorization Authorization needed The asker's reason (e.g. "write denied by sandbox"), or "Tool X requests privileged execution"; plus the session title
The model asks / submits a plan A question is waiting / A plan needs confirmation The question text (plan review uses fixed copy); plus the session title
A turn finishes (session idle) Turn finished The session title

5.2 What the notification does

  • Clicking it: brings the window forward and scrolls to the matching card (approval card, question composer), then dismisses itself.
  • After you answer: answering or dismissing in the UI closes the matching notification, so no stale reminder survives.
  • The same request: notifies once; a repeated observation of the same request never re-fires.

5.3 Foreground suppression and blur flush

"Only when DSH is not in the foreground" is on by default: while you are demonstrably looking at the GUI (page visible and window focused) it stays quiet — and the moment you switch away or minimize, the suppressed notification is flushed. You are neither nagged while watching nor missed when you walk away.

5.4 Pending count

The settings section carries one status line: ● N request(s) are waiting on you while authorizations or questions are pending, and "Nothing is waiting on you right now" otherwise. That is the only place you need to check (no sidebar real estate).

6. Settings

All four are booleans, stored in the browser's localStorage under dsh-desktop-notify:settings (per browser, never uploaded).

Key Default Meaning
approval true Notify when a tool needs authorization
question true Notify when you must answer a question or confirm a plan
completion true Notify when a turn finishes (session idle); tracked host-list sessions only
backgroundOnly true Only notify while DSH is not in the foreground; turning it off notifies even while you watch

Notification permission is not a plugin setting: the browser owns it per site. After a block, re-allow it in the site settings from the address bar (see section 7).

7. Troubleshooting

Symptom Where to look
No notification at all Settings → Notifications shows the permission state: Not granted → press Grant; Blocked by the browser → set Notifications to Allow in the address-bar site settings and reload
Permission is fine, still nothing Windows Focus Assist / Do Not Disturb swallows toasts — allow browser notifications in the system settings; also check whether "Send a test notification" works
Pending work, but no toast The default "only when DSH is not in the foreground" deliberately suppresses it while you watch; switch away to trigger the flush, or turn that switch off
The Settings nav has no Notifications section The plugin did not load: check dsh plugin --profile web list and reload the page (Ctrl+Shift+R)
"Unsupported here" is shown The page is not a secure context (not https, 127.0.0.1 or localhost), so the browser exposes no Notification API
Too noisy Turn off completion and/or question, or keep foreground-only notifications on
Clicking the toast does not jump to a card That card belongs to another session: switch to it in the session list, then click the notification
A subagent finishing shows "Turn finished" Should not happen: completion is filtered by host-list membership — please open an issue with a screenshot if it reproduces

8. Security and compliance (read this)

  • No reads, no writes, no requests: the host half (lib/index.js) is a deliberately inert no-op — no route, no session-log access, no network call; the browser half only reads the state the harness already pushed to the page.
  • The only permission is browser notifications: revocable at any time in the site settings; once revoked the plugin silently stops, without errors and without affecting DSH.
  • Notification bodies can appear on the lock screen / in the notification center: they carry the tool name, the request reason and the session title. Keep this in mind while screen sharing, recording or presenting; turn the relevant switches off for sensitive work.
  • No credentials, no secrets: the repository contains no tokens, keys, internal hosts or machine-absolute paths (docs use placeholders such as D:\path\to\... and $DSH_HOME).
  • Settings stay local: localStorage does not sync across sessions or accounts, and no preference data is ever uploaded.
  • Open an issue for problems; report security details privately through the repository's Security Advisory instead of a public issue.

9. FAQ

Q: Can I get authorization notifications without "turn finished"? A: Yes — turn off the completion switch; the three switches are independent.

Q: Why not a native OS toast (a PowerShell helper, say)? A: This version uses the browser Notification API only: it also renders as a real Windows toast, it can focus the window and scroll to the card when clicked, and it needs no external process per notification. A host-side helper can neither reliably bring the browser forward nor avoid spawning a process each time.

Q: Why is there no sidebar entry? A: This plugin carries attention state only, with no permanent action of its own. One settings section plus the pending count is enough, and the sidebar keeps its space.

Q: Does it notify when the tab is closed? A: No. Notifications come from the page; with no page there is also no UI able to answer, so the request fails closed.

Q: Two browsers open — do I get two notifications? A: Each page decides and raises its own system notification; settings (localStorage) are per browser.

Q: Does it interfere with DSH's own approval flow? A: No. It registers no approval answerer and only observes the official state source, so the official allow / reject path is untouched.

10. Development and implementation

10.1 Module layering

File Responsibility
lib/index.js Host half: deliberately inert (an empty apply), so the plugin row loads cleanly; it provides no service and needs no config
lib/client.js Browser half: registers locale dictionaries, subscribes to the state source, raises notifications, contributes the settings section
cordis.patch.yml Bundle patch: inserts the desktop-notify row into the web profile composition (no inject, no config)

10.2 Why not hook the approval/request waterfall

ctx.remote.$on("approval/request", (req, next) => ...) looks like the natural seam, and it is the wrong one.

The official panel (@deepseek-ai/dsh-client-ui-approval) registers its waterfall listener during boot and intentionally holds the whole waterfall until the user answers (it awaits pending.result). Any listener registered later — every out-of-tree plugin — therefore never runs for a request the panel owns. $on has no prepend option either, so load order cannot fix it.

10.3 What it does instead: observe the official state source

ctx.uiSession.sessionStatus   // HostObservable: { getSnapshot, subscribe }
  └─ Map<SessionId, { running, pendingInteraction, completionUnread }>
  • pendingInteraction.kind already discriminates approval / question / plan-review and carries toolName / reason / questions, so all three cases come from one read;
  • reading state is ordering-free and outside the answering path, which is what makes the zero-intrusion claim true;
  • decoupling from the waterfall is also what makes foreground suppression and blur-time flushing possible at all.

10.4 UI seat

The plugin contributes a settings page through settings.section (order: 5 — after General, before Models, because this is a plain preference rather than a plugin administration page). The sidebar gains no button.

10.5 Build and release

There is no build step (a pure JS classic-script bundle), so no GitHub Actions workflow is configured: dsh plugin add <repo> serves the browser half straight from package.json's exports["./client"]. Changes are committed in Conventional Commits style and releases are SemVer tags.

10.6 Local preview and self-checks

  • Manual: after a link: install, reload the page, use "Send a test notification" and trigger one real authorization request.
  • Theme self-check: render the section with the real DSW theme tokens in light and dark, confirming the surfaces are opaque and legible (this plugin uses no translucent overlay token).

11. Compatibility

Requires DeepSeek Harness 0.1.7-alpha.1 or newer. The contracts it relies on:

Contract Used for
ctx.uiSession.sessionStatus (HostObservable) Pending requests and running state
pendingInteraction.kind: approval / question / plan-review The three notification classes
settings.section slot The settings page seat
Theme tokens --dsw-alias-bg-layer-2 / --dsw-alias-bg-skeleton and friends Section styling

Browser half only (dsh.client.platform = web): no host dependency, no external npm dependency.

13. License

MIT © contributors · see LICENSE


Disclaimer: this plugin only projects pending state that DSH already maintains into a system notification and changes no approval outcome. Focus Assist / Do Not Disturb, browser permission policy, or a closed page can all prevent a notification from appearing — do not make critical approval workflows depend on notifications alone; any consequence of a missed notification rests with the user.