# DSH Desktop 0.2.1-rc.5 Vault compatibility This adapter is pinned to the four macOS Desktop client artifacts shipped with DSH 0.2.1-rc.5 (`/Applications/DeepSeek Harness.app`, Electron 44.7.0, Node 24.21.0). It never replays an older snapshot: `patch-client.mjs` reads the *installed* 0.2.1-rc.5 bundles, refuses any other input SHA-256, and re-applies the Vault seams in place. Everything else in those bundles stays exactly as 0.2.1-rc.5 shipped it, so the `uiConversation` service and the slot contracts that `ui-skill`, `ui-reference`, `ui-secret-mask` and `ui-goal` inject keep their new-version semantics. Pinned inputs (SHA-256 of `lib/client.js`): | package | sha256 | | --- | --- | | `@deepseek-ai/dsh-api-session-controller` | `82f2301c18f0e51340c1eedf8ecdfb939e873b3770a80632e438b86e82887d0e` | | `@deepseek-ai/dsh-client-ui-workspace` | `ea4e8374efef652aa917122be1422047ef012b68513421195dec31f79ee0543a` | | `@deepseek-ai/dsh-client-ui-conversation` | `606ae0ba66ab52f5dd3dda5fa6010a21704329e43e10c28098685e7048d4da7c` | | `@deepseek-ai/dsh-client-ui-layout` | `64366054aba2a9e4abfa0e064e20f5d752f94cfa831e20b0034c21a8031f9860` | `0.2.1-rc.3 → 0.2.1-rc.5` only moved `dsh-client-ui-conversation`; the other three bundles are byte-identical to rc.3 and every seam anchor is still in place, so not a single `replace`/`section` call changed. ## 一条命令升级(推荐) ```sh node compat/upgrade-dsh.mjs # 按已安装版本重建适配层并切换 profile node compat/upgrade-dsh.mjs --dry-run # 只看计划,不写文件 node compat/upgrade-dsh.mjs --restart # 完成后自动重启并核验崩溃日志 ``` 它把下面七步压成一条命令,并且**先验后写**:锚点体检不过就一个文件都不动。 1. 读已安装 `app.asar`,算四个 bundle 的 SHA-256; 2. 用**关掉 hash 门禁**的方式重放全部 seam 编辑(锚点断裂 → 退出码 `2`,什么都不写); 3. `cp -R` 上一个适配层目录为 `compat/dsh-v<新版本>`,只覆盖 `baseline`; 4. 在 hash 门禁**打开**的状态下重放补丁,确认写进去的基线与字节自洽; 5. 抽 fixture 并跑 `compat.test.mjs`(必须 4/4); 6. 用 fixture 重新生成 overlay —— 这一步同时把 overlay 的 `version` 与 `peerDependencies` 抬到新版本,**版本门禁才会过**; 7. 把 `cordis.patch.yml` 的四条 `insert` 指向新 overlay 目录(改前备份 `.bak-<时间戳>`)。 `--restart` 会在结尾 `pkill` + `open`,并对比重启前后 `~/Library/Logs/DeepSeek Harness/crash-*-web-boot.log` 的数量给出 ✅/❌。 ## 为什么不能复用旧版本的 overlay `0.2.1-rc.3` 起 DSH 有**插件 peer 版本门禁**:profile 行所属 package 的 `peerDependencies` 若精确锁在与当前 dsh 不同的版本上,该行会被**静默禁用** —— 不抛错、 不进崩溃日志,只在宿主 stdout 留一行: ``` dsh: disabling profile plugin row "vault-compat-session-controller": Plugin @deepseek-ai/dsh-api-session-controller@0.2.1-rc.3 is incompatible with dsh 0.2.1-rc.5 … Exact-version exemption: not active. ``` 后果是 `sessions` 服务无人提供,`uiSession` / `uiWorkspace` / `uiConversation` 依次排队,最终 `web boot: 33 entries did not activate`(全是 pending、没有 failed), 窗口空白。另三个包只 pin `@deepseek-ai/cordis`(`~4.0.5`,范围),所以只有 session-controller 一行被禁用,崩溃日志里完全看不到适配层的影子。 **不要用 `dsh plugin allow-version` 绕过**:那只是让旧宿主语义跑在新 Host 上。 正确做法是用已安装版本的 fixture 重新生成 overlay,让 `package.json` 的版本与 peers 自动对齐(`prepare-overlay.mjs` 会复制 fixture 的 `package.json`)。 ### 如何看到门禁决策 桌面崩溃日志只收渲染端 `error` 级输出,宿主行级禁用不在里面。把 profile 复制成 非保留名(`desktop-probe`,`node_modules` 软链到 `desktop/`)后用 CLI 启动即可: ```sh dsh --profile desktop-probe # 宿主诊断直接打到 stdout dsh --profile desktop-probe --dump-config | grep vault-compat ``` 零条 `disabling profile plugin row` + 零条 `did not activate` 才算过。这也是拿到 desktop profile `--dump-config` 的唯一办法(`desktop` 这个名字被 Electron 独占)。 ## What the adapter restores * `sessions.openingAccess.register` plus the abort-aware opening wait (`openingGates`), so a locked session is gated before history is fetched. * Sidebar workspace row `action` / `accessory` / `title` and session row `title` chain seats. * `conversation.session.guard` and `conversation.session.header.title`. * `shell.document.title`. ## Manual install / repair Stop Desktop before changing the profile or the overlay output. ```sh python3 compat/dsh-v0.2.1-rc.5/extract-fixture.py \ '/Applications/DeepSeek Harness.app/Contents/Resources/app.asar' \ .cache/dsh-v0.2.1-rc5-fixture DSH_CLIENT_FIXTURE="$PWD/.cache/dsh-v0.2.1-rc5-fixture" \ node --test compat/dsh-v0.2.1-rc.5/compat.test.mjs node compat/dsh-v0.2.1-rc.5/prepare-overlay.mjs \ "$PWD/.cache/dsh-v0.2.1-rc5-fixture" \ "$HOME/.dsh/plugin-packages/vault-desktop-021rc5" \ '/Applications/DeepSeek Harness.app/Contents/Resources/app.asar/dsh/node_modules' ``` Then in the Desktop profile: 1. add `dsh-vault-plugin` to `dsh.profile.bundles` in `~/.dsh/profiles/desktop/package.json`; 2. add the Vault `config` row; 3. disable `session-controller`, `ui-workspace`, `ui-conversation`, `ui-layout` and insert the four replacement rows pointing at the overlay `lib/index.js` files: ```yaml - id: session-controller disabled: true - id: ui-workspace disabled: true - id: ui-conversation disabled: true - id: ui-layout disabled: true - insert: - id: vault-compat-session-controller name: "/Users//.dsh/plugin-packages/vault-desktop-021rc5/@deepseek-ai/dsh-api-session-controller/lib/index.js" - id: vault-compat-ui-workspace name: "/Users//.dsh/plugin-packages/vault-desktop-021rc5/@deepseek-ai/dsh-client-ui-workspace/lib/index.js" - id: vault-compat-ui-conversation name: "/Users//.dsh/plugin-packages/vault-desktop-021rc5/@deepseek-ai/dsh-client-ui-conversation/lib/index.js" - id: vault-compat-ui-layout name: "/Users//.dsh/plugin-packages/vault-desktop-021rc5/@deepseek-ai/dsh-client-ui-layout/lib/index.js" ``` ## Rollback Stop Desktop, remove the four `disabled` rows, the `insert` block and the `dsh-vault` config row, drop `dsh-vault-plugin` from `bundles`, and restart. No Vault state (`~/.dsh/vault-lock`) is touched by installing or removing the adapter. ## Upgrading to a new DSH release ```sh node compat/probe-dsh.mjs # 先看差距:0 精确 / 1 换 hash 或重生成 / 2 锚点断 node compat/upgrade-dsh.mjs # 再让它自动重建(覆盖 L1 与 L1-O) ``` probe 查两道门禁:bundle 字节与 seam 锚点、以及 profile 里引用的 overlay 版本。 `L1-O` 专指「字节已匹配但 overlay 版本过期」——那种情况下只换 hash 一定起不来。 只有 `L2`(锚点断裂)需要人工介入:probe 与 upgrade 都会停在第一个断点并引用确切的 期望字符串,改一处、重跑一次即可(`patch-client.mjs` 按顺序校验)。 Keep the old `compat/dsh-v*` directories — they document previous seam shapes and cost nothing. Overlay directories must be version-named; the four `insert` paths are absolute and will silently rot otherwise. ## 已知判据 `POST /dsh-vault/api` 的 originless 响应码会随版本变化(rc.3 是 `403`,rc.5 是 `401`), **不能单独当作「路由已挂载」的证据**。可靠判据是:重启后无新增 `crash-*-web-boot.log`,且 CLI 复刻启动为 0 条 `disabling profile plugin row`、 0 条 `did not activate`。