dsh-shuttle:在 DSH 与 Codex、Claude Code 之间双向迁移对话记录

前言

如果你同时使用 Codex、Claude Code、Pi、Reasonix、OpenCode 和 DSH,会遇到一个具体问题:对话记录分散在各个工具自己的存储里,格式互不兼容。想在 DSH 里继续之前的对话,或者把 DSH 会话交给其他工具接着用,基本只能手工整理。

下面介绍的 dsh-shuttle 解决的就是这个问题。它是一个 DeepSeek Harness 插件,同时提供离线 CLI,在 DSH 与这五类工具之间双向迁移对话记录。DSH 的理念是「一切皆插件」,对话迁移这类能力同样以插件形式接入,而不是改动 DSH 本体。

这是什么

dsh-shuttle 仓库为 omdsh-dev/dsh-shuttle,包名 @deepseek-ai/dsh-shuttle,由 omdsh-dev 维护,采用 MIT 许可证,当前版本 0.1.0。它支持在 DSH 与 Codex、Claude Code、Pi、Reasonix、OpenCode 之间双向迁移对话记录,既可以作为插件在 DSH 内使用,也可以作为独立 CLI 离线运行。

迁移的工作方式

迁移前,每个来源会先投影为一个 provider-neutral 的中间模型,再转换成 DSH 事件或目标平台的原生导入格式。在目标支持的前提下,文本、推理内容、工具调用与结果、时间戳、工作目录以及 provider/model 身份都会保留。

并非所有数据都可移植:Provider 私有回放状态、缓存数据、UI-only 事件、token 分块与数据库索引不在迁移范围内。二进制/图片附件在无法安全复制字节时,会变成文本占位符。

安全设计

写入类操作有几条硬性约束:

  • 默认 dry-run,带 --apply 才真正执行写入;
  • 已存在的 DSH ID 与目标文件会被跳过,从不覆盖;
  • 读取有大小/数量上限,且不递归符号链接目录;
  • DSH 写入使用 ctx.sessionPersistence,JSONL 与 SQLite 后端均可工作;
  • OpenCode 通过官方 export/import JSON envelope 处理,从不直接编辑其数据库;
  • Shuttle 从不删除源历史。

安装与启用

README 没有给出具体安装命令,只说明通过常规 DSH 插件工作流安装本包。安装后,捆绑的 cordis.patch.yml 会挂载 ctx.shuttlemigrate-conversations 技能,插件导出标准的 nameinjectConfigapply 符号。

运行环境为 Node ^22.19.0 || >=24.0.0,包管理器 pnpm@11.7.0。使用 CLI 前需要先构建:

pnpm install
pnpm build

构建后 CLI 入口为 lib/cli.js,package.json 中注册的 bin 命令名是 dsh-shuttle

通过 Settings UI 迁移

打开 Settings → Conversation migration,可以看到两个独立的导入/导出单元,不需要手工拼命令:

  1. Import to DSH 中选择来源平台,可选设置来源路径与数量上限;
  2. Export from DSH 中选择目标平台、DSH 任务、目标路径与范围;
  3. 每个单元单独预览。Settings 预览使用专用 Remote API,不会创建 DSH 会话,也不会写目标文件;
  4. 查看该单元的报告,勾选确认后执行导入或导出。

执行按钮只在当前表单成功预览后可用;更改任何迁移输入都会使预览失效。

斜杠命令 /shuttle

在存在交互式 DSH 命令服务的环境中,可以在会话输入里输入 /shuttle 查看帮助并执行导入/导出,结果直接显示在 UI,不会发送给模型:

/shuttle import codex
/shuttle import codex --source "~/.codex/sessions" --apply
/shuttle export pi --destination "~/.pi/agent/sessions"
/shuttle export opencode --session <id> --destination /tmp/opencode --apply

不带 --apply 时都是预览。导出默认针对当前 UI 会话,可以通过重复 --session--all 改变选择。

CLI 用法

CLI 提供 import/export 两个子命令,支持 --from/--to--source--destination--session(可重复)、--all--apply--dsh-root。流程是先构建,再预览,确认报告后加 --apply 写入。

先看导入。默认 DSH 存储为 $DSH_HOME/sessions~/.dsh/sessions,可用 --dsh-root 覆盖:

node lib/cli.js import --from codex
node lib/cli.js import --from claude-code --source ~/.claude/projects
node lib/cli.js import --from pi --source ~/.pi/agent/sessions
node lib/cli.js import --from reasonix --source ~/.reasonix

检查 JSON 报告后,加 --apply 重复执行同一命令完成写入。

导出方向:

node lib/cli.js export --to codex --session <id> --destination ~/.codex/sessions --apply
node lib/cli.js export --to pi --destination ~/.pi/agent/sessions --apply
node lib/cli.js export --to reasonix --destination ~/.reasonix --apply

重复 --session 可选择多个会话;省略它则导出至配置的 maxSessions 上限。

OpenCode 的读写配合它自己的 export/import 命令完成:

opencode export <session-id> > /tmp/opencode-session.json
node lib/cli.js import --from opencode --source /tmp/opencode-session.json --apply

node lib/cli.js export --to opencode --session <dsh-session-id> \
  --destination /tmp/dsh-opencode --apply
opencode import /tmp/dsh-opencode/<dsh-session-id>.opencode.json

Reasonix 方向,如果写入后它的目录里没有显示新的权威 JSONL 会话,运行一次 reasonix sessions reindex

插件 API 与配置

插件暴露两个 API,同样遵循先预览、后写入的模式:

const preview = await ctx.shuttle.importConversations({
  from: 'codex',
  source: '/path/to/.codex/sessions',
})

await ctx.shuttle.importConversations({
  from: 'codex',
  source: '/path/to/.codex/sessions',
  apply: true,
})

await ctx.shuttle.exportConversations({
  to: 'claude-code',
  sessionIds: ['session-id'],
  destination: '/path/to/.claude/projects',
  apply: true,
})

两个配置项控制读取上限:

配置项 默认值 含义
maxFileBytes 64 MiB 单个外部工件的最大尺寸
maxSessions 500 每次操作的最大工件/会话数

适用场景与注意事项

它适合在多个编码智能体之间切换、想把历史会话集中到 DSH,或需要把 DSH 会话交给其他工具继续使用的开发者。使用前注意两点:

  • Codex 与 Claude Code 不承诺稳定的公开磁盘转录 schema。读取器是宽容的,但这两家升级后需要重新预览;导出的 Codex/Claude JSONL 匹配当前观察到的 envelope,未来客户端可能需要显式导入器或适配器更新。
  • 插件以当前 dsh 进程的权限运行,安装前应检查源码与许可证(MIT)。

结尾

经过上面的步骤,分散在各家工具里的对话记录就变成了可迁移的数据;默认预览、从不覆盖的设计让每次写入都可控。代码与文档见 GitHub 仓库:

https://github.com/omdsh-dev/dsh-shuttle

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

Xiaoye