dsh-notify-me 1.7.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +53 -0
- package/README.en.md +204 -63
- package/README.md +201 -60
- package/lib/client.js +515 -169
- package/package.json +9 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,59 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to **dsh-notify-me** are documented here.
|
|
4
4
|
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
### 兼容性
|
|
8
|
+
- 适配 `0.2.1-rc.2`(当前 npm latest):隔离 `DSH_HOME` 起 `dsh web`,启动页 70 个条目里插件排第 59、`application` 批,三个注入目标都在它前面且解析正常;`/plugins/??dsh-notify-me/client.js&rev=…` 返回 1.7.0 构建(140,153 B);无头 Chromium 载入页面后 `apply` 执行,`window.__dshNotifyMe.debug()` 报 `uiSession: bound`、来源 `sessionStatus`。宿主侧公共 store 与 `0.2.0-rc.2` 同形(`sessionStatus`、`retainedBy.mainView`、`uiWorkspace.openSession()`),**不需要改代码**。
|
|
9
|
+
- `package.json` 的 `dsh.compatibility.dshReleases` 补 `0.2.1-rc.2`。`0.2.1-rc.2` 的宿主已不再读取该字段(安装门控只看 `peerDependencies` 与 `engines`),它现在只是给人看的记录。
|
|
10
|
+
- README(中英)同步:徽章、实测版本句、代际表、两坑段落与已知限制都补上 `0.2.1-rc.2`。
|
|
11
|
+
|
|
12
|
+
### 测试
|
|
13
|
+
- `npm test` 两套件在 0.2.1-rc.2 的 cordis 4.0.5 上通过(`smoke/smoke-test.cjs` 与真 cordis 腿 `smoke/cordis-host-test.mjs`)。
|
|
14
|
+
|
|
15
|
+
## [1.9.0] — 2026-10-20
|
|
16
|
+
|
|
17
|
+
### 新增
|
|
18
|
+
|
|
19
|
+
- **品牌标志**:`docs/brand/` 收录 24px 线稿、512→32px 应用图标、favicon 与总览图。母题是「铃铛 + 未读圆点」,设置页页眉直接用线稿版内联渲染(不依赖静态资源)。
|
|
20
|
+
|
|
21
|
+
### 变更
|
|
22
|
+
|
|
23
|
+
- **设置页重新排版**:页眉(标志 + 一句话说明)之后按「提醒方式 → 什么时候提醒 → 试一试」三段排开,音效来源、外部推送、运行环境与诊断收进折叠的「高级设置」,高级设置右侧列出内含项。原来六张卡片平铺、每行 hint 三四行的样子不再有。
|
|
24
|
+
- 每一行的说明压到一到两行,只讲一件事;「音量」作为「提示音」的附属行缩进显示,「位置」作为「页面浮层提醒」的附属行缩进显示。
|
|
25
|
+
- README 中英双语同步重排,设置章节与截图换成 1.9.0 的实拍整页图(`docs/screenshots/settings-zh.png` / `settings-en.png`)。
|
|
26
|
+
|
|
27
|
+
### 说明
|
|
28
|
+
|
|
29
|
+
- 插件对 DSH 侧仍然只用 `__ModuleLoader__.load`、`settings.section`、`locale` 三个既有面,1.9.0 没有引入任何新的宿主 API:**0.1.1-rc.2 → 0.2.1-rc.2 的插件条目照旧兼容**,退回旧宿主不需要改配置。
|
|
30
|
+
- 设置左侧导航行的图标由宿主按分区 id 硬编码(只认 account / models / agent-presets / plugins / archived-sessions),`settings.section` 没有图标字段,插件换不了,已在「已知限制」写明。
|
|
31
|
+
|
|
32
|
+
### 测试
|
|
33
|
+
|
|
34
|
+
- smoke 增补:重排后的控件仍能按 `aria-label` 定位;「高级设置」折叠态默认收起、`settingsBoot({ advanced: true })` 展开后能继续走到音效与外部推送;浮层位置下拉仍在默认可见区。
|
|
35
|
+
|
|
36
|
+
## [1.8.0] — 2026-10-20
|
|
37
|
+
|
|
38
|
+
### 新增
|
|
39
|
+
- **页面浮层提醒**(用户建议:分屏时系统通知只出现在主屏,而主屏基本不看):Windows 的横幅固定画在主屏,系统没有设置项、Chromium 也没有 API 能把它指到别的显示器,所以新增一条不经过通知中心的通道。配置项 `overlay`(默认关):在 DSH 页面角落直接画提醒卡片,窗口在哪块屏就出现在哪块屏。
|
|
40
|
+
- 位置 `overlayCorner`:`top-right` / `bottom-right` / `top-left` / `bottom-left`,默认右下,改完立即生效;
|
|
41
|
+
- 不需要通知权限,也不依赖 Service Worker;
|
|
42
|
+
- 审批卡片带「同意 / 拒绝」,走审批卡片自己的 `answer('allowed-once' | 'rejected')`——桌面端(`dsh-app://`,注册不了 Service Worker)因此也能裁决,这是系统通知给不了的;
|
|
43
|
+
- 停留时间:「需要你」20 秒、「回复完成」8 秒,带按钮的审批卡片不自动收;最多叠 4 张;点正文切回对应对话,右上角 × 关闭;
|
|
44
|
+
- 与「系统通知」互不替代,可同时开(主屏 toast + 副屏浮层),也可以只留浮层。
|
|
45
|
+
- 设置页「系统通知」下方新增「页面浮层提醒」开关与「浮层位置」下拉(开关打开时才出现位置选项)。
|
|
46
|
+
- `window.__dshNotifyMe.debug()` 新增 `overlay` 块(`enabled` / `corner` / `cards`)。
|
|
47
|
+
|
|
48
|
+
### 变更
|
|
49
|
+
- `quickFor()` 的门控从「`quickActions` 且 `toast`」放宽为「`quickActions` 且(`toast` 或 `overlay`)」:浮层是独立的按钮通道,关掉系统通知后仍可裁决。
|
|
50
|
+
- 设置页底部按钮提示按渠道如实分流:浮层开着时不再报「快捷裁决按钮暂不可用」,改为「浮层上的「同意」同样等价于「允许一次」」。
|
|
51
|
+
- 浮层的清理:HMR 重新注册时先撤掉上一份图层;关掉开关立即撤下所有卡片;审批在别处被裁决(页面审批卡片、通知按钮、会话切换)时对应浮层随之消失,不留可点的陈旧卡片。
|
|
52
|
+
- 版本号 1.7.0 → 1.8.0;`window.__dshNotifyMe.version` 与 `package.json` 同步;README 中英同步(简介、基础设置、新增「副屏与浮层提醒」一节、提醒方式、控制台配置块、已知限制),client 体积徽章 137 → 152 KiB。
|
|
53
|
+
|
|
54
|
+
### 测试
|
|
55
|
+
- `smoke/smoke-test.cjs` 新增两段。① 浮层通道:默认不动 DOM、固定图层挂在 `<body>` 下、卡片类名/角色/文案、位置切换与非法值回落、4 张上限、点卡片与 × 撤下、关开关撤层、没有 `Notification` 的环境里审批按钮走完 `decidePending()` 并给出「已模拟同意」反馈、`debug().overlay` 上报。② 设置页浮层两行:开关与位置下拉的出现与持久化、文案、按钮提示分流。
|
|
56
|
+
- `npm test` 两套件通过。
|
|
57
|
+
|
|
5
58
|
## [1.7.0] — 2026-10-16
|
|
6
59
|
|
|
7
60
|
### 新增
|
package/README.en.md
CHANGED
|
@@ -1,121 +1,246 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/brand/icon-app-128.png" width="76" height="76" alt="dsh-notify-me">
|
|
4
|
+
|
|
1
5
|
# dsh-notify-me
|
|
2
6
|
|
|
7
|
+
**Step away from DSH and know when to come back.**
|
|
8
|
+
|
|
3
9
|
[简体中文](README.md) | English
|
|
4
10
|
|
|
5
11
|
[](https://www.npmjs.com/package/dsh-notify-me)
|
|
6
|
-
[](https://www.npmjs.com/package/dsh-notify-me)
|
|
7
|
-
](https://www.npmjs.com/package/dsh-notify-me)
|
|
13
|
+
[](https://www.npmjs.com/package/dsh-notify-me)
|
|
14
|
+
[](LICENSE)
|
|
15
|
+
[](#installation)
|
|
16
|
+
[](lib/client.js)
|
|
17
|
+
[](#compatibility)
|
|
10
18
|
[](https://awesome-dsh-plugin.com)
|
|
11
19
|
|
|
12
|
-
|
|
20
|
+
</div>
|
|
13
21
|
|
|
14
|
-
|
|
22
|
+
[Install](#installation) · [Preview](#ui-preview) · [Settings](#configure-it-from-dsh-settings) · [Compatibility](#compatibility) · [Changelog](CHANGELOG.md)
|
|
15
23
|
|
|
16
|
-
|
|
24
|
+
A notification plugin for DSH Web / Desktop, so you can keep full access off without watching the page all day.
|
|
17
25
|
|
|
18
|
-
|
|
26
|
+
- **When input is needed:** approval, plan review, and questions trigger notifications, sound, and a title marker.
|
|
27
|
+
- **When a background reply finishes:** return to the result; click the notification to open its conversation.
|
|
28
|
+
- **When you leave your computer:** optionally forward alerts to Discord, Bark, Gotify, or your own webhook.
|
|
29
|
+
- **When you do not watch the primary display:** an optional in-page overlay follows the DSH window onto whichever screen you are looking at (system notifications only ever appear on the primary display).
|
|
30
|
+
|
|
31
|
+
> Keep the page or desktop app running; backgrounding / minimizing is fine. System notifications require permission. Approval buttons need a Service Worker capable Web environment (such as `http://127.0.0.1` or `https`); Desktop notifications have no buttons — turn on the in-page overlay to decide from there instead (see [Secondary displays and the overlay](#secondary-displays-and-the-overlay)).
|
|
32
|
+
|
|
33
|
+
> 🔎 Looking for it? Search `dsh-notify-me`, **message alerts**, **notification**, **desktop notification**, **reminder**, **approval alert**, **external notifications**, **Discord / Bark / Gotify push** or **可操作提醒 / 消息提醒 / 桌面通知 / 需要你操作** (npm keywords include both English and Chinese terms).
|
|
19
34
|
|
|
20
|
-
|
|
35
|
+
## UI Preview
|
|
21
36
|
|
|
22
|
-
|
|
23
|
-
| --- | --- | --- |
|
|
24
|
-
| No full access (`workspace-write` + ask) | **Waiting** — the agent stops on an approval; if you aren't watching the page, you're just burning wall-clock time | Time, growing with the number of sessions |
|
|
25
|
-
| Full access | **Irreversible risk** — you give up the ability to intercept before anything happens | Risk, independent of whether you watch |
|
|
37
|
+

|
|
26
38
|
|
|
27
|
-
|
|
39
|
+
*Plain notification example · Windows / Edge · no approval buttons.* [View full size](https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/screenshots/notify-toast.png)
|
|
28
40
|
|
|
29
|
-
|
|
41
|
+

|
|
30
42
|
|
|
31
|
-
|
|
43
|
+
*In-page overlay (1.8.0) · the real plugin rendered on a demo page · for when system notifications cannot reach the secondary display; cards appear on whichever display the DSH window is on.* [View full size](https://raw.githubusercontent.com/chromoany/dsh-notify-me/main/docs/screenshots/overlay-en.png)
|
|
32
44
|
|
|
33
|
-
|
|
45
|
+
<details>
|
|
46
|
+
<summary>See the settings interface</summary>
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
The real settings component (v1.9.0 defaults) rendered full-page in a standalone demo shell; the sidebar is kept for context, it is not the DSH shell.
|
|
51
|
+
</details>
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
### DSH Web
|
|
56
|
+
|
|
57
|
+
With the DSH CLI already installed, run in a terminal:
|
|
58
|
+
|
|
59
|
+
```powershell
|
|
60
|
+
# Install and auto-mount into the web profile
|
|
61
|
+
dsh plugin --profile web add dsh-notify-me
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Restart `dsh web`, then hard-refresh the page (Ctrl+Shift+R). If you use another Web profile, replace `web` with its actual name.
|
|
65
|
+
|
|
66
|
+
### DSH Desktop
|
|
67
|
+
|
|
68
|
+
1. Open **Plugins → Add plugin** in the desktop application.
|
|
69
|
+
2. Enter the npm package name `dsh-notify-me`, follow the installation prompts, and confirm that the plugin is enabled.
|
|
70
|
+
3. Quit DSH Desktop completely and relaunch it so the plugin loads.
|
|
71
|
+
|
|
72
|
+
The Electron application manages the `desktop` profile. Do not change the Web command above to `--profile desktop`: the CLI rejects that operation. Installing into the Web profile does not automatically install the plugin into Desktop.
|
|
34
73
|
|
|
35
|
-
|
|
36
|
-
| --- |
|
|
37
|
-
|  |
|
|
74
|
+
## First-use check
|
|
38
75
|
|
|
39
|
-
|
|
76
|
+
1. Click once in the DSH page and allow notifications when prompted. If you previously declined, allow them in the browser's site settings. The operating system must also allow notifications from the browser / DSH Desktop.
|
|
77
|
+
2. Open **Settings → Notify me**. Confirm that the section and plugin version at its foot appear, and leave the master switch, system notifications, and sound enabled.
|
|
78
|
+
3. Click **Test "reply finished"** on the settings page. A test notification should appear and sound according to your cue settings. This local test does not forward to external endpoints and ignores the "while the page is open" toggle.
|
|
79
|
+
|
|
80
|
+
Web users can also test approval buttons. On Desktop that test sends a plain notification: **no Approve / Reject buttons is the expected result**.
|
|
81
|
+
|
|
82
|
+
**Optional console check** — in environments with DevTools, you can also run:
|
|
83
|
+
|
|
84
|
+
```js
|
|
85
|
+
window.__dshNotifyMe.test("done") // "reply finished" sample
|
|
86
|
+
window.__dshNotifyMe.test("attention") // "needs your input" sample
|
|
87
|
+
window.__dshNotifyMe.test("approval") // Approve / Reject with an active Web bridge; buttonless on Desktop
|
|
88
|
+
window.__dshNotifyMe.debug() // the bridge field reports the button channel: "active" = buttons work
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
If no test notification appears, first check:
|
|
92
|
+
|
|
93
|
+
- the notification permission was declined — click anywhere on the page and choose **Allow** (address-bar lock → Site settings → Notifications → Allow → reload);
|
|
94
|
+
- the DSH process wasn't restarted after install;
|
|
95
|
+
- your OS/browser notification settings block the browser's toasts.
|
|
96
|
+
|
|
97
|
+
## Why you need it
|
|
98
|
+
|
|
99
|
+
- **Without full access (`workspace-write` + ask):** keep approval before actions, but a missed request leaves the agent waiting.
|
|
100
|
+
- **With full access:** fewer approval interruptions, at the cost of interception before actions.
|
|
101
|
+
|
|
102
|
+
dsh-notify-me decouples **supervision** from **sitting in front of the screen**: it pulls you back with a system notification only when a decision is genuinely needed (approval / plan review / question) or a reply finishes — **so you can afford to keep full access off** instead of trading away interception for speed. It does not lower the risk of full access itself (it is not a sandbox); it reduces the time spent waiting on missed approvals in ask-mode.
|
|
40
103
|
|
|
41
104
|
## What it alerts about
|
|
42
105
|
|
|
43
|
-
|
|
|
44
|
-
| --- | --- |
|
|
45
|
-
| 🔔
|
|
46
|
-
| ✅
|
|
106
|
+
| Event | Default behavior |
|
|
107
|
+
| --- | --- |
|
|
108
|
+
| 🔔 Input needed | Alerts even in the foreground; the conversation on screen keeps only a title marker |
|
|
109
|
+
| ✅ Reply finished | Alerts while the page is hidden / backgrounded |
|
|
110
|
+
|
|
111
|
+
**Input needed** covers approval requests, plan review, and questions (`ask_user_question`). Supported Web environments show Approve / Reject buttons; Desktop does not.
|
|
112
|
+
|
|
113
|
+
**Reply finished** also covers background sessions. A finished but unread session keeps the `✅ Reply finished ·` title marker until opened. Title markers are independent of the "while the page is open" toggles.
|
|
47
114
|
|
|
48
115
|
> **Background** subagent child sessions are **not** alerted about by default: DSH lists each of them as its own session, but they are steps inside the parent conversation's turn, so an alert for them is only noise. The subagent session you have open is not part of this and alerts as usual. Settings → "Ignore subagent sessions" turns the mute off.
|
|
49
116
|
|
|
50
117
|
## Configure it from DSH Settings
|
|
51
118
|
|
|
52
|
-
Open **Settings → Notify me
|
|
119
|
+
Open **Settings → Notify me**. The page runs as how you get told, when to alert, and a try-it block; the knobs you rarely touch fold into **Advanced** at the bottom.
|
|
120
|
+
|
|
121
|
+
### How you get told
|
|
122
|
+
|
|
123
|
+
- **Enable reminders**: master switch — off means no toasts, no sounds, and the tab title is left alone;
|
|
124
|
+
- **System notifications** (on by default): native toasts through the browser, landing in the Windows / macOS notification center;
|
|
125
|
+
- **In-page overlay** (off by default): cards drawn in the page corner, on whichever display the window sits on — system notifications only land on the primary display. No permission needed, and the Desktop shell can Approve / Reject right on the card. Runs alongside toasts; pick one of four corners when expanded. See [Secondary displays and the overlay](#secondary-displays-and-the-overlay);
|
|
126
|
+
- **Sound / Volume**: master cue switch and a volume slider; what it plays comes from Advanced → Alert sound;
|
|
127
|
+
- **Decide approvals from the toast** (on by default): approval toasts carry Approve / Reject that settle the request in place. **Desktop notifications have no buttons** (`dsh-app://` cannot register a Service Worker) — leave the overlay on instead; the page states plainly which channel can carry buttons right now.
|
|
128
|
+
|
|
129
|
+
### Secondary displays and the overlay
|
|
130
|
+
|
|
131
|
+
Windows draws system notification banners on the primary display only. There is no setting in Windows and no API in the browser to aim one at another monitor, so with DSH parked on a second screen and the primary display unwatched, a toast is as good as not sent.
|
|
132
|
+
|
|
133
|
+
The **in-page overlay** skips the notification center and draws the card inside the DSH page instead: wherever the window is, the card is there too.
|
|
134
|
+
|
|
135
|
+
- **Position** — top right / bottom right / top left / bottom left, default bottom right; changes apply immediately;
|
|
136
|
+
- **No notification permission needed** — it works when permission was never granted, and on the Desktop shell where buttonless toasts are all the OS channel can do;
|
|
137
|
+
- **Approval cards carry Approve / Reject** — the same decision as Allow once / Reject on the approval card, and they work on the Desktop too (no Service Worker involved). Clicking the card body opens its conversation;
|
|
138
|
+
- **Lifetime** — "needs you" cards retire after 20s, "reply finished" after 8s; an approval card with buttons stays until it is decided or closed. At most 4 cards stack at once;
|
|
139
|
+
- **Relation to system notifications** — the two switches are independent. With both on, the primary display gets toasts and the second screen gets the overlay; the overlay alone is also a valid setup.
|
|
140
|
+
|
|
141
|
+
The overlay only knows which screen the window is on, not which screen you are looking at. If the window stays on the primary display while you watch another one, it stays invisible — same as a toast.
|
|
142
|
+
|
|
143
|
+
### When to alert
|
|
144
|
+
|
|
145
|
+
- **Also alert "needs you" while the page is open** (on): turn it off to hear only from the background;
|
|
146
|
+
- **Stay quiet for the conversation on screen** (on): a wait belonging to the conversation you are looking at keeps only the tab marker so the approval card stays readable; backgrounding restores alerts;
|
|
147
|
+
- **Also alert "reply finished" while the page is open** (off): by default only background finishes alert;
|
|
148
|
+
- **Ignore subagent sessions** (on): skip background sessions spawned by a subagent — the parent conversation covers them; the one you have open still alerts;
|
|
149
|
+
- **Click a toast to open that conversation** (on): the click brings DSH forward and switches conversation; with several tabs open only one is raised, and off means a click does nothing. Desktop window-raising details live in [Runtime & diagnostics](#runtime--diagnostics).
|
|
150
|
+
|
|
151
|
+
### Try it
|
|
152
|
+
|
|
153
|
+
Three buttons send one "needs you", one "reply finished" and one "approval buttons" test alert with the current settings — deliberately not limited by the switches above. A line underneath states which channel can carry approval buttons right now.
|
|
154
|
+
|
|
155
|
+
The plugin version sits at the bottom of the page (`dsh-notify-me v…`) — copy that line when reporting a bug or checking whether an update landed.
|
|
156
|
+
|
|
157
|
+
### Advanced
|
|
158
|
+
|
|
159
|
+
Collapsed by default. It holds the three things you rarely touch: alert sounds, external forwarding, and runtime & diagnostics — each documented below.
|
|
160
|
+
|
|
161
|
+
### Sound
|
|
162
|
+
|
|
163
|
+
Choose a built-in cue, custom audio file, or system notification sound independently for each alert kind.
|
|
164
|
+
|
|
165
|
+
<details>
|
|
166
|
+
<summary>Custom audio, previews, and fallback behavior</summary>
|
|
53
167
|
|
|
54
|
-
- **Enable reminders** — master switch; when off, no toasts, no sounds and the tab title is never touched;
|
|
55
|
-
- **Environment** (auto-detect by default) — identifies Web vs Desktop (DSH Desktop, `dsh-app://`) from the page protocol, with a manual override for hosts where detection comes out wrong: on the Desktop a toast click rides the `dsh://` deep link to raise the window and quick-decision buttons are unavailable; on the Web it is `window.focus()` plus the Service Worker bridge. Whenever the override disagrees with detection, the settings page says what detection saw;
|
|
56
|
-
- **System notifications / Sound / Volume** — toast toggle, cue toggle and a volume slider;
|
|
57
168
|
- **Alert sound** (picked separately for "needs you" and "reply finished") — built-in cue (default) / custom audio file / system notification sound. "Custom audio file" takes one local audio file in the settings page (1 MiB limit, stored in the browser, with preview and remove); "system notification sound" plays no plugin cue at all — the toast still appears and the operating system supplies the sound, so its timbre follows your system notification settings; in that mode "Preview" sends a test alert instead, because the sound only exists as part of a toast and that is the sound you hear. Any source that has no file, cannot be read, or does not fit falls back to the built-in cue, so an alert never goes silent;
|
|
169
|
+
|
|
170
|
+
</details>
|
|
171
|
+
|
|
172
|
+
### External push
|
|
173
|
+
|
|
174
|
+
Off by default. Supports Discord Webhook / Bark / Gotify / custom webhooks. Alert text is sent to the addresses you enter; use trusted endpoints.
|
|
175
|
+
|
|
176
|
+
<details>
|
|
177
|
+
<summary>Target URLs, forwarding switches, and test messages</summary>
|
|
178
|
+
|
|
58
179
|
- **External notifications** (default off) — forward each alert to your own push endpoints as well, so it reaches you away from the machine: **Discord Webhook** / **Bark** / **Gotify** / **custom webhook**, any number of targets, each with a type and URL (Discord takes the webhook URL; Bark `https://api.day.app/<device key>`; Gotify `https://<server>/message?token=<app token>`; a custom endpoint receives one POST of JSON: `{source, event, title, body, sessionId, time}`). "Forward 'needs you'" and "Forward 'reply finished'" switch independently; **Send test notification** sends one test message to every target (not limited by those two switches, and never pretending to be a real alert). Forwarding follows exactly the same trigger rules as local alerts ("stay quiet for the conversation on screen" and friends apply to it too); the alert text is sent as-is to the addresses you fill in, so **only use endpoints you trust**;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
|
|
180
|
+
|
|
181
|
+
</details>
|
|
182
|
+
|
|
183
|
+
### Runtime & diagnostics
|
|
184
|
+
|
|
185
|
+
The last block inside Advanced. The page protocol is detected automatically to tell Web from Desktop (`dsh-app://`); override it by hand if detection is wrong — Desktop clicks raise the window through the `dsh://` deep link and carry no quick-decision buttons, while Web uses `window.focus()` plus the Service Worker bridge. When the override disagrees with detection the page says so.
|
|
186
|
+
|
|
187
|
+
<details>
|
|
188
|
+
<summary>Alert language, Desktop window raising, reset</summary>
|
|
189
|
+
|
|
190
|
+
- **Alert language**: follow the UI / Simplified Chinese / English — governs alert copy and the `🔔 …` title marker;
|
|
191
|
+
- **How the Desktop window is raised**: `window.focus()` cannot lift a native Electron window, so since 1.5.2 the page drives the app's own `dsh://open` deep link — it works even when the window is parked in the tray;
|
|
192
|
+
- **Reset settings**: restores every switch and cue setting to the factory defaults (webhook targets and chosen audio files are kept).
|
|
193
|
+
|
|
194
|
+
</details>
|
|
195
|
+
|
|
196
|
+
> The settings sidebar icon is rendered by the DSH settings shell: it hard-codes icons per section id (account / models / agent-presets / plugins / archived-sessions) and gives every other section the default gear — `settings.section` has no icon field, so the plugin's bell can only appear inside its own page.
|
|
67
197
|
|
|
68
198
|
> Notification permission is required: click once on the page → **Allow** (or address-bar lock → Site settings → Notifications → Allow → reload). On macOS, also allow the browser under System Settings → Notifications.
|
|
69
199
|
|
|
70
200
|
## How it alerts
|
|
71
201
|
|
|
72
|
-
- **System notification** — a toast through the browser into the Windows action center / macOS Notification Center (clicking it opens the conversation it came from;
|
|
202
|
+
- **System notification** — a toast through the browser into the Windows action center / macOS Notification Center (clicking it opens the conversation it came from; supported Web environments offer approval buttons, Desktop does not)
|
|
203
|
+
- **In-page overlay** (optional, default off) — an alert card drawn in the corner of the DSH page, on whatever display the window is on, optionally with Approve / Reject buttons; see [Secondary displays and the overlay](#secondary-displays-and-the-overlay)
|
|
73
204
|
- **Sound** — WebAudio beeps by default (distinct patterns for "needs you" vs "done"); each kind can instead play a picked audio file, or hand the sound over to the operating system's own notification sound
|
|
74
205
|
- **Tab title marker** — while something is waiting on you, the tab title is prefixed with `🔔 Action needed · …` / `🔔 需要你 · …`; while a background session is **finished but unread**, with `✅ Reply finished · …` / `✅ 回复完成 · …`, gone once you open that session (or it starts running again). Both kinds can be up together, "needs you" first; a host title change is rebased under the markers
|
|
75
206
|
- **External notifications** (optional, default off) — the same alert is also forwarded to the push targets you configure: Discord Webhook / Bark / Gotify / custom webhook — so the push channel on your phone picks it up while you step away from the machine
|
|
76
207
|
|
|
77
208
|
This is a **browser-layer** plugin: the DSH page must stay open (minimized or backgrounded is fine — that's exactly the "away" state it watches for).
|
|
78
209
|
|
|
79
|
-
##
|
|
210
|
+
## Compatibility
|
|
80
211
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
212
|
+
Per-release adaptation records live in [package.json](package.json), under `dsh.compatibility.dshReleases`. The current host (`0.2.1-rc.2`) no longer reads that field — installation gates only on `peerDependencies` and `engines` — so it is a human-readable record, not a gate.
|
|
213
|
+
|
|
214
|
+
Verified to actually activate on `0.1.2-rc.1`, `0.1.5-rc.1`, `0.1.5-rc.2` and `0.2.0-rc.2` (each booted in its own profile: the plugin entry lands in the boot page's `__DSH_BOOT__` with its inject dependencies resolved, `/plugins/??dsh-notify-me/client.js&rev=…` serves a build containing the new code, and the Settings → Notifications section registers, i.e. the plugin's `apply` really runs), and previously on `0.1.1-rc.2`.
|
|
215
|
+
|
|
216
|
+
`0.2.1-rc.2` (current latest) got its own isolated run: an isolated `DSH_HOME` booting `dsh web` (70 boot entries) placed the plugin entry 59th, in the `application` batch, with all three inject targets present and ordered before it; `/plugins/??dsh-notify-me/client.js&rev=…` served the 1.7.0 source build (140,153 B); loaded in a headless Chromium page, `apply` ran — `window.__dshNotifyMe.debug()` reported `uiSession: bound`, `uiSessionSource: sessionStatus`, `bridge: active`. Host-side shapes match `0.2.0-rc.2`; no plugin code change was needed.
|
|
85
217
|
|
|
86
|
-
|
|
218
|
+
<details>
|
|
219
|
+
<summary>Host generations and adaptation diagnostics</summary>
|
|
87
220
|
|
|
88
|
-
|
|
221
|
+
The plugin picks its interaction source per host generation; the table below marks where each shape appeared — it is not a gate (the current host does not read `dshReleases`):
|
|
89
222
|
|
|
90
223
|
| Host generation | "Needs you" interaction source | Current session | Toast-click navigation |
|
|
91
224
|
| --- | --- | --- | --- |
|
|
92
225
|
| `<= 0.1.2-alpha.1` | controller snapshot `pending[]` | snapshot `current` | `sessions.open()` |
|
|
93
226
|
| `0.1.2-alpha.2 .. 0.1.6-alpha.1` | `uiSession.pendingInteractions` | snapshot `current` | `sessions.open()` |
|
|
94
|
-
| `>= 0.1.6-alpha.2` (incl. `0.2.0-rc.2`) | `uiSession.sessionStatus` | `retainedBy.mainView` | `uiWorkspace.openSession()` |
|
|
227
|
+
| `>= 0.1.6-alpha.2` (incl. `0.2.0-rc.2`, `0.2.1-rc.2`) | `uiSession.sessionStatus` | `retainedBy.mainView` | `uiWorkspace.openSession()` |
|
|
95
228
|
|
|
96
|
-
The ranges are illustrative: the plugin picks its source by store shape (whenever `sessionStatus` exists it takes the new path); the version numbers only mark where each shape appeared. The `peerDependencies` range in `package.json`
|
|
229
|
+
The ranges are illustrative: the plugin picks its source by store shape (whenever `sessionStatus` exists it takes the new path); the version numbers only mark where each shape appeared. The `peerDependencies` range in `package.json` shapes npm's peer warning — `0.2.1-rc.2` already falls inside `>=0.2.0-rc.1 <0.3.0-0`, so no exemption is needed; `dshReleases` is just an archive, real compatibility is per-release testing, and untested new versions fall back to shape-driven behaviour.
|
|
97
230
|
|
|
98
|
-
|
|
231
|
+
Two traps are worth remembering: a package listed in `dsh.client.inject` that a newer runtime no longer ships parks the client entry at `pending (waiting for services: …)` forever — which is what broke 1.1.3 on `0.1.2-rc.1` and later; and when the host renames a store or a field nothing throws, alerts just go **silent** — `0.2.0-rc.2` moved `pendingInteractions`→`sessionStatus`, `list.current`→`retainedBy.mainView` and `sessions.open()`→`uiWorkspace.openSession()`. So every adaptation must confirm `window.__dshNotifyMe.debug()` reports `bound` and which source answered. `0.2.1-rc.2` changed neither: `sessionStatus` is still a Map of `{running, pendingInteraction, completionUnread}`, `uiWorkspace.openSession(id)` is unchanged, and the session list still has no `current`.
|
|
99
232
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
```js
|
|
103
|
-
window.__dshNotifyMe.test("done") // "reply finished" sample
|
|
104
|
-
window.__dshNotifyMe.test("attention") // "needs your input" sample
|
|
105
|
-
window.__dshNotifyMe.test("approval") // "approval buttons" sample: try the Approve / Reject buttons on the toast
|
|
106
|
-
window.__dshNotifyMe.debug() // the bridge field reports the button channel: "active" = buttons work
|
|
107
|
-
```
|
|
233
|
+
</details>
|
|
108
234
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
- the notification permission was declined — click anywhere on the page and choose **Allow** (address-bar lock → Site settings → Notifications → Allow → reload);
|
|
112
|
-
- the DSH process wasn't restarted after install;
|
|
113
|
-
- your OS/browser notification settings block the browser's toasts.
|
|
235
|
+
`1.9.0` neither widens nor narrows that range: the settings page is plain React rendering over the existing CSS variables (every colour carries a fallback) and adds no host API. The overlay, title markers and window raising still go through the 1.7 / 1.8 paths, so **plugin entries stay compatible from 0.1.1-rc.2 through 0.2.1-rc.2**, and stepping back to an older host needs no config change. The only new surface is visual: the bell in the page header is the plugin's own SVG (`docs/brand/`).
|
|
114
236
|
|
|
115
237
|
## Advanced: console configuration
|
|
116
238
|
|
|
117
239
|
The Settings page is the primary entry; preferences live in `localStorage` (key `dshNotifyMe.config`) and can be scripted from the console:
|
|
118
240
|
|
|
241
|
+
<details>
|
|
242
|
+
<summary>Console API and storage reference</summary>
|
|
243
|
+
|
|
119
244
|
```js
|
|
120
245
|
window.__dshNotifyMe.config // view current config
|
|
121
246
|
window.__dshNotifyMe.setConfig({
|
|
@@ -132,6 +257,8 @@ window.__dshNotifyMe.setConfig({
|
|
|
132
257
|
volume: 0.5, // 0..1
|
|
133
258
|
autoFocus: true, // clicking a toast opens the conversation it came from
|
|
134
259
|
quickActions: true, // Approve / Reject buttons on approval toasts
|
|
260
|
+
overlay: false, // in-page overlay alert (follows the DSH window to its display; no notification permission needed)
|
|
261
|
+
overlayCorner: "bottom-right", // overlay anchor: 'top-right' | 'bottom-right' | 'top-left' | 'bottom-left'
|
|
135
262
|
externalEnabled: false, // external-notification forwarding master switch (default off: no endpoint, nothing is sent)
|
|
136
263
|
externalAttention: true, // forward "needs you" (exactly the same trigger rules as local alerts)
|
|
137
264
|
externalDone: true, // forward "reply finished"
|
|
@@ -139,15 +266,24 @@ window.__dshNotifyMe.setConfig({
|
|
|
139
266
|
})
|
|
140
267
|
window.__dshNotifyMe.resetConfig() // restore defaults (also drops any picked audio files)
|
|
141
268
|
window.__dshNotifyMe.decide("approval:3", "allowed-once") // programmatic decision: "allowed-once" | "rejected"
|
|
142
|
-
window.__dshNotifyMe.testExternal() //
|
|
269
|
+
window.__dshNotifyMe.testExternal() // explicit outbound test to valid targets; resolves {sent, unverified, failed, statuses}
|
|
143
270
|
```
|
|
144
271
|
|
|
272
|
+
> **External-test switch behavior:** the settings page's "Send test notification" button requires both the plugin and external-forwarding master switches to be on, but ignores the two per-kind forwarding switches. The console `testExternal()` call is an explicit test: with valid configured targets, it sends to them even when those master switches are off; with no valid targets it sends nothing. Ordinary `test("done")` / `test("attention")` / `test("approval")` calls only test local alerts and never forward externally.
|
|
273
|
+
|
|
145
274
|
> Picked audio files do not live in `dshNotifyMe.config`: each kind gets its own key (`dshNotifyMe.sound.done` / `dshNotifyMe.sound.attention`, holding `{name, size, data}` with a data URL), because a file inflates by ~1.37x once base64-encoded and would slow down every config read. `resetConfig()` clears both keys along with the config.
|
|
146
275
|
>
|
|
147
276
|
> To see which source is live, check `soundDone` / `soundAttention` and `customSoundDone` / `customSoundAttention` in `window.__dshNotifyMe.debug()`.
|
|
148
277
|
|
|
278
|
+
</details>
|
|
279
|
+
|
|
149
280
|
## How it works
|
|
150
281
|
|
|
282
|
+
The reminder core watches session state and pending interactions. The page handles approval decisions; Desktop window activation uses the app deep link.
|
|
283
|
+
|
|
284
|
+
<details>
|
|
285
|
+
<summary>Event sources, approval bridge, and Desktop window activation</summary>
|
|
286
|
+
|
|
151
287
|
The reminder core picks its interaction source per host generation (see the table above); the current session always comes from the client `sessions` service:
|
|
152
288
|
|
|
153
289
|
- the **selected session's** `SessionSnapshot`: a `running: true → false` edge means a reply finished;
|
|
@@ -169,20 +305,25 @@ DSH Desktop is a thin Electron shell and its page lives under `dsh-app://app`: D
|
|
|
169
305
|
|
|
170
306
|
Verified on the real shell (DSH Desktop 0.2.0-rc.2, three rounds of retesting in issue #9): a toast click raises the window and switches the conversation in one step, stable across sessions and with the window in the background. Timing of the fire is what makes the chain work: the deep link must be launched from a **user-gesture handler** — the notification's `onclick` carries one, which is why the product path works — while gesture-less scripted injection (an iframe appended from a CDP evaluate, say) is silently dropped by Chromium and the external protocol never launches, which looks exactly like the channel being blocked.
|
|
171
307
|
|
|
308
|
+
</details>
|
|
309
|
+
|
|
172
310
|
## Known limitations
|
|
173
311
|
|
|
174
312
|
- The page must be open for alerts to fire (background tab / minimized is fine; closing the tab stops it — that's inherent to a browser-layer plugin).
|
|
175
313
|
- Notifications appear through the browser, so the browser needs "show notifications" permission in the OS notification settings, and notification-center "Do Not Disturb" must not suppress them.
|
|
176
314
|
- The first sound/toast of each page load needs one user click on the page first (browser autoplay + permission policy).
|
|
177
315
|
- Toasts are only produced once the notification permission is granted; declining means sound + title marker only.
|
|
316
|
+
- System notification banners are drawn on the primary display only: Windows has no setting and Chromium no API to aim one at another monitor, so on a multi-monitor setup the second screen never receives them. Use the in-page overlay for that — it follows the DSH window to its display.
|
|
178
317
|
- Quick-decision buttons need a Service Worker: they work on `http://127.0.0.1` and `https`, not on plain `http://192.168.x.x`-style LAN addresses, and some browsers or desktop hosts never render notification buttons. **The Desktop (`dsh-app://`) is tested and cannot register a Service Worker**, so buttons never render there and approval toasts fall back to their buttonless form. The `bridge` field of `window.__dshNotifyMe.debug()` says why; everything else keeps working.
|
|
179
318
|
- macOS: in the browser, alerts, sounds, the title marker and toast-click navigation carry no OS assumptions and work as on Windows. Two caveats: DSH Desktop (Electron) notifications require the app to be code-signed — unsigned builds simply emit no notification — and whether the official macOS build satisfies that is untested; and notification buttons on the macOS desktop host are likewise untested (the Windows desktop host is tested and renders none, see the line above), falling back to the buttonless form above.
|
|
180
319
|
- Config lives in browser `localStorage`: switching browsers/devices or clearing site data returns to defaults (one-click restore in the Settings page).
|
|
181
|
-
- On `>= 0.1.6` (including `0.2.0-rc.2`) the "reply finished" toast body carries only the session label, no assistant snippet: host snapshots no longer expose `nodes`. The alert itself still fires.
|
|
320
|
+
- On `>= 0.1.6` (including `0.2.0-rc.2`, `0.2.1-rc.2`) the "reply finished" toast body carries only the session label, no assistant snippet: host snapshots no longer expose `nodes`. The alert itself still fires.
|
|
182
321
|
- The title marker is written into `document.title` alongside the host: when the host recomputes the title it can overwrite the marker until the next alert event rewrites it.
|
|
183
322
|
- "Stay quiet for the conversation on screen" is judged by `document.hidden`: a window fully covered by other apps still counts as visible, so waits in the current conversation stay quiet there too.
|
|
184
323
|
- External notification forwarding is subject to browser CORS rules: an endpoint that does not allow cross-origin requests falls back to a "sent but unverifiable" delivery (no-cors) and is reported honestly as such; Discord webhooks do allow cross-origin, so delivery to them is confirmed. HTTP errors are recorded as failures and never blindly retried. Forwarding runs only after the local alert has decided to fire, so anything the rules silence is never sent out.
|
|
185
324
|
|
|
325
|
+
- **The settings sidebar row keeps the host's default gear icon**: the settings shell hard-codes icons per section id, gives every other section the default gear, and `settings.section` exposes no icon field — the plugin cannot change it. Its own bell only appears inside the settings page and in this README.
|
|
326
|
+
|
|
186
327
|
## Development
|
|
187
328
|
|
|
188
329
|
```powershell
|