fix: strip frontmatter from injected skill content and share parser from src
This commit is contained in:
1 parent
023e012eda
commit
d301ef5a62
7 files changed
+108
-43
No files matched your search
@@ -1,42 +0,0 @@
|
||||
// Minimal YAML-subset frontmatter parser for upstream SKILL.md files.
|
||||
// Supports exactly what mattpocock/skills uses (census 2026-10-14, @49dd158): top-level
|
||||
// `key: value` scalars, double/single-quoted strings with \" escapes, and nested blocks
|
||||
// (e.g. `metadata:`) which are skipped. test/generate.test.ts asserts every vendored skill
|
||||
// parses with non-empty name+description, so an upstream format change fails the build
|
||||
// instead of silently producing a broken manifest.
|
||||
|
||||
export type Frontmatter = Record<string, string>
|
||||
|
||||
export function parseFrontmatter(content: string): { frontmatter: Frontmatter; body: string } {
|
||||
const text = content.replace(/^\uFEFF/, "")
|
||||
if (!text.startsWith("---\n") && !text.startsWith("---\r\n")) {
|
||||
return { frontmatter: {}, body: text }
|
||||
}
|
||||
const end = text.indexOf("\n---", 3)
|
||||
if (end === -1) return { frontmatter: {}, body: text }
|
||||
const raw = text.slice(text.indexOf("\n") + 1, end + 1)
|
||||
const body = text.slice(text.indexOf("\n", end + 1) + 1)
|
||||
|
||||
const frontmatter: Frontmatter = {}
|
||||
for (const line of raw.split(/\r?\n/)) {
|
||||
if (!line || /^\s/.test(line) || line.trim() === "---") continue // nested block or separator
|
||||
const m = /^([A-Za-z][\w-]*):\s*(.*)$/.exec(line)
|
||||
if (!m) continue
|
||||
frontmatter[m[1]] = unquote(m[2].trim())
|
||||
}
|
||||
return { frontmatter, body }
|
||||
}
|
||||
|
||||
function unquote(value: string): string {
|
||||
if (value.length >= 2 && value.startsWith('"') && value.endsWith('"')) {
|
||||
return value.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, "\\")
|
||||
}
|
||||
if (value.length >= 2 && value.startsWith("'") && value.endsWith("'")) {
|
||||
return value.slice(1, -1).replace(/''/g, "'")
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
export function isUserInvoked(frontmatter: Frontmatter): boolean {
|
||||
return frontmatter["disable-model-invocation"] === "true"
|
||||
}
|
||||
+10
-2
@@ -10,10 +10,18 @@
|
||||
//
|
||||
// Deterministic: same inputs produce byte-identical outputs, so the nightly git diff is the
|
||||
// affected-set report. Never hand-edit skills/ or the matrix section.
|
||||
import { cpSync, existsSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs"
|
||||
import {
|
||||
cpSync,
|
||||
existsSync,
|
||||
readFileSync,
|
||||
readdirSync,
|
||||
rmSync,
|
||||
statSync,
|
||||
writeFileSync,
|
||||
} from "node:fs"
|
||||
import path from "node:path"
|
||||
import { fileURLToPath } from "node:url"
|
||||
import { isUserInvoked, parseFrontmatter } from "./frontmatter.ts"
|
||||
import { isUserInvoked, parseFrontmatter } from "../src/frontmatter.ts"
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..")
|
||||
|
||||
|
||||
Reference in new issue
Block a user