🌐 中文 · English
dsh-unarchived-watch
「会话攒到第 11 个,侧边栏底部会替你亮一盏黄灯。」
未归档会话积压的仪表灯:越线就亮 —— 它不归档、不删除、不落盘;唯一会写的,是你在设置页设的那个阈值。
它解决什么问题 · 效果示例 · 快速开始 · 触发方式 · 它和同类有什么不同 · 安全边界 · 文件结构 · 验证与测试
它解决什么问题
DSH 里的归档是个手动动作,而"该归档了"这件事没有任何人提醒你。
于是它总是这样发生:你连着几周只顾开新会话,直到某天打开侧边栏,发现要滚很久才能找到上周那条 —— 然后花半小时翻捡、归档、后悔没早点整理。
这个插件把"该清理了"变成一个被动触发的信号:未归档的普通会话一旦超过你设的阈值(默认 10),侧边栏底部就会亮起一个黄色警告三角,角标上是当前数量;设置页的阈值配置行里也带着同一个数。
它只负责告诉你,不替你动手。 归档动作仍然在你熟悉的侧边栏行内菜单里;插件不接管任何状态。
效果示例
下面是本机实例(DSH Desktop,2026-10-02 11:16)的真实回放,不是编的样例:
会话列表 125 行
其中普通会话 63 个 (排除 48 个子代理子会话 + 14 个空白新建会话)
其中已归档 34 个
→ 未归档普通会话 29 个
→ 阈值 10
→ 侧边栏 亮灯,角标 29
同一场排查里我前后读了两次,归档集从 11 涨到 38(这段时间有 27 个会话被归档),计数随之从 54 掉到 29 —— 它跟着你的清理实时变化,不需要刷新。
数字会跟着你的清理走:写这份文档的十几分钟里,同一个实例的归档集从 11 涨到 59,计数从 54 一路掉到 9(这时灯就灭了)。所以下面这句是那个时刻的真实读数,你自己跑 scripts/replay-count.mjs 得到的一定是新的。
悬停图标会显示一句话,屏幕阅读器读到的是同一句:
未归档会话 29 个,已超过阈值 10 个
快速开始
两条路,任选一条:
# 1) npm 包
dsh plugin --profile web add dsh-unarchived-watch
# 2) 直接指向 GitHub 仓库(不需要构建授权:lib/ 随仓库提交)
dsh plugin --profile web add github:d0ublecl1ck/dsh-unarchived-watch
装完刷新窗口(Cmd+R)。装完第一句话可以直接对 Agent 说:
现在有多少未归档会话?超阈值的时候把阈值调成 20。
阈值也能手写进 profile 的 cordis.patch.yml(注意 row id 就是设置命名空间):
- id: unarchived-watch
name: dsh-unarchived-watch
config:
threshold: 20
触发方式
- "我有多少会话没归档?"
- "侧边栏底部那个黄三角是什么?"
- "未归档有点多了,提醒我一下"
- "阈值改成 20"
- "把未归档会话提醒关掉"(把阈值调到很大,或禁用 row)
它会交付什么
| 位置 | 内容 | 什么时候出现 |
|---|---|---|
| 侧边栏底部 | 黄色警告三角 + 数量角标 | 未归档普通会话数 严格大于 阈值 |
| 悬停 / 键盘聚焦 | 文本气泡:未归档会话 {count} 个,已超过阈值 {threshold} 个 |
图标可见时 |
| Settings → 通用 | 「未归档会话提醒」配置行:输入框 + 当前数量 | Host 服务了本插件配置时 |
它和同类有什么不同
DSH 生态里已经有几个归档管理器(做得都很好)。这个插件的定位刻意不同:
| 维度 | 归档管理器(如 dsh-archive-manager / dsh-archived-conversations / dsh-session-sweeper) | dsh-unarchived-watch |
|---|---|---|
| 回答的问题 | "已归档的在哪里、怎么恢复/删除" | "什么时候该归档了" |
| 入口 | 设置页整页列表 / 侧边栏列表 | 侧边栏底部一盏灯 |
| 触发时机 | 你想起来去看 | 越线自动出现 |
| 写操作 | 会改归档状态(部分会删除会话) | 零写操作,全程只读快照 |
| 状态归属 | 自己持有一份列表/索引 | 不持有任何状态,计数现场算 |
如果你要的是"管理归档",请用那三个;如果你要的是"别让我攒到失控",用这个。
安全边界
- 不写会话或归档状态:没有
archiveSession/unarchiveSession/ 删除调用;归档仍走官方侧边栏的行内动作。插件唯一的写入是你自己改的阈值 —— 它经 Host settings 存进 profile 的cordis.patch.yml,那是配置,不是会话状态。 - 不联网:客户端只读 shell 已经发布的快照(
useSessions/useWorkspaces),不发起任何网络请求。 - 不落盘:插件自己不建文件、不写
localStorage、不注册持久化 domain。 - 不会静默误算:徽标与设置页配置行共用
src/count.ts一份实现,口径(只数普通会话)由单测钉死。 - 什么时候停手:Host 没有服务本插件的配置命名空间时,配置行不注册(徽标照常,用默认阈值)——不会渲染一个改不动的控件。
文件结构
src/index.ts host 半边:只导出 name / Config / apply(threshold 是 volatile 字段)
src/count.ts 纯计数口径(无框架依赖,单测直接打它)
src/client/index.ts 浏览器半边:注册徽标 / 配置行,注册文案与样式
src/client/WarningBadge.tsx 侧边栏底部的图标 + 数量角标 + 官方 Tooltip
src/client/ThresholdRow.tsx 设置页通用栏的阈值输入行
src/client/threshold.ts 把 config form 投影成可订阅的阈值
src/client/styles.ts 注入的 uw-* 样式(一次注入,fiber 卸载时移除)
scripts/build.mjs tsc + esbuild + __ModuleLoader__ 包装
scripts/check-release.mjs 发布前离线体检(清单 / 契约 / externals / 产物新鲜度)
test/ 22 个 node:test 用例(口径、模块契约、SSR 真渲染)
cordis.patch.yml bundle 层:插入 row id 为 unarchived-watch 的那一行
验证与测试
一条命令跑完全部门禁:
npm run verify # typecheck + build + 22 个单测 + check-release
- 单测 22/22:
test/count.test.mjs(口径与边界)、test/client-contract.test.mjs(加载真实lib/client.js验模块 id 与两次注册、且settings.section不再注册)、test/client-render.test.mjs(react-dom/server真渲染徽标与配置行)。 - 发布前体检:
npm run check-release会拦住"改了src/忘了npm run build"、export default折掉inject、浏览器产物 require 了 platform seed 之外的模块、以及 tarball 会漏掉cordis.patch.yml这四类发布事故。 - 真实数据回放:上面的数字是用本机实例跑出来的。scripts/replay-count.mjs 就是当时用的脚本 —— 把实例的会话列表与
storages/workspace.json喂给它,它在任何一台 DSH 实例上都能算出同样的口径(命令见CHANGELOG.md的 0.2.0 节)。 - 已知边界:单测覆盖到"组件渲染出什么"为止;slot 在浏览器里的最终挂载与视觉效果需要刷新页面确认(页面里看不到图标时,先看
document.head里有没有<style data-plugin="dsh-unarchived-watch">)。
No comments yet. Be the first to write one.