fix(skill-downloader): handle in-repo directory symlinks natively#78
Merged
albertodebortoli merged 2 commits intoLucaTools:mainfrom Apr 27, 2026
Merged
Conversation
This commit fixes an issue where the skill downloader fails on symlinked directories (like in twostraws/SwiftUI-Agent-Skill). 1. `GitHubSkillTreeClient` now decodes the `mode` property from the Git Tree API and filters out `120000` (symlink) modes, preventing them from being processed as files and downloaded as raw text strings. 2. `GitRepositorySkillFetcher` now inspects `isSymbolicLinkKey` during enumeration. If a symlink points to a directory, it skips traversing it to prevent crashing on `Data(contentsOf:)` (POSIX Error 21 - Is a directory). Deduplication handles the actual skill scope cleanly.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Test that GitHubSkillTreeClient excludes tree items with mode "120000" and that GitRepositorySkillFetcher skips directory symlinks during enumeration.
Member
|
Thank you so much @peterfriese 🙏🙏🙏 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #77.
Description
When installing a skill that contains a directory symlink in its repository structure (like
twostraws/SwiftUI-Agent-Skillstarting from commited98890), Luca's native downloader would crash withFailed to download skill at path.Root Cause & Changes
This issue occurred in two different code paths depending on the authentication context:
The GitHub API Path (
GitHubSkillTreeClient.swift)type: "blob"andmode: "120000".GitHubTreeItemonly filtered bytype == "blob". Consequently, Luca treated symlinks as regular files. When requested viaraw.githubusercontent.com, GitHub returns the symlink target path as a raw string (e.g.,../../references), corrupting the structure.modeproperty to the decoding struct and explicitly filtered outmode == "120000".The Local Clone Path (
GitRepositorySkillFetcher.swift)FileManager.default.enumeratorcorrectly skips traversing into symlinks that point to directories becauseisDirectoryKeyevaluates tofalsefor the symlink itself.downloadSkillattempted to read the content viaData(contentsOf: fileURL), the underlying POSIX layer automatically resolved the symlink to the target directory. Reading a directory as a data buffer throws POSIX Error 21 (Is a directory), crashing the downloader..isSymbolicLinkKeycheck in the enumerator loop. If the item is a symlink, we resolve it; if the resolved target is a directory, we skip it.(Since
SKILL.mddefines the root of a skill, shared assets referenced via symlink are still caught correctly by the deduplication logic without throwing errors).Testing
lucaand verifying thatluca install twostraws/SwiftUI-Agent-Skillnatively handles the repository structure correctly and successfully symlinks to the active agents cache without requiring the--use-npxflag.