Skip to content
dsh.fish
Bundle

@hjj345345/dsh-sm-context-piano

Configurable Codex-style conversation navigator for the DeepSeek Harness Web GUI, with compact previews and fast paragraph jumps.

Source
hjj345
stars
2 stars
License
MIT
Updated
Updated 12 hours ago

Readme

# 琴键导航 | sm-context-piano

中文文档(默认) · [English documentation](README.en.md)

[![version](https://img.shields.io/badge/version-v1.2.4-blue?style=flat-square)](https://www.npmjs.com/package/%40hjj345345%2Fdsh-sm-context-piano) [![node](https://img.shields.io/badge/node-22.19%20or%2024%2B-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org/) [![license](https://img.shields.io/badge/license-MIT-brightgreen?style=flat-square)](LICENSE)

GitHub:[https://github.com/hjj345/dsh-sm-context-piano](https://github.com/hjj345/dsh-sm-context-piano)

npm:[@hjj345345/dsh-sm-context-piano](https://www.npmjs.com/package/%40hjj345345%2Fdsh-sm-context-piano)

<p align="center">
  <img src="images/sm-context-piano-settings-icon.png" alt="琴键导航插件图标" width="180">
</p>

DeepSeek Harness Web GUI 的 Codex 式对话琴键导航插件。

它在聊天正文左侧增加一组紧凑的横线琴键,将长对话压缩为可预览、可定位的语义节点。用户可以沿琴键快速浏览对话结构,悬停查看摘要,点击或使用键盘跳转到目标段落,而不必反复拖动滚动条寻找上下文。

本插件只负责导航和预览:不修改会话内容、不裁剪模型上下文、不注入系统提示,也不开放额外 HTTP 接口。

## 为什么需要琴键导航

长时间运行的 Agent 会话通常包含大量用户指令、模型回复、工具调用、编辑记录和内部状态。传统滚动条只能表示页面位置,无法告诉用户每一段内容的语义。

琴键导航将对话重新组织为更容易识别的节点:

- 用户消息始终作为独立节点;
- 模型连续输出会合并为一个节点;
- 工具调用、编辑、读取、推理和内部状态不会生成琴键;
- 被非输出内容打断的模型回复会重新分段;
- 当前阅读节点始终在固定窗口中保持可见。

因此,琴键数量不会简单等于页面消息数量,而是更接近用户能够感知的关键对话段落。

## 核心功能

- **Codex 式紧凑琴键**:默认使用 2px 粗细、12px 中心间距和 20 根可见琴键,保持集中排列,不因长历史而无限压缩。
- **纯语义节点**:只显示用户消息和模型可见文本输出,完全过滤 tool、edit、read、reasoning、command、partial 等非输出内容。
- **连续输出合并**:相邻且未被非输出内容打断的模型文本合并为一根琴键;不同阶段的输出保持独立。
- **固定窗口浏览**:节点超过上限时,以当前阅读位置为中心显示固定数量;选择顶部或底部琴键即可继续浏览更早或更晚的内容。
- **连续悬停波形**:整条轨道都是有效命中区域,鼠标位于琴键间隙时也会自动选择最近节点,并以平滑宽度变化提示位置。
- **安全文本预览**:悬停卡片展示标题和正文摘要,跟随明暗主题并自动避开窗口边界;内容始终以纯文本写入。
- **快速定位**:点击琴键或按下 Enter、Space,平滑滚动到目标消息起始位置。
- **阅读位置同步**:滚动聊天时,当前段落琴键会立即加深并加长,固定窗口随阅读位置重新居中。
- **流式增量更新**:模型持续输出或历史内容更新时复用已有琴键 DOM,避免闪烁并保留当前交互状态。
- **三语设置页**:支持简体中文、English、繁體中文,默认简体中文;选择会即时生效并由 DSH 持久化。
- **可配置布局**:可以调整琴键粗细、中心间距和最大显示数量,轨道总高度自动重新计算。
- **响应式设置界面**:通用设置、显示设置、关于插件和安装命令卡片支持窄屏自动排版,长命令可以换行且不会与复制按钮重叠。
- **键盘与辅助技术支持**:支持完整键盘选择、跳转和关闭预览;琴键轨道使用导航角色和无障碍名称。
- **主题与动效偏好**:跟随 DSH 明暗主题,并遵守 `prefers-reduced-motion`。
- **完整卸载**:插件卸载后移除 DOM、样式、监听器、Observer、定时器和动画帧,不残留页面副作用。

## 实际应用效果

插件会在对话正文左侧提供琴键导航,并通过悬停预览和阅读位置同步帮助用户快速浏览长对话。

<p align="center">
  <img src="images/plugin-Application%20Effect-1.png" alt="对话页面中的琴键导航" width="900">
</p>

<p align="center">
  <img src="images/plugin-Application%20Effect-2.png" alt="琴键导航悬停预览" width="900">
</p>

<p align="center">
  <img src="images/plugin-Application%20Effect-3.png" alt="琴键导航定位长文档内容" width="900">
</p>

## 快速开始

### npm 安装

```powershell
dsh plugin --profile web add @hjj345345/dsh-sm-context-piano
```

安装后刷新或重新打开 DSH Web GUI,然后在设置弹窗左侧进入 **琴键导航**。

### 本地开发链接

```powershell
dsh plugin --profile web add link:C:/path/to/dsh-sm-context-piano
```

## 操作方式

| 操作 | 效果 |
| --- | --- |
| 移动鼠标经过琴键轨道 | 选择最近的琴键,展开波形并显示段落预览 |
| 点击琴键或轨道当前位置 | 跳转到当前预览的对话段落 |
| 滚动聊天正文 | 自动更新当前琴键和固定显示窗口 |
| `ArrowUp` / `ArrowDown` | 在当前可见琴键之间移动选择 |
| `Home` / `End` | 选择当前窗口的第一根或最后一根琴键 |
| `Enter` / `Space` | 跳转到已选择的琴键节点 |
| `Escape` | 关闭当前预览并清除悬停状态 |

选择固定窗口顶部或底部的边界琴键后,窗口会立即重新计算,使更早或更晚的节点进入可见区域。

## 设置页面

插件以一级设置项注册在 DSH 设置弹窗中,排序位于官方 **Agent 预设** 下方。第三方设置导航使用 DSH 官方齿轮回退图标。

### 通用设置

| 设置 | 默认值 | 说明 |
| --- | --- | --- |
| `语言/Language` | 简体中文 | 支持简体中文、English、繁體中文;只切换插件设置页文本 |

语言选择由插件独立保存。它不会修改 DSH 全局语言;左侧一级导航名称和琴键轨道的无障碍名称仍跟随 DSH 系统语言。

### 显示设置

| 设置 | 默认值 | 可选范围 / 行为 |
| --- | --- | --- |
| 启用状态 | 开启 | 可随时关闭或重新启用琴键导航 |
| 琴键粗细 | `2px` | `1–4px` |
| 琴键间距 | `12px` | `6–18px`,表示相邻琴键中心点距离 |
| 最大显示数量 | `20` | `5–30`,超出上限时使用固定窗口 |
| 恢复默认值 | — | 同时恢复语言、启用状态和全部显示参数 |

轨道总高度按以下公式自动计算:

```text
(最大显示数量 - 1) × 琴键间距 + 琴键粗细
```

默认值对应 `(20 - 1) × 12 + 2 = 230px`。

### 关于插件与安装命令

“关于插件”卡片显示版本、发布日期、作者、邮箱、GitHub 仓库链接以及正式 npm 包名与链接。“安装命令”使用独立代码卡片展示完整命令,并提供一键复制按钮。

### 设置页面截图

以下截图分别展示中文设置页、插件启用与显示控制,以及 English 界面。

<p align="center">
  <img src="images/plugin-2.png" alt="中文插件设置与显示控制" width="900">
</p>

<p align="center">
  <img src="images/plugin-1.png" alt="中文关于插件与安装命令" width="900">
</p>

<p align="center">
  <img src="images/plugin-English.png" alt="English 插件设置页" width="900">
</p>

## 工作原理

1. 从 DSH `ConversationSnapshot.chat.order/nodes` 读取当前会话中已经加载的有序节点;
2. 将用户消息和模型可见文本转换为安全的导航描述,过滤所有非输出节点;
3. 按连续性合并模型输出,并为不连续输出建立稳定的分段 key;
4. 使用 `[data-chat-anchor-key]` 将语义节点与真实消息行对齐;
5. 根据阅读线计算当前节点,只渲染以它为中心的固定琴键窗口;
6. 通过滚动容器、MutationObserver、ResizeObserver 和动画帧调度保持布局同步。

现有琴键通过稳定 key 增量复用,因此流式回复不会导致整条轨道反复清空和重建。

## 兼容性与实现边界

- 面向 DeepSeek Harness Web profile,依赖当前 ChatView 的 `[data-chat-flow]`、`[data-chat-anchor-key]` 和 `[data-conversation-scroll]` 锚点。
- 仅为当前已经加载到 ChatView 的历史生成琴键;尚未加载的更早记录不会提前出现。
- 工具、编辑、命令、推理和内部状态不会创建琴键,也不会进入悬停预览。
- 同一 DOM 行内由非输出 block 分隔的多段模型文本可以生成多根琴键,但受 Harness 行级锚点限制,跳转位置均为该消息行起点。
- 页面宽度不足、琴键区域与正文重叠或没有可导航节点时,插件会安全隐藏轨道,不影响 DSH 页面使用。
- 当前构建环境要求 Node.js `^22.19.0 || >=24.0.0`。

## 安全与隐私

- 不修改 Session、模型上下文、系统提示或对话数据;
- 不注册额外 HTTP 路由,不发送插件自己的网络请求;
- 设置通过 DSH 官方 settings namespace 保存,不使用单独的浏览器私有存储;
- 预览使用 `textContent` 写入,不执行会话内容中的 HTML;
- 错误提示不包含用户会话正文;
- 关闭时移除琴键 DOM 和会话绑定监听;完整卸载时进一步释放全局观察器和设置订阅。

## 开发与验证

环境要求:Node.js `^22.19.0 || >=24.0.0`、pnpm。

```powershell
pnpm install
pnpm verify
```

`pnpm verify` 依次执行:

1. TypeScript 项目引用和类型检查;
2. 宿主端与客户端生产构建;
3. DSH 客户端模块包装;
4. 输出分段、固定窗口和设置边界逻辑测试;
5. 构建产物冒烟测试;
6. jsdom 页面与交互集成测试。

当前自动化覆盖包括 21 项逻辑断言、4 项构建冒烟检查和 14 项 jsdom 集成场景。

项目内部设计和验收资料保留在仓库的 `docs/` 目录中,npm 发布包不包含这些内部文档。

## 常见问题(Q&A)

### 为什么工具调用和编辑记录没有琴键?

琴键用于定位用户能够直接感知的对话内容。工具、编辑、读取、推理和内部状态只作为模型输出连续性的分界,不作为导航目标。

### 为什么长对话不显示全部琴键?

插件使用固定数量窗口,避免为了容纳全部历史而压缩琴键间距。选择窗口顶部或底部节点即可逐步浏览更早或更晚的内容。

### 为什么切换插件语言后,左侧导航名称没有变化?

插件语言只控制设置页。DSH 一级导航名称和琴键轨道无障碍名称按设计继续跟随 DSH 系统语言。

### 为什么某些更早的消息没有琴键?

琴键只覆盖当前已经加载到 ChatView 的历史。需要先让 DSH 加载对应历史记录,插件才能为其建立导航节点。

### 设置会在刷新后保留吗?

会。语言、启用状态和显示参数均通过 DSH settings namespace 持久化。

## 许可

本项目采用 [MIT License](LICENSE) 开源。

## 更新日志

### v1.2.4 · 2026-09-09

- 优化超宽屏下的琴键导航轨道定位:留白充足时自动向屏幕边缘吸附,空间紧张时保持贴近正文;
- 增加轨道横向平滑过渡,并确保悬停预览在轨道移动后仍能正确定位;
- 补充轨道边缘定位、横向过渡和响应式布局的分组及集成测试。

### v1.2.3 · 2026-09-08

- 修复设置弹窗打开时琴键导航遮挡弹窗的问题:检测可见的 DSH `role="dialog"`,弹窗显示期间暂停插件导航,关闭后自动恢复;
- 增加可见弹窗、隐藏弹窗和导航恢复场景的集成测试,确保官方轮次导航隐藏状态不受影响;

### v1.2.2 · 2026-09-07

- 当前版本开始强兼容 DSH 0.1.2-rc.1 及更高版本;
- 改用 DSH 0.1.2-rc.1 的 `uiConversation` Chat target 读取对话节点,避免依赖旧版 Session snapshot;
- 插件成功挂载后精准屏蔽 DSH 0.1.2-rc.1 内置“轮次导航”,并在插件关闭或异常时恢复官方导航;
- 增加对 DSH 0.1.2-rc.1 官方 ChatView、TurnNavigator 和历史轮次投影的集成测试。

### v1.2.1 · 2026-09-07

- 修复 DSH 0.1.2-rc.1 环境下琴键导航轨道无法正确显示或绑定的问题;
- 改用实际琴键几何位置计算悬停定位,避免轨道空白区域触发错误预览;
- 兼容缺少旧版 flow 标记的会话滚动容器,并在导航轨道被外部移除后自动恢复;
- 调整导航遮罩层级,并在 DSH 对话框打开时隐藏,避免遮挡界面;
- 增加上述绑定、定位、恢复和对话框场景的集成检查。

### v1.2.0 · 2026-09-02

- 修复 DSH 设置命名空间在新版本依赖中的兼容性,确保插件始终以字符串命名空间正确注册;
- 扩展 `@deepseek-ai/cordis`、`@deepseek-ai/dsh-settings` 和 `@deepseek-ai/schemastery` 的宿主兼容版本声明;
- 增加对应的宿主注册、peer 依赖和设置页版本日期 smoke/integration 检查。

### v1.1.2 · 2026-08-29

- 版本号更新为v1.1.2。

### v1.1.1 · 2026-08-29

- 统一插件用户可见版本标识为 `v1.1.1`;
- 优化安装命令卡片的明暗主题背景及暗色文字对比度。

### v1.1.0 · 2026-08-28

- 修复宿主核心包被插件普通依赖遮蔽的问题;
- 将 `@deepseek-ai/dsh-settings` 和 `@deepseek-ai/schemastery` 改为宿主提供的 peer 依赖;
- 更新开发构建基线到 DSH 0.1.1-rc.2,同时保留对已发布 DSH 列车的兼容声明。

### v1.0.0 · 2026-08-21

首次发布版本,包含:

- 实现只覆盖用户消息和模型可见文本输出的 Codex 式琴键导航;
- 支持连续模型输出合并,并过滤工具、编辑、读取、推理、命令和内部状态;
- 支持固定窗口、活动节点居中、边界节点换页、悬停预览和快速跳转;
- 支持滚动位置同步、流式增量更新和稳定 DOM 节点复用;
- 新增一级插件设置页,包含通用设置、显示设置、关于插件和安装命令卡片;
- 支持简体中文、English、繁體中文三语即时切换和持久化,默认简体中文;
- 保持 DSH 一级导航名称和琴键轨道无障碍名称跟随 DSH 系统语言;
- 支持插件开关、琴键粗细、间距、最大显示数量、自动轨道高度和恢复默认值;
- 支持安装命令一键复制、响应式设置布局、窄屏自动换行和明暗主题;
- 支持鼠标、键盘、减少动态效果偏好及完整卸载;
- 完成宿主端、客户端、设置 schema、构建产物和 jsdom 交互验证。

## 贡献者

感谢所有参与本项目讨论、建议、测试和代码贡献的开发者。特别感谢:

- [@amazing-fish](https://github.com/amazing-fish) — 提交 PR #3,提出并实现轨道位置自适应吸边功能。

Install

dsh plugin --profile web add github:hjj345/dsh-sm-context-piano

Profile: web

  • This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.
  • This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.
Source