ceasarXuu/dsh-better-push ↗★ 0

@ceasarxuu/dsh-better-push

macOS system notifications for DeepSeek Harness: turn finished, approval waiting, questions, errors, background jobs, subagents and workflows — with click-to-open-session, per-event switches and a background-only default.

包名
@ceasarxuu/dsh-better-push
兼容性
待验证
Harness 依赖范围
>=0.2.1-rc.3 <0.3.0
版本
0.1.0
许可证
MIT
最近更新
2026年10月28日

安装

$npx -p @deepseek-ai/dsh dsh plugin --profile web add https://github.com/ceasarXuu/dsh-better-push/releases/download/v0.1.0/ceasarxuu-dsh-better-push-0.1.0.tgz

dsh-better-push

Native macOS notifications for DeepSeek Harness. When you step away from the window and the agent finishes a turn, asks for an approval, asks you a question, hits an error, or a background job / subagent / workflow settles, macOS tells you — with the DeepSeek Harness app name and icon. Click the banner and the window comes forward on the Session that fired it.

┌───────────────────────────────────────────────┐
│ 🔔 DeepSeek Harness                           │
│ 回合完成 · dsh-better-push                     │
│ Fixed the parser; tests pass. · 耗时 2m14s     │
└───────────────────────────────────────────────┘

Third-party plugin. Not an official DeepSeek / DeepSeek Harness component.

What it notifies

TriggerWhat you seeDefault
Turn finishedSession name, a one-line reply preview, elapsed timeon
Tool call waiting for approvalSession name + tool name; banner closes itself once you decideon
Agent asking a questionSession name + the questionon
Turn failed / interrupted / out of contextThe provider or turn erroron
Background job settledJob label + status (run_in_background commands, promoted commands)on
Subagent turn finishedParent conversation name + preset; click opens the parent Sessionoff
Workflow run finishedWorkflow name + stop reasonon
Test notificationPushed from the settings page or POST /plugin/better-push/test—

Foreground Bash calls are not notified even though they are jobs internally: the plugin reads the job feed's awaited flag, so only work you actually left running in the background pings you.

Install

Requires DeepSeek Harness 0.2.1-rc.3 or newer (below 0.3.0) on macOS, with the desktop or web surface.

This repository is the distribution for now — the plugin is not published to npm. DSH installs it from GitHub in any of these three ways; pick one.

1. Discover / plugin market (recommended — version pinned to a commit). Add this index URL once in Settings → Plugins → Discover → market sources, then install "Better Push — macOS notifications" from the list:

https://raw.githubusercontent.com/ceasarXuu/dsh-better-push/main/market/index.json

market/index.json is a format-1 DSH plugin-market index whose entry is a git source pinned to an exact commit, so the same URL also works hosted anywhere else (GitHub Pages, object storage).

2. Plugin Manager → Add. Paste the repository URL or the pnpm shorthand:

https://github.com/ceasarXuu/dsh-better-push
github:ceasarXuu/dsh-better-push

or the packed release tarball (exactly what npm pack produces):

https://github.com/ceasarXuu/dsh-better-push/releases/download/v0.1.0/ceasarxuu-dsh-better-push-0.1.0.tgz

3. CLI. Quit the app first (the profile is locked while it runs), then:

dsh plugin --profile desktop add github:ceasarXuu/dsh-better-push
# or a local checkout:
dsh plugin --profile desktop add /absolute/path/to/dsh-better-push

Restart the app once. Settings live in the profile's cordis.patch.yml under row id better-push. Updating = install the newer version the same way (the market index is the only source that pins a commit; github: installs track the default branch head).

Settings

Everything is editable in Settings → 通知 / Notifications (its own section in the settings sidebar, next to General and Plugins; the same form also appears in Settings → Plugins → the plugin's row) and stored in the profile patch. Every switch is independent, and changes apply immediately: the settings page writes the profile patch, the loader commits volatile fields into the running plugin, and the browser half picks the new policy up on its next poll.

KeyDefaultMeaning
enabledtrueMaster switch for all system notifications.
notifyInForegroundtrueAlso notify while the DSH window is focused. Turn off to only notify from the background.
soundtruePlay a sound with each notification.
turnEndtrueNotify when a turn finishes.
approvalstrueNotify when a tool call waits for approval.
questionstrueNotify when the agent asks you a question.
errorstrueNotify on failed, interrupted or out-of-context turns.
jobstrueNotify when a background job settles.
subagentsfalseNotify when a subagent / Agent Teams teammate turn finishes. Off by default: a busy team would otherwise ping on every child turn.
workflowstrueNotify when a workflow run finishes.
previewtruePut a short assistant-reply preview in the finished-turn body.
minTurnSeconds0Skip finished-turn notifications shorter than this (0 = notify every turn).
quietHours""HH:MM-HH:MM local quiet window; overnight ranges allowed.
fallbackWhenNoClienttrueUse osascript when no app window is attached (window closed).
fallbackSoundNameGlassSound used by the osascript fallback.

How it works

Two halves, one package:

  • Host half (index.js) watches session/event for every live Session (turn/end, approval/asked, approval/decided, tool-workflow/*, session/title), the user-questions/request waterfall (observed, never answered), and the jobs feed. It classifies, dedupes, applies quiet hours, and serves a tiny HTTP surface under /plugin/better-push: GET /poll (notifications since a cursor — also the presence heartbeat), GET /state (diagnostics), GET /health, POST /test.
  • Browser half (client.js) polls that route once a second and turns items into renderer Notifications. On the desktop that means a UNUserNotification banner attributed to DeepSeek Harness, the app icon, macOS's own click activation, and uiWorkspace.openSession(sessionId) so the click lands on the right Session. It also closes the approval banner when the approval resolves.

Delivery is renderer-first. When no window is attached (you closed it while a job ran), the host falls back to osascript display notification so you still hear about it — at the cost of Script Editor attribution and a click that cannot open DSH. Turn fallbackWhenNoClient off if you would rather miss it.

Why a poll and not a socket: the desktop renderer runs on dsh-app://app and the Electron shell forwards same-origin fetches to the host; one request a second on loopback is free, and it doubles as the presence signal that decides between the two delivery paths.

Diagnostics

# what the plugin sees right now
curl -s http://127.0.0.1:61670/plugin/better-push/state | jq
# { "clients": 1, "clientIds": ["web-…:granted"], "cursor": 3, "fallback": 0, … }

# show a banner through the normal channel
curl -s -X POST http://127.0.0.1:61670/plugin/better-push/test \
  -H 'content-type: application/json' -d '{"body":"hello"}'

clients: 0 means the window is closed and delivery is on the fallback path. clientIds ending in denied means the renderer cannot notify and the host is already falling back for it.

Development

pnpm install          # @deepseek-ai/schemastery only
node --test test/*.test.mjs

Client bundles hot-swap in a running GUI (~500 ms, no restart); host code needs an app restart. To test host changes without touching your profile, boot a separate web instance and drive it with the bundled CDP verifier — see dev/README.md.

Limits

  • macOS only for now; the renderer half would work on Windows/Linux but the fallback and the copy are macOS-specific and untested there.
  • The renderer path cannot choose a custom sound (Web Notifications expose silent only), cannot set a subtitle, and cannot show action buttons.
  • No dock badge, no notification history screen, no per-session mute yet.
  • Click-to-focus is best-effort: macOS activates the app on banner click, window.focus() cannot raise a minimized window by itself.
  • osascript fallback banners are attributed to Script Editor and clicking one opens Script Editor — a macOS limitation of the legacy display notification path, not a plugin bug.

License

MIT. See LICENSE.