dsh-notify-me 1.10.3 → 1.10.4

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 CHANGED
@@ -2,6 +2,20 @@
2
2
 
3
3
  All notable changes to **dsh-notify-me** are documented here.
4
4
 
5
+ ## [1.10.4] — 2026-10-21
6
+
7
+ ### 新增
8
+
9
+ - **桌面端审批按钮落到页内卡片**:桌面壳在 `dsh-app:` 协议下拿不到 Service Worker(注册被拒),带按钮的审批通知因此只剩标题、点不出「同意 / 拒绝」。现在这种拿不到 SW 的情形会在窗口角落画一张卡片:审批标题与正文、`同意` / `拒绝` 两个按钮、正文过长时可就地展开「详情」,12 秒自动收起,同一条审批不叠第二张卡。按钮走的是和系统通知完全同一条裁决路径(`allowed-once` / `rejected`),裁完即撤卡。Web 端(SW 可用)行为不变,仍是带按钮的系统通知。
10
+
11
+ ### 修复
12
+
13
+ - 页面里写的 `api.version` 与 `package.json` 对齐(1.10.3 的发版提交只改了 `package.json`,页内版本号停在 1.10.2,冒烟断言因此一开始就是红的)。
14
+
15
+ ### 测试
16
+
17
+ - 冒烟新增 12 组断言覆盖桌面降级卡片:出现时机、两个按钮、详情展开/收起、点卡片本体不撤卡、同意、拒绝、审批从状态里消失时撤卡、同一条审批不叠卡、开关关闭时不画卡、12 秒回收、Web 路径不回归。
18
+
5
19
  ## [1.10.3] — 2026-10-21
6
20
 
7
21
  ### 修复
package/README.en.md CHANGED
@@ -77,14 +77,14 @@ The Electron application manages the `desktop` profile. Do not change the Web co
77
77
  2. Open **Settings → Notify me**. Confirm that the section and plugin version at its foot appear, and leave the master switch, the alert type on system notifications, and sound enabled.
78
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
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**.
80
+ Web users can also test approval buttons. On Desktop the shell cannot register a Service Worker, so this test draws an in-page card with Approve / Reject in the window corner (since 1.10.4; earlier versions sent a plain notification).
81
81
 
82
82
  **Optional console check** — in environments with DevTools, you can also run:
83
83
 
84
84
  ```js
85
85
  window.__dshNotifyMe.test("done") // "reply finished" sample
86
86
  window.__dshNotifyMe.test("attention") // "needs your input" sample
87
- window.__dshNotifyMe.test("approval") // Approve / Reject with an active Web bridge; buttonless on Desktop
87
+ window.__dshNotifyMe.test("approval") // Approve / Reject with an active Web bridge; an in-page card on Desktop
88
88
  window.__dshNotifyMe.debug() // the bridge field reports the button channel: "active" = buttons work
89
89
  ```
90
90
 
@@ -108,7 +108,7 @@ dsh-notify-me decouples **supervision** from **sitting in front of the screen**:
108
108
  | 🔔 Input needed | Alerts even in the foreground; the conversation on screen keeps only a title marker |
109
109
  | ✅ Reply finished | Alerts while the page is hidden / backgrounded |
110
110
 
111
- **Input needed** covers approval requests, plan review, and questions (`ask_user_question`). Supported Web environments show Approve / Reject buttons; Desktop does not.
111
+ **Input needed** covers approval requests, plan review, and questions (`ask_user_question`). Approvals carry Approve / Reject: on Web as a system notification with buttons, on Desktop (which cannot register a Service Worker) as a card drawn in the window corner.
112
112
 
113
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.
114
114
 
@@ -125,7 +125,7 @@ Open **Settings → Notify me**. The page runs as how you get told, when to aler
125
125
  - **System notifications** (default): native toasts landing in the Windows / macOS notification center; needs notification permission;
