176 lines
4.5 KiB
JavaScript
176 lines
4.5 KiB
JavaScript
#!/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 }; |