- Início
- Plugins
- Sessões e mensagens
- dsh-session-move
dsh-session-move
ayachinene285/dsh-session-move
Adds nested folders above workspaces in the sidebar, drag-to-reorder for workspaces, folders and sessions, and moves a session to another workspace together with its working directory.
Instalar
dsh plugin --profile web add github:ayachinene285/dsh-session-moveREADME
dsh-session-move
DSH 的侧栏只有「工作区(目录)」这一层,也没有把会话挪到别的工作区的接口。这个插件补了这两块:
- 在工作区上面加一层文件夹。纯虚拟的,能嵌套,能放多个工作区,磁盘上不建任何目录;
- 会话可以在工作区之间搬,搬完以后这条会话里跑的东西都在新目录下。
代码分两块。lib/index.js 跑在 DSH 的本地服务进程里,负责读会话文件、改 cwd、开一个本地接口;lib/client.js 是网页里的部分,负责侧栏、菜单和弹窗。
安装
- clone 或者下载这个仓库到任意目录;
- 装进 profile:
dsh plugin --profile <profile 名> add <插件目录>。桌面版的 profile 由应用自己管理,命令被拒的话,在「插件」页里装,或者手动把dsh-session-move加到 profile 的package.json里dsh.profile.bundles下; - 完全退出 DSH 再打开。改插件不是刷新页面就能生效,界面和后台都要重新加载。
用法
会话行右边的「…」里有「移动到工作区 / 文件夹…」,弹窗里选目标:
- 选工作区:真的搬过去,会话的工作目录会改成那个目录;
- 在文件夹那一行点「把会话放这里」:只在侧栏归组,工作目录不动;
- 会话已经在某个文件夹里时,弹窗最上面多一行「移出文件夹」,点它回到工作区下面;
- 也可以直接填一个新目录,插件会把它登记成新工作区。
同一条会话可以反复搬。已经在目标工作区、会话正在跑、子代理会话,这几种情况会直接给提示,不会动数据。目标目录不存在时,默认先按同名建一个空目录再搬,弹窗里可以把这个行为关掉。
拖动排序
工作区和文件夹都能直接拖动,改上下顺序、换所属层级。行首有一个浅灰色的小手柄 ⠿,
按住整行(或手柄)往上下拖即可 —— 用的是指针事件,不依赖浏览器原生拖放,Electron 里也稳。
- 按住任意一行(工作区、文件夹、会话)拖动;
- 指针落在目标行的上 30% → 插到它前面;下 30% → 插到它后面;
- 落在文件夹行的中间 40% → 放进这个文件夹(并自动展开,免得看起来像消失了);
- 列表最下面还有一条空白落点,拖过去就是放到最外层末尾;
- 拖动时被拖的行变半透明,落点行会有一条蓝线(放进文件夹是一圈蓝框)。
会话也能拖:上下拖改顺序(工作区里的顺序存在浏览器 localStorage,文件夹里的顺序存在
storages/session-move-folders.json),拖进文件夹就归到那个文件夹下。拖动不会改会话的工作目录——
真要换工作区还是用会话菜单里的「移动到工作区 / 文件夹…」。
顺序和层级都存在 storages/session-move-folders.json 里,重启 DSH 不变。
拖进自己的子文件夹、拖到原位这类操作会被忽略或由宿主拒绝并提示,不会写坏数据。
文件夹分组
侧栏右上角「+」可以新建文件夹,不用选本地目录。文件夹能装文件夹,也能装任意多个工作区;工作区本身不能当父级。
工作区行的「…」里有「移入文件夹…」和「不放入文件夹(顶层)」。文件夹行的「…」里有新建子文件夹、重命名、移入其它文件夹、删除。删除只是解散这个文件夹,里面的东西上移一层。
「+」→「新增工作区(选择本地目录)」还是官方的选目录流程;文件夹的「…」里也有「新建工作区(选目录后放进这里)」,建完自动放进去。
展开状态记在浏览器 localStorage 里,默认展开,点行首的箭头收放。
会话可见性跟官方一致:已归档的会话默认隐藏(工作区「…」→「显示已归档的会话」可以切,这个开关跟官方和归档管理插件共用一份状态),子代理会话不显示,不是当前会话的空会话不显示。没归进任何工作区的会话放在最后「未分组」里。
会话也能直接放进文件夹,只动侧栏分组:会话「…」→ 移动到工作区 / 文件夹… → 在文件夹那一行点「把会话放这里」。放进去之后它只在文件夹下面出现一次,不会再重复出现在所属工作区里;想放回去用「移出文件夹」。
会话移动是怎么做的
DSH 判断一条会话属于哪个工作区,看的是会话自己记录的工作目录:
- 挂载会话的时候,DSH 拿会话文件里的 cwd 跟工作区路径比对,不一致就拒绝;
- 会话文件在磁盘上的位置也由这个 cwd 推出来,位置和记录对不上会被当成坏会话;
- 官方没有提供移动会话的接口。
所以插件分两步做完:
- 改数据:重写会话文件第一个 zstd 帧里记录的 cwd,把会话目录搬到新 cwd 对应的项目目录下,正文逐字节不动。写完马上自检,失败就回滚。
- 重新挂载:让 DSH 按磁盘现状重新读一遍这条会话,挂到目标工作区,从旧工作区摘掉,然后马上放掉,不长期占内存。
移动完不需要重启 DSH,也不用手工改 workspace.json,归属由 DSH 自己写。
冷会话和打开着的会话
一条会话只要被打开过(在对话页看过、聊过),DSH 的进程就会一直留着它,并且握着会话文件的写入权,官方没有关掉它的接口。所以:
- 没打开过的:点一下就好,不用重启;
- 打开着但空闲的:这时候改不了文件,插件把这次移动记成待办,下次 DSH 启动时(那时会话都是冷的)自动做完。待办存在
<DSH 数据目录>/storages/session-move-pending.json。重放失败不会把记录删掉,失败原因写进lastError,下次启动继续试,弹窗顶上也会显示上次为什么没成; - 有回合在跑的:直接拒绝,等它跑完再搬。
工作区目录不存在时
工作区的目录如果在 DSH 外面被删了或者改了名,DSH 就解析不出会话记录的 cwd,会话会在侧栏掉进「未分组」,工作区的会话数变成 0,往那里搬也只会得到一句「目标目录不存在」。
现在弹窗会把它标出来(行尾写「目录不存在」,选中后下面显示完整路径),并且默认直接修:
- 点「移动」就行,插件先按同名把空目录建出来,再搬会话,然后把归属补上。补归属的时候会顺手让 DSH 重新解析一次 cwd,所以不用重启就能在侧栏看到;
- 不想让它建目录,把弹窗里的「目录不存在时自动新建同名目录」取消掉,那样会直接报错;
- 如果目录只是改了名,别让它建空目录,用下面的「移动到新目录」填真正的路径,会自动登记成新工作区。
重启后重放的待办也按「目录不在就先建」处理。
本地接口
后台只加了一个本地接口,不替换官方任何东西:
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/dsh-session-move?sessionId=<id> | 工作区列表、这条会话的归属、它的待办移动 |
| POST | /api/dsh-session-move | { action: "move", sessionId, workspaceId 或 targetPath, title?, createMissingDir? } |
写请求只接受本机同源调用,会校验 Origin、Host 和 Sec-Fetch-Site。
配置
package.json 的 dsh.client 指向界面部分的入口,cordis.patch.yml 只有一条 insert,不禁用官方任何入口。
- insert:
- id: dsh-session-move
name: 'dsh-session-move'
开发时踩过的坑
- 改了界面部分也要完整重启 DSH。DSH 会给每个界面模块按文件内容算一个版本号,并且按
immutable缓存;只刷新页面的话,页面会拿着旧的版本号去取,被后台拒掉,表现可能是「插件加载失败」,严重的时候应用起不来。 - 不要直接读没声明依赖的
ctx.xxx。Cordis 里访问没声明的服务属性会直接抛异常,取可选服务用ctx.get("xxx")。 - 注册类调用都要自带 try/catch,包括路由、快捷键、槽位注册。界面部分初始化时抛错,DSH 会判定
entry did not activate,弹启动失败并提示禁用第三方插件。 - 同理,插件对外注册的地方都做了兜底,最坏情况只是这个功能不可用,不会连累 DSH 启动。
已知边界
- 移动会改会话的工作目录,之后这条会话里的工具调用都在新目录下跑;历史记录里的旧路径不会改写。
- 有回合在跑的会话不能移动。
- 只处理官方的 JSONL 存储(
session-persistence-jsonl,日志格式 v4),别的后端会因为没有locate()被拒。 - 已经归档的会话也能移动(归档集合按 id 全局存),但它在侧栏里还是显示为归档。
- 恢复会话时 DSH 会追加一条
session/end-seed事件,这是官方的恢复标记,不影响历史内容。
卸载
从 profile 的 dsh.profile.bundles 里删掉 dsh-session-move,执行 dsh plugin --profile <name> remove dsh-session-move,然后完整重启 DSH。
Plugins relacionados
dsh-web-ui (dsh-chat-recovery)
zhu1090093659/dsh-web-ui
billion-context
ranxianglei/billion-context
dsh-synapse
liangmianya/dsh-synapse
dsh-archive-manager
michengai/dsh-archive-manager