You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
EN abstract — The desktop updater refuses to install a downloaded and verified update, because the shell requires the Host process to exit on its own within 10 s after the shutdown IPC (exitsWithin(exited, 1e4)). The Host stop() awaits shutdown(0), sends shutdown-complete (the "acknowledged" flag in the dialog) and disconnects — it never calls process.exit(), so it depends entirely on the Node event loop draining. Any live handle at that moment (e.g. a long-lived child process spawned by a plugin) keeps it alive; the shell then SIGTERMs it and refuses the install with DesktopHostUncleanExitError. autoInstallOnAppQuit = false, no fallback, and by default no log is written. Reproduced on 0.2.1-rc.2, still present in 0.2.1-rc.3 (identical code).
现象
更新包已下载并校验通过,点「安装并重启」后弹窗:
未能安全停止任务,更新尚未安装,请稍后重试。
展开「查看技术详情」:
desktop update: Host did not complete graceful task teardown (exit null, signal SIGTERM, shutdown acknowledged true, graceful deadline exceeded true)
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
现象
更新包已下载并校验通过,点「安装并重启」后弹窗:
展开「查看技术详情」:
结果:更新不安装,应用窗口也不再回来(用户感知为「包下好了但没自动重启」)。反复点击 100% 复现;跨版本两次尝试(rc.2 → rc.3)均如此。
定位(0.2.1-rc.3,app.asar 内行号;rc.2 相应行号 -1)
退出闸门
lib/main.js:3911-3927:弹窗四个字段与代码逐一对应:
exit null← 被信号终止、无退出码;signal SIGTERM← 10 秒超时后外壳发出的 SIGTERM;shutdown acknowledged true← Host 已回shutdown-complete;graceful deadline exceeded true←!graceful。即:Host 明明确认了关机(ack),却因为没有在 10 秒内自行退出而被判为「不干净」。Host 侧
@deepseek-ai/dsh-desktop-host/lib/index.js:264-268:该文件全文没有
process.exit()(唯一与退出码相关的是致命路径的process.exitCode = 1,:368),也搜不到spawn(/child_process/.kill(/unref(。也就是说:Host 做完应用层清理后完全依赖事件循环排空来结束进程,而它自己不会主动结束任何被插件 spawn 的子进程。失败时刻的进程树(实测):
因果说明(诚实标注):「常驻子进程持有 handle 导致事件循环不排空」是对现象的合理假设——我没有抓到退出瞬间的
process._getActiveHandles()列表(默认不写 journal,见下),无法直接证伪或证实。但以下两条是源码事实:① Host 从不process.exit(),退出取决于事件循环;② 闸门要求 10 秒内自然退出。两者组合足以解释 100% 复现。结构性错位:预检看「任务」,闸门看「进程」
更新前的预检
dsh-desktop-host/lib/index.js:101:它只枚举 running agent / inbox / running|stopping job,完全不涉及 OS 级句柄或插件 spawn 的子进程——而闸门拒绝安装的原因恰恰是后者。UI 文案同向印证(
lib/preload-app.cjs、preload-welcome.cjs):updateActiveTasksDetail: "更新将停止进行中的任务并重启应用,是否继续?"。于是:能被预检放行、又能拖住事件循环的东西(插件 spawn 的常驻子进程),正好落在预检与闸门之间的空档里。复现步骤(稳定)
dsh-free-vision→luma-mcp),启动 DSH,确认该常驻子进程出现。影响与建议
lib/main.js:7808 autoInstallOnAppQuit = false(连「退出时补装」的兜底都没有)、默认不写 journal(DSH_DESKTOP_UPDATE_JOURNAL_DIR未设置即不落盘),用户与支持侧都只能看到「请稍后重试」。shutdown-complete之后显式process.exit(0)(或至少在所有插件卸载完成后强制退出);logs/),便于用户上报;autoInstallOnAppQuit打开作为兜底。DSH_DESKTOP_*全部环境变量里没有任何放宽 10 秒窗口的开关,1e4是硬编码字面量,这是有意为之吗?环境摘要(脱敏)
<安装目录>dshBuildCommit = be72761ee1a6736ebcdf4f3739363b083ae53c98,dshBuildDirty = false)app-update.yml:provider=generic,url=https://download.deepseek.com/dsh-desk/feeds/win-x64/,channel=nightlylib/main.js均为 13198 行 / 516716 字节All reactions