import { parse } from "smol-toml"; import * as path from "node:path"; import type { SkillDefinition, SkillScope, SkillDirectory } from "../types/index.js"; const FRONTMATTER_DELIMITER = "+++"; export function parseSkillFile( filePath: string, content: string, scope: SkillScope, directory: SkillDirectory, ): SkillDefinition { const defaultName = path.basename(filePath, path.extname(filePath)); let name = defaultName; let description = ""; let tags: string[] = []; let body = content; // Check for TOML frontmatter const trimmed = content.trimStart(); if (trimmed.startsWith(FRONTMATTER_DELIMITER)) { const afterOpen = trimmed.slice(FRONTMATTER_DELIMITER.length); // Find the closing +++ const closeIndex = afterOpen.indexOf(FRONTMATTER_DELIMITER); if (closeIndex !== -1) { const tomlSource = afterOpen.slice(0, closeIndex); body = afterOpen.slice(closeIndex + FRONTMATTER_DELIMITER.length); try { const frontmatter = parse(tomlSource); if (typeof frontmatter["name"] === "string") { name = frontmatter["name"]; } if (typeof frontmatter["description"] === "string") { description = frontmatter["description"]; } if (Array.isArray(frontmatter["tags"])) { tags = (frontmatter["tags"] as unknown[]).filter( (t): t is string => typeof t === "string", ); } } catch { // Malformed TOML — fall through with defaults } } } // Trim leading newline from body (handles both LF and CRLF) body = body.replace(/^\r?\n/, ""); return { name, description, tags, content: body, scope, source: filePath, directory, }; }