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

会话迁移 yvban/dsh-session-mover

DeepSeek Harness
yvban21 天前有提交已提供中文文档扫描:含敏感能力

在工作区之间安全搬迁会话并保留完整历史

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

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

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add yvban/dsh-session-mover
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么[目录]—
dsh 原生插件 · other
暂无时间戳·判据 →
装得上吗[实装验证]✓
本站已在 dsh 0.2.1-rc.5 下真实安装成功
非静态推断
L5 · 运行时冒烟等级说明 →
数据截至 2026/11/04·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/04·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 21 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

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

验证判据与等级说明 →

可信度证据

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

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

读写/删除本地文件发起外部网络请求
查看扫描证据(共 33 处,展示前 31 条)
  • 读取本地文件
    lib/index.js:113
    names = readdirSync(dir);
  • 读取本地文件
    lib/index.js:122
    const record = JSON.parse(readFileSync(join(dir, name), 'utf8'))?.record;
  • 读取本地文件
    lib/index.js:166
    projects = readdirSync(root, { withFileTypes: true });
  • 读取本地文件
    lib/index.js:174
    sessionDirs = readdirSync(join(root, project.name), { withFileTypes: true });
  • 读取本地文件
    lib/index.js:276
    if (!existsSync(regPath)) return { ok: false, error: `找不到 ${regPath}` };
  • 读取本地文件
    lib/index.js:277
    const reg = JSON.parse(readFileSync(regPath, 'utf8'));
  • 写入本地文件
    lib/index.js:293
    writeFileSync(tmp, JSON.stringify(reg, null, 2), 'utf8');
  • 写入本地文件
    lib/index.js:294
    renameSync(tmp, regPath);
  • 写入本地文件
    lib/index.js:465
    mkdirSync(backupDir, { recursive: true });
  • 写入本地文件
    lib/index.js:466
    copyFileSync(found.file, join(backupDir, found.generation.name));
  • 写入本地文件
    lib/index.js:468
    writeFileSync(tmp, repaired.buf);
  • 删除本地文件
    lib/index.js:471
    rmSync(tmp, { force: true });
  • 删除本地文件
    lib/index.js:475
    rmSync(tmp, { force: true });
  • 写入本地文件
    lib/index.js:478
    renameSync(tmp, found.file);
  • 发起网络请求
    lib/client.js:81
    const response = await fetch(API + "/state", { headers: { accept: "application/json" } });
  • 发起网络请求
    lib/client.js:103
    const response = await fetch(API + path, {
  • 读取本地文件
    lib/migrate.js:157
    names = readdirSync(sessionDir);
  • 读取本地文件
    lib/migrate.js:169
    sizeBytes = statSync(path).size;
  • 读取本地文件
    lib/migrate.js:192
    entries = readdirSync(root, { withFileTypes: true });
  • 读取本地文件
    lib/migrate.js:212
    const raw = readFileSync(file);
  • 写入本地文件
    lib/migrate.js:388
    mkdirSync(destDir, { recursive: true });
  • 读取本地文件
    lib/migrate.js:430
    if (existsSync(newFile)) {
  • 写入本地文件
    lib/migrate.js:448
    mkdirSync(newSessionDir, { recursive: true });
  • 写入本地文件
    lib/migrate.js:451
    writeFileSync(tmp, buf);
  • 读取本地文件
    lib/migrate.js:452
    verifyRewritten(readFileSync(tmp), { id, cwd: targetCwd, originalRaw: log.raw });
  • 写入本地文件
    lib/migrate.js:453
    renameSync(tmp, newFile);
  • 删除本地文件
    lib/migrate.js:455
    rmSync(tmp, { force: true });
  • 删除本地文件递归
    lib/migrate.js:456
    rmSync(newSessionDir, { recursive: true, force: true });
  • 写入本地文件
    lib/migrate.js:459
    writeFileSync(join(backupDir, 'manifest.json'), JSON.stringify(manifest, null, 2), 'utf8');
  • 删除本地文件递归
    lib/migrate.js:462
    rmSync(found.sessionDir, { recursive: true, force: true });
  • 写入本地文件
    lib/migrate.js:482
    mkdirSync(dirname(restore), { recursive: true });
扫描于 2026/11/4(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DSH 插件:安全迁移会话到其他工作区——帧级 zstd 头重写、字节级校验、整目录备份、实时更新归属

README

由 DeepSeek 最新模型翻译生成
dsh-session-mover 把 DSH 会话从一个工作区安全搬到另一个工作区,保留可续聊的完整历史。 在工作区之间安全迁移 DSH 会话 —— 帧级 zstd 头部改写,字节级校验。 一个 DeepSeek Harness(DSH)插件:在 设置 → 会话迁移 里选目标工作区、选会话、点一下,就把会话搬过去,归属即时更新、无需重启。 为什么需要它 DSH 的会话日志是多帧 zstd,并且有一条硬性约定:第 1 个帧必须只包含 header 那一行,其余每帧独立可解码(带 checksum)。DSH 读取时用 assertZstdHeaderFrame 校验,不满足就抛 SessionPersistenceCorruptionError,而会话枚举会静默跳过这条日志 —— 表现就是: 迁移完成后,那个对话在侧边栏里彻底消失(文件其实完好)。 手工改 header 时最容易踩的两个坑: 1. 把整份日志一次性重压。改完 cwd 后重压全文,会把「头部帧 + 上千个事件帧」塌缩成单个帧,正好触发上面那条校验。 2. 硬编码日志文件名。文件名带格式世代号:v0 叫 session.jsonl.zstd,vN(N>0) 叫 session.vN.jsonl.zstd。硬编码 v0 名字的实现,在较新的 DSH 上会一个会话都定位不到(实测 0/31)。
展开完整文档(README 剩余 1 节)
dsh-session-mover

把 DSH 会话从一个工作区安全搬到另一个工作区,保留可续聊的完整历史。
在工作区之间安全迁移 DSH 会话 —— 帧级 zstd 头部改写,字节级校验。

一个 DeepSeek Harness(DSH)插件:在 设置 → 会话迁移 里选目标工作区、选会话、点一下,就把会话搬过去,归属即时更新、无需重启。

为什么需要它

DSH 的会话日志是多帧 zstd,并且有一条硬性约定:第 1 个帧必须只包含 header 那一行,其余每帧独立可解码(带 checksum)。DSH 读取时用 assertZstdHeaderFrame 校验,不满足就抛 SessionPersistenceCorruptionError,而会话枚举会静默跳过这条日志 —— 表现就是:

迁移完成后,那个对话在侧边栏里彻底消失(文件其实完好)。

手工改 header 时最容易踩的两个坑:

1. 把整份日志一次性重压。改完 cwd 后重压全文,会把「头部帧 + 上千个事件帧」塌缩成单个帧,正好触发上面那条校验。
2. 硬编码日志文件名。文件名带格式世代号:v0 叫 session.jsonl.zstd,vN(N>0) 叫 session.vN.jsonl.zstd。硬编码 v0 名字的实现,在较新的 DSH 上会一个会话都定位不到(实测 0/31)。

本插件按帧处理、按目录里实际存在的世代解析文件名,从根上避开这两个问题。

功能

| 能力 | 说明 |
| 迁移会话 | 设置 → 会话迁移:选目标工作区 → 选会话 → 迁移 |
| 按标题认会话 | 列表显示会话标题(与侧边栏同源),并标出它当前属于哪个分组;支持按标题 / 路径 / ID 过滤 |
| 帧级改写 | 只重压第 1 帧(header,写入新 cwd),body 帧字节原样保留 |
| 字节级校验 | 帧数不变 + 每个 body 帧逐字节比对 + 头部 id/cwd 核对;不做全量解压,大日志也不吃内存 |
| 整目录备份 | 迁移前把整个会话目录 + manifest.json 备份到 <DSH_HOME>/storages/session-mover-backup/<id>/<时间戳>/ |
| 拒绝覆盖 | 目标工作区已有同 id 会话时直接拒绝,不动原会话 |
| 事务性 | 先写临时文件并校验,通过后才 rename;任何一步失败都会清掉半成品 |
| 归属热更新 | 通过官方实体 API(WorkspaceEntity.attachSession / detachSession)更新分组,无需重启 |
| 帧结构修复 | 已经被"整份重压"搞坏、在界面里消失的会话,可以就地修复(修复前自动备份) |

标题从哪来

标题有两个来源,按"快 → 准"的顺序取;取不到只是不显示,绝不影响迁移:

1. 投影缓存(快):<DSH_HOME>/storages/session_projcache/sessions/<id>.json 里的 record.rows.title.val。本机实测覆盖 22/31 个会话。缓存只是显示提示,可能滞后于日志。
2. sessionQuery.readTitleSnapshots()(准):官方公开服务,从日志里折叠标题事件。
只对缓存里没有标题的会话调用,避免每次打开面板都全量读日志。

分组列来自 workspaceRegistry.list() 的成员关系;没有归属的显示为「未分组」。

安装

有 git(标准写法)
dsh plugin --profile <你的 profile> add github:yvban/dsh-session-mover#main

没有 git:pnpm 解析 github: 依赖需要 git,可以改用归档 tarball 的 URL
dsh plugin --profile <你的 profile> add https://github.com/yvban/dsh-session-mover/archive/refs/heads/main.tar.gz

<你的 profile> 通常是 web;桌面版是 desktop。如果 PATH 里没有 dsh,用应用自带的 CLI:

& '<DSH 安装目录>\resources\runtime\cli\bin\dsh.cmd' plugin --profile desktop add github:yvban/dsh-session-mover#main

装完重启 DSH(客户端面板在启动时加载),然后打开 设置 → 会话迁移。

使用

1. 目标工作区:下拉里选一个已注册的工作区。
2. 选中会话:列表按创建时间倒序,每行显示标题 / 当前分组 / 原始 cwd / 体积 / 会话 ID。
- 打开中 的会话不能迁移(日志被写句柄占着)。
- 标了 帧结构异常 的会话先用「修复帧结构」,修完重启 DSH 就会重新出现。
3. 迁移选中会话:完成后归属即时生效,不用重启。

HTTP 接口(面板用的就是这三个)

| 方法 | 路径 | 说明 |
| GET | /plugins/dsh-session-mover/state | 工作区清单 + 会话清单(含 readable / live / title / 分组) |
| POST | /plugins/dsh-session-mover/migrate | { sessionId, targetWorkspaceId } |
| POST | /plugins/dsh-session-mover/repair | { sessionId } |

两个 POST 需要 x-dsh-session-mover: session-mover 头,并通过 Host 的本机同源校验;跨站请求会被拒。

已知边界

- 正在 DSH 里打开的会话不能迁移(日志被写句柄占着),返回 409。请先关掉那个会话。
- 热更新归属只用到一个非公开方法:workspaceRegistry.indexHeader()。attachSession 会用内存里启动时缓存的头部索引校验 cwd,文件搬走后该索引过期,必须先刷新它。这一点无法用公开 API 替代。若该方法在某版本不存在,插件会自动退回「直写 workspace.json」并提示需要重启;再不行就只搬文件,重启后手动把会话拖进目标分组。
- 迁移不会改动 defaultWorkspaceId,也不会动别的会话。
- 只用 Node 内置模块,无第三方运行时依赖。

开发与测试

node --check lib/migrate.js
node --check lib/index.js
node --check lib/client.js
node tests/unit.mjs # 12 项
node tests/host.test.mjs # 10 项

覆盖内容:

- 路径编码(projectKey / encodeSegment)与真实 sessions 目录名逐字一致(含中文路径);
- 合成多帧 fixture 的完整迁移:header 改写、body 帧逐字节不变、旧目录删除、备份与 manifest;
- 世代感知定位:v0 与 vN 两种命名都能定位并沿用同名迁移;文件名世代与 header.version 不一致时判定为不可读;
- 单帧塌缩(历史上导致会话消失的那个 bug)的检测与修复,修复后内容零丢失且幂等;
- no-overwrite、迁移到同工作区的 no-op、日志位置与头部 cwd 不符时拒绝;
- host 集成测试:用模拟 ctx 真实跑通 apply() → 路由注册 → 鉴权(跨站 403、缺确认头 403)→ 迁移成功(attach/detach/indexHeader 调用与文件落位都有断言)→ 打开中的会话 409 → 修复入口;
- 标题优先级:缓存命中直接用,缓存缺失才查 sessionQuery,并断言命中过的不会重复查;
- 归属更新必须被证实:模拟上游 attachSession 静默无效(成员被 canonical-cwd 过滤丢掉)时,插件必须报 disk 而不是 hot,并如实说明需要重启——避免「报成功但侧边栏没有」;
- 真实 DSH 会话根目录的只读回归(本机 31/31 可定位、可读;没有真实目录时自动跳过)。

License

MIT
预览分享卡片长什么样 ↓yvban/dsh-session-mover
分享 · DeepSeek Harness Hub
yvban/dsh-session-mover

在工作区之间安全搬迁会话并保留完整历史

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部