diff --git a/internal/skills/discovery/discovery.go b/internal/skills/discovery/discovery.go index 84f2aa596..4a6bdb940 100644 --- a/internal/skills/discovery/discovery.go +++ b/internal/skills/discovery/discovery.go @@ -491,7 +491,7 @@ func DiscoverSkillByPath(client *api.Client, host, owner, repo, commitSHA, skill } parentPath := path.Dir(skillPath) - apiPath := fmt.Sprintf("repos/%s/%s/contents/%s?ref=%s", url.PathEscape(owner), url.PathEscape(repo), parentPath, commitSHA) + apiPath := fmt.Sprintf("repos/%s/%s/contents/%s?ref=%s", url.PathEscape(owner), url.PathEscape(repo), url.PathEscape(parentPath), commitSHA) var contents []struct { Name string `json:"name"` diff --git a/internal/skills/discovery/discovery_test.go b/internal/skills/discovery/discovery_test.go index 2de7ef683..e2333dfd1 100644 --- a/internal/skills/discovery/discovery_test.go +++ b/internal/skills/discovery/discovery_test.go @@ -699,7 +699,7 @@ func TestDiscoverSkillByPath(t *testing.T) { skillPath: "skills/monalisa/issue-triage", stubs: func(reg *httpmock.Registry) { reg.Register( - httpmock.REST("GET", "repos/monalisa/octocat-skills/contents/skills/monalisa"), + httpmock.REST("GET", "repos/monalisa/octocat-skills/contents/skills%2Fmonalisa"), httpmock.JSONResponse([]map[string]interface{}{ {"name": "issue-triage", "path": "skills/monalisa/issue-triage", "sha": "tree-sha", "type": "dir"}, })) @@ -720,6 +720,31 @@ func TestDiscoverSkillByPath(t *testing.T) { wantName: "issue-triage", wantNS: "monalisa", }, + { + name: "parent path with spaces is URL encoded", + skillPath: "my skills/code-review", + stubs: func(reg *httpmock.Registry) { + reg.Register( + httpmock.REST("GET", "repos/monalisa/octocat-skills/contents/my%20skills"), + httpmock.JSONResponse([]map[string]interface{}{ + {"name": "code-review", "path": "my skills/code-review", "sha": "tree-sha", "type": "dir"}, + })) + reg.Register( + httpmock.REST("GET", "repos/monalisa/octocat-skills/git/trees/tree-sha"), + httpmock.JSONResponse(map[string]interface{}{ + "sha": "tree-sha", "truncated": false, + "tree": []map[string]interface{}{ + {"path": "SKILL.md", "type": "blob", "sha": "blob-sha"}, + }, + })) + reg.Register( + httpmock.REST("GET", "repos/monalisa/octocat-skills/git/blobs/blob-sha"), + httpmock.JSONResponse(map[string]interface{}{ + "sha": "blob-sha", "encoding": "base64", "content": "IyBTa2lsbA==", + })) + }, + wantName: "code-review", + }, { name: "strips trailing SKILL.md from path", skillPath: "skills/code-review/SKILL.md",