全部插件

DSH / BUNDLE / CLIENT-UI

dsh-workspace-mover

v1.3.0PianoPrince / dsh-workspace-mover8c1fcaef73

可安装组合包UI 与客户端插件社区 · Topic 自动分析Web UI

概览

dsh-workspace-mover

在 DSH 侧边栏安全迁移会话:真迁移原始档案,支持失联会话恢复、移动历史和一键撤回。

README / ZH

插件文档

dsh-workspace-mover

> 非官方项目,由社区成员独立开发和维护。

在侧边栏把会话拖到另一个工作区——真迁移原始档案,而不是复制

🌏 中文 · English

📑 目录


✨ 功能一览

DeepSeek Harness 的侧边栏支持工作区内拖拽排序会话,但把会话拖到另一个工作区上会被静默忽略——官方 RPC 只暴露了单工作区内的 insertSessionBefore,没有跨工作区移动接口。本插件补上这块:

  • 🖱️ 拖拽交互:把任意空闲会话行拖到目标工作区的标题行,确认框亮出目标路径,一键迁移
  • 📦 批量迁移:Ctrl/Shift+点击多选会话行(插件自建选择集,带计数徽章),拖任一选中行整批迁移;也可点工作区标题行的「⋯」菜单选「整组迁移…」。单批至多 50 个,逐条独立备份回滚、失败互不牵连
  • 🚚 真迁移:物理搬移原始 session.jsonl.zstd 档案、改写头部 cwd、更新工作区注册表——会话 id 与全部历史原样保留,不产生副本、不重新注入上下文、零 token 消耗
  • 🏠 工作区搬家向导:项目文件夹被移动/改名后,一键把失效的工作区原地重定向到新位置——工作区 id、标题、排序、归档位全部保持,名下会话连同旧路径的失联散件批量原样迁移;运行中的自动跳过,中断后续跑只补剩余
  • 🛟 孤儿会话救援(设置页「会话救援」面板):扫描磁盘上全部会话档案并分类处理——
    • 失联(orphaned):项目文件夹被移动/改名/删除导致 cwd 失效、从侧边栏"消失"的会话(官方讨论 #3012 的社区修复),可一键真迁移到任意现有工作区
    • 未记账(unregistered):cwd 仍有效但从未被任何工作区记账的会话(bootstrap 只跑一次、agent 内部 fork 不注册等),可原地补挂账
    • 挂错分组(misfiled):真实文件夹属于 B 分组、记账却在 A 分组的会话(克隆式迁移工具、改名后重建分组等场景),识别出应属分组后一键归位或全部归位——只修正归属记录,文件不动
    • 已归档会话:被官方「归档」隐藏、再也无法从界面找回的会话按分组列出,一键恢复原分组或换组恢复;真实文件夹属于别分组的会话带归位建议标记
    • 幽灵记账(ghosts):注册表有账但磁盘档案已缺失的 id(只读提示)
    • 全部走同一条备份+回滚管线
  • 🧹 分组合并:在组标题的「⋯」菜单选「整组迁移…」迁入目标分组后,若源分组已空可一键删除——两条命令完成分组合并
  • 🗂️ 空分组清理:救援面板只列出真正零成员的工作区(归档会话、幽灵记录都算成员,绝不误报),单个删除或全部清理;删除只移除分组登记,不碰任何会话
  • 🗑️ 会话回收站:救援面板可把异常/归档会话移入回收站——文件、标题、归属、归档状态完整保留,随时还原到原位置或任意分组;彻底删除需二次确认
  • 💾 备份管理:迁移自动生成的字节级备份按会话聚合展示(份数/占用/时间跨度),一键恢复(回读校验后才挂账)或按会话清理
  • 📂 打开文件夹:组标题「⋯」菜单一键用系统文件管理器打开该分组目录
  • ⏪ 移动历史与撤回:记录最近 100 次跨工作区移动,批量移动聚合为一条记录、整批一键撤回,撤回本身同样生成备份并复用回滚保护
  • 🧾 迁移任务中心 + 🛡️ 数据保护:批量迁移逐项持久化记录(完成/失败、最后错误与尝试时间),失败项一键重试;回收站与备份的份数/占用汇总,按时间清理先预览释放量再执行
  • ✅ 迁移后校验 + 一键修复:每次搬运落地即回读档案做 id/cwd 双确认,不符视同失败整体回退;救援面板"一键修复"自动跑完可修复项(逐项隔离,三态汇报),全部列表支持按标题/ID/路径即时筛选
  • 🏷️ 会话标题优先:确认框、救援列表和最近移动记录都先显示会话标题,找不到标题时显示「未命名会话」

🔬 技术要点

  1. 常驻会话一致性修复:打开过的会话在宿主内存里有冻结头与持久化写入缓存。直接搬文件会导致它下次对话时把新事件写回旧路径造成历史分叉——本插件迁移后清理陈旧写入状态并刷新注册表索引,宿主自动从新位置重新接管。
  2. 安全兜底:每次移动前强制字节级备份;改写、搬运、记账任一步失败自动回滚到移动前状态。
  3. Windows 加固:目录内刚发生文件改名后立刻改目录名会瞬时 EPERM——指数退避重试,仍失败退化为复制+删除。
  4. 主题自适应 UI:确认框/Toast 全部使用官方 --dsw-alias-* 设计令牌,跟随设置里的外观即时切换。
  5. 零依赖免构建:host 半零 npm 依赖,client 半 source-as-product,无构建产物漂移风险。
  6. 重定向的剪枝防御:官方工作区实体的每次写入都会按「内存索引中的会话 cwd」剪枝成员名单——搬家向导先把全部受影响会话的三张索引预置成新路径,再经实体的统一写入通道 mutate 原地换 path,成员一个不丢。

🚀 安装

dsh plugin --profile web add "github:PianoPrince/dsh-workspace-mover"
# 重启 dsh web 一次

零构建授权:本插件是纯 JavaScript 源码即产物(无 TypeScript、无构建步骤),从 GitHub 安装时不需要 allowBuilds 构建授权——pnpm 不会执行任何安装期脚本。

npm 渠道
dsh plugin --profile web add dsh-workspace-mover
本地开发安装
dsh plugin --profile web add "link:E:/path/to/dsh-workspace-mover"
常见问题
现象 原因与解决
拖了但没反应 只在「分组视图」把会话行投到工作区标题行上才会触发;「扁平列表」视图没有标题行,本插件在该视图不激活
提示会话正在运行中 宿主端校验回合状态;等该会话回合结束再拖即可
移动失败的 toast 每次操作前都有字节级备份、失败自动回滚;按 toast 说明处理后重试,详细原因见宿主日志中的 MOVE FAILED 条目
移动成功但侧边栏没归位 插件迁移后会主动重拉一次工作区基线;偶发未生效时手动刷新页面
有些会话从侧边栏不见了 打开 设置 → 会话救援 自动扫描,「失联」「未记账」「挂错分组」三类都能一键找回

🖼️ 特性巡礼

以下均为真实界面实拍(点击可放大)。

拖拽跨工作区迁移

把空闲会话行拖到目标工作区标题行,出现虚线高亮 确认框亮出目标工作区路径,一键移动
设置 → 会话救援:一键找回失联与未记账的会话

批量迁移 · 多选拖拽

Ctrl+点击选中多个会话(当前打开的会话自动带上),左下角亮出计数徽章;拖到目标工作区标题行即整批移动,Esc 清空
组标题「⋯」菜单里的「整组迁移…」:整组搬移,迁入后可删除已空的源分组(分组合并)

工作区搬家向导 · 实测全程

以下为一次真实搬家的完整记录:把 Test1 文件夹改名为 Test2 后,用向导原地修复工作区。

改名前:Test1 分组正常工作 改名后侧边栏仍显示旧分组(磁盘上文件夹已不在)
打开设置 → 会话修复:「工作区体检」把分组标为「路径失效」,填入新路径 确认框亮出起讫路径与将要迁移的会话数
搬家完成:分组原地更名为 Test2,会话与历史原样保留

⌨️ 使用

拖拽跨工作区迁移

  1. 重启后在侧边栏分组视图里,按住任意空闲会话行;
  2. 拖到目标工作区的标题行(出现虚线高亮)松手;
  3. 确认框显示目标工作区路径 → 点「移动」;
  4. 完成 toast 提示;若宿主广播未触发自动刷新,手动刷新页面即可。

运行中的会话会被拒绝(宿主端校验),移动失败自动回滚并在 toast 中说明原因。

会话救援面板

  1. 重启后打开 设置 → 会话救援,面板自动完成首次扫描;
  2. 失联行:选目标工作区 → 点「迁移过去」(真迁移,ID 保留);
  3. 未记账行:点「补挂账」原地挂到路径匹配的工作区;
  4. 挂错分组行:显示「当前分组 → 应属分组」,点「归位」或「全部归位」即时修正归属(文件不动);
  5. 一键修复:自动跑完可修复项(挂错归位、未记账补账,逐项隔离失败),孤儿/损坏项跳过并说明原因;
  6. 筛选框:按标题 / 会话 ID / 路径 / 分组即时过滤所有列表;
  7. 已归档 / 回收站 / 备份:归档会话一键恢复;删除的会话进回收站,可还原到原位置或任意分组、确认后彻底删除;迁移自动生成的字节级备份按会话聚合,可恢复或清理;
  8. 每次操作前后都有备份与回滚保护,结果按 已修复/跳过/失败 即时反馈。

批量迁移

  1. 侧边栏 Ctrl/Cmd+点击 会话行加入多选(再点取消),Shift+点击 在组内范围选择,左下角徽章实时显示已选数量,Esc 清空;
  2. 按住任一选中行拖到目标工作区标题行,确认框显示本批数量 → 点「全部移动」;
  3. 也可点工作区标题行的**「⋯」菜单 →「整组迁移…」**,选目标分组整组搬移;源分组因此清空时,可确认后直接删除空分组(分组合并);
  4. 每个会话独立备份回滚,个别失败(如正在运行)不影响其余,结果 toast 汇总成功与跳过数。

工作区搬家向导

  1. 文件夹被移动/改名后,面板顶部的工作区体检会把对应分组标记为「路径失效」;
  2. 在该行的输入框填入文件夹现在的完整路径,点「搬家」;
  3. 确认框亮出旧路径 → 新路径与将要迁移的会话数量,确认后执行;
  4. 名下会话连同旧路径的失联散件一起原样迁移;正在运行的会话本次跳过,结束后用同样的输入再跑一次即可续跑剩余部分。

🔌 与 DSH 的集成方式

  • Host 半lib/index.js,零 npm 依赖):经 cordis.patch.yml 以标准 insert 行挂载;通过 ctx.connection.rpc.handle('/workspace-mover', …) 注册逻辑通道,端点 mover.status / mover.workspaces / mover.move / mover.moveMany / mover.scan / mover.repair / mover.repairAll / mover.history / mover.undo / mover.ws.audit / mover.repoint / mover.archived / mover.unarchive / mover.openFolder / mover.session.delete / mover.trash.list / mover.trash.restore / mover.trash.purge / mover.backups.list / mover.backups.restore / mover.backups.deleteOne,失败详情写入宿主日志(MOVE FAILED)。
  • 移动算法
    1. 运行状态检查:仅拒绝回合进行中的会话(agents.get(id)?.status === 'running',与宿主 UI"进行中"徽标同款判据);常驻内存但空闲的会话允许迁移;
    2. 从磁盘读取权威会话头,校验目标 ≠ 源;
    3. 原始字节备份到 $DSH_HOME/workspace-mover/backups/(每会话保留最近 20 份);
    4. 仅重写首帧(头部 cwd),其余帧字节级保留;临时文件 + 原子改名发布;
    5. 会话目录整体搬移(Windows 目录改名怪癖:指数退避重试,仍失败退化为复制+删除);
    6. 内存一致性收尾:失效注册表三张索引;常驻会话额外清理持久化协调器的陈旧写入状态、刷新索引并预置目标记账(绕开冻结头的旧 cwd 校验);
    7. 调用目标实体 attachSession 持久化记账,源实体已先行 detachSession
    8. 任一步失败自动回滚:撤销预置 → 还原索引快照 → 原件放回源目录 → 重新挂回源工作区。
  • Client 半client/client.js,免构建 source-as-product):仅依赖 ARIA 语义属性定位行元素(会话行 [aria-selected] / 工作区标题行 [aria-expanded]),不碰 CSS-module 哈希类名;只拦截「跨组投放」场景,官方同组排序不受影响。迁移成功后主动重拉一次工作区基线(公开 API),侧边栏分组即时归位。
  • 救援面板:经官方 settings.section 插槽注册设置页分栏,RPC 端点 mover.scan(分类扫描)与 mover.repair(批量 attach/relink,relink 复用同一条迁移管线)。
  • 迁移历史:保存于 $DSH_HOME/workspace-mover/history.json,最多保留最近 100 条;原工作区仍存在时可直接撤回,原工作区已删除时会明确要求重新选择目标分组。

