Repository navigation
[Bug] DSH 桌面版:profile 被认成 web,profile 配置完全不被快照;undo_doctor 启动预检误报核心 bundle 不可解析 #43
Description
[Bug] DSH 桌面版:profile 被认成 web,profile 配置完全不被快照;undo_doctor 启动预检误报核心 bundle 不可解析
环境
| 项 | 值 |
|---|---|
| DSH | DeepSeek Harness 桌面版 0.1.7-rc.2(profile 目录 ~/.dsh/profiles/desktop) |
| 插件 | dsh-undo-savepoint@0.4.9(npm latest) |
| 系统 | Windows 11 x64 |
| Node | 宿主内置 24.21.0 |
问题 1(严重):桌面版下 profile 被认成 web,profile 配置完全不被快照
现象
装好之后 undo_list 显示:
Profile: web
而实际 profile 是 desktop。后果是快照里只有 home 级的文件,profile 里的配置一个都没有。实测快照目录内容:
undo-snapshots\auto\20260927-175456-a5ba\home-.credentials.yaml ← 只有这一个
undo-snapshots\auto\20260927-175456-a5ba\manifest.json
cordis.patch.yml / package.json / cordis.yml / pnpm-workspace.yaml / pnpm-lock.yaml 全部缺失 —— 而 profile 配置恰恰是这个插件最该保护的东西。手工指定 profileName: desktop 后同一个基线快照立刻变成 6 个文件 / 50.3 KB,其中就有 profile-cordis.patch.yml。
根因
桌面版由 Electron 应用启动,启动参数里没有 --profile。宿主进程的完整命令行是:
"D:\dsh\dsh\DeepSeek Harness.exe" --expose-internals \
...\app.asar\dsh\node_modules\@deepseek-ai\dsh-desktop-host\lib\index.js \
...\app.asar\dsh \
C:\Users\<user>\.dsh\profiles\desktop \ ← profile 目录在这里,但只是位置参数
D:\dsh\dsh\resources\runtime\primary-runtime \
...
lib/index.js:235 是 config.profileName ?? detectProfileName(),而 detectProfileName() 只解析 --profile(桌面版没有),于是回退到 web;profileDir 随之变成 ~/.dsh/profiles/web(不存在),导致 profile 文件全部扫不到 —— 而且是静默失败,界面上看不出任何异常。
建议修法
桌面宿主会在进程环境里设置这两个变量(我在宿主进程的子 shell 里实测到):
DSH_PROFILE = desktop
DSH_PROFILE_DIR = C:\Users\<user>\.dsh\profiles\desktop
所以建议把优先级改成:
const profileName = config.profileName
?? process.env.DSH_PROFILE
?? detectProfileName();
// 并且优先直接采用 DSH_PROFILE_DIR
const profileDir = config.profileDir
?? process.env.DSH_PROFILE_DIR
?? join(DSH_HOME, 'profiles', profileName);另:settings.json 里的 profileName 对宿主插件无效 —— lib/index.js:235 只读 config.profileName,而其它设置都是 config.X ?? fileSettings.X。只有离线 PowerShell CLI 读 settings 里的 profileName。这个不一致也值得顺手统一。
问题 2:undo_doctor 的启动预检在桌面版误报,并给出会误伤的建议
现象
❌ bundle @deepseek-ai/dsh-base: cannot resolve @deepseek-ai/dsh-base, DSH aborts before loading any plugin
→ run dsh-undo.ps1 safe-mode -Label on, then restart DSH
❌ bundle @deepseek-ai/dsh-web-app: cannot resolve ...
❌ bundle @deepseek-ai/dsh-experimental-agent-team-profile: cannot resolve ...
❌ bundle @deepseek-ai/dsh-experimental-auto-review: cannot resolve ...
为什么是误报
桌面版的核心 bundle 不在 profile 的 node_modules 里,而是从应用载荷 app.asar/dsh/node_modules/ 解析。实测该 profile 的 node_modules/@deepseek-ai/ 下只有 cosmokit 和 schemastery 两个包 —— 找不到 dsh-base 是正常的,DSH 运行得好好的(当前会话就在里面跑)。
按提示去执行 safe-mode 会把用户所有插件全部禁用,属于误伤。
建议
预检在桌面版下要么跳过 bundle 解析检查,要么改用与 DSH 启动器相同的解析根(可用 DSH_ROOT / DSH_PROFILE_DIR 推导)。至少要能区分"确实不可解析"和"这是桌面版"。
问题 3(不确定责任方,仅供参考):写进 profile patch 的覆盖项会在约 2 秒后被删除
这一条我不确定是不是本插件造成的,但现象稳定复现,贴出来供你判断。
在 <profile>/cordis.patch.yml 末尾追加:
# some comment
- id: dsh-undo
name: dsh-undo-savepoint
config:
profileName: desktop结果是:插件确实读到了配置(undo_list 立刻显示 Profile: desktop,并随即产生 6 文件的基线快照),但大约 2 秒后,那 4 行条目被删掉了,而前面的注释行原样保留。连续两次,两次的现象完全一致。
快照时间戳为证:
| 时间 | 类型 | 文件数 | 说明 |
|---|---|---|---|
| 17:56:06 | baseline | 6 | 配置生效 |
| 17:56:08 | patch-change | 6 | 文件已被改写(截断状态) |
| 17:56:08 | baseline | 1 | 重新挂载,配置丢失 → 回到 web |
| 18:43:25 | baseline | 6 | 第二次写入,配置生效 |
| 18:43:27 | patch-change | 6 | 又被改写 |
| 18:43:27 | baseline | 1 | 再次丢失 |
我怀疑是"撤销不会撤销掉自己"那套"恢复后自动检查并重新写入挂载条"的逻辑在做归一化时丢掉了带 config 的覆盖项(也可能是 dsh-plugin-manager 的重写,所以我标为不确定)。
我目前的绕过方式:把 config.profileName 写进包自己的 bundle patch(node_modules/dsh-undo-savepoint/cordis.patch.yml),并用 pnpm patch 持久化。那份文件没有别的组件在动,配置能稳定存活。
复现
任何桌面版用户都能复现问题 1 和 2,不需要特殊配置:装完插件,undo_list 的 Profile: 一定是 web,快照里一定没有 profile 配置。
macOS 的 DeepSeek Harness.app 应该同理(它同样不带 --profile 启动)—— 我这边是 Windows,只验了 Windows。
我本地的补丁
如果短期内不打算修问题 1,我可以继续用 pnpm patch 自我维持;贴出来只是想说:这个默认行为在桌面版上是静默失效的,用户不会收到任何提示,很容易以为配置已经受保护了。
Activity
lire1131 commentedon Sep 29, 2026
Thanks for a remarkably thorough report — all three problems reproduce or trace to confirmed root causes on our side. Findings first, fix plan at the end.
Problem 1 (profile detected as
webon desktop) — confirmed, and it's a capability gap, not a regression.detectProfileName()(v0.3.3) only parses--profilefrom argv and falls back toweb. The desktop host never passes that flag: it launches viarunProfile({ profile: 'desktop', ... })and injects the profile through theprofileContextservice (name/dir/patchPath) before plugins mount. In-process plugins therefore see an Electron argv with no--profile, and the fallback fires silently. You're also right thatprofileNameinundo/settings.jsonhas no effect for the host-mounted plugin: our config resolution chain for that key only consults the pluginconfigobject — every other setting falls back to the settings file;profileNamedoesn't. Two genuine bugs; the fix plan below covers both.Problem 2 (doctor false-positive on core bundles) — confirmed, with a caveat that matters more than the false positive.
bundleCheckresolves bundles from exactly two anchors (~/.dshand the profile directory). Desktop's core bundles live insideapp.asar, outside both, so every one of them reports "cannot resolve". The dangerous part:safe-modeconsumes the same check. If anyone follows the doctor's advice and runs safe-mode on a desktop profile, it will prune those bundles as "unrecoverable" — if you're on the desktop build, please don't run safe-mode until the fix ships.Problem 3 (mount entry with
configdeleted ~2s after save) — confirmed, reproduced, and it's ours, not dsh-plugin-manager's. The culprit is our own mount deduplication (the startup self-heal that keeps exactly one canonical mount): when the profile'spackage.jsonlistsdsh-undo-savepointindsh.profile.bundles, the bundle mount ranks as canonical and any patch-file entry for the same plugin is treated as a duplicate and removed. Your entry carried aconfigblock — that's configuration injection, not a redundant mount — but the dedup logic doesn't distinguish. We reproduced it end-to-end: the entry is stripped, the comment line survives, and (a detail worse than what you reported) the deletion leaves a dangling- insert:behind because the block splitter misreads indented list items as new blocks. The 2-second delay you observed is the watcher debounce picking up the rewrite, followed by the re-mount landing back onweb— exactly your timeline table. The.dsh-undo-baksibling should hold your pre-deletion state if you want the exact block back.Your
pnpm patchworkaround is sound for now — that file is outside the dedup scan surface, so nothing will touch it.Fix plan (all three land in 0.5.0, currently in canary staging):
configblock are exempt from dedup removal; the block splitter is also being fixed so partial deletions can't leave danglinginsert:keys.--profileargv →profileContextservice (the desktop host's official channel) →DSH_PROFILEenv →web; andprofileNamegains the settings-file tier like every other option.profileContext.startedBundles) are reported as host-managed instead of "cannot resolve", and safe-mode refuses to touch desktop profiles rather than pruning asar-hosted bundles.One note on
DSH_PROFILE/DSH_PROFILE_DIR: we didn't find either being set by the host in 0.1.7-rc.2's desktop-host source; the channel we verified isprofileContext. If you observed those variables in your process, we'd genuinely like to know — it may be a newer build than the tag we inspected.lire1131 commentedon Sep 30, 2026
Scheduling update on my earlier reply: all three land in canary.4, together with the desktop adaptation itself (internal ticket W40), rather than in the canary.3 batch I mentioned. The fix plan I described stands unchanged: mount entries carrying a
configblock are exempt from dedup removal and the block splitter stops leaving danglinginsert:keys; the profile detection chain becomes argv--profile, then the host's profile channel, thenDSH_PROFILE, thenweb, withprofileNamegaining the settings-file tier; and the doctor learns the desktop shape so host-started bundles are reported as host-managed and safe mode refuses to touch desktop profiles.Until then the warning from my earlier reply still holds: on the desktop build, do not run safe mode.
One open question from that reply, in case you can check it: we did not find
DSH_PROFILEorDSH_PROFILE_DIRbeing set by the 0.1.7-rc.2 desktop host, and the channel we verified is the host's profile context. If you saw those variables in your process, tell us which build, since it may be newer than the tag we inspected.Your
pnpm patchworkaround holds for now. Note that plugin upgrades overwritenode_modules, so keep the persistence step.lire1131 commentedon Sep 30, 2026
Correction to my previous comment: the adaptation work is scoped to DSH 0.2.0, not 0.1.7. The 0.1.7 wording was a typo. The fix plan and the scheduling are otherwise unchanged.
lire1131 commentedon Oct 3, 2026
All three problems are fixed in v0.4.10, now on npm latest. Thanks for the exceptionally detailed report, the manifest diff between auto-detected and manual profileName snapshots is what pinned problem 1.
On why this shipped ahead of the canary.4 schedule mentioned above. The fixes were originally planned for 0.5.0, but 0.4.9 on npm latest also carried #42 (write/edit unusable) and #39 (a security leak), so we cut an emergency 0.4.x release with the verified fixes instead of letting fresh installs hit known bugs while 0.5.0 finishes its desktop install chain and real-machine validation.
What 0.4.10 ships, problem by problem.
Problem 1 (profile detected as web). detectProfileName now runs a four-layer chain, argv --profile first, then the host profileContext (the desktop host's actual source of truth), then DSH_PROFILE/DSH_PROFILE_DIR shell env, then the web default. settings.json also gained a profileName key, explicit config wins over auto-detection. Desktop snapshots now capture the full profile config set, your manual profileName workaround is no longer needed.
Problem 2 (doctor false positives). bundleAnchors gained the installation anchor, matching the official order where the dsh installation resolves before the profile directory. Host-started bundles are reported as host-managed at ok level instead of cannot resolve. One deliberate behavior change, undo_safe_mode now refuses to enable for desktop profiles, both when a desktop host context is present and when targeting --profile desktop directly, pointing to DSH's own fatal-recovery dialog. Pruning desktop bundle sets is riskier than the mode is worth until the 0.5.0 install chain lands. Turning safe-mode off remains always allowed, snapshots and undo are unaffected.
Problem 3 (configured mount entries deleted). Entries carrying a user config block now win deduplication, the bundle face is withdrawn instead, and the block splitter no longer leaves dangling - insert: keys. Historical leftovers are swept on the next pass.
The suite adds 21 cases across these fixes, 15 for the detection chain and the #44 anchor matrix, 6 for the dedupe guard. Smoke total is 371 passed, 0 failed. Desktop real-machine validation and the install-chain polish remain on the 0.5.0 track, a confirmation from your side after updating would be welcome, this issue stays open until then.
lire1131 commentedon Oct 5, 2026
Status update on the three problems, closing the loop opened in my 2026-10-03 reply.
Verdict. All three are fixed, and the 0.5.0-canary.4 build now carries the same verified implementations. The stable channel got them first: v0.4.10, on npm latest since 2026-10-03, is where most of this landed for regular users.
Root causes, restated in one line each. Profile detection had no path to the host's profile channel, so the desktop build fell back to
web.bundleAnchors()walked only the home and profile directories, so host-started bundles under the install tree never resolved and safe mode, which consumes the same check, treated them as prunable. Mount deduplication ranked the bundle mount as canonical and removed the patch entry, without checking that the entry carried aconfigblock.What is fixed. Entries carrying a
configblock are exempt from dedup removal and the bundle face is withdrawn instead, and the block splitter no longer leaves danglinginsert:keys. Detection now walks explicit config, the settings file, the command line, the host profile channel, the environment and a default, in that order, and bothundo_listandundo_doctorreport which tier won.bundleAnchors()gained the installation anchor in the official order, host-started@deepseek-ai/dshbundles are reported as host-managed, andundo_safe_moderefuses to enable on a desktop profile before anything is written, whileoffstill works.Tests. The canary.4 batch brings the smoke gate to 509 passing, 0 failing, with dedicated cases for the dedupe exemption, the six-tier detection chain with source reporting, the anchor order, host-managed exemption, the non-desktop shape staying byte-identical, and the desktop refusal. The v0.4.10 build that introduced these fixes reported its own smaller total, and that remains accurate for that build.
Known boundaries. Desktop real-machine validation of the install chain is still in progress, so the desktop install path is not yet declared verified. On a desktop profile, do not run safe mode until that validation lands, and note that the plugin now refuses the operation rather than attempting a prune. The
pnpm patchworkaround is no longer needed: update past 0.4.10, and if you installed from master the dedupe exemption applies. One more boundary worth knowing: the official sanitize trace detection requires all three elements (a backup file exists, the current patch does not mention this plugin, and the manifest's bundles do not list it), so a partial sanitize where the bundles section was restored but the patch content was not is not detected yet, and that gap is tracked separately.A confirmation from your side after updating would close this out.