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
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.
一句话:插件重建之后,宿主继续跑旧模块,而且没有任何地方提示这件事;agent 既不能重载单个插件、也不能重启宿主,只能反复请人重启。2026-09-30 一次会话里请了 5 次,其中一次重启静默无效(加载的产物比修复更早),还有一次卡在人工闸门的关键路径上约 20 分钟。
问题(一次会话里的 5 次实证)
dist/index.mjs重建于 20:23;宿主在 19:44 加载的是更早的构建,重启因此静默无效v1-7 → v1-9且三项同名;同一命令在新构建下产出连续编号与可区分标题skipping profile bundle "…": failed to read overlay …(bundle 的 patch 文件缺失时,加载器是跳过而非响亮失败)node --input-type=module -e "import('dsh-pmboard')"(无任何状态面暴露)桌面端已经有重启机器(崩溃恢复
fatal-recovery.ts、更新安装app.relaunch()、开发重启命令),但只服务它自己的流程:没有面向 agent/CLI 的接缝,没有单插件宿主侧重载,没有陈旧态信号。提案(三档,按"单位风险换来的价值"排序)
第 1 档 · 已加载产物的身份与陈旧态上报(风险最低、收益最大)
加载插件时记录它实际加载的产物身份(路径 /
mtimeMs/ 大小 / 内容哈希),只读暴露;磁盘产物更新时报state: "stale_build",bundle 读不到时报state: "not_loaded"并附加载器原因。把整类问题从静默变成有名。第 2 档 · 单插件重载接缝
PluginReload在进程内拆掉单个插件的注册再重新应用(走 client 插件 HMR 已经在用的那条注册路径);成功后上报新的已加载身份;有在跑之活或会打断别的插件时,以结构化原因拒绝并点名持有者。这一档彻底免掉开发循环里的整应用重启。
第 3 档 · 经人确认的重启 + 延续被打断的那一轮
agent 只能请求(携带"哪块陈旧、什么会被打断"),在既有闸门通道里变成确认卡;肯定后在会话记录里先宣告、再重启(桌面已有
app.relaunch()),恢复后重新注入被打断的那一轮。quit-inspection.ts已经算出了这一档需要的"在跑之活"。贯穿三档:绝不静默、绝不单方——每一档都报告状态,重启在两条通道里都保持为人的决定。
考虑过的替代(为什么不是它们)
验收标准(要点)
stale_build,而已加载模块不变(测试锁定)。dsh.bundle.patch→ 同一状态面报not_loaded+ 原因,而不是插件静默缺席(测试锁定消息)。PluginReload成功后上报身份 == 文件当前哈希,且"仅 v2 存在"的标记可观察;有存活 job 时拒绝且不改动任何状态。风险(要点)
拆解不完整会泄漏注册(工具/路由/slot 重复)→ 需要经验证的拆解清单 + "重载两次"测试,不参与清单的插件宁可不重载;陈旧态检查开销 → 加载时哈希一次,之后先比
mtime/大小;"续跑"只能承诺那一轮而非精确步骤,必须在卡片与续跑路径上说明;跨插件服务耦合 → 第 2 档在别的插件持有其服务时拒绝并点名(重载依赖集刻意不在本提案范围)。完整 Agent Note(中文全文;英文稿 + i18n sidecar 已按其
.agents/notes约定就绪,本地格式门禁与 pre-commit 钩子均通过)问题
agent 无法让自己写的代码在运行中的宿主里生效。插件的构建产物(
dist/)重建之后,宿主继续跑先前加载的那个模块;宿主、CLI 与 agent 的工具面都没有任何入口能重载单个插件或重启进程,也没有任何地方会报告"正在运行的模块比磁盘上的产物旧"。于是失败在两头都是静默的:用户以为自己已经重启,agent 看到一个健康插件、实际却在跑旧代码。桌面端其实已经有重启机器,但只服务它自己的流程——崩溃恢复(
apps/desktop/src/fatal-recovery.ts)、更新安装(apps/desktop/src/main.ts的app.relaunch()),以及一个开发用重启命令。不存在面向 agent 或 CLI 的接缝,没有宿主半边的单插件重载,也没有陈旧态信号。2026-09-30 的一次插件开发会话,独立地付出了五次这类代价:
dist/index.mjs(20:23)与宿主已加载的旧构建(19:44)在会话内部无法区分。用户重启了两次应用;第一次重启静默无效,因为它加载的产物早于修复。没有任何界面说过"运行中的模块比磁盘产物旧"。v1-7→v1-9)且把三个不同项标成同名,而同一命令在新构建下产出连续编号与可区分标题。两张单子各自都是其构建的"正确"输出,agent 只能手工对账。dsh.bundle.patch)缺失;加载器对这种 bundle 是跳过而非响亮失败。唯一线索是宿主 stderr 上的一行(skipping profile bundle "…": failed to read overlay …)。agent 的工具就这么消失了,而原因无法从任何状态面拿到。node --input-type=module -e "import('dsh-pmboard')"),因为没有界面暴露"下次启动会加载什么"。提案
三档,由小到大。每档单独可用;按"单位风险换来的价值"排序。
第 1 档 —— 已加载产物的身份与陈旧态上报
宿主加载插件模块时,记录它实际加载的那个产物的身份(解析后的路径、
mtimeMs、大小、内容哈希)。以只读方式暴露——CLI 的插件状态面,以及在既有状态响应里给 agent 一个字段,例如:{ "plugin": "dsh-pmboard", "loaded": { "path": "…/dist/index.mjs", "hash": "…", "at": "…" }, "onDisk": { "hash": "…", "at": "…" }, "state": "stale_build" }state: "stale_build"表示磁盘产物比已加载模块新。这把上面整类问题从静默变成有名:上次那种"bundle 缺失"的情形会报state: "not_loaded"并附加载器给的原因,而不是让插件凭空消失。陈旧态在加载时计算,并按间隔(或按需)复核,不是每次请求都算。第 2 档 —— 单插件重载接缝
一个宿主 Service——
PluginReload——在进程内拆掉单个插件的注册再重新应用,走的是 client 插件 HMR 接收器已经在用的那套注册路径。契约:对最常见的开发循环(重建 → 看到生效)而言,这一档彻底免掉了重启整个应用。
第 3 档 —— 经人确认的重启与续跑
一个 agent 只能请求、永不自作的重启:请求携带"哪块陈旧、什么会被打断",并在既有闸门通道里变成一张确认卡。答案为肯定时,宿主执行桌面端已经会做的重启(
app.relaunch()),先在会话记录里宣告这次重启,恢复后在下一轮重新注入被打断的那一轮,让回合继续而不是断头。quit-inspection.ts已经算出了这一档需要的"在跑之活"输入;确认卡应当用它来警告,而不是静默拦下。贯穿三档:绝不静默、绝不单方
每一档都要报告状态,任何一档都不许悄悄失败。重启在两条通道(会话卡与看板)里都保持为人的决定,与既有闸门模式一致;agent 只能请求。
考虑过的替代方案
维持现状——只靠人工重启。 代价是每次改动运行中的插件都要一次人的往返;更糟的是它在会话内部不可证伪——当天那次会话把一次人工重启花在了一个不可能含有修复的构建上,随后只能宣布端到端证明不完整。落选原因是:真正的代价不是重启本身,而是缺少一个信号来回答"是否需要重启、重启是否生效"。
只要产物更新就自动重载。 把人完全移出循环,但它会在未获同意时杀掉在跑的 agent 与 job,并且与"正在进行的构建"抢跑(写了一半的
dist比已加载模块新,就会被加载)。落选为默认行为;它作为开发 profile 的可选策略存活,建立在第 1 档的状态与第 2 档的接缝之上。只用整进程重启这一种机制。 新增面最小,且桌面端已经把难的部分实现了。落选为唯一档位的原因是:它丢弃每个会话的内存视图、慢,而且落回到它并不回答的那个问题——"生效了吗"。因此它被保留为兜底档(第 3 档),而不是首选。
让每个插件自带构建 id 并在请求时读取。 这要求每个插件作者自行实现身份与陈旧判定,而且仍然回答不了"下次启动会加载什么"。落选原因是:模块加载归宿主所有,身份记录就该由宿主持有;插件自报 id 仍然可以作为补充叠加在宿主记录的哈希之上,而不是替代它。
监听构建产物并自动热重载(仅开发用的 watcher)。 对插件作者开发期很有吸引力,client 半边也已经是这个行为。落选为首要提案的原因是:watcher 无法对"在跑之活"或"跨插件服务注入"做判断,而且它在打包安装里并不存在——当天那次会话恰恰跑在打包安装里。一旦第 2 档的接缝与拒绝语义就位,它是这一档的天然客户。
验收标准
mtimeMs、大小与内容哈希,并以只读方式暴露。测试:在插件保持加载的状态下把产物文件换成不同内容,断言上报状态翻转为stale_build,而已加载模块不变。state: "not_loaded"并附加载器原因,而不是插件静默缺席。测试锁定dsh.bundle.patch缺失时的消息。PluginReload可重载单个插件:成功重载后上报身份等于该文件当前哈希,且一个"仅存在于 v2"的标记变为可观察;当该插件有存活 job 时以结构化原因拒绝并点名该工作。测试锁定"拒绝不改动任何状态"。风险
mtimeMs/大小,只有它们变了才重算哈希;按间隔复核而不是每次调用。附注:本建议已按
.agents/notes/proposed/feature/的格式写成中英对照 + i18n sidecar 三件套(pnpm run verify-agent-note-format→ 575 篇全合规;pre-commit 的 translation pairing / whitespace / vendor manifest 三钩均通过)。因 CONTRIBUTING 写明暂不接受外部 PR,故在此以讨论形式提交;如需我用 Inline 英文稿另开一帖或调整粒度,请告知。All reactions