DeepSeek Harness 运行维护与故障修复手册(合并定稿版)
本文无密钥、无 token、无 cookie,可直接外发。 本文件合并了「DSH 自身实测取证版」与「ChatGPT + Codex 联合经验版」两份手册,冲突之处已逐条核查并给出结论。
0. 怎么用这份文档(最高优先级规则)
- 先读 Harness 自己生成的最新维护文档(本文件即其中之一);
- 再核验本机真实状态(版本 / DSH_HOME / PID / launchd / 端口 / 日志);
- 只有核验通过后才允许修改;
- 优先级:当前机器真实状态 > 本文件 > 旧聊天记录与旧手册。
本文件每条内容都带标签,请按标签决定信任程度:
| 标签 | 含义 |
|---|---|
| 【长期规则】 | 与版本无关的稳定结论,可直接照做 |
| 【已验证】 | 2026-09-12 在本机实测/取证过,附证据文件 |
| 【历史快照】 | 当时的状态记录,使用前必须重新核验 |
| 【待复核】 | 证据不足或与其它记载冲突,需现场确认 |
任何 PID、版本号、插件状态、端口、路径都可能在将来变化——不要把历史快照当永久事实。
1. 使用导航
| 你的处境 | 跳转 |
|---|---|
| 页面打不开 / 白屏 / 一直转圈 | §5 → §14(回退 RC8) |
| Chrome 无限弹新标签页 | §4(含完整根因,能省几小时) |
| 侧边栏工作区是空的 / 历史会话不见了 | §11(数据完整性三层模型) |
| 要升级到新版本 | §13(升级 SOP + 预检 + 红线) |
| 要删旧环境 / 回收磁盘 | §15(删除 Guard + 退役计划) |
| 给别的 AI 交代任务 | §18(接管提示词模板) |
| 想快速定位症状 | §17(症状→病因速查表) |
2. 环境快照【历史快照·2026-09-12 实测】
2.1 生产设施
| 项目 | 值 |
|---|---|
| 生产版本 | 0.1.5-rc.2(代号 RC9;上一个是 0.1.0-rc.8 = RC8) |
生产 DSH_HOME |
~/.dsh-rc9-clean |
| CLI 安装(隔离) | ~/.local/lib/dsh-versions/0.1.5-rc.2/(故意不覆盖全局安装) |
| 全局旧 CLI(回退用) | ~/.local/lib/node_modules/@deepseek-ai/dsh(0.1.0-rc.8) |
| 用户入口 | ~/.local/bin/dsh(包装器,绑定 DSH_HOME,防止回落到旧 ~/.dsh) |
| 服务 | http://127.0.0.1:3080,PID 记于 ~/Library/Logs/DeepSeek Harness/rc9-server.pid |
| Node | ~/.hermes/node/bin/node |
| LaunchAgent | ~/Library/LaunchAgents/ai.deepseek.harness.server.plist,RunAtLoad=false + KeepAlive=false |
| 默认模型 | deepseek-official / deepseek-v4-flash-vision-exp(原生多模态) |
2.2 三个启动/回退脚本(使用前先读它们的当前内容)
| 脚本 | 职责 |
|---|---|
~/.local/bin/dsh-rc9-serve |
真正的启动命令:固定 rc9 CLI + 正式 DSH_HOME + 视觉配置路径;强制 --no-open;端口被占则拒绝启动;PATH 已前置 ~/.hermes/node/bin |
~/.local/bin/dsh-rc9-start [--open] |
按需启动:停/复用判定 + PID 与命令行双重校验 + 认证 readiness(token GET=200)+ 只在 --open 时打开一次页面 |
~/.local/bin/dsh-rc8-start [--open] + dsh-rc8-serve |
回退到 RC8 的对应实现(本次新增,配套手动步骤见 §14) |
两者都内置一条守卫【已验证】:启动前若发现 旧的 ai.deepseek.harness.switch job 仍在加载,会直接拒绝启动——这个守卫是为 §4 的事故专门加的。
2.3 桌面 App【已验证】
~/Applications/DeepSeek Harness.app:原生 Swift/AppKit + WKWebView 壳(Mach-O arm64,bundle idai.deepseek.harness.rc9.native,图标AppIcon.icns)。- 行为:调用
~/.local/bin/dsh-rc9-start(不传--open)→ 从~/Library/Logs/DeepSeek Harness/rc9-server.log里用正则取最新http://127.0.0.1:3080/?token=...→ 在独立窗口里加载。App 退出不杀服务。 - 历史版本备份:
DeepSeek Harness.app.backup-20260912-184837(376K)、.backup-before-native-20260912-190814(780K,是更早的 AppleScript applet)。 - 图标异常(白卷纸):检查
Contents/Resources/AppIcon.icns、Info.plist/CFBundleIconFile、bundle id、codesign,以及 LaunchServices/Dock 缓存;不要另生成一套不一致的图标。
2.4 插件与 profile【已验证】
~/.dsh-rc9-clean/profiles/web/package.json 的 dsh.profile.bundles:
@deepseek-ai/dsh-base、@deepseek-ai/dsh-web-app、dsh-memory、dsh-design-skills、dsh-free-vision、dshmarket、@linxin666/dsh-skins、@linxin666/dsh-client-ui-task-board、dsh-cost-meter
依赖版本:task-board 0.3.20、skins 0.2.9、cost-meter 1.7.20、market 1.45.1、free-vision 1.0.8(保持 disabled)、memory/design-skills 走 file: 指向 rc9 自己的 vendor:
file:/Users/…/.dsh-rc9-clean/vendor/dsh-memory
file:/Users/…/.dsh-rc9-clean/vendor/dsh-design-skills
【已验证】vendor 已自包含(不再引用待删的旧 ~/.dsh),lockfile 里的 file: 全指向 rc9 自身。
已移除的(0.1.5 不兼容):@lmmzss/dsh-plugin-balance、@linxin666/dsh-client-ui-aionui-panel;替代品 = dsh-cost-meter。
2.5 工作区【已验证】
| 工作区 | 会话 | 路径 |
|---|---|---|
| deepseek harness | 19 | ~/Documents/deepseek harness |
| 卓望 | 4 | ~/Documents/我的知识库/卓望工作相关/卓望(旧位置有符号链接指过来) |
| 求职 | 4 | ~/Documents/我的知识库/求职相关/求职(同上) |
| 我的知识库 | 2 | ~/Documents/我的知识库 |
3. 排错总顺序【长期规则】
出任何问题,按这个顺序查,不要从底层数据开始乱修:
A. 当前真实版本与 CLI 路径(command -v dsh / cat ~/.local/bin/dsh / dsh --version)
↓
B. DSH_HOME(echo $DSH_HOME,实际进程用的是哪个)
↓
C. 所有 Harness 相关 launchd job(不止 server!见 §5)
↓
D. PID / PPID / PGID / 监听端口 / 启动时间
↓
E. 日志与信号(rc9-server.log、server.log、exit code、SIGTERM)
↓
F. credentials / config schema(按**当前版本源码**校验)
↓
G. 核心 profile 与 bundles
↓
H. 插件(逐个兼容审计)
↓
I. MCP(真实调用,而非只看进程)
↓
J. UI / 索引 / 缓存
↓
K. 数据完整性(最后才碰数据)
永远不要"重装碰运气"。 先定位根因,再做最小修复。
判断「Host 是否真的重启过」,只认三样:lsof -nP -iTCP:3080 -sTCP:LISTEN -t 的 PID、~/Library/Logs/DeepSeek Harness/rc9-server.pid、以及投递脚本自己的日志文件是否存在。不要只信自己回显的「已投递/已执行」——2026-09-15 连续两次翻车都栽在这上面(§5.4)。
4. 「Chrome 无限弹新标签页」的完整根因【已验证·三方证据合流】
4.1 现象
rc8 → rc9 升级过程中,Chrome 不断自动打开新的 Harness 页面,人工抢救数小时。
4.2 三层机制(缺任何一层都不会失控)
【第一层|反复被杀/反复退出】——两个驱动源,当时同时存在
a) 旧的 launchd job `ai.deepseek.harness.switch` 托管着 switch-to-rc9.sh 循环执行;
该脚本第 13 行是 `pkill -f "dsh-versions/0.1.5-rc.2"` → 每轮都把 rc9 杀掉。
rc9 把 SIGTERM 正常映射为 exit 0,所以日志里"正常退出"是假象。
b) 插件树启动崩溃:0.1.5 的 @deepseek-ai/dsh-settings 不再导出 installSettingsSection,
rc8 带过来的 @linxin666/* 0.2.5(由 dsh-skins 引入的 skin-center)import 失败
→ `dsh: plugin tree failed to load` → 进程直接退出。
↓
【第二层|自动重启】server plist 当时是 KeepAlive=true + RunAtLoad=true
→ 进程一退出就立刻被拉起,形成死循环。
↓
【第三层|每次启动都开浏览器】当时的启动命令是 `dsh web --port 3080`(缺 --no-open)
→ 每次拉起都"打开默认浏览器" → 每循环一次 = 一个 Chrome 标签页。
4.3 决定性证据
| 证据文件 | 证明什么 |
|---|---|
~/.dsh-rc9-clean/switch-to-rc9.sh 第 3、13、26–28 行 |
switch 脚本由 launchd 托管、含 pkill -f dsh-versions/0.1.5-rc.2、每轮 bootout/bootstrap server job |
34 个 ~/Library/LaunchAgents/ai.deepseek.harness.server.plist.before-switch-* |
该脚本至少运行了 34 次(每轮生成一个备份) |
~/.dsh-rc9-clean/.full-start.log |
插件树崩溃的完整堆栈(installSettingsSection 缺失) |
旧 server.log:28 次 dsh web: http://… + 28 次 opening the default browser |
28 次启动 = 28 个自动弹出的标签页 |
plist.before-0.1.5-rc.2 / plist.before-lifecycle-fix-20260912-123047 |
旧 plist 确实是 KeepAlive=true+RunAtLoad=true+无 --no-open |
launchctl print gui/501/ai.deepseek.harness.switch → 现已 "Could not find service" |
该 job 现在已不存在(事故后已清理) |
4.4 两份文档的分歧与结论
- Codex 侧重 launchd 的
switchjob 循环 pkill; - DSH 自查侧重 插件树崩溃 + server plist KeepAlive + 缺
--no-open; - 结论:两者都对,且是同一个事故的不同层次。 switch job 提供了"反复杀/反复重启"的驱动,插件崩溃提供了"进程自己也会退"的驱动,server plist 的 KeepAlive 把任何退出都放大成循环,
--no-open的缺失则把每次循环变成一个新标签页。 - 因此修复必须三处同时做,只修一处仍会复现:
| 修复项 | 现状 |
|---|---|
1. 清掉/不加载旧的 switch job;禁止重跑旧 switch 脚本 |
【已验证】已不存在;启动脚本内置守卫 |
| 2. 插件升到兼容版本(0.2.5 → 0.3.20),踢掉不兼容插件 | 【已验证】见 §2.4 |
3. plist 改 RunAtLoad=false+KeepAlive=false;启动命令带 --no-open;开页面仅由显式 --open 触发 |
【已验证】见 §2.2 |
5. launchd 长期规则【长期规则】
5.1 排查时必须枚举所有 Harness 相关 label
launchctl list 2>/dev/null | grep -i -E "harness|deepseek|dsh"
launchctl print "gui/$(id -u)/ai.deepseek.harness.server" # 单个 label 的详情
ls -la ~/Library/LaunchAgents/ | grep -i harness
重点排查 label 名里含:switch / watcher / monitor / updater / legacy。本次事故的真凶就是 ai.deepseek.harness.switch,而不是 server。
5.2 不要盲目 KeepAlive
KeepAlive=true + 自动开浏览器 + 启动异常 = 无限循环。生产入口改为显式启动脚本 + 按需拉起。
5.3 Bootstrap failed: 5: Input/output error 不要立刻 sudo
先检查:plist 语法(plutil -lint)、owner/permissions、xattr(xattr -l)、label 是否已存在、service 是否被 disable、真实 executable 是否存在。
不要立刻 sudo / 删 plist / 重建全部配置。(本次该报错最终是良性重试即可。)
5.4 投递「一次性延迟任务」:不要用 launchctl submit【2026-09-15 实测翻车】
场景:想做到"回答先送达、再重启 Host"。两种投递方式都真实踩过坑:
| 投递方式 | 现象 | 原因 |
|---|---|---|
setsid nohup … & |
静默失败,脚本根本没跑,只剩"已投递"的错觉 | macOS 没有 setsid(Linux 才有);重定向到 /dev/null 把报错吞了 |
launchctl submit -l <label> |
第一遍正常,紧接着自动跑第二遍 → 杀 Host → 起新的 → 再杀,反复弹标签页(§4 同机制) | submit 的作业退出后会被 launchd 自动重拉 |
正确做法:
- 用
launchctl submit之后必须在结束时launchctl remove <label>;排查时先确认没有残留作业。 - 更稳的路径:
kill "$(cat ~/Library/Logs/DeepSeek\ Harness/rc9-server.pid)"→ 等 3080 释放 →~/.local/bin/dsh-rc9-start --open(§6),且这个动作要脱离被杀的会话执行(杀宿主会连带杀掉该会话的 shell)。 - 无论哪种,只认三样判断"是否真重启":监听 PID、
rc9-server.pid、投递脚本自己的日志(§3)。
2026-09-15 实例:旧 PID 50412 → 新 PID 78177(10:46:44 起);第二遍循环在 30 秒延迟期内被
launchctl remove+pkill拦下,宿主未被二次杀。
6. 认证与健康检查【长期规则】
带认证的入口,正常流程是:
未认证 GET / → 401
带启动 token GET /?token=… → 设置 cookie → 跳转 /
带有效 cookie GET / → 200
所以:
curl -sI --noproxy '*' http://127.0.0.1:3080/ # 401 可能是健康的
401 ≠ 服务挂了。 本机装过代理,curl 不加 --noproxy '*' 可能得到误导性的 502。
完整健康验收(四件套,缺一不可):
lsof -nP -iTCP:3080 -sTCP:LISTEN -t # 1) 端口在听
cat ~/Library/Logs/DeepSeek\ Harness/rc9-server.pid # 2) PID 与之一致
grep -o 'http://127.0.0.1:3080/?token=[A-Za-z0-9_-]*' \
~/Library/Logs/DeepSeek\ Harness/rc9-server.log | tail -1 # 3) 拿新 token
# 4) 打开页面确认可用(或 ~/.local/bin/dsh-rc9-start --open)
token 每次启动都不同,重启后必须用新链接(App 会自动从日志里取最新一条)。
7. credentials 修复规则【长期规则】
本次踩过:version must be a string / refs must be a string。
当前(0.1.5-rc.2).credentials.yaml 顶层形态:
version: 1 # 数字,不是字符串 "1"
refs: # mapping,不是字符串
…: …
records:
…:
当时真正的修改只有两处:顶层 version: "1" → 1;records["client-connection/browser-session"].payload.version: "1" → 1。其余(refs 结构、records 结构、API Key、secret)一律不动。
规则:
- 先备份原文件;
- 先确认当前真正运行的 CLI 源码(不是记忆里的版本);
- 读完整 parser,再读具体消费者的 schema;
- 不按第一条报错逐字段猜改;
- 不打印完整 API Key / cookie / token;
- 不把
refs/records整体转成字符串; - 改完做完整结构比对,确认只有必要字段变化;
- parser 通过后再启动服务。
8. 插件:兼容审计与恢复优先级【长期规则】
8.1 判定方法(0.1.5 的坑最多)
- 0.1.5 删除了三个前端模块,引用它们的插件必崩:
@deepseek-ai/dsh-client-runtime、@deepseek-ai/dsh-client-ui-slots、@deepseek-ai/dsh-client-ui-primitives。 - 同族坑:
@deepseek-ai/dsh-settings不再导出installSettingsSection(本次事故根因之一)。 - "发布时间新" ≠ 兼容:实测有"刚发布"的插件照样 inject 已删模块。
- 判据顺序:① 包元数据
dsh.compatibility.dshReleases兼容矩阵 → ②dsh.engines.dsh >= 0.1.5-rc.1且 client 无 inject 声明 → ③--dump-config+ 真启动看日志。 - 权威可用清单:
~/.dsh-rc9-clean/profiles/node_modules/@deepseek-ai/。 - warning ≠ fatal:例如
session/list: no active Remote method exports this endpoint只是降级发现;先证明因果,再考虑禁用。 - **
npm/pnpm 能装 ≠ 兼容**;plugin add退出码 1 也可能是**既有插件**(free-vision / sharp)引发的ERR_PNPM_IGNORED_BUILDS,不一定是新插件失败——先看dependencies/bundles/dump-config`。
8.2 恢复优先级
P0 核心数据 credentials / sessions / workspace
P1 能力 memory / design-skills / vision
P2 工具 market / cost-meter
P3 MCP Playwright / Figma / 其它
P4 UI skins / task board / panel
P5 高风险 老旧主题 / aqua / 未更新插件
不要拿 rc8 的插件清单当 rc9 的必恢复清单。
8.3 老环境 file: 依赖必须 vendor 自包含
历史上的坑:package.json 仍写 file:/Users/…/.dsh/plugins-source/…,一旦 pnpm install 就会重新依赖待删的旧 ~/.dsh。
正确做法:把运行实体放到 NEW_DSH_HOME/vendor/,让 package.json/lockfile 指向新位置。【已验证】rc9 现在已指向自己的 vendor。
9. MCP【长期规则】
- 逐个恢复,必须做真实调用,不能只看进程存在;
- Playwright:
browser_navigate打开https://example.com读到Example Domain= 通过; - Figma:必须同时看
figma_status的pluginConnected/sessions。 【已验证】本机现状:pluginConnected=false、sessions=[]、bridge 端口在跑 → 即 MCP server 正常,但 Figma 桌面端 Bridge 未连接;要在 Figma Desktop → Plugins → Development → Figma UI MCP Bridge → Run。这种情况不能写成"Figma 全部通过"。 - Open Design / 其它第三方 MCP:动态端口、token 来源、IPC、workspace 注入、cwd、生命周期都未证明前,保持暂停迁移(旧
OD_DAEMON_URL=http://127.0.0.1:56060已不可靠)。
10. 视觉能力:原生 Vision 与 free-vision 必须区分【已验证】
| 说明 | |
|---|---|
| 当前生效 | 原生 deepseek-v4-flash-vision-exp(settings.yaml 里 inputModalities: [text, image]) |
| free-vision | 已 disabled(profiles/web/cordis.patch.yml 里 - id: free-vision / disabled: true),不要因为 rc8 经验擅自恢复 |
| 实测 | 拖入图片识图成功(红圆 / 蓝方 / 绿三角) |
排查"能拖入图片但提示模型不支持"要分层:附件已进输入框 ✅ → 发送前 capability guard ❌。要查:当前会话模型 capability、附件路由、原生 vision、free-vision、第三方 provider。不要第一反应重装 free-vision。
10.1 分辨率常识【已验证】
| RC8(0.1.0-rc.8) | RC9(0.1.5-rc.2) | |
|---|---|---|
| 单边硬上限 | 2000px(超出报错) | 8192px |
| 总像素 | 40M | 64M |
| 单图 / 单条消息 | — | 20MB / 20 张 / 200MB |
| 送给模型 | 原图 base64 | 先按面积预算压缩:默认 640,000 像素(imagePixelBudget,可设数字或 "low"=512×512),单张 ≤1MB |
证据:本机 attachments/v1/request-images/ 里那张请求图是 1170×546 = 638,820 px,正好卡在 64 万预算之下。
想更清晰:调 settings.yaml → llm-deepseek.models[].imagePixelBudget。
11. 历史会话与工作区:数据完整性三层模型【已验证】
"UI 看不到" ≠ "数据丢了"。 必须分三层查:
第 1 层:真实 session 文件(磁盘) ← 唯一的事实来源
第 2 层:workspace.json 的归属记录 ← 只是索引
第 3 层:UI 的显示(折叠/排序/过滤/草稿) ← 只是表现
11.1 session 文件是 Zstandard 多帧,不要只解第一帧
rc9 的 session.v3.jsonl.zstd 可以包含多个独立 Zstd frame。只解第一帧只会看到 header,从而误判"聊天内容丢了"。正确做法:扫描完整 frame 边界 → 逐帧解压 → 拼接 JSONL → 分析事件(title / user / assistant / system event / runtime append / session-end-seed)。
11.2 文件 hash 变了 ≠ 历史被覆盖
正常运行会追加 session/end-seed、runtime event、新消息,导致整文件 hash 改变。"发生追加"与"原历史被覆盖"是两件事(可用 frame 边界分析 + 原始前缀字节 hash 比对确认原始数据仍作为完整前缀存在)。
11.3 工作区↔会话的归属规则(最容易误判的一条)
DSH 判定会话属于哪个工作区的规则是:把会话 header 的 cwd 与工作区记录的 path 都做 fs.realpath 规范化,再字符串相等才归属(dsh-workspace/lib/index.js:117 + realpathNormalize)。
三条推论【已验证】:
- 目录一旦被删除,该目录下的会话会全部掉进侧边栏「未分组」——即使
workspace.json的sessionIds还记着它们。本次实例:…/deepseek harness/卓望(4 会话)与…/deepseek harness/求职(4 会话)删除后全部失联(当时「未分组」里有 29 个会话)。 - 只改
workspace.json的 path 没用:会话 cwd 是历史事实,改记录改不了会话;必须让旧 cwd 那个路径能被realpath解析。 - 归属索引在 Host 启动时建立(
replaceHeaderIndex+bootstrap)→ 改完必须重启 Host,刷新浏览器页面无效(已实测)。
本次采用的正确修复(两步都要 + 重启):
# ① 工作区记录指向知识库真实目录
# ② 在旧位置建符号链接指向真实目录(不复制数据,读写同一份)
ln -s "~/Documents/我的知识库/卓望工作相关/卓望" \
"~/Documents/deepseek harness/卓望"
ln -s "~/Documents/我的知识库/求职相关/求职" \
"~/Documents/deepseek harness/求职"
# ③ 重启 Host
~/.local/bin/dsh-rc9-start --open
【已验证】结果:侧边栏「卓望」「求职」各恢复 4 个会话,内容读写落在知识库那一份。
11.4 反例记录(曾经的错误猜测)
"卓望是空的,是因为建知识库时把聊天搬走了"——证据不支持这个结论。当时的真相是:目录被删 → 归属索引失配 → 会话落到「未分组」;session 文件本身完好(session/list 能返回全部四条,rc8 与 rc9 成员一致)。
12. 配置与存储语义【已验证·长期规则】
12.1 workspace.json 是「单文件 unit」,改它必须停 Host
~/.dsh-rc9-clean/storages/workspace.json:Host 启动时把内容读进内存,此后每次工作区变更都用内存快照整体重写该文件,没有文件监视器。所以:
- 运行时手改 → ① 不重启不生效;② 可能被下一次写入覆盖。
- 正确姿势:停 Host → 改文件 → 重启(已封装为
~/Documents/deepseek harness/dsh-rc9-repoint-workspaces.sh,幂等)。
另:DSH 的 workspace 只支持 create / rename / delete,path 创建后不可改(域层只有 setTitle)。要"重指路径"只能停机手改文件,或删掉旧记录重新添加。
12.2 记忆文件 DD.md 的迁移陷阱
迁移时点之后写入的条目只会在旧家目录里。本次:rc9 目录 17:41 复制,而新条目 18:36 才写进 rc8 → rc9 "失忆"两条。
规则:迁移完成后必须 diff ~/.dsh-旧/DD.md ~/.dsh-新/DD.md 并在新家目录里补齐。
12.3 附件存储
~/.dsh-rc9-clean/attachments/v1/{objects,request-images,files,file-objects}/;对话里的图片/文件本体在这里,删掉原始临时文件不影响对话。
12.4 全局记忆注入:顺序 + maxChars 上限(重启修不好的一类 bug)【已验证·2026-09-15】
dsh-memory 插件把 <DSH_HOME>/DD.md 与 <DSH_HOME>/memory/*.md 拼成一段「全局记忆」,注入每个会话的 system prompt。实现:~/.dsh-rc9-clean/vendor/dsh-memory/src/index.js(与 profiles/web/node_modules/dsh-memory/ 是硬链接)。
- 上限:
config.maxChars(默认 12000 字符)会截断拼接结果——超出就只留前 N 字符 + 一行「[全局记忆已截断…]」。DD.md 只增不减,实测 16979 +memory/知识库规则.md396 = 17393 > 12000 → 规则文件被整段截掉,等于没写。 - 反直觉点:截断发生在每次拼 prompt 时(注入文本是个每轮求值的函数),所以单纯重启 Host 不会让被截掉的文件出现;反过来,改
memory/里文件的内容连重启都不需要(改maxChars或插件代码才需要重启)。 - 修法(两条都做,互为保险):
- 把
memory/*.md的循环移到 DD.md 之前 → 规则文件永远落在截断线内,DD.md 再涨也不怕; - 给插件行加
config.maxChars: 24000(在vendor/dsh-memory/cordis.patch.yml的- insert:行内加config:)→ 现有 17393 字符全量注入。
- 把
- 改完必须:
cp同步 vendor 与 profile 两份(edit/write工具是替换式写入、会换 inode 从而断开硬链接)→ 校验两份md5一致 +node --check→ 重启 Host → 在新会话里确认能看到--- 知识库规则.md ---段。 - 代价:每请求注入从 12000 升到约 17400 字符(约 +3~4K tokens)。嫌重就把 DD.md 里的老条目归档进
memory/。 - 备份:
~/.dsh-rc9-clean/backups/dsh-memory-20260915/。
13. 升级 SOP【长期规则·最高价值章节】
13.1 标准流程
生产基线报告 → 完整备份 → 新版本装到独立目录 → 新建 NEW_DSH_HOME(复制而非移动)
→ 用新端口纯净启动(前台、--no-open、不用 launchd 托管)
→ 核心数据迁移 → 插件逐个兼容审计 → MCP 逐个恢复 → 独立验证
→ 正式切换(新 plist:RunAtLoad=false / KeepAlive=false / serve 脚本含 --no-open)
→ 生产回归验收 → 观察数日 → 旧环境 Guard → 清理旧版本
命名约定:~/.dsh-rc8-clean → ~/.dsh-rc9-clean → ~/.dsh-rc10-clean;永远不要反复覆盖同一个 ~/.dsh。
13.2 升级前必做
- 备份:
DD.md、settings.yaml、.credentials.yaml、profiles/web/{package.json,cordis.patch.yml}、storages/、sessions/、当前 plist; - 基线记录:真实 CLI 路径、版本、DSH_HOME、Node、launchd labels、PID、端口、bundles、plugins、MCP、session 数、workspace 数、vendor、patch、环境变量 → 存成「升级前生产基线报告」;
- 读本文件 §4、§8、§13.3;
- 纯净环境先证新 CLI 自己能起来:纯净环境都起不来 → 先解决新版本本身,禁止迁移旧数据。
13.3 红线(绝对不要做)
| 红线 | 后果 |
|---|---|
npm i -g 覆盖全局 CLI |
"新二进制 + 旧数据",旧实例下次重启即崩 |
| 原地升级正在使用的 DSH_HOME | 数据被新版写过,回退不再干净 |
整包复制旧 profiles/、node_modules、旧 cordis.patch、旧 bundle tree |
插件 API 已变,必然崩 |
用 launchd KeepAlive=true 托管未验证的新版本 |
崩溃→重启→崩溃;若缺 --no-open 还会无限弹标签页 |
生产启动用裸 dsh web |
可能跑在 ~/.dsh(空环境,看起来"历史全没了"),且每次启动弹标签页 |
| 一口气恢复全部插件 | 分不清是谁把树搞崩的 |
| 看到 warning 就卸插件 | 把降级当致命 |
盲目 pnpm install / approve build scripts |
ERR_PNPM_IGNORED_BUILDS、旧 file: 复活 |
| 运行未知 self-repair | 不可预测地改基础设施 |
重新执行旧 switch-to-rc9.sh |
内含 pkill -f dsh-versions/0.1.5-rc.2(§4 真凶之一) |
使用宽泛 pkill |
误杀正在运行的生产 |
只停 server job,不查其它 launchd label |
漏掉 switch/watcher |
| 未经 Guard 删除旧环境 | 无法回退 |
| 把 API Key / cookie / token 打进日志或文档 | 泄密 |
为了 UI/索引异常直接改或复制 sessions/ |
破坏唯一事实来源 |
用 launchctl submit 投递一次性任务后不 remove |
作业被自动重拉 → 反复杀/启 Host、反复弹标签页(§5.4) |
在 macOS 上用 setsid 投递后台任务 |
该命令不存在,静默失败;任务根本没跑却以为已投递(§5.4) |
改完 memory/*.md 或 maxChars 后「重启一下」就宣称已生效 |
截断发生在每轮拼 prompt,上限不够时重启也没用(§12.4) |
13.4 迁移顺序
1. credentials → 2. storages → 3. sessions → 4. settings → 5. workspace/index
不要整包复制 profiles/、node_modules/、plugins-source/。
13.5 生产回归验收清单
Launch/进程、正确 PID、正确 DSH_HOME、端口、认证、主页、历史工作区、历史会话正文、新建会话、真实对话、原生 Vision、memory、skills、market、cost-meter、skins、Task Board、Playwright、Figma、其它关键 MCP。 任何一项没验证 → 标"未验证",不要写"通过"。
14. 回退到 RC8【已验证】
14.1 一行回退
~/.local/bin/dsh-rc8-start --open
自动流程:停掉 3080 上的 RC9 实例(只杀"记录在案且命令行匹配 dsh"的进程)→ 用 RC8 的 home + CLI 在 3080 起一个 --no-open 实例 → 校验认证 200 → 打开新页面。
回 RC9:
kill "$(cat ~/Library/Logs/DeepSeek\ Harness/rc8-server.pid)"
~/.local/bin/dsh-rc9-start --open
14.2 手动回退(脚本坏了也能做)
kill "$(cat ~/Library/Logs/DeepSeek\ Harness/rc9-server.pid)" ; sleep 2
ls -d ~/.local/lib/node_modules/@deepseek-ai/dsh # rc8 全局 CLI
ls -d ~/.dsh-rc8-clean # rc8 的 DSH_HOME
DSH_HOME="$HOME/.dsh-rc8-clean" \
DSH_FREE_VISION_CONFIG_PATH="$HOME/.dsh-rc8-clean/free-vision.json" \
"$HOME/.hermes/node/bin/node" \
"$HOME/.local/lib/node_modules/@deepseek-ai/dsh/lib/bin.js" web --port 3080 --no-open
14.3 回退时不要做
- ❌ 不要直接恢复旧 plist
ai.deepseek.harness.server.plist.before-0.1.5-rc.2:它带KeepAlive=true且缺--no-open,会把 §4 的事故请回来; - ❌ 不要重跑
恢复-全局dsh到rc8.sh.BROKEN.bak(残留文本,会刷报错;正确做法见上); - ❌ 不要把新 CLI 覆盖安装到全局目录。
15. 旧环境删除 Guard 与退役计划【长期规则】
15.1 删除前必须全部确认
1. 当前生产 DSH_HOME 指向新环境
2. 当前 PID 没有旧环境 open files
3. package.json 无旧 file:
4. lockfile 无旧路径
5. node_modules 无旧 hardlink
6. symlink 无旧路径
7. cordis 配置无旧路径
8. MCP 无旧路径
9. vendor 已自包含
10. 新环境稳定运行(观察数日)
15.2 本机 RC8 资源与时间表【历史快照】
四份合计约 1.0 GB:
| 路径 | 体积 | 定位 |
|---|---|---|
~/.dsh-rc8-clean/ |
229M(46 会话) | RC8 数据家目录,回退必需 |
~/.dsh-before-0.1.5-rc.2-20260911-173658/ |
509M | 升级前总备份(含 rc8 home 副本、rc8 CLI、旧 plist、35 个归档 plist) |
~/.local/lib/node_modules/@deepseek-ai/dsh |
279M | RC8 全局 CLI 0.1.0-rc.8,回退必需 |
~/.dsh(更早遗留) |
148K | 永久保留,别动 |
| 时间 | 动作 |
|---|---|
| 09-12 → 09-19 | 全留 |
| 2026-09-19(机主要求的提醒日) | 复核 rc9 稳定后,删冗余副本 ~/.dsh-before-…/dsh-rc8-clean/(与 ~/.dsh-rc8-clean 重复) |
| 2026-10 之后 | 确定不再回退时:先冷备移动硬盘,再删 ~/.dsh-rc8-clean 与全局 rc8 CLI |
| 任何时候 | 删除前先确认 dsh-rc9-start --open 能正常起来 |
DSH 没有跨会话定时推送能力,本日期同时写在全局记忆
DD.md里,到期需机主或下一次会话的 AI 主动提起。
16. 其它长期规则与历史教训
- Task Board 单实例锁:同一数据目录不能同时跑两个实例(
task-board ledger is already owned by process …)。测试要用独立 DSH_HOME,或先停生产。 session/listwarning 不致命(§8.1 第 6 条)。- 不要把
~/.dsh当成生产:裸跑dsh web可能回落到它,表现为"历史会话全没了"。生产入口只用 §2.2 的脚本。 - 打开页面与服务生命周期必须分离:后台永远
--no-open;开页面只由用户的显式动作触发(--open或桌面 App)。 - LaunchAgent / KeepAlive 属于生产基础设施,不应让插件或自修复脚本随意修改。
- 三层区分:UI 展示 / workspace 归属 / 真实 session 文件(§11)。
- 不要用错误版本的源码解释当前版本的报错(credentials 误判的来源,§7)。
17. 症状 → 病因 速查表
| 症状 | 优先怀疑 | 处置 |
|---|---|---|
| Chrome 无限弹新标签页 | switch job 循环 pkill / 插件树崩溃 / KeepAlive / 缺 --no-open |
§4,四处一起查 |
| 启动即退出,exit 0 | 外部 SIGTERM(switch/pkill/watchdog)或正常 shutdown 路径 | 查 launchd labels + PID/PPID + 信号;§5 |
| 启动即崩,堆栈里有 import 报错 | 插件引用 0.1.5 已删导出 | §8.1 |
| 页面白屏 | 前端插件 inject 已删模块(ui-slots 等) | §8.1 |
| 侧边栏工作区是空的 | 目录被删 → realpath 失败 → 会话进「未分组」 | §11.3 |
| 历史会话"消失" | 多半是 UI/归属层,不是数据层 | §11.1–11.4 |
| 打开页面要 token / 401 | 正常 | §6 取新 token |
| credentials 报 schema 错 | 用错版本源码猜改 | §7 |
| 装插件后起不来 | 兼容性 / ERR_PNPM_IGNORED_BUILDS |
§8.1 第 7 条 |
| 识图说"模型不支持" | capability guard / provider 混淆 | §10 |
| Figma 工具失败 | 桌面端 Bridge 未连接 | §9 |
| bootstrap 报 5: I/O error | plist 语法/权限/xattr/已存在 | §5.3 |
| 图标变白卷纸 | 图标/codesign/缓存 | §2.3 |
写进 memory/*.md 的规则/记忆不生效 |
注入被 maxChars 截断(DD.md 太长) |
§12.4;先看上下文末尾有无「[全局记忆已截断]」 |
| 说好的「延迟重启」没发生 | macOS 无 setsid,投递脚本没跑起来 |
§5.4;只认 PID/pid 文件/脚本日志三样 |
| 重启被反复触发、又弹标签页 | launchctl submit 作业退出后被自动重拉 |
§5.4;launchctl remove <label> 立即止住 |
18. 交接与接管提示词
18.1 给 Codex / 其它能直接操作本机的 AI
请先完整阅读(按顺序):
1. DeepSeek Harness 最新自维护文档;
2. 《DeepSeek Harness 运行维护与故障修复手册(合并定稿版)》
~/Documents/我的知识库/个人学习ai 相关/DSH-运维与故障修复手册-合并版.md
(工作区同一份:~/Documents/deepseek harness/DSH-运维与故障修复手册-合并版.md)
要求:
- 不根据旧 PID / 旧版本 / 旧插件状态直接操作;先重新核验 command -v dsh、真实 CLI 路径、
dsh --version、DSH_HOME、3080 PID、所有 Harness 相关 launchd jobs;
- 改任何文件前先做时间戳备份;
- 不输出 API Key / cookie / token / secret;
- 不删改 sessions、workspace、storages;
- 不运行旧 switch 脚本;不用宽泛 pkill;不盲目 pnpm install;不运行 self-repair;
- 不因为 warning 就卸插件;
- 先定位根因,再做最小修复。
按手册 §3 的顺序排查。最终必须输出:根因 / 改动文件 / 备份路径 / 实际修复 /
稳定性验证 / 历史数据验证 / 核心功能回归 / 插件与 MCP 状态 / 剩余风险 / 后续建议。
未验证的项必须标"未验证"。
18.2 给 ChatGPT(当用户只做"复核者"时)
优先检查报告是否闭环:有没有把 warning 当 fatal、有没有遗漏真实执行路径、有没有误碰 sessions、有没有查外部 launchd / switch job、是否正确理解 401、是否区分原生 Vision 与 free-vision、"插件 enabled"是否真的做过真实调用。 用户抄命令困难时 → 优先把任务交给能直接操作本机的 AI。
18.3 给 DSH 自己
启动即读全局记忆 DD.md;本机相关条目里的硬规则优先于猜测。涉及工作区归属、附件/识图、升级,先 grep 本文件。
19. 一句话总原则
不要"重装碰运气"。先确认真正运行的是哪套版本、哪个 DSH_HOME、哪些 launchd job、哪个 PID,再做最小修复。升级永远隔离迁移,修复永远先备份;UI 看不到不等于数据丢失,exit 0 不等于没有外部终止,401 不等于服务失败。
20. 文档维护规则
出现以下情况必须更新本文件:大版本升级 / 重大修复 / 启动机制调整 / credentials schema 改动 / 插件大规模变化 / MCP 变化 / session 存储变化 / 桌面 App 重做。
更新时:保留长期规则 → 刷新"环境快照" → 新增事故案例 → 标记已废弃经验 → 不要删除仍有参考价值的历史教训。建议用 Git 管理版本。
附录 A:关键文件与证据索引【已验证】
| 路径 | 作用 / 证明什么 |
|---|---|
~/.local/bin/dsh |
CLI 包装器(绑定 DSH_HOME,防回落旧 ~/.dsh) |
~/.local/bin/dsh-rc9-serve / dsh-rc9-start |
生产启动与按需拉起(含 switch job 守卫) |
~/.local/bin/dsh-rc8-serve / dsh-rc8-start |
RC8 回退 |
~/Library/LaunchAgents/ai.deepseek.harness.server.plist |
现役 LaunchAgent(不自动启动、不自动重启) |
~/Library/Logs/DeepSeek Harness/rc9-server.log |
当前服务日志(排错第一现场,含 token 链接) |
~/Library/Logs/DeepSeek Harness/rc9-server.pid |
当前 PID |
~/Library/Logs/DeepSeek Harness/server.log |
历史日志:28 次自动开浏览器的直接证据 |
~/.dsh-rc9-clean/switch-to-rc9.sh |
含 pkill -f dsh-versions/0.1.5-rc.2(事故真凶之一) |
~/.dsh-rc9-clean/.full-start.log |
插件树崩溃堆栈(installSettingsSection) |
~/.dsh-rc9-clean/settings.yaml |
模型 / imagePixelBudget / 皮肤 |
~/.dsh-rc9-clean/profiles/web/package.json |
dsh.profile.bundles 与插件版本 |
~/.dsh-rc9-clean/profiles/web/cordis.patch.yml |
free-vision 禁用、MCP 插入 |
~/.dsh-rc9-clean/storages/workspace.json |
侧边栏工作区记录(改动要停 Host) |
~/.dsh-rc9-clean/DD.md |
全局记忆(跨会话硬规则) |
~/.dsh-rc9-clean/memory/*.md |
全局记忆的分文件部分;先于 DD.md 注入,故不会被截断(§12.4) |
~/.dsh-rc9-clean/vendor/dsh-memory/src/index.js |
记忆注入实现:注入顺序 + maxChars 截断(§12.4) |
~/.dsh-rc9-clean/backups/dsh-memory-20260915/ |
记忆注入改动前的两份原件备份(可整体回滚) |
~/.dsh-rc9-clean/vendor/ |
自包含的 file: 插件实体 |
~/.dsh-before-0.1.5-rc.2-20260911-173658/ |
升级前总备份(rc8 home 副本 + rc8 CLI + 旧 plist + 归档 plist + 回退说明) |
~/Documents/deepseek harness/dsh-rc9-repoint-workspaces.sh |
工作区重指(停→改→重启,幂等) |
~/Applications/DeepSeek Harness.app |
原生 WKWebView 壳(自动取最新 token) |
附录 B:改动台账
2026-09-12(合并定稿轮)
| 轮次 | 改动 |
|---|---|
| 1 | 补齐 rc9 缺失的两条全局记忆(DD.md 13425 → 15841 字节) |
| 1 | workspace.json 重指(卓望/求职 → 知识库真实目录)+ 备份 |
| 1 | 归档 35 个备份 plist 到 …/launchagents-stale-plists-20260912/ |
| 1 | 新增 dsh-rc9-repoint-workspaces.sh;新增 dsh-rc8-serve / dsh-rc8-start;隔离坏脚本为 .BROKEN.bak |
| 2 | dsh-rc9-serve 的 PATH 前置 ~/.hermes/node/bin(消除 env: node: No such file) |
| 2 | 记忆新增:RC9 事故根因 + 手册指引 + 09-19 退役提醒 |
| 3 | 建立符号链接让旧 cwd 可 realpath 解析 → 侧边栏 8 个会话回归【已验证】 |
| 3 | 记忆新增:工作区↔会话 realpath 归属规则 |
| 4 | 清理 /private/tmp 下 17 项抢救期遗留物 |
| 5 | 本文:两份手册合并定稿;旧手册标注"已被取代,保留作事故取证" |
2026-09-15(记忆注入修复 + 重启投递翻车)
| 改动 | 说明 |
|---|---|
| 记忆注入顺序调整 | memory/*.md 提到 DD.md 之前(§12.4) |
maxChars: 12000 → 24000 |
让 17393 字符全量注入,规则文件不再被截掉(§12.4) |
定位「memory/知识库规则.md 进不了上下文」 |
结论:截断发生在每轮拼 prompt,单独重启无效 |
| 新增 §3 校验规则、§5.4、§12.4、§13.3 三条红线、§17 三行症状 | 全部来自本次两次真实翻车 |
| Host 重启 | 旧 PID 50412 → 新 PID 78177(10:46:44 起);第二遍循环在延迟期内被拦下 |
本手册由 DSH 于 2026-09-12 在机器实测、源码取证与三方记录交叉核对基础上整理。所有"已验证"结论都可按附录 A 的证据文件复核。若与本机现状冲突,以本机现状为准。(2026-09-15 补充:§3 重启校验、§5.4 一次性任务投递、§12.4 全局记忆注入;附录 A/B 已同步。)