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

宿主迁移助手 cutiedirt/dsh-migrate

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

安全搬迁会话、工作区与凭据到新机器

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

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

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

状态速览

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

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

验证判据与等级说明 →

可信度证据

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

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

读写/删除本地文件
查看扫描证据(共 48 处,展示前 46 条)
  • 读取本地文件
    bin/dsh-migrate.mjs:21
    const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8'))
  • 读取本地文件
    bin/dsh-migrate.mjs:57
    push(existsSync(p), `${step}: ${p}`, existsSync(p) ? '' : '不存在')
  • 读取本地文件
    lib/manifest.mjs:14
    while (existsSync(dir)) dir = join(root, `run-${stamp}-${++n}`)
  • 写入本地文件
    lib/manifest.mjs:15
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    lib/manifest.mjs:24
    mkdirSync(manifest.backupDir, { recursive: true })
  • 读取本地文件
    lib/manifest.mjs:33
    if (!existsSync(absPath)) {
  • 写入本地文件
    lib/manifest.mjs:41
    copyFileSync(absPath, target)
  • 读取本地文件
    lib/manifest.mjs:68
    if (!e.backupPath || !existsSync(e.backupPath)) { result.missingBackup.push(e.path); continue }
  • 写入本地文件
    lib/manifest.mjs:69
    mkdirSync(dirname(e.path), { recursive: true })
  • 写入本地文件
    lib/manifest.mjs:70
    copyFileSync(e.backupPath, e.path)
  • 写入本地文件
    lib/util.mjs:10
    mkdirSync(p, { recursive: true })
  • 读取本地文件
    lib/util.mjs:15
    return JSON.parse(readFileSync(p, 'utf8'))
  • 写入本地文件
    lib/util.mjs:20
    writeFileSync(p, JSON.stringify(obj, null, 2) + '\n', 'utf8')
  • 读取本地文件
    lib/util.mjs:29
    return sha256(readFileSync(p))
  • 读取本地文件
    lib/util.mjs:43
    if (!existsSync(root)) return out
  • 读取本地文件
    lib/util.mjs:45
    for (const e of readdirSync(dir, { withFileTypes: true })) {
  • 读取本地文件
    lib/util.mjs:56
    try { return statSync(p) } catch { return undefined }
  • 读取本地文件
    lib/steps/attachments.mjs:19
    if (!existsSync(dir)) return []
  • 读取本地文件
    lib/steps/attachments.mjs:29
    if (!existsSync(dst)) missing.push({ from: p, to: dst, rel })
  • 写入本地文件
    lib/steps/attachments.mjs:41
    mkdirSync(join(objectsOf(section.target), m.rel.split(/[ /]/).slice(0, 1)[0]), { recursive: true })
  • 读取本地文件
    lib/steps/attachments.mjs:42
    if (existsSync(m.to)) {
  • 写入本地文件
    lib/steps/attachments.mjs:47
    copyFileSync(m.from, m.to)
  • 读取本地文件
    lib/steps/attachments.mjs:63
    if (!existsSync(dst)) { missing.push(rel); continue }
  • 读取本地文件
    lib/steps/memory.mjs:86
    if (!existsSync(section.source)) throw new Error(`源库不存在:${section.source}`)
  • 读取本地文件
    lib/steps/memory.mjs:88
    const tgtExists = existsSync(section.target)
  • 读取本地文件
    lib/steps/memory.mjs:121
    if (!existsSync(section.target)) {
  • 写入本地文件
    lib/steps/memory.mjs:125
    copyFileSync(section.source, section.target)
  • 读取本地文件
    lib/steps/memory.mjs:179
    const result = { source: section.source, target: section.target, exists: existsSync(section.target), ok: false }
  • 读取本地文件
    lib/steps/memory.mjs:180
    if (!existsSync(section.target)) { log?.error('目标库不存在'); return result }
  • 读取本地文件
    lib/steps/sessions.mjs:15
    if (!section?.root || !existsSync(section.root)) return { files, skippedNonZstd }
  • 读取本地文件
    lib/steps/sessions.mjs:17
    try { projects = readdirSync(section.root, { withFileTypes: true }) } catch { return { files, skippedNonZstd } }
  • 读取本地文件
    lib/steps/sessions.mjs:22
    try { sessions = readdirSync(projectPath, { withFileTypes: true }) } catch { continue }
  • 读取本地文件
    lib/steps/sessions.mjs:27
    try { entries = readdirSync(sessionPath, { withFileTypes: true }) } catch { continue }
  • 读取本地文件
    lib/steps/sessions.mjs:50
    const buf = readFileSync(file)
  • 读取本地文件
    lib/steps/sessions.mjs:92
    const original = readFileSync(action.file)
  • 写入本地文件
    lib/steps/sessions.mjs:94
    writeFileSync(action.file, rewritten.buffer)
  • 读取本地文件
    lib/steps/usage.mjs:54
    const target = existsSync(section.target) ? loadLedger(section.target) : { version: 1, days: {} }
  • 读取本地文件
    lib/steps/usage.mjs:57
    if (!existsSync(src)) { log?.warn(`源账本不存在,跳过:${src}`); continue }
  • 读取本地文件
    lib/steps/usage.mjs:75
    const merged = existsSync(section.target) ? loadLedger(section.target) : { version: 1, days: {} }
  • 读取本地文件
    lib/steps/usage.mjs:79
    if (!existsSync(src)) { log?.warn(`源账本不存在,跳过:${src}`); continue }
  • 读取本地文件
    lib/steps/usage.mjs:102
    if (!existsSync(section.target)) return { error: 'target 不存在', ok: false }
  • 读取本地文件
    lib/steps/workspace.mjs:21
    if (!existsSync(sessionsRoot)) { log?.warn(`sessionsRoot 不存在:${sessionsRoot}`); return out }
  • 读取本地文件
    lib/steps/workspace.mjs:22
    for (const wsDir of readdirSync(sessionsRoot, { withFileTypes: true })) {
  • 读取本地文件
    lib/steps/workspace.mjs:26
    for (const s of readdirSync(dir, { withFileTypes: true })) {
  • 读取本地文件
    lib/steps/workspace.mjs:28
    const hasLog = readdirSync(join(dir, s.name)).some((f) => f.endsWith('.zstd'))
  • 读取本地文件
    lib/steps/workspace.mjs:97
    registrySha256: existsSync(section.registry) ? sha256File(section.registry) : null,
扫描于 2026/11/3(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

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

README

由 DeepSeek 最新模型翻译生成
dsh-migrate 把一个 DSH(DeepSeek Harness)宿主的本地状态,安全地搬到另一个宿主 / 另一台机器:设定、凭据、工作区注册表、历史会话、附件、用量账本、以及(可选)meow-memory 记忆库。 非官方工具。 只操作磁盘上的公开格式,不调用 DSH 私有 API,不联网,不碰凭据内容。 作者与本工具与 DeepSeek 官方无关。 为什么需要它 手工搬 DSH 数据有三类「静默损坏」,每一类都真实发生过: | 坑 | 后果 | | 会话日志是多帧 zstd,用 zstdDecompressSync(整文件) 只解第一帧 | 「整文件解压再重压」= 历史全丢(实测把 111 份会话写成只剩 header) | | 会话归属取决于日志第一帧 header 里的 cwd | 复制到新宿主后,工作区里一个会话都不显示 | | 工作区注册表 / 归档列表与磁盘不同步 | 会话文件在磁盘上,侧栏里永远看不到 | dsh-migrate 把这三件事做成带校验、可回滚、幂等的步骤。
展开完整文档(README 剩余 1 节)
dsh-migrate

把一个 DSH(DeepSeek Harness)宿主的本地状态,安全地搬到另一个宿主 / 另一台机器:设定、凭据、工作区注册表、历史会话、附件、用量账本、以及(可选)meow-memory 记忆库。

非官方工具。 只操作磁盘上的公开格式,不调用 DSH 私有 API,不联网,不碰凭据内容。
作者与本工具与 DeepSeek 官方无关。

为什么需要它

手工搬 DSH 数据有三类「静默损坏」,每一类都真实发生过:

| 坑 | 后果 |
| 会话日志是多帧 zstd,用 zstdDecompressSync(整文件) 只解第一帧 | 「整文件解压再重压」= 历史全丢(实测把 111 份会话写成只剩 header) |
| 会话归属取决于日志第一帧 header 里的 cwd | 复制到新宿主后,工作区里一个会话都不显示 |
| 工作区注册表 / 归档列表与磁盘不同步 | 会话文件在磁盘上,侧栏里永远看不到 |

dsh-migrate 把这三件事做成带校验、可回滚、幂等的步骤。

快速开始

node bin/dsh-migrate.mjs doctor -c migrate.json # 体检两端环境,只读
node bin/dsh-migrate.mjs plan -c migrate.json # 只读:列出将要改什么、多少字节
node bin/dsh-migrate.mjs apply -c migrate.json --step sessions
node bin/dsh-migrate.mjs verify -c migrate.json # 出机器可读报告
node bin/dsh-migrate.mjs rollback -c migrate.json # 按 manifest 还原

默认 dry-run:不给 --write 时,apply 只打印计划,不落盘。

步骤

| 步骤 | 作用 | 状态 |
| sessions | 按帧改写会话日志第一帧的 cwd(尾部逐字节保留),并校验 | ✅ v0.1 |
| workspace | 对齐 storages/workspace.json 的 sessionIds / archivedSessionIds | ✅ v0.1 |
| attachments | 补齐内容寻址附件对象(attachments/v1/objects/…) | ✅ v0.1 |
| usage | 按来源分桶合并用量账本(重跑幂等) | ✅ v0.1 |
| memory | meow-memory 记忆库(SQLite)按主键并集合并(源只读、目标先备份、自增主键表按内容键去重) | ✅ v0.2 |
| preset | 校验智能体预设是否被新宿主识别(声明行形式) | v0.2 |

已验收(v0.1.0)

| 检查 | 结果 |
| node --test "test/.test.mjs" | 11 pass / 1 skip(/mnt 拒绝那条在 Windows 上跳过),连续跑两次结果一致(测试不污染共享夹具) |
| CLI 端到端(夹具) | plan → apply(dry-run) → apply --write → 重跑 0 变更 → verify:badFrames=0, mismatched=0 |
| 真实会话日志(只读,改写只发生在临时副本) | 3 份最大样本:7.16 MB / 2120 帧、7.33 MB / 2767 帧、5.09 MB / 14478 帧(v0 无版本老日志) —— 帧数/行数不变、尾部逐字节一致、原件 SHA 未变 |
| 真实 sessions 根只读 plan | 171 个 .zstd,unreadable=0 |
| 真实记忆库合并(两份真库副本) | 11 张表、+2 插入 / ~1 替换;重跑 0 变更;integrity_check=ok、missing=0 |

真实数据压测脚本:node tools/accept-real-logs.mjs <repoDir> <sessionsRoot> [maxFiles](只读真实文件)。

安全红线

1. dry-run 默认;--write 才落盘,每步先备份。
2. 永不删除原件;只写副本,manifest 记录每一个字节的去向。
3. 幂等:重跑零变更;中断可续。
4. 会话日志只重编码第一帧,并断言「尾部逐字节一致」;不一致立即中止。
5. 禁止把 SQLite 库放在 /mnt/(drvfs/9p)给 WSL 侧使用——实测会 disk I/O error 甚至损坏。
6. 任何「看起来成功」都要有机器可读的校验报告(verify 输出 JSON)。

细节见 docs/DESIGN.md 与 docs/SAFETY.md。

测试

node test/make-fixtures.mjs test/fixtures # 生成合成会话/注册表夹具
node --test test/ # 跑全部测试

夹具全部是合成数据,仓库内不含任何真实会话、记忆或凭据。

License

MIT
预览分享卡片长什么样 ↓cutiedirt/dsh-migrate
分享 · DeepSeek Harness Hub
cutiedirt/dsh-migrate

安全搬迁会话、工作区与凭据到新机器

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