Skip to main content

dsh-notifier

53Stars4Forks8Issues1Watchers

DSH Unified Notification & Remote Control Plugin: A single notify() API integrates with 27 push channels, while sending approvals, questions, and conversations from mobile back to desktop. Long-running tasks use automatic heartbeat with one-click stop support.

Evidence5/5methodologySourceInstallMaintenanceDSH versionSecurity scan
Machine-auditedInstall commandRepo verifieddsh-plugin topicLicenseREADMEAI wiki
Language
JavaScript
License
MIT
Branch
main
dsh-plugin

Install

cmdweb profile
$ dsh plugin --profile web add dsh-notifier

Run the command above in your terminal to install this plugin via the dsh CLI. You can switch Profile in the top-right corner. New to dsh? Read the beginner tutorial

Install via your agent

Install the DeepSeek Harness plugin THEWOLFWALKER/dsh-notifier for me: review the repository at https://github.com/THEWOLFWALKER/dsh-notifier first, then run the install command and verify the plugin loads successfully.

Paste this instruction to the DSH Web GUI assistant — it will install and verify for you.

One-Line Pitch

Unified notification and remote control plugin for DSH: host events (task completion/error/approval) and model-initiated pushes share a single notify() API to deliver messages to 27 push channels; 6 of those channels work bidirectionally to pull approvals, questions, and messages from phone back to desktop, and transform long-running tasks into a mobile command center with heartbeat and stop button.

Core Capabilities

  • 27 Outbound Channels: Telegram, Slack, Discord, Feishu, DingTalk, Enterprise WeChat (group/app), QQ Bot, OneBot, Teams, Mattermost, Google Chat, Bark, Pushover, PushDeer, Chanify, ntfy, Gotify, iGot, WxPusher, PushPlus, Server酱, Qmsg, 息知, Webhook, Terminal Bell, System Desktop Notification
  • Automatic Status Push: Host events (task start, completion, error, blocked, aborted, token limit reached, interrupted, approval needed) automatically forwarded to all configured channels; same-session rounds deduplicated with 10-second trailing-edge merging
  • Tiered Routing: Emergency/Active/Passive three-tier semantics mapped to each channel's native delivery form (silent push, priority, @mention), with tiered retry
  • Remote Approval & Dialogue: Six channels (Telegram, Feishu, QQ, WxPusher, WeChat, DingTalk) support callbacks; click buttons or reply 1/2 to remotely decide approvals; plain text messages enter agent session (follow-up questions/mid-course injection/steer)
  • Mobile Command Center: Long tasks send first heartbeat after 15 minutes + one every 15 minutes after; no events for 10 minutes triggers potential stall warning; Telegram/Feishu cards come with one-stop stop button
  • Remote Questions: ask_user tool pushes multiple-choice questions to phone (Feishu/Telegram option cards, other channels reply with number); user answers are sent back to agent; never auto-answer on timeout
  • Local Web Console: Binds to 127.0.0.1 + Bearer token only, includes 6 pages: overview, notification stream, members, pairing codes, binding matrix, session ledger, channel credentials; mobile-adaptive
  • Open Event Source: Other plugins can inject into notifier service for pushing, or subscribe to dsh-notifier/sent event to monitor each broadcast result; rate-limited to 10/min per source
  • Identity System: Runtime pairing code admission, composite key binding (channel:userId isolates channel identity), member management, and QR code authorization; empty list starts in guided mode

Technical Implementation

  • Language: JavaScript ESM (.mjs, pure ESM, zero build steps)
  • Key Dependencies: @deepseek-ai/cordis (host plugin framework), @larksuiteoapi/node-sdk (Feishu long connection, lazy-loaded optional), @tencent-connect/qqbot-connector (QQ Bot, optional), qrcode-terminal (terminal QR code, optional)
  • Architecture: Declarative spec engine (most channels generate adapters from data declaration tables) + 12 hand-written adapters; exposes service to host and other plugins via ctx.provide('notifier', facade); event bus auto-pushes on turn/end, approval/asked, agent/error; HMAC one-time token for remote approval
  • Entry Files: src/index.mjs (apply entry), src/config.mjs (config parsing and defaults), src/notify.mjs (outbound core)

Use Cases

