Skip to content

Releases: GooDAnDReaDY/dsh-plugin-notify

v0.4.8

Choose a tag to compare

@GooDAnDReaDY GooDAnDReaDY released this 01 Nov 20:51

English

Added

  • Interactive Question and Plan Review Notifications (#5): Added question_requested event kind (in default events) observing Cordis waterfall user-questions/request as a passive observer (return next()). Accurately discriminates plan-mode review cards (exit_plan_mode, intent.kind === 'plan-review') with summary 'Plan ready for review' and generic questions (ask_user_question) with question header/text. Dispatches to all configured channels (SSE, IM webhooks, Web Push, audio chimes, toasts, desktop push) with full subagent and prefix filtering support.

简体中文

新增

  • 用户提问与计划审阅通知 (#5):新增 question_requested 事件类型(默认启用),作为被动观察者(return next())监听 Cordis waterfall user-questions/request。准确识别计划模式审阅卡片(exit_plan_mode,intent.kind === 'plan-review',摘要为“Plan ready for review”)以及通用问题(ask_user_question,携带标题与问题文本)。支持全部通知通道(SSE、IM Webhooks、Web Push、提示音、横幅 Toast、系统桌面推送),并完整继承会话前缀排除与子代理过滤逻辑。

Русский

Добавлено

  • Уведомления для вопросов пользователю и ревью плана (#5): добавлен тип события question_requested (включён в события по умолчанию), прослушивающий Cordis waterfall user-questions/request в качестве пассивного наблюдателя (return next()). Точно распознаёт карточки ревью плана (exit_plan_mode, intent.kind === 'plan-review') со сводкой 'Plan ready for review' и стандартные вопросы пользователю (ask_user_question) с текстом/заголовком вопроса. Поддерживает все каналы доставки (SSE, вебхуки, Web Push, звуковые сигналы, тосты, десктопные пуши) с фильтрацией субагентов и исключённых префиксов сессий.

v0.4.7

Choose a tag to compare

@GooDAnDReaDY GooDAnDReaDY released this 26 Oct 07:59

English

Added

  • Subagent Session Filtering & Noise Suppression (#4): Added notifySubagents option (boolean, default false) in configuration schema and settings card UI. Suppresses turn completion (turn/end) and approval (approval/asked) notifications from delegated subagents (such as dsh-mnemon and background subagent runs). Subagents are recognized by session metadata (origin === 'subagent', header.parentSession, header.parentId, isSubagent, agentType) and bare UUID format, while main interactive user conversations (session-<uuid>) continue to notify as expected.

简体中文

新增

  • 子代理会话过滤与静音 (#4):在配置 Schema 和设置卡片中新增 notifySubagents 选项(布尔值,默认 false)。自动过滤并抑制来自委托子代理(例如 dsh-mnemon 及后台子代理任务)的回合完成(turn/end)和等待审批(approval/asked)通知。系统通过会话元数据(origin === 'subagent'、header.parentSession、header.parentId、isSubagent、agentType)以及纯 UUID 格式准确识别子代理,同时完全保留主交互会话(session-<uuid>)的正常通知。

Русский

Добавлено

  • Фильтрация и подавление шума от субагентов (#4): добавлена опция notifySubagents (boolean, по умолчанию false) в схеме настроек и карточке интерфейса. Подавляет уведомления о завершении хода (turn/end) и ожидании подтверждения (approval/asked) для вспомогательных субагентов (например, dsh-mnemon и фоновых запусков задач). Субагенты определяются по метаданным сессии (origin === 'subagent', header.parentSession, header.parentId, isSubagent, agentType) и формату чистого UUID, сохраняя штатные уведомления для основных интерактивных сессий пользователя (session-<uuid>).

v0.4.6 [Security: Web Push SSRF Protection]

Choose a tag to compare

@GooDAnDReaDY GooDAnDReaDY released this 22 Oct 15:58

English

Security

  • Web Push Endpoint Allowlist & SSRF Protection: Enforce strict validation of subscription endpoints against canonical Web Push gateways (Google FCM, Mozilla Autopush, Apple Web Push, Microsoft WNS) with optional webPush.allowedHosts; reject loopback, private IPv4/IPv6, link-local, userinfo, and non-standard ports.
  • Push Endpoint Masking in Logs: Mask subscription endpoint tokens in server logs (maskEndpoint) and delivery error messages to prevent token exfiltration.
  • Subscription Capacity Bound: Constrain total stored subscriptions (max 100) to prevent state file exhaustion DoS.
  • Dead & Disallowed Endpoint Pruning: Prune any invalid or unapproved endpoints during deliverWebPush without dispatching requests.

简体中文

安全性

  • Web Push 端点白名单与 SSRF 防护:对推送订阅端点实施严格校验,仅允许规范的 Web Push 网关(Google FCM、Mozilla Autopush、Apple Web Push、Microsoft WNS),支持可选的 webPush.allowedHosts;严格拒绝环回、私有 IPv4/IPv6、链路本地地址、凭据以及非标准端口。
  • 日志端点脱敏:在服务端日志(maskEndpoint)和发送错误提示中对订阅端点 Token 进行脱敏,防止凭证泄露。
  • 订阅容量限制:限制持久化订阅最大数量(上限 100),防止状态文件资源耗尽。
  • 自动清理无效端点:在 deliverWebPush 执行期间自动检测并清理未授权或失效的端点,拒绝向其派发请求。

Русский

Безопасность

  • Allowlist эндпоинтов Web Push и защита от SSRF: введена строгая валидация эндпоинтов подписки с разрешением только канонических Web Push шлюзов (Google FCM, Mozilla Autopush, Apple Web Push, Microsoft WNS) и поддержкой webPush.allowedHosts; блокируются loopback, private IPv4/IPv6, link-local адреса, userinfo и нестандартные порты.
  • Маскирование токенов эндпоинтов в логах: полные URL с токенами подписок маскируются в логах сервера (maskEndpoint) и текстах ошибок отправки для защиты от утечки данных.
  • Ограничение емкости подписок: зафиксирован лимит количества активных подписок (максимум 100) для предотвращения исчерпания ресурсов хранилища.
  • Очистка недопустимых эндпоинтов: при вызове deliverWebPush недопустимые или отклонённые эндпоинты удаляются без выполнения сетевых запросов.

v0.4.5 [DSH v0.2.0-rc.2]

Choose a tag to compare

@GooDAnDReaDY GooDAnDReaDY released this 19 Oct 07:47

English

Fixed

  • Safe Logger Invocations: Guard logger method invocations with safeLog(ctx, message) binding receiver this (fn.call(logger, message)) to prevent TypeError: this is not a function in Cordis 0.2 LoggerService.
  • Object Settings Persistence: Decompose non-leaf object configuration fields (webhooks, dnd, webPush) into individual leaf paths (['webhooks', key]) and save atomically via scope.mutate(ops) with fallback to scope.set, passing dsh-settings volatile path validation.
  • Session Events & Title Cascade: Add eventsOf(session) supporting append-only session.log, session.eventsSnapshot, and session.snapshotEvents(); add cachedTitle(session) reading projected title cache from disk (storages/session_projcache/sessions/<id>.json), preventing fallback to raw UUIDs.
  • Session Navigation Priority: Target uiWorkspace.openSession(sessionId) as the primary navigation service in navigateToSession with graceful fallbacks.

简体中文

修复

  • 安全的日志记录调用:使用 safeLog(ctx, message) 绑定 this 接收器(fn.call(logger, message)),防止 Cordis 0.2 LoggerService 抛出 TypeError: this is not a function。
  • 对象设置持久化:将非叶子对象配置项(webhooks、dnd、webPush)分解为单独的叶子路径(['webhooks', key]),并通过 scope.mutate(ops) 原子化保存(兼容 scope.set),符合 dsh-settings 的 volatile 模式校验。
  • 会话事件与标题级联:新增 eventsOf(session) 支持只追加的 session.log、session.eventsSnapshot 和 session.snapshotEvents();新增 cachedTitle(session) 从磁盘读取投射的标题缓存(storages/session_projcache/sessions/<id>.json),防止标题回退为原始 UUID。
  • 会话导航优先级:在 navigateToSession 中优先使用 uiWorkspace.openSession(sessionId) 作为主导航服务,并保留向下兼容回退。

Русский

Исправления

  • Безопасный вызов методов логгера: функция safeLog(ctx, message) с явной привязкой контекста this (fn.call(logger, message)) устраняет падение с TypeError: this is not a function в LoggerService фреймворка Cordis 0.2.
  • Персистентность объектных настроек: поля-объекты (webhooks, dnd, webPush) раскладываются на листовые пути (['webhooks', key]) и сохраняются атомарно через scope.mutate(ops) с фолбэком на scope.set, успешно проходя валидацию volatile-схемы dsh-settings.
  • Каскад поиска событий и заголовков сессии: функция eventsOf(session) извлекает события из современных структур (session.log, session.eventsSnapshot, session.snapshotEvents()); функция cachedTitle(session) читает спроецированный кэш с диска (storages/session_projcache/sessions/<id>.json), предотвращая показ UUID вместо заголовков.
  • Приоритет навигации к сессии: navigateToSession приоритетно использует uiWorkspace.openSession(sessionId) (основной навигатор DSH 0.2) с каскадными фолбэками.

v0.4.4

Choose a tag to compare

@GooDAnDReaDY GooDAnDReaDY released this 15 Oct 17:47

Fixed

  • Client config form lookup (#61): Query \ctx.configForms\ strictly by canonical entry id \plugin-notify\ (\ROW_ID) rather than attempting fallback queries to scoped package name @goodandready/dsh-plugin-notify, fixing unresolvable configuration lookups in the settings panel.

v0.4.3 [DSH v0.1.7-rc.2 / v0.2.0-rc.2]

Choose a tag to compare

@GooDAnDReaDY GooDAnDReaDY released this 15 Oct 15:06

Fixed

  • Host event cleanup (#59): Prune dead listener on non-existent host event \settings/updated\ in \lib/index.js\ (active settings updates remain reliably monitored via \settings/document-updated\ and \loader/volatile-update).
  • Client slot registration (#59): Remove dead registration of non-existent client seat \settings.plugin.item\ in \lib/client.js\ (official plugin list page seat \plugins.item\ and row config seat \plugins.row.config\ handle settings cards).
  • Web push state path containment (#59): Constrain custom \webPush.stateFile\ paths by resolving relative paths against the DSH home directory instead of returning raw unconstrained strings.

v0.4.2 [DSH v0.1.7-rc.2 / v0.2.0-rc.2]

Choose a tag to compare

@GooDAnDReaDY GooDAnDReaDY released this 10 Oct 14:48

Fixed

  • Request trust enforcement on HTTP/SSE routes (#46): Route SSE and Push subscriptions through \isTrustedRequest\ / \getRequestRejection, ensuring origin and session checks with loopback fallback.
  • Webhook error logging diagnostic (#49): Log human-readable channel name instead of truncated webhook URL on POST failure, preventing credential token leakage.
  • Multi-instance SSE client isolation (#50): Isolate SSE client sets per plugin lifecycle context on dispose, avoiding cross-instance connection drops on reload.
  • Deterministic memory bound on turnStarts map (#51): Enforce deterministic FIFO eviction bound (\maxSize = 100) on \ urnStarts\ map under session bursts.

v0.4.1 [DSH v0.1.7-rc.2 / v0.2.0-rc.2]

Choose a tag to compare

@GooDAnDReaDY GooDAnDReaDY released this 10 Oct 13:55

Fixed

  • Settings registration namespace & Desktop crash protection (#55): Use canonical ENTRY_ID = \plugin-notify' instead of scoped package name in settings.register; wrap call with try/catch logging warning instead of throwing TypeError in DSH Desktop.
  • Settings form slot binding (#54): Bind UI settings.plugin.item slot key to ROW_ID (\plugin-notify'), and prioritize ROW_ID in configForms candidates over legacy NS.
  • Dynamic settings observation (#48): Make describe settings fallback reactive: observe loader/volatile-update, settings/document-updated, and settings/updated to dynamically refresh settings when edited in UI or external config.
  • Config unboxing guarantee (#47): Guarantee getConfig() always unwraps volatile boxes via unwrapConfig(config ?? {}), preventing TypeError during session/event event unboxing.
  • DSH 0.2.0-rc.1 clean activation & volatile schema (#42): Guarantee clean activation on DSH 0.2.0-rc.1 when settings.register is absent; confirm all user-facing fields in Config have .volatile() markers.

v0.4.0: Web Push PWA Background Notifications

Choose a tag to compare

@GooDAnDReaDY GooDAnDReaDY released this 05 Oct 20:02

@goodandready/dsh-plugin-notify v0.4.0

🇬🇧 English

Web Push (PWA) Background Notification Channel

  • Background Delivery: Real-time push notifications delivered via W3C Push API & Service Worker (/dsh-plugin-notify/sw.js), reaching desktop and mobile devices even when all DeepSeek Harness browser tabs are closed.
  • Instant Deep-Linking: Clicking or tapping the push notification immediately navigates to or opens the triggering session (?dshNotifySession=<id>).
  • Smart Away Filtering: webPush.onlyWhenAway automatically suppresses push notifications while a live browser client is connected to the SSE stream.
  • Zero-Config VAPID: Automatic key generation and persistent storage in $DSH_HOME/plugin-notify-state.json, with optional environment overrides (DSH_NOTIFY_VAPID_PUBLIC_KEY, DSH_NOTIFY_VAPID_PRIVATE_KEY).
  • Interactive Card Controls: Native settings card section with device push enrollment, live status, and one-click test push.
  • Full Test Coverage: Comprehensive 27 new tests covering VAPID persistence, route security, gating, and delivery (total 48 passing tests).

Special thanks to @tespio for contributing the feature (PR #2)!


🇨🇳 中文说明

Web Push (PWA) 后台推送通知通道

  • 真后台推送:基于 W3C Push API 和 Service Worker (/dsh-plugin-notify/sw.js),即使所有 DeepSeek Harness 浏览器标签页已关闭,手机或电脑也能收到推送提醒。
  • 即时深度链接:点击通知可直接跳转或激活触发事件的对应会话 (?dshNotifySession=<id>)。
  • 智能免打扰过滤:webPush.onlyWhenAway 在已有浏览器客户端连接 SSE 流时自动跳过推送,避免前台操作时的重复打扰。
  • 免配置 VAPID:初次启用自动生成密钥并持久化保存至 $DSH_HOME/plugin-notify-state.json,支持环境变量覆盖。
  • 交互式设置卡片:插件卡片中提供一键开启本机推送、实时状态查看与测试推送功能。
  • 完整测试覆盖:新增 27 项自动化测试,全套件 48 项测试全部通过。

感谢 @tespio 提交的核心贡献 (PR #2)!


🇷🇺 Русский

Фоновый канал Web Push (PWA)

  • Фоновая доставка: Настоящие push-уведомления по стандарту W3C Push API через Service Worker (/dsh-plugin-notify/sw.js), доставляемые даже при полностью закрытых вкладках DeepSeek Harness.
  • Мгновенный переход: Нажатие на уведомление сразу открывает сессию, в которой завершился ход или ожидается подтверждение (?dshNotifySession=<id>).
  • Умная фильтрация активности: webPush.onlyWhenAway автоматически пропускает web push, пока открыта активная вкладка с SSE-потоком.
  • Автогенерация VAPID: Ключи генерируются автоматически и сохраняются в $DSH_HOME/plugin-notify-state.json с поддержкой env-переменных DSH_NOTIFY_VAPID_PUBLIC_KEY и DSH_NOTIFY_VAPID_PRIVATE_KEY.
  • Интерактивное управление: В карточке настроек доступны кнопки включения push на устройстве, проверка статуса и тестовый пуш.
  • Полное покрытие тестами: 27 новых тестов, 48 тестов в наборе — все пройдены (FAIL=0 в preflight).

Спасибо @tespio за вклад в разработку (PR #2)!

v0.3.6

Choose a tag to compare

@GooDAnDReaDY GooDAnDReaDY released this 25 Sep 19:41

[0.3.6] - 2026-09-25

Fixed

  • SSE Authentication Security Boundary (#21): Replaced client-controlled header checks (\Authorization.length > 5, \sec-fetch-site) with authentic DSH session verification via \connection.requestRejection(req)\ (\Host/\Origin\ fence and browser session validation), with loopback-only fallback when connection service is absent.
  • SSE Clients & Turn Starts Lifecycle Leak (#40): Bound SSE clients, route registration, heartbeat timer, and \ urnStarts\ map to unified effect-owned lifecycle. On plugin dispose, active SSE connections are cleanly terminated with closing comment and ended, route is unregistered, and \ urnStarts\ map is cleared to ensure complete isolation on reload.

Gitea commit: 623bf90d00efa13d220074c960085ed3ea743442
Mirror commit: 6b46dc3