Files
mapbox__mapbox-agent-skills/scripts/validate-skills.js
Matthew Podwysocki 3c3702c3d7 Add Prettier formatter for consistent code formatting
- Add prettier as dev dependency
- Create .prettierrc config with markdown-specific settings
- Add .prettierignore to exclude node_modules and generated files
- Add npm scripts:
  - format: Format all files with prettier
  - format:check: Check formatting without changes
- Update npm check script to include format:check
- Add format check step to GitHub Actions CI
- Format all existing files with prettier

Prettier config:
- Preserve line wrapping in markdown (proseWrap: preserve)
- 120 char print width for markdown
- Consistent formatting for JSON and JS files

This ensures all markdown, JSON, and JS files maintain consistent
formatting across the repository.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-04 14:17:21 -05:00

110 lines
3.1 KiB
JavaScript

#!/usr/bin/env node
import { readdir, readFile } from 'fs/promises';
import { join } from 'path';
/**
* Validates that all skills have proper SKILL.md files with required YAML frontmatter
*/
async function validateSkills() {
const skillsDir = 'skills';
let hasErrors = false;
try {
const entries = await readdir(skillsDir, { withFileTypes: true });
const skillDirs = entries.filter((entry) => entry.isDirectory());
if (skillDirs.length === 0) {
console.error('❌ No skill directories found in skills/');
process.exit(1);
}
console.log(`Found ${skillDirs.length} skill directories\n`);
for (const dir of skillDirs) {
const skillName = dir.name;
const skillPath = join(skillsDir, skillName);
const skillFile = join(skillPath, 'SKILL.md');
console.log(`Validating ${skillName}...`);
try {
const content = await readFile(skillFile, 'utf-8');
// Check for YAML frontmatter
if (!content.startsWith('---\n')) {
console.error(` ❌ Missing YAML frontmatter (must start with ---)`);
hasErrors = true;
continue;
}
// Extract frontmatter
const frontmatterEnd = content.indexOf('\n---\n', 4);
if (frontmatterEnd === -1) {
console.error(
` ❌ Malformed YAML frontmatter (missing closing ---)`
);
hasErrors = true;
continue;
}
const frontmatter = content.substring(4, frontmatterEnd);
const body = content.substring(frontmatterEnd + 5).trim();
// Parse YAML frontmatter (simple parsing for required fields)
const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
if (!nameMatch) {
console.error(` ❌ Missing required field: name`);
hasErrors = true;
} else {
const name = nameMatch[1].trim();
if (name !== skillName) {
console.error(
` ❌ Skill name mismatch: directory is "${skillName}" but YAML name is "${name}"`
);
hasErrors = true;
}
}
if (!descMatch) {
console.error(` ❌ Missing required field: description`);
hasErrors = true;
}
// Check for content after frontmatter
if (body.length === 0) {
console.error(` ❌ No content found after YAML frontmatter`);
hasErrors = true;
}
if (!hasErrors) {
console.log(` ✅ Valid`);
}
} catch (error) {
if (error.code === 'ENOENT') {
console.error(` ❌ Missing SKILL.md file`);
} else {
console.error(` ❌ Error reading file: ${error.message}`);
}
hasErrors = true;
}
console.log('');
}
if (hasErrors) {
console.error('❌ Skill validation failed');
process.exit(1);
}
console.log('✅ All skills are valid');
} catch (error) {
console.error(`❌ Error reading skills directory: ${error.message}`);
process.exit(1);
}
}
validateSkills();