DSH plugin 右侧栏怎么扩展:pane-tab slot、导航服务、资源地址与路由
DSH plugin 的右侧栏不是「加一个面板」,而是往一套有身份、有路由、有生命周期的停靠面里注册一个 tab 类型。 三个概念决定一切:每个会话恰有一个停靠面(保存在会话作用域的 slot store 里,刷新可恢复布局);tab 身份是 (kind, address)(同类型同地址复用,不同类型同地址并存);路由是一次排序认领(先按优先级档,再按最长模式,最后才看注册顺序)。再叠加 keepMounted 的懒保活与 canOpen 的同步否决,你就能控制「谁能打开这个地址」和「切走后正文还在不在」。
DSH plugin 右侧栏的定位:每会话一个停靠面
一句话结论:一个会话一个面,保存在会话作用域的 slot store 里,刷新后恢复布局。
- 组成:会话区旁的一列 pane 与 tab,内容按地址寻址,可打开、分栏、浮出、关闭。
- 所有权:右侧栏包拥有面、tab 类型注册表与导航服务;布局引擎是内部依赖。
- root 控制器:为选中会话与已初始化
keepMounted正文的后台会话保留独立席位,但只有前台会话可见。 - 变更记录:面的每次变化都是纯规划器算出的一条历史记录。
- 不空 pane:根 pane 为空时会自动补位,不会留下空白栏。
DSH plugin 的地址两族与 tab 身份
一句话结论:资源地址由调用方给,页面地址由 Sidebar 自己写;身份是 (kind, address)。
| 地址族 | 形式 | 谁生成 |
|---|---|---|
| 资源地址 | dsh-resource://<type>/… | 调用方(例如文件树) |
| 页面地址 | sidebar://<kind> | Sidebar 的 openTab(kind) |
- 资源地址的作用域:
file协议以session/<id>或absolute开头。 - 页面地址别手拼:引导页与文件树用
openTab('guide')、openTab('files')。 - 身份规则:同一地址经同一类型再次打开会命中已有 tab;经两个类型打开则是两个 tab。
- contentId:认领时把地址原文作为记录的
contentId。 - 没有其它导航地址:这套系统只承认这两族。
DSH plugin 的 pane-tab 类型注册:七个字段
一句话结论:定义是静态的,没有运行时 hook,也没有按 tab 或按会话的字段。
| 字段 | 作用 |
|---|---|
id | 唯一身份,包名是自然取值;正文与标题坑位按它注册 |
kind | 类型判别名,不唯一;内置为 guide、text、files |
patterns | 可选资源地址 glob;页面类型省略 |
priority | extension(默认最高)/ builtin / fallback |
canOpen | 同步否决,每次路由决策都调用 |
title | chip 文本,打开时捕获,之后不再改写 |
keepMounted | 懒保活,跨隐藏、会话切换与停靠切换保留 |
- 注册方式:
ctx.sidebarRightTabs.register(definition),放在ctx.effect里。 - 重复 id 抛错:同一
id第二次注册直接失败。 - glob 细节:含
:的模式匹配整个地址,不含的只匹配 URL 路径部分且任意深度;不分大小写、不隐藏 dotfile,语法为 picomatch 的 POSIX 方言。 - extension 接管 kind:同一 kind 可同时有 builtin 与 extension,extension 注销后 builtin 恢复。
- 引导入口:可选
guide框,点了就把该类型作为页面打开。
DSH plugin 的路由:一次排序认领
一句话结论:档位 → 最长命中模式 → 注册顺序;没人认领就抛错,这是接线问题。
- 候选:
candidates(address)先过滤模式命中且未被canOpen否决的类型。 - 排序:先按 priority 档,再按最长命中模式的长度,最后按注册顺序。
- 认领:
claim(address, kind?)取第一个候选;点名kind时跳过 glob,但canOpen仍生效。 - 返回:
{ kind, contentId: address, title }。 - 无人认领即抛错:说明没有类型能处理该地址,属于接线错误而非用户操作错误。
DSH plugin 的 keepMounted 与引导页
一句话结论:保活只保留已访问过的正文;引导页是类型自己的入口框,不占用 tab。
- 保活范围:已访问正文跨隐藏、会话切换与停靠切换保留,由所属 View 持有会话引用。
- 不提前挂载:从未访问的正文不会因为 keepMounted 而提前渲染。
- 与资源模型配合:右侧栏在每条打开 tab 的存续期内钉住其地址,所以切 tab 不关流。
- 引导框:
{ order, title(), description?, icon? },点框即打开该类型的页面。 - 验证:切走再切回,正文状态应保留;新开的 tab 不应被保活。
DSH plugin 排查注意事项
一句话结论:右侧栏问题先分「没人认领」「认领错类型」「正文没保活」三类。
- 打开报错 → 没有类型认领该地址,检查 patterns 与
canOpen。 - 打开成另一个类型 → 检查 priority 档与 pattern 长度,extension 默认压过 builtin。
- 同地址出现两个 tab → 用了两个 kind 打开,身份是
(kind, address)。 - 切走再回来状态没了 → 没开
keepMounted,或正文从未访问过。 - 重复注册报错 →
id撞了,检查是否在两个插件里各注册一次。 - 修复状态如实:本文的地址规则、注册字段、三层排序与保活语义均取自官方「右侧 Sidebar」页面;扩展 slot 与内置类型清单以该页及包 README 为准。
常见问题
DSH plugin 的 tab 身份是 (kind, address) 二元组:同一地址经同一类型再次打开会找到已有 tab,同一地址经两个类型打开则是两个 tab。注册表的认领会把地址原文作为 contentId。
DSH plugin 的资源地址是 dsh-resource:// 形式的 URL,host 是协议;页面地址是 sidebar://<kind>,由 Sidebar 自己在 openTab(kind) 时写入。调用方从不手拼页面地址。
能,DSH plugin 的同一 kind 可以同时有一个 builtin 与一个 extension 注册,extension 在认领、get、openTab 与引导页上生效。extension 注销后 builtin 自动恢复,不需要重新注册。
DSH plugin 的认领先按优先级档(extension、builtin、fallback),再按最长命中模式,最后按注册顺序。注册顺序只在前面都相同时才起作用,不携带其它语义。
DSH plugin 的 keepMounted 是懒保活:已访问的正文跨隐藏、会话切换与停靠切换保留,由所属 View 持有会话引用。它不会让从未访问过的正文提前挂载。
相关术语
- sidebar://<kind>
- sidebar://<kind> 是 DSH plugin 右侧栏的页面地址,由 Sidebar 在 openTab(kind) 时写入,用于按类型而非按资源打开的 tab。调用方不应自行拼接该地址。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/sidebar-right
- tab 身份 (kind, address)
- DSH plugin 的 tab 身份由类型判别名与地址共同决定:同类型同地址复用已有 tab,不同类型同地址则生成两个 tab。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/sidebar-right
- keepMounted
- keepMounted 是 DSH plugin 右侧栏 tab 类型的可选懒保活:已访问的正文跨隐藏、会话与停靠切换保留,由所属 View 持有会话引用。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/sidebar-right
- canOpen
- canOpen 是 DSH plugin 注册定义里的同步否决函数,对 glob 命中生效,每次路由决策都会调用。返回否即跳过该类型,即使模式匹配。— https://deepseek-harness.github.io/deepseek-harness/reference/subsystems/sidebar-right
来源
- DeepSeek Harness 文档 — 右侧 Sidebar(地址、tab 类型注册、导航服务、扩展 slot)· deepseek-harness.github.io
- dsh-client-ui-sidebar-right 包 README(状态、扩展席位与内置类型)· deepseek-ai(GitHub)
- DeepSeek Harness 文档 — 客户端资源(tab 钉住地址的机制)· deepseek-harness.github.io