UNPKG

cmte

Version:

Design by Committee™ except it's just you and LLMs

93 lines (84 loc) 2.86 kB
import yaml from 'js-yaml'; import { readFile } from '../../utils/fs.js'; import { logger } from '../../utils/logger.js'; /** * Extracts and validates frontmatter from content * @param {string} content Content to parse * @returns {Object} Object containing metadata and content */ export function extractFrontmatter(content) { const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/; const match = content.match(frontmatterRegex); if (!match) { return { metadata: {}, content }; } try { const [_, frontmatter, remainingContent] = match; const metadata = yaml.load(frontmatter); return { metadata, content: remainingContent }; } catch (error) { logger.error('Error parsing frontmatter YAML', { error }); throw new Error(`Failed to parse frontmatter: ${error.message}`); } } /** * Validates thinking configuration in frontmatter * @param {Object} metadata Frontmatter metadata * @throws {Error} If validation fails */ export function validateThinkingConfig(metadata) { if (!metadata.thinking) { return; // No thinking config to validate } // Validate thinking_paragraphs if present if (metadata.thinking_paragraphs !== undefined) { if (!Number.isInteger(metadata.thinking_paragraphs) || metadata.thinking_paragraphs < 1) { throw new Error('thinking_paragraphs must be a positive integer'); } } // Validate thinking_position if present if (metadata.thinking_position && !['prepend', 'append'].includes(metadata.thinking_position)) { throw new Error('thinking_position must be either "prepend" or "append"'); } // Validate thinking_prompt if present if (metadata.thinking_prompt && typeof metadata.thinking_prompt !== 'string') { throw new Error('thinking_prompt must be a string'); } } /** * Loads and validates a task file * @param {string} filePath Path to task file * @returns {Object} Task configuration and content */ export async function loadTaskFromFile(filePath) { try { const fileContent = await readFile(filePath); const { metadata, content } = extractFrontmatter(fileContent); // Validate thinking configuration if present validateThinkingConfig(metadata); // Return simplified task structure return { task: { name: metadata.name, thinking: metadata.thinking || false, thinkingConfig: metadata.thinking ? { paragraphs: metadata.thinking_paragraphs || 5, position: metadata.thinking_position || 'append', instruction: metadata.thinking_instruction, introduction: metadata.thinking_introduction, promptFile: metadata.thinking_prompt } : null }, content }; } catch (error) { logger.error(`Error loading task from file: ${filePath}`, { error }); throw error; } }