🤝 与其他插件的共存

设计上就按"与生态共生"标准实现,与其他插件冲突面很小:

  • 通信全命名空间:RPC 只占 /workspace-mover 一个通道、不注册任何 HTTP 路由;面板走官方 settings.section 插槽(槽位系统天生支持多插件并存);CSS 类 wsm-* 与 DOM 属性 data-wsm-* 均为自有命名空间;
  • 不改写官方 bundle 任何字节,只挂事件监听与槽位注入(对比少数直接 patch 官方 bundle 的插件,不存在那类雷);
  • 宿主写入全走官方通道(registry 的 mutate/attachSession/detachSession、持久域状态),不引入私有数据形态,其他插件读到的永远是官方形态的数据;
  • 零 npm 依赖,不存在共享依赖的版本冲突。

与其他类目插件同装的兼容性:

同装插件类目 兼容性 说明
侧边栏增强 / better-sidebar / 终端 / 费用统计 / 记忆 / 导出分享 ✅ 无冲突 面板与数据面完全不同
归档管理类插件 ✅ 兼容 双方都读写官方归档集,数据层一致(面板功能会有些重复)
排序 / 置顶类插件 ⚠️ 基本兼容 本插件移动后精确重排「最近更新」,置顶/排序插件各自维护自己的集合——并存无碍,仅各自面板展示顺序可能不完全一致
重画侧边栏的插件(自绘工作区树) ⚠️ 降级共存 若对方替换官方工作区 DOM,本插件的 ARIA 语义选择器可能找不到行——表现为功能静默不触发,不会损坏数据
其他会话移动器 ❌ 建议二选一 同类插件同样在 document 层拦截拖拽投放,同时安装可能导致一次拖拽被双重处理。本插件已覆盖移动 / 批量 / 合并 / 归位 / 归档恢复场景,无需重复安装

