DSH / Atlas
2026-09-08implementedfeaturearchived 2026-09-30

Windows uninstall retains the Harness home

Windows 卸载保留 Harness 主目录

Desktop and CLI share conversations, credentials, settings and plugins in the Harness home. Electron keeps browser storage and caches under `%APPDATA%`, and the updater keeps downloaded installers under `%LOCALAPPDATA%`; the upstream NSIS template leaves both behind unless a command-line flag is passed. Users who uninstall expect the application to leave no residue, while users who reinstall expect their conversation

English

Problem

Desktop and CLI share conversations, credentials, settings and plugins in the Harness home. Electron keeps browser storage and caches under %APPDATA%, and the updater keeps downloaded installers under %LOCALAPPDATA%; the upstream NSIS template leaves both behind unless a command-line flag is passed. Users who uninstall expect the application to leave no residue, while users who reinstall expect their conversations back.

Decision

Windows uninstallation removes the Electron user-data directory, the %APPDATA% product directory and the updater cache together with the application, and never touches the Harness home. This is the 2026-09-08 proposal in amended form: Windows only, without the installed-artifact inventory programme, and without a user choice. No custom uninstaller page exists; silent uninstallation removes the same data. An uninstaller started with --updated or /KEEP_APP_DATA retains it, which covers electron-builder's in-place update and its replacement of an older installation from another directory, so updates keep UI preferences. A DSH_HOME published as a Windows environment variable protects every target overlapping it; the native helper cannot see a home configured only in a shell profile.

Electron derives its user-data directory from the scoped package name, so the removal targets %APPDATA%\@deepseek-ai\dsh-desktop and afterwards removes ordinary empty parents below %APPDATA%, never a linked or populated scope directory. Removal runs through the native helper in window-frame.dll, which rejects protected Windows folders and paths overlapping the installation or the protected home, holds directory handles with listing access during traversal so the directory cannot be renamed or replaced underneath it, unlinks reparse points without entering their targets, clears the read-only attribute, and keeps deleting siblings after a locked file. It requires a fixed local drive and leaves a linked root or ancestor in place. A failure leaves residue and does not stop or report on uninstallation; the uninstaller has no custom copy.

Installation also records InstallLocation on the Windows uninstall entry as standard inventory metadata. Launching the uninstaller directly from the Start menu context menu is unavailable to Win32 installers on Windows 11; only MSIX packages uninstall from there, so that request is outside this decision.

Alternatives considered

Opt-in removal on a custom uninstaller page, including the desktop profile and the whole home. The desktop profile, sessions and credentials belong to the home shared with the CLI and stay in place for reinstallation; the remaining Electron data holds only UI preferences and caches, which does not justify a choice the user must understand, a recorded home path for the uninstaller, and a bilingual native dialog.

Delete the whole home when desktop is the only profile. Profile presence does not establish whether shared data is needed by CLI or a future reinstall.

Leave Electron data in place, matching the upstream default. Chromium caches grow to hundreds of megabytes and are the residue users report after uninstalling.

Use electron-builder's deleteAppDataOnUninstall. The upstream RMDir /r follows no ownership rules, ignores long paths and enters linked directories; the native helper owns removal instead.

Establish the cleanup inventory by observing disposable accounts across install, update and uninstall. The three roots follow from Electron's userData derivation and electron-builder's updater cache name, both fixed by configuration; observation would confirm what the configuration already states.

Deferred

macOS cleanup (a signed helper behind an Uninstall and keep Harness data action, since drag-to-Trash cannot run application code) remains open under #3540 and is not decided here.

Consequences

Reinstallation restores conversations, settings and plugins but not UI layout preferences. The desktop profile under the home remains with its packages and lock files. Other historical homes and user projects are not discovered or deleted. Roaming profiles on network or removable drives are left in place.

Qualification uses isolated product identities with a per-run scoped package name. Source regressions cover template adaptation; the native remover regression covers refused roots, the protected home, rename blocking while pinned, read-only and locked files, and empty-parent removal; the uninstaller fixtures cover interactive, silent, --updated, /KEEP_APP_DATA, and a DSH_HOME inside the Electron directory, with a junction to an external project inside the removed data. The standard uninstaller pages render correctly at 200% scaling on the development host.

