dsh-notify-me 1.9.0 → 1.9.1

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.9.1] — 2026-10-20
6
+
7
+ ### 新增
8
+
9
+ - **设置左侧导航行换成品牌铃铛**:DSH 的设置外壳按分区 id 硬编码导航图标,`settings.section` 没有图标字段,所以插件改为面板渲染后打补丁——按本地化标签找到自己那一行的导航按钮,把宿主生成的 `<svg>` 换成品牌线稿(形状与 `docs/brand/icon-outline.svg` 一致),沿用宿主给的 icon class,并用 MutationObserver 跟随面板重渲染与重开。
10
+ - 宿主改结构时补丁静默放弃,显示回默认齿轮,其他功能不受影响。
11
+
12
+ ### 变更
13
+
14
+ - README(中英)与 `docs/brand/README.md` 的旧口径「导航行图标换不了」改成实际做法与失效条件;`screenshots.json` 补上 1.8.0 / 1.9.0 的截图并修正已删除的 `.jpg` 路径;徽章 bundle 尺寸更新为 ~161 KiB。
15
+
16
+ ### 测试
17
+
18
+ - `npm test` 两套件通过;另用真 bundle + 合成宿主面板(`data-shortcut-modal="settings"`、`button.navCell > svg + span.navLabel`)在无头 Chromium 里验证:三行导航里只有「通知提醒」变成铃铛(`data-dnm-nav="1"`、三条 shape),另外两行保持齿轮,图标 class 未丢。
5
19
  ## [Unreleased]
6
20
 
7
21
  ### 兼容性
