跳到主要内容
路径文档

版本升级与迁移指南

一句话版:保留旧环境,先在新的 DSH home 和测试工作区验收源码版,再切换日常入口;回退时同时恢复旧运行时与旧数据副本。

审计基线 0.1.5-alpha.1 @ 5dda764ed3(2026-09-09 核验)。 本文处理升级到 0.1.5-alpha.1 的迁移:第 3 节汇总 0.1.2 以来的接口变更,第 4 节是 0.1.5 新增的会话存储格式 v2 → v3 迁移;不构成对未来版本的兼容性承诺。shell 示例适用于 macOS / Linux。

1. 先选渠道,而非直接换版本号

渠道本次核验结果适合
npm latest / next都是 0.1.2-rc.1继续使用已发布包
官方源码 / tag0.1.5-alpha.1,tag 为 dsh-v0.1.5-alpha.1验证本文的新接口
npm alpha 通道0.1.5-alpha.1想直接用已发布包时选它
node --version
npm view @deepseek-ai/dsh dist-tags --json

源码 Node 要求为 ^22.19.0 || >=24.0.0。默认 npx @deepseek-ai/dsh web 仍启动 npm 版;Git tag 存在不等于同名 npm 包已发布。后续渠道变化以 状态页 和现场查询为准。

2. 升级流程

记录与备份

先记录当前使用的是 npm 还是源码、精确版本 / commit、DSH_HOME、profile、额外 patch 与外部插件路径。停止 Web、SDK、ACP 等使用同一 home 的进程,等日志写入结束;只关闭浏览器标签页并不等于停掉 Host。

export DSH_HOME="${DSH_HOME:-$HOME/.dsh}"
STAMP="$(date +%Y%m%d-%H%M%S)"
BACKUP="${DSH_HOME%/}.backup-$STAMP"

umask 077
test -d "$DSH_HOME" && test ! -e "$BACKUP" && \
cp -a "$DSH_HOME" "$BACKUP" && printf 'Backup: %s\n' "$BACKUP"

备份包含凭据、对话与插件配置,应留在私有目录。它不覆盖项目工作区,也不一定覆盖外部插件源码或 MCP 记忆库;这些需按各自位置另存。不要一边运行一边复制数据库或会话日志。

独立构建与试运行

下面的源码目录与试用 home 均应为新路径:

git clone --branch dsh-v0.1.5-alpha.1 --depth 1 \
https://github.com/deepseek-ai/deepseek-harness.git \
"$HOME/deepseek-harness-alpha-trial"
cd "$HOME/deepseek-harness-alpha-trial"
git rev-parse HEAD
pnpm install
pnpm run build

export TRIAL_HOME="$HOME/.dsh-alpha-trial-$STAMP"
DSH_HOME="$TRIAL_HOME" pnpm dsh web

首次试运行配置独立的模型凭据,并选择不含敏感信息的测试目录。新 home 不会自动继承旧 home 的登录、设置或会话;单独换 home 也不构成工作区隔离。

先确认出厂组合正常,再逐项迁入旧 profile patch 和自定义插件。不要用整个旧 profile 目录覆盖新模板,否则旧依赖清单及安装产物也会一起进入新环境。外部绝对路径和插件版本尤其要复核。

3. 必查迁移表

旧写法 / 习惯新基线的处理深入说明
DSH_TOOLS_MODE=codemode: code改用 ptc;纯 PTC 下具名工具直调返回 UNKNOWN_TOOL,通过 run_code 的 SDK 绑定调用工具执行
导入 dsh-host-apiproxy旧包已移除,按 Session / Settings / Workspace 等领域消费 typed RemoteRemote API
导入 dsh-client-runtime按职责迁至 store、Session controller 或 React 适配层,别机械替换包名Web UI
TS SDK launch: { command, args }使用 dshBinprofilepatches;客户端与运行时版本匹配SDK
SDK / ACP demo bin使用 dsh --profile sdk / sdk-minimal / acpACP
直接访问干净的 Web 根地址首次打开 CLI 打印的 token 启动链接,换取浏览器会话 cookie快速上手
--host 0.0.0.0 开放 Web UI当前 Web 启动拒绝该值;远程使用 SSH 转发,Host 信任仍与登录分开Remote API
把遥测视为单一开关OTel 默认 FEEDBACK_ONLY;插件包元数据默认开,额外 Session 日志元数据默认关,分别检查隐私

旧日志中的 tool/code-dispatch* 事件名保持有效,不要因为模式改名而批量改写历史日志。sdk-minimal 是独立组合并固定 full-access 策略,不是“更受限”的 SDK。

4. 会话存储格式迁移:V2 → V3

没有命令,打开就迁移。 session-persistence-jsonlopen(id, 'read' | 'write') 选择会话目录里版本号最高的规范 generation;若它低于 SESSION_FORMAT_VERSION(当前 3packages/core/session/src/types.ts),catalog 就把该版本到当前版本之间的相邻迁移边串成一次流式还原——0.1.5-alpha.1 新增的是最后一条边 session-format-v2-to-v3(0.1.2 写的是 v0,所以要连跑 v0→v1→v2→v3)。apps/cli 里没有迁移命令,JSONL 后端也没有迁移开关——它的配置只有 root(必填)与 compression(可选)。

打开方式行为
read单遍解码并迁移、校验当前逻辑结果,不发布后继,直接把结果返回给读者
write复用同一份按 revision 记忆的 preparation;同目录临时文件分块编码 → Worker Thread 校验 → 重查源 revision → 无覆盖发布当前 generation;源文件保持字节不变

