dsh-multiview
v0.1.100
Published
2-4 real Chats you rearrange entirely from the keyboard, save as named layouts, and jump through by which pane needs you.
Maintainers
Readme
dsh-multiview — 多会话分屏
2–4 个真实对话:全键盘排布、存成命名布局、按「哪一格需要你」跳转。
一个窗口并排打开 2–4 个真实对话。每一格就是原生 Chat:composer、流式输出、工具卡、审批卡、
ask_user_question、附件、斜杠命令、停止/排队,全部照旧。目标不是"能跑的分屏",而是看起来像 DSH 自带的功能:不覆盖标题栏、不抢布局、不 monkey-patch 任何非公开扩展点。
English | 中文

安装
已发布到 npm:dsh plugin add dsh-multiview,或在 DSH Desktop 的 插件 → 添加 里搜索安装(维护者也可用 plugin_manager install_bundle),然后完全退出并重新打开 DeepSeek Harness,让客户端 bundle 重新加载。
装好后左侧面板列表多一个「分屏」图标;点它把中央列切换为分屏舞台,再点一次回到原生会话。
- 要求:DSH
>=0.2.1-rc.5 <0.2.2-0 || >=0.2.2-rc.1 <0.2.3-0 || >=0.2.3-rc.1 <0.3.0-0(engines.dsh)。每一条预发布线都显式列出——node-semver 不会让预发布版本匹配一个未点名该版本的区间。 - 卸载:插件页停用/移除 → 重启即可。会留下两个
localStorage键:dsh.multiview.v1(保存的布局与分屏) 与dsh.multiview.update.v1(上次更新检查结果,避免每次重新加载都再查一遍)。面板里的「还原」只清布局键; 想要完全干净,把两个都删掉。
用法
| 动作 | 操作 |
|---|---|
| 打开/收起 | 左侧面板列表「分屏」图标 |
| 切换 2 / 3 / 4 格 | 舞台顶栏的 2 3 4 |
| 调整比例 | 拖动格与格之间的分割线 |
| 交换两格 | 拖动一格的标题到另一格上,或 Mod+Alt+S 与下一格交换 |
| 最大化 / 还原 | 双击格头不生效,用格头右侧的 ⤢ 图标;舞台顶栏出现「还原」 |
| 给空格选会话 | 空格里直接搜索并点选——可按标题,也可按对话里说过的内容:输入两个字起,该格会向宿主检索消息内容,命中列表附带片段 |
| 把任意会话放进分屏 | 侧栏会话行悬停时出现的分屏按钮,或该行的 … 菜单 →「在分屏中打开」。不用离开分屏:有空格就填空格,未满 4 格就新增一格,四格已满才替换当前聚焦格 |
| 不打开分屏也能知道 | 只要有一格在等你回答或完成未读,侧栏「分屏」图标就带一个圆点——不用盯着分屏也知道有事 |
| 跳到需要你处理的格 | 格头的状态点本身就是按钮(等待回答 / 完成未读时出现);Mod+Alt+J 跳到下一个这样的格;如果没有任何格需要你,就跳到下一格(这个键不会什么都不做) |
| 换掉某一格的对话 | 格头的 ⇄ 图标:在该格原地重开选择器并替换对话。两格分屏里删格是不可能的,这是唯一能换对话的路径 |
| 在原生视图打开 | 格头右侧 ↗ 图标:把该会话交回原生对话(右栏文件预览/改动评审要在原生视图里才可用) |
| 移除一格 | 格头右侧 ✕;已绑定的一格会回到会话列表(分屏形状不变),空格再点 ✕ 才真正移除 |
| 视图 | 顶栏「视图」:绑定 2 格以上会自动记住,点击恢复;✎ 重命名(手写的名字在之后改布局时不会被自动名覆盖);✕ 删除。停在某套已保存的布局上继续移动、交换、增减格,改动会落在这一条上,而不是堆出一堆近似重复项 |
| 检查更新 | 顶栏右侧刷新图标:每 24h 自动检查,有更新带红点,确认后自动更新 |
快捷键(模块默认值,可在 设置 → 快捷键 改):
| 命令 | 默认键(桌面端) |
|---|---|
| 聚焦上一格 / 下一格 | Mod+Alt+[ / Mod+Alt+] |
| 跳到下一个需要你处理的格 | Mod+Alt+J |
| 与下一格交换位置 | Mod+Alt+S |
| 最大化或还原当前格 | Mod+Alt+M |
| 从分屏移除当前格 | Mod+Alt+W |
分割线本身是可聚焦的分隔条:←/→(上下分屏用 ↑/↓)每次移动 2 %,按住 Shift 为 5 %,Home / Enter / Space 恢复均分。
浏览器(Web)端默认不绑定这些键:DSH 的快捷键层对 Web/Linux 允许的组合极窄,硬绑会在启动时报"reserved"。桌面端默认值可用,Web 端请按需自绑。
几个边界行为
- 两格是下限。 两格分屏里的空格不能删除(✕ 不显示)——预置形状、
234按钮与保存布局的键都假定至少两格。 - 归档即离屏。 在任意位置归档一个对话,它所在的格会立刻清空,格的位置不变。
- 缩格保住你正在看的。 从四格缩到两格会丢掉两个对话,但被聚焦的那一个一定留下,并占据第一格。
- 最大化要有对话。 空窗格不提供 ⤢:把选择器放大到全屏会把其他对话全藏起来。
- 旧布局会自愈。 应用一套会话已被删除或归档的保存布局时,形状照旧恢复、只清空那些格;保存条目不会被静默删除,而是改写为实际能恢复的样子。
真机逐条确认清单见 docs/VERIFY-BY-HAND.md。
项目现状(0.1.28 以来的变化、已验证与未验证的部分):docs/STATE-OF-PLAY.md。
目标用户与需求证据的诚实评审:docs/POSITIONING.md。
明确不支持(v1)
这些是刻意不做的,不是遗漏:
- 格内文件预览 / 改动评审:DSH 在任何一个全局面板激活时都会卸下右栏的会话面板(
no session surface is mounted,自带的面板也一样)。要用右栏,请用格头的 ↗ 切到原生视图。 - 格内新建会话:Hero 的工作区选择器属于应用级导航,会把整个界面带走;新建会话请在原生视图里做。
- 格内 Trajectory / 插件视图切换:每格固定 Chat,不另造 tab。
- 点侧栏会话直接送进聚焦格:拦截整行点击等于劫持非公开的导航路径,所以普通点击保持原生行为(会离开分屏)。想送进分屏,请用该行的悬停分屏按钮或
…菜单——由你主动按下去,而不是被改掉的点击行为。 - 自动休眠:只在手动移除/切格时释放资源;不伪造"非聚焦格暂停渲染"。
- 最多 4 格。
看不到分屏入口时
按顺序排掉这几种情况,绝大多数问题在第一步:
- 完整退出再打开。插件是客户端 bundle,启动时读取一次;关掉窗口但进程仍在运行时,装好的新版本不会生效。
- 确认插件已启用:设置 → 插件,
dsh-multiview应处于启用状态。 - 对照版本号:把鼠标停在分屏面板标题上,提示里写着正在运行的插件版本。如果它比你刚装的新版本旧,就是没重启成功。
- 确认宿主版本满足
engines.dsh(见上);宿主版本过高时插件仍会加载,并在同一处提示"宿主未经校验"。 - 侧栏面板列表里只有三项(插件 / 自动化任务 / 分屏);分屏固定排在最后。
性能
在 desktop-kfscv8c-1(1530×851 窗口)用 CDP rAF 采样实测:
| 场景 | p50 | p95 | 最长帧 | >50ms 长任务 | JS 堆 | |---|---|---|---|---|---| | 原生会话(基线) | 16.7ms | 16.7ms | 16.8ms | 0 | 43MB | | 4 格挂载、空闲 | 16.7ms | 16.8ms | 16.8ms | 0 | 75MB | | 4 格挂载、2 路同时流式 | 16.7ms | 16.7ms | 16.8ms | 0 | 85MB | | 4 格、4 路同时长流式 | 16.7ms | 50ms | 150ms | 2 | 53MB |
四路长文同时输出是最重场景:平均仍近 60fps,但 p95 升到 50ms、偶发一次 150ms 长帧(四份 transcript 各自按 chunk 重排)。v1 不降频——"每格都是真实 Chat"优先于帧率数字。
长帧不是本插件造成的:3 分钟两格同时流式的实测记录了 205 个长任务,于是趁流式期间采样 CPU 归因(0.5ms 采样,3609 个样本):
| 归属 | 采样时间占比 |
|---|---|
| dsh-multiview | 0.0% |
| 宿主 / DSH 各 UI 包 | 7.1% |
| 空闲、(program)、GC、原生 | 92.9% |
同一段 3 分钟里:0 个未捕获错误,JS 堆 53MB → 峰值 85MB → 42MB(已回落,无无界增长),两格都跑到完成。
对话历史按 turn 虚拟化(DSH 自带),因此每格成本 ≈ 一个活跃 turn 的增量渲染 + 一个编辑器实例。窗口窄于 900px 或矮于 520px 时自动降级成「单格 + 顶栏格切换器」(切换器会显示每格状态:运行中 / 等待回答 / 完成未读),布局树保留。
开发
零第三方依赖,只用本机 Node ≥ 22.18(本仓库用 24.13):
npm run build # src/client/*.ts → client.js(单文件 bundle);src/host/index.ts → index.js
npm test # 布局代数单测(node --test)
npm run check # 发布自检:manifest / 产物 / 文案 / 体积隔离验证(不写任何 profile):
dsh --profile web --patch <repo>\.dev\dev.patch.yml --port 40602 --no-opendev.patch.yml 里的 row 名用绝对 file:/// 指向本仓库的 index.js(Loader 的相对名锚定在 profile 根,不是 patch 文件旁)。
渲染只走公开插槽面:main keyed 面板 + 会话作用域子槽 + SessionProvider + conversation.content
factory(variant:'embedded')+ sessions.retain + shortcuts + locale。
有两处不在这条线上,安装前值得知道:从格内打开文件预览时,它会按类名找到宿主自己的文件胶囊并
代为点击(全局面板激活时右栏没有会话面);另外它读取一个私有 store 字段(retainedBy.mainView)
来判断谁当前占着原生视图。两者都是有据可查的兜底路径,不是主路径。详见 docs/DESIGN.md。
状态与支持
预 1.0:接口稳定到可以日常使用,但小版本里仍可能出现小范围破坏性变更,每一处都记在 CHANGELOG.md。发布由 CI 从 tag 触发并带 npm provenance,所以 npm 上的包就是本仓库构建出的那一个。
客户端只会发两类网络请求:插件市场的同源 API,以及仅用于版本发现的 registry.npmjs.org/dsh-multiview/latest
公共读取(不带凭据、不带 referrer)。安装仍然走市场。scripts/check.mjs 会守住这份清单。
engines.dsh 接受从 0.2.1-rc.5 起的 0.2 线;0.2.0 与 rc.5 之前的 0.2.1 预发布不在范围内。
构建在 0.2.1-rc.5 与 0.2.2-rc.1 上验证过,这两条线(含其补丁版本)不会触发顶栏提示;
其他小版本会在 tooltip 里追加「DSH x.y.z 尚未验证」,而不是假装验证过。
- Bug 与需求:issues(模板会问最要紧的两件事:插件版本、宿主版本)。
- 多格渲染成本:已在上游立项 discussion #12559。
- 限制浮层层级对比的主题令牌缺口(浅色无色阶、缺 state-business-secondary):discussion #12770。
- 非分屏专属的问题(会话、权限、模型供应商)属于 harness 项目本身。
许可
MIT。
