Skip to content

fix(cli): resolve the Windows skills junction against the link directory - #495

Open
blurrah wants to merge 3 commits into
blurra/inline-skills-scaffoldfrom
fix-win-skill-junction
Open

fix(cli): resolve the Windows skills junction against the link directory#495
blurrah wants to merge 3 commits into
blurra/inline-skills-scaffoldfrom
fix-win-skill-junction

Conversation

@blurrah

@blurrah blurrah commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to @boris's review of #492 after #493 merged into that branch. Targets blurra/inline-skills-scaffold so the fix ships with #492 — that branch is where the junction is created (apps/cli/index.mjs).

Problem

inlineAgentAssets linked .claude/skills/<name> to the canonical copy with a bare relative target:

await symlink(join('..', '..', '.agents', 'skills', name), link, 'junction');

POSIX symlinks resolve that against the link's own directory, so it works. Windows junctions are always absolute, and Node resolves a relative target with path.resolve(target) — against process.cwd(), not the link's directory. Scaffolding from anywhere other than the project's parent therefore produced a junction pointing somewhere else entirely, and fs.symlink still succeeded, so nothing surfaced the problem: Claude Code just found no project skills.

Simulating Node's junction handling with path.win32, cwd C:\Users\me, project D:\work\my-shop:

canonical      : D:\work\my-shop\.agents\skills\build-shop
old -> junction: C:\.agents\skills\build-shop      <- dangling, no error
new -> junction: D:\work\my-shop\.agents\skills\build-shop

Solution

New exported skillLinkTarget(link, canonical, platform) computes the target from the link's own directory:

  • Windows — resolves to an absolute path against dirname(link), so the junction is correct regardless of the working directory.
  • POSIX — stays relative, so a scaffolded project remains movable (copy or rename the directory and the symlink still resolves).

The catch fallback to a plain copy (Windows without Developer Mode) is unchanged.

Tests

apps/cli/index.test.mjs grows 3 cases (22 total, all passing):

  • skillLinkTarget returns ../../.agents/skills/<name> on POSIX.
  • skillLinkTarget returns an absolute, link-relative path on win32 — this is the regression guard; it fails against the pre-fix behavior (verified by reverting the platform branch locally: not ok 21, 21 pass / 1 fail).
  • inlineAgentAssets run with process.chdir() set to an unrelated directory still produces a link whose target resolves to .agents/skills/<name> from the link's directory.

Docs

No change needed — the troubleshooting entry only says .claude/skills/ should link to .agents/skills/, which is now true on Windows too.

🤖 Generated with Claude Code

vercel Bot and others added 3 commits August 7, 2026 19:18
…process installs

create-vercel-shop already downloads the full repo tarball, so extract
packages/plugin/skills into .agents/skills/ (with per-skill Claude Code
symlinks in .claude/skills/, copy fallback) and packages/plugin/commands
into .claude/commands/ from the same single fetch.

- Removes the three post-scaffold 'npx plugins add' subprocesses, which
  ran even when the dependency install failed
- Skills are now versioned with the scaffolded project and always as
  fresh as main at scaffold time
- --no-template now inlines only the agent assets into an existing
  project and returns 1 cleanly when the download fails
- Companion plugins (vercel/vercel-plugin, Shopify/shopify-ai-toolkit)
  are recommended via printed commands instead of auto-installed
- Updated template AGENTS.md/README, init-vercel-shop, build-shop, and
  update-shop skills, and the docs pages describing the flow; ran the
  docs skill sync script

Co-Authored-By: Boris Besemer <borisbesemer@gmail.com>
The `.claude/skills/<name>` link was created with a relative target
(`../../.agents/skills/<name>`). Node resolves a relative target for a
junction against `process.cwd()` rather than the link's own directory, so
scaffolding from anywhere but the project's parent produced a junction
aimed at a path that does not exist — silently, since the call succeeds.

Resolve the target against the link's directory on Windows. POSIX
symlinks keep the relative target so a scaffolded project stays movable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

Co-Authored-By: Boris Besemer <2852507+blurrah@users.noreply.github.com>
@vercel

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
shop-docs Ready Ready Preview Aug 7, 2026 7:19pm
shop-template Ready Ready Preview, v0 Aug 7, 2026 7:19pm

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant