#2595

fix(update): honor locked paths with mirrored skills on generic Git sources

OpenRyangr0wants to merge intofrom

Summary

Follow-up to #2231. Fixes #2594.

#2231 let the locked skillPath win over same-name mirrors only when the install URL can carry a subpath. Generic Git and SSH sources stayed fail-closed, because the global reinstall picked the skill by name from the whole clone. This PR removes that reason instead of working around it:

  • Global update: for sources that can't carry a subpath in the URL, the locked folder is now applied as parsed.subpath after cloning (lockedSubpathForUpdate). resolveSkills already hands parsed.subpath to discoverSkills for clones, so the reinstall finds exactly the locked folder.
  • Project update: no change needed. Since #2563 it installs the skill discovered at the resolved path from the same clone.
  • Resolver: both paths now install from the locked folder for every source type, so resolveSkillLocations checks the exact locked path first and the exactPathDisambiguates option is gone. A missing locked path with several same-name candidates still fails closed, and a skill locked at the repository root still installs from the root.

Tests

  • npx vitest run src/skill-relocation.test.ts tests/update.test.ts src/update-source.test.ts: 72 passed.
  • Changed: the three tests that asserted the generic-Git fail-closed behaviour now assert the update goes through from the locked path (resolver, project update, global SSH update).
  • Added: a global generic-Git update with a .claude/skills mirror, and unit tests for lockedSubpathForUpdate.
  • pnpm type-check and Prettier: pass.
  • Full suite: 1005 passed, 9 failed. The same 9 fail on main without this change; they are agent-detection and project-guard tests that trip because I ran them from inside an agent session.
  • End to end: I built dist/ and ran update -g in a scratch HOME against a real self-hosted Forgejo repository that has each skill in skills/, .claude/skills/ and .agents/skills/. Stock 1.7.4 printed the "Multiple current paths match" warning and updated nothing. This branch updated both skills, and the installed folders are byte-identical to skills/<name>/, not to the older .claude/skills/ copies.

AI assistance disclosure

Developed with Claude Code: repository analysis, the change, the tests and this description, under my direction and review.