diff --git a/pkg/skills/installer.go b/pkg/skills/installer.go index 20c8cc086..44a08d65e 100644 --- a/pkg/skills/installer.go +++ b/pkg/skills/installer.go @@ -168,6 +168,38 @@ func parseGitHubRefPathParts(repoURL *url.URL, githubBaseURL string) []string { return parts[len(baseParts):] } +func splitGitHubTreeOrBlobRefPath(parts []string, defaultRef string) (string, string) { + if len(parts) == 0 { + return defaultRef, "" + } + for i := 1; i < len(parts); i++ { + candidateRef := strings.Join(parts[:i], "/") + candidateSubPath := strings.Join(parts[i:], "/") + if looksLikeSkillSubPath(candidateSubPath) { + return candidateRef, candidateSubPath + } + } + return parts[0], strings.Join(parts[1:], "/") +} + +func looksLikeSkillSubPath(subPath string) bool { + subPath = strings.Trim(strings.TrimSpace(subPath), "/") + if subPath == "" { + return false + } + if subPath == "SKILL.md" || strings.HasSuffix(subPath, "/SKILL.md") { + return true + } + parts := strings.Split(subPath, "/") + if len(parts) >= 2 && parts[0] == "skills" { + return true + } + if len(parts) >= 3 && parts[0] == ".agents" && parts[1] == "skills" { + return true + } + return false +} + // parseGitHubRef parses a GitHub reference. // Supports: "owner/repo", "owner/repo/path", or full URL like "https://github.com/owner/repo/tree/ref/path" func parseGitHubRef(repo string) (GitHubRef, error) { @@ -197,8 +229,7 @@ func parseGitHubRefWithBaseURL(repo, githubBaseURL, defaultRef string) (GitHubRe for i := 2; i < len(parts); i++ { if parts[i] == "tree" || parts[i] == "blob" { if i+1 < len(parts) { - ref.Ref = parts[i+1] - ref.SubPath = strings.Join(parts[i+2:], "/") + ref.Ref, ref.SubPath = splitGitHubTreeOrBlobRefPath(parts[i+1:], defaultRef) } break } diff --git a/pkg/skills/installer_test.go b/pkg/skills/installer_test.go index abdd5e042..32c88ff22 100644 --- a/pkg/skills/installer_test.go +++ b/pkg/skills/installer_test.go @@ -167,6 +167,21 @@ func TestParseGitHubRefWithBaseURL(t *testing.T) { if ref.Ref != "" { t.Fatalf("ref = %q, want empty", ref.Ref) } + + ref, err = parseGitHubRefWithBaseURL( + "https://github.com/org/repo/tree/feature/skills-registry/.agents/skills/pr-review", + "", + "main", + ) + if err != nil { + t.Fatalf("parseGitHubRefWithBaseURL() unexpected error for slash branch = %v", err) + } + if ref.Ref != "feature/skills-registry" { + t.Fatalf("ref = %q, want feature/skills-registry", ref.Ref) + } + if ref.SubPath != ".agents/skills/pr-review" { + t.Fatalf("subPath = %q, want .agents/skills/pr-review", ref.SubPath) + } } func TestSkillInstallerResolveGitHubRefUsesDefaultBranch(t *testing.T) {