@idoall/dsh-session-colors
v0.1.14
Published
DSH web plugin: give any Session a colour mark, shown as a chip in the sidebar and picked from the conversation header. Marks are stored on the Host, so a colour chosen on one device is visible on every other one — including over LAN and tunnels.
Maintainers
Readme
✅ 已支持 DSH
0.2.2-alpha.2—— 当前alpha构建(npmalpha)。 已针对安装的运行时核查兼容性,并保留此前验证的0.2.1-rc.4、0.2.1-rc.3、0.2.1-rc.2、0.2.1-alpha.5、0.2.1-alpha.4、0.2.1-alpha.3、0.2.0-rc.2、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1与0.1.7-alpha.2;详见兼容性。
DSH Session Colors 是 DeepSeek Harness 社区插件。它不修改 DSH 核心,也不改写任何会话或工作区数据:一个标记只是"会话 ID → 一个颜色"。
工作分散在多个工作区里,而工作区列表就是一堵长得差不多的标题墙。任务跑完之后,刚才那条会话就很难再找回来——状态点已经回到空闲,标题也只是二十个里的一个。自己选的颜色,是让一行变得好认的最省事办法。
功能
- 会话行上的颜色标记——行左侧内边距里的一小段色条,刻意避开状态点,所以"哪个跑完了"这个信号不会被盖掉。
- 系统风格的颜色选择器——大色板、色相与透明度滑条、十六进制与 RGBA 输入、七个主题色、我的颜色,以及浏览器支持
EyeDropper时的屏幕吸色。注册在会话头部的工具区,不占标题位置。 - 一处标记,处处可见。 标记存在宿主而不是浏览器里,所以在电脑上选的颜色,手机上也能看到——局域网地址、隧道访问都算。
- 手机端同样显示。 手机把侧栏变成抽屉,色块跟着抽屉走:抽屉滑进来时它一起移动,并且画在抽屉之上。
- 自动获取改动。 页面重新可见时、以及每 20 秒会重读一次,别的设备改了颜色不用刷新就能看到。
- 绝不挡住界面。 色块浮层点击穿透,并且按侧栏滚动容器裁剪;最坏情况只是色块不显示。
- 失败会说。 读不到存储时,头部控制会显示 ⚠ 并给出原因,而不是装作"这个会话没有颜色"。
安装
要求:
- 带 Web profile 的 DeepSeek Harness
- Node.js 20 或更新版本
- 已验证的 DSH 版本:
0.2.2-alpha.2(当前alpha构建)、0.2.1-rc.4、0.2.1-rc.3、0.2.1-rc.2、0.2.1-alpha.5、0.2.1-alpha.4、0.2.1-alpha.3、0.2.0-rc.2、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1与0.1.7-alpha.2——插件0.1.14(见兼容性)
dsh plugin --profile <profile> add @idoall/dsh-session-colors@latest要按 DSH 版本精确对应,用兼容性表里的具体版本号。
要改插件本身就用目录安装:
dsh plugin --profile <profile> add link:/path/to/dsh-session-colors然后在 profile 的 cordis.patch.yml 里给它一个数据目录(与其它需要持久化的插件做法一致,插件不会去猜 profile 路径):
- id: dsh-session-colors
config:
dataDir: /absolute/path/to/profiles/<profile>/data/dsh-session-colors最后重启 dsh web(宿主半边只在启动时加载),再刷新 Web GUI。不配 dataDir 也能用,但标记只活在宿主进程的生命周期里。
使用
- 打开要标记的会话。
- 点会话头部的颜色控件(未设色时显示 🎨,设色后显示该颜色)。
- 选一个颜色,或直接粘贴十六进制值。该会话在侧栏的行上会立刻出现色条。
- 取消标记:再次打开选择器,点清除标记,或选主题色里那个透明色块。
在已标记的会话上打开选择器,会从它当前的颜色开始。颜色以 HSVA 保存,所以透明度能原样往返。
兼容性
当前版本:插件 0.1.14 已针对 DeepSeek Harness 0.2.2-alpha.2(当前 alpha 构建,npm alpha)核查兼容性,并保留此前验证的 0.2.1-rc.4、0.2.1-rc.3、0.2.1-rc.2、0.2.1-alpha.5、0.2.1-alpha.4、0.2.1-alpha.3、0.2.0-rc.2、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1 与 0.1.7-alpha.2。
| 插件版本 | 已验证的 DeepSeek Harness | npm 发布状态 | 该版本是什么 |
| --- | --- | --- | --- |
| 0.1.14 | 0.2.2-alpha.2(alpha)、0.2.1-rc.4、0.2.1-rc.3、0.2.1-rc.2、0.2.1-alpha.5、0.2.1-alpha.4、0.2.1-alpha.3、0.2.0-rc.2、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1、0.1.7-alpha.2 | latest | 记录 DSH 0.2.2-alpha.2 兼容性,并把 0.2.2 预发布元组写进声明的加载范围。可执行代码不变,从 0.1.13 升级无需迁移。 |
| 0.1.13 | 0.2.1-rc.4(最新 0.2.1 RC)、0.2.1-rc.3、0.2.1-rc.2、0.2.1-alpha.5、0.2.1-alpha.4、0.2.1-alpha.3、0.2.0-rc.2、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1、0.1.7-alpha.2 | 已发布 | 记录 DSH 0.2.1-rc.4 兼容性。可执行代码及加载范围不变,从 0.1.12 升级无需迁移。 |
| 0.1.12 | 0.2.1-rc.3(RC)、0.2.1-rc.2、0.2.1-alpha.5、0.2.1-alpha.4、0.2.1-alpha.3、0.2.0-rc.2、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1、0.1.7-alpha.2 | 已发布 | 记录 DSH 0.2.1-rc.3 兼容性。可执行代码及加载范围不变,从 0.1.11 升级无需迁移。 |
| 0.1.11 | 0.2.1-rc.2(RC)、0.2.1-alpha.5、0.2.1-alpha.4、0.2.1-alpha.3、0.2.0-rc.2、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1、0.1.7-alpha.2 | 已发布 | 在 DSH 0.2.1-rc.2 上实测同一份代码,该版本里本插件消费的每个包都与 0.2.1-alpha.5 逐字节相同。逻辑与 0.1.10 相同,升级无需迁移。 |
| 0.1.10 | 0.2.1-alpha.5(alpha)、0.2.1-alpha.4、0.2.1-alpha.3、0.2.0-rc.2、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1、0.1.7-alpha.2 | 已发布 | 在 DSH 0.2.1-alpha.5 上实测同一份代码,该版本里本插件消费的每个包都与 0.2.1-alpha.4 逐字节相同。逻辑与 0.1.9 相同,升级无需迁移。 |
| 0.1.9 | 0.2.1-alpha.4(alpha)、0.2.1-alpha.3、0.2.0-rc.2、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1、0.1.7-alpha.2 | 已发布 | 在 DSH 0.2.1-alpha.4 上实测同一份代码,并把加载范围挪到 alpha.4 真正生效的那个字段:顶层 engines.dsh。逻辑与 0.1.8 相同,升级无需迁移。 |
| 0.1.8 | 0.2.1-alpha.3(alpha)、0.2.0-rc.2、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1、0.1.7-alpha.2 | 已发布 | 在 DSH 0.2.1-alpha.3 上实测同一份代码,并把该元组写进声明的加载范围。逻辑与 0.1.7 相同,升级无需迁移。 |
| 0.1.7 | 0.2.0-rc.2(RC)、0.2.0-rc.1、0.1.7-rc.2、0.1.7-rc.1、0.1.7-alpha.2 | 已发布 | 在 DSH 0.2.0-rc.2 上实测同一份代码,并把该确切版本加进声明的加载范围。逻辑与 0.1.6 相同(仅订正一处注释),升级无需迁移。 |
| 0.1.6 | 0.2.0-rc.1(RC)、0.1.7-rc.2、0.1.7-rc.1、0.1.7-alpha.2 | 已发布 | 在 DSH 0.2.0-rc.1 上实测同一份代码,并重写声明范围使插件能在 0.2.0 正式版上继续加载。代码与 0.1.5 相同,升级无需迁移。 |
| 0.1.5 | 0.1.7-rc.2(最新 0.1.7 RC)、0.1.7-rc.1、0.1.7-alpha.2 | 已发布 | 确认同一份代码在第二个候选版本上原样可用并加以声明。代码与 0.1.4 相同,升级无需迁移。 |
| 0.1.4 | 0.1.7-rc.1(RC)、0.1.7-alpha.2 | 已发布 | 确认 0.1.7 适配在首个候选版本上原样可用并加以声明。代码与 0.1.3 相同。 |
| 0.1.3 | 0.1.7-alpha.2 | 已发布 | 适配 DSH 0.1.7:会话 id 改从行自身的 data-row-key 读取(保留 fiber 回退),色块跟随 0.1.7 引入的 Web Animations 行滑动;宿主依赖按 0.1.7 对 link 插件的解析方式声明。 |
| 0.1.2 | 0.1.6-alpha.2 | 已发布 | 修掉折叠/展开工作区后色块停在旧位置约 20 秒:同一个 target 上第二次 MutationObserver.observe() 把 childList 监听顶掉了。 |
| 0.1.1 | 0.1.6-alpha.2 | 已发布 | 仅文档:打包进 npm 的 README 不再写"尚未发布",并声明了市场截图。 |
| 0.1.0 | 0.1.6-alpha.2 | 已发布 | 首个版本:会话颜色标记、宿主侧存储、手机抽屉内可见 |
0.1.14 支持 DSH 0.2.2-alpha.2,即当前 alpha 构建。 此补丁记录兼容性,并把 0.2.2 预发布元组写进声明的加载范围;可执行代码不变。本插件消费的每个包都在已发布的 0.2.1-rc.4 与安装的 0.2.2-alpha.2 之间做了对比:宿主 webServer 仍接受 kind/path/handler 形式的处理器路由,只是新增了可选的 Fetch 资源形式;connection 的 requestRejection 仍在。浏览器加载器仍接受 window.__ModuleLoader__.load({ id, factory }),仍内置 react 与 react-dom;两个目标槽位声明(conversation.session.header.utilities 与 shell.overlay)及其 owner props 未变。侧栏仍保留 data-row-key="session:<id>"、role="treeitem" 与 aria-selected,行高仍是色块几何测量时的 32px。行动画从 workspace 包搬到了外壳内置的 @deepseek-ai/dsh-client-ui-primitives 静态模块,rowKeys 与 Web Animations 行为一致,退场克隆仍会去掉 data-row-key,所以不会给淡出的副本多画色块。locale.register 仍只要求 zh/en 基线;新增的六种语言是可选的,本插件对它们按设计回退到英文。
原有 0.2.1 比较分支仍接纳 0.2.1-rc.4,但按 node-semver 默认规则不会延伸到 0.2.2-alpha.2:预发布只有在某个比较符写出它自己的 major.minor.patch 时才被接纳。因此加载范围新增第六个分支 >=0.2.2-alpha.2 <0.3.0。DSH 自己的预检带 includePrerelease,旧范围本来就能进,所以这是声明层面的补齐而非破坏。核查时 DSH 的 npm alpha 为 0.2.2-alpha.2,next 为 0.2.1-rc.4,latest 为 0.2.1-rc.2。
另外用一套一次性 profile 安装 0.1.14 的 tarball 并在 0.2.2-alpha.2 上启动 dsh web:没有被兼容门禁拦下,标记路由对已认证的 GET 返回 200、POST 的标记能正确回读,启动图里带着 @idoall/dsh-session-colors 及其带修订号的客户端包。该检查跑在独立的临时 DSH_HOME 与备用端口上,没有触碰用户的 profile 和正在运行的服务。头部控件在真实浏览器里的渲染效果本次没有复看,因此不宣称重新完成了视觉验证;38 个单元测试覆盖选择器、存储和色块几何。
0.1.9 把那串范围挪到了顶层 engines.dsh——0.2.1-alpha.4 起由它单独决定门禁,市场读的也是同一字段;这次沿用该位置,未作改动。
从 0.1.13 升级无需任何迁移。 仍在更旧的 DSH(含 0.1.6-alpha.2)上时,请继续用插件 0.1.2。更高的 DSH 版本不会被自动宣称为兼容。
- 已验证的 DeepSeek Harness 列出针对本插件核查过的确切 DSH 版本;验证深度及浏览器测试限制见上文。这份清单只有一个存放处——
package.json的dsh.compatibility.dshReleases——并且有测试保证两个 README 的兼容性段落与它逐字一致、且落在peerDependencies与engines.dsh两者声明的范围内。未列出的 DSH 版本不会被宣称为兼容。 peerDependencies声明的范围是>=0.1.7-alpha.2 <0.2.0-0 || 0.2.0-rc.1 || 0.2.0-rc.2 || >=0.2.0 <0.3.0 || >=0.2.1-alpha.3 <0.3.0 || >=0.2.2-alpha.2 <0.3.0(dsh-client-ui-layout与dsh-client-ui-conversation),顶层engines.dsh把同一范围声明为宿主要求:这是允许加载的范围,不等于已验证。六个分支是刻意写的:按 node-semver 的预发布规则,预发布只有在某个比较符写出同一个major.minor.patch时才被接纳——所以0.1.7线要自己的比较符,0.2.0-rc.1与0.2.0-rc.2各自精确钉死(没人测过的0.2.0-rc.3进不来),0.2.0正式版线放开是为了插件能在正式版上继续加载,0.2.1与0.2.2线分别覆盖各自元组上已验证的 alpha 和 RC。下界特意写成这个 alpha:>=0.1.6-0 <0.2.0这样的范围一个已验证版本都不接纳。- DSH 会在启动时校验这些要求,范围不满足就直接禁用该插件行,因此正确范围并非只为展示。自
0.2.1-alpha.4起,预检优先使用顶层engines.dsh,而非 peer 范围(所以0.1.9将范围移至该处);安装的0.2.2-alpha.2预检接纳本包。rc.4 → alpha.2 对比中会话、侧栏与 locale 客户端包确有变化;兼容不代表所有 DSH 产物逐字节相同。 - DSH 0.1.7-rc.2 新增了一个真正的会话行座位
sidebar.session.row.leading(标题前那格 16px)。色块刻意仍留在自己的点击穿透浮层上:该座位与状态点共用同一格,且只在行处于空闲时才挂载(运行中、等待中、已归档的行都不渲染占位),把色块放进去反而会在最需要它的时候消失。详见限制与设计记录。 @deepseek-ai/schemastery声明为 peer,不是普通依赖:DSH 0.1.7 只把 link 插件的 peer 依赖解析到运行实例,所以用link:装入本目录时,普通依赖会让宿主半边 import 失败。- DSH 升级快于插件时,插件本身不会因此报错:色块依赖 DSH 的行 DOM(见限制),所以 DSH 大改行结构时最坏的结果是色块不再显示,不会挡住点击。
跨设备与局域网
存储走插件自己的 HTTP 路由(GET/POST /plugins/dsh-session-colors/marks),落盘到 profile 数据目录里的一个 JSON 文件。这是有意为之:
DSH 自带的用户设置服务只对回环页面做宿主持久化——
persistence = $host.isLoopback ? "host" : "memory"——所以用局域网地址或隧道打开的页面,设置 scope 会永久不可用,读不了也写不进。自有路由不受这条规则限制,这正是标记能跨设备的原因。局域网转发(dsh-bridge、dsh-lan-proxy 等)会把 Host/Origin 改写成回环并注入认证 cookie,所以经局域网进来的请求在 DSH 侧仍是回环,路由正常响应。
配置
| 字段 | 类型 | 含义 |
| --- | --- | --- |
| dataDir | 绝对路径 | session-colors.json 的写入位置。不填则标记只存在于进程内存。 |
标记是一个 JSON 文档:
{
"version": 1,
"marks": {
"session-0698599a-…": { "h": 211.3, "s": 1, "v": 1, "a": 1 }
}
}写入是原子的(先写临时文件,再 rename)。要清掉某个标记,用选择器里的清除标记,或直接从文件里删掉那一行。
故障排查
手机上还是看不到颜色。 先看设备跑的是哪个构建:
document.querySelector('.dsh-sc-layer').dataset
// { dshScBuild, dshScStatus, dshScWritable, dshScMarks, dshScError }dshScBuild 不是 host-routes+animated-rows 就是客户端缓存,刷新页面即可(客户端半边刷新即热重载,不需要重启 DSH)。dshScStatus 不是 ready 则是存储读不到,见下一条。
头部控制显示 ⚠。
表示读不到存储:dshScError 里有原因,dshScWritable 说明能不能写。宿主路由未注册(插件没被 profile 加载)或数据目录不可写时会这样。注意这不是"这个会话没有颜色"。
局域网页面上功能不全。
从 0.1.0 起本插件在局域网/隧道页面与回环页面行为一致(存储走自有路由)。如果你看到的是旧版那种"设置读不到"的表现,先确认装的是哪个版本。
色块位置不对或消失。
色块浮层靠 ARIA role 找会话行、靠行自身的 data-row-key 取会话 ID(取不到时回退到 React fiber)。DSH 大改侧栏结构后可能找不到行;此时色块会消失,但不会影响点击,因为浮层是点击穿透的。
安全边界
- 标记只保存会话 ID 与颜色,不写会话日志、标题、历史、状态、归档记录或工作区归属。
- 不创建、不复制、不移动、不重排任何会话;标记不是会话数据的一部分。
- 色块浮层从不接收指针事件,并且按侧栏滚动容器裁剪:最坏情况只是色块不显示。
- 宿主路由复用 DSH 自带的鉴权栅栏(
connection.requestRejection),写入另加同源检查。 - 插件不注册模型 Tool、不启动子进程、不访问网络。
限制
- 色块依赖 DSH 的行 DOM。 它靠 ARIA role 找行、靠行自身的
data-row-key取会话 ID(回退到 React 内部结构)。DSH 未来改版可能让色块不再显示;但不会影响点击。 - 色块不是行内占位元素。 DSH 0.1.7-rc.2 声明了真正的行座位
sidebar.session.row.leading(就落在状态点那一格),本插件刻意不使用它:该座位只在行空闲时挂载,色块放进去会在运行中、等待中与已归档的会话上消失。色块因此留在自己的点击穿透浮层上——任何状态下都可见,也永远不盖住状态点。 - 标记属于单个 DSH 实例。 它存在某个 profile 的数据目录里,两个独立的 DSH 服务之间不共享。
- 没有权限模型。 凡是能访问该 profile 已鉴权路由的人,都能读写标记。
- 只有颜色。 没有文字标签、图标或 emoji。
卸载
dsh plugin --profile <profile> remove @idoall/dsh-session-colors重启 DSH 并刷新 Web GUI。数据目录里的 session-colors.json 不会被自动删除;不需要就自行删除。
开发
npm test # 38 项:bundle 结构、存储、路由、跨设备、几何、文档一致性浏览器半边是手写的 __ModuleLoader__ bundle——这是 DSH 客户端加载器接受的唯一格式。手写是刻意的:没有构建步骤,就不会有产物与目标 DSH 版本漂移的问题。
src/index.js 宿主半边:路由、JSON 存储、鉴权栅栏
src/client.js 浏览器半边:选择器、色块浮层、fetch 存储
tests/ 两个半边的单元测试,外加文档一致性检查
docs/ 设计记录(中文)与 README 截图
demos/ 独立的选择器 HTML Demo设计取舍与实测记录见 docs/plugin-design.zh.md;独立的选择器 Demo 见 demos/session-color-mark-demo.html。
