- Home
- Plugin
- Miglioramenti UI
- dsh-multi-session
V
dsh-multi-session
vegetable86/dsh-multi-session
Multi-session split view panel for DeepSeek Harness
Installazione
dsh plugin --profile web add github:vegetable86/dsh-multi-sessionREADME
多会话面板(dsh-multi-session)
在 DeepSeek Harness 里把多个会话并排看:一个独立的「多会话」主面板,格子数量不设上限,每格绑定一个已有会话,每格都是完整的原生对话(消息流 + 输入框)。所有格子不重叠地平铺,拖动分隔条就能像 tmux 那样调整相邻格子的长宽。
npm 包:@vegataa/dsh-multi-session
用法
- 左侧边栏点「多会话」图标进入面板。
1.1 面板最上方是类似浏览器的标签栏:每个标签都是一整套独立的多会话布局(自己的格子、分隔条权重、最大化 / 最小化状态)。点标签切换,
+新建一个标签(默认填入最近两个会话),×关闭标签(至少保留一个),双击标签可以改名,按住标签拖动可以调整它们的前后顺序;标签标题默认跟着它的第一个会话走,会话正在跑时标签上有个小绿点。 - 首次打开自动填入最近两个会话;每格标题栏点会话名可以换一个会话(支持搜索)。
- 工具条「+ 添加会话格」想加多少加多少。格子不重叠地平铺:两格并排,三格是上面一整格、下面两格,四格是 2×2,更多格子按两列往下排。拖行与行之间的横分隔条,上下两行一起变高变矮;拖同一行里两格之间的竖分隔条,一边变宽另一边就变窄,和 tmux 的分屏手感一样。任何时候格子都会铺满面板、不会互相遮挡。单格可最大化 / 还原,也可关闭(至少保留一格)。工具条的「均分」把所有分隔条恢复成平均分配。 3.1 每格标题栏的「最小化」把它收成面板上方的一条标题(带运行状态点);收起的格子不占网格空间,剩下的格子自动铺满,点标题即可展开回原来的位置。所有格子都可以收起。 3.2 每格标题栏的「在主面板打开」(箭头图标)把该格的会话交给普通对话页显示,多会话面板随之退到侧边栏;适合临时想仔细看某一段对话时用。标题栏还可以按住拖到另一个格子上:松手后两格交换各自显示的会话,格子的位置和大小不变。
- 空格的「新建会话」按钮、以及每格选择器底部的「新建会话」,会先弹出一个工作区选择框:选好工作区后再在这一格里创建会话,整个过程都留在多会话页面,不会跳到新会话。没有工作区时才退回 Host 的默认目录。
- 工具条右上角的「沉浸全屏」(四个角的图标)把整个面板铺满窗口,盖住左右两栏,能多出侧栏那一整条宽度;再点一次或按
Esc退出,布局原样保留。 - 工具条上的密度按钮在「紧凑 / 舒适」之间切换:紧凑是默认值,同样的窗口能多显示几行对话;舒适会把间距、按钮、标签和分隔条整体放大一档。选择随布局一起记住。
- 第一次打开面板时,工具条下方有一条操作提示(拖分隔条调大小、拖标题栏交换会话、标题栏箭头在主面板打开),点「知道了」收起;工具条上的
?随时能再叫出来。图标按钮悬停会立即显示名称,标题栏左侧的六点手柄表示这一格可以拖动。 - 布局、每格绑定的会话、最大化 / 最小化 / 全屏 / 密度状态都会自动记住,刷新或重启后恢复;会话不存在时那一格显示「不可用」,可以重新选择。
- 选择器默认不列子代理会话,也不列空白会话(当前格自己绑定的空白会话除外)。
实现要点
- 只注册一个
main面板(keymultisession)和一个sidebar.panellist图标,普通对话页完全不受影响。 - 每格通过
<SessionProvider session={reference}>显式绑定会话,引用由sessions.retain(...)获取、卸载时release()。 - 格子内部用官方
conversation.content工厂槽(variant: 'embedded')渲染,得到的是原生对话组件,不是自绘的聊天界面。 - 每格包两层错误边界:格子内的渲染异常会在 0.6s / 1.2s 后自动重建两次,仍失败才显示错误卡片(可手动「重试」);整个面板崩了还有一层兜底,可以一键清掉布局重置。
conversation.content是 Harness 的内部工厂槽,签名变了会抛错:每格对这次调用做了捕获,失败时只显示「此视图暂不可用」+ 重试,不会把整个面板打空。- 「新建会话」自己问工作区,然后直接
sessions.create({ workspaceId });不走uiWorkspace.openWorkspace——后者在 hero 工作区选择器里会layout.selectPanel(null),把主面板切回单个会话,这正是新建后跳走的原因。 - 格子的外壳用
React.memo包起来:拖动分隔条时只有父级容器重算样式,各格的对话组件不会跟着重渲染。 - 最大化改为 CSS 覆盖层(其余格子
visibility: hidden但保持挂载),切换最大化不会重挂载对话,滚动位置和正在流式的回复都保留。 - 沉浸全屏不是新窗口,也不是新面板:根节点切到
position: fixed; inset: 0,一层z-index盖住三栏框架,面板里的会话组件完全不用重挂载;Esc先退最大化、再退全屏。顶部留出 Windows 标题栏的高度,避免盖住窗口拖动区。 - 「在主面板打开」调用平台的
uiWorkspace.openSession(sessionId);它会把该会话交给当前主面板并切换到单个对话,属于宿主既有的导航入口,插件不自己造一套。 - 交换会话走 HTML5 拖放,MIME 用自定义的
text/x-multisession-pane,只在面板内部认;拖拽过程中不改 DOM 结构,松手时只交换两个格子的sessionId,所以对话视图和滚动位置都还在原来的格子实例里。 - 格子按「行 → 列」两级权重存储:每行的
rowWeights决定高度,每行内两格的colWeights决定宽度;拖动分隔条只改这两级权重,所以相邻格子永远互补、整块面板始终铺满。最小化是每个格子的minimized标志:收起后该格不再参与网格计算(行里只剩一格就独占整行),但它在rows里的位置保留着,展开即回原位。 - 标签栏是「多套布局」而不是「多套面板」:v7 的存储是一份
{ tabs, activeTabId, immersive, density },每个 tab 里放的正是原来那套panes / rows / rowWeights / colWeights / maximizedId。切标签只是换activeTabId,面板本身不重建;旧版本(v1–v6)的布局会原样升级,不会丢。 - 最近访问的 3 个标签会保持挂载(
MAX_MOUNTED_TABS):切回来时滚动位置、输入框草稿和正在流式输出的内容都还在;超出的标签整块卸载,但会话本身在后台继续跑。 - 密度不是两套样式表:
METRICS里放紧凑 / 舒适两档的尺寸,组件通过DensityContext取当前这档,拖动计算(beginSplitDrag的可用像素、最小格宽高)也跟着同一份数字走,避免尺寸和命中区各算各的。 - 分隔条只在视觉上是 6px / 10px 的细线:外层是命中区,内层
span才是那条线,悬停只改内层颜色和透明度,不改布局,所以拖起来不会抖。 - 标签拖动排序走 HTML5 拖放(自定义类型
text/x-multisession-tab),松手时只重排board.tabs数组,activeTabId不变、布局不重建;拖到标签条空白处则移到最末。落点只按左右半区判断插到目标前还是后,不额外算几何。
开发
纯手写客户端 bundle,无需构建步骤。client.js 直接就是 window.__ModuleLoader__.load(...) 包。
npm test # 注册形态冒烟 + jsdom 渲染冒烟
目录
index.js # Host 侧空实现(本插件纯客户端)
client.js # 客户端 bundle:面板、格子、选择器、持久化、i18n
cordis.patch.yml
locale/*.json # 面板名称与描述
icon.svg
scripts/ # 冒烟测试、发布打包、市场索引生成
market/ # 插件市场索引与目录提交模板
docs/superpowers/{specs,plans}/
LICENSE
许可证
MIT,见 LICENSE。
Plugin correlati
Z
dsh-web (dsh-task-board)
zhu1090093659/dsh-web
10.4k10 ore faMiglioramenti UIApache-2.0
Z
dsh-web (dsh-web-all)
zhu1090093659/dsh-web
10.4k10 ore faMiglioramenti UIApache-2.0
C
dsh-TUI
ccch1mneyyy/dsh-tui
7.7k3 ore faMiglioramenti UIMIT
Z
dsh-web-ui (dsh-task-board)
zhu1090093659/dsh-web-ui
6.3k3 mesi faMiglioramenti UIApache-2.0