PR https://github.com/makecindy/cindy/pull/4728(head `8cfa9d6fb822bf430beeb8b1d494120a81537f61`)需要维护者确认后再进入代码审查与合并。 ## 这次改了什么 自定义 Library 已打开后,若原磁盘或目录暂时消失,缓存会话仍可能再次创建原路径并形成空库。本 PR 让每次请求先核对实际 binding:目标消失时返回 unavailable、不创建空目录;同一原目标恢复后,既有 open/status 可继续访问原件。实现上新增 `libraryDirFd.ts`,并改动 `librarySlot.ts` / `libraryVault.ts` 与对应测试,同时修订 `docs/dev-rules/plugin-library-storage.md`。 ## 为何需要维护者确认 当前确认门同时命中三类触发,优先级最高的是插件基座: 1. **pluginBase(当前在拦)**:改到 Desktop Library 槽与 vault(`librarySlot.ts`、`libraryVault.ts`、新建 `libraryDirFd.ts` 及测试)。这是全部已装插件共用的持久 Library 能力槽。插件基座不吃 bugfix / 纯技术改动豁免:用户升级后什么都不做时,已装、已批准、已启用的插件必须照旧可用,不得要求重新安装、重新确认权限或重新配置。 2. **rules**:改到审查判据 `docs/dev-rules/plugin-library-storage.md`,不是纯排版/错别字/失效链接。 3. **arch**:核心路径约 1720 行、总 diff 约 1730 行,超过架构门阈值。结构上新增 fd-relative 首次建库 helper,并改变 cached session 的 binding 复核与不可用语义。 请维护者核验: - 存量自定义 Library binding / 已授权 extraDir 在升级后是否无需用户再操作即可继续使用; - 目标暂时不可用时是否只返回 unavailable,而不会重建空库或改写 owner/epoch; - 原目标恢复后是否仍能访问原件; - 规则文档是否与实际行为一致。 ## 请维护者怎么做 请直接在 PR 上 **Approve** 放行讨论门;若需要作者修改,请 **Request Changes**。普通评论、讨论 issue 留言或摘标签都不构成通过。 --- 关联 PR:#4728(作者 @PraiseZhu);本 issue 由 review-pr 流程自动创建,用于先讨论该 PR 涉及的插件基座改动(影响全部已装插件),维护者确认后 PR 会恢复推进。
Activity
dash-s-cindy commentedon Sep 20, 2026
判断:自定义 Library 的持久 binding、owner 隔离和协议兼容基础已经存在,正常升级不应要求已安装插件重新安装、重新确认权限或重新配置;本次真正需要处理的是缓存会话在自定义目标暂时消失后的绑定复核,避免把原库误当成可重新创建的空库。行动:建议对 #4728 Request Changes,暂不 Approve;待跨平台、并发和恢复场景补齐后再进行维护者放行。
已确认的现状
当前主线已有以下产品约束:
apps/desktop/src/main/cindy-brain/libraryBinding.ts将自定义位置持久化在 owner-scoped binding 中,并在解析时区分disk-missing与binding-moved;路径消失或授权对象被替换时不应静默跟随、不应回退到默认根。apps/desktop/src/main/cindy-brain/librarySlot.ts已有 owner scope 复核、opaque library identity、extraDir 会话同步和漂移状态的unavailable结果;这些接口设计支持存量插件继续工作,也不要求重新授权。docs/dev-rules/plugin-library-storage.md已明确“不可用 ≠ 空库”、卸载不删除 Library、binding 漂移不得自动重建,并保留了 Windows 上st_ino不可靠的已知限制。disk-missing、同名对象替换、owner 切换、旧插件忽略新增握手字段等场景。对问题现象的核验
进一步检查发现,当前主线的 binding 漂移保护主要发生在创建或重建 session 时:
GhostLibrarySlot.getOrCreateSession()在没有缓存 session 时调用resolveLibraryRoot();已有 session 被复用时,不会在每个请求前重新解析自定义 binding。与此同时,LibraryVault.open()会对rootDir()执行mkdir(..., { recursive: true })。因此,一个已经打开的 custom Library 在原目录暂时消失后,后续请求仍可能沿用旧缓存 session 并重新创建路径,形成与原件无关的空库。这与 #4728 要解决的核心现象一致。不过,是否可直接合并不能只看这个修复目标。#4728 的公开说明称其新增 fd-relative helper,并已通过 80 项定向库测试、related tests、typecheck 和 diff 检查;但同时明确没有做真实 Cindy 冷启动、断盘桌面操作、Windows 实机或真实模型消费验证。
合并前必须澄清或修正的风险
UNSUPPORTED,而LibraryVault.open()对已有和新建 custom Library 都会经过该路径,结果可能是 Windows 自定义 Library 全部不可用,而不只是“同路径替换无法识别”的既有限制。请提供 Windows 的安全实现,或让已存在的 custom Library 走不依赖首次建库 helper 的验证路径;不能把所有 Windows custom Library 变成 unavailable 后再合并。open/status交错失败。建议将 binding 复核、teardown、session 创建和自动 open 放入 per-ghost 临界区,或仅条件性作废调用方此前持有的 session,并增加并发回归测试。sweepStaleTmp(),以及正常 custom open 可能重复全量扫描 usage。两点都需要对照 PR 实际 diff 和行为确认:临时.tmp/.stream文件仍应有安全清理路径,已有有效usage.json不应被无条件绕过,否则会引入长期磁盘占用或重复 I/O。建议的验证门槛
open、status、read、write,确认只返回 unavailable,不创建空目录、不修改 binding、generation 或 identity。binding-moved,不得跟随新目录。open/status/恢复请求,确认新 session 不会被另一请求误作废;同时确认不同 ghost 的 extraDir 槽不会互相撤销。pnpm --filter desktop exec vitest run src/main/cindy-brain/__tests__/library与pnpm --filter desktop typecheck,并在 PR 中列出 Windows/冷启动/并发测试结果。相关记录
MagicLizi commentedon Sep 21, 2026
维护者确认已通过,讨论结束,PR 恢复正常推进。关联 PR:#4728(https://github.com/makecindy/cindy/pull/4728)。本 issue 由 review-pr 流程自动关闭。