DSH 版本敏感点(非插件冲突):取消归档走 registry 持久状态写通道,在不支持的宿主版本上会明确提示而非报错;投影缓存标题按 v3 形状防御性解析,文件缺失时退化为档案头标题。

🆕 最近更新

v1.0.0 · 2026-09-05

  • 迁移后一致性校验:每次搬运(单个/批量/工作区搬家)落地后回读档案,id 与 cwd 双确认才算成功,不符自动整体回退
  • 一键修复:可自动修复项(挂错归位、未记账补账)一次跑完,逐项隔离失败;孤儿/损坏项跳过并说明原因,结果按 已修复/跳过/失败 汇报
  • 面板筛选:按标题 / 会话 ID / 路径 / 分组即时过滤所有救援列表,分区显示 命中/总数

v0.9.0 · 2026-09-05

  • 会话回收站:救援面板各区块新增「删除」,会话完整移入回收站(文件、标题、归属、归档状态全保留),一键还原到原位置或任意分组,确认后彻底删除
  • 备份管理:迁移自动生成的字节级备份终于可见——按会话聚合展示份数/占用/时间跨度,一键恢复(回读校验后才挂账)或按会话删除
  • 删除即四件套清理:文件、记账、投影缓存、注册表索引一次清干净,不留幽灵

