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

Function parseScenario

scripts/skill-bench.js:95–182  ·  view source on GitHub ↗

* Parse a scenario .md file. * Frontmatter fields supported: * name — scenario identifier * skill — which skill this tests * description — human-readable summary * tags — comma-separated or YAML list: [fringe, missing-state] * input — the

(filePath)

Source from the content-addressed store, hash-verified

93 * @returns {object|null} parsed scenario, or null with error logged
94 */
95function parseScenario(filePath) {
96 let content;
97 try {
98 content = fs.readFileSync(filePath, 'utf8');
99 } catch (e) {
100 console.error(` ERROR reading ${filePath}: ${e.message}`);
101 return null;
102 }
103
104 const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
105 if (!fmMatch) {
106 console.error(` ERROR: ${path.basename(filePath)} has no frontmatter block`);
107 return null;
108 }
109
110 const raw = fmMatch[1];
111 const body = fmMatch[2].trim();
112 const fm = {};
113
114 // Parse YAML-like frontmatter
115 const lines = raw.split(/\r?\n/);
116 let i = 0;
117 let currentListKey = null;
118
119 while (i < lines.length) {
120 const line = lines[i];
121
122 // YAML list item
123 if (/^\s+-\s+/.test(line) && currentListKey) {
124 let value = line.replace(/^\s+-\s+/, '').trim();
125 // Strip surrounding quotes (YAML allows quoting list values: - "pattern")
126 value = value.replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1');
127 fm[currentListKey] = fm[currentListKey] || [];
128 fm[currentListKey].push(value);
129 i++;
130 continue;
131 }
132
133 // Key: value or Key: (list follows)
134 const kvMatch = line.match(/^([\w-]+):\s*(.*)/);
135 if (kvMatch) {
136 const key = kvMatch[1];
137 const val = kvMatch[2].trim();
138 currentListKey = null;
139
140 if (val === '' || val === '[]') {
141 // empty or explicit empty list — will be populated by list items below
142 fm[key] = [];
143 currentListKey = key;
144 } else if (val.startsWith('[') && val.endsWith(']')) {
145 // Inline list: [a, b, c]
146 fm[key] = val.slice(1, -1).split(',').map(s => s.trim()).filter(Boolean);
147 } else {
148 fm[key] = val.replace(/^"(.*)"$/, '$1').replace(/^'(.*)'$/, '$1');
149 }
150 } else {
151 currentListKey = null;
152 }

Callers 1

discoverScenariosFunction · 0.85

Calls

no outgoing calls

Tested by

no test coverage detected