# dsh-starred-turns 在对话右侧的**轮次导航条**上收藏某一轮。那排短横线里,每一条对应一轮对话,点击即可跳回那一轮。被收藏的短横线会变长并换成强调色,所以在一段很长的对话里也能一眼找到它。 右键短横线即可收藏,再右键一次取消收藏。 ## 为什么做这个 长对话的导航条是一排一模一样的短横线。官方版本已经能区分**当前**那一轮,但没有任何办法标记**你自己**在乎的那几轮——那个关键决定、那次 diff、那个你反复回滚去看的答案。这个插件就补上「每轮一个标记位」这件事,并复用导航条自带的「全长」几何让它在视觉上一目了然。 ## 功能 - **右键收藏某一轮。** 短横线从静止长度(未载入对话记录中的轮次是 `scaleX` 0.4,已载入是 0.6)变为导航条满宽(`scaleX` 1),颜色从中性边框色换成强调色。 - **收藏按对话隔离。** 一段对话里的第 5 轮和另一段对话里的第 5 轮是两个不同的位置;对话标识取当前选中的会话 id。 - **收藏会持久保存。** 刷新页面后仍在;桌面版重启应用后也在。 - **不引起布局跳动。** 导航条保持固定的 10px 间距,变的只是短横线自身的 `scaleX`。 ## 安装 ```sh dsh plugin add dsh-starred-turns ``` 或手工写进 profile 的 `cordis.patch.yml`: ```yaml - insert: - id: starred-turns name: dsh-starred-turns ``` 安装后需要重启应用(或等 HMR 重新扫描):宿主只在启动时扫描插件包。 ## 如何在不动原插件的前提下挂上去 导航条由 `@deepseek-ai/dsh-client-ui-chat` 绘制,且没有开放扩展点,所以本插件从外部装饰它,而不是 fork 那个包。每条短横线是: ```html ``` 可见的短横线由 `::before` 伪元素提供: ```css .…_mark:before { width: 20px; height: 2px; transform: translateY(-50%) scaleX(.6); } .…_markActive:before { transform: translateY(-50%) scaleX(1); } .…_markUnloaded:before { transform: translateY(-50%) scaleX(.4); } ``` 于是插件只做三件外部的事: 1. 在 `document` 上挂一个捕获阶段的 `contextmenu` 监听,切换指针下那条短横线的收藏状态; 2. 用 `MutationObserver`(只看 `data-index` 与子节点插入)加上 store 订阅,把 `data-dsh-starred-turn` 属性画到正确的短横线上; 3. 自己的样式表把这个属性变成强调色的 `scaleX(1)`。 收藏刻意复用短横线自身的 `scaleX` 几何,而不是改宽高——这正是导航条间距不被打乱的原因。 观察器从不监听插件自己写的那个属性:属性是它自己写的,不设防就会无限自我触发。绘制前也会先读一次当前值,原因相同。 ## 存储 收藏存在名为 `dsh.starred-turns.v1` 的客户端 store 里,按对话分组: ```json { "byConversation": { "session-…": ["1", "7"] } } ``` 宿主用 `localStorage` 承载 `persist`。桌面版的页面 origin 是固定的 `dsh-app://app`,所以在桌面版重启后收藏仍在。普通浏览器下宿主每次启动会换一个回环端口,而浏览器按含端口的 origin 隔离 `localStorage`,因此该模式下收藏不跨重启保留。 ## 开发 ```sh npm install npm run build # src -> lib(客户端 bundle,shell 的 closure-factory 格式) npm test # bundle 形态、导出面、选择器目标 ``` - `src/client.js` —— store、短横线绘制、右键手势、样式表 - `src/index.js` —— node 半边(宿主侧空实现;存在只是为了让 Loader 有入口模块) - `scripts/build.mjs` —— 复制 node 半边并用 esbuild 打包浏览器半边 ## 许可 MIT