Repository navigation
Conversation
There was a problem hiding this comment.
The fix looks right to me, and I found nothing that should block a merge.
How I checked: I ran the updated reload.test.ts against the base. All four loads skills when <root> appears after startup cases time out at the step that creates the root before skills/, so the bug is real. With this PR the file passes 12/12 on three runs (it uses the real native watcher). The rest of test/config passes (238 tests) and typecheck in packages/core is clean.
Code: readiness can't loop, because FiberMap.run(..., { onlyIfMissing: true }) only consumes the stream (and fires onReady) for a newly attached key. Watches that died drop out of the map and get reattached on the next refresh. The file watch on a missing <root>/skills matches what ConfigSkillPlugin does.
Public API: unchanged.
Note on #54114 / #53393: dropping FiberMap.clear means a refresh no longer rebuilds the native watches. But refresh() still calls watcher.subscribe for every root, and that writes a watcher subscribe log line on every refresh. If the data directory is the same as the config directory, those writes can still feed back into config.changes(), so I've listed both as related rather than fixed. #54450 is an outside PR that also reconciles these watches.
Fixes the flaky
config plugin reloads > loads skills when <root> appears after startuptest.Failing runs:
.agents)../.claude)Cause
ConfigCompatibilityPluginonly watched<root>/skillswhen it already existed. If.agentsor.claudeexisted withoutskills/, a laterskills/was never loaded until restart.Bun.write(".agents/skills/probe/SKILL.md")creates the directories one by one. When the refresh ran betweenmkdir .agentsandmkdir .agents/skills, the skill was lost.Fix
compatibility.ts<root>/skillsas afiletarget when it is missing, so its creation triggers a refresh. This is the same approach asConfigSkillPlugin.watcher.subscribe, so a newly attached watch triggers one rescan.Configuses the same pattern.reload.test.tssettle(events, action, condition). It subscribes toconfig.updatedorskill.updatedbefore the action and checks the condition on each event. The test runner timeout is the only time limit.skills/, which covers the product bug. Recreating the whole tree in one write still covers the concurrent case.Not in this PR
error: Failed to run "turbo" due to signal SIGSEGVafterbun testexited normally with code 1. In this window it happened in 2 of 19 failed linuxunitjobs, and only after a task failed. That matches a known turbo 2.10.x crash when a run ends with a failed task. The repo pinsturbo2.10.2.Added by the opencode bot (AI-generated).
Related: #54114, #53393, #42478