Skills Manager v1.35.1
发布日期:2026-08-28
递交范围:v1.35.0...v1.35.1
发布概览
- 在同时配置了两个 Agent 的项目里,在靠后那个 Agent 下所做的修改推不到 Skills 中心,而照着随后显示的状态操作会把这份修改覆盖掉。本次修复,并一并处理了「无论推哪一份都不安全」的情况。
用户可见更新
- 在任意 Agent 下的修改现在都能推到中心(#327)—— 项目里的 skill 在每个 Agent 目录下各有一份,卡片把它们聚合显示。只要任意一份被改过,卡片就会亮起「更新到中心」,但推上去的却是 Agent 名称字母序排第一的那一份。于是在同时配了 Claude Code 的情况下改 Codex 那份,推上去的是没动过的 Claude 副本:提示显示成功,改动一个字都没到中心,而刚被写过的中心随后又显示为「更新」——照着卡片点「更新到项目」,那份修改就没了。现在推的是真正带着修改的那一份,其余副本随后从中心对齐,卡片不再来回翻。感谢 @enshulv。修复 #322。
- 无法证明安全时,一个字都不写 —— 如果一个 skill 有超过一份副本不处于「已同步」状态,本次更新会被整体拒绝并说明冲突,而不是挑一份推、把其余悄悄丢下。只有「已同步」能证明这份副本没有独有内容——它是内容比对的结果;而「中心更新」是在内容已经不同之后按时间戳判的边,这样的副本完全可能带着会被拉取毁掉的内容。这比以前更严格:两个 Agent 各有一份尚未入库的同名 skill 时,现在必须先整理成一份,中心才会接受。
开发者与治理更新
classify_sync_status只有在内容 hash 已经不同之后才会走到center_newer,然后按 mtime 分边——它并不能证明项目副本是多余的。而对齐逻辑把它当成了证明,拒绝的门槛又画在「被编辑过」而不是「能证明干净」上;两者都会让一份带着独有内容的副本,被卡片自己提供的后续操作覆盖。- 推送会重建中心目录、把它的 mtime 变成当前时间,这正是让每一份被丢下的副本变成
center_newer的原因——而处于该状态时,卡片上仅剩的操作会覆盖全部副本,后端的守卫也不会拒绝(它只拒绝project_newer)。真正的数据丢失路径是这条链,而不是推送本身。 - 兄弟副本的对齐改为串行执行。两个 Agent 的 skills 根目录可能是指向同一个目录的软链,而每次对齐都会重建目标,并发调用会让其中一个毫无理由地失败,批量还会计为失败。
- 共做了三轮跨厂商复核,实质缺陷在第二轮之后不再出现。把拒绝范围放宽之后,原本为绕开该问题而加的记账逻辑变得不可达,因此最终改动比初稿还少 38 行。
- 已知且未修复:如果两个 Agent 的 skills 根目录是指向同一目录的软链,一份物理 skill 会被扫描成两份「被编辑过」的副本,而这种拒绝无法通过改文件解开。按 canonical path 合并根目录属于扫描器改动,本次刻意未做。
- 本次均为前端改动,而仓库没有前端测试框架,
test.yml也不覆盖src/,因此验证手段是 lint、build 与复核。
当前校验状态
- ✅ 跨平台构建通过(macOS Intel / macOS ARM / Windows x64 / Linux x64 / Linux ARM64)
- ✅ TypeScript typecheck 通过
English release notes
Release date: 2026-08-28
Commit range: v1.35.0...v1.35.1
Release Overview
- In a project with two agents, an edit made under the second one could not reach the Skills Center, and following the status the app then showed would overwrite that edit. Fixed, together with the cases where no push is safe at all.
User-facing
- An edit under any agent now reaches the center (#327) — A project skill exists once per agent directory and the card aggregates them. The card lit "update to center" if any copy was edited, but pushed the copy whose agent name sorted first. Editing under Codex while Claude Code was also configured therefore pushed the untouched Claude copy: the toast said success, nothing of the edit arrived, and the freshly written center then read as newer — so following the card to "update to project" destroyed the edit. The copy that actually carries the edit is pushed now, and the others are realigned from the center afterwards so the card settles instead of flipping. Thanks to @enshulv. Fixes #322.
- When no copy can be shown to be safe, nothing is written — If more than one copy of a skill is anything other than in sync with the center, the update is refused and the conflict is named, rather than picking one and silently stranding the rest. Only "in sync" proves a copy holds nothing of its own: it is a content match, while "center is newer" is decided by timestamp after the contents already differed, so such a copy can hold work that a pull would destroy. This is stricter than before: two agents each holding their own not-yet-imported copy of the same skill now have to be reconciled into one before the center will accept it.
Developer & Governance
classify_sync_statusreturnscenter_neweronly after the content hashes differ, then picks a side by mtime — it is not proof that the project copy is redundant. The realign step treated it as proof, and the refusal threshold was drawn at "edited" rather than "not provably clean"; both let a copy holding unique content be overwritten by a later action the card itself offered.- Pushing rebuilds the center directory, moving its mtime to now, which is what turned every stranded copy into
center_newer— a status whose only remaining card action overwrites all variants, and which the backend's guard does not refuse (it refusesproject_neweronly). That chain, not the push itself, was the data-loss path. - Sibling realignment runs serially. Two agents' skills roots can be symlinks onto one directory, and each realign rebuilds its target, so concurrent calls on one path failed for no real reason and the batch counted it as a failure.
- Three rounds of cross-vendor review; the substantive defects stopped appearing after the second. Widening the refusal made the bookkeeping it was working around unreachable, so the change ends 38 lines shorter than its first draft.
- Known and unfixed: if two agents' skills roots are symlinks onto one directory, one physical skill scans as two edited copies and the refusal cannot be resolved by editing files. Collapsing roots by canonical path is a scanner change, deliberately not made here.
- These are frontend-only changes and the repo has no frontend test runner, so
test.ymldoes not cover them. Verification waslint,build, and review.
Current Verification
- ✅ Cross-platform build passed (macOS Intel / macOS ARM / Windows x64 / Linux x64 / Linux ARM64)
- ✅ TypeScript typecheck passed
完整变更:v1.35.0...v1.35.1