openai-compatible-task-master
Version:
使用MCP解析PRD文档并生成任务列表
165 lines (162 loc) • 6.34 kB
JavaScript
import * as fs from 'fs';
import * as path from 'path';
/**
* 递归查找任务
* @param tasks 任务列表
* @param targetId 目标任务ID
* @returns 找到的任务及其父任务链
*/
function findTaskWithParentChain(tasks, targetId) {
function findInTasks(tasks, parentChain = []) {
for (const task of tasks) {
// 检查当前任务
if (String(task.id) === targetId) {
return { task, parentChain };
}
// 检查子任务
if (task.subTasks) {
for (const subTask of task.subTasks) {
if (String(subTask.id) === targetId) {
return { task: subTask, parentChain: [task, ...parentChain] };
}
// 递归检查更深层的子任务
const result = findInTasks(subTask.subTasks || [], [task, ...parentChain]);
if (result.task) {
return result;
}
}
}
}
return { task: null, parentChain: [] };
}
return findInTasks(tasks);
}
/**
* 检查所有子任务是否完成
* @param task 任务
* @returns 是否所有子任务已完成
* @internal
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function areAllSubTasksDone(task) {
if (!task.subTasks || task.subTasks.length === 0) {
return true;
}
return task.subTasks.every(subTask => {
if (subTask.status !== 'done') {
return false;
}
return areAllSubTasksDone(subTask);
});
}
/**
* 检查父任务链中是否有已完成的任务
* @param tasks 任务列表
* @param taskId 任务ID
* @returns 是否存在已完成的父任务
* @internal
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function hasCompletedParent(tasks, taskId) {
const parts = taskId.split('.');
if (parts.length <= 1)
return false;
// 构建父任务ID
const parentId = parts.slice(0, -1).join('.');
const { task: parentTask } = findTaskWithParentChain(tasks, parentId);
if (!parentTask)
return false;
return parentTask.status === 'done';
}
/**
* 设置任务状态
* @param projectDir 项目根目录
* @param tasksPath 任务文件路径
* @param taskId 要更新的任务ID
* @param status 新状态
* @param completionSummary 完成总结(仅在status为done时有效)
* @returns 包含操作结果的对象
*/
export async function setTaskStatus(projectDir, tasksPath, taskId, status, completionSummary) {
// 验证状态值
if (!['pending', 'in-progress', 'done'].includes(status)) {
return { saved: false, message: '无效的状态值。必须是 pending、in-progress 或 done 之一' };
}
// 验证completionSummary
if (status === 'done' && !completionSummary) {
return {
saved: false,
message: `当状态设置为done时,必须使用--summary参数提供完成总结。
如何写好完成总结:
1. 简明扼要地描述已实现的功能和解决的问题
2. 提及重要的实现细节和采用的技术方案
3. 指出任何潜在的限制或需要注意的事项
4. 如有适用,提及后续可能的优化方向
示例:--summary "实现了用户认证功能,包括登录、注册和密码重置。采用JWT进行身份验证,使用bcrypt加密密码。添加了必要的输入验证和错误处理。"
命令示例:
npx octm-cli set-status --task-id ${taskId} --status done --summary "实现了任务要求的功能,包括...,解决了...的问题"`
};
}
try {
// 构建完整的任务文件路径
const fullTasksPath = path.resolve(projectDir, tasksPath);
// 检查任务文件是否存在
if (!fs.existsSync(fullTasksPath)) {
throw new Error(`任务文件不存在: ${fullTasksPath}`);
}
// 读取任务文件
const tasksContent = fs.readFileSync(fullTasksPath, 'utf8');
const tasksData = JSON.parse(tasksContent);
// 查找要更新的任务
let taskFound = false;
const updateTaskStatus = (tasks) => {
for (const task of tasks) {
// 检查当前任务是否匹配
if (task.id === taskId) {
// 如果任务已经完成,不允许更改状态
if (task.status === 'done' && status !== 'done') {
return false;
}
// 更新任务状态
task.status = status;
// 如果状态是done,设置完成总结;否则清除完成总结
if (status === 'done') {
task.completionSummary = completionSummary;
}
else if (task.completionSummary) {
// 如果状态不是done但存在完成总结,清除它
delete task.completionSummary;
}
taskFound = true;
return true;
}
// 递归检查子任务
if (task.subTasks && task.subTasks.length > 0) {
const subtaskUpdated = updateTaskStatus(task.subTasks);
if (subtaskUpdated) {
return true;
}
}
}
return false;
};
// 尝试更新任务状态
const updated = updateTaskStatus(tasksData.tasks);
if (!taskFound) {
return { saved: false, message: `未找到ID为 ${taskId} 的任务` };
}
if (!updated) {
return { saved: false, message: '无法更新任务状态。已完成的任务不能更改为其他状态' };
}
// 保存更新后的任务文件
fs.writeFileSync(fullTasksPath, JSON.stringify(tasksData, null, 2));
return {
saved: true,
message: `已将任务 ${taskId} 的状态更新为 ${status}${status === 'done' ? ',并添加了完成总结' : ''}`
};
}
catch (error) {
throw new Error(`更新任务状态时出错: ${error.message}`);
}
}
//# sourceMappingURL=set_status.js.map