Remove the Desktop production profile core-package cleanup
移除 Desktop 生产启动前的核心包清理
Since 2026-09-15, production Desktop cleaned the profile before starting the Host, using the package names listed by the runtime descriptor: it deleted same-named entries under `$DSH_HOME/profiles/desktop/node_modules`, pruned the manifest's dependency declarations and pnpm overrides for those names, discarded the lockfile when package state changed, and removed development-time links once according to `desktop-runti
English
Problem
Since 2026-09-15, production Desktop cleaned the profile before starting the Host, using the package names listed by the runtime descriptor: it deleted same-named entries under $DSH_HOME/profiles/desktop/node_modules, pruned the manifest's dependency declarations and pnpm overrides for those names, discarded the lockfile when package state changed, and removed development-time links once according to desktop-runtime-state.json. It targeted two kinds of residue: earlier Desktop builds had installed the core packages into the profile as local tarballs through pnpm, writing declarations, overrides, and a lockfile; and the development mode of the link backend had projected the installation closure into the same profile's node_modules. Under nearest-wins resolution those copies shadowed the runtime bundled with the application, combining an old Web frontend with new plugins.
Both kinds of residue exist only on internal development and test machines; Desktop has not been released. Since the runtime ships inside the application, new profiles no longer contain core packages, and after the link backend removal development mode writes no links into the profile. The cleanup had to rerun on every production launch and fought the next pnpm operation, which reinstalled packages from the retained declarations.
Decision
Delete apps/desktop/src/profile-core-cleanup.ts, apps/desktop/src/profile-packages.ts, and their two specs. DesktopProjectManager.applyRelease validates the runtime descriptor, migrates profile settings, creates the profile files, and removes the projections a link-backend launch wrote through the shared removeLinkProjections; beyond that, neither production nor development launches modify the profile's node_modules, manifest, overrides, lockfile, or desktop-runtime-state.json.
Resolution inside the profile follows the lookup-order Note: packages in the profile's own node_modules win as the nearest layer, and installation package names are occupied by the generation at $DSH_HOME/profiles/node_modules. When a package installed into the profile declares @deepseek-ai/* packages under dependencies, pnpm installs copies into the profile and those copies run at their own versions. Official packages keep only pure-function packages under dependencies and declare every package with module-level identity as a peer; a third-party plugin that declares an identity-bearing dsh package as a real dependency makes that packaging choice for itself.
Capability given up: core-package copies and their declarations that earlier Desktop builds installed into a profile need one manual removal; desktop-runtime-state.json is no longer read or deleted. Projections the link backend wrote are removed by the shared profile load, see the lookup-order Note.
Reintroduction conditions: a released Desktop wrote core-package copies into external users' profiles, or official packages change their dependency conventions so that profiles gain copies competing with the runtime for identity.
Alternatives considered
Keep the original cleanup. The residue it served is no longer produced, yet it deleted directories, pruned declarations, and discarded the lockfile on every production launch, fighting the following pnpm operations.
Delete only same-named directories under the profile's node_modules, leaving declarations and the lockfile alone. The 2026-09-15 decision already rejected this: pnpm reinstalls the same old packages from the retained declarations and overrides.
Give @deepseek-ai/* generation entries absolute precedence over same-named copies inside the profile. That overrides versions plugins bring along and is a new resolution-rule decision outside the scope of removing the cleanup.
Clean only in the installer. The 2026-09-15 decision already rejected this: it misses other profiles and cannot reach copies recreated after installation.
Verification
- project-manager.spec.ts asserts that after one launch preparation the installed core package directory, the third-party plugin directory, the manifest declarations,
desktop-runtime-state.json, and the lockfile are byte-for-byte unchanged. - The repository has no remaining references to
cleanProfileCorePackages,migrateDesktopProfileLinks,CLEAN_PROFILE_CORE_PACKAGES, orDESKTOP_PROFILE_STATE.
Consequences
Bought: production launches no longer write into the profile, there is no temporary enable switch, and Desktop and the CLI apply one rule to copies inside a profile. Paid: core-package copies earlier Desktop builds installed into a profile are removed by hand; dsh copies that third-party plugins bring into the profile as real dependencies run at their own versions.
中文
Problem
2026-09-15 起,生产版 Desktop 在启动 Host 前按运行时描述符列出的包名清理 profile:删除 $DSH_HOME/profiles/desktop/node_modules 里的同名条目,剪掉 manifest 对这些名字的依赖声明与 pnpm overrides,包状态变化时丢弃锁文件,并按 desktop-runtime-state.json 记录一次性移除开发期链接。它针对两类残留:更早的 Desktop 曾把核心包做成本地 tarball 用 pnpm 装进 profile 并写入声明、overrides 与锁文件;Link 后端的开发模式曾把安装闭包投影进同一个 profile 的 node_modules。在最近者优先的解析下,这些副本会压过应用自带的运行时,把旧 Web 前端与新插件组合在一起。
这两类残留只存在于内部开发与测试机器上,Desktop 没有对外发布过。运行时随应用打包后,新 profile 不再包含核心包;Link 后端删除后,开发模式不再向 profile 写任何链接。清理每次生产启动都要重跑,并与下一次 pnpm 操作按保留的依赖重新安装形成拉锯。
Decision
删除 apps/desktop/src/profile-core-cleanup.ts、apps/desktop/src/profile-packages.ts 及其两个 spec。DesktopProjectManager.applyRelease 校验运行时描述符、迁移 profile 设置、创建 profile 文件,并通过共享的 removeLinkProjections 删除 Link 后端启动写下的投影;除此之外,生产与开发启动都不改动 profile 的 node_modules、manifest、overrides、锁文件与 desktop-runtime-state.json。
profile 内的解析按查找顺序 Note:profile 自己 node_modules 里的包最近者优先,本体包名在 $DSH_HOME/profiles/node_modules 的位置由 generation 占据。装进 profile 的包若在 dependencies 里声明了 @deepseek-ai/*,pnpm 会把副本装进 profile,这些副本按其自身版本运行。官方包只把纯函数包放在 dependencies,带模块级身份的包一律声明为 peer;第三方插件把身份敏感的 dsh 包写成实依赖,是该插件自身的打包选择。
放弃的能力:旧版 Desktop 装进 profile 的核心包副本及其声明需要手工删除一次;desktop-runtime-state.json 不再被读取或删除。Link 后端写下的投影由共享的 profile 加载一次性删除,见查找顺序 Note。
重新引入的条件:外部用户的 profile 曾被某个发布版 Desktop 写入核心包副本,或官方包改变依赖声明约定,使 profile 内出现与运行时争抢身份的副本。
Alternatives considered
保留原清理。 它服务的残留不再产生,却在每次生产启动删除目录、剪声明并丢弃锁文件,与随后的 pnpm 操作反复拉锯。
只删除 profile node_modules 里的同名目录,不动声明与锁文件。 2026-09-15 的决策已经否决:pnpm 会按保留的声明与 overrides 重装相同的旧包。
让 generation 中的 @deepseek-ai/* 条目绝对优先于 profile 内的同名副本。 这会覆盖插件自带的版本,是解析规则的新决策,不在移除清理的范围内。
只在安装器中清理。 2026-09-15 的决策已经否决:遗漏其他 profile,也管不到安装后重新产生的副本。
Verification
- project-manager.spec.ts 断言一次启动准备后,profile 里已安装的核心包目录、第三方插件目录、manifest 声明、
desktop-runtime-state.json与锁文件逐字节不变。 - 仓库中不再有
cleanProfileCorePackages、migrateDesktopProfileLinks、CLEAN_PROFILE_CORE_PACKAGES与DESKTOP_PROFILE_STATE的引用。
Consequences
买到的:生产启动不再写 profile,没有临时启用开关,Desktop 与 CLI 对 profile 内副本采用同一套规则。付出的:旧版 Desktop 装进 profile 的核心包副本靠手工清理;第三方插件以实依赖带进 profile 的 dsh 副本按其自身版本运行。