dsh-hidden-workspaces
Verified@szhl/dsh-hidden-workspaces · v1.0.1 · MIT · Web UI
DeepSeek Harness plugin: hide a whole workspace from the sidebar and bring it back with one view option — the workspace, its sessions and its registration stay untouched.
Install
dsh plugin add @szhl/dsh-hidden-workspaces Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Published to npm without a public repository. Inspect the package contents before installing.
Tags
Readme
@szhl/dsh-hidden-workspaces
把整个工作区从侧栏里收起来。侧栏工作区行右侧的「⋯」菜单里多一项隐藏工作区,点一下,这个文件夹的标题行、它名下的会话行、折叠计数一起从列表里消失;侧栏顶部「视图选项」里多一节筛选工作区,两个选项:
- 不展示隐藏工作区(默认勾选)
- 展示隐藏工作区 —— 选中后,之前隐藏的工作区照常显示,再从它的「⋯」菜单里点取消隐藏,它就回到普通状态。
隐藏只改浏览器这边的显示:工作区登记、会话、磁盘上的文件一概不动,也没有任何东西写进 profile。
安装
dsh plugin --profile desktop add @szhl/dsh-hidden-workspaces
--profile 换成你自己的 profile 名(桌面版是 desktop);dsh plugin 会把后面的参数转交给 profile 里的 pnpm。装完重启 DSH 生效。
(本地开发时也可以在 profile 的 package.json 里用 link: 挂进来,再把包名加进 dsh.profile.bundles。)
用法
- 侧栏里把鼠标移到某个工作区行上 → 点行尾的「⋯」→ 菜单里「重命名」下面就是隐藏工作区(红色「删除工作区」仍然在最后)。
- 点它,那个工作区连同它名下的会话就从列表里消失了。
- 想找回来:点侧栏工作区标题右边的视图选项(滑杆图标)→ 最下面新增的一节筛选工作区 → 选展示隐藏工作区,被隐藏的工作区就照常显示出来 → 再点它的「⋯」→ 取消隐藏。
两个选择都记在浏览器里(localStorage 的 dsh-hidden-workspaces.v1),刷新页面、重启 DSH 都还在。
隐藏都做了什么
- 整节收起:浏览器的树把「一个文件夹 = 一个 section」渲染成一个容器(工作区行 + 它名下的会话行 + 「展开其余 N 个会话」+ 树形模式下挂在它下面的子工作区)。插件给这个容器打一个
data-dsh-hidden-workspace属性,配合一条display: none !important的样式把它整节移出列表。 - 单列表模式也一样:这种模式没有文件夹行,插件改为直接按「这个会话属于哪个工作区」(
ctx.workspaces.list里每个工作区的sessionIds)给会话行打标记,所以隐藏的工作区在单列表里也不会剩下会话行。 - 过滤开关只影响显示:选「展示隐藏工作区」时,所有标记都被摘掉,隐藏的工作区原样显示(按需求不做灰化、不加角标);它的「⋯」菜单这时会显示取消隐藏。
- 点完之后焦点回到原来的按钮:插件按宿主的方式收菜单并把键盘交还给触发它的那个按钮(工作区的「⋯」或视图选项),鼠标点完不会留下焦点悬空。
- 登记表变了会自己对齐:工作区被真正删除后,它的隐藏记录会在下一次完整的工作区快照到达时被忘掉(重新添加同一个文件夹不会莫名其妙又是隐藏的);而快照还没到、或者这次读取失败时,记录一律保留,不会因为一次空的列表就把你的设置清掉。
为什么是「动 DOM」而不是注册插槽
官方的工作区浏览器只给会话行留了扩展位(sidebar.workspaces.session.menu.item / sidebar.workspaces.session.row.action);工作区行的「⋯」菜单和视图选项菜单是 Rows.tsx / WorkspaceBrowser.tsx 里的两个写死的数组,没有任何插槽可以占,而整个侧栏浏览区本身是一个 single 类型的洞(唯一的占用者就是官方浏览器);能改的共享原语 @deepseek-ai/dsh-client-ui-primitives 的 Menu 又是冻结的平台种子模块,改不动。
所以这个插件走的是外观类插件同一条路:读浏览器渲染出来的 DOM。它只用浏览器自己的结构性约定,不碰样式表里的哈希类名:
| 用到的钩子 | 来源 |
|---|---|
data-row-key="workspace:<id>" / "session:<id>" / "overflow:<id>" |
浏览器自己的 AnimatedRows 就是靠它给行动画排序的 |
一个 section 容器 = 树根或 role="group" 的直接子元素 |
树的真实结构(工作区行 + 子工作区 + 会话行 + 折叠计数) |
菜单卡的 role="menu" / menuitem / separator / presentation 标题行 |
共享 Menu 自己的 ARIA 契约 |
ctx.workspaces.list |
公开的工作区投影(哪个会话属于哪个工作区) |
插进去的菜单行是克隆菜单里已有的行再换文案和图标:哈希类名、图标格、文案格、选中打勾的样式都照抄屏幕上那一份,所以它和宿主行长得一模一样,也照常参与菜单的键盘走位(方向键、Tab 选中、Esc 关闭、关闭后焦点回到触发按钮)。
有一处没有身份钩子:「视图选项」菜单既没有 id 也没有 data 属性,只能靠它自己渲染的文案认(筛选会话 / 隐藏已归档 / 全部对话(显示已归档) / 仅显示已归档,中英两份都在 HOST_COPY 里)。将来某个版本改了这几个词,代价是这个插件少一节「筛选工作区」,别的都不会坏 —— 所有插入都是这种「认不出就不插」的尽力而为,不会把侧栏弄坏。
限制
- 只动侧栏列表。搜索结果的会话行、空状态里的工作区选择器、以及别的前端(比如「在工作区里新建会话」)都照旧显示隐藏的工作区 —— 隐藏是一个列表视图上的状态,不是权限。
- 隐藏一个工作区不会关掉它里面正开着的对话:主区域继续停在那个会话上,只是侧栏那一行不见了。想回去就按上面的步骤显示并取消隐藏。
- 树形模式下隐藏父文件夹,会连它下面嵌套的子工作区一起收起(它们在同一个 section 容器里)。子工作区自己是独立的工作区,单独隐藏/取消隐藏互不影响。
- 单列表模式下看不到「⋯」菜单(那种模式没有文件夹行),所以隐藏/取消隐藏要在「按工作区」或「按工作区树」分组下操作。
- 依赖运行时 DOM 结构:DSH 若改动上面那张表里的钩子(
data-row-key的写法、菜单的 ARIA 结构、或那几句文案),对应的那一半会静默失效(不插行、或不再隐藏),不会报错也不会影响侧栏本身。 - 隐藏的是「这个工作区」,不是「这个路径下的所有东西」:同一目录不会被注册成两个工作区,所以按路径回退匹配只是为了让「删掉又加回来」的工作区保持隐藏。
验证状态
client.js/index.js语法、package.json、两份 locale JSON 均已校验。- 侧栏行为测试:
.tools/test-hidden-workspaces.mjs,57/57 通过(jsdom + 按安装包里真实渲染结构搭的假页面:侧栏树、工作区行、会话行、折叠计数、以及共享Menu的菜单卡)。覆盖:菜单里那一行插在「删除工作区」之前且保持宿主行的结构与图标格;点击后整节(含会话行与折叠计数)被标记;未分组那一节永远不动;点我们插的行会关菜单并把焦点还给触发行(走宿主的指针关闭路径,且不发出任何合成按键);只有 Escape 一条路的菜单也能关掉、焦点照样回到触发行;「视图选项」里新增的分隔线/标题/两个选项位置正确、默认项带勾、勾的样式和类名抄自宿主当前选中项;切到「展示隐藏工作区」会摘掉所有标记并落盘、焦点回到视图选项按钮;重新打开菜单显示「取消隐藏」并能清掉记录;单列表模式下按sessionIds隐藏会话行(并断言getComputedStyle真的是display:none);刷新(重新 apply)后仍生效;按 id 和按路径两种匹配;登记表里已经没有的工作区会被忘记,而快照 pending / 读取失败时记录保留;后到的会话行会被补标记、改派到可见工作区的会话行会自己放开;只认识那两个菜单(同形状但没有工作区行点击记录的菜单、以及有别的标题的菜单都不碰);中英两套文案;以及卸载后标记、注入行、样式表、监听器全部撤掉。 - 关菜单为什么不发 Escape:视图选项按钮自带 Tooltip,而 ui-primitives 的 Tooltip 只要发现「上一次输入不是指针」就会在获得焦点时弹泡(
pointerModality()守卫,输入模态由 window 上的 keydown 监听翻转)。合成 Escape 正好会把它翻成键盘,于是菜单把焦点交还按钮时那枚「视图选项」气泡就冒出来了。所以指针激活时改走 Menu 自己的外部 pointerdown 关闭路径(不合成按键、不翻模态),焦点由插件自己交还给触发行;键盘激活(click的detail === 0)仍走 Escape,和宿主行被键盘选中时的行为一致。测试里两条路径各有一组断言,并直接断言指针路径没有发出 Escape。 - 仍需人工点一次(插件要重启 DSH 才会加载,而重启会结束当前会话,所以这一步交给操作者):隐藏一个工作区,确认 ①它整节从侧栏消失 ②刷新页面后仍然消失 ③「视图选项 → 展示隐藏工作区」能让它原样回来 ④「取消隐藏」之后它和普通工作区完全一样 ⑤选完不再弹出「视图选项」气泡。
- 仍需人工点一次(插件要重启 DSH 才会加载,而重启会结束当前会话,所以这一步交给操作者):隐藏一个工作区,确认 ①它整节从侧栏消失 ②刷新页面后仍然消失 ③「视图选项 → 展示隐藏工作区」能让它原样回来 ④「取消隐藏」之后它和普通工作区完全一样。
许可
MIT © 2026 suzhilin