126
126
  - **In-page overlay**: 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. With the overlay chosen, a Corner row appears; open it to pick one of four positions. See [Secondary displays and the overlay](#secondary-displays-and-the-overlay);
127
127
  - **Sound / Volume**: the switch is direct; the slider folds into that row — click the title (▸ turns into ▾) to reveal it. What it plays comes from Advanced → Alert sound;
128
- - **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) — pick the in-page overlay as the channel instead; the page states plainly which channel can carry buttons right now.
128
+ - **Decide approvals from the toast** (on by default): approvals carry Approve / Reject that settle the request in place. On Web that is a system notification with buttons; on Desktop `dsh-app://` cannot register a Service Worker, so the buttons are drawn on a card in the window corner (auto-dismissed after 12 s, one card per approval). You can also switch the channel to the in-page overlay and decide there.
129
129
 
130
130
  ### Secondary displays and the overlay
131
131
 
package/README.md CHANGED
@@ -77,14 +77,14 @@ dsh plugin --profile web add dsh-notify-me
77
77
  2. 打开 **设置 → 通知提醒**,确认出现该分区及底部插件版本号,保持「启用提醒」「提示音」开启,通知类型先留「系统通知」。
78
78
  3. 点击设置页的「测试『回复完成』」按钮:应出现一条测试通知,并按当前音效设置播放声音。这个本地测试不会转发到外部通知端点,也不受「页面打开时也提醒」开关限制。
79
79
 
80
- Web 用户可再测试审批按钮;桌面端该测试只发普通通知,**没有「同意 / 拒绝」按钮属于预期行为**。
80
+ Web 用户可再测试审批按钮。桌面端拿不到 Service Worker,这条测试会在窗口角落画一张带「同意 / 拒绝」的卡片(1.10.4 起;之前的版本这里只发普通通知)。
81
81
 
82
82
  **控制台验证(可选)** — 支持 DevTools 的环境也可执行:
83
83
 
84
84
  ```js
85
85
  window.__dshNotifyMe.test("done") // 「完成」示例
86
86
  window.__dshNotifyMe.test("attention") // 「需要你」示例
87
- window.__dshNotifyMe.test("approval") // Web 桥可用时带「同意 / 拒绝」按钮;桌面端为无按钮通知
87
+ window.__dshNotifyMe.test("approval") // 桥可用时带「同意 / 拒绝」按钮;桌面端画在窗口角落的卡片上
88
88
  window.__dshNotifyMe.debug() // 桥接状态看 bridge 字段,active = 按钮可用
89
89
  ```
90
90
 
@@ -104,7 +104,7 @@ dsh-notify-me 把「监督」和「守在屏幕前」解耦:只在真的出现
104
104
  | 🔔 需要你操作 | 页面可见也提醒;当前对话只留标题标记 |
105
105
  | ✅ 回复完成 | 页面隐藏 / 后台时提醒 |
106
106
 
107
- **需要你操作**包括审批请求、方案待确认(plan review)和提问(`ask_user_question`)。支持快捷裁决的 Web 环境会显示「同意 / 拒绝」按钮,桌面端无按钮。
107
+ **需要你操作**包括审批请求、方案待确认(plan review)和提问(`ask_user_question`)。审批带「同意 / 拒绝」:Web 走带按钮的系统通知,桌面端(注册不了 Service Worker)改画在窗口角落的卡片上。
108
108
 
109
109
  **回复完成**也覆盖后台会话;完成但还没看时,标题带 `✅ 回复完成 ·` 标记,打开对应会话即撤。标题标记不受「页面打开时也提醒」开关限制。
110
110
 
@@ -121,7 +121,7 @@ dsh-notify-me 把「监督」和「守在屏幕前」解耦:只在真的出现
121
121
  - **系统通知**(默认):进 Windows / macOS 通知中心,需要通知权限;
