From a95d0d3f828b92eb332fdd5b8e4305b00e170937 Mon Sep 17 00:00:00 2001 From: Jasmine Kaur Date: Thu, 25 Jun 2026 20:33:56 +0530 Subject: [PATCH] fix: allow nested YAML lists in metadata sub-keys (sync with internal) @W-23173617@ (#298) fix: allow nested YAML lists in metadata sub-keys (sync with internal) The validator incorrectly rejected skills with list-type fields (e.g. cliTools) nested under metadata sub-keys. This syncs the parseMetadataBlock() fix from sf-skills-internal that distinguishes direct-child lists from nested ones. Co-authored-by: Claude Opus 4.6 --- scripts/validate-skills.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/validate-skills.ts b/scripts/validate-skills.ts index da9eb58..128b14b 100644 --- a/scripts/validate-skills.ts +++ b/scripts/validate-skills.ts @@ -420,7 +420,8 @@ Wrap values that contain \`: \` (colon + space), such as long descriptions with /** * Extracts nested key-value pairs from the `metadata:` block in raw frontmatter. * Returns `null` if no metadata block, `"scalar"` if metadata has an inline value, - * `"list"` if it contains YAML list items, or a `Record` of sub-keys. + * `"list"` if direct children are YAML list items, or a `Record` of sub-keys. + * Nested lists under sub-keys (e.g. cliTools: [{tool:"sf"}]) are allowed. */ function parseMetadataBlock(rawFrontmatter: string): Record | "scalar" | "list" | null { const lines = rawFrontmatter.split(/\r?\n/) @@ -431,12 +432,16 @@ function parseMetadataBlock(rawFrontmatter: string): Record | "s const inlineValue = metaLine.slice(metaLine.indexOf(":") + 1).trim() if (inlineValue && !inlineValue.startsWith("#")) return "scalar" + let directIndent: number | null = null const result: Record = {} for (let i = metaIdx + 1; i < lines.length; i++) { const line = lines[i] if (!line.startsWith(" ") && !line.startsWith("\t")) break + const indent = line.length - line.trimStart().length + if (directIndent === null) directIndent = indent const trimmed = line.trim() - if (trimmed.startsWith("- ")) return "list" + if (indent === directIndent && trimmed.startsWith("- ")) return "list" + if (indent !== directIndent) continue const colonIdx = trimmed.indexOf(":") if (colonIdx === -1) continue const key = trimmed.slice(0, colonIdx).trim()