MCPcopy Create free account
hub / github.com/garrytan/gstack / extractGbrainBlock

Function extractGbrainBlock

lib/gstack-memory-helpers.ts:357–419  ·  view source on GitHub ↗
(frontmatter: string)

Source from the content-addressed store, hash-verified

355}
356
357function extractGbrainBlock(frontmatter: string): GbrainManifest | null {
358 // Naive YAML extraction — finds the `gbrain:` key and parses its sub-tree.
359 // Real YAML parsing avoided to keep zero-deps; gen-skill-docs validates the
360 // shape strictly at build time.
361 const lines = frontmatter.split("\n");
362 const start = lines.findIndex((l) => /^gbrain\s*:/.test(l));
363 if (start === -1) return null;
364
365 // Collect indented lines under `gbrain:` until next top-level key or EOF
366 const block: string[] = [];
367 for (let i = start + 1; i < lines.length; i++) {
368 const line = lines[i];
369 if (/^[A-Za-z_][A-Za-z0-9_-]*\s*:/.test(line)) break; // next top-level key
370 block.push(line);
371 }
372
373 const text = block.join("\n");
374 // Extract schema number
375 const schemaMatch = text.match(/\n\s*schema\s*:\s*(\d+)/);
376 const schema = schemaMatch ? parseInt(schemaMatch[1], 10) : 1;
377
378 // Extract context_queries items
379 const queries: GbrainManifestQuery[] = [];
380 const cqMatch = text.match(/\n\s*context_queries\s*:\s*\n([\s\S]+)/);
381 if (cqMatch) {
382 const cqText = cqMatch[1];
383 // Split using a positive lookahead so each chunk begins with the list-item dash.
384 // Pattern: line starting with 4-6 spaces + "-" + whitespace.
385 const rawItems = cqText.split(/(?=^[ ]{4,6}-\s)/m);
386 const items = rawItems.filter((s) => /^[ ]{4,6}-\s/.test(s));
387 for (const item of items) {
388 const q: Partial<GbrainManifestQuery> = {};
389 // Strip the leading list-item marker so id/kind/etc. regexes can use line-start.
390 const body = item.replace(/^[ ]{4,6}-\s+/, " ");
391 const idM = body.match(/(?:^|\n)\s*id\s*:\s*([^\n]+)/);
392 const kindM = body.match(/(?:^|\n)\s*kind\s*:\s*([^\n]+)/);
393 const renderM = body.match(/(?:^|\n)\s*render_as\s*:\s*"?([^"\n]+?)"?\s*$/m);
394 const queryM = body.match(/(?:^|\n)\s*query\s*:\s*"?([^"\n]+?)"?\s*$/m);
395 const limitM = body.match(/(?:^|\n)\s*limit\s*:\s*(\d+)/);
396 const globM = body.match(/(?:^|\n)\s*glob\s*:\s*"?([^"\n]+?)"?\s*$/m);
397 const sortM = body.match(/(?:^|\n)\s*sort\s*:\s*([^\n]+)/);
398 const tailM = body.match(/(?:^|\n)\s*tail\s*:\s*(\d+)/);
399
400 if (idM) q.id = idM[1].trim();
401 if (kindM) {
402 const k = kindM[1].trim();
403 if (k === "vector" || k === "list" || k === "filesystem") q.kind = k;
404 }
405 if (renderM) q.render_as = renderM[1].trim();
406 if (queryM) q.query = queryM[1].trim();
407 if (limitM) q.limit = parseInt(limitM[1], 10);
408 if (globM) q.glob = globM[1].trim();
409 if (sortM) q.sort = sortM[1].trim();
410 if (tailM) q.tail = parseInt(tailM[1], 10);
411
412 if (q.id && q.kind && q.render_as) {
413 queries.push(q as GbrainManifestQuery);
414 }

Callers 1

parseSkillManifestFunction · 0.85

Calls 1

pushMethod · 0.45

Tested by

no test coverage detected