前言¶
DeepSeek Harness(DSH)侧栏默认只有一层「工作区(目录)」:多个本地项目并列展示,会话归属完全由工作目录(cwd)决定。官方没有把工作区再分组的虚拟层级,也没有把一条会话迁到另一个工作区并同步改 cwd 的接口。项目一多、会话一多,侧栏会显得扁平,跨目录整理会话只能手工改底层数据。
dsh-session-move(维护者 ayachinene285,版本 0.2.1,MIT)在客户端侧补上「文件夹分组 + 拖动排序 + 真会话搬家」三块能力:分组只在侧栏生效,磁盘上不建虚拟目录;真正换工作区时会改会话文件里的 cwd 并搬迁会话目录,与 DSH 的挂载规则对齐。
这是什么¶
一句话:DSH 客户端插件,在工作区之上增加可嵌套的虚拟文件夹,并支持把工作区/文件夹/会话拖动排序,以及把会话移动到另一个工作区(或仅归入文件夹)。
代码分两部分:lib/index.js 跑在 DSH 本地服务进程,负责读会话文件、改 cwd、提供本地 API;lib/client.js 负责侧栏 UI、菜单和弹窗。通过 cordis.patch.yml 以 insert 方式挂载,不禁用官方入口。
核心功能¶
虚拟文件夹分组¶
- 侧栏右上角「+」可新建文件夹,不选本地目录;文件夹可嵌套,可包含多个工作区;工作区不能作为父级。
- 工作区「…」:移入文件夹 / 不放入文件夹(顶层)。
- 文件夹「…」:新建子文件夹、重命名、移入其它文件夹、删除(解散后内容上移一层)。
- 「+」→「新增工作区(选择本地目录)」仍走官方选目录流程;文件夹内也可「新建工作区(选目录后放进这里)」。
- 展开状态记在浏览器 localStorage,默认展开。
- 会话可见性与官方一致:已归档默认隐藏、子代理不显示、非当前空会话不显示;未归属任何工作区的会话在「未分组」。
会话:搬家与仅分组¶
会话行「…」→「移动到工作区 / 文件夹…」:
| 操作 | 效果 |
|---|---|
| 选工作区 | 真正移动:会话 cwd 改为该目录,会话目录搬到新项目下 |
| 文件夹行「把会话放这里」 | 仅侧栏归组,工作目录不变 |
| 「移出文件夹」 | 回到工作区列表下,不改 cwd |
| 填写新目录 | 登记为新工作区并移动 |
同一条会话可反复移动。已在目标工作区、会话正在跑、子代理会话等情况会提示且不动数据。目标目录不存在时,默认先建同名空目录再搬;弹窗可关闭该行为。
仅分组时,会话在文件夹下只出现一次,不会在工作区里重复;移出用「移出文件夹」。
拖动排序¶
工作区、文件夹、会话均可拖(行首浅灰手柄 ⠿,指针事件实现,不依赖浏览器原生拖放):
- 落在目标行上 30%:插到前面;下 30%:插到后面。
- 落在文件夹行中间 40%:放进该文件夹(自动展开)。
- 列表底部空白:放到最外层末尾。
拖动不会改会话的工作目录;换工作区仍用菜单「移动到工作区 / 文件夹…」。工作区内会话顺序在 localStorage;文件夹内顺序与层级在 storages/session-move-folders.json,重启后保持。
会话移动的实现要点¶
DSH 用会话文件中的 cwd 判定归属;官方无移动 API。插件两步完成:
- 改数据:重写会话文件第一个 zstd 帧里的 cwd,把会话目录搬到新 cwd 对应项目目录下,正文逐字节不动;失败回滚。
- 重新挂载:让 DSH 按磁盘现状重读会话,挂到目标工作区并从旧工作区摘掉。
移动后不需重启 DSH,也无需手工改 workspace.json。
冷会话与打开中的会话¶
- 从未打开:可直接移动。
- 已打开但空闲:进程占用写入权,移动记入待办
<DSH 数据目录>/storages/session-move-pending.json,下次启动自动执行;失败保留记录并写入lastError。 - 有回合在跑:拒绝,需等跑完。
工作区目录不存在¶
弹窗标「目录不存在」;默认可先建同名空目录再搬。取消「目录不存在时自动新建同名目录」则直接报错。目录仅改名时,可用「移动到新目录」填真实路径并登记新工作区。
本地 API¶
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/dsh-session-move?sessionId=<id> |
工作区列表、会话归属、待办移动 |
| POST | /api/dsh-session-move |
{ action: "move", sessionId, workspaceId 或 targetPath, title?, createMissingDir? } |
写请求仅接受本机同源,校验 Origin、Host、Sec-Fetch-Site。
安装与启用¶
插件以当前 DSH 进程权限运行,安装前建议浏览 GitHub 仓库 源码并确认 MIT 许可证。
- 将插件包放到本机任意目录(README 支持 clone 或下载仓库;亦可从 SkillHub 目录页 获取分发方式)。
- 装入 profile:
dsh plugin --profile <profile 名> add <插件目录>
桌面版若命令被拒,可在应用内「插件」页安装,或手动把 dsh-session-move 加入 profile 的 package.json 中 dsh.profile.bundles。
- 完全退出 DSH 再打开。改插件不能靠刷新页面;界面与后台都需重载。
卸载:从 dsh.profile.bundles 删除条目,执行 dsh plugin --profile <name> remove dsh-session-move,再完整重启。
典型用法¶
- 侧栏「+」新建文件夹,用「…」把工作区移入,或拖进文件夹中间区域。
- 多项目并行时,用拖动调整工作区/文件夹顺序;会话在同一工作区内拖只改显示顺序。
- 要把 Agent 会话换到另一个仓库:会话「…」→「移动到工作区 / 文件夹…」→ 选目标工作区(或填新路径);仅想侧栏归类则点文件夹行的「把会话放这里」。
- 目标目录被删:在弹窗确认路径,保留默认「自动新建同名目录」后点移动,或填新路径登记工作区。
适用场景与注意¶
适合谁:本地多仓库、侧栏需要层级整理;需要把会话 cwd 迁到另一项目且不想手改 JSONL/zstd 的用户。
已知边界(来自 README):
- 移动后工具调用在新目录下执行;历史里旧路径不会改写。
- 有回合在跑的会话不能移动。
- 仅支持官方 JSONL 存储(
session-persistence-jsonl,日志 v4)。 - 已归档会话可移动,侧栏仍显示为归档。
- 界面模块有 immutable 缓存,改
client后必须完整重启 DSH。
社区插件生态遵循 DSH「一切皆插件」思路;SkillHub 为独立目录站,与 DeepSeek / 幻方无官方从属关系。
结尾¶
dsh-session-move 用虚拟文件夹和拖动排序减轻侧栏扁平化的负担,并在官方未提供移动 API 的前提下,按 DSH 的 cwd 规则安全改写会话数据并完成重新挂载。需要分组展示与真实换库开发时,可对照 README 安装并在完全重启后使用。