中文

问题

Desktop 和 CLI 在 Harness 主目录中共享会话、凭据、设置和插件。Electron 把浏览器存储和缓存放在 %APPDATA% 下,更新器把下载的安装包放在 %LOCALAPPDATA% 下;上游 NSIS 模板在没有命令行参数时会把两者都留下。卸载的用户期望应用不留残余,重装的用户期望会话仍在。

决策

Windows 卸载随应用一起删除 Electron 用户数据目录、%APPDATA% 下的产品目录和更新器缓存,从不触碰 Harness 主目录。这是 2026-09-08 提案的修正形式:仅限 Windows,不含已安装产物清单方案,也不让用户选择。卸载程序没有自定义页面;静默卸载删除相同的数据。以 --updated 或 /KEEP_APP_DATA 启动的卸载程序保留数据,这覆盖了 electron-builder 的原地更新和从其他目录替换旧安装两种情况,因此更新保留界面偏好。以 Windows 环境变量发布的 DSH_HOME 会保护所有与其重叠的目标;原生辅助程序看不到只在 shell 配置文件中设置的主目录。

Electron 根据带作用域的包名派生用户数据目录,因此删除目标是 %APPDATA%\@deepseek-ai\dsh-desktop,随后移除 %APPDATA% 之下普通且已空的父目录,从不移除链接或非空的作用域目录。删除通过 window-frame.dll 中的原生辅助程序执行:它拒绝受保护的 Windows 目录以及与安装目录或受保护主目录重叠的路径,遍历期间以列举权限持有目录句柄,使目录无法在其下被改名或替换,遇到重解析点只解除链接而不进入目标,清除只读属性,并在遇到被占用文件后继续删除其余兄弟项。它要求固定的本地驱动器,链接的根目录或祖先目录会原样保留。失败只留下残余,不中止也不提示卸载;卸载程序没有任何自定义文案。

安装时还会在 Windows 卸载注册项上记录 InstallLocation 作为标准的清单元数据。Windows 11 上 Win32 安装包无法让开始菜单右键菜单中的“卸载”直接启动卸载程序,只有 MSIX 包能做到,因此该需求不在本决策范围内。

备选方案

在自定义卸载页上按需删除,包括桌面配置档案和整个主目录。 桌面配置档案、会话和凭据属于与 CLI 共享的主目录,为重装而保留;剩余的 Electron 数据只包含界面偏好和缓存,不值得让用户理解并做出选择,也不值得为卸载程序记录主目录路径并维护双语原生对话框。

当桌面是唯一配置档案时删除整个主目录。 配置档案的存在不能证明共享数据是否被 CLI 或将来的重装需要。

沿用上游默认,保留 Electron 数据。 Chromium 缓存会增长到数百 MB,正是用户卸载后反馈的残余。

使用 electron-builder 的 deleteAppDataOnUninstall。 上游的 RMDir /r 不遵守归属规则、不支持长路径并会进入链接目录;改由原生辅助程序负责删除。

通过在一次性账户上观察安装、更新和卸载来建立清理清单。 三个根目录由 Electron 的 userData 派生规则和 electron-builder 的更新器缓存名决定,两者都由配置固定;观察只会确认配置已经说明的事实。

推迟事项

macOS 清理(由签名辅助程序支撑的“卸载并保留 Harness 数据”操作,因为拖到废纸篓无法运行应用代码)仍在 #3540 下开放,本决策不涉及。

结果

重装恢复会话、设置和插件,但不恢复界面布局偏好。主目录下的桌面配置档案及其包和锁文件保留。其他历史主目录和用户项目不会被发现或删除。位于网络或可移动驱动器上的漫游配置文件原样保留。

验收使用每次运行唯一的带作用域包名的隔离产品身份。源码回归覆盖模板适配;原生删除器回归覆盖被拒绝的根目录、受保护的主目录、持有期间阻止改名、只读与被占用文件,以及空父目录移除;卸载夹具覆盖交互、静默、--updated、/KEEP_APP_DATA,以及位于 Electron 目录内的 DSH_HOME,被删除的数据内含指向外部项目的 junction。标准卸载页面在开发机 200% 缩放下渲染正确。