diff --git a/.github/workflows/check-skill-names.yml b/.github/workflows/check-skill-names.yml new file mode 100644 index 0000000..d1b22e7 --- /dev/null +++ b/.github/workflows/check-skill-names.yml @@ -0,0 +1,17 @@ +name: Skill names + +on: + pull_request: + push: + branches: + - main + +jobs: + skill-names: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - run: node scripts/check-skill-names.mjs diff --git a/scripts/check-skill-names.mjs b/scripts/check-skill-names.mjs new file mode 100644 index 0000000..9878382 --- /dev/null +++ b/scripts/check-skill-names.mjs @@ -0,0 +1,52 @@ +#!/usr/bin/env node +import { execFileSync } from "node:child_process"; +import fs from "node:fs"; +import path from "node:path"; +import process from "node:process"; + +const files = execFileSync("git", ["ls-files", "-z", "--", "*SKILL.md"], { + encoding: "utf8", +}) + .split("\0") + .filter(Boolean); + +const frontmatterName = (raw) => { + const lines = raw.split(/\r?\n/); + if (lines[0] !== "---") return undefined; + const end = lines.indexOf("---", 1); + if (end === -1) return undefined; + for (const line of lines.slice(1, end)) { + const match = /^name:\s*(.*)$/.exec(line); + if (!match) continue; + const trimmed = match[1].trim(); + if ( + trimmed.length >= 2 && + ((trimmed.startsWith('"') && trimmed.endsWith('"')) || + (trimmed.startsWith("'") && trimmed.endsWith("'"))) + ) { + return trimmed.slice(1, -1).trim(); + } + return trimmed; + } + return undefined; +}; + +const records = files.map((file) => ({ + path: file, + folder: path.basename(path.dirname(file)), + name: frontmatterName(fs.readFileSync(file, "utf8")), +})); + +const mismatches = records.filter((record) => record.name !== record.folder); +for (const record of mismatches) { + if (record.name === undefined) { + console.error(`${record.path}: missing frontmatter name`); + } else { + console.error( + `${record.path}: name "${record.name}" does not match folder "${record.folder}"`, + ); + } +} +if (mismatches.length) process.exit(1); + +console.log(`${records.length} skill names match their folders`); diff --git a/skills/make-bot-ui/SKILL.md b/skills/make-bot-ui/SKILL.md index 285df75..446342c 100644 --- a/skills/make-bot-ui/SKILL.md +++ b/skills/make-bot-ui/SKILL.md @@ -1,5 +1,5 @@ --- -name: Make Bot UI +name: make-bot-ui description: >- Use when building a custom UI (page, dashboard, buttons) that should wake a Grok Bot over a webhook, when the user must provide a webhook sender key, or diff --git a/skills/odd-mode/SKILL.md b/skills/odd-mode/SKILL.md index 2fbcca6..681ea21 100644 --- a/skills/odd-mode/SKILL.md +++ b/skills/odd-mode/SKILL.md @@ -1,5 +1,5 @@ --- -name: Odium Mode +name: odd-mode description: odium's agent style for concise, detailed responses, deliberate subagents, unslopped prose, simple code, and verified work. Use for odium, /odd-mode, or requests to work in this style. disable-model-invocation: true mode: true