From df1c26ce639edf2fc156735a129a98f6094f7985 Mon Sep 17 00:00:00 2001 From: Paul Bakaus Date: Fri, 20 Mar 2026 23:33:22 -0700 Subject: [PATCH] Fix user-invokable -> user-invocable spelling across entire codebase PR #50 fixed the output SKILL.md files but the source files, build scripts, tests, docs, and server code still used the wrong spelling. Claude Code expects `user-invocable` (with c) for slash command autocomplete to work. Co-Authored-By: Claude Opus 4.6 (1M context) --- .claude-plugin/plugin.json | 2 +- .impeccable.md | 19 ++++++++++++ CLAUDE.md | 2 +- DEVELOP.md | 18 ++++++------ public/index.html | 2 +- scripts/build.js | 10 +++---- scripts/lib/transformers/agents.js | 16 +++++----- scripts/lib/transformers/claude-code.js | 12 ++++---- scripts/lib/transformers/codex.js | 22 +++++++------- scripts/lib/transformers/cursor.js | 10 +++---- scripts/lib/transformers/gemini.js | 16 +++++----- scripts/lib/transformers/kiro.js | 8 ++--- scripts/lib/transformers/opencode.js | 12 ++++---- scripts/lib/transformers/pi.js | 8 ++--- scripts/lib/utils.js | 4 +-- server/lib/api-handlers.js | 6 ++-- source/skills/adapt/SKILL.md | 2 +- source/skills/animate/SKILL.md | 2 +- source/skills/arrange/SKILL.md | 2 +- source/skills/audit/SKILL.md | 2 +- source/skills/bolder/SKILL.md | 2 +- source/skills/clarify/SKILL.md | 2 +- source/skills/colorize/SKILL.md | 2 +- source/skills/critique/SKILL.md | 2 +- source/skills/delight/SKILL.md | 2 +- source/skills/distill/SKILL.md | 2 +- source/skills/extract/SKILL.md | 2 +- source/skills/harden/SKILL.md | 2 +- source/skills/normalize/SKILL.md | 2 +- source/skills/onboard/SKILL.md | 2 +- source/skills/optimize/SKILL.md | 2 +- source/skills/overdrive/SKILL.md | 2 +- source/skills/polish/SKILL.md | 2 +- source/skills/quieter/SKILL.md | 2 +- source/skills/teach-impeccable/SKILL.md | 2 +- source/skills/typeset/SKILL.md | 2 +- tests/build.test.js | 12 ++++---- tests/lib/transformers/agents.test.js | 34 +++++++++++----------- tests/lib/transformers/claude-code.test.js | 24 +++++++-------- tests/lib/transformers/codex.test.js | 24 +++++++-------- tests/lib/transformers/cursor.test.js | 6 ++-- tests/lib/transformers/gemini.test.js | 20 ++++++------- tests/lib/transformers/kiro.test.js | 24 +++++++-------- tests/lib/transformers/opencode.test.js | 32 ++++++++++---------- tests/lib/transformers/pi.test.js | 24 +++++++-------- tests/lib/utils.test.js | 26 ++++++++--------- 46 files changed, 226 insertions(+), 207 deletions(-) create mode 100644 .impeccable.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index dadbc8834..5260451c1 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "impeccable", - "description": "Design vocabulary and skills for frontend development. Includes 21 skills (20 user-invokable: /polish, /distill, /audit, /typeset, /overdrive, etc.) and an enhanced frontend-design skill with curated anti-patterns.", + "description": "Design vocabulary and skills for frontend development. Includes 21 skills (20 user-invocable: /polish, /distill, /audit, /typeset, /overdrive, etc.) and an enhanced frontend-design skill with curated anti-patterns.", "version": "1.5.1", "author": { "name": "Paul Bakaus", diff --git a/.impeccable.md b/.impeccable.md new file mode 100644 index 000000000..15be2e4ce --- /dev/null +++ b/.impeccable.md @@ -0,0 +1,19 @@ +## Design Context + +### Users +Frontend and full-stack developers who use AI coding tools (Cursor, Claude Code, Gemini CLI, Codex CLI, etc.) and want better design output from their AI. They land on the site from GitHub, social media, or word of mouth, already aware that AI-generated UIs have quality problems. They're looking for a practical solution, not education about the problem. + +### Brand Personality +Expert, opinionated, refined. Impeccable speaks with an authoritative design voice -- confident taste, editorial quality, zero hedging. It's the design director in the room who knows exactly what's wrong and how to fix it. + +### Aesthetic Direction +- **Visual tone**: Editorial precision meets fluid motion. Light, high-contrast, typographically bold. The site itself must be proof of what Impeccable enables -- it should practice what it preaches. +- **Theme**: Light mode with warm paper tones, vibrant magenta/rose accent, serif display + clean sans body +- **Anti-references**: Generic AI tool marketing (dark mode, purple gradients, glassmorphism, neon accents). The site should be the antithesis of everything it critiques. + +### Design Principles +1. **Practice what you preach** -- the site must pass its own anti-pattern tests with flying colors +2. **Show, don't tell** -- demonstrate design quality through execution, not just words +3. **Expert confidence** -- no hedging, no "maybe consider." Direct, opinionated, decisive. +4. **Editorial over marketing** -- feels like a design publication, not a SaaS landing page +5. **Purposeful restraint** -- every element earns its place; nothing decorative without function diff --git a/CLAUDE.md b/CLAUDE.md index 33de089a2..a94d60543 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -53,7 +53,7 @@ When bumping the version, update **all** of these locations to keep them in sync ## Adding New Skills -When adding a new user-invokable skill, update the command count in **all** of these locations: +When adding a new user-invocable skill, update the command count in **all** of these locations: - `public/index.html` → meta descriptions, hero box, section lead - `public/cheatsheet.html` → meta description, subtitle, `commandCategories`, `commandRelationships` diff --git a/DEVELOP.md b/DEVELOP.md index 16219237e..bce128a66 100644 --- a/DEVELOP.md +++ b/DEVELOP.md @@ -9,7 +9,7 @@ This repository uses a **feature-rich source format** that transforms into provi ### Why This Approach? Different providers have different capabilities: -- **Claude Code, OpenCode**: Full metadata — args, user-invokable, allowed-tools, license, compatibility +- **Claude Code, OpenCode**: Full metadata — args, user-invocable, allowed-tools, license, compatibility - **Codex, Agents**: Args converted to `argument-hint` format - **Gemini**: Minimal frontmatter, `{{arg}}` placeholders become `{{args}}` - **Cursor, Kiro, Pi**: Basic frontmatter (name, description, license/compatibility) @@ -34,8 +34,8 @@ Your skill instructions here... **Frontmatter fields** (based on [Agent Skills spec](https://agentskills.io/specification)): - `name` (required): Skill identifier (1-64 chars, lowercase/numbers/hyphens) - `description` (required): What the skill provides (1-1024 chars) -- `user-invokable` (optional): Boolean — if `true`, the skill can be invoked as a slash command -- `args` (optional): Array of argument objects (for user-invokable skills) +- `user-invocable` (optional): Boolean — if `true`, the skill can be invoked as a slash command +- `args` (optional): Array of argument objects (for user-invocable skills) - `name`: Argument identifier - `description`: What it's for - `required`: Boolean (defaults to false) @@ -90,27 +90,27 @@ All providers output skills to `dist/{provider}/.{config}/skills/{name}/SKILL.md ### Claude Code (Full Featured) - Output: `dist/claude-code/.claude/skills/{name}/SKILL.md` -- Frontmatter: name, description, user-invokable, args, license, compatibility, metadata, allowed-tools +- Frontmatter: name, description, user-invocable, args, license, compatibility, metadata, allowed-tools - Preserves `{{arg}}` placeholders in body ### OpenCode (Full Featured) - Output: `dist/opencode/.opencode/skills/{name}/SKILL.md` -- Frontmatter: name, description, user-invokable, args, license, compatibility, metadata, allowed-tools +- Frontmatter: name, description, user-invocable, args, license, compatibility, metadata, allowed-tools - Same format as Claude Code ### Gemini CLI - Output: `dist/gemini/.gemini/skills/{name}/SKILL.md` - Frontmatter: name, description -- For user-invokable skills: remaining `{{arg}}` placeholders become `{{args}}` +- For user-invocable skills: remaining `{{arg}}` placeholders become `{{args}}` ### Codex CLI - Output: `dist/codex/.codex/skills/{name}/SKILL.md` - Frontmatter: name, description, argument-hint, license -- For user-invokable skills: `{{argname}}` → `$ARGNAME` (uppercase) +- For user-invocable skills: `{{argname}}` → `$ARGNAME` (uppercase) ### Agents (VS Code Copilot, Antigravity) - Output: `dist/agents/.agents/skills/{name}/SKILL.md` -- Frontmatter: name, description, user-invokable, argument-hint +- Frontmatter: name, description, user-invocable, argument-hint - Args converted to `argument-hint` format (e.g., ` [FORMAT=]`) ### Kiro @@ -170,7 +170,7 @@ The build system uses a modular architecture under `scripts/`: - `transformClaudeCode()`: Full metadata with args and allowed-tools - `transformGemini()`: Minimal frontmatter, `{{arg}}` → `{{args}}` - `transformCodex()`: Args → argument-hint, `{{arg}}` → `$ARGNAME` -- `transformAgents()`: Args → argument-hint, user-invokable flag +- `transformAgents()`: Args → argument-hint, user-invocable flag - `transformKiro()`: Basic frontmatter with license/compatibility/metadata - `transformOpenCode()`: Full metadata (same as Claude Code) - `transformPi()`: Basic frontmatter with license/compatibility/metadata diff --git a/public/index.html b/public/index.html index 26aa638e9..849179cb7 100644 --- a/public/index.html +++ b/public/index.html @@ -362,7 +362,7 @@ March 4, 2026
    -
  • Unified skills architecture — commands are now skills with user-invokable: true
  • +
  • Unified skills architecture — commands are now skills with user-invocable: true
  • Added VS Code Copilot and Google Antigravity support (.agents/skills/)
  • New install flow: npx skills add as primary, universal ZIP as fallback
  • Added universal ZIP containing all 5 provider directories
  • diff --git a/scripts/build.js b/scripts/build.js index 2e51691b6..ff576d3fe 100644 --- a/scripts/build.js +++ b/scripts/build.js @@ -200,12 +200,12 @@ function generateApiData(buildDir, skills, patterns) { id: path.basename(path.dirname(s.filePath)), name: s.name, description: s.description, - userInvokable: s.userInvokable, + userInvocable: s.userInvocable, })); fs.writeFileSync(path.join(apiDir, 'skills.json'), JSON.stringify(skillsData)); - // commands.json (user-invokable skills only) - const commandsData = skillsData.filter(s => s.userInvokable); + // commands.json (user-invocable skills only) + const commandsData = skillsData.filter(s => s.userInvocable); fs.writeFileSync(path.join(apiDir, 'commands.json'), JSON.stringify(commandsData)); // patterns.json @@ -337,8 +337,8 @@ async function build() { // Read source files (unified skills architecture) const { skills } = readSourceFiles(ROOT_DIR); const patterns = readPatterns(ROOT_DIR); - const userInvokableCount = skills.filter(s => s.userInvokable).length; - console.log(`📖 Read ${skills.length} skills (${userInvokableCount} user-invokable) and ${patterns.patterns.length + patterns.antipatterns.length} pattern categories\n`); + const userInvocableCount = skills.filter(s => s.userInvocable).length; + console.log(`📖 Read ${skills.length} skills (${userInvocableCount} user-invocable) and ${patterns.patterns.length + patterns.antipatterns.length} pattern categories\n`); // Transform for each provider transformCursor(skills, DIST_DIR, patterns); diff --git a/scripts/lib/transformers/agents.js b/scripts/lib/transformers/agents.js index 80c141d66..7e27fbf6b 100644 --- a/scripts/lib/transformers/agents.js +++ b/scripts/lib/transformers/agents.js @@ -5,9 +5,9 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho * Agents Transformer (VS Code Copilot + Antigravity) * * All skills output to .agents/skills/{name}/SKILL.md - * Frontmatter: name, description, user-invokable (if true), argument-hint (from args) + * Frontmatter: name, description, user-invocable (if true), argument-hint (from args) * - * @param {Array} skills - All skills (including user-invokable ones) + * @param {Array} skills - All skills (including user-invocable ones) * @param {string} distDir - Distribution output directory * @param {Object} patterns - Design patterns data (unused) * @param {Object} options - Optional settings @@ -21,7 +21,7 @@ export function transformAgents(skills, distDir, patterns = null, options = {}) ensureDir(skillsDir); const allSkillNames = skills.map(s => s.name); - const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`); + const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`); let refCount = 0; for (const skill of skills) { const skillName = `${prefix}${skill.name}`; @@ -32,10 +32,10 @@ export function transformAgents(skills, distDir, patterns = null, options = {}) description: skill.description, }; - if (skill.userInvokable) frontmatterObj['user-invokable'] = true; + if (skill.userInvocable) frontmatterObj['user-invocable'] = true; - // Build argument-hint from args array for user-invokable skills - if (skill.userInvokable && skill.args && skill.args.length > 0) { + // Build argument-hint from args array for user-invocable skills + if (skill.userInvocable && skill.args && skill.args.length > 0) { const hints = skill.args.map(arg => { return arg.required ? `<${arg.name}>` : `[${arg.name.toUpperCase()}=]`; }); @@ -62,8 +62,8 @@ export function transformAgents(skills, distDir, patterns = null, options = {}) } } - const userInvokableCount = skills.filter(s => s.userInvokable).length; + const userInvocableCount = skills.filter(s => s.userInvocable).length; const refInfo = refCount > 0 ? ` (${refCount} reference files)` : ''; const prefixInfo = prefix ? ` [${prefix}prefixed]` : ''; - console.log(`✓ Agents${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`); + console.log(`✓ Agents${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`); } diff --git a/scripts/lib/transformers/claude-code.js b/scripts/lib/transformers/claude-code.js index b7db1df40..365647bda 100644 --- a/scripts/lib/transformers/claude-code.js +++ b/scripts/lib/transformers/claude-code.js @@ -7,11 +7,11 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho * All skills output to .claude/skills/{name}/SKILL.md * User-invokable skills get args support in frontmatter. * - * @param {Array} skills - All skills (including user-invokable ones) + * @param {Array} skills - All skills (including user-invocable ones) * @param {string} distDir - Distribution output directory * @param {Object} patterns - Design patterns data (unused, kept for interface consistency) * @param {Object} options - Optional settings - * @param {string} options.prefix - Prefix to add to user-invokable skill names (e.g., 'i-') + * @param {string} options.prefix - Prefix to add to user-invocable skill names (e.g., 'i-') * @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed') */ export function transformClaudeCode(skills, distDir, patterns = null, options = {}) { @@ -23,7 +23,7 @@ export function transformClaudeCode(skills, distDir, patterns = null, options = ensureDir(skillsDir); const allSkillNames = skills.map(s => s.name); - const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`); + const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`); let refCount = 0; for (const skill of skills) { const skillName = `${prefix}${skill.name}`; @@ -34,7 +34,7 @@ export function transformClaudeCode(skills, distDir, patterns = null, options = description: skill.description, }; - if (skill.userInvokable) frontmatterObj['user-invokable'] = true; + if (skill.userInvocable) frontmatterObj['user-invocable'] = true; if (skill.args && skill.args.length > 0) frontmatterObj.args = skill.args; if (skill.license) frontmatterObj.license = skill.license; if (skill.compatibility) frontmatterObj.compatibility = skill.compatibility; @@ -61,8 +61,8 @@ export function transformClaudeCode(skills, distDir, patterns = null, options = } } - const userInvokableCount = skills.filter(s => s.userInvokable).length; + const userInvocableCount = skills.filter(s => s.userInvocable).length; const refInfo = refCount > 0 ? ` (${refCount} reference files)` : ''; const prefixInfo = prefix ? ` [${prefix}prefixed]` : ''; - console.log(`✓ Claude Code${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`); + console.log(`✓ Claude Code${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`); } diff --git a/scripts/lib/transformers/codex.js b/scripts/lib/transformers/codex.js index e96c49dbc..2192e3ee3 100644 --- a/scripts/lib/transformers/codex.js +++ b/scripts/lib/transformers/codex.js @@ -5,14 +5,14 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho * Codex Transformer (Skills Only) * * All skills output to .codex/skills/{name}/SKILL.md - * Frontmatter: name, description, argument-hint (from args for user-invokable) - * For user-invokable skills: {{argname}} becomes $ARGNAME in body + * Frontmatter: name, description, argument-hint (from args for user-invocable) + * For user-invocable skills: {{argname}} becomes $ARGNAME in body * - * @param {Array} skills - All skills (including user-invokable ones) + * @param {Array} skills - All skills (including user-invocable ones) * @param {string} distDir - Distribution output directory * @param {Object} patterns - Design patterns data (unused) * @param {Object} options - Optional settings - * @param {string} options.prefix - Prefix to add to user-invokable skill names (e.g., 'i-') + * @param {string} options.prefix - Prefix to add to user-invocable skill names (e.g., 'i-') * @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed') */ export function transformCodex(skills, distDir, patterns = null, options = {}) { @@ -24,7 +24,7 @@ export function transformCodex(skills, distDir, patterns = null, options = {}) { ensureDir(skillsDir); const allSkillNames = skills.map(s => s.name); - const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`); + const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`); let refCount = 0; for (const skill of skills) { const skillName = `${prefix}${skill.name}`; @@ -35,8 +35,8 @@ export function transformCodex(skills, distDir, patterns = null, options = {}) { description: skill.description, }; - // Build argument-hint from args array for user-invokable skills - if (skill.userInvokable && skill.args && skill.args.length > 0) { + // Build argument-hint from args array for user-invocable skills + if (skill.userInvocable && skill.args && skill.args.length > 0) { const hints = skill.args.map(arg => { return arg.required ? `<${arg.name}>` : `[${arg.name.toUpperCase()}=]`; }); @@ -48,8 +48,8 @@ export function transformCodex(skills, distDir, patterns = null, options = {}) { let skillBody = replacePlaceholders(skill.body, 'codex', commandNames); if (prefix) skillBody = prefixSkillReferences(skillBody, prefix, allSkillNames); - // For user-invokable skills, transform remaining {{argname}} to $ARGNAME - if (skill.userInvokable) { + // For user-invocable skills, transform remaining {{argname}} to $ARGNAME + if (skill.userInvocable) { skillBody = skillBody.replace(/\{\{([^}]+)\}\}/g, (match, argName) => { return `$${argName.toUpperCase()}`; }); @@ -72,8 +72,8 @@ export function transformCodex(skills, distDir, patterns = null, options = {}) { } } - const userInvokableCount = skills.filter(s => s.userInvokable).length; + const userInvocableCount = skills.filter(s => s.userInvocable).length; const refInfo = refCount > 0 ? ` (${refCount} reference files)` : ''; const prefixInfo = prefix ? ` [${prefix}prefixed]` : ''; - console.log(`✓ Codex${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`); + console.log(`✓ Codex${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`); } diff --git a/scripts/lib/transformers/cursor.js b/scripts/lib/transformers/cursor.js index f5123f1d3..9d91d7d9f 100644 --- a/scripts/lib/transformers/cursor.js +++ b/scripts/lib/transformers/cursor.js @@ -7,11 +7,11 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho * All skills output to .cursor/skills/{name}/SKILL.md * Frontmatter: name, description, license * - * @param {Array} skills - All skills (including user-invokable ones) + * @param {Array} skills - All skills (including user-invocable ones) * @param {string} distDir - Distribution output directory * @param {Object} patterns - Design patterns data (unused) * @param {Object} options - Optional settings - * @param {string} options.prefix - Prefix to add to user-invokable skill names (e.g., 'i-') + * @param {string} options.prefix - Prefix to add to user-invocable skill names (e.g., 'i-') * @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed') */ export function transformCursor(skills, distDir, patterns = null, options = {}) { @@ -23,7 +23,7 @@ export function transformCursor(skills, distDir, patterns = null, options = {}) ensureDir(skillsDir); const allSkillNames = skills.map(s => s.name); - const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`); + const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`); let refCount = 0; for (const skill of skills) { const skillName = `${prefix}${skill.name}`; @@ -55,8 +55,8 @@ export function transformCursor(skills, distDir, patterns = null, options = {}) } } - const userInvokableCount = skills.filter(s => s.userInvokable).length; + const userInvocableCount = skills.filter(s => s.userInvocable).length; const refInfo = refCount > 0 ? ` (${refCount} reference files)` : ''; const prefixInfo = prefix ? ` [${prefix}prefixed]` : ''; - console.log(`✓ Cursor${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`); + console.log(`✓ Cursor${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`); } diff --git a/scripts/lib/transformers/gemini.js b/scripts/lib/transformers/gemini.js index ead1b1223..4b1a6b7f0 100644 --- a/scripts/lib/transformers/gemini.js +++ b/scripts/lib/transformers/gemini.js @@ -6,13 +6,13 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho * * All skills output to .gemini/skills/{name}/SKILL.md * Frontmatter: name, description - * For user-invokable skills: {{arg}} placeholders become {{args}} in body + * For user-invocable skills: {{arg}} placeholders become {{args}} in body * - * @param {Array} skills - All skills (including user-invokable ones) + * @param {Array} skills - All skills (including user-invocable ones) * @param {string} distDir - Distribution output directory * @param {Object} patterns - Design patterns data (unused) * @param {Object} options - Optional settings - * @param {string} options.prefix - Prefix to add to user-invokable skill names (e.g., 'i-') + * @param {string} options.prefix - Prefix to add to user-invocable skill names (e.g., 'i-') * @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed') */ export function transformGemini(skills, distDir, patterns = null, options = {}) { @@ -24,7 +24,7 @@ export function transformGemini(skills, distDir, patterns = null, options = {}) ensureDir(skillsDir); const allSkillNames = skills.map(s => s.name); - const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`); + const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`); let refCount = 0; for (const skill of skills) { const skillName = `${prefix}${skill.name}`; @@ -37,8 +37,8 @@ export function transformGemini(skills, distDir, patterns = null, options = {}) let skillBody = replacePlaceholders(skill.body, 'gemini', commandNames); if (prefix) skillBody = prefixSkillReferences(skillBody, prefix, allSkillNames); - // For user-invokable skills, replace remaining {{arg}} placeholders with {{args}} - if (skill.userInvokable) { + // For user-invocable skills, replace remaining {{arg}} placeholders with {{args}} + if (skill.userInvocable) { skillBody = skillBody.replace(/\{\{[^}]+\}\}/g, '{{args}}'); } @@ -59,8 +59,8 @@ export function transformGemini(skills, distDir, patterns = null, options = {}) } } - const userInvokableCount = skills.filter(s => s.userInvokable).length; + const userInvocableCount = skills.filter(s => s.userInvocable).length; const refInfo = refCount > 0 ? ` (${refCount} reference files)` : ''; const prefixInfo = prefix ? ` [${prefix}prefixed]` : ''; - console.log(`✓ Gemini${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`); + console.log(`✓ Gemini${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`); } diff --git a/scripts/lib/transformers/kiro.js b/scripts/lib/transformers/kiro.js index 4d20ca728..84a334b1e 100644 --- a/scripts/lib/transformers/kiro.js +++ b/scripts/lib/transformers/kiro.js @@ -7,7 +7,7 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho * All skills output to .kiro/skills/{name}/SKILL.md * Frontmatter: name, description, license, compatibility, metadata * - * @param {Array} skills - All skills (including user-invokable ones) + * @param {Array} skills - All skills (including user-invocable ones) * @param {string} distDir - Distribution output directory * @param {Object} patterns - Design patterns data (unused) * @param {Object} options - Optional settings @@ -23,7 +23,7 @@ export function transformKiro(skills, distDir, patterns = null, options = {}) { ensureDir(skillsDir); const allSkillNames = skills.map(s => s.name); - const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`); + const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`); let refCount = 0; for (const skill of skills) { const skillName = `${prefix}${skill.name}`; @@ -58,8 +58,8 @@ export function transformKiro(skills, distDir, patterns = null, options = {}) { } } - const userInvokableCount = skills.filter(s => s.userInvokable).length; + const userInvocableCount = skills.filter(s => s.userInvocable).length; const refInfo = refCount > 0 ? ` (${refCount} reference files)` : ''; const prefixInfo = prefix ? ` [${prefix}prefixed]` : ''; - console.log(`✓ Kiro${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`); + console.log(`✓ Kiro${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`); } diff --git a/scripts/lib/transformers/opencode.js b/scripts/lib/transformers/opencode.js index 838233eea..05181d964 100644 --- a/scripts/lib/transformers/opencode.js +++ b/scripts/lib/transformers/opencode.js @@ -14,11 +14,11 @@ import { * All skills output to .opencode/skills/{name}/SKILL.md * User-invokable skills get args support in frontmatter. * - * @param {Array} skills - All skills (including user-invokable ones) + * @param {Array} skills - All skills (including user-invocable ones) * @param {string} distDir - Distribution output directory * @param {Object} patterns - Design patterns data (unused, kept for interface consistency) * @param {Object} options - Optional settings - * @param {string} options.prefix - Prefix to add to user-invokable skill names (e.g., 'i-') + * @param {string} options.prefix - Prefix to add to user-invocable skill names (e.g., 'i-') * @param {string} options.outputSuffix - Suffix for output directory (e.g., '-prefixed') */ export function transformOpenCode( @@ -36,7 +36,7 @@ export function transformOpenCode( const allSkillNames = skills.map((s) => s.name); const commandNames = skills - .filter((s) => s.userInvokable) + .filter((s) => s.userInvocable) .map((s) => `${prefix}${s.name}`); let refCount = 0; for (const skill of skills) { @@ -48,7 +48,7 @@ export function transformOpenCode( description: skill.description, }; - if (skill.userInvokable) frontmatterObj['user-invokable'] = true; + if (skill.userInvocable) frontmatterObj['user-invocable'] = true; if (skill.args && skill.args.length > 0) frontmatterObj.args = skill.args; if (skill.license) frontmatterObj.license = skill.license; if (skill.compatibility) frontmatterObj.compatibility = skill.compatibility; @@ -77,8 +77,8 @@ export function transformOpenCode( } } - const userInvokableCount = skills.filter((s) => s.userInvokable).length; + const userInvocableCount = skills.filter((s) => s.userInvocable).length; const refInfo = refCount > 0 ? ` (${refCount} reference files)` : ''; const prefixInfo = prefix ? ` [${prefix}prefixed]` : ''; - console.log(`✓ OpenCode${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`); + console.log(`✓ OpenCode${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`); } diff --git a/scripts/lib/transformers/pi.js b/scripts/lib/transformers/pi.js index d78d4a59c..88cf97aea 100644 --- a/scripts/lib/transformers/pi.js +++ b/scripts/lib/transformers/pi.js @@ -7,7 +7,7 @@ import { cleanDir, ensureDir, writeFile, generateYamlFrontmatter, replacePlaceho * All skills output to .pi/skills/{name}/SKILL.md * Frontmatter: name, description, license, compatibility, metadata * - * @param {Array} skills - All skills (including user-invokable ones) + * @param {Array} skills - All skills (including user-invocable ones) * @param {string} distDir - Distribution output directory * @param {Object} patterns - Design patterns data (unused) * @param {Object} options - Optional settings @@ -23,7 +23,7 @@ export function transformPi(skills, distDir, patterns = null, options = {}) { ensureDir(skillsDir); const allSkillNames = skills.map(s => s.name); - const commandNames = skills.filter(s => s.userInvokable).map(s => `${prefix}${s.name}`); + const commandNames = skills.filter(s => s.userInvocable).map(s => `${prefix}${s.name}`); let refCount = 0; for (const skill of skills) { const skillName = `${prefix}${skill.name}`; @@ -58,8 +58,8 @@ export function transformPi(skills, distDir, patterns = null, options = {}) { } } - const userInvokableCount = skills.filter(s => s.userInvokable).length; + const userInvocableCount = skills.filter(s => s.userInvocable).length; const refInfo = refCount > 0 ? ` (${refCount} reference files)` : ''; const prefixInfo = prefix ? ` [${prefix}prefixed]` : ''; - console.log(`✓ Pi${prefixInfo}: ${skills.length} skills (${userInvokableCount} user-invokable)${refInfo}`); + console.log(`✓ Pi${prefixInfo}: ${skills.length} skills (${userInvocableCount} user-invocable)${refInfo}`); } diff --git a/scripts/lib/utils.js b/scripts/lib/utils.js index ba741dd7d..5b58795c4 100644 --- a/scripts/lib/utils.js +++ b/scripts/lib/utils.js @@ -104,7 +104,7 @@ export function readFilesRecursive(dir, fileList = []) { /** * Read and parse all source files (unified skills architecture) * All source lives in source/skills/{name}/SKILL.md - * Returns { skills } where each skill has userInvokable flag + * Returns { skills } where each skill has userInvocable flag */ export function readSourceFiles(rootDir) { const skillsDir = path.join(rootDir, 'source/skills'); @@ -147,7 +147,7 @@ export function readSourceFiles(rootDir) { compatibility: frontmatter.compatibility || '', metadata: frontmatter.metadata || null, allowedTools: frontmatter['allowed-tools'] || '', - userInvokable: frontmatter['user-invokable'] === true || frontmatter['user-invokable'] === 'true', + userInvocable: frontmatter['user-invocable'] === true || frontmatter['user-invocable'] === 'true', args: frontmatter.args || [], context: frontmatter.context || null, body, diff --git a/server/lib/api-handlers.js b/server/lib/api-handlers.js index 288fdbc5a..c27ab428d 100644 --- a/server/lib/api-handlers.js +++ b/server/lib/api-handlers.js @@ -40,17 +40,17 @@ export async function getSkills() { id: entry.name, name: frontmatter.name || entry.name, description: frontmatter.description || "No description available", - userInvokable: frontmatter['user-invokable'] === true || frontmatter['user-invokable'] === 'true', + userInvocable: frontmatter['user-invocable'] === true || frontmatter['user-invocable'] === 'true', }); } return skills; } -// Read commands (user-invokable skills) +// Read commands (user-invocable skills) export async function getCommands() { const allSkills = await getSkills(); - return allSkills.filter(s => s.userInvokable); + return allSkills.filter(s => s.userInvocable); } // Get command/skill source content diff --git a/source/skills/adapt/SKILL.md b/source/skills/adapt/SKILL.md index 1a3773596..0dc9ca859 100644 --- a/source/skills/adapt/SKILL.md +++ b/source/skills/adapt/SKILL.md @@ -8,7 +8,7 @@ args: - name: context description: What to adapt for (mobile, tablet, desktop, print, email, etc.) required: false -user-invokable: true +user-invocable: true --- Adapt existing designs to work effectively across different contexts - different screen sizes, devices, platforms, or use cases. diff --git a/source/skills/animate/SKILL.md b/source/skills/animate/SKILL.md index fc6aeba83..8789e8e34 100644 --- a/source/skills/animate/SKILL.md +++ b/source/skills/animate/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or component to animate (optional) required: false -user-invokable: true +user-invocable: true --- Analyze a feature and strategically add animations and micro-interactions that enhance understanding, provide feedback, and create delight. diff --git a/source/skills/arrange/SKILL.md b/source/skills/arrange/SKILL.md index 98eaea2b9..dc3a889cf 100644 --- a/source/skills/arrange/SKILL.md +++ b/source/skills/arrange/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or component to improve layout for (optional) required: false -user-invokable: true +user-invocable: true --- Assess and improve layout and spacing that feels monotonous, crowded, or structurally weak — turning generic arrangements into intentional, rhythmic compositions. diff --git a/source/skills/audit/SKILL.md b/source/skills/audit/SKILL.md index e30b036f6..7e70200e1 100644 --- a/source/skills/audit/SKILL.md +++ b/source/skills/audit/SKILL.md @@ -5,7 +5,7 @@ args: - name: area description: The feature or area to audit (optional) required: false -user-invokable: true +user-invocable: true --- Run systematic quality checks and generate a comprehensive audit report with prioritized issues and actionable recommendations. Don't fix issues - document them for other commands to address. diff --git a/source/skills/bolder/SKILL.md b/source/skills/bolder/SKILL.md index 38cffc374..387b174a5 100644 --- a/source/skills/bolder/SKILL.md +++ b/source/skills/bolder/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or component to make bolder (optional) required: false -user-invokable: true +user-invocable: true --- Increase visual impact and personality in designs that are too safe, generic, or visually underwhelming, creating more engaging and memorable experiences. diff --git a/source/skills/clarify/SKILL.md b/source/skills/clarify/SKILL.md index 9bf07bd98..69b75eddb 100644 --- a/source/skills/clarify/SKILL.md +++ b/source/skills/clarify/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or component with unclear copy (optional) required: false -user-invokable: true +user-invocable: true --- Identify and improve unclear, confusing, or poorly written interface text to make the product easier to understand and use. diff --git a/source/skills/colorize/SKILL.md b/source/skills/colorize/SKILL.md index 004b36eb9..8ecb974f7 100644 --- a/source/skills/colorize/SKILL.md +++ b/source/skills/colorize/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or component to colorize (optional) required: false -user-invokable: true +user-invocable: true --- Strategically introduce color to designs that are too monochromatic, gray, or lacking in visual warmth and personality. diff --git a/source/skills/critique/SKILL.md b/source/skills/critique/SKILL.md index 5b5f4978e..618e69d55 100644 --- a/source/skills/critique/SKILL.md +++ b/source/skills/critique/SKILL.md @@ -5,7 +5,7 @@ args: - name: area description: The feature or area to critique (optional) required: false -user-invokable: true +user-invocable: true --- ## MANDATORY PREPARATION diff --git a/source/skills/delight/SKILL.md b/source/skills/delight/SKILL.md index e3e0de820..fae4b827a 100644 --- a/source/skills/delight/SKILL.md +++ b/source/skills/delight/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or area to add delight to (optional) required: false -user-invokable: true +user-invocable: true --- Identify opportunities to add moments of joy, personality, and unexpected polish that transform functional interfaces into delightful experiences. diff --git a/source/skills/distill/SKILL.md b/source/skills/distill/SKILL.md index 62d318a2a..866c20c70 100644 --- a/source/skills/distill/SKILL.md +++ b/source/skills/distill/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or component to distill (optional) required: false -user-invokable: true +user-invocable: true --- Remove unnecessary complexity from designs, revealing the essential elements and creating clarity through ruthless simplification. diff --git a/source/skills/extract/SKILL.md b/source/skills/extract/SKILL.md index 58592ab1d..252a31e09 100644 --- a/source/skills/extract/SKILL.md +++ b/source/skills/extract/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature, component, or area to extract from (optional) required: false -user-invokable: true +user-invocable: true --- Identify reusable patterns, components, and design tokens, then extract and consolidate them into the design system for systematic reuse. diff --git a/source/skills/harden/SKILL.md b/source/skills/harden/SKILL.md index 3ba23eac0..eda956685 100644 --- a/source/skills/harden/SKILL.md +++ b/source/skills/harden/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or area to harden (optional) required: false -user-invokable: true +user-invocable: true --- Strengthen interfaces against edge cases, errors, internationalization issues, and real-world usage scenarios that break idealized designs. diff --git a/source/skills/normalize/SKILL.md b/source/skills/normalize/SKILL.md index 5a8fc542e..cae143ee4 100644 --- a/source/skills/normalize/SKILL.md +++ b/source/skills/normalize/SKILL.md @@ -5,7 +5,7 @@ args: - name: feature description: The page, route, or feature to normalize (optional) required: false -user-invokable: true +user-invocable: true --- Analyze and redesign the feature to perfectly match our design system standards, aesthetics, and established patterns. diff --git a/source/skills/onboard/SKILL.md b/source/skills/onboard/SKILL.md index 46bf34d96..1944d0b1f 100644 --- a/source/skills/onboard/SKILL.md +++ b/source/skills/onboard/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or area needing onboarding (optional) required: false -user-invokable: true +user-invocable: true --- ## MANDATORY PREPARATION diff --git a/source/skills/optimize/SKILL.md b/source/skills/optimize/SKILL.md index 720ccc792..724a1e8c0 100644 --- a/source/skills/optimize/SKILL.md +++ b/source/skills/optimize/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or area to optimize (optional) required: false -user-invokable: true +user-invocable: true --- Identify and fix performance issues to create faster, smoother user experiences. diff --git a/source/skills/overdrive/SKILL.md b/source/skills/overdrive/SKILL.md index b600d3938..199632a8b 100644 --- a/source/skills/overdrive/SKILL.md +++ b/source/skills/overdrive/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or area to push into overdrive (optional) required: false -user-invokable: true +user-invocable: true --- Start your response with: diff --git a/source/skills/polish/SKILL.md b/source/skills/polish/SKILL.md index cfdeda837..ae348bfa5 100644 --- a/source/skills/polish/SKILL.md +++ b/source/skills/polish/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or area to polish (optional) required: false -user-invokable: true +user-invocable: true --- ## MANDATORY PREPARATION diff --git a/source/skills/quieter/SKILL.md b/source/skills/quieter/SKILL.md index 503a522c7..190d35241 100644 --- a/source/skills/quieter/SKILL.md +++ b/source/skills/quieter/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or component to make quieter (optional) required: false -user-invokable: true +user-invocable: true --- Reduce visual intensity in designs that are too bold, aggressive, or overstimulating, creating a more refined and approachable aesthetic without losing effectiveness. diff --git a/source/skills/teach-impeccable/SKILL.md b/source/skills/teach-impeccable/SKILL.md index 64a7a1b73..0fc4860ad 100644 --- a/source/skills/teach-impeccable/SKILL.md +++ b/source/skills/teach-impeccable/SKILL.md @@ -1,7 +1,7 @@ --- name: teach-impeccable description: One-time setup that gathers design context for your project and saves it to your AI config file. Run once to establish persistent design guidelines. -user-invokable: true +user-invocable: true --- Gather design context for this project, then persist it for all future sessions. diff --git a/source/skills/typeset/SKILL.md b/source/skills/typeset/SKILL.md index 29cf689a9..e5c792e54 100644 --- a/source/skills/typeset/SKILL.md +++ b/source/skills/typeset/SKILL.md @@ -5,7 +5,7 @@ args: - name: target description: The feature or component to improve typography for (optional) required: false -user-invokable: true +user-invocable: true --- Assess and improve typography that feels generic, inconsistent, or poorly structured — turning default-looking text into intentional, well-crafted type. diff --git a/tests/build.test.js b/tests/build.test.js index ad5bd8de1..cdcd8bac3 100644 --- a/tests/build.test.js +++ b/tests/build.test.js @@ -166,7 +166,7 @@ This is a test skill body.`; const skillContent = `--- name: audit description: Run technical quality checks -user-invokable: true +user-invocable: true args: - name: target description: Target element @@ -188,31 +188,31 @@ Please audit {{target}} for technical quality. Ask {{model}} for help.`; transformers.transformGemini(skills, DIST_DIR, patterns); transformers.transformCodex(skills, DIST_DIR, patterns); - // Verify Cursor: full frontmatter with user-invokable + // Verify Cursor: full frontmatter with user-invocable const cursorContent = fs.readFileSync(path.join(DIST_DIR, 'cursor/.cursor/skills/audit/SKILL.md'), 'utf-8'); expect(cursorContent).toContain('---'); expect(cursorContent).toContain('name: audit'); expect(cursorContent).toContain('{{target}}'); expect(cursorContent).toContain('the model'); - // Verify Claude Code: full frontmatter with user-invokable and args + // Verify Claude Code: full frontmatter with user-invocable and args const claudeContent = fs.readFileSync(path.join(DIST_DIR, 'claude-code/.claude/skills/audit/SKILL.md'), 'utf-8'); expect(claudeContent).toContain('---'); expect(claudeContent).toContain('name: audit'); - expect(claudeContent).toContain('user-invokable: true'); + expect(claudeContent).toContain('user-invocable: true'); expect(claudeContent).toContain('{{target}}'); expect(claudeContent).toContain('Claude'); // Verify Gemini: skill in skills directory expect(fs.existsSync(path.join(DIST_DIR, 'gemini/.gemini/skills/audit/SKILL.md'))).toBe(true); const geminiContent = fs.readFileSync(path.join(DIST_DIR, 'gemini/.gemini/skills/audit/SKILL.md'), 'utf-8'); - expect(geminiContent).toContain('{{args}}'); // Replaced for user-invokable in Gemini + expect(geminiContent).toContain('{{args}}'); // Replaced for user-invocable in Gemini expect(geminiContent).toContain('Gemini'); // Verify Codex: skill in skills directory expect(fs.existsSync(path.join(DIST_DIR, 'codex/.codex/skills/audit/SKILL.md'))).toBe(true); const codexContent = fs.readFileSync(path.join(DIST_DIR, 'codex/.codex/skills/audit/SKILL.md'), 'utf-8'); - expect(codexContent).toContain('$TARGET'); // Replaced for user-invokable in Codex + expect(codexContent).toContain('$TARGET'); // Replaced for user-invocable in Codex expect(codexContent).toContain('GPT'); }); diff --git a/tests/lib/transformers/agents.test.js b/tests/lib/transformers/agents.test.js index d43273eed..09667de48 100644 --- a/tests/lib/transformers/agents.test.js +++ b/tests/lib/transformers/agents.test.js @@ -47,12 +47,12 @@ describe('transformAgents', () => { expect(parsed.body).toBe('Skill instructions.'); }); - test('should add user-invokable flag for user-invokable skills', () => { + test('should add user-invocable flag for user-invocable skills', () => { const skills = [ { name: 'audit', description: 'Audit command', - userInvokable: true, + userInvocable: true, body: 'Audit the code.' } ]; @@ -62,10 +62,10 @@ describe('transformAgents', () => { const content = fs.readFileSync(path.join(TEST_DIR, 'agents/.agents/skills/audit/SKILL.md'), 'utf-8'); const parsed = parseFrontmatter(content); - expect(parsed.frontmatter['user-invokable']).toBe(true); + expect(parsed.frontmatter['user-invocable']).toBe(true); }); - test('should not add user-invokable flag for non-user-invokable skills', () => { + test('should not add user-invocable flag for non-user-invocable skills', () => { const skills = [ { name: 'helper', @@ -79,7 +79,7 @@ describe('transformAgents', () => { const content = fs.readFileSync(path.join(TEST_DIR, 'agents/.agents/skills/helper/SKILL.md'), 'utf-8'); const parsed = parseFrontmatter(content); - expect(parsed.frontmatter['user-invokable']).toBeUndefined(); + expect(parsed.frontmatter['user-invocable']).toBeUndefined(); }); test('should create argument-hint for required args', () => { @@ -87,7 +87,7 @@ describe('transformAgents', () => { { name: 'with-args', description: 'Command with args', - userInvokable: true, + userInvocable: true, args: [ { name: 'target', description: 'Target', required: true }, { name: 'format', description: 'Format', required: false } @@ -109,7 +109,7 @@ describe('transformAgents', () => { { name: 'no-args', description: 'No args', - userInvokable: true, + userInvocable: true, args: [], body: 'Simple body.' } @@ -123,12 +123,12 @@ describe('transformAgents', () => { expect(parsed.frontmatter['argument-hint']).toBeUndefined(); }); - test('should not add argument-hint for non-user-invokable skills with args', () => { + test('should not add argument-hint for non-user-invocable skills with args', () => { const skills = [ { name: 'internal', description: 'Internal skill', - userInvokable: false, + userInvocable: false, args: [{ name: 'target', description: 'Target', required: true }], body: 'Body.' } @@ -188,8 +188,8 @@ describe('transformAgents', () => { test('should replace {{available_commands}} placeholder', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Available: {{available_commands}}' }, - { name: 'polish', description: 'Polish', userInvokable: true, body: 'Polish body.' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Available: {{available_commands}}' }, + { name: 'polish', description: 'Polish', userInvocable: true, body: 'Polish body.' } ]; transformAgents(skills, TEST_DIR); @@ -241,7 +241,7 @@ describe('transformAgents', () => { test('should support prefix option', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Audit body' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Audit body' } ]; transformAgents(skills, TEST_DIR, null, { prefix: 'i-', outputSuffix: '-prefixed' }); @@ -255,8 +255,8 @@ describe('transformAgents', () => { test('should prefix skill references in body when prefix is set', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Run /polish after the audit skill.' }, - { name: 'polish', description: 'Polish', userInvokable: true, body: 'Polish body.' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Run /polish after the audit skill.' }, + { name: 'polish', description: 'Polish', userInvocable: true, body: 'Polish body.' } ]; transformAgents(skills, TEST_DIR, null, { prefix: 'i-', outputSuffix: '-prefixed' }); @@ -284,8 +284,8 @@ describe('transformAgents', () => { console.log = consoleMock; const skills = [ - { name: 'skill1', description: 'Test', userInvokable: true, body: 'body' }, - { name: 'skill2', description: 'Test', userInvokable: false, body: 'body' } + { name: 'skill1', description: 'Test', userInvocable: true, body: 'body' }, + { name: 'skill2', description: 'Test', userInvocable: false, body: 'body' } ]; transformAgents(skills, TEST_DIR); @@ -294,7 +294,7 @@ describe('transformAgents', () => { expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('✓ Agents:')); expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('2 skills')); - expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invokable')); + expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invocable')); }); test('should log reference file count', () => { diff --git a/tests/lib/transformers/claude-code.test.js b/tests/lib/transformers/claude-code.test.js index f3ac5f24f..fdaf35909 100644 --- a/tests/lib/transformers/claude-code.test.js +++ b/tests/lib/transformers/claude-code.test.js @@ -51,12 +51,12 @@ describe('transformClaudeCode', () => { expect(parsed.body).toBe('Skill instructions.'); }); - test('should add user-invokable flag for user-invokable skills', () => { + test('should add user-invocable flag for user-invocable skills', () => { const skills = [ { name: 'audit', description: 'Audit command', - userInvokable: true, + userInvocable: true, body: 'Audit the code.' } ]; @@ -66,15 +66,15 @@ describe('transformClaudeCode', () => { const content = fs.readFileSync(path.join(TEST_DIR, 'claude-code/.claude/skills/audit/SKILL.md'), 'utf-8'); const parsed = parseFrontmatter(content); - expect(parsed.frontmatter['user-invokable']).toBe(true); + expect(parsed.frontmatter['user-invocable']).toBe(true); }); - test('should include args in frontmatter for user-invokable skills', () => { + test('should include args in frontmatter for user-invocable skills', () => { const skills = [ { name: 'test-command', description: 'A test command', - userInvokable: true, + userInvocable: true, args: [ { name: 'target', description: 'The target', required: false }, { name: 'output', description: 'Output format', required: true } @@ -100,7 +100,7 @@ describe('transformClaudeCode', () => { { name: 'simple-skill', description: 'Simple skill', - userInvokable: true, + userInvocable: true, args: [], body: 'Simple body.' } @@ -162,7 +162,7 @@ describe('transformClaudeCode', () => { { name: 'with-placeholder', description: 'Has placeholder', - userInvokable: true, + userInvocable: true, args: [{ name: 'target', description: 'Target', required: false }], body: 'Process {{target}} and generate output.' } @@ -203,8 +203,8 @@ describe('transformClaudeCode', () => { console.log = consoleMock; const skills = [ - { name: 'skill1', description: 'Test', license: '', userInvokable: true, body: 'body' }, - { name: 'skill2', description: 'Test', license: '', userInvokable: false, body: 'body' } + { name: 'skill1', description: 'Test', license: '', userInvocable: true, body: 'body' }, + { name: 'skill2', description: 'Test', license: '', userInvocable: false, body: 'body' } ]; transformClaudeCode(skills, TEST_DIR); @@ -213,7 +213,7 @@ describe('transformClaudeCode', () => { expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('✓ Claude Code:')); expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('2 skills')); - expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invokable')); + expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invocable')); }); test('should handle empty arrays', () => { @@ -228,7 +228,7 @@ describe('transformClaudeCode', () => { { name: 'test', description: 'Test command', - userInvokable: true, + userInvocable: true, args: [ { name: 'arg1', description: 'First arg', required: true }, { name: 'arg2', description: 'Second arg', required: false } @@ -279,7 +279,7 @@ Second paragraph with details. test('should support prefix option', () => { const skills = [ - { name: 'audit', description: 'Audit', license: '', userInvokable: true, body: 'Audit body' } + { name: 'audit', description: 'Audit', license: '', userInvocable: true, body: 'Audit body' } ]; transformClaudeCode(skills, TEST_DIR, null, { prefix: 'i-', outputSuffix: '-prefixed' }); diff --git a/tests/lib/transformers/codex.test.js b/tests/lib/transformers/codex.test.js index b5afbcd86..70e95850f 100644 --- a/tests/lib/transformers/codex.test.js +++ b/tests/lib/transformers/codex.test.js @@ -55,7 +55,7 @@ describe('transformCodex', () => { { name: 'with-args', description: 'Command with args', - userInvokable: true, + userInvocable: true, args: [ { name: 'target', description: 'Target', required: true }, { name: 'output', description: 'Output', required: true } @@ -77,7 +77,7 @@ describe('transformCodex', () => { { name: 'optional-args', description: 'Command with optional args', - userInvokable: true, + userInvocable: true, args: [ { name: 'format', description: 'Format', required: false } ], @@ -98,7 +98,7 @@ describe('transformCodex', () => { { name: 'mixed-args', description: 'Mixed args', - userInvokable: true, + userInvocable: true, args: [ { name: 'input', description: 'Input', required: true }, { name: 'format', description: 'Format', required: false }, @@ -116,12 +116,12 @@ describe('transformCodex', () => { expect(parsed.frontmatter['argument-hint']).toBe(' [FORMAT=] '); }); - test('should transform {{argname}} to $ARGNAME for user-invokable skills', () => { + test('should transform {{argname}} to $ARGNAME for user-invocable skills', () => { const skills = [ { name: 'normalize', description: 'Normalize', - userInvokable: true, + userInvocable: true, args: [{ name: 'target', description: 'Target', required: false }], body: 'Please normalize {{target}} to match the design system.' } @@ -141,7 +141,7 @@ describe('transformCodex', () => { { name: 'multi-arg', description: 'Multiple args', - userInvokable: true, + userInvocable: true, args: [], body: 'Process {{input}} and output to {{output}} with {{format}}.' } @@ -198,8 +198,8 @@ describe('transformCodex', () => { console.log = consoleMock; const skills = [ - { name: 'skill1', description: 'Test', license: '', userInvokable: true, body: 'body' }, - { name: 'skill2', description: 'Test', license: '', userInvokable: false, body: 'body' } + { name: 'skill1', description: 'Test', license: '', userInvocable: true, body: 'body' }, + { name: 'skill2', description: 'Test', license: '', userInvocable: false, body: 'body' } ]; transformCodex(skills, TEST_DIR); @@ -208,7 +208,7 @@ describe('transformCodex', () => { expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('✓ Codex:')); expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('2 skills')); - expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invokable')); + expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invocable')); }); test('should handle empty arrays', () => { @@ -218,12 +218,12 @@ describe('transformCodex', () => { expect(skillDirs).toHaveLength(0); }); - test('should handle user-invokable skills without args', () => { + test('should handle user-invocable skills without args', () => { const skills = [ { name: 'no-args', description: 'No args command', - userInvokable: true, + userInvocable: true, args: [], body: 'Body content' } @@ -263,7 +263,7 @@ Second line after blank. test('should support prefix option', () => { const skills = [ - { name: 'audit', description: 'Audit', license: '', userInvokable: true, body: 'Audit body' } + { name: 'audit', description: 'Audit', license: '', userInvocable: true, body: 'Audit body' } ]; transformCodex(skills, TEST_DIR, null, { prefix: 'i-', outputSuffix: '-prefixed' }); diff --git a/tests/lib/transformers/cursor.test.js b/tests/lib/transformers/cursor.test.js index 39fc3308b..23ba63df2 100644 --- a/tests/lib/transformers/cursor.test.js +++ b/tests/lib/transformers/cursor.test.js @@ -123,8 +123,8 @@ describe('transformCursor', () => { console.log = consoleMock; const skills = [ - { name: 'skill1', description: '', license: '', userInvokable: true, body: 'body1' }, - { name: 'skill2', description: '', license: '', userInvokable: false, body: 'body2' } + { name: 'skill1', description: '', license: '', userInvocable: true, body: 'body1' }, + { name: 'skill2', description: '', license: '', userInvocable: false, body: 'body2' } ]; transformCursor(skills, TEST_DIR); @@ -133,7 +133,7 @@ describe('transformCursor', () => { expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('✓ Cursor:')); expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('2 skills')); - expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invokable')); + expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invocable')); }); test('should handle empty skills array', () => { diff --git a/tests/lib/transformers/gemini.test.js b/tests/lib/transformers/gemini.test.js index 648d7a3c3..9908bed11 100644 --- a/tests/lib/transformers/gemini.test.js +++ b/tests/lib/transformers/gemini.test.js @@ -62,12 +62,12 @@ describe('transformGemini', () => { expect(fs.existsSync(path.join(TEST_DIR, 'gemini/.gemini/skills/skill3/SKILL.md'))).toBe(true); }); - test('should handle user-invokable skills with args', () => { + test('should handle user-invocable skills with args', () => { const skills = [ { name: 'normalize', description: 'Normalize design', - userInvokable: true, + userInvocable: true, args: [{ name: 'target', description: 'Target', required: false }], body: 'Please normalize {{target}} to match the design system.' } @@ -76,17 +76,17 @@ describe('transformGemini', () => { transformGemini(skills, TEST_DIR); const content = fs.readFileSync(path.join(TEST_DIR, 'gemini/.gemini/skills/normalize/SKILL.md'), 'utf-8'); - // For user-invokable skills, {{arg}} placeholders become {{args}} + // For user-invocable skills, {{arg}} placeholders become {{args}} expect(content).toContain('{{args}}'); expect(content).not.toContain('{{target}}'); }); - test('should replace multiple different placeholders with {{args}} for user-invokable skills', () => { + test('should replace multiple different placeholders with {{args}} for user-invocable skills', () => { const skills = [ { name: 'multi-arg', description: 'Multiple args', - userInvokable: true, + userInvocable: true, args: [], body: 'Process {{input}} and output to {{output}} with {{format}}.' } @@ -99,12 +99,12 @@ describe('transformGemini', () => { expect(argsMatches).toHaveLength(3); }); - test('should not replace placeholders for non-user-invokable skills', () => { + test('should not replace placeholders for non-user-invocable skills', () => { const skills = [ { name: 'passive-skill', description: 'Passive skill', - userInvokable: false, + userInvocable: false, body: 'Process {{target}} normally.' } ]; @@ -143,8 +143,8 @@ describe('transformGemini', () => { console.log = consoleMock; const skills = [ - { name: 'skill1', description: 'Test', license: '', userInvokable: true, body: 'body' }, - { name: 'skill2', description: 'Test', license: '', userInvokable: false, body: 'body' } + { name: 'skill1', description: 'Test', license: '', userInvocable: true, body: 'body' }, + { name: 'skill2', description: 'Test', license: '', userInvocable: false, body: 'body' } ]; transformGemini(skills, TEST_DIR); @@ -153,7 +153,7 @@ describe('transformGemini', () => { expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('✓ Gemini:')); expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('2 skills')); - expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invokable')); + expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invocable')); }); test('should handle empty arrays', () => { diff --git a/tests/lib/transformers/kiro.test.js b/tests/lib/transformers/kiro.test.js index 060089aef..935e5b0d6 100644 --- a/tests/lib/transformers/kiro.test.js +++ b/tests/lib/transformers/kiro.test.js @@ -80,12 +80,12 @@ describe('transformKiro', () => { expect(content).toContain('metadata: some-metadata'); }); - test('should not include user-invokable in frontmatter (Kiro does not use it)', () => { + test('should not include user-invocable in frontmatter (Kiro does not use it)', () => { const skills = [ { name: 'test', description: 'Test', - userInvokable: true, + userInvocable: true, body: 'Body' } ]; @@ -93,7 +93,7 @@ describe('transformKiro', () => { transformKiro(skills, TEST_DIR); const content = fs.readFileSync(path.join(TEST_DIR, 'kiro/.kiro/skills/test/SKILL.md'), 'utf-8'); - expect(content).not.toContain('user-invokable'); + expect(content).not.toContain('user-invocable'); }); test('should handle multiple skills', () => { @@ -142,8 +142,8 @@ describe('transformKiro', () => { test('should replace {{available_commands}} placeholder', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Available: {{available_commands}}' }, - { name: 'polish', description: 'Polish', userInvokable: true, body: 'Polish body.' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Available: {{available_commands}}' }, + { name: 'polish', description: 'Polish', userInvocable: true, body: 'Polish body.' } ]; transformKiro(skills, TEST_DIR); @@ -180,7 +180,7 @@ describe('transformKiro', () => { { name: 'test', description: 'Test', - userInvokable: true, + userInvocable: true, body: 'Body with {{available_commands}}.', references: [ { name: 'ref', content: 'Use {{model}} with {{config_file}}. Commands: {{available_commands}}.', filePath: '/fake/ref.md' } @@ -198,7 +198,7 @@ describe('transformKiro', () => { test('should support prefix option', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Audit body' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Audit body' } ]; transformKiro(skills, TEST_DIR, null, { prefix: 'i-', outputSuffix: '-prefixed' }); @@ -212,8 +212,8 @@ describe('transformKiro', () => { test('should prefix skill references in body when prefix is set', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Run /polish after the audit skill.' }, - { name: 'polish', description: 'Polish', userInvokable: true, body: 'Polish body.' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Run /polish after the audit skill.' }, + { name: 'polish', description: 'Polish', userInvocable: true, body: 'Polish body.' } ]; transformKiro(skills, TEST_DIR, null, { prefix: 'i-', outputSuffix: '-prefixed' }); @@ -241,8 +241,8 @@ describe('transformKiro', () => { console.log = consoleMock; const skills = [ - { name: 'skill1', description: 'Test', userInvokable: true, body: 'body' }, - { name: 'skill2', description: 'Test', userInvokable: false, body: 'body' } + { name: 'skill1', description: 'Test', userInvocable: true, body: 'body' }, + { name: 'skill2', description: 'Test', userInvocable: false, body: 'body' } ]; transformKiro(skills, TEST_DIR); @@ -251,7 +251,7 @@ describe('transformKiro', () => { expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('✓ Kiro:')); expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('2 skills')); - expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invokable')); + expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invocable')); }); test('should log reference file count', () => { diff --git a/tests/lib/transformers/opencode.test.js b/tests/lib/transformers/opencode.test.js index 24e8af592..e6b3b558a 100644 --- a/tests/lib/transformers/opencode.test.js +++ b/tests/lib/transformers/opencode.test.js @@ -48,12 +48,12 @@ describe('transformOpenCode', () => { expect(parsed.body).toBe('Skill instructions.'); }); - test('should add user-invokable flag for user-invokable skills', () => { + test('should add user-invocable flag for user-invocable skills', () => { const skills = [ { name: 'audit', description: 'Audit command', - userInvokable: true, + userInvocable: true, body: 'Audit the code.' } ]; @@ -63,10 +63,10 @@ describe('transformOpenCode', () => { const content = fs.readFileSync(path.join(TEST_DIR, 'opencode/.opencode/skills/audit/SKILL.md'), 'utf-8'); const parsed = parseFrontmatter(content); - expect(parsed.frontmatter['user-invokable']).toBe(true); + expect(parsed.frontmatter['user-invocable']).toBe(true); }); - test('should not add user-invokable flag for non-user-invokable skills', () => { + test('should not add user-invocable flag for non-user-invocable skills', () => { const skills = [ { name: 'helper', @@ -80,7 +80,7 @@ describe('transformOpenCode', () => { const content = fs.readFileSync(path.join(TEST_DIR, 'opencode/.opencode/skills/helper/SKILL.md'), 'utf-8'); const parsed = parseFrontmatter(content); - expect(parsed.frontmatter['user-invokable']).toBeUndefined(); + expect(parsed.frontmatter['user-invocable']).toBeUndefined(); }); test('should include args in frontmatter', () => { @@ -88,7 +88,7 @@ describe('transformOpenCode', () => { { name: 'with-args', description: 'Command with args', - userInvokable: true, + userInvocable: true, args: [ { name: 'target', description: 'Target element', required: false } ], @@ -111,7 +111,7 @@ describe('transformOpenCode', () => { { name: 'no-args', description: 'No args', - userInvokable: true, + userInvocable: true, args: [], body: 'Simple body.' } @@ -234,8 +234,8 @@ describe('transformOpenCode', () => { test('should replace {{available_commands}} placeholder', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Available: {{available_commands}}' }, - { name: 'polish', description: 'Polish', userInvokable: true, body: 'Polish body.' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Available: {{available_commands}}' }, + { name: 'polish', description: 'Polish', userInvocable: true, body: 'Polish body.' } ]; transformOpenCode(skills, TEST_DIR); @@ -272,7 +272,7 @@ describe('transformOpenCode', () => { { name: 'test', description: 'Test', - userInvokable: true, + userInvocable: true, body: 'Body with {{available_commands}}.', references: [ { name: 'ref', content: 'Use {{model}} with {{config_file}}. Commands: {{available_commands}}.', filePath: '/fake/ref.md' } @@ -290,7 +290,7 @@ describe('transformOpenCode', () => { test('should support prefix option', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Audit body' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Audit body' } ]; transformOpenCode(skills, TEST_DIR, null, { prefix: 'i-', outputSuffix: '-prefixed' }); @@ -304,8 +304,8 @@ describe('transformOpenCode', () => { test('should prefix skill references in body when prefix is set', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Run /polish after the audit skill.' }, - { name: 'polish', description: 'Polish', userInvokable: true, body: 'Polish body.' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Run /polish after the audit skill.' }, + { name: 'polish', description: 'Polish', userInvocable: true, body: 'Polish body.' } ]; transformOpenCode(skills, TEST_DIR, null, { prefix: 'i-', outputSuffix: '-prefixed' }); @@ -333,8 +333,8 @@ describe('transformOpenCode', () => { console.log = consoleMock; const skills = [ - { name: 'skill1', description: 'Test', userInvokable: true, body: 'body' }, - { name: 'skill2', description: 'Test', userInvokable: false, body: 'body' } + { name: 'skill1', description: 'Test', userInvocable: true, body: 'body' }, + { name: 'skill2', description: 'Test', userInvocable: false, body: 'body' } ]; transformOpenCode(skills, TEST_DIR); @@ -343,7 +343,7 @@ describe('transformOpenCode', () => { expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('✓ OpenCode:')); expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('2 skills')); - expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invokable')); + expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invocable')); }); test('should log reference file count', () => { diff --git a/tests/lib/transformers/pi.test.js b/tests/lib/transformers/pi.test.js index 32fc172b6..1d4fa87b5 100644 --- a/tests/lib/transformers/pi.test.js +++ b/tests/lib/transformers/pi.test.js @@ -80,12 +80,12 @@ describe('transformPi', () => { expect(content).toContain('metadata: some-metadata'); }); - test('should not include user-invokable in frontmatter (Pi does not use it)', () => { + test('should not include user-invocable in frontmatter (Pi does not use it)', () => { const skills = [ { name: 'test', description: 'Test', - userInvokable: true, + userInvocable: true, body: 'Body' } ]; @@ -93,7 +93,7 @@ describe('transformPi', () => { transformPi(skills, TEST_DIR); const content = fs.readFileSync(path.join(TEST_DIR, 'pi/.pi/skills/test/SKILL.md'), 'utf-8'); - expect(content).not.toContain('user-invokable'); + expect(content).not.toContain('user-invocable'); }); test('should handle multiple skills', () => { @@ -142,8 +142,8 @@ describe('transformPi', () => { test('should replace {{available_commands}} placeholder', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Available: {{available_commands}}' }, - { name: 'polish', description: 'Polish', userInvokable: true, body: 'Polish body.' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Available: {{available_commands}}' }, + { name: 'polish', description: 'Polish', userInvocable: true, body: 'Polish body.' } ]; transformPi(skills, TEST_DIR); @@ -180,7 +180,7 @@ describe('transformPi', () => { { name: 'test', description: 'Test', - userInvokable: true, + userInvocable: true, body: 'Body with {{available_commands}}.', references: [ { name: 'ref', content: 'Use {{model}} with {{config_file}}. Commands: {{available_commands}}.', filePath: '/fake/ref.md' } @@ -198,7 +198,7 @@ describe('transformPi', () => { test('should support prefix option', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Audit body' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Audit body' } ]; transformPi(skills, TEST_DIR, null, { prefix: 'i-', outputSuffix: '-prefixed' }); @@ -212,8 +212,8 @@ describe('transformPi', () => { test('should prefix skill references in body when prefix is set', () => { const skills = [ - { name: 'audit', description: 'Audit', userInvokable: true, body: 'Run /polish after the audit skill.' }, - { name: 'polish', description: 'Polish', userInvokable: true, body: 'Polish body.' } + { name: 'audit', description: 'Audit', userInvocable: true, body: 'Run /polish after the audit skill.' }, + { name: 'polish', description: 'Polish', userInvocable: true, body: 'Polish body.' } ]; transformPi(skills, TEST_DIR, null, { prefix: 'i-', outputSuffix: '-prefixed' }); @@ -241,8 +241,8 @@ describe('transformPi', () => { console.log = consoleMock; const skills = [ - { name: 'skill1', description: 'Test', userInvokable: true, body: 'body' }, - { name: 'skill2', description: 'Test', userInvokable: false, body: 'body' } + { name: 'skill1', description: 'Test', userInvocable: true, body: 'body' }, + { name: 'skill2', description: 'Test', userInvocable: false, body: 'body' } ]; transformPi(skills, TEST_DIR); @@ -251,7 +251,7 @@ describe('transformPi', () => { expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('✓ Pi:')); expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('2 skills')); - expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invokable')); + expect(consoleMock).toHaveBeenCalledWith(expect.stringContaining('1 user-invocable')); }); test('should log reference file count', () => { diff --git a/tests/lib/utils.test.js b/tests/lib/utils.test.js index 5af8cbe99..af019a966 100644 --- a/tests/lib/utils.test.js +++ b/tests/lib/utils.test.js @@ -89,29 +89,29 @@ Skill body.`; expect(result.frontmatter.license).toBe('MIT'); }); - test('should parse user-invokable boolean', () => { + test('should parse user-invocable boolean', () => { const content = `--- name: test-skill -user-invokable: true +user-invocable: true --- Body.`; const result = parseFrontmatter(content); - expect(result.frontmatter['user-invokable']).toBe(true); + expect(result.frontmatter['user-invocable']).toBe(true); }); - test('should parse user-invokable as string true (code behavior)', () => { + test('should parse user-invocable as string true (code behavior)', () => { const content = `--- name: test-skill -user-invokable: 'true' +user-invocable: 'true' --- Body.`; const result = parseFrontmatter(content); // The parseFrontmatter function doesn't strip quotes from YAML string values - expect(result.frontmatter['user-invokable']).toBe("'true'"); + expect(result.frontmatter['user-invocable']).toBe("'true'"); }); test('should parse allowed-tools field', () => { @@ -162,11 +162,11 @@ describe('generateYamlFrontmatter', () => { const data = { name: 'test', description: 'Test', - 'user-invokable': true + 'user-invocable': true }; const result = generateYamlFrontmatter(data); - expect(result).toContain('user-invokable: true'); + expect(result).toContain('user-invocable: true'); }); test('should roundtrip: generate and parse back', () => { @@ -372,11 +372,11 @@ Skill instructions here.`; expect(skills[0].body).toBe('Skill instructions here.'); }); - test('should read skill with user-invokable flag', () => { + test('should read skill with user-invocable flag', () => { const skillContent = `--- name: audit description: Run technical quality checks -user-invokable: true +user-invocable: true --- Audit the code.`; @@ -388,7 +388,7 @@ Audit the code.`; const { skills } = readSourceFiles(testRootDir); expect(skills).toHaveLength(1); - expect(skills[0].userInvokable).toBe(true); + expect(skills[0].userInvocable).toBe(true); }); test('should read skill with reference files', () => { @@ -478,7 +478,7 @@ name: test-skill description: A comprehensive test skill license: Apache-2.0 compatibility: claude-code -user-invokable: true +user-invocable: true allowed-tools: Bash,Edit --- @@ -494,7 +494,7 @@ Body content.`; expect(skills[0].description).toBe('A comprehensive test skill'); expect(skills[0].license).toBe('Apache-2.0'); expect(skills[0].compatibility).toBe('claude-code'); - expect(skills[0].userInvokable).toBe(true); + expect(skills[0].userInvocable).toBe(true); expect(skills[0].allowedTools).toBe('Bash,Edit'); }); });