Repository navigation
Replies: 2 comments
|
同版本上再次命中(0.2.1-rc.2 / Windows 10 x64 / 命中场景:失败启动循环期间(同日连续 10 次
补充观察 1:那次覆盖没有 同一文件的其他写入都留了备份: 补充观察 2:顺序是先砍 bundles、后写 patch patch 被写成 4 条的时候,bundles 已经是 2 条了;写出来的内容恰好等于"只挂两个官方 bundle 时组合出来的行"。这解释了"为什么幸存项的取值也回默认":不是有人把值改了,而是整份内容被换成了默认组合。 同意你的四条建议,最想要第 2 条(改 patch 必须留可发现的时间戳备份)和第 4 条(用 disable 而不是 delete)。这次要不是 |
|
Cross-link: this makes the dialog dangerous in a case where nothing is actually broken. #12098 documents a startup failure that a plain restart always resolves — the host is started with Suggested ordering, if the dialog is touched at all: recognise non-actionable failures ( |
Uh oh!
There was an error while loading. Please reload this page.
The in-app recovery dialog for a failed startup offers:
I triggered this once (a third-party plugin of mine failed to load — that's on me, and I've since fixed it and added a self-disabling safety net). But the recovery action itself damaged the profile in ways the label doesn't disclose, and the damage was silent and multi-symptom.
Reproduced on
dsh 0.2.0-rc.2, desktop, Windows. All figures below come from comparing the profile directory before/after, using backups the action itself left behind.Damage 1 — four first-party bundles were removed
The label says third-party. The action reduced
profile.bundlesfrom 6 to 2:Nothing in the dialog said first-party features would disappear. The user simply loses voice input, Agent Teams, auto-review and scheduled tasks — with no message on the next start.
Damage 2 — the user's own
cordis.patch.ymlwas guttedThis is the more serious one. The patch layer is where a user's own configuration lives (third-party model providers, permission presets, theme, subagent limits, chat view options). After the recovery action it went from 4218 bytes / 11 entries to 661 bytes / 4 entries:
- id: ui-settings-general- id: llm-pi-ai ← ★ third-party model providers, all of them- id: agent-default-model- id: permission ← permission presets- id: ui-theme- id: ui-chat- id: ui-settings- id: ui-settings-account- id: agent-loop- id: subagent-model-selection-settings- id: subagent+ id: ui-settings-account+ id: ui-chat+ id: ui-settings+ id: agent-default-modelConcretely, a configured provider block like this disappeared entirely:
And the four surviving entries had their values reset to defaults — not just the missing ones:
entry | before | after -- | -- | -- ui-chat.performanceUsage | detailed | compact ui-settings.enabled | true | false ui-settings-account.usage | detailed | compact ui-settings-account.developerTools | true | false ui-settings-account.completion | api-key | skippedI spent several debugging cycles investigating whether my own plugin had removed that UI tab — I registered a slot in the same area and suspected a registration bug. It was the config reset. A plugin author will look at their own code first. That is a large, misdirected cost created by a silent config change.
What would help
Either scope the action to third-party plugins, or say what it actually does. Removing first-party bundles under a third-party label is the core mismatch.
Never rewrite the user's patch layer without a fresh, discoverable backup. If "back up profile patch" is in the label, the backup should be the version being replaced, timestamped, and easy to find.
Report what was changed on the next successful start — e.g. "3 plugin entries disabled, 4 bundles removed, patch backed up to
<path>". Right now the change is completely silent.Prefer disabling over deleting. Marking entries/bundles as disabled (reversible from the UI) would avoid needing file-level recovery at all.
A related, separate issue: unexpected plugin failure kills startup
Happy to file this separately, but it's what led me here. In my case a third-party plugin's
applypath produced an error and the desktop host reported:dsh: fatal load failure: Error: <message>and refused to start, showing "The application could not start or stopped unexpectedly."
Two things worth distinguishing, as another maintainer suggested to me:
an awaited
apply()rejection — arguably the plugin's fault, but the failure mode is severe: the user cannot start the app, and therefore cannot reach the plugin author at all.an unhandled promise rejection left behind by a plugin — in my case this was the actual mechanism. An
asyncfunction that throws returns a rejected promise; if nobody awaits it, Node terminates the process by default. That is a much harder class to defend against.I'd suggest the host consider starting with failed plugins skipped (and reported), rather than failing the whole boot. I can't ask for arbitrary in-process fault isolation — that would be an overpromise — but "app starts, that plugin is disabled, here's why" seems achievable and would keep the user able to act.
★ For the record, I added a self-disabling safety net on my side: the plugin writes a "loading" marker on start, flips it to "ok" after surviving 15 s, and disables itself on the next start if it finds a stale "loading" marker — so the app always boots and the user can reach me. That's a workaround for a host-level gap, not a fix.
中文摘要(可附在英文正文之后)
恢复动作「Disable third-party plugins, back up profile patch, and restart」的破坏范围超出它的文案。
在
0.2.0-rc.2桌面版实测,三类破坏:摘掉 4 个官方 bundle —— 文案说 third-party,实际把
profile.bundles从 6 个砍到 2 个, 语音输入、Agent Teams、自动审阅、定时任务全部消失,启动后没有任何提示。清空用户自己的
cordis.patch.yml—— 从 4218 字节 / 11 条变成 661 字节 / 4 条。 第三方模型服务商(llm-pi-ai)、权限预设、主题、子代理设置全丢; 存活的 4 条取值也被改回默认(performanceUsage、developerTools、completion等)。声称"back up profile patch"却没留下新备份 —— 事后只有一份前一天的旧备份。
★ 最关键的一点:一次动作产生至少 6 类看起来互不相关的症状,没有一条指向"恢复动作"。 其中"某个界面标签消失"让我怀疑是自己插件的 Slot 注册有问题,为此查了好几轮。 静默改配置的诊断代价很大,而且会把人引向错误的方向。
建议:范围与文案一致;改 patch 前必须留可发现的时间戳备份;下次启动时报告改了什么; 能用"禁用"就不要用"删除"。
另附一条相关问题:第三方插件加载失败会导致宿主起不来, 用户因此无法联系插件作者(没有可用会话)。建议宿主改为"跳过失败插件继续启动并报告原因"。
All reactions