From 1160943af343d9904356db0d9f4bb2f5b5a9b651 Mon Sep 17 00:00:00 2001 From: Sam Morrow Date: Tue, 21 Apr 2026 09:56:27 +0200 Subject: [PATCH 1/2] fix(skills): match skills by install name in preview command The preview command's selectSkill function only matched skills by DisplayName() and Name. For plugins-convention skills, the install hint outputs InstallName() (namespace/name), which matched neither - DisplayName() includes a [plugins] prefix and Name is just the base name. This caused 'skill not found' errors when users ran the suggested preview command after install. Add InstallName() as an additional match criterion so that namespaced skill identifiers produced by the install hint are accepted. Closes #13248 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/cmd/skills/preview/preview.go | 2 +- pkg/cmd/skills/preview/preview_test.go | 45 ++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/skills/preview/preview.go b/pkg/cmd/skills/preview/preview.go index e9f1e0442..98762fb11 100644 --- a/pkg/cmd/skills/preview/preview.go +++ b/pkg/cmd/skills/preview/preview.go @@ -391,7 +391,7 @@ func isMarkdownFile(filePath string) bool { func selectSkill(opts *PreviewOptions, skills []discovery.Skill) (discovery.Skill, error) { if opts.SkillName != "" { for _, s := range skills { - if s.DisplayName() == opts.SkillName || s.Name == opts.SkillName { + if s.DisplayName() == opts.SkillName || s.Name == opts.SkillName || s.InstallName() == opts.SkillName { return s, nil } } diff --git a/pkg/cmd/skills/preview/preview_test.go b/pkg/cmd/skills/preview/preview_test.go index a5d5554ff..be3c86117 100644 --- a/pkg/cmd/skills/preview/preview_test.go +++ b/pkg/cmd/skills/preview/preview_test.go @@ -206,6 +206,51 @@ func TestPreviewRun(t *testing.T) { }, wantStdout: "My Skill", }, + { + name: "preview plugins skill matched by install name", + tty: true, + opts: &PreviewOptions{ + repo: ghrepo.New("owner", "repo"), + SkillName: "aws-common/aws-mcp-setup", + }, + httpStubs: func(reg *httpmock.Registry) { + reg.Register( + httpmock.REST("GET", "repos/owner/repo/releases/latest"), + httpmock.StringResponse(`{"tag_name": "v1.0.0"}`), + ) + reg.Register( + httpmock.REST("GET", "repos/owner/repo/git/ref/tags/v1.0.0"), + httpmock.StringResponse(`{"object": {"sha": "abc123", "type": "commit"}}`), + ) + reg.Register( + httpmock.REST("GET", "repos/owner/repo/git/trees/abc123"), + httpmock.StringResponse(`{ + "sha": "abc123", + "truncated": false, + "tree": [ + {"path": "plugins", "type": "tree", "sha": "tree-plugins"}, + {"path": "plugins/aws-common", "type": "tree", "sha": "tree-awscommon"}, + {"path": "plugins/aws-common/skills", "type": "tree", "sha": "tree-awsskills"}, + {"path": "plugins/aws-common/skills/aws-mcp-setup", "type": "tree", "sha": "treeSHA3"}, + {"path": "plugins/aws-common/skills/aws-mcp-setup/SKILL.md", "type": "blob", "sha": "blob789"} + ] + }`), + ) + reg.Register( + httpmock.REST("GET", "repos/owner/repo/git/trees/treeSHA3"), + httpmock.StringResponse(`{ + "tree": [ + {"path": "SKILL.md", "type": "blob", "sha": "blob789", "size": 50} + ] + }`), + ) + reg.Register( + httpmock.REST("GET", "repos/owner/repo/git/blobs/blob789"), + httpmock.StringResponse(`{"sha": "blob789", "content": "`+encodedContent+`", "encoding": "base64"}`), + ) + }, + wantStdout: "My Skill", + }, { name: "skill not found", tty: true, From 6fcc9c24df4e0307a89be32d6ebaa0002d4545e3 Mon Sep 17 00:00:00 2001 From: Sam Morrow Date: Tue, 21 Apr 2026 10:09:20 +0200 Subject: [PATCH 2/2] fix(skills): prioritize DisplayName/Name over InstallName match Use a two-pass search so exact DisplayName and Name matches are preferred over InstallName. This avoids incorrectly selecting a plugins-convention skill via InstallName when a standard namespaced skill with a matching DisplayName exists later in the sorted slice. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pkg/cmd/skills/preview/preview.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/cmd/skills/preview/preview.go b/pkg/cmd/skills/preview/preview.go index 98762fb11..1c9d4d913 100644 --- a/pkg/cmd/skills/preview/preview.go +++ b/pkg/cmd/skills/preview/preview.go @@ -391,7 +391,14 @@ func isMarkdownFile(filePath string) bool { func selectSkill(opts *PreviewOptions, skills []discovery.Skill) (discovery.Skill, error) { if opts.SkillName != "" { for _, s := range skills { - if s.DisplayName() == opts.SkillName || s.Name == opts.SkillName || s.InstallName() == opts.SkillName { + if s.DisplayName() == opts.SkillName || s.Name == opts.SkillName { + return s, nil + } + } + // Fall back to InstallName so that namespaced identifiers produced + // by the post-install hint (e.g. "namespace/skill") are accepted. + for _, s := range skills { + if s.InstallName() == opts.SkillName { return s, nil } }