Skip to main content
Glama
parse.ts•9.58 kB
import { Command } from 'commander'; import { PRDIntegrationService } from '../../integrations/prd-integration.js'; import { TaskListIntegrationService } from '../../integrations/task-list-integration.js'; import { getProjectOperations } from '../../core/operations/project-operations.js'; import { CLIUtils } from './index.js'; import logger from '../../../../logger.js'; /** * Parse command for PRDs and task lists */ export const parseCommand = new Command('parse') .description('Parse existing PRDs and task lists from generators') .configureHelp({ sortSubcommands: true }); /** * Parse PRD subcommand */ const parsePRDCommand = new Command('prd') .description('Parse an existing PRD from prd-generator') .option('-p, --project <name>', 'Project name to filter PRDs') .option('-f, --file <path>', 'Specific PRD file path') .option('--format <format>', 'Output format (table|json|yaml)', 'table') .option('--create-project', 'Create project from PRD after parsing', false) .action(async (options) => { try { logger.info({ options }, 'Parsing PRD via CLI'); // Get PRD integration service const prdService = PRDIntegrationService.getInstance(); // Detect or parse PRD let prdInfo; if (options.file) { // Use specific file path CLIUtils.info(`Parsing PRD from: ${options.file}`); const result = await prdService.parsePRD(options.file); if (!result.success) { CLIUtils.error(`Failed to parse PRD: ${result.error}`); } prdInfo = result.prdData!; } else { // Auto-detect PRD CLIUtils.info(`Detecting existing PRD${options.project ? ` for project "${options.project}"` : ''}...`); const detectedPRD = await prdService.detectExistingPRD(options.project); if (!detectedPRD) { CLIUtils.error(`No PRD found${options.project ? ` for project "${options.project}"` : ''}. Please ensure a PRD exists in the VibeCoderOutput/prd-generator/ directory.`); } CLIUtils.info(`Found PRD: ${detectedPRD.fileName}`); const result = await prdService.parsePRD(detectedPRD.filePath); if (!result.success) { CLIUtils.error(`Failed to parse PRD: ${result.error}`); } prdInfo = result.prdData!; } // Display PRD information CLIUtils.success('PRD parsed successfully!'); const displayData = { 'Project Name': prdInfo.metadata.projectName, 'File Path': prdInfo.metadata.filePath, 'File Size': `${(prdInfo.metadata.fileSize / 1024).toFixed(1)} KB`, 'Created At': CLIUtils.formatDate(prdInfo.metadata.createdAt), 'Features Count': prdInfo.features.length, 'Tech Stack': prdInfo.technical.techStack.slice(0, 3).join(', ') + (prdInfo.technical.techStack.length > 3 ? '...' : ''), 'Business Goals': prdInfo.overview.businessGoals.length, 'Product Goals': prdInfo.overview.productGoals.length }; console.log('\nPRD Details:'); console.log(CLIUtils.formatOutput(displayData, options.format)); // Show features if (prdInfo.features.length > 0) { console.log('\nFeatures:'); prdInfo.features.slice(0, 10).forEach((feature, index) => { console.log(` ${index + 1}. ${feature.title} (${feature.priority})`); }); if (prdInfo.features.length > 10) { console.log(` ... and ${prdInfo.features.length - 10} more features`); } } // Create project if requested if (options.createProject) { CLIUtils.info('Creating project from PRD...'); const projectOperations = getProjectOperations(); const projectResult = await projectOperations.createProjectFromPRD(prdInfo as unknown as Record<string, unknown>, 'cli-user'); if (!projectResult.success) { CLIUtils.error(`Failed to create project from PRD: ${projectResult.error}`); } const project = projectResult.data!; CLIUtils.success(`Project created: ${project.id} - ${project.name}`); } logger.info({ projectName: prdInfo.metadata.projectName }, 'PRD parsed successfully via CLI'); } catch (error) { logger.error({ err: error, options }, 'Failed to parse PRD via CLI'); CLIUtils.error(error instanceof Error ? error.message : 'Unknown error occurred'); } }); /** * Parse task list subcommand */ const parseTasksCommand = new Command('tasks') .description('Parse an existing task list from task-list-generator') .option('-p, --project <name>', 'Project name to filter task lists') .option('-f, --file <path>', 'Specific task list file path') .option('--format <format>', 'Output format (table|json|yaml)', 'table') .option('--create-project', 'Create project from task list after parsing', false) .action(async (options) => { try { logger.info({ options }, 'Parsing task list via CLI'); // Get task list integration service const taskListService = TaskListIntegrationService.getInstance(); // Detect or parse task list let taskListInfo; if (options.file) { // Use specific file path CLIUtils.info(`Parsing task list from: ${options.file}`); const result = await taskListService.parseTaskList(options.file); if (!result.success) { CLIUtils.error(`Failed to parse task list: ${result.error}`); } taskListInfo = result.taskListData!; } else { // Auto-detect task list CLIUtils.info(`Detecting existing task list${options.project ? ` for project "${options.project}"` : ''}...`); const detectedTaskList = await taskListService.detectExistingTaskList(options.project); if (!detectedTaskList) { CLIUtils.error(`No task list found${options.project ? ` for project "${options.project}"` : ''}. Please ensure a task list exists in the VibeCoderOutput/generated_task_lists/ directory.`); } CLIUtils.info(`Found task list: ${detectedTaskList.fileName}`); const result = await taskListService.parseTaskList(detectedTaskList.filePath); if (!result.success) { CLIUtils.error(`Failed to parse task list: ${result.error}`); } taskListInfo = result.taskListData!; } // Display task list information CLIUtils.success('Task list parsed successfully!'); const displayData = { 'Project Name': taskListInfo.metadata.projectName, 'File Path': taskListInfo.metadata.filePath, 'File Size': `${(taskListInfo.metadata.fileSize / 1024).toFixed(1)} KB`, 'Created At': CLIUtils.formatDate(taskListInfo.metadata.createdAt), 'Total Tasks': taskListInfo.metadata.totalTasks, 'Phases': taskListInfo.metadata.phaseCount, 'Estimated Hours': taskListInfo.statistics.totalEstimatedHours, 'List Type': taskListInfo.metadata.listType }; console.log('\nTask List Details:'); console.log(CLIUtils.formatOutput(displayData, options.format)); // Show phases if (taskListInfo.phases.length > 0) { console.log('\nPhases:'); taskListInfo.phases.forEach((phase, index) => { console.log(` ${index + 1}. ${phase.name} (${phase.tasks.length} tasks)`); }); } // Create project if requested if (options.createProject) { CLIUtils.info('Creating project from task list...'); const projectOperations = getProjectOperations(); const projectResult = await projectOperations.createProjectFromTaskList(taskListInfo as unknown as Record<string, unknown>, 'cli-user'); if (!projectResult.success) { CLIUtils.error(`Failed to create project from task list: ${projectResult.error}`); } const project = projectResult.data!; CLIUtils.success(`Project created: ${project.id} - ${project.name}`); // Convert to atomic tasks const atomicTasks = await taskListService.convertToAtomicTasks( taskListInfo, project.id, 'default-epic', 'cli-user' ); CLIUtils.info(`Created ${atomicTasks.length} atomic tasks`); } logger.info({ projectName: taskListInfo.metadata.projectName }, 'Task list parsed successfully via CLI'); } catch (error) { logger.error({ err: error, options }, 'Failed to parse task list via CLI'); CLIUtils.error(error instanceof Error ? error.message : 'Unknown error occurred'); } }); // Add subcommands to parse command parseCommand.addCommand(parsePRDCommand); parseCommand.addCommand(parseTasksCommand); // Add help examples parseCommand.addHelpText('after', ` Examples: # Parse PRD files $ vibe-tasks parse prd --project "E-commerce Platform" --create-project $ vibe-tasks parse prd --file "/path/to/ecommerce-prd.md" $ vibe-tasks parse prd --project "My Web App" --format json # Parse task list files $ vibe-tasks parse tasks --project "Mobile App" --create-project $ vibe-tasks parse tasks --file "/path/to/mobile-task-list-detailed.md" $ vibe-tasks parse tasks --project "E-commerce Platform" --format yaml # Auto-discovery (searches VibeCoderOutput directories) $ vibe-tasks parse prd --project "My Project" $ vibe-tasks parse tasks --project "My Project" # Import with specific file paths $ vibe-tasks parse prd --file "VibeCoderOutput/prd-generator/ecommerce-prd.md" $ vibe-tasks parse tasks --file "VibeCoderOutput/generated_task_lists/mobile-task-list-detailed.md" `);

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/freshtechbro/vibe-coder-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server