磁盘上会多出一个当前 generation,源文件原名保留(中间的 v1/v2 不会落地——catalog 把相邻边串成一次流式还原,只发布最终结果):

<root>/--<归一化 cwd>--/<encoded-id>/
session.jsonl.zstd ← 迁移前的 generation,原名保留(0.1.2 写的是 v0)
session.v3.jsonl.zstd ← 写打开后发布的当前 generation

compression: 'none' 时后缀是 .jsonl;文件名由 packages/session/session-format/src/filename.tssessionFormatLogFilename 决定:版本 0 仍叫 session.jsonl,之后是 session.vN.jsonl。)

迁移改了什么(packages/session/session-format-v2-to-v3):

变化内容
逻辑头version: 2 → 3;保留 idcreatedAtisSeededdelegationDepth 与可选的 cwd / parentSession / origin
系统提示词request/header.data.header.system 提升为 surface 的 system/message 头(首个 step/start 之后),随后从每个 request header 移除
preset精确 id codeptcheader.agentPreset 与所有 agent-preset/selected
PTC 词汇tool/code-dispatch-start / tool/code-dispatchtool/ptc-dispatch-start / tool/ptc-dispatch;插件归属 tools-code-modetools-ptc
引用重映射surface 的 sourceEventSeqs、compaction 的 shadowedRange / shadowedSeqscommand/done.sourceEventSeq、标题事件的 messageSeqs 按插入后的位置重算
信封规范化{ op: 'replace', start, end }{ op: 'replace', startSeq, endSeq };省略 tools: []adapterDefaults: {}

兼容性与拒绝

  • 迁移保持历史请求的含义,但会插入系统事件,所以事件数、密集 seq 与局部引用都会变;不要把 v3 文件当成 v2 的逐字副本。
  • 源文件字节不变;迁移边拒绝时不发布后继,报 SessionFormatUnsupportedError(底层是 SessionFormatUnsupportedMigrationError),原始日志仍在原地,可用来排查。
  • 已标记 V3 的输入不走这条边(原生 V3 admission 另有一套更严的校验)。
  • catalog 是构建期静态清单session-format-catalog):profile 不能挂插件来增删或重排迁移边。

回退:持久化层明确不为保留的旧 generation 提供降级支持,唯一受支持的回退是第 2 节那份升级前的 home 备份。手动删除或改名 session.v3.jsonl* 只能算取证手段,不是回退方案:v3 里已经追加了迁移之后的历史,旧版读不到这些事件;而且旧运行时按"版本号最高的规范 generation"选择文件,看到 v3 会因版本高于自己支持的版本直接 SessionFormatUnsupportedError

验证:

# 当前格式版本
grep -n "SESSION_FORMAT_VERSION" packages/core/session/src/types.ts

# 一个会话目录里同时存在哪些 generation(迁移前后对比)
ls -1 ~/.dsh/sessions/*/*/session*.jsonl*

# 迁移边是构建期静态清单,不是运行时插件
grep -rn "sessionFormatMigration" packages/session/session-format-v2-to-v3/package.json

5. 分层验收,避免把启动成功当作升级完成

在源码目录、使用试用 home 检查:

DSH_HOME="$TRIAL_HOME" pnpm dsh web --dump-config
DSH_HOME="$TRIAL_HOME" pnpm dsh --profile sdk --help
DSH_HOME="$TRIAL_HOME" pnpm dsh --profile acp --help
应看到的证据
版本与组合目标 commit 正确;旧包引用已迁移;profile / patch 来源符合预期
Web 登录完整启动链接完成登录;页面没有连续 401/403 或 WebSocket 重连
基础执行在测试目录发一次读文件 / 简单工具请求,有真实结果而非只看到工具 schema
PTC(若使用)run_code 的工具绑定正常,结果进入会话
SDK / ACP(若使用)完成实际 prompt、接收结果、关闭子进程;help 只验证入口
数据与插件新会话保存并可再次打开;逐个启用的外部插件行为正常
隐私三类数据出口、模型路由及所选 permission preset 与预期一致

若要检验旧会话兼容性,用备份另建一个迁移测试副本,保留原备份不动。不要让新旧运行时同时读写同一 home。

6. 切换与回退

验收后,更新日常启动脚本中的运行时路径、DSH_HOME 和 profile,避免终端里的旧全局 dsh 与源码入口混用。保留旧备份,直到常用任务完成验证。

需要回退时,先停止新进程,保留失败环境,再从旧备份创建一个恢复 home:

RESTORE_HOME="${DSH_HOME%/}.restored-$STAMP"
test -d "$BACKUP" && test ! -e "$RESTORE_HOME" && \
cp -a "$BACKUP" "$RESTORE_HOME" && \
DSH_HOME="$RESTORE_HOME" npx @deepseek-ai/dsh@0.1.2-rc.1 web

该命令对应旧环境原本使用 npm 0.1.2-rc.1 的情况;旧环境若来自源码,应启动事先记录的旧 checkout。回退 runtime 不会撤销 Agent 对项目文件的修改;项目文件使用自己的 Git / 备份策略恢复。不要把 alpha 新写的数据直接当作旧版兼容数据。会话日志的格式迁移(第 4 节)同理:它不提供降级,回退只能靠升级前的 home 备份。

源码依据与下一步