v0.8.0 · 2026-09-05

  • 归档会话管理:救援面板新增「已归档的会话」区——被官方归档隐藏的会话按分组列出,一键恢复原分组,或「恢复到…」换组恢复(走完整迁移保护);挂错的归档会话带归位建议标记
  • 空分组检测与清理:只列出真正零成员的工作区(归档会话、幽灵记录都算成员,绝不误报),支持单个删除与全部清理
  • 工作区「⋯」菜单新增「打开文件夹」:系统文件管理器直达分组目录

v0.7.0 · 2026-08-28

  • 会话救援新增「挂错分组」识别:真实文件夹属于 B 分组、记账却在 A 分组的会话自动列出应属分组,逐条「归位」或一键「全部归位」——只修正归属记录,文件不动
  • 分组合并:组标题「⋯」菜单新增「整组迁移…」入口;整组迁入后源分组已空时可直接删除,两条命令完成合并
  • 扫描摘要与各区块同步展示「挂错分组」数量

v0.6.3 · 2026-08-28

  • 会话移动后自动按「最近更新」精确归位,无需手动切换排序
  • 行→会话识别升级为直读行元素自带的会话标识:无论分组里有多少隐藏/归档会话,多选与移动都精确命中所选
  • 新增批量多选实拍截图

v0.6.2 · 2026-08-28

  • 设置页撤回 / 补账 / 重新归组后侧边栏即时刷新,会话立刻回到目标分组
  • Ctrl+点击开始多选时自动带上当前打开的会话:正开着 A、Ctrl+点 B,一步选中 {A, B}

v0.6.1 · 2026-08-28

  • 批量移动在「最近移动」聚合为一条记录,支持整批一键撤回
  • 普通点击会话行即退出多选;Esc 可随时清空多选

