MCPcopy Create free account
hub / github.com/SethGammon/Citadel / parseFrontmatter

Function parseFrontmatter

scripts/skill-lint.js:195–239  ·  view source on GitHub ↗

* Extract key-value pairs from a YAML-like frontmatter block. * Handles: string values, booleans, multiline (>-), and simple lists. * * @param {string} content - Full SKILL.md content * @returns {{ frontmatter: object|null, body: string }}

(content)

Source from the content-addressed store, hash-verified

193 * @returns {{ frontmatter: object|null, body: string }}
194 */
195function parseFrontmatter(content) {
196 const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
197 if (!match) return { frontmatter: null, body: content };
198
199 const raw = match[1];
200 const body = match[2];
201 const fm = {};
202
203 const lines = raw.split(/\r?\n/);
204 let i = 0;
205 while (i < lines.length) {
206 const line = lines[i];
207
208 // Multiline value (>- or |)
209 const multilineMatch = line.match(/^(\S[\w-]*):\s*[>|]-?\s*$/);
210 if (multilineMatch) {
211 const key = multilineMatch[1];
212 const parts = [];
213 i++;
214 while (i < lines.length && /^\s+/.test(lines[i])) {
215 parts.push(lines[i].trim());
216 i++;
217 }
218 fm[key] = parts.join(' ');
219 continue;
220 }
221
222 // Simple key: value
223 const kvMatch = line.match(/^(\S[\w-]*):\s*(.*)/);
224 if (kvMatch) {
225 const key = kvMatch[1];
226 const val = kvMatch[2].trim();
227 if (val === 'true') fm[key] = true;
228 else if (val === 'false') fm[key] = false;
229 else if (val.startsWith('[') && val.endsWith(']')) {
230 fm[key] = val.slice(1, -1).split(',').map(s => s.trim()).filter(Boolean);
231 }
232 else if (val === '') fm[key] = null;
233 else fm[key] = val;
234 }
235 i++;
236 }
237
238 return { frontmatter: fm, body };
239}
240
241// ── Skill discovery ───────────────────────────────────────────────────────────
242

Callers 2

countPendingIntakeItemsFunction · 0.70
lintSkillFunction · 0.70

Calls

no outgoing calls

Tested by

no test coverage detected