Files
session-notify/CHANGELOG.md
T

87 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 变更记录
版本说明按倒序排列。提交信息遵循 [CONTRIBUTING.md](CONTRIBUTING.md) 的单行规范,因此每次改动"为什么这样改、影响面是什么"记在这里,而不是提交信息里。
## v1.0.9
- 轻弹窗改成 **DSH 的浮层卡片**,跟随 DSH 的深色 / 浅色模式。原来用的是 DSH 的 `--dsw-alias-toast-bg`,而那个令牌在**两种模式下都是深灰**(浅色模式 `#353638`、深色模式 `#43454a`),所以在浅色页面里浮窗是一块接近纯黑的板子,和周围的卡片不是一种东西。现在照 DSH 自己的做法来(下面这些都是 shell 主题里真实存在、并且会随 `body[data-ds-dark-theme]` 一起切换的令牌):
- 底色 `--dsw-alias-bg-layer-2`:浅色 `#fff`、深色 `#2c2c2e`,和浮动菜单 / 弹窗用的是同一层;
- 发丝线与大阴影用 `--dsw-elevation-stroke-color` + `--dsw-elevation-prominent`(DSH 菜单的做法,发丝线取 `--dsw-alias-border-l1`:浅色 `#0000000a`、深色 `#ffffff0f`);
- 文字改 `--dsw-alias-label-primary` / `-secondary` / `-tertiary`,不再是写死的白字加 `opacity`;
- 入场动画用 shell 自己的 `--ds-transition-duration` 与 `--ds-ease-in-out`。
- 「查看」按钮改成 `--dsw-alias-state-business-primary`(浅色 `#4176e6`、深色 `#7aaaff`);原来是写死的 `--dsw-static-deepseek-400`,在白底上对比度不够、也不随主题变化。关闭按钮用 `--dsw-alias-label-tertiary`,hover 升到主文字色。三类图标仍是状态令牌:完成绿 `#22c55e`、授权琥珀 `#dd8629`、提问蓝(随主题)。
- 新增 `tests/unit/styles.test.js`(5 条)把两条不变量钉住:**样式表里不出现字面颜色、也不用 `--dsw-static-*` 这类不随主题切换的令牌**;弹窗必须用上面那套浮层配方,且**不许再出现 `--dsw-alias-toast-bg`**。以后谁把颜色写死、或又退回那个深色板子,测试会直接失败。
- 行为未改:位置(右上角)、尺寸、停留时间、hover 暂停、`Esc` / ✕ 关闭、同屏 3 条都不变,只换皮。
## v1.0.8
- 修复:**授权与提问两类提醒从来不会弹**(只有「会话已完成」会弹)。原因不是判据写错了,而是投递前的「是否还值得提醒」那道闸门用错了事实:
- `stillWorth` 原本对所有提醒都要求「会话已经不在运行」,可待处理请求恰恰出现在会话仍在运行的时候——客户端的 `running` 只镜像宿主的 `api-session/status`,和有没有待处理请求是两件独立的事(`dsh-client-ui-session` 的 `observeRunning` 就是这么写的),于是每条授权 / 提问提醒都在 400ms 确认窗口结束时被静默丢掉;
- 更糟的是丢之前 `pendingNotice` 已经记下了这个请求,所以它再也不会被重新排进队列——同一请求只报一次的规则反而变成了"一次都不报"。
- 现在两类提醒用各自该问的问题:**待处理请求问「它还在等吗」**(请求被你自己答掉就不提醒,还在就提醒,不看运行状态),**完成提醒仍问「这一轮真的停下来了吗」**(在确认窗口里又跑起来就不提醒)。
- 修复:**计划确认(`plan-review`)的文案从 v1.0.1 起就是死代码**——`copyFor` 先判断 `kind === 'question'`,而计划确认正是以 `kind: 'question'` 入队的,于是「计划正在等待你确认」永远走不到,实际显示的是提问那段文案。现在先看判别符,计划确认用自己的文案,与 README 的说明一致。
- 投递节流不再丢待处理提醒:1.5 秒的洪泛保护原本会直接吃掉被拦下的提醒,现在**待处理请求**被拦下时会回到队列、下一个 tick 重试(只有你能清掉它,所以它一直是欠你的);完成提醒保持原有的丢弃语义,多个会话同时结束仍然不会刷屏。
- 重新设计插件页(**插件 → 会话通知**):原来是一段孤立说明 + 四段标题与行标题同字号的段落,状态区把四句话和按钮挤在一行里。现在:
- 顶部一句「提醒是怎么送出去的」,下面三组:**提醒内容 / 系统通知权限 / 运行状态**,组标题加粗,组内是「左侧对象 + 右侧唯一控件」的列表,行之间用细线分隔;
- 权限状态带一个小圆点(绿=已开启,黄=未授权,红=被系统关掉,灰=当前环境不支持),下面一行按情况给出该去哪授权或该按钮验什么;
- 运行状态改成**键值对照表**(窗口状态 / 会话监听 / 最近一次投递 / 待补发提醒),最近一次投递拆成「时间 · 通道」加下一行提醒类型,不再是四个句子堆在一个格子里;
- 「测试提醒」独立成行右对齐,按钮区分主次(未授权时的「允许通知」是主按钮),行高与圆角统一。
- 字典随之增删:新增 `config.diag.watch`、`config.diag.replayValue`,`config.diag.replay` 改成短标签「待补发提醒」、`config.diag.replayNone` 改成「没有」,两个字典键集合仍然完全一致,没有死键。
- 测试从 36 条增加到 39 条:新增「待处理请求放着 `running: true` 也照样该提醒」的回归用例(这条如果早就有,v1.0.7 之前就能发现上面那个 bug)、计划确认文案用例,并把页面渲染测试改到新的结构与文案上。
## v1.0.7
- 重构:**客户端源码拆成模块,`client.js` 从「手写文件」变成「构建产物」**。原来的 `client.js` 是 1452 行单文件,通知引擎、轻弹窗、插件页、观察器、字典、样式、图标全塞在一个 `apply` 里,改任何一处都要在同一个文件里上下翻。现在:
- `src/client/core/` 是行为:`observe`(一轮派生)、`delivery`(通道决策、节流、400ms 确认窗口)、`system-channel`(系统通知与平台回执)、`replay`(回前台补发)、`toasts`(弹窗栈与计时)、`actions`(两个测试按钮、权限请求、开关)、以及 `copy` / `session` / `storage` / `store` / `log`;
- `src/client/ui/` 是界面:`ToastLayer`、`KindRow`、`ConfigSection`、`NotifyObserver`、`icons`、`styles`、`hooks`;
- `src/client/i18n/` 是字典与翻译器,`src/client/platform.js` 是浏览器与平台事实,`src/client/plugin.js` 是组合根(建 store、装配模块、注册三个 slot),`src/client/index.js` 是构建入口。
- **`client.js` 仍然是包根那一个文件,安装路径与发布清单都没变**:`exports`、`files`、`main`、`icon`、`dsh` 与 `cordis.patch.yml`、`locale/` 全部原样,使用者依旧零依赖、零构建。
- 新增 `scripts/build-client.mjs`(esbuild):把 `src/client/**` 打包成一个自包含单文件,并校验它仍然满足注册契约(只有一个 factory、`require('react')` 落在 factory 内、没有顶层 `import`/`export`、除了 `react` 不再向模块表要别的模块)。这一步无法省略:客户端模块系统只交给插件一个自包含 bundle,factory 里的 `require` 不能 require 同一个包里的相对文件。
- 新增 `tests/`(`pnpm test`,用 `node --test`,无第三方依赖):26 个纯函数单测(文案、会话派生、存储、字典与翻译器)、4 个产物测试(注册 id、factory 返回值、`apply` 在没有 DOM 的 Node 里也能跑通、**产物与 `src/**` 是否一致**)、6 个渲染测试(用一份最小 React 替身渲染插件页与轻弹窗,验证重构后的 props 装配:开关的选中态、诊断行、按钮回调、观察器的健康上报)。以后改完源码忘了重新构建,测试会直接失败。
- 维护者现在需要跑一次 `pnpm install`(唯一 devDependency 是 esbuild);**使用者不需要**。README 的安装说明按这个区分改写了,并新增「仓库结构」一节。
- 行为未改:三类提醒的判定、通道选择、节流与确认窗口、补发与去重、开关的存储键、CSS 全文与 `dsn-*` 类名、全部字典键与文案都逐字保持(构建产物与 v1.0.6 的字符串逐条比对通过,样式表 4615 字节完全一致)。
- 顺带记录一个**本次没有修的既有缺陷**:`body.planReview`(「计划正在等待你确认」)在 v1.0.6 里已是死代码——`copyFor` 先判断 `kind === 'question'`,而计划确认正是以 `kind: 'question'` 入队的,所以计划提醒实际显示的是提问那段文案。修它要调整判断顺序、属于行为变更,因此这次只把现状写进 `src/client/core/copy.js` 的注释,并在 `tests/unit/copy.test.js` 里钉住当前输出。
## v1.0.6
- 修复:**窗口不在前台时,提醒有可能一次都看不到**。排查证据:一次真实投递(会话 17:52:29 结束)在插件页留下 `09:52:30 · 系统通知`——`09:52:30` 是 UTC,本机时间是 17:52:30;而 Windows 的通知平台记录 `LastNotificationAddedTime` 停在 70 分钟前。也就是说 `new Notification()` 没抛错,但**构造函数成功不等于通知真的弹出来了**,加上系统通知的气泡只存在几秒,人不在电脑前时它等于没送达。这一版不再把"发出去"当成"收到了":
- 每条系统通知都订阅 `show` / `error`:系统是否确认显示会写进插件页的「最近一次投递」,不再只报"系统通知"三个字;
- **凡是在窗口不在前台时投递的提醒,都会在窗口回到前台的那一刻用应用内轻弹窗补发一次**。同一会话同一类只保留最新一条,超过 30 分钟不再补发;"正在看的会话不打扰"这条规则不适用于补发,因为它发生的时候你并不在看。唯一的例外是系统确认气泡已弹出、且你在 20 秒内就回到窗口(气泡还在屏幕上,不再重复);
- 点掉系统通知本身(`click`)会取消对应的补发,不重复打扰。
- 修复「最近一次投递」的时间显示成 UTC(比本地时间早 8 小时,17:52 显示成 09:52)的问题,现在显示本机时间。
- 修复确认窗口的队列会把提醒永久卡住的问题:一次确认窗口只投递一条,剩下没轮到的会自己再排一次(以前排完之后队列里再没人触发,后面的提醒就被吞了)。
- 系统通知对象改为有界持有引用:防御性改动,避免显示还没落定时对象被回收(实测中保留引用与否都能送达,所以这不是那次丢失的原因)。
- 插件页「运行状态」新增一行:还有几条提醒在等你回到窗口时补发。
## v1.0.5
- 修复:**应用在后台时不发系统通知**。前台/后台以前只靠 `window` 的 `focus`/`blur` 事件记住,桌面外壳里 `blur` 可能不到,插件就一直以为窗口在前台,于是走了轻弹窗分支(而用户没在看,表现就是完全没有通知)。现在每次投递都现读 `document.visibilityState` 与 `document.hasFocus()`,任一表示不可见即走系统通知;观察器订阅的事件只是让重算更及时,不再决定通道。
- 系统通知构造失败时降级:改用轻弹窗,并把被拒原因写进插件页,不再静默失败。
- 插件页新增诊断:窗口当前状态(前台/后台,即会走哪条通道)、观察器健康、最近一次投递的通道与时间;「测试系统通知」按钮直接走系统通道(前台也照发),用来单独验证系统通知是否可用。
- 修掉日志前缀重复(`session-notify: session-notify:`)。
## v1.0.4
- 配置块去掉重复:插件页顶部已经有 DSH 渲染的插件标题与描述,原配置块又写了一遍标题和几乎一样的说明。现在这一段直接用一句「提醒是怎么送出去的」开头,随后进入设置项。
- 移除未使用的字典键 `config.title` / `config.note`,保证字典里没有死键。
## v1.0.3
- 设置从「设置 → 通用」移到插件自己的介绍页:注册 `plugins.bundle.config`(key 取包名),与官方 `dsh-experimental-voice-input-bundle` 用的是同一个口子;通用设置里不再有本插件的行。
- 应用内轻弹窗改成标题 + 描述两行:标题是提醒类型(会话已完成 / 需要授权 / 需要回答),描述是会话题目与细节;关闭按钮从 18px 放大到 28px 的方形热区,「查看」改成有 hover 背景的文字按钮,整条浮窗 hover 时暂停自动消失。
- 三个开关改为存浏览器本地(`localStorage`),重开页面、重装插件都保留;仍然不写 DSH 的配置文件。
- 插件页配置分四段:说明、提醒内容(三个开关)、系统通知权限、运行状态。
## v1.0.2
- 补上 `ctx.locale.register('session-notify', { zh, en })`:没有注册时 `locale.bind(ns)` 会把 key 原样返回,界面上就显示成 `settings.title` 这样的原始键。
- 字典兜底与 locale 兜底同时保留:缺框架的 `t`、或 locale 服务没保存注册,都不会显示原始键。
- 快照语言字段改为真实字段 `snapshot.active`。
## v1.0.1
- 首个发布版本:会话完成 / 需要授权 / 需要回答三类提醒。
- 窗口不在前台走系统通知(Windows / macOS / Linux 同一条渲染进程通道,无平台分支);窗口在前台走应用内轻弹窗;正在看的那个会话完成时不打扰。
- 只对「运行中 → 空闲」的转变提醒,同一会话同一轮只报一次,同一待处理请求只报一次;子智能体会话与空白会话跳过;多个会话同时完成有 1.5 秒节流,完成提醒前有 400ms 确认窗口。
- 修复:无渲染观察器原先挂在 `sidebar.panellist`,而该 slot 的宿主会把每个条目的 id 当作一个左侧面板按钮,导致左侧多出一行空面板并挤坏侧边栏;现改挂通用浮层 `shell.overlay`。