- Início
- Plugins
- Melhorias de UI
- dsh-session-drag-move
dsh-session-drag-move
furrybear2025/dsh-session-drag-move
Drag a session onto another workspace in the DSH sidebar and it really moves: the session-log header cwd is rewritten and the log directory is re-homed under the target project, with a progress bar while it runs.
Instalar
dsh plugin --profile web add github:furrybear2025/dsh-session-drag-moveREADME
dsh-session-drag-move
左侧栏「工作区」面板里,把会话拖到别的工作区——真正改归属,不只是改个名字分组。
官方只支持同一工作区内部拖排序;跨工作区拖拽是完全不响应的(onDrop 只在
drag.accountKey === group.key 时生效,insertSessionBefore 也拒绝不属于本工作区的会话)。
这个插件只接管这段本来就是空的行为,同工作区拖拽照旧交给官方。
它到底做了什么
DSH 里会话的归属是派生的,不是存出来的:
工作区拥有「会话日志 header 的 cwd 等于本工作区路径」的那些会话
~/.dsh/storages/workspace.json 里的 sessionIds 只是顺序账本,path 不匹配的 id
会在下次写入时被剪掉。所以换工作区必须改会话日志 header 里的 cwd。
会话日志是独立 Zstandard 帧的拼接,第一帧就是 header:
<root>/--<projectKey(cwd)>--/<sessionId>/session.v4.jsonl.zstd
└ 项目目录由 cwd 决定 └ 首帧 = header,其后每帧 = 一个追加批次
帧彼此独立,所以移动 = 重新压缩新的第一帧 + 原文件第二个 magic 之后的字节原样复制, 事件数据一个字节都不动。写完再自行解压校验一遍,然后把旧目录移到备份区。
最后同步正在运行的进程(否则要重启才生效):更新 registry 的 header 缓存与
session-path 索引,再走官方的 attachSession / insertSessionBefore / detachSession。
attachSession 会重新读 header 并校验 cwd,它成功就证明存储层改动真的落盘了。
安装
# 1. 放进 profile 的 node_modules
Copy-Item 'E:\dsh插件开发' "$env:USERPROFILE\.dsh\profiles\desktop\node_modules\dsh-session-drag-move" -Recurse -Force
# 2. 在 profile 的 cordis.patch.yml 里加一行
# - insert:
# - id: session-drag-move
# name: 'dsh-session-drag-move'
# 3. 重启 DSH
也可以用官方 CLI:
dsh plugin --profile desktop add dsh-session-drag-move
配置(host 半边)
| 字段 | 默认 | 含义 |
|---|---|---|
root | ~/.dsh/sessions | 会话存储根目录 |
backupRoot | <root>/../session-drag-move-backup | 移动前的会话目录停放处 |
allowRemote | false | 默认只接受 loopback 请求;局域网部署需显式打开 |
使用
- 拖会话行到另一个工作区的头行 → 归入该工作区(追加到末尾)
- 拖会话行到另一个工作区的某个会话行上半 → 插到它前面;下半 → 插到它后面
- 同工作区内拖拽 → 不拦截,仍是官方排序
- 运行中 / 当前会话会被拒绝
拖拽时源行会变淡,目标行出现蓝色虚线框。松手后底部显示迁移进度条:先按阶段推进
(查找目录 → 读取日志 → 重写 cwd → 搬运文件 → 备份 → 同步账本),搬运大量日志世代或
分支会话时显示 已处理 n / 总数,完成后变绿并自动消失,失败变红并显示原因。
侧栏适配
客户端按运行时 DOM 契约识别行,而不是按源码里的类名:
| 信号 | 用途 |
|---|---|
[data-row-key="session:<id>"] | 会话行识别 + 会话 id(主契约) |
[data-row-key="workspace:<id>"] | 工作区头识别 + 工作区 id(主契约) |
类名 *_sessionRow 后缀 | 无 data-row-key 时的兜底 |
[draggable="true"] / [role="treeitem"] | 最后的形状兜底 |
注意 dsh-better-workspace 等第三方侧栏用 CSS Modules 构建,源码里的可读类名
(bw-session-row)在产物中会被哈希成 <hash>_sessionRow,因此按源码类名匹配一定失败;
本插件匹配后缀与属性,跨构建稳定。目标工作区由几何位置(该行上方最近的工作区头)判定。
识别失败时会向 console 打印 [sm] 诊断日志(window.__smQuiet = true 可静默)。
迁移进度接口
长迁移在后台作业中执行,避免长时间无响应:
POST /session-drag-move/api/move → { jobId, started: true }
POST /session-drag-move/api/progress → { state, phase, detail, result, error }
move 传 wait: true 时同步返回最终结果(脚本/测试用)。phase 取值:
resolve scan index read rewrite write-main move-extras backup
ledger branches done;detail 在可量化阶段带 { done, total, current }。
安全边界
- 只重写第一帧;尾部原样复制;写完重新解压自检(id + cwd + 能解出 session header)
- 旧目录移出 sessions 根(留着会被扫到重复 id),停在备份区,可回滚
- 目标文件已存在则整体拒绝,不做半截写入
- 跨区移动前检查会话是否在运行
已知限制
- 依赖
workspaceRegistry的内部字段(headers/sessionPaths/host.rememberSessionPath) 同步运行状态。这些是普通字段不是#private,能用,但版本敏感——所有访问都做了 feature-probe,探测不到会返回结构化错误而不是抛栈。 - 侧栏适配跟随
dsh-better-workspace的data-row-key契约,另留有类名/形状兜底。若某个 侧栏把这套信号全部换掉,插件会静默不接管(不影响原生拖拽),此时用?smdiag=1或 默认的[sm]日志定位。 - 投影缓存
~/.dsh/storages/session_projcache/sessions/<id>.json里的record.identity.cwd目前未改写(可重建缓存,不影响归属)。
开发
$node = "$env:USERPROFILE\.dsh\dsh-runtimes\dsh-primary-runtime\dependencies\node\bin\node.exe"
& $node --test tests\smoke.mjs
测试覆盖路径编码(与本机磁盘目录逐字比对)、header 帧定位与校验、 真实会话日志的 cwd 改写 round-trip(含尾部字节完全一致断言)。
许可证
MIT
Plugins relacionados
dsh-web (dsh-task-board)
zhu1090093659/dsh-web
dsh-web (dsh-web-all)
zhu1090093659/dsh-web
dsh-web-ui (dsh-task-board)
zhu1090093659/dsh-web-ui
dsh-web-ui (dsh-web-ui-all)
zhu1090093659/dsh-web-ui