122
122
  - **页面浮层**:在 DSH 页面角落画提醒卡片,窗口在哪块屏它就在哪块屏——系统通知只会画在主屏,主屏不看时用它;不需要通知权限,桌面端也能在卡片上直接「同意 / 拒绝」。选中后卡片里会多出「浮层位置」子行,点开可选四个角落,见[副屏与浮层提醒](#副屏与浮层提醒);
123
123
  - **提示音 / 音量**:开关直接切;音量滑块收在该行里,点一下标题(▸ 变成 ▾)展开。具体播什么由「高级设置 → 音效来源」决定;
124
- - **审批通知上直接裁决**(默认开):审批通知带「同意 / 拒绝」,点一下即完成裁决,不用切回页面。**桌面端的通知没有按钮**(`dsh-app://` 页面无法注册 Service Worker),需要按钮就打开「页面浮层提醒」,改在浮层上裁决;设置页会如实说明当前哪种渠道能给按钮。
124
+ - **审批通知上直接裁决**(默认开):审批带「同意 / 拒绝」,点一下即完成裁决,不用切回页面。Web 走带按钮的系统通知;桌面端 `dsh-app://` 注册不了 Service Worker,于是把按钮画在窗口角落的卡片上(12 秒自动收起,同一条审批不叠第二张卡)。也可以把「通知类型」换成「页面浮层」,改在浮层卡片上裁决。
125
125
 
126
126
  ### 副屏与浮层提醒
127
127
 
package/lib/client.js CHANGED
@@ -321,13 +321,18 @@
321
321
  // Persist a patch, swap the live module config and re-apply any active
322
322
  // title marker (its prefix follows the notification language).
323
323
  function setConfigLocal(patch) {
324
+ var wasOverlay = config.channel === "overlay";
324
325
  config = writeConfig(patch);
325
326
  applyTitle();
326
- // Overlay re-apply: switching it off takes the cards down at once and a
327
- // new corner moves the layer without waiting for the next alert.
327
+ // Overlay re-apply: leaving the overlay channel takes its cards down at
328
+ // once, and a new corner moves the layer without waiting for the next
329
+ // alert. Cards can also exist on the toast channel (the desktop fallback),
330
+ // so an unrelated patch must not sweep them away.
328
331
  try {
329
- if (config.channel !== "overlay") clearOverlays();
330
- else if (overlayLayer) overlayLayer.className = "dnm-ov-layer dnm-ov-" + overlayCorner();
332
+ if (config.channel !== "overlay") {
333
+ if (wasOverlay) clearOverlays();
334
+ else if (overlayLayer) overlayLayer.className = "dnm-ov-layer dnm-ov-" + overlayCorner();
335
+ } else if (overlayLayer) overlayLayer.className = "dnm-ov-layer dnm-ov-" + overlayCorner();
331
336
  } catch (e) {}
332
337
  return config;
333
338
  }
@@ -384,6 +389,8 @@
384
389
  approve: "同意",
385
390
  reject: "拒绝",
386
391
  dismiss: "关闭这条提醒",
392
+ details: "详情",
393
+ collapse: "收起",
387
394
  testAttention: "这是一条测试提醒:DSH 需要你的操作",
388
395
  testDone: "测试提醒 · 回复完成示例",
389
396
  testApproval: "这是一条测试审批:点「同意 / 拒绝」试试快捷裁决",
@@ -411,6 +418,8 @@
411
418
  approve: "Approve",
412
419
  reject: "Reject",
413
420
  dismiss: "Dismiss this alert",
421
+ details: "Details",
422
+ collapse: "Collapse",
414
423
  testAttention: "This is a test alert: DSH is waiting for your input",
415
424
  testDone: "Test alert · reply-finished sample",
416
425
  testApproval: "This is a test approval: try the Approve / Reject buttons to settle it",
@@ -833,9 +842,11 @@
833
842
  ".dnm-ov-attention .dnm-ov-dot{color:var(--dsw-alias-state-warning-primary,#f59e0b);opacity:1}" +
834
843
  ".dnm-ov-done .dnm-ov-dot{color:var(--dsw-alias-state-success-primary,#22c55e);opacity:1}" +
835
844
  ".dnm-ov-title{flex:1;min-width:0;font-weight:600;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}" +
836
- ".dnm-ov-x{flex:none;border:0;background:transparent;color:inherit;opacity:.6;font-size:15px;line-height:15px;padding:0 2px;cursor:pointer;font-family:inherit}" +
837
- ".dnm-ov-x:hover{opacity:1}" +
845
+ ".dnm-ov-x,.dnm-ov-more{flex:none;border:0;background:transparent;color:inherit;opacity:.6;font-size:15px;line-height:15px;padding:0 2px;cursor:pointer;font-family:inherit}" +
846
+ ".dnm-ov-x:hover,.dnm-ov-more:hover{opacity:1}" +
847
+ ".dnm-ov-more{font-size:11px;opacity:.8;white-space:nowrap}" +
838
848
  ".dnm-ov-body{color:var(--dsw-alias-label-secondary,rgba(220,222,226,.86));font-size:12px;line-height:18px;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden;word-break:break-word}" +
849
+ ".dnm-ov.dnm-ov-open .dnm-ov-body{display:block;-webkit-line-clamp:unset;max-height:40vh;overflow:auto}" +
839
850
  ".dnm-ov-actions{display:flex;gap:8px;margin-top:2px}" +
840
851
  ".dnm-ov-btn{flex:1;border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.4));background:var(--dsw-alias-bg-layer-1,rgba(255,255,255,.06));color:inherit;border-radius:8px;padding:5px 10px;font-size:12px;font-family:inherit;cursor:pointer}" +
841
852
  ".dnm-ov-btn:hover{background:var(--dsw-alias-bg-layer-2,rgba(255,255,255,.12))}" +
@@ -911,17 +922,30 @@
911
922
  }
