UNPKG

agents

Version:

A home for your AI agents

86 lines (85 loc) • 3.65 kB
import { d as err, f as ok, l as parseSkillFrontmatter, s as SkillParseError } from "./resource-B59OV2a2.js"; import { parse, stringify } from "yaml"; //#region src/skills/markdown.ts /** * `SKILL.md` text: YAML frontmatter between `---` lines, then Markdown. * Kept apart from `./skill` because it loads the YAML parser. * * @module */ const FRONTMATTER = /^\uFEFF?---[ \t]*\r?\n(?:([\s\S]*?)\r?\n)?---[ \t]*(?:\r?\n([\s\S]*))?$/; /** * Parse a `SKILL.md` file. * * Follows the spec's guide for agents: a skill that breaks a rule still * parses, with each broken rule in `warnings`. Frontmatter that only fails * because of unquoted values containing `: ` (for example * `description: Use when: the user asks`), which many clients accept, is * read again with those values quoted. The parse fails only when the skill * cannot be used: no frontmatter, YAML that still does not parse, no * description, or an unsafe name. * * To check a skill before storing it, require `warnings` to be empty. * * @param markdown - The full file: YAML frontmatter, then Markdown. * @param options - `directory` to check the name against. * @returns The parsed skill and warnings, or a `SkillParseError`. */ function parseSkill(markdown, options = {}) { const match = FRONTMATTER.exec(markdown); if (!match) return err(new SkillParseError("missing-frontmatter", "SKILL.md must start with YAML frontmatter between --- lines.")); const yaml = match[1] ?? ""; const body = match[2] ?? ""; const parsed = parseFrontmatterYaml(yaml); if (parsed.ok) return parseSkillFrontmatter(parsed.value ?? {}, body, options); const repaired = parseFrontmatterYaml(quoteColonValues(yaml)); if (!repaired.ok) return parsed; const result = parseSkillFrontmatter(repaired.value ?? {}, body, options); return result.ok ? { ...result, warnings: [new SkillParseError("invalid-yaml", "SKILL.md frontmatter is not valid YAML; it was read after quoting values that contain `: `.", { cause: parsed.error.cause }), ...result.warnings] } : result; } function parseFrontmatterYaml(yaml) { try { return ok(parse(yaml)); } catch (cause) { return err(new SkillParseError("invalid-yaml", `SKILL.md frontmatter is not valid YAML: ${cause instanceof Error ? cause.message : String(cause)}`, { cause })); } } /** * Quote top-level `key: value` lines whose value contains `: `, the most * common way hand-written frontmatter breaks YAML. Values that are already * quoted, block scalars, or flow collections are left alone. */ function quoteColonValues(yaml) { return yaml.split(/\r?\n/).map((line) => { const match = /^([A-Za-z0-9_-]+):[ \t]+(.+)$/.exec(line); if (!match) return line; const [, key, value] = match; if (value === void 0 || !value.includes(": ")) return line; if (/^["'|>[{&*!]/.test(value)) return line; return `${key}: ${JSON.stringify(value.trim())}`; }).join("\n"); } /** * Render a skill back to `SKILL.md` text. * * @param skill - The parsed skill. * @returns Frontmatter and body that {@link parseSkill} reads back to an * equal skill. */ function formatSkill(skill) { return `---\n${stringify({ name: skill.name, description: skill.description, ...skill.license === void 0 ? {} : { license: skill.license }, ...skill.compatibility === void 0 ? {} : { compatibility: skill.compatibility }, ...Object.keys(skill.metadata).length === 0 ? {} : { metadata: skill.metadata }, ...skill.allowedTools.length === 0 ? {} : { "allowed-tools": skill.allowedTools.join(" ") }, ...skill.extraFields }).trimEnd()}\n---\n${skill.body}`; } //#endregion export { parseSkill as n, formatSkill as t }; //# sourceMappingURL=markdown-BZ-VLtA1.js.map