v0.6.0 · 2026-08-28

  • 批量迁移:插件自建侧边栏多选(Ctrl/Shift+点击、Esc 清空、计数徽章),拖任一选中行整批迁移;组标题「⋯」菜单可整组搬移
  • 新增 mover.moveMany 端点:单批 ≤50 个,复用单条迁移管线——逐会话独立备份回滚、错误隔离、移动历史落账(可撤回)
  • 测试 27 → 30 用例

v0.5.1 · 2026-08-27

  • 搬家时工作区标题自动跟随新文件夹名(自定义标题原样保留)
  • 迁移后 @ 文件引用即刻指向新位置,无需重启
  • 冷启动保留会话列表标题缓存,列表稳定显示会话名
  • 测试 24 → 27 用例

v0.5.0 · 2026-08-27

  • 工作区搬家向导:体检面板识别「路径失效」的分组,一键原地重定向到新位置——工作区 id、标题、排序、归档位全部保持,经实体统一写入通道 mutate 换 path(先预置三张索引,成员零丢失)
  • 批量迁移名下会话与旧路径失联散件:逐文件备份回滚、常驻写入状态清理;运行中的自动跳过,中断可携原路径续跑
  • 新增端点 mover.ws.audit / mover.repoint(18 → 24 用例)

v0.4.0 · 2026-08-26

  • 移动历史与一键撤回:保存最近 100 条跨工作区移动记录(mover.history / mover.undo 端点),设置页确认后移回原分组,撤回同样受备份与回滚保护
  • 确认框、救援列表与移动记录优先显示会话标题

v0.3.2

  • 孤儿会话救援:磁盘全量扫描、失联会话真迁移、未记账会话补挂账,全程回滚保护

🔐 安全设计

  • 移动前强制备份;落地回读校验(id/cwd 双确认,不符整体回退);attach 失败自动回滚(撤销预置记账 → 还原索引 → 还原字节 + 清理目标 + 重新挂回源工作区);
  • 删除进回收站:物理移动先行,失败零副作用;manifest 完整记录还原所需信息;彻底删除需二次确认;
  • 驻留内存的会话拒绝删除(防止文件被驻留对象重建为僵尸),并给出重启释放的明确指引;
  • 仅拒绝回合进行中的会话;常驻空闲会话迁移后修复写路径归属,杜绝历史分叉;
  • 注册表/持久化内部访问全部包在 try/catch 中,失败降级为功能可用 + 重启建议提示;
  • 兼容性目标:Node ≥ 22,dsh 0.1.1-rc.2;核心纯函数与端到端沙箱测试见 npm test(70 用例,含回滚路径、救援扫描/修复、历史撤回、工作区重定向、批量迁移、迁移后校验、回收站与备份恢复、迁移任务中心与数据保护清理)。

⚠️ 已知限制

  • 不支持把会话移入「Ungrouped」桶;
  • 常驻内存的会话(近期打开过)不能直接删除——文件会被驻留对象重建;重启 Harness 释放后再删,删除时会给出 toast 提示;
  • 行 → 会话识别优先读取行元素自带的会话标识(React props),渲染顺序对齐仅作兜底;若第三方插件替换侧边栏 DOM 导致 ARIA 选择器失效,相关功能静默停用(不损坏数据);
  • 「扁平列表」视图无工作区标题行,本插件在该视图不激活;
  • 若宿主升级改变了注册表缓存字段名或实体结构,相关步骤走降级路径(功能可用,归属刷新可能需重启);取消归档依赖 registry 持久写通道,不可用时明确报错而非静默失败;
  • 工作区搬家依赖实体的统一写入通道 mutate;若宿主结构变化使其不可用,向导会在改动第一个文件之前中止并明确提示。

License

MIT

LIMITATIONS

已知限制

- 不支持把会话移入「Ungrouped」桶; - 常驻内存的会话(近期打开过)不能直接删除——文件会被驻留对象重建;重启 Harness 释放后再删,删除时会给出 toast 提示; - 行 → 会话识别优先读取行元素自带的会话标识(React props),渲染顺序对齐仅作兜底;若第三方插件替换侧边栏 DOM 导致 ARIA 选择器失效,相关功能静默停用(不损坏数据); - 「扁平列表」视图无工作区标题行,本插件在该视图不激活; - 若宿主升级改变了注册表缓存字段名或实体结构,相关步骤走降级路径(功能可用,归属刷新可能需重启);取消归档依赖 registry 持久写通道,不可用时明确报错而非静默失败; - 工作区搬家依赖实体的统一写入通道 `mutate`;若宿主结构变化使其不可用,向导会在改动第一个文件之前中止并明确提示。