package/README.en.md CHANGED
@@ -13,7 +13,7 @@
13
13
  [![npm total downloads](https://img.shields.io/npm/dt/dsh-notify-me?style=flat-square&label=total%20downloads&color=1F883D)](https://www.npmjs.com/package/dsh-notify-me)
14
14
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE)
15
15
  [![DSH Web and Desktop](https://img.shields.io/badge/DSH-Web%20%7C%20Desktop-blue?style=flat-square)](#installation)
16
- [![Client bundle size](https://img.shields.io/badge/client-%7E156%20KiB-green?style=flat-square)](lib/client.js)
16
+ [![Client bundle size](https://img.shields.io/badge/client-%7E161%20KiB-green?style=flat-square)](lib/client.js)
17
17
  [![DSH Compatibility](https://img.shields.io/badge/DSH-tested%200.2.1--rc.2-6366f1.svg?style=flat-square)](#compatibility)
18
18
  [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
19
19
 
@@ -193,7 +193,7 @@ The last block inside Advanced. The page protocol is detected automatically to t
193
193
 
194
194
  </details>
195
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.
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 `settings.section` has no icon field. The plugin therefore patches that row after the panel renders: it finds its own entry by the localised label text, swaps the host `<svg>` for the brand bell (keeping the host icon class), and follows re-renders with a MutationObserver; if the host changes its markup the patch quietly gives up and the default gear stays.
197
197
 
198
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.
199
199
 
@@ -322,7 +322,7 @@ Verified on the real shell (DSH Desktop 0.2.0-rc.2, three rounds of retesting in
322
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.
323
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.
324
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.
325
+ - **The settings sidebar glyph relies on a DOM patch**: the shell hard-codes icons per section id and `settings.section` exposes no icon field, so the plugin can only swap the `<svg>` in its own row after the panel renders. It depends on the current panel structure (`data-shortcut-modal="settings"` plus a label `<span>` inside each nav button); if DSH changes that markup the patch silently stops working and the default gear shows instead — nothing else is affected.
326
326
 
327
327
  ## Development
328
328
 
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  [![npm total downloads](https://img.shields.io/npm/dt/dsh-notify-me?style=flat-square&label=total%20downloads&color=1F883D)](https://www.npmjs.com/package/dsh-notify-me)
14
14
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE)
15
15
  [![DSH Web and Desktop](https://img.shields.io/badge/DSH-Web%20%7C%20Desktop-blue?style=flat-square)](#安装)
16
- [![Client bundle size](https://img.shields.io/badge/client-%7E156%20KiB-green?style=flat-square)](lib/client.js)
16
+ [![Client bundle size](https://img.shields.io/badge/client-%7E161%20KiB-green?style=flat-square)](lib/client.js)
17
17
  [![DSH Compatibility](https://img.shields.io/badge/DSH-%E5%B7%B2%E9%80%82%E9%85%8D%200.2.1--rc.2-6366f1.svg?style=flat-square)](#兼容性)
18
18
  [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
19
19
 
@@ -189,7 +189,7 @@ Windows 的系统通知横幅固定画在主屏上,系统没有设置项、浏
189
189
 
190
190
  </details>
191
191
 
192
- > 左侧导航行的图标由 DSH 设置外壳统一渲染:外壳按分区 id 硬编码(只认 account / models / agent-presets / plugins / archived-sessions),其他分区一律给默认齿轮,`settings.section` 也没有图标字段——插件的铃铛标志只能出现在自己的页面里,换不了导航行。
192
+ > 左侧导航行的图标由 DSH 设置外壳统一渲染:外壳按分区 id 硬编码(只认 account / models / agent-presets / plugins / archived-sessions),其他分区一律给默认齿轮,`settings.section` 也没有图标字段。插件的做法是在设置面板渲染后替换那一行:按本地化标签文本找到自己的入口,把宿主的 `<svg>` 换成品牌铃铛(保留宿主给的 icon class),并用 MutationObserver 跟随重渲染;宿主改结构时会自动放弃、回落到齿轮。
193
193
 
194
194
  > 需要浏览器通知权限:页面上点一下 → 允许;或地址栏锁 → 站点设置 → 通知 → 允许 → 刷新。macOS 还要在 系统设置 → 通知 里允许该浏览器。
195
195
 
@@ -318,7 +318,7 @@ DSH Desktop 是一层 Electron 壳,页面跑在 `dsh-app://app` 下:DOM 的
318
318
  - 「当前对话不弹通知」按 `document.hidden` 判定:窗口被别的应用完全盖住时仍算「页面可见」,此时当前对话的等待照样静默。
319
319
  - 外部通知转发受浏览器跨域(CORS)限制:端点不放行时自动降级为「送出但不可确认」(no-cors),如实标为「已送出不可确认」;Discord Webhook 官方放行跨域,可直接确认送达。HTTP 错误如实记失败、不重试。转发在本地提醒决定要发之后才触发,所以被「当前对话不弹通知」等规则静音的提醒也不会外发。
320
320
 
321
- - **设置左侧导航行是宿主的默认齿轮图标**:设置外壳按分区 id 硬编码图标,其它分区一律给默认齿轮,`settings.section` 没有图标字段,插件改不了;插件自己的铃铛标志只出现在设置页页眉与 README。
321
+ - **设置左侧导航行图标靠 DOM 补丁**:外壳按分区 id 硬编码图标且 `settings.section` 没有图标字段,插件只能在面板渲染后把那一行的 `<svg>` 换成铃铛。命中依赖宿主当前的面板结构(`data-shortcut-modal="settings"` + 导航按钮里的标签 `<span>`);如果 DSH 改了这套结构,补丁会静默失效、显示回默认齿轮,其他功能不受影响。
322
322
 
323
323
  ## 开发自检
324
324
 
package/lib/client.js CHANGED
@@ -1937,7 +1937,7 @@
1937
1937
  });
1938
1938
  } catch (e) {}
1939
1939
  // keep in sync with package.json "version" on every release
1940
- api.version = "1.9.0";
1940
+ api.version = "1.9.1";
1941
1941
  api.setConfig = function (patch) { return setConfigLocal(patch); };
1942
1942
  api.resetConfig = function () {
1943
1943
  try {
@@ -2311,6 +2311,94 @@
2311
2311
  offHint: "Reminders are off: enable them first, then test.",
2312
2312
  versionLine: "Plugin version: dsh-notify-me v"
2313
2313
  };
2314
+ // ─────────────────── sidebar row glyph ───────────────────────────
2315
+ // The settings shell picks the nav glyph from a table keyed by section id
2316
+ // (account / models / agent-presets / plugins / archived-sessions) and hands
2317
+ // every other section the settings gear; settings.section carries no icon
2318
+ // field, so there is no supported way to give our row the bell. Patch the
2319
+ // rendered cell instead: find the nav button whose label is ours and swap
2320
+ // its <svg> for the brand bell. The panel is portaled fresh on every open,
2321
+ // so this re-applies itself; if a host updates its markup the label lookup
2322
+ // simply finds nothing and the gear stays.
2323
+ function bellNavSvg() {
2324
+ var NS = "http://www.w3.org/2000/svg";
2325
+ var svg = document.createElementNS(NS, "svg");
2326
+ var attrs = {
2327
+ viewBox: "0 0 24 24", width: "16", height: "16", fill: "none",
2328
+ stroke: "currentColor", "stroke-width": "1.6", "stroke-linecap": "round",
2329
+ "stroke-linejoin": "round", "aria-hidden": "true", "data-dnm-nav": "1"
2330
+ };
2331
+ for (var k in attrs) if (Object.prototype.hasOwnProperty.call(attrs, k)) svg.setAttribute(k, attrs[k]);
2332
+ var shapes = [
2333
+ ["path", { d: "M12 3.4a5.1 5.1 0 0 0-5.1 5.1v3.1c0 .9-.3 1.7-.9 2.4l-1.1 1.3c-.5.6-.1 1.5.7 1.5h12.8c.8 0 1.2-.9.7-1.5l-1.1-1.3a3.8 3.8 0 0 1-.9-2.4V8.5A5.1 5.1 0 0 0 12 3.4Z" }],
2334
+ ["path", { d: "M9.8 19.2a2.4 2.4 0 0 0 4.4 0" }],
2335
+ ["circle", { cx: "18.3", cy: "5.3", r: "2.35", fill: "currentColor", stroke: "none" }]
2336
+ ];
2337
+ for (var i = 0; i < shapes.length; i++) {
2338
+ var el = document.createElementNS(NS, shapes[i][0]);
2339
+ for (var a in shapes[i][1]) if (Object.prototype.hasOwnProperty.call(shapes[i][1], a)) el.setAttribute(a, shapes[i][1][a]);
2340
+ svg.appendChild(el);
2341
+ }
2342
+ return svg;
2343
+ }
2344
+
2345
+ function installNavBell(labelOf) {
2346
+ if (typeof document === "undefined" || !document.body || typeof MutationObserver !== "function") {
2347
+ return function () {};
2348
+ }
2349
+ var PANEL = '[data-shortcut-modal="settings"]';
2350
+ var observed = null;
2351
+ var watching = null;
2352
+
2353
+ function patchPanel(panel) {
2354
+ try {
2355
+ var label = String(labelOf() || "").trim();
2356
+ if (!label || !panel) return;
2357
+ var cells = panel.querySelectorAll("button");
2358
+ for (var i = 0; i < cells.length; i++) {
2359
+ var cell = cells[i];
2360
+ var spans = cell.querySelectorAll("span");
2361
+ var hit = false;
2362
+ for (var s = 0; s < spans.length; s++) {
2363
+ if (String(spans[s].textContent || "").trim() === label) { hit = true; break; }
2364
+ }
2365
+ if (!hit) continue;
2366
+ var svg = cell.querySelector("svg");
2367
+ if (!svg || svg.getAttribute("data-dnm-nav") === "1") continue;
2368
+ var bell = bellNavSvg();
2369
+ // Keep the shell's own icon class so the box size and color match.
2370
+ var cls = svg.getAttribute("class");
2371
+ if (cls) bell.setAttribute("class", cls);
2372
+ if (svg.parentNode) svg.parentNode.replaceChild(bell, svg);
2373
+ }
2374
+ } catch (e) {}
2375
+ }
2376
+
2377
+ function watchPanel(panel) {
2378
+ if (!panel || panel === observed) return;
2379
+ observed = panel;
2380
+ patchPanel(panel);
2381
+ if (watching) { try { watching.disconnect(); } catch (e) {} }
2382
+ watching = new MutationObserver(function () { patchPanel(observed); });
2383
+ watching.observe(panel, { childList: true, subtree: true });
2384
+ }
2385
+
2386
+ // The panel is portaled onto <body>, so a body-level childList observer is
2387
+ // enough to notice it opening without watching the whole page.
2388
+ var opener = new MutationObserver(function () {
2389
+ var panel = document.querySelector(PANEL);
2390
+ if (panel) watchPanel(panel);
2391
+ else if (watching) { try { watching.disconnect(); } catch (e) {} watching = null; observed = null; }
2392
+ });
2393
+ opener.observe(document.body, { childList: true });
2394
+ var existing = document.querySelector(PANEL);
2395
+ if (existing) watchPanel(existing);
2396
+ return function () {
2397
+ try { opener.disconnect(); } catch (e) {}
2398
+ if (watching) { try { watching.disconnect(); } catch (e) {} }
2399
+ };
2400
+ }
2401
+
2314
2402
  // Small element helper to keep the hand-written page readable.
2315
2403
  function h(tag, props) {
2316
2404
  var args = [tag, props || null];
@@ -2932,6 +3020,11 @@
2932
3020
  return React.createElement(NotifySettingsView, { ctx: ctx, t: t });
2933
3021
  });
2934
3022
  });
3023
+ // Same page, different layer: give the sidebar row the bell instead of
3024
+ // the gear the shell falls back to for unknown section ids.
3025
+ ctx.effect(function () {
3026
+ return installNavBell(function () { return t("nav"); });
3027
+ }, "dsh-notify-me: sidebar glyph");
2935
3028
  }
2936
3029
  } catch (e) {
2937
3030
  try { console.error("[dsh-notify-me] settings page unavailable", e); } catch (e2) {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-notify-me",
3
- "version": "1.9.0",
3
+ "version": "1.9.1",
4
4
  "description": "离开 DSH 页面也能收到提醒:需要你操作 / 后台回复完成时发系统通知、标题标记与可选页面浮层(副屏也能看见),支持审批快捷裁决与外部推送。Brand icon and a reworked settings page in 1.9.0.",
5
5
  "license": "MIT",
6
6
  "type": "module",