912
923
  }
913
924
  function overlayCount() { return Object.keys(overlayCards).length; }
914
- // Same inputs as showToast: `quick` is the approval record built by
915
- // quickFor(), and it is what lets an overlay settle the request in place.
916
- function showOverlay(kind, title, body, sessionId, quick) {
917
- if (config.channel !== "overlay") return false;
925
+ // One card builder for both channels: the overlay channel draws with it,
926
+ // and so does the desktop fallback below. `opts` keeps the two behaviours
927
+ // apart: the overlay card is a shortcut (a click opens the conversation and
928
+ // takes the card down), while the fallback card carries a decision the OS
929
+ // notification cannot — so a click must not dismiss it unanswered, and a
930
+ // "详情 / Details" toggle exposes the body that the CSS clamps to 3 lines.
931
+ function drawOverlayCard(kind, title, body, sessionId, quick, opts) {
932
+ opts = opts || {};
918
933
  var layer = ensureOverlayLayer();
919
934
  if (!layer) return false;
935
+ // One card per approval key: a re-delivery (the quieted copy that fires
936
+ // when the page is backgrounded) must not stack a second card.
937
+ if (quick && typeof quick.key === "string") {
938
+ var known = Object.keys(overlayCards);
939
+ for (var k = 0; k < known.length; k++) {
940
+ if (overlayCards[known[k]].key === quick.key) return false;
941
+ }
942
+ }
920
943
  var d = texts();
921
944
  try {
922
945
  var id = "ov" + (++overlaySeq);
946
+ var baseClass = "dnm-ov dnm-ov-" + (kind === "attention" ? "attention" : "done");
923
947
  var card = document.createElement("div");
924
- card.className = "dnm-ov dnm-ov-" + (kind === "attention" ? "attention" : "done");
948
+ card.className = baseClass;
925
949
  card.setAttribute("role", kind === "attention" ? "alert" : "status");
926
950
  var head = document.createElement("div");
927
951
  head.className = "dnm-ov-head";
@@ -930,6 +954,22 @@
930
954
  var label = document.createElement("span");
931
955
  label.className = "dnm-ov-title";
932
956
  label.textContent = String(title == null ? "" : title);
957
+ var more = null;
958
+ if (opts.expand && body) {
959
+ more = document.createElement("button");
960
+ more.type = "button";
961
+ more.className = "dnm-ov-more";
962
+ more.setAttribute("aria-label", d.details);
963
+ more.setAttribute("aria-expanded", "false");
964
+ more.textContent = d.details;
965
+ more.onclick = function (ev) {
966
+ if (ev && ev.stopPropagation) ev.stopPropagation();
967
+ var open = card.className.indexOf("dnm-ov-open") !== -1;
968
+ card.className = baseClass + (open ? "" : " dnm-ov-open");
969
+ more.textContent = open ? d.details : d.collapse;
970
+ more.setAttribute("aria-expanded", open ? "false" : "true");
971
+ };
972
+ }
933
973
  var close = document.createElement("button");
934
974
  close.type = "button";
935
975
  close.className = "dnm-ov-x";
@@ -941,6 +981,7 @@
941
981
  };
942
982
  head.appendChild(dot);
943
983
  head.appendChild(label);
984
+ if (more) head.appendChild(more);
944
985
  head.appendChild(close);
945
986
  card.appendChild(head);
946
987
  if (body) {
@@ -970,10 +1011,12 @@
970
1011
  }
971
1012
  // A click on the card body opens the conversation, exactly like a toast
972
1013
  // body click — and here it is an ordinary page gesture, so it reaches the
973
- // desktop's dsh:// raise path even though a worker click would not.
1014
+ // desktop's dsh:// raise path even though a worker click would not. The
1015
+ // overlay channel also takes the card down; the fallback card stays, so
1016
+ // the decision is still one click away after a look at the conversation.
974
1017
  card.onclick = function () {
975
1018
  if (config.autoFocus) focusSession(sessionId || null);
976
- dismissOverlay(id);
1019
+ if (opts.dismissOnClick !== false) dismissOverlay(id);
977
1020
  };
978
1021
  layer.appendChild(card);
979
1022
  var rec = { card: card, key: (quick && quick.key) ? quick.key : null, kind: kind, timer: null };
@@ -987,6 +1030,29 @@
987
1030
  return true;
988
1031
  } catch (e) { return false; }
989
1032
  }
