中文EN

@whybebabo/dsh-better-workspace

ui已测通过npmMIT

在原生工作区列表之上叠加主题分组:emoji 分组文件夹、筛选与搜索、批量归档,以及带安全边界的永久删除。

下载量 / Downloads
1,826
依赖体积 / node_modules
0.52 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

安装

dsh plugin --profile web add @whybebabo/dsh-better-workspace

沙箱测试结果

阶段结果
1 安装✓
2 列装✓
3 挂载✓
4 启动—

四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。

README

dsh-better-workspace

[English](./README.en.md) | 简体中文

dsh-better-workspace 是 DeepSeek Harness 的侧边栏主题分组插件。它叠加在原生"工作区"区域之上,不替换官方列表:会话仍由宿主管理,插件只在这块区域上重新组织显示,并补上宿主没有的批量操作与安全删除。

有了它,散落在各个工作区里的会话可以按自己的习惯归类:

  • 主题分组:每个工作区内部是一棵树,用 emoji 标记的"分组"文件夹收纳会话,另有系统默认分组与「已归档」桶;
  • 筛选与搜索:工作区下拉筛选、面板内本地搜索、「只看此分组」;
  • 批量操作:归档 / 取消归档 / 移动到分组 / 永久删除,在选择模式下由标题栏一行原生图标按钮承载;
  • 安全删除:DSH 本身没有删除会话的命令,插件自行实现,规则是"宁可拒删"(见[永久删除的安全边界](#永久删除的安全边界));
  • 与原生一致:状态点、置顶上浮、行内悬浮卡、行尾操作条、定时任务时钟、图标与配色,都对齐宿主自己的实现。

插件不会接管 DSH 的其余部分:侧栏折叠、窄视口或路由不可达时,面板会完全隐藏并交还原生 UI(见[失效保护](#覆盖策略与失效保护))。

界面预览

工作方式

  • 叠加而非替换:面板渲染在 shell.overlay,用结构选择器定位原生工作区区域,覆盖矩形与该区域自身盒子重合。被覆盖区域加上 inert + aria-hidden,官方弹窗出现时自动释放。
  • 主题数据单独存放:分组与归属关系写在 <DSH_HOME>/dsh-better-workspace/topics.v1.json 这个单文件 sidecar 里,可直接备份、可与宿主升级解耦;卸载插件后数据仍在。
  • 顺序分两种:分组顺序写入 sidecar(跨窗口共享);工作区与会话的拖拽顺序存在本地偏好 localStorage。
  • 全部走官方命令:打开会话、归档、置顶、分叉、建工作区都调用宿主 uiWorkspace / workspaces 服务,重命名会话走宿主自己的 sessions.using(...)(0.2.1 的 UiWorkspace 没有这个方法,官方改名对话框也是这么做的);插件不声明、不借用其它包的插槽。

安装

环境要求

  • DeepSeek Harness Desktop 或 Web 0.2.1-rc.x,@deepseek-ai/cordis 4.0.5;
  • Node.js ≥ 22.19;
  • 本机可用 Git(以 github: 方式安装时)。

从 npm 安装(推荐)

dsh plugin --profile web add @whybebabo/dsh-better-workspace

DSH 会把插件装进 Web profile,并把 @whybebabo/dsh-better-workspace 注册到 dsh.profile.bundles,不需要克隆仓库、手动安装依赖或构建客户端。

没有全局 dsh 命令时,用 npx 执行:

npx @deepseek-ai/dsh plugin --profile web add @whybebabo/dsh-better-workspace

安装命令需要本机可以使用 Git 与 pnpm;使用 npx 时还需要 Node.js。

Desktop 会修改 desktop profile,装之前建议先备份 cordis.patch.yml / package.json / pnpm-lock.yaml:

dsh plugin --profile desktop add @whybebabo/dsh-better-workspace

从 GitHub 安装

不经过 npm,直接从仓库安装某个发布版本:

dsh plugin --profile web add github:whybebabo/dsh-better-workspace#v0.1.10

把 #v0.1.10 换成你要的 tag。这条路径同样需要 Git 与 pnpm,也不需要克隆仓库。

从源码安装

需要改代码或跟 main 分支时:

git clone https://github.com/whybebabo/dsh-better-workspace.git
cd dsh-better-workspace
npm install && npm run build

先在不影响现有 profile 的隔离环境里验证一遍:

dsh --profile topic-e2e --from-default-profile web --dump-config
dsh plugin --profile topic-e2e add "link:$(pwd)"
dsh --profile topic-e2e --no-open --port 8791      # 打印带 token 的 URL

确认无误后装到日常使用的 profile:

dsh plugin --profile web add "link:$(pwd)"

以 link: 方式安装时,宿主读取的始终是当前目录的产物:改完代码 npm run build 并重启即可,不必重新 add。

启动或重启 DSH

安装后关闭旧的 DSH Web 进程并重新启动:

dsh web

使用 npx 的启动方式:

npx @deepseek-ai/dsh web

打开侧栏,点「工作区」标题旁出现的 ▾,或把鼠标移到「工作区」上——看到工作区下拉与分组树,说明插件已加载。

升级

发布新版本后重新执行安装命令并替换版本:

dsh plugin --profile web add @whybebabo/dsh-better-workspace

随后重启 DSH。以源码方式安装的则用:

git pull && npm install && npm run build

卸载

dsh plugin --profile web remove @whybebabo/dsh-better-workspace

主题数据保留在 <DSH_HOME>/dsh-better-workspace/,需要清除请手动删除该目录。

验证安装

插件在宿主上注册了只读的 GET /state。浏览器访问(端口换成你实际使用的):

Invoke-WebRequest 'http://127.0.0.1:3080/dsh-better-workspace/api/state' | Select-Object StatusCode

预期状态码 200,返回体里 ok: true、result.workspaces 是你的分组数据。

该路由只接受本机回环 + 同源请求,用别的机器访问会拿到 403,这不是故障。

用法

分组

  • 新建分组:工作区 ⋯ 菜单,或标题栏 + 菜单里的「新建主题并放入…」;也可以把会话拖到目标分组来实现归类。新分组默认排在该工作区分组列表的最上面,创建后不用再滚到底部去找。从工作区 ⋯ 菜单创建时,所属工作区会自动展开,新分组滚进视野并短暂高亮——即使之前折叠了这个工作区,也不会出现「建完却找不到」。新建会话界面的分组选择栏(输入框上方的分组 chip)里新建分组,则会把当前会话直接归入新分组,chip 立即显示它。
  • 新建会话:分组行尾的 + 直接在该分组下新建会话(工作区行尾的 + 则在该工作区新建)。
  • 改名:双击分组名直接内联编辑(重名与非法字符会即时提示并禁用保存)。
  • 悬停分组名:显示完整的分组名称,名字被省略号截断时也能一眼看全。
  • 排序:拖动分组行,拖到目标行的上/下半区决定插入位置。拖动开始时,同一级的所有行——包括被拖动的那一行——会从指针所在位置向外依次收起(300 ms 缓动,逐行 20 ms 延迟,最远 4 档),被拖分组庞大的会话列表不会再挡住目标表头;松手后恢复原来的展开状态,并把各行以 200 ms 缓动滑到新位置,而不是瞬间换序。拖动会话时同理:本工作区的其它分组会收起,只保留被拖会话所在分组的行(那是组内排序的区域),把会话拖到较远的分组只需对准它的表头。
  • 只看此分组:分组 ⋯ 菜单里的筛选会同时锁定它所属的工作区——同名分组不会跨工作区串味。
  • 删除分组:只清除归属,组内会话回到系统默认分组,不删会话。

每个工作区都有系统默认分组,不能改名或删除,但可以像普通分组一样拖动排序。

会话

  • 双击重命名(与桌面端一致);
  • 悬停出现原版同款悬浮卡:完整标题、相对时间、空闲/进行中/待回答状态,已归档则显示归档标记;
  • 悬停被截断的标题:与原生一致,标题以约 30 px/s 匀速滚到末尾后停在末尾(不回弹、不来回摆);移开鼠标立刻回到开头。溢出不足 8px 时不滚(否则看起来像抖动),开启「减少动态效果」时直接跳到末尾;
  • 行尾 hover 出现 ⋯ / 归档 / 置顶,悬停时行内时间让位;
  • 拖拽:拖到别的工作区会拒绝(护栏),拖到别的分组则直接归入;拖动期间本工作区的其它分组会自动收起(被拖会话所在分组保持展开,组内排序照常),因此把会话拖到远处的分组只需对准它的表头;
  • 置顶会真正上浮到所属分组顶部(按宿主置顶顺序,最近置顶在前)。

新建会话落在哪里

  • 工作区行的 +、rail 上的「新建会话」:会话不被写入任何分组归属,因此留在系统默认分组里,并按原生顺序排在该桶最前面——与官方列表一致;
  • 标题栏 + →「新会话」:先选工作区与分组(默认分组也在列表里),再建会话并按所选归组;
  • 分组行的 +、+→「新会话」里显式选中的分组:先建会话,再把它归入该分组;
  • 正在「只看此分组」时新建:归入当前筛选的那个分组(此时它就是你正在看的地方);只有新空白确实属于该工作区时才会写入,另一个窗口在别的工作区新建的空白不会被误归;
  • 分叉会话:子会话跟随源会话所在的分组(行菜单、官方分叉快捷键、聊天视图里的分叉都适用);树投影直接按源分组渲染,不会先在默认分组闪一下再跳过去,写入归属只是持久化;源会话本身就在默认分组时不写归属,子会话自然留在默认分组;
  • 早先版本会把隐式新建的会话塞进「最近创建的分组」;分组当时按创建时间升序渲染,那个分组通常排在最后,于是新会话直接掉到了工作区最底部。该行为已移除;现在新建分组本身默认置顶,更不会把新会话带到列表末尾。
默认分组本身也能被拖到别的位置(与原生一致:它只是「不能改名、不能删除」,排序不受限)。把它拖到下面时,不归组的会话会跟着它排在那个位置——这是你自己排的序,不是插件又把新会话送到底部;拖回顶部即可恢复。

手动排序与新建会话

拖动会话产生的顺序只对它点名过的 id 生效:这些 id 在各自原有的槽位上互相置换,未出现在手动顺序里的会话(例如拖拽之后才新建的那个)保持宿主给的位置,不会被降级到末尾。这样「先手动排一次,再新建会话」不会把新会话挤到列表底部。

在此之上还有一条与原生对齐的活动提升:某个会话的 updatedAt 变新(发出第一条消息、被回复、另一个窗口写入、本来就还没落账的新会话首次出现),它会被提到所属工作区顺序的最前面,并写回本地顺序。宿主不会为「新会话」重新挂载一个已经存在的空白,而是直接复用那个空白;它此前只是靠 blank 被顶到前面,第一条消息清掉这个标记后就会掉回旧槽位——活动提升就是补上这一步。刷新页面不做整表重排:首次快照只记录时间戳,不会改动你已经排好的顺序。

批量操作

点标题栏的「选择」进入选择模式,选择模式接管标题栏:退出、已选数量、归档/取消归档/移动/永久删除排成一行原生图标按钮,窄侧栏不折行。

  • 选择混入已归档条目时,归档与移动置灰;混入未归档条目时取消归档置灰;混入未分组会话时移动置灰;
  • 工具栏下方直接说明置灰原因,悬停也有提示;
  • 暂存中的「新会话」占位行不参与批量选择;
  • 「全选」只包含当前显示出来的行:分组头复选框、分组 ⋯ 菜单、工作区 ⋯ 菜单走同一个派生(selectableIds),超过「显示全部 60 条」的分组会提示「已选中 N 条;另有 M 条未显示」,展开后再选即可——不会悄悄把没渲染过的会话带进批量删除;
  • 另一窗口删掉的会话会从批量

…(truncated)

以上内容来自 npm 上的 README,我们只做格式化,不改内容。

版本

npm 上共发布:10,最后更新 2026-11-03

链接

GitHub · Homepage · npm

同类插件