fix(coding-agent): kept claude home skills user-scoped
Skipped the home directory during Claude project skill walk-up so disabling Claude user skills cannot reload the same files as project skills. Added regression coverage for the home-skill duplicate path with an enabled agents fallback. Fixes #4648
This commit is contained in:
@@ -167,17 +167,21 @@ async function loadContextFiles(ctx: LoadContext): Promise<LoadResult<ContextFil
|
||||
async function loadSkills(ctx: LoadContext): Promise<LoadResult<Skill>> {
|
||||
const userSkillsDir = path.join(getUserClaude(ctx), "skills");
|
||||
|
||||
// Walk up from cwd finding .claude/skills/ in ancestors
|
||||
// Walk up from cwd finding .claude/skills/ in ancestors. Skip $HOME:
|
||||
// that path is already scanned as the Claude user source below, and scanning
|
||||
// it again as project would bypass enableClaudeUser when project skills stay enabled.
|
||||
const projectScans: Promise<LoadResult<Skill>>[] = [];
|
||||
let current = ctx.cwd;
|
||||
while (true) {
|
||||
projectScans.push(
|
||||
scanSkillsFromDir(ctx, {
|
||||
dir: path.join(current, CONFIG_DIR, "skills"),
|
||||
providerId: PROVIDER_ID,
|
||||
level: "project",
|
||||
}),
|
||||
);
|
||||
if (current !== ctx.home) {
|
||||
projectScans.push(
|
||||
scanSkillsFromDir(ctx, {
|
||||
dir: path.join(current, CONFIG_DIR, "skills"),
|
||||
providerId: PROVIDER_ID,
|
||||
level: "project",
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (current === (ctx.repoRoot ?? ctx.home)) break;
|
||||
const parent = path.dirname(current);
|
||||
if (parent === current) break; // filesystem root
|
||||
|
||||
@@ -113,6 +113,21 @@ describe("managed-skills discovery", () => {
|
||||
expect(matches[0]?.source).toBe("agents:user");
|
||||
});
|
||||
|
||||
it("does not resurrect disabled home claude user skills as project skills when cwd is under home", async () => {
|
||||
// No repo root marker is created in tempHome/work. A Claude home skill must
|
||||
// stay user-scoped only even while project skills remain enabled by default.
|
||||
await writeSkill(path.join(tempHome, ".claude", "skills"), "home-only", "Disabled claude home skill.");
|
||||
await writeSkill(path.join(tempHome, ".agents", "skills"), "home-only", "Enabled agents fallback.");
|
||||
const { skills } = await loadSkills({
|
||||
cwd: tempCwd,
|
||||
enableClaudeUser: false,
|
||||
});
|
||||
const matches = skills.filter(s => s.name === "home-only");
|
||||
expect(matches).toHaveLength(1);
|
||||
expect(matches[0]?.source).toBe("agents:user");
|
||||
expect(skills.some(s => s.name === "home-only" && s.source === "claude:project")).toBe(false);
|
||||
});
|
||||
|
||||
it("preserves provider priority when duplicate authored providers are both enabled (#4648)", async () => {
|
||||
await writeSkill(path.join(tempHome, ".claude", "skills"), "priority-authored", "Enabled claude.");
|
||||
await writeSkill(path.join(tempHome, ".agents", "skills"), "priority-authored", "Enabled agents.");
|
||||
|
||||
Reference in New Issue
Block a user