← 返回列表
未验证
按窗口比例调侧边栏宽度,并让父会话组共享右侧面板
尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/9/15 · 已提供中文文档
DSH 插件:侧边栏按窗口比例打开(左栏默认 14%、右栏可选),同一父会话组内共享右侧栏面板。 | DSH plugin: sidebar widths as a window ratio, plus one shared right panel across a parent session group.
综合分
29.9
GitHub 分
29.9
用户评分
—
★ Stars
0
周下载量
—
兼容 / 相关生态插件(非 dsh 原生,请按其对应运行时安装)
git clone https://github.com/masknull/dsh-sidebar-ratio.git数据截至 2026/9/16(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动
README
dsh-sidebar-ratio
license
platform
给 DSH(DeepSeek Harness) 网页版的两件事:
1. 侧边栏按窗口比例打开 —— 左栏默认 14%,右栏可选;拖原生把手或快捷键直接调,比例记在浏览器里。
2. 同一个父总会话组内共享右侧栏面板 —— 父代理开着的文件/预览面板,切到它的子代理、孙代理、同级子代理时自动带上同一个标签。
不修改 deepseek-harness 任何源码文件。 宽度靠浏览器运行时改内联样式;面板继承只用官方公开的客户端 API。
为什么需要它
侧边栏宽度是写死的像素值。 DSH 原生左栏宽度是固定像素、拖动区间只有 264~420px
(columns.ts 的 SIDEBAR_MIN/SIDEBAR_MAX),
所以"想比原生更窄"做不到;右侧栏首次打开固定为窗口的 45%。窗口越宽,固定像素占比越小。
右侧栏面板是按会话隔离的。 每个会话各有一份面板状态,新建即"收起、无标签",
所以父代理打开的文件面板,一切到子代理会话就没了 —— 这是原生设计而非缺陷,但对
"父代理指挥、子代理执行"的用法很不顺手。
本插件针对这两点分别用两种手段解决。
功能
一、侧边栏按窗口比例
| 操作 | 效果 |
| --- | --- |
| 拖动原生把手 | 直接改那一列的比例(左、右都可以),不再被 264~420px 夹住 |
| Alt + ← / → | 左侧栏 −1% / +1% |
| Alt + Shift + ← / → | 右侧栏 −1% / +1% |
| Alt + 0 | 总开关:关掉即完全回到 DSH 原生行为 |
- 比例存浏览器 localStorage(key dsh.sidebar-ratio.v1),刷新后保持,不落任何磁盘文件。
- 左栏下限默认 200px、上限 45%;右栏下限默认 300px、上限 70% —— 像素与比例双重夹取,保证中央会话区不被挤没。
- 拖动是接管原生把手实现的,手感与原生一致,而且能拖到 264px 以下。
二、父总会话组内共享右侧栏面板
分组规则:沿会话谱系上溯到顶层,同一个父总会话(顶层会话本身 + 它下面所有层级的子代理)算一组,组内共用一个面板基准。
- 父 → 直接子、父 → 孙、同级子代理之间,行为一致;不同父总会话之间互不影响。
- 只对当前收起的会话生效 —— 目标会话自己已经开着面板时,插件一律不打扰。
- 组基准由谁定(inheritFromParent,默认 false):
- false:组内统一。谁开面板谁成为该组基准,父会话开面板自然成为基准。
- true:严格依据父。只有父总会话能写基准,子代理只读。
- "关掉"只在观测到同一个会话从展开变收起时才认定,所以不会把"新会话本来就没开过"误判成用户关闭。
安装
从 GitHub 安装(推荐)
dsh plugin --profile web add github:masknull/dsh-sidebar-ratio
想固定版本(避免跟随主分支变动):
dsh plugin --profile web add github:masknull/dsh-sidebar-ratio#v0.2.0
CLI 会把包名追加进 profile 的 dsh.profile.bundles,并在启动时应用本包自带的 cordis.patch.yml。
命令行的 git / 路径 / tarball 规格会由 pnpm 先落成真实依赖名,再按真实包名登记到 bundles
(apps/cli/src/plugin.ts:59-91),所以上面这两种写法都会正确登记为 dsh-sidebar-ratio。
从本地目录安装(开发用)
dsh plugin --profile web add
相对路径也可以 —— CLI 会把它锚定到你当前所在的目录(apps/cli/src/plugin.ts:104-112),
所以在本仓库根目录直接执行下面这行同样有效:
dsh plugin --profile web add .
装完必须重启一次
新增 bundle 层只在启动时组合,所以:
1. 重启 dsh web
2. 浏览器 F5
之后改代码,什么时候需要重启
| 改了什么 | 生效方式 |
| --- | --- |
| lib/dom.js(宽度逻辑) | 只需 F5(宿主半边每次渲染 index.html 都重新读这个文件) |
| lib/client.js(面板继承逻辑) | 需要重启 dsh web(客户端 bundle 的装载图在启动时组合) |
| lib/index.js、cordis.patch.yml | 需要重启(apply 只在启动时执行一次) |
本包是纯 JavaScript,没有任何构建步骤:从 GitHub 装下来即可运行,不需要 pnpm build。
配置
在 cordis.patch.yml 的 config 里改(改完需要重启):
| 键 | 默认 | 说明 |
| --- | --- | --- |
| left | 0.14 | 左侧栏占比;null = 不接管左栏 |
| right | null | 右侧栏占比;null = 不接管右栏 |
| minLeft | 200 | 左栏像素下限(原生是 264) |
| minRight | 300 | 右栏像素下限(原生 RIGHTBAR_MIN 是 300) |
| enabled | true | 宽度接管总开关的默认值 |
| inherit | true | 是否启用「父总会话组内共享右侧栏」 |
| inheritAll | false | true = 忽略分组,任意会话切换都继承 |
| inheritFromParent | false | 组基准规则,见「功能二」 |
控制台 API
// 宽度
dshSidebarRatio.get() // 当前状态;leftBlocked / rightBlocked 会说明"设了但当前不生效"的原因
dshSidebarRatio.set(0.12) // 左栏 12%(写 12 也表示 12%)
dshSidebarRatio.right(0.26) // 右栏 26%
dshSidebarRatio.enabled(false) // 临时交还原生行为
dshSidebarRatio.native() // 两侧都交还原生
dshSidebarRatio.reset() // 清掉 localStorage 记录,回到配置默认值
// 排查
dshSidebarRatio.debug(true) // 打开实时日志
dshSidebarRatio.trace() // 最近 40 条内部事件(谁触发、改成了什么)
dshSidebarRatio.probe() // 立刻按当前 DOM 重解一次,返回前后签名
// 面板继承
dshSidebarInherit.get() // 各父总会话组的当前基准、当前会话属于哪一组
dshSidebarInherit.enabled(false)
dshSidebarInherit.all(true) // 忽略分组
dshSidebarInherit.rootOf(id) // 某个会话属于哪个父总会话组
dshSidebarInherit.verbose(true)
工作原理
宽度:接管 DSH 自己的内联样式,但和 React 讲清楚"谁写的"
插件改的是 React 托管的内联样式(frame 的 grid-template-columns、左栏内容的 width、
两个把手的 left、右侧面板的 width)。难点不在"改",而在和 React 抢方向盘时不打架,所以有三条规则:
1. 谁改的必须分得清:每次写入前先"认账" —— DOM 现值不等于我们上次写过的值,说明是 React 刚写的,
记为"原生值"。还原时写回这个最新原生值,而不是第一次接管时的过期快照。
2. 重写必须赶在绘制前:MutationObserver 回调本身就是微任务、在绘制之前执行,所以命中时同步重写,
不排 requestAnimationFrame —— 排 rAF 会慢整整一帧,那一帧就是肉眼看到的"官方宽度闪一下"。
3. 观察白名单只是快路径,不是唯一路径:回调只认 frame、两个列容器和插件接管的那几个节点
(中央会话列被刻意排除 —— 流式输出会产生海量 style/class 变更)。白名单认不出、但落在列容器内部的
结构变化(React 换掉中间 wrapper、重建面板)走下一帧核对签名;再兜一层每 400ms 的签名比对
(只读 5 个内联样式串,纯 CSSOM 读、不触发排版),外加 ResizeObserver 覆盖"框体尺寸变了但没 window resize"。
最坏收敛时间有硬上限,不依赖"哪条 mutation 会被漏掉"的假设。
面板继承:只记"意图",再借官方 API 重放
官方公开面里唯一能跨会话写的入口是 ctx.sidebarRight.openTabIn(sessionId, kind, options) /
openResourceIn(sessionId, address, options),且 openContent 会强制 setExpanded(true) ——
即"打开标签"必然把该会话的右列展开。反过来,没有任何公开 API 能读另一个会话的标签集
(active()/mounted() 只读上屏会话),所以插件自己记住"当前上屏会话开着哪个标签"
(kind + contentId)作为组基准,切到组内收起状态的会话时重放。
值得一提的是:DSH v0.1.6-alpha.1 新增的侧边栏终端,官方自己就是用
ctx.sidebarRight.openTabIn(sessionId, 'terminal', { params: … }) 做跨会话重放的
(ui-sidebar-terminal)——
本插件用的正是同一条官方路径。
已知边界
这些不是"没做",而是官方公开面里没有对应能力,或属于原生行为:
| 边界 | 说明 |
| --- | --- |
| 只能继承当前激活的那个标签 | active() 只给当前激活标签;没有公开 API 能列出别的会话的标签集 |
| 继承不了并存的多个标签、分栏、浮窗、mode | 同上;可读的 TabRecord 只有 {id, kind, contentId, title} |
| 继承不了标签内的滚动位置等 params | 导航 params 不在公开读取面内。具体到侧边栏终端:官方恢复流程自带 params: { terminalId } 调 openTabIn,插件读不到那串参数,因此子会话会新开一个终端,而不是接续父会话的那一个 |
| 无法"只展开、不开标签" | 官方没有 setExpandedIn(sessionId, bool) |
| 左栏比例在侧栏收起或帧宽 <1024px 时不生效 | 收起态是 56px 导轨,不该被拉宽(原生 SIDEBAR_AUTO_COLLAPSE) |
| 右栏比例在右栏没有独立轨道时不生效 | 帧宽 <768px 会派生自动全屏(原生行为);该状态下也没有把手可拖 |
| 接管期间的宽度范围与原生不同 | 左栏 200px 下限 / 45% 上限是本插件自造口径;Alt+0 关掉后回到原生 264~420 |
读数气泡与 dshSidebarRatio.get() 的 leftBlocked / rightBlocked 会明确标注“设了但当前不生效”及其原因,
不会假装生效。
排查
| 现象 | 先看什么 |
| --- | --- |
| 宽度没按比例 | dshSidebarRatio.get() 看 leftBlocked / rightBlocked;再 debug(true) 看实时日志 |
| 切会话时闪一下宽度 | dshSidebarRatio.trace():正常应看到「观察器命中」(同步、肉眼不可见);若频繁出现「签名不一致」,trace 里会写明漏掉的 target 形态 |
| 不确定页面加载的是哪个版本 | typeof dshSidebarRatio.trace —— 是函数即新版 |
| 面板继承没生效 | dshSidebarInherit.get() 看 groups 与 currentRoot;verbose(true) 看捕获/重放日志 |
兼容性与维护锚点
开发期已在 cordis 4.0.2、react-dom 18.3.1 的 DSH 源码树上逐条核对,并*对照 dsh-v0.1.6-alpha.1
做过逐字节核验(用 git blob SHA 对撞,而非肉眼比对):本插件依赖的 13 个锚点文件中
9 个与该版本逐字节相同,另 4 个的差异全部是 tag 侧新增能力,本插件依赖的方法、DOM 标记与属性一律未动,
无破坏性改动。
下表的路径均相对于 deepseek-harness 仓库根目录(链接指向核验所用的 tag);DSH 升级后若出现异常,优先核对这几处:
| 依赖的东西 | 位置 |
| --- | --- |
| 三列网格内联样式、frame 上的 data-、把手 [data-side] | ui-layout/…/AppFrame.tsx |
| 边界常量 SIDEBAR_MIN/MAX、RIGHTBAR_MIN、CENTER_MIN、RIGHTBAR_MAX_RATIO | ui-layout/…/columns.ts |
| 轨道过渡、.handle、两列 overflow | ui-layout/…/AppFrame.module.css |
| 左栏内容自带内联 width | ui-sidebar/…/SidebarRoot.tsx |
| 右侧面板 data-sidebar-right-panel + 内联 width | ui-sidebar-right/…/shell/SidebarRight.tsx |
| 跨会话打开标签的公开入口 openTabIn / openResourceIn | ui-sidebar-right/…/service.ts |
| 可读的 TabRecord 结构 | ui-dockkit/…/contract/types.ts |
| 会话谱系字段 SessionSummary.parentId、会话切换信号 | session-controller/…/sessions/service.ts |
| 结构化注入行协议(global / script;script 正文不得含结束标签字面量) | webserver/src/injections.ts |
| 客户端 bundle 发现契约(exports["./client"]、dsh.client.platform) | client/modules/src/index.ts |
开发期的逻辑验证方式是零依赖的桩 DOM 回归(该脚手架不随仓库提供,此处仅说明验证强度):伪造 AppFrame 结构
(含中间 wrapper、面板替换等真实层级)+ 可控计时器 + 手动喂 mutation record,覆盖接管、微任务内同步纠正、
还原最新原生值、单侧还原、阻塞态读数、拖拽拦截等场景;另用变异体反向证明断言不是空转
(把实现改坏必须能被测出来)。
卸载
dsh plugin --profile web remove dsh-sidebar-ratio
然后重启 dsh web + F5。浏览器侧残留只有 localStorage 的 key dsh.sidebar-ratio.v1,
可用 dshSidebarRatio.reset() 清除。
许可
MIT同作者(masknull)的其他插件
扫码进群