Skip to content

fix(startup): make recovery independent of profile links - #533

Merged
yaojin3616 merged 4 commits into
mainfrom
fix/startup-recovery-to-main
Sep 22, 2026
Merged

yaojin3616 merged 4 commits into
mainfrom
fix/startup-recovery-to-main

Conversation

@yaojin3616

Copy link
Copy Markdown
Contributor

#504 的启动恢复链路直接带到 main。V0.9.2 已废弃,06f042649c 把整条线从 main 撤掉后,这批修复需要单独落地。

内容是 #504 本体(合入 V0.9.2 时的 squash 8a5a364754)加上之后针对它的 3 个修复,这 3 个是对同一套代码的修正,单独拿前者意义不大。

主要内容

启动恢复

  • 先建立市场兼容基线再迁移普通插件,延后的迁移不会再跳过基线。市场安装保留 .desktop-market-install-pending.json 直到 pnpm 成功且活动包被校验,半成品安装即使版本号看着是新的也会强制重试。
  • 普通 Profile 启动前用 Harness 自己的 profile loader 读 bundle manifest 和 YAML 层。声明了但已不在的 bundle,其声明会被移除一次后重新检查——停用插件写的是 patch 层,清不掉 manifest 层面的故障。只删第三方声明,不碰核心 bundle、包文件、用户 patch 行和插件数据。仍然无效的输入才进安全模式,并在其中列出失败的 bundle。
  • 装不上市场基线不再单独阻断启动。pnpm 的 fetch 失败、404 和 EPERM 在受限网络里很常见(现网上报里约 130 份),只有当 Profile 里已有的市场缺失、不可读或仍被 generation 占用时才进安全模式。

宿主依赖解析

  • 本地链接插件的宿主 peer fallback:保留插件自身的正常 Node 解析,仅在缺失 @deepseek-ai/* 时从当前安装目录重试,不把普通第三方依赖泄漏给插件。
  • ERR_MODULE_NOT_FOUND 外也重试 ERR_PACKAGE_PATH_NOT_EXPORTED。现网数据里这是主要形态:插件从陈旧的 profiles/node_modules 解析到旧版宿主包、缺子路径(例如 dsh-subprocess-local 导入 dsh-subprocess/control)。重试只在安装目录确实导出该子路径时才成功。
  • 宿主重试失败时保留原始错误而不是覆盖它。上报中 code 会被 loader 的包装层吃掉,imported from <插件路径> 往往是唯一还能指认肇事插件的信息。

安全模式

  • 后端、客户端 bundle 发现和 Agent preset 统一从当前安装目录解析,不依赖 profiles/node_modules
  • 市场状态文案区分「已是最新版」「高于市场最新版」「当前 DSH 暂无可用更新」,不再把更新检查结果显示成加载错误。

PPT

  • 启动时的 bundle 对账从普通 Profile 的额外 bundle 列表中移除 dsh-pptdsh-ppt-composer——Desktop patch 已经加载 composer,由它挂载 core。避免重复的预览路由和 skill provider。依赖、已安装包、用户 patch 文件和既有 kimi-ppt 项目都保留。

冲突处理

摘到 main 时只有一个冲突,src/main/index.ts:本 PR 的 repairable 安全模式日志与 main 的 migratePersonaPrefixesBeforeStart 相邻且互不排斥,两者都保留。

验证

  • npm ci 后 28 个补丁全部干净应用、0 失败
  • npm run typecheck 通过
  • npm test:129 个测试文件 / 1143 项全部通过

尚未执行 Windows 安装包上的 junction、普通用户首次启动和安全模式端到端验收。新增的自动修剪路径建议在真实 Profile 上过一遍。

🤖 Generated with Claude Code

yaojin3616 and others added 4 commits September 22, 2026 07:25
* fix(ppt): avoid duplicate profile and desktop composition

* fix(startup): establish market baseline and isolate recovery boot

* fix(recovery): resolve agent presets from host installation

* fix(startup): resolve linked plugin host peers
…ilure

Field crash reports show the host peer fallback missing its main case: a
plugin resolving an older copy of a @deepseek-ai package from the shared
Profile tree fails with ERR_PACKAGE_PATH_NOT_EXPORTED, not not-found. The
retry is safe because it only succeeds when the installation really exports
that subpath. Reports also lose `code` to the loader's wrapper, so the first
failure's "imported from <plugin>" is all that still names the faulty plugin;
the host retry now augments that error instead of replacing it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Two startup faults sent users to Safe Mode with no way out of it.

A bundle declared in the manifest but no longer installed fails the boot
preflight, and Safe Mode cannot clear it: disabling a plugin writes a patch
row, while the fault lives in dsh.profile.bundles. Startup now drops those
third-party declarations once and re-checks before giving up, and carries the
failing package name through so Safe Mode lists it. Core bundles, host
packages, package files, user patch rows and plugin data are never touched;
pnpm-lock.yaml is dropped so the next install re-resolves. This is a narrow,
declaration-only exception to "startup leaves destructive repair to recovery",
recorded in the module docstring and the architecture notes.

A market baseline that cannot be installed no longer blocks the boot on its
own. pnpm fetch failures, 404s and EPERM are ordinary on restricted networks
and account for roughly 130 field reports; startup only enters Safe Mode when
the market already in the profile is absent, unreadable or still owned by a
generation. The pending marker keeps the repair queued for the next launch,
and an unreadable marker no longer throws the boot away either.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The client-modules patch dereferenced ctx.loader without the optional chain
its paired agent-presets patch uses. host-module-fallback.mjs is a top-level
import of the Harness entry, so leaving it out of extraResources would stop
the entry loading rather than degrade the fallback; assert it is packaged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@yaojin3616 yaojin3616 changed the title fix(startup): 让启动恢复不依赖 Profile 链接 fix(startup): make recovery independent of profile links Sep 22, 2026
@yaojin3616
yaojin3616 merged commit 969bfb5 into main Sep 22, 2026
4 checks passed
@yaojin3616
yaojin3616 deleted the fix/startup-recovery-to-main branch September 22, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant