#!/usr/bin/env node /** * bootstrap.js - MetaCraft 自举循环入口 * * 1. 读取待办任务列表 * 2. 显示可选任务 * 3. 执行选中的任务(调用对应prompt) * 4. 验证结果并更新任务状态 */ const fs = require('fs'); const path = require('path'); const readline = require('readline'); const TODO_FILE = path.join(__dirname, '../meta/todo.md'); const PROMPTS_DIR = path.join(__dirname, '../prompts'); // 解析待办任务文件 function parseTodo(content) { const lines = content.split('\n'); const tasks = []; let currentCategory = ''; for (const line of lines) { const categoryMatch = line.match(/^##\s+(.+)/); if (categoryMatch) { currentCategory = categoryMatch[1].trim(); continue; } const taskMatch = line.match(/^- \[( |x)\]\s+(.+)/); if (taskMatch) { const checked = taskMatch[1] === 'x'; const description = taskMatch[2].trim(); tasks.push({ category: currentCategory, description, checked, raw: line }); } } return tasks; } // 更新待办任务文件 function updateTodo(tasks, updatedTask) { // 简化的实现:找到对应行并替换 const content = fs.readFileSync(TODO_FILE, 'utf-8'); const lines = content.split('\n'); for (let i = 0; i < lines.length; i++) { if (lines[i].includes(updatedTask.description)) { const newLine = lines[i].replace('- [ ]', '- [x]'); lines[i] = newLine; break; } } fs.writeFileSync(TODO_FILE, lines.join('\n'), 'utf-8'); } // 查找对应prompt文件 function findPromptForTask(task) { // 简单映射:将任务描述转换为文件名 const name = task.description .toLowerCase() .replace(/[^\w\s]/g, '') .replace(/\s+/g, '-'); const possiblePaths = [ path.join(PROMPTS_DIR, `${name}.md`), path.join(PROMPTS_DIR, `implement-${name}.md`), path.join(PROMPTS_DIR, `task-${name}.md`) ]; for (const p of possiblePaths) { if (fs.existsSync(p)) { return p; } } return null; } async function main() { console.log('🚀 MetaCraft 自举循环启动\n'); if (!fs.existsSync(TODO_FILE)) { console.error('❌ 待办任务文件不存在:', TODO_FILE); process.exit(1); } const todoContent = fs.readFileSync(TODO_FILE, 'utf-8'); const tasks = parseTodo(todoContent); const pendingTasks = tasks.filter(t => !t.checked); if (pendingTasks.length === 0) { console.log('🎉 所有任务已完成!'); return; } console.log('📋 待办任务列表:'); pendingTasks.forEach((task, index) => { console.log(` ${index + 1}. [${task.category}] ${task.description}`); }); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); function askQuestion(query) { return new Promise(resolve => { rl.question(query, answer => { resolve(answer); }); }); } const answer = await askQuestion('\n请输入要执行的任务编号(或按回车跳过):'); rl.close(); if (!answer.trim()) { console.log('⏭️ 跳过任务选择'); return; } const taskIndex = parseInt(answer) - 1; if (isNaN(taskIndex) || taskIndex < 0 || taskIndex >= pendingTasks.length) { console.error('❌ 无效的选择'); process.exit(1); } const selectedTask = pendingTasks[taskIndex]; console.log(`\n🎯 选中任务:${selectedTask.description}`); const promptPath = findPromptForTask(selectedTask); if (!promptPath) { console.error(`❌ 未找到对应prompt文件,请在 ${PROMPTS_DIR} 中创建。`); console.log('提示:prompt文件名应与任务描述相关,如 "implement-prompt-engine.md"'); return; } console.log(`📄 找到prompt文件:${promptPath}`); // 执行prompt const { main: runPrompt } = require('./run-prompt'); await runPrompt([promptPath]); // 询问是否标记为完成 const confirm = await new Promise(resolve => { const confirmRl = readline.createInterface({ input: process.stdin, output: process.stdout }); confirmRl.question('\n✅ 任务是否已完成?(y/n) ', answer => { confirmRl.close(); resolve(answer.toLowerCase() === 'y'); }); }); if (confirm) { updateTodo(tasks, selectedTask); console.log('📝 已更新待办任务状态'); } else { console.log('⚠️ 任务状态未更新,请手动处理'); } } if (require.main === module) { main().catch(err => { console.error('自举循环错误:', err); process.exit(1); }); } module.exports = { parseTodo, findPromptForTask };