MetaCraft/scripts/plan-next.js

393 lines
11 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
/**
* plan-next.js - 规划下一步功能
*
* 1. 分析当前项目状态待办任务已完成任务
* 2. 根据优先级推荐下一个要完成的任务
* 3. 生成对应的prompt文件或下一步文档
*/
const fs = require('fs');
const path = require('path');
const TODO_FILE = path.join(__dirname, '../meta/todo.md');
const PROMPTS_DIR = path.join(__dirname, '../prompts');
const OUTPUT_DIR = path.join(__dirname, '../docs/next-steps');
// 任务优先级映射
const PRIORITY_MAP = {
'核心功能开发': 'high',
'基础设施': 'medium',
'文档': 'medium',
'测试与质量': 'medium',
'未来功能': 'low'
};
// 解析待办任务文件
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,
priority: PRIORITY_MAP[currentCategory] || 'medium',
raw: line
});
}
}
return tasks;
}
// 分析项目状态并推荐下一个任务
function recommendNextTask(tasks) {
// 只考虑未完成的任务
const pendingTasks = tasks.filter(t => !t.checked);
if (pendingTasks.length === 0) {
return {
recommended: null,
message: '🎉 所有任务已完成!没有待推荐的任务。'
};
}
// 按优先级排序high > medium > low
const priorityOrder = { high: 1, medium: 2, low: 3 };
pendingTasks.sort((a, b) => {
if (priorityOrder[a.priority] !== priorityOrder[b.priority]) {
return priorityOrder[a.priority] - priorityOrder[b.priority];
}
// 同优先级按类别排序
const categoryOrder = ['核心功能开发', '基础设施', '文档', '测试与质量', '未来功能'];
return categoryOrder.indexOf(a.category) - categoryOrder.indexOf(b.category);
});
const recommendedTask = pendingTasks[0];
// 计算统计数据
const totalTasks = tasks.length;
const completedTasks = tasks.filter(t => t.checked).length;
const pendingByCategory = {};
pendingTasks.forEach(task => {
pendingByCategory[task.category] = (pendingByCategory[task.category] || 0) + 1;
});
return {
recommended: recommendedTask,
stats: {
totalTasks,
completedTasks,
pendingTasks: pendingTasks.length,
completionRate: totalTasks > 0 ? Math.round((completedTasks / totalTasks) * 100) : 0,
pendingByCategory
},
message: `🎯 推荐下一个任务:${recommendedTask.description} (优先级: ${recommendedTask.priority}, 类别: ${recommendedTask.category})`
};
}
// 为推荐的任务生成prompt文件
function generatePromptForTask(task) {
if (!task) return null;
// 生成文件名将任务描述转换为kebab-case
// 保留中文字符、英文字母、数字,将其他字符替换为空格,然后转换为连字符
const fileName = task.description
.toLowerCase()
// 保留中文字符 (\u4e00-\u9fff)、英文字母、数字、空格
.replace(/[^\u4e00-\u9fffa-z0-9\s]/g, ' ')
// 将连续的多个空格替换为单个空格
.replace(/\s+/g, ' ')
.trim()
// 将空格替换为连字符
.replace(/\s/g, '-')
.replace(/^implement-/, '') // 如果以implement-开头,去掉它
+ '.md';
const filePath = path.join(PROMPTS_DIR, fileName);
// 生成prompt内容
const promptContent = `# ${task.description}
<!-- target: ${task.description.toLowerCase().replace(/[^\u4e00-\u9fffa-z0-9\s]/g, ' ').replace(/\s+/g, ' ').trim().replace(/\s/g, '-').replace(/^implement-/, '')} -->
<!-- priority: ${task.priority} -->
<!-- category: ${task.category} -->
## 描述
详细描述${task.description}的功能需求和实现目标
## 要求
1. 明确的功能边界和交付物
2. 与现有系统集成的考虑
3. 代码质量标准和最佳实践
4. 必要的测试覆盖
## 上下文
当前项目状态
- 项目MetaCraft (AI驱动的元开发工具)
- 阶段早期开发
- 已完成任务${task.checked ? '是' : '否'}
- 优先级${task.priority}
相关依赖和前置条件
根据任务分析添加具体依赖
## 输出
请提供
1. 完整的设计方案
2. 具体的实现代码
3. 必要的测试用例
4. 文档更新建议
## 约束
- 保持与现有代码风格一致
- 考虑可扩展性和维护性
- 遵循项目架构设计原则`;
// 确保prompts目录存在
if (!fs.existsSync(PROMPTS_DIR)) {
fs.mkdirSync(PROMPTS_DIR, { recursive: true });
}
// 写入文件
fs.writeFileSync(filePath, promptContent, 'utf-8');
return {
filePath,
fileName,
promptContent
};
}
// 生成下一步文档
function generateNextStepDocument(task, stats) {
if (!task) return null;
// 确保输出目录存在
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
const timestamp = new Date().toISOString().split('T')[0];
const docFileName = `next-step-${timestamp}.md`;
const docFilePath = path.join(OUTPUT_DIR, docFileName);
const docContent = `# 下一步规划:${task.description}
生成时间${new Date().toLocaleString()}
## 项目状态概览
- 总任务数${stats.totalTasks}
- 已完成${stats.completedTasks}
- 待完成${stats.pendingTasks}
- 完成率${stats.completionRate}%
### 按类别待完成任务
${Object.entries(stats.pendingByCategory).map(([cat, count]) => `- ${cat}: ${count}`).join('\n')}
## 推荐的下一个任务
**任务描述**${task.description}
**优先级**${task.priority}
**类别**${task.category}
## 任务分析
### 为什么选择这个任务
1. **优先级最高**属于"${task.category}"类别在当前开发阶段最为关键
2. **依赖关系**可能是其他任务的前置条件
3. **价值最大**完成此任务将为后续开发奠定基础
### 预期影响
- 推动核心功能开发进度
- 为后续任务扫清障碍
- 验证工具链的有效性
## 详细需求
### 功能要求
1. 明确的功能定义和边界
2. 与现有系统的集成点
3. 输入/输出接口规范
4. 错误处理和边界情况
### 技术实现考虑
1. 代码结构和模块设计
2. 性能和安全要求
3. 测试策略和覆盖目标
4. 文档和示例代码
## 验收标准
- [ ] 功能实现完整且符合需求
- [ ] 代码质量符合项目标准
- [ ] 测试用例覆盖主要场景
- [ ] 文档更新及时准确
## 时间规划建议
**阶段1设计与规划** (1-2)
- 详细需求分析
- 技术方案设计
- 接口定义和原型验证
**阶段2实现与测试** (2-3)
- 核心功能实现
- 单元测试和集成测试
- 代码审查和优化
**阶段3集成与文档** (1)
- 系统集成和验证
- 文档编写和示例
- 部署和发布准备
## 风险与缓解
### 技术风险
- 与现有系统兼容性问题
- 性能瓶颈或扩展性限制
### 缓解措施
- 提前进行技术验证和原型测试
- 分阶段实现及时反馈和调整
## 后续任务建议
完成此任务后建议考虑
1. **${task.category}**中的其他高优先级任务
2. 依赖此任务的下游功能开发
3. 相关文档和测试完善
---
*本文档由MetaCraft的"规划下一步"功能自动生成*`;
fs.writeFileSync(docFilePath, docContent, 'utf-8');
return {
docFilePath,
docFileName,
docContent
};
}
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 recommendation = recommendNextTask(tasks);
console.log(recommendation.message);
if (recommendation.recommended) {
// 显示统计信息
console.log('\n📊 项目状态统计:');
console.log(` 总任务数:${recommendation.stats.totalTasks}`);
console.log(` 已完成:${recommendation.stats.completedTasks}`);
console.log(` 待完成:${recommendation.stats.pendingTasks}`);
console.log(` 完成率:${recommendation.stats.completionRate}%`);
console.log('\n📈 按类别待完成任务:');
Object.entries(recommendation.stats.pendingByCategory).forEach(([cat, count]) => {
console.log(` ${cat}: ${count}`);
});
// 询问用户要做什么
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function askQuestion(query) {
return new Promise(resolve => {
rl.question(query, answer => {
resolve(answer.trim());
});
});
}
console.log('\n📝 请选择操作:');
console.log(' 1. 为推荐任务生成prompt文件');
console.log(' 2. 生成下一步规划文档');
console.log(' 3. 两者都生成');
console.log(' 4. 只显示推荐,不生成文件');
const choice = await askQuestion('\n请输入选择 (1-4默认3): ') || '3';
let promptResult = null;
let docResult = null;
switch(choice) {
case '1':
promptResult = generatePromptForTask(recommendation.recommended);
break;
case '2':
docResult = generateNextStepDocument(recommendation.recommended, recommendation.stats);
break;
case '3':
promptResult = generatePromptForTask(recommendation.recommended);
docResult = generateNextStepDocument(recommendation.recommended, recommendation.stats);
break;
case '4':
console.log('\n👌 已跳过文件生成。');
break;
default:
console.log(`\n❌ 无效的选择:"${choice}",跳过文件生成。`);
}
// 输出生成结果
if (promptResult) {
console.log(`\n✅ 已生成prompt文件${promptResult.filePath}`);
}
if (docResult) {
console.log(`\n📄 已生成下一步规划文档:${docResult.docFilePath}`);
}
rl.close();
// 给出后续建议
if (promptResult || docResult) {
console.log('\n💡 后续建议:');
console.log(' 1. 查看生成的文件,根据需要调整内容');
console.log(' 2. 运行 bootstrap.js 执行该任务');
console.log(' 3. 或直接运行 promptnode scripts/run-prompt.js prompts/...');
}
} else {
console.log(recommendation.message);
}
}
if (require.main === module) {
main().catch(err => {
console.error('规划下一步功能错误:', err);
process.exit(1);
});
}
module.exports = {
parseTodo,
recommendNextTask,
generatePromptForTask,
generateNextStepDocument
};