🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

工作区层级树 lsdt45/dsh-workspace-plus

DeepSeek Harnessv0.4.0
lsdt450 天前有提交已提供中文文档扫描:含敏感能力

给 DSH 的侧边栏装上「文件夹系统」与浏览器式会话标签页,外加统一状态点与插件配置页

32.9/100
综合分
4
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/11/3 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

自动兼容检查有告警:npm 同名包「dsh-workspace-plus」归属 sen70s/dsh-workspace-plus,装到的可能不是本插件。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add lsdt45/dsh-workspace-plus
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · browser
装得上吗
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 0 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/10/1) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意

npm 同名包「dsh-workspace-plus」归属 sen70s/dsh-workspace-plus,装到的可能不是本插件

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✓npm 包dsh-workspace-plus @ 0.4.0
✓Node 引擎要求 >=18 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/9 17:37:46

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件写入剪贴板(不计风险)发起外部网络请求
查看扫描证据(共 17 处,展示前 14 条)
  • 读取本地文件
    dist/index.js:137
    const raw = readFileSync(path);
  • 读取本地文件
    dist/index.js:165
    names = readdirSync(sessionDir);
  • 读取本地文件
    dist/index.js:179
    workspaces = readdirSync(sessionsRoot);
  • 读取本地文件
    dist/index.js:188
    if (!statSync(workspaceDir).isDirectory()) continue;
  • 读取本地文件
    dist/index.js:189
    sessionDirs = readdirSync(workspaceDir);
  • 读取本地文件
    dist/index.js:196
    if (!statSync(sessionDir).isDirectory()) continue;
  • 写入本地文件
    dist/index.js:246
    mkdirSync(dirname(options.dbPath), { recursive: true });
  • 删除本地文件递归
    dist/index.js:559
    await rm(sessionDir, { recursive: true, force: true });
  • 发起网络请求
    dist/client.js:751
    const response = await fetch(SESSION_DELETE_ROUTE, { method: "GET" });
  • 发起网络请求
    dist/client.js:757
    const response = await fetch(SESSION_DELETE_ROUTE, {
  • 写入剪贴板
    dist/client.js:772
    if (typeof writeClipboard === "function") return writeClipboard(text);
  • 写入剪贴板
    dist/client.js:774
    await navigator.clipboard.writeText(text);
  • 发起网络请求
    dist/client.js:780
    const response = await fetch("/api/session/openWorkspacePath", {
  • 发起网络请求
    dist/client.js:6449
    response = await fetch(SESSION_SEARCH_ROUTE, {
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-settings@deepseek-ai/schemastery
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 层级工作区树
  • 时间分桶视图
  • 会话置顶

DSH web 插件:层级工作区树 + 时间分桶视图 + 会话置顶。fork 自 KannaKuron/dsh-better-workspace

README

由 DeepSeek 最新模型翻译生成
dsh-workspace-plus 给 DSH 的侧边栏装上「文件夹系统」与浏览器式会话标签页,外加统一状态点与插件配置页 Awesome DSH Plugin 简体中文 · English DSH 插件:给 DeepSeek Harness (DSH) 侧边栏的「工作区」列表装上一套文件夹系统——工作区还是那个工作区(一个目录),但标题里的 / 就是层级,让「网页前端」「网页后端」这类工作区归到同一个 web 分组下;再叠加浏览器风格的会话标签页、统一状态点与插件配置页。 - 🗂️ 层级树 —— 工作区 / 会话标题里的 / 即分组,任意多级;另含分区、置顶、时间分桶与拖拽排序 - 📑 会话标签页 —— 点击会话即开新标签(Shift+点击改为替换当前标签,可在设置里把两种手势对调)、行末 + 一键新会话、未发送的新会话标签切走也不关、右键复用会话菜单、拖拽实时排序;标签过多时先压缩、再滚动,并以「全部标签页」列表兜底;顺序随重启恢复,最多 12 个 - 🌿 气泡详情 —— 悬浮会话行或标签页弹出的气泡里带上「项目 · 当前 git 分支 · 时间」,气泡取不到分支时自动省略该段 - 🔍 全文检索 —— 窗口正中的浮层搜索:标题即时匹配 + 会话正文检索(插件自带容错索引,坏日志逐条跳过);「内容」开关、⌃1–9 直达。
展开完整文档(README 剩余 1 节)
dsh-workspace-plus

给 DSH 的侧边栏装上「文件夹系统」与浏览器式会话标签页,外加统一状态点与插件配置页

Awesome DSH Plugin

简体中文 · English

DSH 插件:给 DeepSeek Harness (DSH) 侧边栏的「工作区」列表装上一套文件夹系统——工作区还是那个工作区(一个目录),但标题里的 / 就是层级,让「网页前端」「网页后端」这类工作区归到同一个 web 分组下;再叠加浏览器风格的会话标签页、统一状态点与插件配置页。

- 🗂️ 层级树 —— 工作区 / 会话标题里的 / 即分组,任意多级;另含分区、置顶、时间分桶与拖拽排序
- 📑 会话标签页 —— 点击会话即开新标签(Shift+点击改为替换当前标签,可在设置里把两种手势对调)、行末 + 一键新会话、未发送的新会话标签切走也不关、右键复用会话菜单、拖拽实时排序;标签过多时先压缩、再滚动,并以「全部标签页」列表兜底;顺序随重启恢复,最多 12 个
- 🌿 气泡详情 —— 悬浮会话行或标签页弹出的气泡里带上「项目 · 当前 git 分支 · 时间」,气泡取不到分支时自动省略该段
- 🔍 全文检索 —— 窗口正中的浮层搜索:标题即时匹配 + 会话正文检索(插件自带容错索引,坏日志逐条跳过);「内容」开关、⌃1–9 直达。首次内容检索会在后台建索引,需几十秒,期间标题检索照常可用
- 🔴 状态点 —— 每行统一 6px:运行橙呼吸 / 待交互琥珀 / 完成绿,标签条同步显示
- 🎛️ 插件配置页 —— 「展示会话标签页」「启用圆点状态」等开关,关掉即还原宿主原生顶栏与状态灯
- 📦 装上就能用 —— 预构建产物随仓库与 Release 提供,从 git 安装无需构建

更新提示:dsh plugin --profile desktop update @lsdt45-dal/dsh-workspace-plus(Web 端把 desktop 换成 web),更新后重启 DSH 生效;标签页与状态点都可在「设置 → 插件 → 更好的工作区」里逐项开关。

Fork of KannaKuron/dsh-better-workspace

目录:功能与效果 · 安装 · 工作原理 · 开发 · 更新日志 · License

功能小节索引

- 层级树
- 添加工作区:点选分区与分组
- 分组增删
- 会话标签页
- 搜索
- 工作区与会话分区
- 视图配置
- 插件配置页
- 会话置顶
- 状态一目了然
- 外观自定义
- 单链折叠
- 拖拽
- 右键菜单
- 不丢原生能力

github/ ← 虚拟分组(不是真实目录,纯命名层级) └─ dsh-plan-plus ← 工作区「github/dsh-plan-plus」 dsh-workspace-plus ← 原有的单层工作区照常工作 codeisland-ask-bridge dsh-model-config

功能与效果

层级树

层级树(项目视图)工作区名称里的 / 即分组:如 github/dsh-plan-plus 自动归入 github 虚拟分组,支持任意多级;单层工作区(如 dsh-workspace-plus)照常显示在根层。重命名工作区后树即时重排——分组只是名字的投影,没有第二份需要同步的数据。

添加工作区:点选分区与分组

点「添加工作区」并选完文件夹后,弹出一个小对话框,两个目标字段都可直接点选,不再是只能打字的原生 datalist:
- 所属分区:点开就是分区列表,单击即选中(含「不分区(项目)」);也可以就地「新建分区…」输入名称,回车或「确定」后随工作区一起创建——取消弹窗不会留下空分区。
- 所属分组:自由输入名称路径(如 web),下拉里列出已有层级并可单击选中,也支持「新建分组「…」」与「不嵌套(根级)」。

两处控件外形一致(方框右内侧同一个箭头),下拉都是浮层:展开/收起时弹窗高度不变,也不会被弹窗圆角裁切;最后一个「所属分组」的下拉在空间不足时自动向上展开,因此底部按钮始终可见。列表展开时按 Esc 只收起列表,不会关闭整个弹窗;支持单击选择与 ↑/↓/Home/End 走查。对话框底部实时预览最终标题(如 web/frontend/新项目)以及是否并入某个分区。确认后插件创建工作区、写入分组前缀并使它立即出现在所选分区下。对话空态页的「添加工作区」走的也是这条交互。

远程 / 无桌面宿主:DSH 可能只提供 browse(应用内目录浏览)而不是 OS 原生选择器。此时「添加工作区」会自动切到插件内置的目录浏览器:逐级进入文件夹、显示隐藏文件夹、就地新建文件夹,点「选择此文件夹」后再进入分区/分组弹窗。原生选择器可用时仍优先用它,行为不变。

分组增删

右键任意分组行即可:新增子分组(路径自动带上父分组前缀)、新增子工作区(选完目录后所属分组输入框自动预填)、重命名分组、删除空分组;标题栏不放独立按钮。空分组持久保存在浏览器本地;一旦有工作区落进去,分组就由名称自然派生。

会话标签页

打开的会话一个占一个标签,排在对话顶栏、视图切换行上方:每个标签自带状态点、标题和关闭按钮,当前标签用品牌色下划线 + 加粗标题强调。行末还有一个 + 用于新建会话。

- 打开方式:点击左侧会话 = 在新标签页打开(不会顶掉正在看的页面);Shift + 点击 = 替换当前标签里的会话。两者可在「设置 → 插件 → 更好的工作区 → 点击会话即在新标签页打开」里对调:关掉开关后普通点击恢复「替换当前标签」,Shift+点击则改开新标签。新建会话(标签条行末的 +、工作区行的 + 按钮、快捷键,或任何宿主入口)自动开一个新标签——标签条上的 + 调用的就是宿主自己的「新会话」入口,工作区由宿主按「当前工作区 → 最近工作区」挑,和快捷键完全一致——未发消息时标签显示「新会话」,发出第一条消息后变成正式标题。未发送的新会话标签不会因为你切到别的会话而被关掉——它留在原处,点回来即可继续输入。标签槽位于顶栏左侧的公开插槽;标签条宽度按顶栏实际可用空间测量(52vw 只是首次测量前的兜底),不会挤占右上角的宿主控件。
- 悬停看详情:鼠标停在标签上会弹出一个气泡(位置在标签下方),显示完整标题和「所属项目 · 当前 git 分支 · 更新时间」,和左侧会话行悬停时的气泡同一套样式,长标题被截断也能看全。分支名取该标签所属项目目录(会话的 cwd)当前检出的分支;目录不是 git 仓库、detached HEAD 或取不到时,自动省略这一段,其余内容照旧。
- 标签宽度自适应:每个标签按自己的标题自适应宽度(短标题短、长标题长,上限 200px,下限 72px),不再被拉伸成等宽;标签条整体以「右侧操作区之前 12px」为上限,标题长、标签多时先压缩到下限再横向滚动,始终不会挤压右上角的宿主控件。
- 标签过多时(溢出处理):标签先按浏览器习惯自动压缩到可读宽度;仍放不下时标签条变成可横向滚动——滚轮/触控板横滑直接滚动标签条,两端出现渐隐提示还有标签,末尾出现 ▾「全部标签页」 按钮。点开即列出全部标签(含被滚出可见区的):状态点、当前项勾选、悬停逐个关闭,右键仍是同一套会话菜单;↑/↓ + Enter 键盘切换,Esc 关闭。切换标签(含从列表里选择)时当前标签会自动滚回可见,不会再出现「最后一个标签被切掉、又翻不到」的情况。
- 右键菜单:在标签上右键,弹出与左侧会话行完全相同的菜单(重命名 / 归档 / 分区 / 置顶 / 分支 / 删除 / 自定义外观 / 刷新…,内容见下文「右键菜单」),因为它复用同一套菜单状态,不是另做一份。
- 拖拽排序:按住标签左右拖动即可实时换位(HTML5 拖拽;拖动中的标签半透明,其余标签即时让位,松手即落位)。
- 持久化与上限:标签顺序与打开的标签列表保存在当前浏览器(dsh.betterWorkspace.tabs.v1),刷新/重启后恢复;最多 12 个,超出时最旧的标签自动退出。
- 关闭与清理:关闭当前标签时相邻标签接管;已归档会话的标签会自动移除。新建但还没发送的「新会话」标签会保留(切到别的会话也不会被自动关掉),只有手动关闭它才消失——切走时目标会话按「开新标签」处理,不会占用刚保留的那个标签位。
- 可以整体关掉:插件配置页的「展示会话标签页」关掉后,标签条消失、顶栏完全还原为宿主原生布局;重新打开即恢复原来的标签列表。

标签放不下时:先压缩、再滚动、最后列全标签按浏览器习惯先压缩到可读宽度;仍放不下就变成可横向滚动(滚轮/触控板横滑),两端渐隐提示还有内容。末尾的 ▾ 按钮列出全部标签——包括被滚出可见区的:每行带状态点与所属项目,当前标签打勾,右侧可逐个关闭,右键仍是同一套会话菜单;↑/↓ + Enter 键盘切换,Esc 关闭。

搜索

点击侧栏标题栏的搜索按钮(或折叠栏的放大镜)打开一个窗口正中的浮层搜索面板,样式对齐 Codex App:

- 标题匹配(即时):输入即在前端过滤会话标题与工作区名,命中的会话排在最前;
- 内容匹配(插件自带索引):防抖后检索历史消息正文,只把消息里命中的会话补进结果,第二行显示命中片段;
- 内容开关:输入框右侧的「内容」开关控制是否检索会话内容;关闭后只做标题匹配、不再发起检索。状态保存在当前浏览器;
- 键盘操作:↑/↓ 选择、Enter 打开、Esc 关闭、⌃/⌘ + 1–9 直接打开前 9 条;鼠标悬停/点击同样可用;
- 打开时先列出最近会话,输入后自动切换为搜索结果;内容索引不可用时自动退化为纯标题匹配,并在面板底部显示原因。

第一次搜到正文会慢一次。「内容」开关默认开启,从输入第 2 个字符起插件就会在后台为 ~/.dsh/sessions 建立本地索引,面板显示「正在建立内容索引(首次较慢)…」。大语料(上万条消息)通常需要几十秒,期间面板不会卡住——标题匹配与最近会话列表照常可用。索引建好后写入 ~/.dsh/storages/workspace-plus-search.db,之后按文件 mtime/大小增量更新,正常检索毫秒级返回;删除该文件会在下次检索时自动重建(同样只需要慢一次)。

旧的侧栏内联过滤框已被浮层取代。浮层挂在宿主的 shell.overlay 座位上,因此面板不受侧栏宽度裁切,可以覆盖到对话区。

性能与容错:本地标题匹配逐键即时;内容检索 180ms 防抖、至少 2 个字符、输入法组合期暂停,同一查询命中面板内缓存,快速退格/重复输入不会重复请求,结果上限 20 条。

内容索引由插件自己维护:直接读取 ~/.dsh/sessions 下的会话日志,损坏或旧格式的日志会被逐个跳过,不会拖垮整次检索(宿主自带的严格索引遇到这类日志会整体失败,这也是这里改用自有索引的原因)。索引的建立与增量更新规则见上文提示块。

匹配语义:英文按单词命中;中文逐字分词,因此中文子串(如「模型」)也能命中。索引只包含用户与助手消息正文,不含思考过程、工具调用与工具输出。

索引不可用时:面板底部显示「内容检索失败:{reason}」,标题匹配与最近列表不受影响;修复环境后重新打开面板即可重试。

工作区与会话分区

分区:把工作区和会话各自归到一处右键工作区或会话 → 分区,选已有分区、未分区(项目)或新建分区…。新建时自动移入当前右键对象;右键分区标题也可创建空分区。
分区是单层结构,工作区与会话共用一份列表:单独分区的会话直接显示在分区下,并带所属工作区角标;分区标题可折叠、可拖拽放置,也可重命名或删除(删除前会确认)。

- 移动粒度:会话操作只移动当前会话;工作区操作连同它的所有会话一起移动,包括此前单独分区的会话。会话可设为跟随所属工作区来撤销独立分区。
- 拖拽归属:把工作区或会话拖到分区标题即移动,拖到「项目」即移回未分区;折叠分区与空分区同样能接收,放入后自动展开。置顶、归档与未分组的会话也支持拖入。
- 与视图的关系:分区只出现在工作区树与工作区视图;单列表、时间视图仍平铺会话。名称路径分组保留在「项目」区域,分区内显示工作区完整名称。
- 排序例外:最近更新排序下仍可移动分区,但显示顺序继续按最近更新排列。

存储与还原:工作区与会话按 ID 保存归属,不改名称、目录或宿主的工作区-会话关联。删除分区后,工作区移回「项目」,单独分区的会话恢复跟随所属工作区。分区归属与折叠状态保存在当前浏览器。

视图配置

单键切换视图侧边栏标题栏的视图按钮预览当前形态(工作区、树、列表或日历),菜单分为「分组方式 / 排序方式 / 筛选会话」,设置 → 插件 → 更好的工作区(Better Workspaces) 配置页里有等效选项(见下文「插件配置页」)。
时间视图(单一全局时间线)跨项目所有会话聚合展示,按「今天 / 昨天 / 近 7 天 / 近 30 天 / 更早」分桶(本地时区自然日),空桶自动隐藏,名称分组此时隐去;方向可选「最新在前 / 最旧在前」。悬浮会话条时,行尾相对时间互换为所属项目小角标(并出现置顶按钮),条目右侧弹出气泡(Codex 风格:贴着行右缘、与行垂直居中;右侧放不下翻到左侧,两侧都放不下才回落到下方。不透明深底,两行:完整标题 + 项目 · git 分支 · 绝对时间,分支取不到时省略该段);气泡由插件自己持有,指针离开、行被重排移走或列表滚动时都会立即收起,不会停留在屏幕上。

- 按工作区树(默认):名称分组树,保留多级文件夹、单链折叠与外观定制。
- 按工作区:各独立分组与「项目」区域内平铺工作区,使用完整名称;切换视图或跨名称分组重排均不改名。
- 单列表:跨工作区平铺会话,悬浮时显示所属工作区角标;手动顺序沿用宿主工作区与其会话顺序,请在工作区视图中拖拽调整。
- 按时间:跨工作区按「今天 / 昨天 / 近 7 天 / 近 30 天 / 更早」分桶,支持最新 / 最旧在前。
- 排序方式:手动排序 / 最近更新独立于分组方式。最近更新按可见会话时间排列工作区、虚拟分组与组内会话,只改变显示顺序;切回手动恢复宿主原顺序。自动排序、单列表与时间视图关闭重排拖拽,置顶区仍保持最近置顶在前。
- 筛选会话:隐藏已归档(默认) / 全部对话 / 仅显示已归档,统一作用于各视图与浮层搜索。仅归档模式隐藏无匹配会话的工作区和空分组;空态提供「查看全部对话」。归档行带标识,右键或悬浮按钮可取消归档;取消归档后才可打开。旧宿主没有恢复接口时禁用恢复入口。
- 偏好持久化在当前浏览器,旧版项目 / 时间视图与排序偏好继续兼容。

插件配置页

设置 → 插件 → 更好的工作区(Better Workspaces)插件在设置里占一个独立配置页(标题旁显示当前插件版本),不用去侧栏菜单里翻:显示:五个开关——展示会话标签页(关掉后顶栏完全还原为宿主原生布局)、点击会话即在新标签页打开(默认开;关掉后普通点击恢复「替换当前标签」,Shift+点击改开新标签)、启用圆点状态(关掉后侧栏改用宿主原生状态灯,标签页不再显示状态点)、单链分组折叠、状态呼吸灯。
视图:分组方式(按工作区 / 按工作区树 / 单列表 / 按时间)、排序方式(手动 / 最近更新)、时间方向(最新在前 / 最旧在前,仅「按时间」视图出现)、筛选会话(隐藏已归档 / 全部对话 / 仅显示已归档)。
与侧栏视图按钮的菜单读写同一份偏好——在配置页改完,侧栏立刻生效;偏好持久化在当前浏览器。

会话置顶

全局置顶托盘任意会话(含未分组)右键「置顶 / 取消置顶」,或行悬浮时点击图钉按钮即可置顶。
全局已置顶区固定在列表最顶:跨工作区聚合、最近置顶在前、行尾带所属工作区小角标、点击直开(自动跨工作区切换);被置顶的会话在原工作区/未分组区内隐藏(只在置顶区展示,取消置顶即回归原位),收起的工作区行保留图钉计数徽标。
置顶行带品牌色小图钉 + 弱底色 + 左侧强调条,与「当前会话高亮」可叠加。纯显示层投影(不改会话顺序/标题),状态跨重启持久;删除后自动取消置顶,归档期间从置顶区隐藏,选择显示归档时在普通列表展示;置顶记录保留,取消归档自动回归置顶区。

状态一目了然

统一的 6px 状态点生成中:插件自绘橙色 #ff9f45 呼吸点,含「{n} 个子任务运行中」(子代理在跑同样按生成中显示);等待批准 / 计划确认 / 回答:琥珀 #d29922;已完成未读:绿色 #3fb950。已读会话不画点,正在查看的会话即使刚跑完也不显示绿点;三种点同一尺寸,状态变化不会让行抖动,橙色也不会和旁边的琥珀看混。有活动定时任务的会话显示闹钟角标(与官方行一致)。当前会话另有行高亮(可与置顶强调叠加)。
可以整体关掉:插件配置页的「启用圆点状态」关闭后,侧栏改用宿主原生的状态灯样式,标签页也不再显示状态点;重新打开即恢复统一 6px 圆点。
状态呼吸灯(插件配置可关):被折叠藏起的状态沿层级向外冒泡——工作区/分组行图标按状态色呼吸发光(自定义过文字发光的标题一起呼吸),会话分组行显示呼吸状态灯;运行橙只在本层呼吸、不外渗,关掉后它是静止橙点。

外观自定义

外观自定义右键任意一层(工作区分组 / 工作区 / 会话 / 会话分组)→「自定义外观」:颜色(9 个预设色板 + 取色器 + RGB 输入)、发光强度(0–14 拖动条,只作用于文字光晕)、字体粗细(常规 / 中 / 半粗 / 粗)、字体阴影开关、图标(71 个:实心 / 空心 / 不显示 3 种文件夹图标样式 + 68 个 dsh 原语图标;图标仅对工作区与工作区分组行生效),底部带实时预览,一键清除即复原。

改完即见颜色、文字发光、字体粗细、阴影与图标按行应用,和展开状态一起经 dsh 客户端 store 持久化在当前浏览器。

单链折叠

插件配置页里的开关(默认开):一层恰好只有一个子级时合并显示为一行(如 测试层1 挂着 AI交易 → 测试层1/AI交易),出现多个子级时自动还原为树;拖拽工作区期间临时展开,任意一级可投放。

拖拽

工作区行拖到另一工作区行上/下半即调整顺序(写回宿主序),拖到分组行即移入该分组;会话行同工作区内拖到另一会话上/下半重排,拖到会话子分组行即移动进该分组。拖拽工作区期间,单链合并显示的行临时展开回文件夹树——路径里每一级都是可投放的分组行,松手后自动合并。显示顺序 = 宿主手动序,拖拽结果立即生效(自动排序、单列表、时间模式、归档行与置顶行不参与重排)。

右键菜单

会话右键菜单右键菜单把操作收进一处,并按功能划分清晰分组:

会话管理:重命名、归档、分区(移入已有分区/新建分区/跟随工作区)、删除会话(永久删除,红色高亮带确认)。
路径与系统:在资源管理器中打开(定位会话目录)、复制工作目录、复制会话 ID。
派生与常驻:创建会话分支(创建后自动打开分支会话)、置顶(快捷加入置顶区)。
外观定制:自定义外观(独立配置行颜色、文字发光、字体粗细与阴影)。
界面工具:刷新(菜单右侧标注 Ctrl+R,即浏览器自身的重载)。

「分区」是二级菜单菜单里的「分区」直接展开第二级:移入已有分区、跟随所属工作区(撤销独立分区)、或当场新建分区…。分区列表与侧栏、工作区树的图标区共用同一份数据,勾选态实时反映当前归属。

工作区行支持重命名、删除、自定义外观;工作区分组行支持新增子分组、新增子工作区、重命名分组(同步更新组内所有工作区名称)、删除空分组、自定义外观;会话分组支持重命名、自定义外观。

目录优先取目标会话的 cwd,缺失时使用所属工作区路径,未分组会话也可使用自己的目录。已归档会话提供取消归档、删除、目录和复制操作。

永久删除由本插件的宿主半实现(POST /dsh-workspace-plus/delete-session;DSH 只有归档、没有删除 RPC)。删除前会确认;确认后宿主先停止运行中的任务、脱离 live session,再只删除「位于会话持久化根目录(通常是 DSH_HOME/sessions)下且目录名与会话 ID 完全一致」的目录,随后清理投影缓存与工作区记账。删除成功后清除本插件的置顶记录并刷新会话列表;被拒绝时(目录缺失、子代理会话、缺少持久化服务、路径越界)提示会给出失败阶段与原因。

不丢原生能力

- 会话行:打开 / 重命名 / 分叉 / 归档;每工作区「新会话」(点 + 总是先展开该工作区,让新会话立刻可见,并在标签条上新开一个标签);当前会话高亮;未分组会话兜底。
- URL/斜杠标题不拆层:宿主自动生成的会话标题落地时若含 /(如复述了 URL),整串自动包上 “” 原样显示,绝不解析成层级——只对本次启动后新建的会话生效,并等命名稳定(约 20 秒,让原生 AI 命名先落地)才处理;存量会话与你手动命名的 / 分组标题永不被改动。引号内(含手动添加)的 / 永不切分,孤立引号只当普通字符;无引号但含 URL 的旧标题也有平铺兜底。
- 中英双语跟随界面语言;会话行行尾显示相对时间(悬浮时让位)。

安装

将插件安装到 DSH 正在使用的 profile。桌面端通常使用 desktop,Web 版通常使用 web。

推荐从 npm 安装(预构建产物、可按版本更新,也是插件市场 Discover 索引的收录来源):

DSH 桌面端
dsh plugin --profile desktop add @lsdt45-dal/dsh-workspace-plus

DSH Web
dsh plugin --profile web add @lsdt45-dal/dsh-workspace-plus

也可以直接从 GitHub 仓库安装(拉整仓,速度稍慢):

dsh plugin --profile desktop add https://github.com/lsdt45/dsh-workspace-plus.git

安装完成后重启 DSH 即生效。

包名迁移(1.2.0 起):包名由 dsh-workspace-plus 改为 @lsdt45-dal/dsh-workspace-plus。npm 上原有的 dsh-workspace-plus 是同名的另一个项目(作者 Sen70s,实现的是「工作区多目录 + Windows 通知」),我们无法在其上发布;加 scope 后才能真正发布并进入插件市场 Discover 索引。旧安装需先卸载再重装:

dsh plugin --profile desktop remove dsh-workspace-plus
dsh plugin --profile desktop add @lsdt45-dal/dsh-workspace-plus

浏览器侧的视图、分区、置顶、标签页与外观数据都存在 dsh.betterWorkspace. 命名空间下,不随包名变化,重装后原样沿用。

插件在 package.json 的 engines.dsh 中声明兼容 DSH >=0.2.0-rc.1 <0.3.0-0;运行时版本不满足时,DSH 会在安装或加载时提示不兼容(可用 dsh plugin allow-version 按精确版本豁免)。

安装时的 WARN

用 dsh plugin add 装任何插件时,pnpm 常会打印这两条警告,它们与具体插件无关,是该 profile 依赖树本身的聚合结果,装完不影响使用:

[WARN] 1 deprecated subdependencies found: domexception@4.0.0
[WARN] Issues with peer dependencies found. Run "pnpm peers check" to list them.

- domexception@4.0.0:由 ds-harness-remote → @roamhq/wrtc 的 optionalDependency 引入,上游已标 deprecated(@roamhq/wrtc 最新版仍是 0.10.0,没有可升级的版本),只能忽略。
- peer dependencies:报告的是宿主(DSH 本体)在运行时提供、但不会装进 profile node_modules 的包(@deepseek-ai/dsh-、react-dom 等)。插件本应以 peerDependenciesMeta.optional 声明,属已知误报。
要彻底消掉,在该 profile 目录(如 ~/.dsh/profiles/desktop)的 pnpm-workspace.yaml 里加:

allowedDeprecatedVersions:
domexception: ''

peerDependencyRules:
版本冲突也记在 missing 里,所以缺的与冲突的都要列 ignoreMissing:
- '@deepseek-ai/'
- 'react-dom'
allowAny:
- '@deepseek-ai/'
- '@omdsh/'

不要用 '' 通配整个列表,否则真正需要关注的 react / cordis 版本冲突也会被一起吞掉。查当前真实清单用 pnpm peers check(在同一个 profile 目录下执行)。

更新

按 profile 更新(npm 与 Git 两种安装方式同一条命令):

dsh plugin --profile desktop update @lsdt45-dal/dsh-workspace-plus

如果使用的是 Web profile,将 desktop 替换为 web。更新后重启 DSH。

使用本地源码预览

将路径替换为本地仓库的绝对路径:

dsh plugin --profile desktop add /absolute/path/to/dsh-workspace-plus

本地目录会以 link 依赖加入该 profile。修改源码后重启 DSH,即可加载本地版本。Web profile 同理,将 desktop 改为 web。

卸载

dsh plugin --profile desktop remove @lsdt45-dal/dsh-workspace-plus

卸载后重启 DSH。Web profile 请使用 --profile web。

工作原理

DSH 的侧边栏浏览区是一个公开插槽 sidebar.workspaces(single),官方工作区浏览器是它的占用者;本插件以更低优先级注册同一插槽,整区替换为层级树版本。数据全部来自插槽标准注入(useWorkspaces / useSessions 快照钩子),动作(打开会话、重命名/删除工作区、归档等)也走注入的宿主动作——不碰任何私有 API。

「添加工作区」则落在 dsh 专门为第三方设计的一条缝里:sidebar.workspaces.directoryFlow 与 conversation.hero.workspace.directoryFlow 两个目录流插槽。触发按钮与忙碌语义由官方持有;本插件负责「触发之后、交付路径之前」的交互——正好用来塞进「选完文件夹 → 弹窗选分区/分组 → 创建 → 改名加前缀 → 并入分区」这条链。宿主只提供 browse 时,这段交互会切到插件内置的目录浏览器(见上)。

这条链在两种宿主下都要能拿到分区与已有分组数据:除了自己占用 sidebar.workspaces 时直接传入 store,两个目录流插槽也各自声明了同一个 store 座位(store: viewStore,均为 root scope,由渲染层按 handle+scope 复用同一实例),所以官方宿主托管该插槽时,弹窗依旧能列出分区与分组。

会话标签页同样不碰私有 API:标签条落在对话顶栏的公开插槽 conversation.header.leading(root scope,与具体会话无关,所以切换会话不会重挂组件),标签列表由插件自己的小 store 持久化。

「当前是哪个会话」不读会话列表快照(快照里没有 current 字段),而是读每条会话摘要上的 mainView 引用计数——官方侧栏判定「当前会话」用的就是它。这样新建会话、快捷键、命令面板、分支(fork)等所有导航路径都能被标签条感知:新的空白会话开新标签;从空白新会话切到别的会话时,目标会话也开新标签(刚建的空白标签保留,而不是被替换掉);插件自己的会话点击在导航前就写好标签列表(tabsForClick,默认新开标签、Shift 替换);其余非点击导航保持「替换当前标签」,不会在用户没点标签条时悄悄长出标签。

气泡里的 git 分支名同样不碰 DSH 私有接口:host 半新增一条同源 JSON 只读路由(POST /dsh-workspace-plus/git-branch),按传入的项目目录执行 git -C <dir> symbolic-ref --short -q HEAD——不经过 shell、不写仓库、单路径失败只省略该路径、结果约 20 秒缓存;client 半只把气泡要显示的目录交给这条路由,路由不可用时气泡自动退回「项目 · 时间」的旧样子。

视图状态(分组折叠、会话展开、显式空分组、标签顺序)、外观自定义与插件设置都通过浏览器本地存储持久化(dsh.betterWorkspace.view.v1、dsh.betterWorkspace.tabs.v1)。注意:view store 的 hydration 是整值替换、不合并默认值——升级后如果遇到状态字段缺失,重启前的旧状态按旧结构保留,缺的键自动回退默认。

开发

构建

整个插件是 TypeScript 工程:浏览器侧源码在 src/client/(src/client/index.ts 为 bundle 入口),宿主侧在 src/index.ts,由 scripts/build.ts 用 esbuild 产出 dist/client.js(+ sourcemap)与 dist/index.js(DSH 客户端模块表每个包只接受一个
bundle:exports["./client"],模块图扁平,拆分源码必须打包回单一产物)。产物一并提交进仓库,从 git / tarball 安装依旧零构建。
开发需要 Node ≥ 22.18:构建脚本与测试直接运行 .ts(原生类型擦除),不额外引入 ts-node / tsx。

npm run build # 源码 → dist/client.js(+ .map) + dist/index.js,原子替换
npm run dev # 监听 src/client/* 与 src/index.ts,改动即重打包(宿主每 500ms 轮询产物,HMR 自动重载插件)
npm run check # 校验已提交 dist/ 与 TypeScript 源码一致(不同步则失败)
npm run typecheck # tsc --noEmit:src / tests / scripts 全量类型检查
npm test # node --test:纯逻辑单测 + 产物契约 + 渲染冒烟 + 架构守卫
npm run verify # typecheck + build + check + test
npm pack # 出 tarball 后可本地安装验证(prepack 会先构建并校验)

不要手改 dist/ 里的产物;改 src//.ts 后至少跑一次 npm run dev 或 npm run build。

产物一致性守卫

dist/ 是提交物,所以有两道防线防止「改了源码忘构建」把旧产物发出去:

- 本地 pre-commit 钩子(.githooks/pre-commit,随仓库版本化):提交时跑 npm run check,dist/ 与源码不一致就阻止提交并打印修复命令;未安装依赖(没有 esbuild)时只提示并跳过,不会卡住全新 clone。每个 clone 启用一次:

bash
git config core.hooksPath .githooks

紧急绕过:git commit --no-verify;停用:git config --unset core.hooksPath。

- CI(.github/workflows/verify.yml,push / PR):npm install → npm run check(在任何构建之前比对已提交产物) → npm run typecheck → npm test。

两道防线只覆盖产物同步与测试;完整本地校验仍是 npm run verify。

插件展示元数据

设置 → 插件里的卡片标题与一行描述也来自插件包自身,不是写死在 README 里:

- locale/en.json、locale/zh.json 的 meta.title / meta.description 是本地化的展示元数据(DSH 按界面语言选择);缺省时回退到 package.json 的 name / description。
- DSH 只读取已导出的包内资源,所以 package.json 的 exports 必须包含 "./locale/.json" 与 "./package.json";漏了这两条,插件列表里就只剩名字、描述为空(本插件 1.0.0 修复的正是这个)。
- files 里同样要带上 locale,否则 npm 安装的副本会缺这两个文件。
- package.json 的 icon 指向包根 icon.svg(36×36 viewBox 的独立 SVG);DSH 把它读成 data URL 画在插件卡片 48px 的图标框里(行内 40px 框同理)。缺省或解码失败时卡片静默退回默认插画,所以 files 里必须带上 icon.svg,并由 tests/icon.manifest.test.ts 守住:声明存在、文件在包内、是带命名空间的独立 SVG、没有脚本/外链/重复的 gradient id。

模块地图

| 路径 | 职责 |
| src/client/index.ts | bundle 入口 + BetterBrowser 组件(探针、状态、装配);把各模块工厂的返回值解构回原名 |
| src/client/platform.ts | 唯一平台边界:installPlatform(hostRequire) 注入 react / client-store / ui-primitives,其余模块从它 import |
| src/client/core/ | 纯逻辑(文本切分、时间分桶、视图规则、虚拟树与单链压缩),零 React/DOM,可直接单测 |
| src/client/browser/ | model(派生模型)、dnd、actions、tree-view、menu、layout:都是 createX(input) 工厂,依赖经 input 显式注入 |
| src/client/{store,host,icons,styles}.ts、ui/、rows.ts、customize.ts、settings.ts | 视图状态、宿主调用、图标、样式、行组件、外观与设置 |
| src/client/git-branch.ts、src/client/ui/branch.ts | 气泡用的分支名缓存(微任务批量合并、TTL 与失败冷却、路由不可用时停用)与 useGitBranch 钩子 |
| src/client/{tabs,tabs-strip}.ts | 标签规则(纯函数:打开/替换/排序/关闭/对账)与顶栏标签条组件(含 HTML5 拖拽排序、右键菜单桥) |
| src/index.ts | 宿主半(Node):三条精确路由——会话永久删除、内容检索与 git 分支查询 |
| src/search-index.ts | 内容检索索引:多帧 zstd 解码、中文逐字分词、按路径 + mtime + 大小增量更新(SQLite FTS5) |
| src/git-branch.ts | git 分支只读查询:execFile 调 git symbolic-ref(无 shell)、路径校验与短 TTL 缓存 |
| scripts/build.ts | 构建/校验入口:esbuild 产出 dist/client.js(浏览器 bundle)与 dist/index.js(宿主机半) |
| dist/ | 提交进仓库的产物(bundle + sourcemap + 宿主机半),不要手改;npm run check 校验其与 src//.ts 一致 |

tests/architecture.test.ts 守卫这些边界:只有入口/平台层能拿平台模块、core/i18n/styles/host 不得引用平台句柄、跨模块引用(含类型引用)必须 import、组件作用域的名字必须经 input 注入;tests/browser.render.test.ts 用 stub React 真正渲染侧栏(四种视图、归档筛选、置顶托盘、分组与自定义外观),拆分中漏接输入会立刻以 ReferenceError 暴露。
测试与构建脚本都是 .ts,由 Node 22 的原生类型擦除直接执行(不依赖 ts-node/tsx);类型检查由 tsconfig.json 的 strict 模式覆盖 src/、tests/、scripts/ 三处。平台模块没有发布类型声明,因此它们集中在 platform.ts 的 any 句柄里(唯一的动态边界),其余模块各自的 props / 数据结构都显式声明类型。

本地验证

把 npm pack 产出的 tarball 装进配置档,或直接把仓库路径 link 进配置档: bash
dsh plugin --profile web add /absolute/path/to/dsh-workspace-plus # 目录以 link 方式加入,改源码重启即生效

验证清单:层级树渲染、添加工作区弹窗、重命名即时重排、新建分组、时间视图分桶、置顶托盘、拖拽重排、右键菜单、会话标签页(点击开新标签 / Shift+点击替换 / 行末 + 新会话 / 未发送的新会话标签保留 / 右键菜单 / 拖拽排序 / 刷新后恢复)、气泡中的 git 分支名、外观自定义、设置页开关、永久删除会话往返、卸载后回到原浏览器。

注意:desktop 配置档若以 拷贝 方式安装(而非 link:),运行中的 DSH 读的是配置档里的旧副本;用 link: 安装才能让构建产物即时生效。

License

MIT
预览分享卡片长什么样 ↓lsdt45/dsh-workspace-plus
分享 · DeepSeek Harness Hub
lsdt45/dsh-workspace-plus

给 DSH 的侧边栏装上「文件夹系统」与浏览器式会话标签页,外加统一状态点与插件配置页

这是你的仓库?认领条目

回到顶部