新增任務相關欄位,包括全局分析結果、實現指南及驗證標準,並調整任務更新邏輯以支持這些新欄位,提升任務管理的完整性與可追溯性。

This commit is contained in:
siage 2025-04-13 20:06:47 +08:00
parent b312ec0863
commit 6b6d7b6867
5 changed files with 314 additions and 136 deletions

View File

@ -132,6 +132,12 @@ async function main() {
.describe(
"任務更新模式選擇:'append'(保留所有現有任務並添加新任務)、'overwrite'(清除所有未完成任務並完全替換,保留已完成任務)、'selective'(智能更新:根據任務名稱匹配更新現有任務,保留不在列表中的任務,推薦用於任務微調)、'clearAllTasks'(清除所有任務並創建備份)。\n預設為'clearAllTasks'模式,只有用戶要求變更或修改計畫內容才使用其他模式"
),
globalAnalysisResult: z
.string()
.optional()
.describe(
"全局分析結果:來自 reflect_task 的完整分析結果,適用於所有任務的通用部分"
),
tasks: z
.array(
z.object({
@ -178,6 +184,14 @@ async function main() {
)
.optional()
.describe("與任務相關的檔案列表,包含檔案路徑、類型和描述"),
implementationGuide: z
.string()
.optional()
.describe("此特定任務的具體實現方法和步驟"),
verificationCriteria: z
.string()
.optional()
.describe("此特定任務的驗證標準和檢驗方法"),
})
)
.describe("結構化的任務清單,每個任務應保持原子性且有明確的完成標準"),
@ -303,7 +317,7 @@ async function main() {
.enum([
RelatedFileType.TO_MODIFY,
RelatedFileType.REFERENCE,
RelatedFileType.OUTPUT,
RelatedFileType.CREATE,
RelatedFileType.DEPENDENCY,
RelatedFileType.OTHER,
])

View File

@ -262,150 +262,202 @@ export async function batchCreateOrUpdateTasks(
notes?: string;
dependencies?: string[];
relatedFiles?: RelatedFile[];
implementationGuide?: string; // 新增:實現指南
verificationCriteria?: string; // 新增:驗證標準
}>,
updateMode: "append" | "overwrite" | "selective" | "clearAllTasks" // 必填參數,指定任務更新策略
updateMode: "append" | "overwrite" | "selective" | "clearAllTasks", // 必填參數,指定任務更新策略
globalAnalysisResult?: string // 新增:全局分析結果
): Promise<Task[]> {
// 獲取現有任務
// 讀取現有的所有任務
const existingTasks = await readTasks();
const nameToIdMap = new Map<string, string>();
const idToTaskMap = new Map<string, Task>();
// 添加現有任務到映射表
existingTasks.forEach((task) => {
nameToIdMap.set(task.name, task.id);
idToTaskMap.set(task.id, task);
});
// 根據更新模式處理現有任務
let tasksToKeep: Task[] = [];
// 處理不同的更新模式
if (updateMode === "overwrite") {
// 覆蓋模式:只刪除未完成的任務,保留已完成的任務
const completedTasks = existingTasks.filter(
if (updateMode === "append") {
// 追加模式:保留所有現有任務
tasksToKeep = [...existingTasks];
} else if (updateMode === "overwrite") {
// 覆蓋模式:僅保留已完成的任務,清除所有未完成任務
tasksToKeep = existingTasks.filter(
(task) => task.status === TaskStatus.COMPLETED
);
await writeTasks(completedTasks);
// 更新映射表,只保留已完成的任務
nameToIdMap.clear();
idToTaskMap.clear();
completedTasks.forEach((task) => {
nameToIdMap.set(task.name, task.id);
idToTaskMap.set(task.id, task);
});
} else if (updateMode === "selective") {
// selective 模式:保留未在清單中的現有任務,更新名稱匹配的任務
// 不做任何預處理,保留所有現有任務,在處理每個新任務時進行選擇性更新
} else {
// append 模式:保留所有現有任務,不需要特殊處理
// 選擇性更新模式:根據任務名稱選擇性更新,保留未在更新列表中的任務
// 1. 提取待更新任務的名稱清單
const updateTaskNames = new Set(taskDataList.map((task) => task.name));
// 2. 保留所有沒有出現在更新列表中的任務
tasksToKeep = existingTasks.filter(
(task) => !updateTaskNames.has(task.name)
);
} else if (updateMode === "clearAllTasks") {
// 清除所有任務模式:清空任務列表
tasksToKeep = [];
}
// 創建任務名稱集合,用於選擇性更新模式
const taskNameSet = new Set(taskDataList.map((task) => task.name));
// 這個映射將用於存儲名稱到任務ID的映射用於支持通過名稱引用任務
const taskNameToIdMap = new Map<string, string>();
// 準備最終的任務清單,如果是 selective 模式,先保留不在新清單中的任務
let finalTaskList: Task[] = [];
// 對於選擇性更新模式先將現有任務的名稱和ID記錄下來
if (updateMode === "selective") {
finalTaskList = existingTasks.filter((task) => !taskNameSet.has(task.name));
existingTasks.forEach((task) => {
taskNameToIdMap.set(task.name, task.id);
});
}
// 第一階段:創建或更新任務,但不設置依賴
const firstPassTasks: Array<{ task: Task; originalDeps: string[] }> = [];
// 記錄所有任務的名稱和ID無論是要保留的任務還是新建的任務
// 這將用於稍後解析依賴關係
tasksToKeep.forEach((task) => {
taskNameToIdMap.set(task.name, task.id);
});
// 創建新任務的列表
const newTasks: Task[] = [];
for (const taskData of taskDataList) {
let newTask: Task;
// 檢查是否為選擇性更新模式且該任務名稱已存在
if (updateMode === "selective" && taskNameToIdMap.has(taskData.name)) {
// 獲取現有任務的ID
const existingTaskId = taskNameToIdMap.get(taskData.name)!;
// 查找是否存在同名任務
const existingTaskId = nameToIdMap.get(taskData.name);
const isExistingTask = existingTaskId !== undefined;
// 查找現有任務
const existingTaskIndex = existingTasks.findIndex(
(task) => task.id === existingTaskId
);
if (isExistingTask && updateMode === "selective") {
// 選擇性更新模式:更新現有任務
const existingTask = idToTaskMap.get(existingTaskId)!;
// 如果找到現有任務並且該任務未完成,則更新它
if (
existingTaskIndex !== -1 &&
existingTasks[existingTaskIndex].status !== TaskStatus.COMPLETED
) {
const taskToUpdate = existingTasks[existingTaskIndex];
// 更新任務內容但保留原始ID和創建時間
newTask = (await updateTask(existingTaskId, {
name: taskData.name,
description: taskData.description,
notes: taskData.notes,
// 暫時不更新依賴,在第二階段處理
relatedFiles: taskData.relatedFiles,
})) as Task;
// 更新任務的基本信息但保留原始ID、創建時間等
const updatedTask: Task = {
...taskToUpdate,
name: taskData.name,
description: taskData.description,
notes: taskData.notes,
// 後面會處理 dependencies
updatedAt: new Date(),
// 新增:保存實現指南(如果有)
implementationGuide: taskData.implementationGuide,
// 新增:保存驗證標準(如果有)
verificationCriteria: taskData.verificationCriteria,
// 新增:保存全局分析結果(如果有)
analysisResult: globalAnalysisResult,
};
// 如果更新失敗,使用現有任務作為後備
if (!newTask) {
console.warn(
`警告:更新任務 "${taskData.name}" 失敗,使用現有任務作為後備`
);
newTask = existingTask;
// 處理相關文件(如果有)
if (taskData.relatedFiles) {
updatedTask.relatedFiles = taskData.relatedFiles;
}
// 將更新後的任務添加到新任務列表
newTasks.push(updatedTask);
// 從tasksToKeep中移除此任務因為它已經被更新並添加到newTasks中了
tasksToKeep = tasksToKeep.filter((task) => task.id !== existingTaskId);
} else {
// 如果任務已完成或找不到,則跳過更新,可能在控制台輸出警告
if (
existingTaskIndex !== -1 &&
existingTasks[existingTaskIndex].status === TaskStatus.COMPLETED
) {
console.warn(
`警告:嘗試更新已完成的任務 "${taskData.name}",操作被忽略`
);
} else {
console.warn(
`警告:嘗試更新不存在的任務 "${taskData.name}",操作被忽略`
);
}
}
} else {
// 創建新任務
newTask = await createTask(
taskData.name,
taskData.description,
taskData.notes,
[], // 空依賴列表,在第二階段設置
taskData.relatedFiles
);
const newTaskId = uuidv4();
// 將新任務的名稱和ID添加到映射中
taskNameToIdMap.set(taskData.name, newTaskId);
const newTask: Task = {
id: newTaskId,
name: taskData.name,
description: taskData.description,
notes: taskData.notes,
status: TaskStatus.PENDING,
dependencies: [], // 後面會填充
createdAt: new Date(),
updatedAt: new Date(),
relatedFiles: taskData.relatedFiles,
// 新增:保存實現指南(如果有)
implementationGuide: taskData.implementationGuide,
// 新增:保存驗證標準(如果有)
verificationCriteria: taskData.verificationCriteria,
// 新增:保存全局分析結果(如果有)
analysisResult: globalAnalysisResult,
};
newTasks.push(newTask);
}
// 將新任務添加到映射表
nameToIdMap.set(newTask.name, newTask.id);
idToTaskMap.set(newTask.id, newTask);
// 保存原始依賴信息
firstPassTasks.push({
task: newTask,
originalDeps: taskData.dependencies || [],
});
}
// 第二階段:更新所有新增或修改任務的依賴關係
const processedTasks: Task[] = [];
// 處理任務之間的依賴關係
for (let i = 0; i < taskDataList.length; i++) {
const taskData = taskDataList[i];
const newTask = newTasks[i];
for (const { task, originalDeps } of firstPassTasks) {
// 解析依賴關係
const resolvedDependencies: TaskDependency[] = [];
// 如果存在依賴關係,處理它們
if (taskData.dependencies && taskData.dependencies.length > 0) {
const resolvedDependencies: TaskDependency[] = [];
for (const dep of originalDeps) {
// 嘗試將依賴名稱解析為ID
let depId = dep;
for (const dependencyName of taskData.dependencies) {
// 首先嘗試將依賴項解釋為任務ID
let dependencyTaskId = dependencyName;
// 如果不是UUID格式嘗試將其作為任務名稱解析
if (
!/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
dep
)
) {
const resolvedId = nameToIdMap.get(dep);
if (resolvedId) {
depId = resolvedId;
// 如果依賴項看起來不像UUID則嘗試將其解釋為任務名稱
if (
!dependencyName.match(
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
)
) {
// 如果映射中存在此名稱則使用對應的ID
if (taskNameToIdMap.has(dependencyName)) {
dependencyTaskId = taskNameToIdMap.get(dependencyName)!;
} else {
console.warn(
`警告:任務 "${taskData.name}" 引用了未知的依賴任務 "${dependencyName}",此依賴將被忽略`
);
continue; // 跳過此依賴
}
} else {
console.warn(`警告:找不到名為 "${dep}" 的任務,已忽略此依賴`);
continue; // 跳過此依賴
// 是UUID格式但需要確認此ID是否對應實際存在的任務
const idExists = [...tasksToKeep, ...newTasks].some(
(task) => task.id === dependencyTaskId
);
if (!idExists) {
console.warn(
`警告:任務 "${taskData.name}" 引用了未知的依賴任務ID "${dependencyTaskId}",此依賴將被忽略`
);
continue; // 跳過此依賴
}
}
resolvedDependencies.push({ taskId: dependencyTaskId });
}
resolvedDependencies.push({ taskId: depId });
}
// 更新任務的依賴
const updatedTask = await updateTask(task.id, {
dependencies: resolvedDependencies,
});
if (updatedTask) {
processedTasks.push(updatedTask);
} else {
processedTasks.push(task); // 回退到原始任務
newTask.dependencies = resolvedDependencies;
}
}
// 如果是選擇性更新模式,合併保留的任務和新建/更新的任務
if (updateMode === "selective") {
return [...finalTaskList, ...processedTasks];
}
// 合併保留的任務和新任務
const allTasks = [...tasksToKeep, ...newTasks];
return processedTasks;
// 寫入更新後的任務列表
await writeTasks(allTasks);
return newTasks;
}
// 檢查任務是否可以執行(所有依賴都已完成)

View File

@ -404,6 +404,16 @@ export async function reflectTask({
- ****使 updateMode="selective"
- ****使 updateMode="clearAllTasks"
##
1. **** -
2. **** -
3. **** -
`;
return {
@ -424,6 +434,12 @@ export const splitTasksSchema = z
.describe(
"任務更新模式(必填):'append'(保留現有任務並新增)、'overwrite'(清除所有未完成任務並重建)、'selective'(根據名稱匹配更新現有任務,保留其餘任務)、'clearAllTasks'(清除所有任務並創建備份)"
),
globalAnalysisResult: z
.string()
.optional()
.describe(
"全局分析結果:來自 reflect_task 的完整分析結果,適用於所有任務的通用部分"
),
tasks: z
.array(
z.object({
@ -468,6 +484,14 @@ export const splitTasksSchema = z
)
.optional()
.describe("與任務相關的檔案列表,包含檔案路徑、類型和描述"),
implementationGuide: z
.string()
.optional()
.describe("此特定任務的具體實現方法和步驟"),
verificationCriteria: z
.string()
.optional()
.describe("此特定任務的驗證標準和檢驗方法"),
})
)
.min(1, { message: "至少需要提供一個任務,請確保任務列表不為空" })
@ -494,6 +518,7 @@ export const splitTasksSchema = z
export async function splitTasks({
updateMode,
tasks,
globalAnalysisResult,
}: z.infer<typeof splitTasksSchema>) {
// 處理 clearAllTasks 模式,直接調用 modelClearAllTasks 函數
if (updateMode === "clearAllTasks") {
@ -546,8 +571,12 @@ export async function splitTasks({
updateModeMessage = "清除模式:清除所有任務並創建備份";
}
// 批量創建任務 - 將 updateMode 傳遞給 batchCreateOrUpdateTasks
const createdTasks = await batchCreateOrUpdateTasks(tasks, updateMode);
// 批量創建任務 - 將 updateMode 和 globalAnalysisResult 傳遞給 batchCreateOrUpdateTasks
const createdTasks = await batchCreateOrUpdateTasks(
tasks,
updateMode,
globalAnalysisResult
);
// 獲取所有任務,用於顯示完整的依賴關係
const allTasks = await getAllTasks();
@ -596,26 +625,52 @@ export async function splitTasks({
-
## \n\n${createdTasks
.map(
(task, index) =>
`### 任務 ${index + 1}${task.name}\n**ID:** \`${
task.id
}\`\n**描述:** ${task.description}\n${
task.notes ? `**注意事項:** ${task.notes}\n` : ""
}${
task.dependencies.length > 0
? `**依賴任務:** ${task.dependencies
.map((d) => {
// 查找依賴任務的名稱,提供更友好的顯示
const depTask = allTasks.find((t) => t.id === d.taskId);
return depTask
? `"${depTask.name}" (\`${d.taskId}\`)`
: `\`${d.taskId}\``;
})
.join(", ")}\n`
: "**依賴任務:** 無\n"
}`
)
.map((task, index) => {
let taskInfo = `### 任務 ${index + 1}${task.name}\n**ID:** \`${
task.id
}\`\n**描述:** ${task.description}\n`;
if (task.notes) {
taskInfo += `**注意事項:** ${task.notes}\n`;
}
// 添加實現指南的顯示(如果有)
if (task.implementationGuide) {
taskInfo += `**實現指南:** ${
task.implementationGuide.length > 100
? task.implementationGuide.substring(0, 100) +
"... (執行時可查看完整內容)"
: task.implementationGuide
}\n`;
}
// 添加驗證標準的顯示(如果有)
if (task.verificationCriteria) {
taskInfo += `**驗證標準:** ${
task.verificationCriteria.length > 100
? task.verificationCriteria.substring(0, 100) +
"... (驗證時可查看完整內容)"
: task.verificationCriteria
}\n`;
}
// 添加依賴任務
taskInfo += `${
task.dependencies.length > 0
? `**依賴任務:** ${task.dependencies
.map((d) => {
// 查找依賴任務的名稱,提供更友好的顯示
const depTask = allTasks.find((t) => t.id === d.taskId);
return depTask
? `"${depTask.name}" (\`${d.taskId}\`)`
: `\`${d.taskId}\``;
})
.join(", ")}\n`
: "**依賴任務:** 無\n"
}`;
return taskInfo;
})
.join(
"\n"
)}\n\n## \n\n### \n在建立新任務時\n\n1. **使**使 \`"建立用戶界面"\`\n2. **使用任務ID**:使用任務的唯一標識符,如 \`"${
@ -784,6 +839,21 @@ export async function executeTask({
task.notes ? `- **注意事項:** ${task.notes}\n` : ""
}\n`;
// ===== 增強:顯示實現指南(如果有) =====
if (task.implementationGuide) {
prompt += `\n## 實現指南\n\n${task.implementationGuide}\n\n`;
}
// ===== 增強:顯示驗證標準(如果有) =====
if (task.verificationCriteria) {
prompt += `\n## 驗證標準\n\n${task.verificationCriteria}\n\n`;
}
// ===== 增強:顯示分析結果(如果有) =====
if (task.analysisResult) {
prompt += `\n## 分析背景\n\n${task.analysisResult}\n\n`;
}
// ===== 增強:處理相關文件內容 =====
let relatedFilesSummary = "";
let contextInfo = "";
@ -1039,13 +1109,36 @@ export async function verifyTask({ taskId }: z.infer<typeof verifyTaskSchema>) {
};
}
const prompt = `## 任務驗證評估\n\n### 任務資料\n\n- **名稱:** ${
// 構建基本的任務詳情
let prompt = `## 任務驗證評估\n\n### 任務資料\n\n- **名稱:** ${
task.name
}\n- **ID:** \`${task.id}\`\n- **描述:** ${task.description}\n${
task.notes ? `- **注意事項:** ${task.notes}\n` : ""
}\n`;
// 新增:顯示任務特定的驗證標準(如果有)
if (task.verificationCriteria) {
prompt += `\n## 任務特定驗證標準\n\n${task.verificationCriteria}\n\n`;
}
## \n\n請根據以下關鍵標準進行嚴格的質量檢查
// 新增:顯示實現指南的主要內容(如果有)
if (task.implementationGuide) {
prompt += `\n## 實現指南摘要\n\n${
task.implementationGuide.length > 200
? task.implementationGuide.substring(0, 200) + "... (參見完整實現指南)"
: task.implementationGuide
}\n\n`;
}
// 新增:顯示分析結果摘要(如果有)
if (task.analysisResult) {
prompt += `\n## 分析要點摘要\n\n在驗證時應考慮原始分析中強調的以下關鍵點\n\n${extractSummary(
task.analysisResult,
300
)}\n\n`;
}
prompt += `## 完整性驗證標準\n\n請根據以下關鍵標準進行嚴格的質量檢查為每個評估項目提供詳細的證據和具體範例
### 1. (30%)
####
@ -1403,7 +1496,7 @@ export const updateTaskContentSchema = z
.enum([
RelatedFileType.TO_MODIFY,
RelatedFileType.REFERENCE,
RelatedFileType.OUTPUT,
RelatedFileType.CREATE,
RelatedFileType.DEPENDENCY,
RelatedFileType.OTHER,
])
@ -1570,7 +1663,7 @@ export const updateTaskRelatedFilesSchema = z
.enum([
RelatedFileType.TO_MODIFY,
RelatedFileType.REFERENCE,
RelatedFileType.OUTPUT,
RelatedFileType.CREATE,
RelatedFileType.DEPENDENCY,
RelatedFileType.OTHER,
])

View File

@ -15,7 +15,7 @@ export interface TaskDependency {
export enum RelatedFileType {
TO_MODIFY = "待修改", // 需要在任務中修改的文件
REFERENCE = "參考資料", // 任務的參考資料或相關文檔
OUTPUT = "輸出結果", // 任務產生的輸出文件
CREATE = "待建立", // 需要在任務中建立的文件
DEPENDENCY = "依賴文件", // 任務依賴的組件或庫文件
OTHER = "其他", // 其他類型的相關文件
}
@ -42,6 +42,15 @@ export interface Task {
completedAt?: Date; // 任務完成的時間戳(僅適用於已完成的任務)
summary?: string; // 任務完成摘要,簡潔描述實施結果和重要決策(僅適用於已完成的任務)
relatedFiles?: RelatedFile[]; // 與任務相關的文件列表(選填)
// 新增欄位:保存完整的技術分析結果
analysisResult?: string; // 來自 analyze_task 和 reflect_task 階段的完整分析結果
// 新增欄位:保存具體的實現指南
implementationGuide?: string; // 具體的實現方法、步驟和建議
// 新增欄位:保存驗證標準和檢驗方法
verificationCriteria?: string; // 明確的驗證標準、測試要點和驗收條件
}
// 規劃任務的參數:用於初始化任務規劃階段
@ -73,12 +82,22 @@ export interface SplitTasksArgs {
* - "clearAllTasks"
*/
updateMode: "append" | "overwrite" | "selective" | "clearAllTasks";
// 全局分析結果:用於所有任務的共享分析數據
globalAnalysisResult?: string; // 來自 reflect_task 的完整分析結果,適用於所有任務的通用部分
tasks: Array<{
name: string; // 簡潔明確的任務名稱,應能清晰表達任務目的
description: string; // 詳細的任務描述,包含實施要點、技術細節和驗收標準
notes?: string; // 補充說明、特殊處理要求或實施建議(選填)
dependencies?: string[]; // 此任務依賴的前置任務ID列表形成任務的有向無環依賴圖
relatedFiles?: RelatedFile[]; // 與任務相關的文件列表(選填)
// 新增欄位:任務專屬的實現指南
implementationGuide?: string; // 此特定任務的具體實現方法和步驟
// 新增欄位:任務專屬的驗證標準
verificationCriteria?: string; // 此特定任務的驗證標準和檢驗方法
}>;
}

View File

@ -33,7 +33,7 @@ export async function loadTaskRelatedFiles(
[RelatedFileType.TO_MODIFY]: 1,
[RelatedFileType.REFERENCE]: 2,
[RelatedFileType.DEPENDENCY]: 3,
[RelatedFileType.OUTPUT]: 4,
[RelatedFileType.CREATE]: 4,
[RelatedFileType.OTHER]: 5,
};