You have an agent running on DSH, but tasks often take 10+ minutes, and keeping a browser open on desktop to watch progress is exhausting; you want to receive completion/error notifications on your phone, click a card to stop a runaway turn, or even reply from the road to steer the agent's execution direction. The same configuration should cover both overseas/office IM like Telegram and Feishu, and domestic push apps like Server酱, Bark, and PushPlus, with new channels not requiring changes to the main flow.

Prerequisites & Compatibility

DependencyMin VersionNotes
DSH0.1.0-rc.6Explicitly declared via dshWorkshop.compatibility.dshVersions; injected via cordis.patch.yml
Node.js>= 22Enforced by engines.node; Feishu and QQ inbound depend on native WebSocket
PlatformCross-platformDesktop notification channels have native implementations on macOS/Windows/Linux (osascript/notify-send/PowerShell Toast), other channels are network-only
Native ModulesNoneUses only node:crypto, native WebSocket, fetch; no native addons

Installation

dsh plugin --profile web add github:THEWOLFWALKER/dsh-notifier

Configuration Options

Written under config of the dsh-notifier entry in profile's cordis.patch.yml. Main blocks as follows (detailed schema in src/config.mjs):

ConfigTypeDescriptionDefault
channels[]ArrayChannel list, each item contains type and channel credential fields (e.g., telegram's botToken+chatId)Empty array (no error, no action)
enabledBooleanMaster switch; when off, no event subscription or tool registration, only exposes no-op stub service to prevent dependency blockersOn
titlePrefixStringAuto-push title prefix (can be empty)Empty
summaryMaxCharsNumberAuto-push reply body truncation character count500
debounceMsNumberSame-session consecutive event trailing-edge merge window (ms)10000
graceSecondsNumberIdle grace window after turn ends; user terminal input cancels disturbance0
events.turnStart.enabledBooleanWhether to push on task startOff
events.longRunningObjectLong task heartbeat (firstAfterMs first delay, everyMs subsequent interval, min 60s)On, 900000 / same value
events.stallObjectPotential stall warning (afterMs silent duration threshold, min 60s)On, 600000
events.turnEndBoolean/ObjectMaster switch for task completion; can control per reason.kind (completed/error/blocked/aborted/max-tokens/interrupted)All on
events.approvalBooleanWhether to push approval requestsOn
events.agentErrorBooleanWhether to push agent errorsOn
toolRateLimitPerMinuteNumberModel's notify tool calls per minute limit (prevent injection spam)10
inbound.allowUsersString ArrayInbound whitelist user IDs (first YAML broadcast then managed via console or /pair)Empty (enters guided mode)
inbound.telegram / feishu / qq / wxpusher / wechat / dingtalkObjectEach inbound channel credentials (specific fields in FIELD_HINTS, can be omitted for QR code/CLI credential fallback)Each defaults
inbound.tokenSecretStringSymmetric key for HMAC one-time tokens; if not set, all old tokens invalidated after restartProcess random
inbound.stateDirStringstate.json / ledger / audit file directory~/.dsh-notifier/
inbound.conversationObjectConversation routing params (mergeWindowMs, etc.)Default
approval.modeStringApproval remote response mode (answer remote can decide / observe observe only)Not enabled
approval.timeoutMsNumberApproval timeout fallback wait time to desktop120000
questions.enabledBooleanWhether to enable ask_user remote question toolOn
questions.timeoutMsNumberQuestion timeout (30s-30min clamp)300000
questions.rateLimitPerMinuteNumberModel's ask_user calls per minute limit6
route.sessionTtlHoursNumberConversation routing expiration duration24
admin.enabledBooleanWhether to start local web console (host hardcoded to 127.0.0.1, not configurable)Off
admin.portNumberConsole port (1-65535)8104
admin.tokenStringConsole Bearer token; if not set, auto-generated on first start (printed to stdout once)Auto-generated
digest.enabledBooleanWhether to enable notification ledger + daily digest pushOff
digest.maxEntriesNumberLedger entry retention limitDefault
segment.maxCodepointsNumberUnicode codepoint segmentation threshold for overly long messages1200
public.enabledBooleanWhether to expose notifier service externallyOn
public.limitPerMinutePerSourceNumberEach caller push limit per minute10
public.emitBooleanWhether to emit dsh-notifier/sent eventsOn

FAQ

Q: What do I need to do first after installation to receive notifications?

A: Add channels under config of the dsh-notifier entry in profile's cordis.patch.yml, configuring credentials for at least one channel. Empty channels won't cause plugin errors—it will just subscribe to events without acting.

Q: How do I send approvals from phone back to desktop?

A: Enable the inbound section and configure at least one inbound channel (telegram/feishu/qq/wxpusher/wechat/dingtalk). On first deployment, write whitelist user IDs in inbound.allowUsers (after first YAML broadcast, managed via console or /pair). Then in the channel's private chat, click buttons or reply 1/2 to decide.

Q: How is notification frequency controlled?

A: Three dimensions stack: events section controls which host events trigger pushes; debounceMs controls same-session consecutive turn trailing-edge merge (default 10s); graceSeconds controls idle grace window (default 0). These three don't affect each other and can be tuned independently.

Q: How do I know a long-running task is still alive?

A: Both longRunning (first heartbeat after 15 minutes, then one every 15 minutes) and stall (no events for 10 minutes = potential stall) are on by default. Telegram/Feishu channel notification cards have a one-stop stop button—clicking it cancels the turn. turnStart is off by default to avoid alerting on every task start.

Q: Can other plugins use this notification system?

A: Yes. Inject notifier service (ctx.inject(['notifier'], …)) and call push(), or subscribe to dsh-notifier/sent event to monitor each broadcast result. Rate-limited to 10/min per source (public.limitPerMinutePerSource); excess returns structured skipped without throwing errors.

Q: Is the web console secure?

A: Host is hardcoded to 127.0.0.1, never binding to public internet (not configurable). Token is auto-generated on first start and printed to stdout once, validated with SHA-256 hash after restart; explicitly configured admin.token takes precedence. For remote access, set up your own reverse proxy.

Q: Will state data be retained after uninstall?

A: state.json stays in $HOME/dsh-notifier/ (stateDir configurable), recording whitelist, pairing codes, ledger, audit logs. Uninstalling the plugin doesn't auto-clean the disk; reinstallation can continue; manually delete the directory for complete cleanup.

Q: What happens when a channel quota is exhausted or network is down?

A: Each channel has independent circuit-breaking (short retry with backoff); when below threshold, tiered retry applies; when threshold exhausted, that channel is skipped, host continues running, ledger records failure count, other channels unaffected.

Learning Curve

Advanced — large configuration matrix (27 channels × bidirectional inbound/outbound × multi-level switches). Beginners should start with the web console (auto-generates config). When hand-writing YAML, note ${ENV:NAME} reference semantics (supported for both outbound and inbound).

Known Issues & Limitations

  • WxPusher inbound depends on HTTP callback, requires public internet reach (frp/reverse proxy user responsibility); other 5 inbound channels use long connection/long polling, no public IP needed
  • QQ/DingTalk/WeChat inbound don't support button cards, rely solely on number replies (reply 1 approve / 2 reject)
  • Windows desktop notifications require PowerShell's BurntToast module, otherwise that channel is locally ineffective
  • DingTalk Stream implementation reuses official SDK field naming (uesrAgent, noted in source) — upstream convention, copied as-is
  • Feishu inbound depends on @larksuiteoapi/node-sdk (optionalDependency); when not installed, SDK load failure gives Chinese guidance then silently downgrades
  • Long task heartbeat/stall warning interval min clamped at 60s (Math.max(60_000, Number(x) || default)), setting 0 not allowed — use enabled: false to disable
  • state.json multi-process concurrent writes already have key-level merge + cross-process write lock + read coalescing three-layer defense, but extreme cases (massive concurrent writes) may degrade to lock-free writes with one-time warn
  • v0.7.3 fixed Feishu WSClient logger: null silent crash and card message_id wrong value (CHANGELOG #1/#6), please confirm fix before upgrading
  • Web console host hardcoded to 127.0.0.1 (not configurable), any attempt to expose is blocked at code level — remote access requires user-provided reverse proxy

Read the usage guide →

Install steps, key points, FAQ and compatibility for this plugin — auto-derived from indexed fields.

Listing badge

Listed on deepseek-plugin.org
[![Listed on deepseek-plugin.org](https://img.shields.io/badge/listed_on-deepseek--plugin.org-007EC6)](https://deepseek-plugin.org/plugins/THEWOLFWALKER/dsh-notifier)

Paste this markdown into your GitHub README to link back to this listing. The badge only states the listing — not a security endorsement.

← Back to plugin directory