1033
+ // Same inputs as showToast: `quick` is the approval record built by
1034
+ // quickFor(), and it is what lets an overlay settle the request in place.
1035
+ function showOverlay(kind, title, body, sessionId, quick) {
1036
+ if (config.channel !== "overlay") return false;
1037
+ return drawOverlayCard(kind, title, body, sessionId, quick, { dismissOnClick: true });
1038
+ }
1039
+ // The desktop shell cannot register the Service Worker that OS action
1040
+ // buttons require, so an approval toast on a dsh-app:// page has no button
1041
+ // to click. While the alert channel is system notifications, an approval
1042
+ // therefore also drops a card into the same in-page layer, in the same
1043
+ // corner and with the same styling: its buttons call decidePending(), the
1044
+ // exact path a Web toast button takes. Only states that prove the bridge is
1045
+ // unusable qualify — 'idle'/'registering' are transitional, 'disabled' means
1046
+ // the quick-decision switch is off (quickFor() then returns null, so no card
1047
+ // is drawn at all), and the Web path stays untouched once the worker is up.
1048
+ function showFallbackApprovalCard(kind, title, body, sessionId, quick) {
1049
+ if (kind !== "attention") return false;
1050
+ if (!quick || typeof quick.key !== "string") return false;
1051
+ if (config.channel !== "toast") return false;
1052
+ if (bridgeActive()) return false;
1053
+ if (swState.indexOf("unsupported:") !== 0 && swState.indexOf("failed:") !== 0) return false;
1054
+ return drawOverlayCard(kind, title, body, sessionId, quick, { dismissOnClick: false, expand: true });
1055
+ }
990
1056
  // Sound: WebAudio beeps (no asset needed). The context only runs after a
991
1057
  // user gesture; we unlock it on the first pointer/key event.
992
1058
  var audioCtx = null;
@@ -1341,6 +1407,7 @@
1341
1407
  if (!config.enabled) return;
1342
1408
  showToast(kind, title, body, sessionId, quick);
1343
1409
  showOverlay(kind, title, body, sessionId, quick);
1410
+ showFallbackApprovalCard(kind, title, body, sessionId, quick);
1344
1411
  if (kind === "attention") {
1345
1412
  playAttentionSound();
1346
1413
  } else {
@@ -1980,7 +2047,7 @@
1980
2047
  });
1981
2048
  } catch (e) {}
1982
2049
  // keep in sync with package.json "version" on every release
1983
- api.version = "1.10.2";
2050
+ api.version = "1.10.4";
1984
2051
  api.setConfig = function (patch) { return setConfigLocal(patch); };
