diff --git a/.changeset/skill-install-frontmatter.md b/.changeset/skill-install-frontmatter.md new file mode 100644 index 00000000..9ec40f79 --- /dev/null +++ b/.changeset/skill-install-frontmatter.md @@ -0,0 +1,5 @@ +--- +"clerk": patch +--- + +Fix `clerk skill install` failing with `No valid skills found` on published releases. The bundled skill's frontmatter now parses as strict YAML. diff --git a/packages/cli-core/src/commands/skill/install.test.ts b/packages/cli-core/src/commands/skill/install.test.ts index c3338677..73b13be1 100644 --- a/packages/cli-core/src/commands/skill/install.test.ts +++ b/packages/cli-core/src/commands/skill/install.test.ts @@ -2,6 +2,7 @@ import { test, expect, describe } from "bun:test"; import { existsSync } from "node:fs"; import { readFile, stat } from "node:fs/promises"; import { join } from "node:path"; +import YAML from "yaml"; import { buildSkillsArgs, renderSkillVersionPlaceholder, withStagedClerkSkill } from "./install.ts"; describe("buildSkillsArgs", () => { @@ -136,6 +137,27 @@ describe("withStagedClerkSkill version rendering", () => { }); }); +describe("bundled SKILL.md frontmatter", () => { + // Regression guard: the upstream `skills` CLI parses SKILL.md frontmatter as + // strict YAML and silently drops skills whose frontmatter fails to parse. + // An unquoted `: ` inside the description (e.g. `raw HTTP: it handles`) + // triggers "Nested mappings are not allowed in compact mappings" and makes + // `clerk skill install` fail with "No valid skills found". + test("parses as YAML with name and description strings", async () => { + await withStagedClerkSkill(undefined, async (stageDir) => { + const content = await readFile(join(stageDir, "clerk/SKILL.md"), "utf8"); + const frontmatter = content.match(/^---\n([\s\S]*?)\n---/)?.[1]; + expect(frontmatter, "SKILL.md must have YAML frontmatter").toBeDefined(); + + const parsed = YAML.parse(frontmatter!); + expect(typeof parsed.name).toBe("string"); + expect(typeof parsed.description).toBe("string"); + expect(parsed.name.length).toBeGreaterThan(0); + expect(parsed.description.length).toBeGreaterThan(0); + }); + }); +}); + describe("renderSkillVersionPlaceholder", () => { test("replaces {{CLI_VERSION}} with the provided version", () => { const result = renderSkillVersionPlaceholder("Pinned: `bunx clerk@{{CLI_VERSION}}`.", "1.2.3"); diff --git a/skills/clerk/SKILL.md b/skills/clerk/SKILL.md index 9d09b88f..0ce9f6f3 100644 --- a/skills/clerk/SKILL.md +++ b/skills/clerk/SKILL.md @@ -1,6 +1,12 @@ --- name: clerk -description: Operate the Clerk CLI (`clerk` binary) for authentication, user/org/session management, instance config, env keys, and any Clerk Backend or Platform API call. Use when the user mentions Clerk management tasks, "list clerk users", "create a clerk user", "update organization", "pull clerk config", "clerk env pull", "clerk doctor", "clerk api", or any ad-hoc Clerk API request. Prefer the CLI over raw HTTP: it handles auth, key resolution, app/instance targeting, and formatting automatically. +description: >- + Operate the Clerk CLI (`clerk` binary) for authentication, user/org/session management, + instance config, env keys, and any Clerk Backend or Platform API call. Use when the user + mentions Clerk management tasks, "list clerk users", "create a clerk user", "update + organization", "pull clerk config", "clerk env pull", "clerk doctor", "clerk api", or + any ad-hoc Clerk API request. Prefer the CLI over raw HTTP: it handles auth, key + resolution, app/instance targeting, and formatting automatically. --- # Clerk CLI