MetaCraft/scripts/bootstrap.js

176 lines
4.5 KiB
JavaScript
Raw Normal View History

#!/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 };