1985
2052
  api.resetConfig = function () {
1986
2053
  try {
@@ -2193,16 +2260,16 @@
2193
2260
  autoFocus: "点击通知回到对应对话",
2194
2261
  autoFocusHint: "点通知会切到这条提醒所属的对话;关掉后点击不做任何事。",
2195
2262
  quickActions: "审批通知上直接裁决",
2196
- quickActionsHint: "审批通知上带「同意 / 拒绝」,点一下即完成裁决,不用切回页面。需要 Service Worker(http://127.0.0.1 或 https),用不了时退回普通通知。",
2263
+ quickActionsHint: "审批通知上带「同意 / 拒绝」,点一下即完成裁决,不用切回页面。需要 Service Worker(http://127.0.0.1 或 https);用不了时按钮改画在窗口角落的卡片上(桌面端就是这条路)。",
2197
2264
  quickApprovalNote: "「同意」等价于审批卡片上的「允许一次」,只放行这一次。",
2198
2265
  bridgeOff: "快捷裁决按钮暂不可用(",
2199
- bridgeOffTail: "):审批通知会退回不带按钮的普通样式。",
2200
- bridgeOffDesktop: "系统通知没有「同意 / 拒绝」按钮:桌面端页面(dsh-app://)注册不了 Service Worker(宿主少给 allowServiceWorkers 特权),按钮发不出来。想一键裁决就把「提醒方式」切到「页面浮层」。",
2266
+ bridgeOffTail: "):系统通知没有按钮,按钮改画在窗口角落的卡片上。",
2267
+ bridgeOffDesktop: "系统通知本身没有「同意 / 拒绝」按钮:桌面端页面(dsh-app://)注册不了 Service Worker(宿主少给 allowServiceWorkers 特权)。审批类提醒会同时在窗口角落弹一张卡片,按钮就在卡片上;想只留卡片、不弹系统通知,把「提醒方式」切到「页面浮层」。",
2201
2268
  overlay: "页面浮层提醒",
2202
2269
  overlayHint: "在窗口角落画提醒卡片:窗口在哪块屏,它就在哪块屏;系统通知只会出现在主屏,主屏不看时用它。不需要通知权限,卡片上能直接「同意 / 拒绝」。与系统通知二选一。",
2203
2270
  channelLabel: "通知类型",
2204
2271
  overlaySeg: "浮层提醒",
2205
- channelHint: "系统通知只会出现在主屏,进通知中心要权限,桌面端也没有「同意 / 拒绝」按钮;页面浮层画在 DSH 窗口所在的那块屏,不需要权限,卡片上能直接裁决。两个只能选一个。",
2272
+ channelHint: "系统通知只会出现在主屏,进通知中心要权限,桌面端的通知本身没有「同意 / 拒绝」按钮(审批会额外在窗口角落弹一张可点击的卡片);页面浮层画在 DSH 窗口所在的那块屏,不需要权限,卡片上能直接裁决。两个只能选一个。",
2206
2273
  overlayCorner: "浮层位置",
2207
2274
  overlayCornerHint: "贴在 DSH 窗口的哪个角;窗口在哪块屏,浮层就出现在哪块屏。",
2208
2275
  overlayPosTR: "右上",
@@ -2210,7 +2277,7 @@
2210
2277
  overlayPosTL: "左上",
2211
2278
  overlayPosBL: "左下",
2212
2279
  overlayQuickNote: "浮层上的「同意」同样等价于审批卡片上的「允许一次」,与通知按钮一致。",
2213
- testApprovalNoBridge: "已发普通测试通知(快捷裁决按钮需要 Service Worker,当前环境没有,按钮渲染不了)。",
2280
+ testApprovalNoBridge: "已发测试提醒:系统通知没有按钮,快捷裁决按钮画在窗口角落的卡片上。",
2214
2281
  testNeedsQuick: "先打开上面的「审批通知上直接裁决」才能测按钮。",
2215
2282
  volume: "音量",
2216
2283
  language: "通知语言",
@@ -2323,16 +2390,16 @@
2323
2390
  autoFocus: "Click a toast to open that conversation",
2324
2391
  autoFocusHint: "A click switches to the conversation the alert came from; off means a click does nothing.",
2325
2392
  quickActions: "Decide approvals from the toast",
2326
- quickActionsHint: "Approval notifications carry Approve / Reject; one click settles the request without switching back. Needs a Service Worker browser (http://127.0.0.1 or https), else plain toasts.",
2393
+ quickActionsHint: "Approval notifications carry Approve / Reject; one click settles the request without switching back. Needs a Service Worker browser (http://127.0.0.1 or https); when it is unavailable the buttons land on a card in the window corner (the Desktop shell's route).",
2327
2394
  quickApprovalNote: "\"Approve\" equals \"Allow once\" on the approval card — it allows that one call only.",
2328
2395
  bridgeOff: "Quick-decision buttons are unavailable right now (",
2329
- bridgeOffTail: "); approval toasts fall back to their plain form.",
2330
- bridgeOffDesktop: "System notifications carry no Approve / Reject buttons: dsh-app:// pages cannot register a Service Worker (the shell does not grant the allowServiceWorkers privilege), so the buttons cannot be attached. Switch the alert channel to the in-page overlay to settle approvals in one click.",
2396
+ bridgeOffTail: "); system notifications carry no buttons, so they are drawn on a card in the window corner instead.",
2397
+ bridgeOffDesktop: "System notifications carry no Approve / Reject buttons: dsh-app:// pages cannot register a Service Worker (the shell does not grant the allowServiceWorkers privilege). An approval therefore also drops a clickable card in the window corner, buttons and all; switch the alert channel to the in-page overlay to keep only the card and skip the system notification.",
2331
2398
  overlay: "In-page overlay",
2332
2399
  overlayHint: "Draw a card in the window corner, on whatever display the window sits on. System notifications only ever show on the primary display. No permission needed, and the card carries Approve / Reject directly. It replaces system notifications rather than adding to them.",
2333
2400
  channelLabel: "Alert type",
2334
2401
  overlaySeg: "Overlay",
2335
- channelHint: "System notifications land in the Windows notification center: permission needed, primary display only, and no Approve / Reject buttons on the Desktop shell. The in-page overlay draws on whichever display the DSH window sits on, needs no permission, and lets the Desktop shell decide right on the card. Pick one.",
2402
+ channelHint: "System notifications land in the Windows notification center: permission needed, primary display only, and the Desktop shell's notifications carry no Approve / Reject buttons (an approval also drops a clickable card in the window corner). The in-page overlay draws on whichever display the DSH window sits on, needs no permission, and lets the Desktop shell decide right on the card. Pick one.",
2336
2403
  overlayCorner: "Overlay position",
2337
2404
  overlayCornerHint: "Which corner of the DSH window the cards stack in; they follow the window to whatever display it is on.",
2338
2405
  overlayPosTR: "Top right",
@@ -2340,7 +2407,7 @@
2340
2407
  overlayPosTL: "Top left",
2341
2408
  overlayPosBL: "Bottom left",
2342
2409
  overlayQuickNote: "\"Approve\" here equals \"Allow once\" on the approval card — the same decision the toast buttons send.",
2343
- testApprovalNoBridge: "Plain test notification sent (quick-decision buttons need a Service Worker, which this environment lacks, so they cannot render).",
2410
+ testApprovalNoBridge: "Test alert sent: system notifications carry no buttons, so the quick-decision buttons are drawn on a card in the window corner.",
2344
2411
  testNeedsQuick: "Turn on \"Decide approvals from the toast\" above to test the buttons.",
2345
2412
  volume: "Volume",
2346
2413
  language: "Notification language",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-notify-me",
3
- "version": "1.10.3",
4
- "description": "离开 DSH 页面也能收到提醒:需要你操作 / 后台回复完成时发系统通知、标题标记与可选页面浮层(副屏也能看见),支持审批快捷裁决与外部推送。Brand icon and a reworked settings page in 1.9.0.",
3
+ "version": "1.10.4",
4
+ "description": "离开 DSH 页面也能收到提醒:需要你操作 / 后台回复完成时发系统通知、标题标记与可选页面浮层(副屏也能看见),支持审批快捷裁决与外部推送,Web 版与桌面版均可用。",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "lib/index.js",