DeepSeek-Harness 更新后启动连环报错?pnpm clean + 插件升级 + 缓存重建------大版本升级的三层残留排查
Windows 10 · DeepSeek Harness v0.1.1-rc.2 → 0.1.2-alpha.4 · Node v24.15.0 / pnpm 11.7.0 · dshmarket 1.17.1 → 1.38.1 · 最后更新 2026-09-02
一、这篇日志解决什么问题

一句话定位: 自建(git clone)部署的 DeepSeek Harness 从 v0.1.1-rc.2 升级到 v0.1.2-alpha.4 后,构建、启动、再启动连续报三个错,每个错都发生在不同的「本地状态层」------本文按出现顺序拆解三个报错的完整根因与修复命令,并沉淀出一套**「大版本更新 = 三层本地残留」**的排查框架。
跳读指南:
- 只想抄修复命令 → 七、速查卡
- 想看第一个报错(构建失败 MISSING_EXPORT)→ 四、Debug #1
- 想看第二个报错(插件 ESM 导入失败)→ 五、Debug #2
- 想看第三个报错(存储缓存 schema 不匹配)→ 六、Debug #3
- 想理解「为什么 git pull 重新拉一遍也没用」→ 三、机制:三层本地残留
阅读前提:
- 用 git clone 方式部署过 DeepSeek Harness(或同类 Node monorepo 项目),不是 npm 全局安装
- 装过第三方 dsh 插件(如 dshmarket),或知道插件装在
<项目根>\.dsh\profiles\web\node_modules下 - 会用
pnpm基本命令
读完能得到:
- 三个报错的一对一修复命令(clean / update / 缓存备份重建)
- 「三层本地残留」排查框架:仓库构建产物、用户 profile 插件、运行时存储缓存------大版本更新后分别怎么失效、怎么验证
- 两个值得留意的上游信号:npm 暂缓发布与缓存域版本号未同步
二、背景:一次「成功了一半」的大版本更新
DeepSeek Harness(dsh)在 2026-08-13 以 v0.1 开发者预览版开源,理念是「一切皆插件」------模型、工具、会话、存储、UI 全部由 Cordis 插件组合而成。我的本地部署是 git clone 到 <项目根>\DeepSeek-Harness,日常用两个批处理脚本维护:__更新DeepSeek-Harness.bat(git pull + pnpm install)和 __启动DeepSeek-Harness.bat(pnpm dsh web)。
2026-09-02 例行更新时,git fetch 发现远端已领先 1727 个提交,版本从 dsh-v0.1.1-rc.2 跳到 dsh-v0.1.2-alpha.4。按既有流程执行:
bash
git pull --autostash # 成功,快进合并无冲突
pnpm install # 成功,依赖同步完成
pnpm build # 失败 ← Debug #1
跳过 Debug #1 后继续:
bash
pnpm dsh web # 失败 ← Debug #2
# 修完 Debug #2 再启动
pnpm dsh web # 失败 ← Debug #3
三个报错按「构建 → 加载 → 存储」的顺序出现,分别发生在三个完全不同的位置 。事后查官方 release 说明才理解为什么会这样:v0.1.2-alpha 是一次重构烈度极高的破坏性版本------APIProxy 通道彻底移除、Web 客户端大幅拆分、Session 架构改为严格可重放语义、模型/Provider 体系全面升级。官方甚至因此暂缓了 npm 发布(npm latest 仍停留在 0.1.1-rc.2),就是为了留时间给下游插件适配------但本地已有的旧状态不会自己适配。
三、机制:为什么「git pull 重新拉一遍」救不了
升级后系统里存在三类「本地状态」,git 全都管不到:
| 层 | 位置 | 内容 | 升级后可能失效的原因 |
|---|---|---|---|
| ① 仓库构建产物 | <项目根>\DeepSeek-Harness\packages\**\lib |
tsc / tsdown 编译输出 | .gitignore 忽略了 lib/,git pull 不会删除旧产物 |
| ② 用户 profile 插件 | <项目根>\.dsh\profiles\web\node_modules |
第三方插件及其编译产物 | 在仓库目录外,插件版本由 profile 的 package.json 管理,不会自动升级 |
| ③ 运行时存储缓存 | <项目根>\.dsh\storages |
各存储域的缓存数据文件 | 在仓库目录外,记录 schema 由代码版本决定,旧记录按新 schema 解析会失败 |
为什么 CI 上从来不会遇到这些问题?因为 CI 是全新克隆 + 全新安装 ------它没有历史残留,只有 git clone 那一刻的状态。本地升级则是「在旧状态之上叠加新代码」,三层残留中任何一层失效都会让流程中断。这解释了下面三个 Debug 的共同特征:报错信息指向的都是「新代码 + 旧数据」的组合,而不是「代码本身写错了」。
四、Debug #1 --- 构建失败 MISSING_EXPORT:被删包的编译产物还躺在磁盘上
报错日志
pnpm build 失败,外层是构建脚本的包装错误,内层是 tsdown(rolldown 打包器)的缺导出错误:
[ELIFECYCLE] Command failed with exit code 1.
D:\<项目根>\DeepSeek-Harness\scripts\build.ts:27
throw new Error(`build: ${script} exited with ${String(result.status ?? result.signal)}`)
Error: build: build:lib exited with 1
[MISSING_EXPORT] "PresetExistsError" is not exported by
"../../preset/agent-presets/src/index.ts".
lib/types/api-proxy.js:20:32
[MISSING_EXPORT] "PresetMountError" is not exported by
"../../preset/agent-presets/src/index.ts".
lib/types/api-proxy.js:20:51
[MISSING_EXPORT] "PresetNotWritableError" is not exported by
"../../preset/agent-presets/src/index.ts".
lib/types/api-proxy.js:20:69
根因
报错文件是 lib/types/api-proxy.js------注意,这是编译产物 (源码在 src/ 下,tsc 输出到 lib/)。查证后确认:
- v0.1.2 彻底移除了 APIProxy(官方 release 说明原文),源码里的
packages/host/apiproxy包整个被删掉了 - 但旧版编译产物
packages/host/apiproxy/lib/还在磁盘上------.gitignore第 4 行就写着lib/,git pull 不会碰它 tsc -b是增量编译,不会清理「源文件已删除」的孤儿输出- tsdown 打包时按目录扫描,把这份过期产物当成了源码,其中引用的
PresetExistsError等导出在新版agent-presets包里已经不存在 → MISSING_EXPORT
机制层面一句话:删除一个包,不等于删除它的输出。 .gitignore 保护了产物不被版本控制,但也意味着没有任何机制负责回收它们。
对比表
| 维度 | 修复前 | 修复后 |
|---|---|---|
packages/host/apiproxy/ 源码 |
已删除(新版) | 已删除(保持) |
packages/host/apiproxy/lib/ 产物 |
残留,被 tsdown 当源码打包 | 随 pnpm clean 移除 |
| 构建行为 | 打包残留文件 → MISSING_EXPORT | 正常打包全部现存包 |
代码修复
项目自带的 scripts/clean.ts 专门处理这种情况------它扫描所有包目录,识别出**没有 package.json 且目录里只剩已知残留(lib、node_modules 等)**的目录并删除;遇到目录里有未知文件时会拒绝删除(保守设计,防止误删用户文件)。
bash
npx tsx scripts/clean.ts
# clean: removed 269 paths
顺手把这一步固化进了更新脚本:
__更新DeepSeek-Harness.bat的流程从「pull → install」扩展为「pull → install → clean」,下次更新不再需要手动排查。大版本更新后,先 clean 再 build 应该成为默认流程。
验证
bash
pnpm build
# ✓ built in 1.98s
# build: recorded 220 client artifact(s) with 3 public value(s)
五、Debug #2 --- 启动失败 installSettingsSection:第三方插件比 SDK 老一代
报错日志
构建通过后启动,这次崩在插件加载阶段:
Error: failed to import loader entry dsh-market (dshmarket): The requested
module '@deepseek-ai/dsh-settings' does not provide an export named
'installSettingsSection'
at updateError (D:\<项目根>\DeepSeek-Harness\vendor\loader\src\config\entry.ts:26:10)
[cause]: file:///D:\<项目根>\.dsh\profiles\web\node_modules\dshmarket\lib\settings.js:35
import { installSettingsSection, settingsNamespace } from '@deepseek-ai/dsh-settings';
SyntaxError: The requested module '@deepseek-ai/dsh-settings' does not
provide an export named 'installSettingsSection'
根因
dshmarket 是第三方插件(GitHub: dsh-market/dsh-market,npm 包名 dshmarket),本机装的是 v1.17.1。它编译后的 lib/settings.js 导入了 installSettingsSection 和 settingsNamespace 两个工具函数------而 0.1.2-alpha 的 @deepseek-ai/dsh-settings 已经把这两个导出删掉了 (插件的 peerDependencies 还写着 ^0.1.0-rc.7,是上一代 SDK 的依赖声明)。
这里有个机制细节值得记住:ESM 的具名导入(named import)解析失败,是模块求值阶段的 SyntaxError,而不是运行时错误。 插件作者原本指望「settings 服务没装就优雅降级」(ctx.inject 会安静地返回 null)------但导入的是「导出」而不是「服务」:导出不存在 = 模块直接语法错误 = 加载器把整个 entry 判为失败 = 宿主进程退出。服务缺失可以降级,导出缺失只能崩。
官方其实预料到了这个局面:0.1.2-alpha 在 GitHub 发布但故意不发布到 npm,就是为了等社区插件适配。只是本地旧插件的适配需要你自己升级。
对比表
| 维度 | dshmarket 1.17.1(旧) | dshmarket 1.38.1(新) |
|---|---|---|
| 对 dsh-settings 的依赖 | 具名导入已删除的导出 | 内联实现原 wrapper 逻辑,零依赖 |
| peerDependencies | ^0.1.0-rc.7(旧 SDK) |
兼容 dsh 0.1.2 的 settings peer |
| 启动行为 | 模块求值报错,宿主退出 | 正常加载 |
代码修复
插件装在 profile 目录(<项目根>\.dsh\profiles\web),profile 的 package.json 里声明的是 "dshmarket": "^1.17.1"------^ 范围允许升到最新 1.x,直接更新即可:
bash
cd <项目根>\.dsh\profiles\web
pnpm update dshmarket
# Packages: +1 → dshmarket 1.38.1
为什么是 1.38.1 而不是当时最新的 1.39.0?1.38.1 的 release note 正是「修复:安装市场插件不再导致 dsh 0.1.2-alpha 启动失败」,1.39.0 进一步声明支持 dsh 0.1.2 的 settings peer。
pnpm update按 lockfile 约束解析,如果没升到预期版本,显式pnpm add dshmarket@latest兜底。
验证
bash
pnpm dsh web
# 不再出现 loader entry 报错
六、Debug #3 --- 启动失败 session_projcache schema 不匹配:缓存域的版本号没跟上
报错日志
插件问题解决后再次启动,这次崩在存储域打开阶段:
Error: failed to apply loader entry session-projection-cache
(@deepseek-ai/dsh-session-projection-cache): domain 'session_projcache':
stored record '10d15c18-046e-406c-aca0-9688c1a455a7' in table 'sessions'
does not match its schema
Invalid input: expected number, received undefined
path: ["identity", "inheritedEventCount"]
根因
session_projcache 是会话投影缓存域,记录的是「每个会话的投影检查点」。新版在记录的 identity 里新增了必填字段 inheritedEventCount (fork 继承的事件前缀长度),而磁盘上 0.1.1 时代写入的旧记录没有这个字段------按新 schema 解析,expected number, received undefined。
关键在域版本号:spec.ts 里域声明是 version: 5,schema 变更后版本号没有 bump。而项目源码注释明确写了这个域的设计语义:
缓存是 fold shortcut,never an authority------记录可能过期(seq 说明过期程度)但永远不会错,所以每次写入都是 fail-soft;per-record 布局下,域版本 bump 后过期的文档会在 open 时被丢弃(缓存语义),而不是拒绝整个介质。
也就是说:设计上「版本号 bump → 旧文档自动丢弃 → 多花一次尾部重放」;实际是「版本号没 bump → 旧文档按新 schema 硬解析 → 整个域打开失败 → 启动中止」。机制层面这是缓存域的版本号管理与 schema 演进没同步(疑似上游 bug:master 上该域版本仍为 5)。
对比表
| 维度 | 设计预期 | 实际发生 |
|---|---|---|
| 域版本号 | schema 变更时 bump | 仍为 5,未同步 |
| 过期记录处理 | open 时丢弃(缓存语义) | 按新 schema 解析,抛错 |
| 启动行为 | 多一次尾部重放,正常启动 | 整个域失败,宿主退出 |
代码修复
既然是「非权威」的缓存,正确的处理就是丢弃后重建。稳妥起见先改名备份(不直接删),确认系统正常后再删:
bash
cd <项目根>\.dsh\storages
mv session_projcache session_projcache.stale-v4.bak
mv session_projcache.json session_projcache.json.stale-v4.bak
为什么不直接删?改名保留了恢复路径,万一下一次启动还有别的问题,可以马上还原对比。缓存丢了唯一的代价是「冷读时多一次尾部重放」------真实会话数据在
<项目根>\.dsh\sessions\(session 持久化),完全不受影响。
验证
bash
pnpm dsh web
# 启动成功,无报错
curl http://127.0.0.1:3080/ # 返回 401
401 是正常的:dsh web 对 /api 有浏览器信任围栏(browser-trust fence),无浏览器上下文的 curl 请求会被拒,浏览器访问不受影响。服务确认在监听即可。
七、速查卡
7.1 路径汇总
| 层 | 路径 | 说明 |
|---|---|---|
| ① 仓库构建产物 | <项目根>\DeepSeek-Harness\packages\**\lib |
tsc/tsdown 输出,被 .gitignore 忽略 |
| ② profile 插件 | <项目根>\.dsh\profiles\web\node_modules |
第三方插件(dshmarket 等),插件声明在 profile 的 package.json |
| ③ 存储缓存 | <项目根>\.dsh\storages\session_projcache* |
会话投影缓存(非权威数据) |
| ③ 真实会话 | <项目根>\.dsh\sessions\ |
会话持久化数据,清缓存不影响 |
| 工具 | <项目根>\DeepSeek-Harness\scripts\clean.ts |
仓库清理脚本(pnpm clean) |
7.2 常见报错 → 解决方案
| 报错特征 | 解决 |
|---|---|
MISSING_EXPORT ... not exported by ... 且报错文件在 lib/ 下 |
被删包的编译产物残留 → npx tsx scripts/clean.ts([Debug #1](#1) does not provide an export named 'installSettingsSection' / loader entry 导入失败 第三方插件比 SDK 老一代 → cd <项目根>.dsh\profiles\web && pnpm update <插件名>(Debug #2) stored record ... does not match its schema / expected number, received undefined 缓存记录 schema 过期 → 改名备份 session_projcache* 后重启(Debug #3) curl 访问 3080 端口返回 401 正常,浏览器信任围栏(browser-trust fence))) |
does not provide an export named 'installSettingsSection' / loader entry 导入失败 |
第三方插件比 SDK 老一代 → cd <项目根>\.dsh\profiles\web && pnpm update <插件名>([Debug #2](#1) does not provide an export named 'installSettingsSection' / loader entry 导入失败 第三方插件比 SDK 老一代 → cd <项目根>.dsh\profiles\web && pnpm update <插件名>(Debug #2) stored record ... does not match its schema / expected number, received undefined 缓存记录 schema 过期 → 改名备份 session_projcache* 后重启(Debug #3) curl 访问 3080 端口返回 401 正常,浏览器信任围栏(browser-trust fence))) |
stored record ... does not match its schema / expected number, received undefined |
缓存记录 schema 过期 → 改名备份 session_projcache* 后重启([Debug #3](#1) does not provide an export named 'installSettingsSection' / loader entry 导入失败 第三方插件比 SDK 老一代 → cd <项目根>.dsh\profiles\web && pnpm update <插件名>(Debug #2) stored record ... does not match its schema / expected number, received undefined 缓存记录 schema 过期 → 改名备份 session_projcache* 后重启(Debug #3) curl 访问 3080 端口返回 401 正常,浏览器信任围栏(browser-trust fence))) |
| curl 访问 3080 端口返回 401 | 正常,浏览器信任围栏(browser-trust fence) |
7.3 大版本更新检查清单
-
git pull后先看版本跳了多大(git describe --tags --abbrev=0),跨 alpha/rc 大版本默认按「三层残留」排查 - 构建前
pnpm clean(更新脚本已内置此步) - 构建失败看报错路径:
lib/下 → clean;node_modules下 → 升级插件 - 启动失败看报错阶段:loader entry → 插件;storage domain → 缓存
- 动
.dsh数据前先改名备份,确认后再删 - 启动后
curl http://127.0.0.1:3080/有响应(401 也算)即服务在线
八、扩展阅读
本系列相关文章:
- AI 写代码反复返工?先冻结契约再让 AI 动手------26 份 ADR 的实战提炼(AI 写代码反复返工?先冻结契约再让 AI 动手------26 份 ADR 的实战提炼.md) --- 同系列方法论篇:排障修的是「代码层」还是「规则层」,先分类再动手
- Claude Code 一用 Bash 就刷屏 hook 报错 node 找不到?Git Bash 的 PATH 里根本没有 node(Claude Code 一用 Bash 就刷屏 hook 报错 node 找不到?Git Bash 的 PATH 里根本没有 node.md) --- 同系列排障日志,环境层问题排查
参考文献
- DeepSeek Harness --- GitHub --- 官方仓库(本文全部源码排查依据)
- dsh-v0.1.2-alpha 版本发布说明 --- 官方 release,APIProxy 移除与破坏性重构的说明
- dsh-market --- GitHub --- dshmarket 插件仓库,v1.38.1 修复 0.1.2-alpha 启动问题的发布记录