From e31109ff550bb708aaa5ca86279bbabd0e2fdde7 Mon Sep 17 00:00:00 2001 From: nguyenngothuong Date: Sun, 31 May 2026 13:16:30 +0700 Subject: [PATCH] fix: parse grouped skills list output --- internal/skillscheck/sync.go | 19 +++++++++++++------ internal/skillscheck/sync_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/internal/skillscheck/sync.go b/internal/skillscheck/sync.go index f2d2a2cf8..d89e2e792 100644 --- a/internal/skillscheck/sync.go +++ b/internal/skillscheck/sync.go @@ -77,14 +77,12 @@ func parseGlobalSkillsList(lines []string) []string { continue } - // Skip indented lines (Agents: ...) - if strings.HasPrefix(line, " ") || strings.HasPrefix(line, "\t") { - continue - } - // Extract skill name, format is typically "skill-name /path/to/skill" parts := strings.Fields(trimmed) - if len(parts) == 0 { + if len(parts) < 2 { + continue + } + if !looksLikeSkillPath(parts[1]) { continue } @@ -106,6 +104,15 @@ func parseGlobalSkillsList(lines []string) []string { return sortedKeys(seen) } +func looksLikeSkillPath(s string) bool { + return strings.HasPrefix(s, "~/") || + strings.HasPrefix(s, "/") || + strings.HasPrefix(s, "./") || + strings.HasPrefix(s, "../") || + strings.Contains(s, `:\`) || + strings.Contains(s, `/`) +} + // parseOfficialSkillsList parses the output of "npx -y skills add ... --list" func parseOfficialSkillsList(lines []string) []string { seen := map[string]bool{} diff --git a/internal/skillscheck/sync_test.go b/internal/skillscheck/sync_test.go index 18a2802c6..020db4e11 100644 --- a/internal/skillscheck/sync_test.go +++ b/internal/skillscheck/sync_test.go @@ -53,6 +53,30 @@ yuanbao ~/.hermes/skills/yuanbao } } +func TestParseGlobalSkillsListWithGroupedIndentedSkills(t *testing.T) { + input := `Global Skills + +General + lark-apps ~/.agents/skills/lark-apps + lark-base ~/.agents/skills/lark-base + lark-contact ~/.agents/skills/lark-contact + +Document + lark-doc ~/.agents/skills/lark-doc + lark-openapi-explorer ~/.agents/skills/lark-openapi-explorer + +Knowledge Base + lark-wiki /Users/me/.agents/skills/lark-wiki + +Tip: Use the -y flag to run in non-interactive mode (for CI and AI agents). +` + got := ParseSkillsList(input) + want := []string{"lark-apps", "lark-base", "lark-contact", "lark-doc", "lark-openapi-explorer", "lark-wiki"} + if !reflect.DeepEqual(got, want) { + t.Fatalf("ParseSkillsList() (grouped Global Skills) = %#v, want %#v", got, want) + } +} + func TestParseGlobalSkillsListWithANSI(t *testing.T) { input := "\x1b[1mGlobal Skills\x1b[0m\n\n" + "\x1b[36mlark-calendar\x1b[0m \x1b[38;5;102m~/.agents/skills/lark-calendar\x1b[0m\n" +