mirror of https://github.com/garrytan/gstack.git
55 lines
1.6 KiB
TypeScript
55 lines
1.6 KiB
TypeScript
#!/usr/bin/env bun
|
|
/**
|
|
* Validate YAML frontmatter for generated SKILL.md files.
|
|
*
|
|
* This is intentionally narrower than skill:check so CI can run it after
|
|
* regenerating only the host outputs relevant to a workflow.
|
|
*/
|
|
|
|
import { discoverSkillFiles } from './discover-skills';
|
|
import { validateSkillFrontmatter } from '../test/helpers/skill-parser';
|
|
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
|
|
const ROOT = path.resolve(import.meta.dir, '..');
|
|
|
|
function walkSkillFiles(dir: string, acc: string[]): void {
|
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
if (entry.name === '.git' || entry.name === 'node_modules') continue;
|
|
const fullPath = path.join(dir, entry.name);
|
|
if (entry.isDirectory()) {
|
|
walkSkillFiles(fullPath, acc);
|
|
continue;
|
|
}
|
|
if (entry.name === 'SKILL.md') {
|
|
acc.push(path.relative(ROOT, fullPath));
|
|
}
|
|
}
|
|
}
|
|
|
|
const files = new Set(discoverSkillFiles(ROOT));
|
|
for (const hostDir of ['.agents', '.factory']) {
|
|
const fullPath = path.join(ROOT, hostDir);
|
|
if (fs.existsSync(fullPath)) {
|
|
const hostFiles: string[] = [];
|
|
walkSkillFiles(fullPath, hostFiles);
|
|
for (const file of hostFiles) files.add(file);
|
|
}
|
|
}
|
|
|
|
const errors: string[] = [];
|
|
for (const file of [...files].sort()) {
|
|
const fullPath = path.join(ROOT, file);
|
|
for (const error of validateSkillFrontmatter(fullPath)) {
|
|
errors.push(`${file}:${error.line}: ${error.message}`);
|
|
}
|
|
}
|
|
|
|
if (errors.length > 0) {
|
|
console.error('Invalid SKILL.md frontmatter:');
|
|
for (const error of errors) console.error(` ${error}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`Validated frontmatter for ${files.size} SKILL.md files.`);
|