1857 lines
68 KiB
TypeScript
Raw Normal View History

2025-04-11 15:45:35 +08:00
import { z } from "zod";
import {
getAllTasks,
getTaskById,
updateTaskStatus,
canExecuteTask,
batchCreateOrUpdateTasks,
deleteTask as modelDeleteTask,
updateTaskSummary,
assessTaskComplexity,
clearAllTasks as modelClearAllTasks,
updateTaskContent as modelUpdateTaskContent,
updateTaskRelatedFiles as modelUpdateTaskRelatedFiles,
2025-04-11 15:45:35 +08:00
} from "../models/taskModel.js";
import {
TaskStatus,
TaskComplexityLevel,
RelatedFileType,
RelatedFile,
Task,
TaskDependency,
} from "../types/index.js";
import {
extractSummary,
generateTaskSummary,
} from "../utils/summaryExtractor.js";
import { loadTaskRelatedFiles } from "../utils/fileLoader.js";
2025-04-11 15:45:35 +08:00
/**
*
*/
function getTaskStatusDisplay(status: TaskStatus): string {
switch (status) {
case TaskStatus.PENDING:
return "待處理";
case TaskStatus.IN_PROGRESS:
return "進行中";
case TaskStatus.COMPLETED:
return "已完成";
default:
return status;
}
}
/**
*
*/
function formatDate(date: Date): string {
return date.toLocaleString("zh-TW", {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
});
}
2025-04-11 15:45:35 +08:00
// 開始規劃工具
export const planTaskSchema = z.object({
description: z
.string()
.min(10, {
message: "任務描述不能少於10個字符請提供更詳細的描述以確保任務目標明確",
})
2025-04-11 15:45:35 +08:00
.describe("完整詳細的任務問題描述,應包含任務目標、背景及預期成果"),
requirements: z
.string()
.optional()
.describe("任務的特定技術要求、業務約束條件或品質標準(選填)"),
existingTasksReference: z
.boolean()
.optional()
.default(false)
.describe("是否參考現有任務作為規劃基礎,用於任務調整和延續性規劃"),
2025-04-11 15:45:35 +08:00
});
export async function planTask({
description,
requirements,
existingTasksReference = false,
2025-04-11 15:45:35 +08:00
}: z.infer<typeof planTaskSchema>) {
let prompt = `## 任務分析請求\n\n請仔細分析以下任務問題理解其核心要求、範圍和約束條件\n\n\`\`\`\n${description}\n\`\`\`\n\n`;
if (requirements) {
prompt += `## 附加要求與限制條件\n\n請確保方案完全符合以下要求\n\n\`\`\`\n${requirements}\n\`\`\`\n\n`;
}
// 當 existingTasksReference 為 true 時,從數據庫中載入所有任務作為參考
if (existingTasksReference) {
try {
const allTasks = await getAllTasks();
// 將任務分為已完成和未完成兩類
const completedTasks = allTasks.filter(
(task) => task.status === TaskStatus.COMPLETED
);
const pendingTasks = allTasks.filter(
(task) => task.status !== TaskStatus.COMPLETED
);
// 如果存在任務,則添加到提示詞中
if (allTasks.length > 0) {
prompt += `## 現有任務參考\n\n您正在對現有任務進行調整或延續規劃。以下任務資訊將作為您分析和規劃的基礎\n\n`;
// 添加已完成任務的參考
if (completedTasks.length > 0) {
prompt += `### 已完成的任務(僅供參考,不可修改)\n\n`;
prompt += `以下任務已標記為完成,作為系統穩定功能的基石和固定參考點:\n\n`;
// 最多顯示10個已完成任務避免提示詞過長
const tasksToShow =
completedTasks.length > 10
? completedTasks.slice(0, 10)
: completedTasks;
tasksToShow.forEach((task, index) => {
// 使用摘要提取工具處理較長的描述
const taskDescriptionSummary = extractSummary(
task.description,
100
);
prompt += `${index + 1}. **${task.name}** (ID: \`${task.id}\`)\n`;
prompt += ` - 描述:${taskDescriptionSummary}\n`;
if (task.completedAt) {
prompt += ` - 完成時間:${formatDate(task.completedAt)}\n`;
}
if (index < tasksToShow.length - 1) {
prompt += `\n`;
}
});
if (completedTasks.length > 10) {
prompt += `\n*僅顯示前10個已完成任務實際共有 ${completedTasks.length} 個已完成任務)*\n`;
}
}
// 添加未完成任務的參考
if (pendingTasks.length > 0) {
prompt += `\n### 未完成的任務(可根據需要調整)\n\n`;
prompt += `以下任務尚未完成,您可以根據新需求對其進行調整或重新規劃:\n\n`;
pendingTasks.forEach((task, index) => {
// 使用摘要提取工具處理較長的描述
const taskDescriptionSummary = extractSummary(
task.description,
150
);
prompt += `${index + 1}. **${task.name}** (ID: \`${task.id}\`)\n`;
prompt += ` - 描述:${taskDescriptionSummary}\n`;
prompt += ` - 狀態:${getTaskStatusDisplay(task.status)}\n`;
// 如果有依賴關係,也顯示出來
if (task.dependencies && task.dependencies.length > 0) {
prompt += ` - 依賴:${task.dependencies
.map((dep) => `\`${dep.taskId}\``)
.join(", ")}\n`;
}
if (index < pendingTasks.length - 1) {
prompt += `\n`;
}
});
}
prompt += `\n## 任務調整指南\n\n`;
prompt += `規劃新任務或調整現有任務時,請嚴格遵循以下五項原則:\n\n`;
prompt += `1. **已完成任務保護原則** - 已完成的任務是系統穩定功能的基石,絕對不可修改或刪除。\n`;
prompt += `2. **未完成任務可調整原則** - 未完成的任務可以根據新需求進行調整,包括修改描述、依賴關係等,或建議移除。\n`;
prompt += `3. **任務ID一致性原則** - 引用現有任務時必須使用其原始ID以確保系統跟踪的準確性。\n`;
prompt += `4. **依賴關係完整性原則** - 調整任務計劃時必須維護依賴關係的完整性:\n`;
prompt += ` - 不創建循環依賴\n`;
prompt += ` - 不依賴已標記為移除的任務\n`;
prompt += ` - 確保新增依賴關係合理且必要\n`;
prompt += `5. **任務延續性原則** - 新任務應與現有任務構成連貫整體,維持整體計劃的邏輯性和可行性。\n\n`;
prompt += `**重要提醒:** 系統強制執行已完成任務保護機制,無法修改已完成的任務。請在規劃階段充分考慮這一限制。\n\n`;
// 添加選擇性任務更新模式指導
prompt += `## 選擇性任務更新指南\n\n`;
prompt += `任務更新時,您可以選擇以下三種更新模式,每種模式適用於不同的場景:\n\n`;
prompt += `### 1. **追加模式(append)**\n`;
prompt += `- **說明**:保留所有現有任務,僅添加新任務\n`;
prompt += `- **適用場景**:逐步擴展功能,添加獨立的新特性,現有任務計劃仍然有效\n`;
prompt += `- **使用方式**split_tasks 工具中設置 \`updateMode="append"\`\n`;
prompt += `- **潛在問題**:長期使用可能導致積累過多已不再相關但未完成的任務\n\n`;
prompt += `### 2. **覆蓋模式(overwrite)**\n`;
prompt += `- **說明**:清除所有現有未完成任務,完全使用新任務列表替換\n`;
prompt += `- **適用場景**:徹底變更方向,現有未完成任務已完全不相關\n`;
prompt += `- **使用方式**split_tasks 工具中設置 \`updateMode="overwrite"\`\n`;
prompt += `- **潛在問題**:可能會丟失有價值的未完成任務,需要確保所有重要任務都在新列表中\n\n`;
prompt += `### 3. **選擇性更新模式(selective)**\n`;
prompt += `- **說明**:根據任務名稱匹配選擇性地更新任務,保留不在列表中的現有任務\n`;
prompt += `- **適用場景**:部分調整任務計劃,保留部分未完成任務,更新或添加其他任務\n`;
prompt += `- **使用方式**split_tasks 工具中設置 \`updateMode="selective"\`\n`;
prompt += `- **工作原理**\n`;
prompt += ` 1. 對於名稱相同的任務更新其內容描述、注釋等保留原ID和創建時間\n`;
prompt += ` 2. 新任務名稱的條目將被創建為新任務\n`;
prompt += ` 3. 不在提交列表中的現有任務將被保留不變\n`;
prompt += `- **最佳實踐**:在需要微調部分任務時優先選擇此模式,既避免重建所有任務,又能保持計劃的連續性\n\n`;
prompt += `### 實際應用建議\n`;
prompt += `- 對於小範圍調整,優先使用 **selective** 模式,精確更新目標任務\n`;
prompt += `- 需要添加新功能時,可使用 **append** 模式保留現有工作\n`;
prompt += `- 僅在徹底重構計劃時使用 **overwrite** 模式,謹慎權衡是否真正需要刪除所有未完成任務\n`;
prompt += `- 無論使用哪種模式,始終需要**維護依賴關係的完整性和正確性**\n\n`;
}
} catch (error) {
console.error("載入現有任務時發生錯誤:", error);
}
}
2025-04-11 15:45:35 +08:00
prompt += `## 分析指引\n\n1. 首先確定任務的確切目標和預期成果
2.
3.
4.
5.
6.
2025-04-11 15:45:35 +08:00
2025-04-11 15:45:35 +08:00
## \n\n-
-
-
-
##
-
-
-
- 使 ddg_searchwebweb_search ...
## \n\n完成初步分析後使analyze_task\n\n1. ****
-
-
-
-
2. ****
-
-
-
-
`;
2025-04-11 15:45:35 +08:00
return {
content: [
{
type: "text" as const,
text: prompt,
},
],
};
}
// 分析問題工具
export const analyzeTaskSchema = z.object({
summary: z
.string()
.min(20, {
message:
"任務摘要太短,請提供更詳細的摘要,包含任務目標、範圍與關鍵技術挑戰",
})
2025-04-11 15:45:35 +08:00
.describe("結構化的任務摘要,包含任務目標、範圍與關鍵技術挑戰"),
initialConcept: z
.string()
.min(50, {
message: "初步解答構想過於簡短,請提供更完整的技術方案和實施策略詳情",
})
2025-04-11 15:45:35 +08:00
.describe("初步解答構想,包含技術方案、架構設計和實施策略"),
previousAnalysis: z
.string()
.optional()
.describe("前次迭代的分析結果,用於持續改進方案(僅在重新分析時需提供)"),
});
export async function analyzeTask({
summary,
initialConcept,
previousAnalysis,
}: z.infer<typeof analyzeTaskSchema>) {
let prompt = `## 代碼庫分析任務\n\n### 任務摘要\n\`\`\`\n${summary}\n\`\`\`\n\n已收到您的初步解答構想\n\n\`\`\`\n${initialConcept}\n\`\`\`\n\n`;
prompt += `## 技術審核指引\n\n請執行以下詳細的技術分析步驟\n\n### 1. 代碼庫分析
-
-
-
-
### 2.
-
-
-
-
2025-04-11 15:45:35 +08:00
### 3.
-
-
-
### 4.
-
-
-
`;
2025-04-11 15:45:35 +08:00
if (previousAnalysis) {
prompt += `\n\n## 迭代分析\n\n請對照先前的分析結果進行比較和改進\n\n\`\`\`\n${previousAnalysis}\n\`\`\`\n\n請明確識別\n1. 哪些問題已經解決,以及解決方案的有效性
2.
3.
4. `;
2025-04-11 15:45:35 +08:00
}
prompt += `\n\n## 下一步行動\n\n完成深入分析後請使用「reflect_task」工具提交您的最終分析必須包含\n\n1. **原始任務摘要**
-
-
2. ****
-
-
-
-
-
`;
2025-04-11 15:45:35 +08:00
return {
content: [
{
type: "text" as const,
text: prompt,
},
],
};
}
// 反思構想工具
export const reflectTaskSchema = z
.object({
summary: z
.string()
.min(20, {
message: "任務摘要太短,請確保包含完整的任務目標和範圍以維持分析連續性",
})
.describe("結構化的任務摘要,保持與分析階段一致以確保連續性"),
analysis: z
.string()
.min(100, {
message:
"技術分析結果過於簡略,請提供更詳盡的技術細節、依賴組件和實施方案說明",
})
.describe("完整詳盡的技術分析結果,包括所有技術細節、依賴組件和實施方案"),
})
.refine((data) => data.summary.length * 3 <= data.analysis.length, {
message:
"分析內容應該比摘要更詳細建議分析部分至少是摘要長度的3倍以提供足夠的技術深度",
path: ["analysis"],
});
2025-04-11 15:45:35 +08:00
export async function reflectTask({
summary,
analysis,
}: z.infer<typeof reflectTaskSchema>) {
const prompt = `## 解決方案反思與評估\n\n### 任務摘要\n\`\`\`\n${summary}\n\`\`\`\n\n### 詳細分析結果\n\`\`\`\n${analysis}\n\`\`\`\n\n## 批判性評估指引\n\n請從以下多個維度對您的解決方案進行全面且批判性的審查\n\n### 1. 技術完整性評估
-
-
-
-
-
2025-04-11 15:45:35 +08:00
### 2.
- 使
-
-
-
2025-04-11 15:45:35 +08:00
### 3.
-
-
-
- 使
-
2025-04-11 15:45:35 +08:00
## \n\n基於您的反思\n\n- ****
- 使analyze_task
-
-
- **調**
-
- 調
- ****
- 使split_tasks
-
-
## split_tasks updateMode
- ****使 updateMode="append"
- ****使 updateMode="overwrite"
- ****使 updateMode="selective"
- ****使 updateMode="clearAllTasks"
##
1. **** -
2. **** -
3. **** -
`;
2025-04-11 15:45:35 +08:00
return {
content: [
{
type: "text" as const,
text: prompt,
},
],
};
}
// 拆分任務工具
export const splitTasksSchema = z
.object({
updateMode: z
.enum(["append", "overwrite", "selective", "clearAllTasks"])
.describe(
"任務更新模式(必填):'append'(保留現有任務並新增)、'overwrite'(清除所有未完成任務並重建)、'selective'(根據名稱匹配更新現有任務,保留其餘任務)、'clearAllTasks'(清除所有任務並創建備份)"
),
globalAnalysisResult: z
.string()
.optional()
.describe(
"全局分析結果:來自 reflect_task 的完整分析結果,適用於所有任務的通用部分"
),
tasks: z
.array(
z.object({
name: z
.string()
.max(100, { message: "任務名稱過長請保持簡潔不超過100個字符" })
.describe("簡潔明確的任務名稱,應能清晰表達任務目的"),
description: z
.string()
.min(10, {
message:
"任務描述太簡短,請提供更詳細的描述,包含實施要點和驗收標準",
})
.describe("詳細的任務描述,包含實施要點、技術細節和驗收標準"),
notes: z
.string()
.optional()
.describe("補充說明、特殊處理要求或實施建議(選填)"),
dependencies: z
.array(z.string(), {
message: "必須是字串陣列支援任務名稱或任務ID(UUID)",
})
.optional()
.describe(
"此任務依賴的前置任務ID或任務名稱列表支持兩種引用方式名稱引用更直觀"
),
relatedFiles: z
.array(
z.object({
path: z
.string()
.min(1, { message: "檔案路徑不能為空" })
.describe("檔案路徑,相對於專案根目錄"),
type: z
.nativeEnum(RelatedFileType)
.describe("檔案類型,用於區分不同類型的檔案"),
description: z
.string()
.min(1, { message: "檔案描述不能為空" })
.describe("檔案描述,用於說明檔案的用途和內容"),
})
)
.optional()
.describe("與任務相關的檔案列表,包含檔案路徑、類型和描述"),
implementationGuide: z
.string()
.optional()
.describe("此特定任務的具體實現方法和步驟"),
verificationCriteria: z
.string()
.optional()
.describe("此特定任務的驗證標準和檢驗方法"),
})
)
.min(1, { message: "至少需要提供一個任務,請確保任務列表不為空" })
.describe("結構化的任務清單,每個任務應保持原子性且有明確的完成標準"),
})
.refine(
(data) => {
// 檢查任務名稱是否有重複
const nameSet = new Set();
for (const task of data.tasks) {
if (nameSet.has(task.name)) {
return false;
}
nameSet.add(task.name);
}
return true;
},
{
message: "任務列表中存在重複的任務名稱,請確保每個任務名稱是唯一的",
path: ["tasks"],
}
);
2025-04-11 15:45:35 +08:00
export async function splitTasks({
updateMode,
2025-04-11 15:45:35 +08:00
tasks,
globalAnalysisResult,
2025-04-11 15:45:35 +08:00
}: z.infer<typeof splitTasksSchema>) {
// 處理 clearAllTasks 模式,直接調用 modelClearAllTasks 函數
if (updateMode === "clearAllTasks") {
const clearResult = await modelClearAllTasks();
// 返回清除操作結果
let prompt = `## 任務清除結果\n\n### 系統通知\n${clearResult.message}\n\n`;
if (clearResult.success) {
if (clearResult.backupFile) {
prompt += `### 備份信息\n備份文件已創建${clearResult.backupFile}\n\n`;
}
if (tasks.length > 0) {
prompt += `系統將繼續創建您請求的 ${tasks.length} 個新任務。\n`;
} else {
prompt += `### 注意\n您沒有提供任何新任務。如需創建新任務請使用 "append" 模式並提供任務列表。\n`;
return {
content: [
{
type: "text" as const,
text: prompt,
},
],
};
}
} else {
prompt += `### 錯誤信息\n清除任務時遇到問題${clearResult.message}\n任務清單未更改。\n`;
return {
content: [
{
type: "text" as const,
text: prompt,
},
],
};
}
}
// 根據不同更新模式生成日誌訊息
let updateModeMessage = "";
if (updateMode === "append") {
updateModeMessage = "追加模式:保留現有任務並新增";
} else if (updateMode === "overwrite") {
updateModeMessage = "覆蓋模式:清除所有未完成任務並重建";
} else if (updateMode === "selective") {
updateModeMessage =
"選擇性更新模式:根據任務名稱更新現有任務、新增缺少任務,保留其餘任務";
} else if (updateMode === "clearAllTasks") {
updateModeMessage = "清除模式:清除所有任務並創建備份";
}
// 批量創建任務 - 將 updateMode 和 globalAnalysisResult 傳遞給 batchCreateOrUpdateTasks
const createdTasks = await batchCreateOrUpdateTasks(
tasks,
updateMode,
globalAnalysisResult
);
2025-04-11 15:45:35 +08:00
// 獲取所有任務,用於顯示完整的依賴關係
const allTasks = await getAllTasks();
let prompt = `## 任務拆分結果 - ${updateMode} 模式\n\n### 系統確認\n任務已成功${
updateMode === "overwrite"
? "覆蓋未完成的任務清單(已完成任務已保留)"
: updateMode === "selective"
? "選擇性更新任務清單"
: "新增至現有任務清單"
}\n\n`;
prompt += `## 任務拆分指南\n\n### 有效的任務拆分策略\n\n1. **按功能分解** - 將大功能拆分為獨立可測試的子功能
-
-
-
2. **** - 沿
-
- 便
-
3. **** -
-
-
-
4. **** -
-
-
-
## \n\n請根據以下標準對任務拆分進行嚴格的質量審核\n\n### 1. \n-
2025-04-11 15:45:35 +08:00
-
-
-
2025-04-11 15:45:35 +08:00
### 2. \n-
-
-
-
2025-04-11 15:45:35 +08:00
### 3. \n-
-
-
-
2025-04-11 15:45:35 +08:00
## \n\n${createdTasks
.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;
})
2025-04-11 15:45:35 +08:00
.join(
"\n"
)}\n\n## \n\n### \n在建立新任務時\n\n1. **使**使 \`"建立用戶界面"\`\n2. **使用任務ID**:使用任務的唯一標識符,如 \`"${
2025-04-11 15:45:35 +08:00
createdTasks.length > 0
? createdTasks[0].id
: "a1b2c3d4-e5f6-g7h8-i9j0-k1l2m3n4o5p6"
}"\`\n
###
- **** -
- **** -
- **** -
- **** -
##
###
-
-
-
## \n\n請選擇下一步行動\n\n- split_tasks調\n\n- `;
2025-04-11 15:45:35 +08:00
return {
content: [
{
type: "text" as const,
text: prompt,
},
],
};
}
// 列出任務工具
export async function listTasks() {
const tasks = await getAllTasks();
if (tasks.length === 0) {
return {
content: [
{
type: "text" as const,
text: "## 系統通知\n\n目前系統中沒有註冊任何任務。請先使用「split_tasks」工具創建任務結構再進行後續操作。",
},
],
};
}
const tasksByStatus = tasks.reduce((acc, task) => {
if (!acc[task.status]) {
acc[task.status] = [];
}
acc[task.status].push(task);
return acc;
}, {} as Record<string, typeof tasks>);
let result = "# 任務管理儀表板\n\n## 任務狀態概覽\n\n";
// 添加任務狀態計數摘要
const statusCounts = Object.values(TaskStatus)
.map((status) => {
const count = tasksByStatus[status]?.length || 0;
return `- **${status}**: ${count} 個任務`;
})
.join("\n");
result += `${statusCounts}\n\n`;
// 添加每個狀態下的詳細任務
for (const status of Object.values(TaskStatus)) {
const tasksWithStatus = tasksByStatus[status] || [];
if (tasksWithStatus.length > 0) {
result += `## ${status} (${tasksWithStatus.length})\n\n`;
tasksWithStatus.forEach((task, index) => {
result += formatTaskDetails(task);
2025-04-11 15:45:35 +08:00
});
}
}
return {
content: [
{
type: "text" as const,
text: result,
},
],
};
}
// 執行任務工具
export const executeTaskSchema = z.object({
taskId: z
.string()
.uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
2025-04-11 15:45:35 +08:00
.describe("待執行任務的唯一標識符必須是系統中存在的有效任務ID"),
});
export async function executeTask({
taskId,
}: z.infer<typeof executeTaskSchema>) {
const task = await getTaskById(taskId);
if (!task) {
return {
content: [
{
type: "text" as const,
text: `## 系統錯誤\n\n找不到ID為 \`${taskId}\` 的任務。請使用「list_tasks」工具確認有效的任務ID後再試。`,
},
],
isError: true,
};
}
if (task.status === TaskStatus.COMPLETED) {
return {
content: [
{
type: "text" as const,
text: `## 系統通知\n\n任務 "${task.name}" (ID: \`${task.id}\`) 已於 ${
task.completedAt?.toISOString() || "先前"
} \n\n如需修改或重新執行`,
},
],
};
}
const { canExecute, blockedBy } = await canExecuteTask(taskId);
if (!canExecute && blockedBy) {
// 找出阻塞的任務名稱
const allTasks = await getAllTasks();
const blockedByTaskNames = blockedBy.map((id) => {
const blockingTask = allTasks.find((t) => t.id === id);
return blockingTask
? `"${blockingTask.name}" (ID: \`${id}\`)`
: `ID: \`${id}\``;
});
return {
content: [
{
type: "text" as const,
text: `## 任務依賴阻塞通知\n\n無法執行任務 "${task.name}" (ID: \`${
task.id
}\`)。\n\n### 阻塞原因\n此任務依賴於尚未完成的前置任務。請先完成以下依賴任務\n\n${blockedByTaskNames
.map((name, i) => `${i + 1}. ${name}`)
.join("\n")}`,
},
],
isError: true,
};
}
// ===== 新增:評估任務複雜度 =====
const complexityAssessment = await assessTaskComplexity(taskId);
2025-04-11 15:45:35 +08:00
// 更新任務狀態為進行中
await updateTaskStatus(taskId, TaskStatus.IN_PROGRESS);
// 構建任務執行提示
let prompt = `## 任務執行指示\n\n### 任務詳情\n\n- **名稱:** ${
2025-04-11 15:45:35 +08:00
task.name
}\n- **ID:** \`${task.id}\`\n- **描述:** ${task.description}\n${
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 = "";
// 查找依賴任務的相關信息
if (task.dependencies && task.dependencies.length > 0) {
try {
const allTasks = await getAllTasks();
const depTasks = task.dependencies
.map((dep) => allTasks.find((t) => t.id === dep.taskId))
.filter((t) => t !== undefined) as Task[];
if (depTasks.length > 0) {
const completedDepTasks = depTasks.filter(
(t) => t.status === TaskStatus.COMPLETED
);
if (completedDepTasks.length > 0) {
contextInfo += `\n## 依賴任務完成摘要\n\n`;
for (const depTask of completedDepTasks) {
contextInfo += `### ${depTask.name}\n`;
if (depTask.summary) {
contextInfo += `${depTask.summary}\n\n`;
} else {
contextInfo += `*無完成摘要*\n\n`;
}
}
}
}
} catch (error) {
console.error("加載依賴任務信息時發生錯誤:", error);
}
}
if (task.relatedFiles && task.relatedFiles.length > 0) {
try {
// 生成任務相關文件的摘要資訊
// 使用loadTaskRelatedFiles生成文件摘要現在函數直接返回格式化的文本
// 而不是包含content和summary的物件
const relatedFilesSummary = await loadTaskRelatedFiles(task.relatedFiles);
} catch (error) {
console.error("生成任務相關文件摘要時發生錯誤:", error);
relatedFilesSummary =
"## 相關文件摘要生成失敗\n\n生成文件摘要時發生錯誤請手動查看相關文件。";
}
} else {
// 沒有相關文件的情況
relatedFilesSummary =
"## 相關文件\n\n當前任務沒有關聯的文件。可以使用 `update_task_files` 工具添加相關文件,以便在執行任務時提供上下文。";
// 嘗試自動發現相關文件
try {
// 基於任務名稱和描述關鍵詞,嘗試推測可能相關的文件
const taskWords = [
...task.name.split(/[\s,.;:]+/),
...task.description.split(/[\s,.;:]+/),
]
.filter((word) => word.length > 3)
.map((word) => word.toLowerCase());
// 從關鍵詞中提取可能的文件名或路徑片段
const potentialFileKeywords = taskWords.filter(
(word) =>
/^[a-z0-9]+$/i.test(word) &&
![
"task",
"function",
"model",
"index",
"with",
"from",
"this",
].includes(word.toLowerCase())
);
if (potentialFileKeywords.length > 0) {
// 推薦自動關聯文件的提示
relatedFilesSummary += `\n\n### 推薦操作\n基於任務描述您可能需要查看以下相關文件\n`;
// 列出可能相關的文件類型或名稱
potentialFileKeywords.slice(0, 5).forEach((keyword) => {
relatedFilesSummary += `- 含有 "${keyword}" 的文件\n`;
});
relatedFilesSummary += `\n使用 update_task_files 工具關聯相關文件,以獲得更好的上下文記憶支持。`;
}
} catch (error) {
console.error("推薦相關文件時發生錯誤:", error);
}
}
// 新增:添加複雜度評估部分
if (complexityAssessment) {
// 添加複雜度評估部分
prompt += `\n## 任務複雜度評估\n\n- **複雜度級別:** ${complexityAssessment.level}`;
// 根據複雜度級別使用不同風格
let complexityStyle = "";
if (complexityAssessment.level === TaskComplexityLevel.VERY_HIGH) {
complexityStyle = "⚠️ **警告:此任務複雜度極高** ⚠️";
} else if (complexityAssessment.level === TaskComplexityLevel.HIGH) {
complexityStyle = "⚠️ **注意:此任務複雜度較高**";
} else if (complexityAssessment.level === TaskComplexityLevel.MEDIUM) {
complexityStyle = "**提示:此任務具有一定複雜性**";
}
if (complexityStyle) {
prompt += `\n\n${complexityStyle}\n`;
}
// 添加評估指標
prompt += `\n### 評估指標\n`;
prompt += `- 描述長度: ${complexityAssessment.metrics.descriptionLength} 字符\n`;
prompt += `- 依賴任務數: ${complexityAssessment.metrics.dependenciesCount}\n`;
if (complexityAssessment.metrics.hasNotes) {
prompt += `- 注記長度: ${complexityAssessment.metrics.notesLength} 字符\n`;
}
// 添加處理建議
if (complexityAssessment.recommendations.length > 0) {
prompt += `\n### 處理建議\n`;
complexityAssessment.recommendations.forEach((recommendation, index) => {
prompt += `${index + 1}. ${recommendation}\n`;
});
}
prompt += `\n`;
2025-04-11 15:45:35 +08:00
}
// 直接添加相關文件摘要到prompt中
if (relatedFilesSummary) {
prompt += relatedFilesSummary;
}
// 添加上下文信息
if (contextInfo) {
prompt += contextInfo;
}
prompt += `\n## 執行指引\n\n### 理解與規劃階段
1. **** -
-
-
-
2. **** -
-
-
-
###
3. **** -
-
-
-
-
4. **** -
-
-
- 使
-
###
5. **** -
-
-
-
-
6. **** -
- 使 update_task_files
- 便
-
## \n\n###
- **** -
-
-
-
- **** -
-
- 使
-
###
- **** -
-
-
-
-
- **** - 使
-
-
-
-
## \n\n完成實施後使verify_task
- -
- -
- -
- - 滿
使complete_task`;
2025-04-11 15:45:35 +08:00
return {
content: [
{
type: "text" as const,
text: prompt,
},
],
};
}
// 檢驗任務工具
export const verifyTaskSchema = z.object({
taskId: z
.string()
.uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
2025-04-11 15:45:35 +08:00
.describe("待驗證任務的唯一標識符必須是狀態為「進行中」的有效任務ID"),
});
export async function verifyTask({ taskId }: z.infer<typeof verifyTaskSchema>) {
const task = await getTaskById(taskId);
if (!task) {
return {
content: [
{
type: "text" as const,
text: `## 系統錯誤\n\n找不到ID為 \`${taskId}\` 的任務。請使用「list_tasks」工具確認有效的任務ID後再試。`,
},
],
isError: true,
};
}
if (task.status !== TaskStatus.IN_PROGRESS) {
return {
content: [
{
type: "text" as const,
text: `## 狀態錯誤\n\n任務 "${task.name}" (ID: \`${task.id}\`) 當前狀態為 "${task.status}",不處於進行中狀態,無法進行檢驗。\n\n只有狀態為「進行中」的任務才能進行檢驗。請先使用「execute_task」工具開始任務執行。`,
},
],
isError: true,
};
}
// 構建基本的任務詳情
let prompt = `## 任務驗證評估\n\n### 任務資料\n\n- **名稱:** ${
2025-04-11 15:45:35 +08:00
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`;
}
// 新增:顯示實現指南的主要內容(如果有)
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`;
2025-04-11 15:45:35 +08:00
}
prompt += `## 完整性驗證標準\n\n請根據以下關鍵標準進行嚴格的質量檢查為每個評估項目提供詳細的證據和具體範例
### 1. (30%)
####
- **** -
-
-
-
- **** -
-
-
-
- **** -
-
-
-
####
- **(90-100%)**:
- **(75-89%)**:
- **(60-74%)**:
- **(<60%)**: 關鍵功能缺失或實現不正確需要重大修改
### 2. (30%)
####
- **** -
-
-
-
- **** -
-
-
-
- **** -
-
-
-
####
- **(90-100%)**:
- **(75-89%)**:
- **(60-74%)**:
- **(<60%)**: 代碼質量較差存在明顯的架構問題或錯誤處理不足
### 3. (20%)
####
- **** -
-
-
- 使
- **** -
-
-
-
- **** -
- API或界面的變更是否維持兼容性
-
-
####
- **(90-100%)**:
- **(75-89%)**:
- **(60-74%)**:
- **(<60%)**: 集成存在明顯問題對現有系統造成破壞性影響
### 4. (20%)
####
- **** -
- 使
-
-
- **** -
-
- 使
-
- **** -
-
- 使
- IO操作的效率
####
- **(90-100%)**:
- **(75-89%)**: 滿
- **(60-74%)**:
- **(<60%)**: 存在明顯的性能問題或資源使用不當
## \n\n請提供詳細的驗證結果報告
1. ****
-
-
2. ****
-
-
-
3. ****
-
-
-
4. ****
-
-
## \n\n根據您的全面驗證評估
- ****
-
-
-
- plan_task
- ****
-
- 使complete_task
-
`;
2025-04-11 15:45:35 +08:00
return {
content: [
{
type: "text" as const,
text: prompt,
},
],
};
}
// 完成任務工具
export const completeTaskSchema = z.object({
taskId: z
.string()
.uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
2025-04-11 15:45:35 +08:00
.describe(
"待標記為完成的任務唯一標識符必須是狀態為「進行中」的有效任務ID"
),
summary: z
.string()
.min(30, {
message: "任務摘要太簡短,請提供更詳細的完成報告,包含實施結果和主要決策",
})
.optional()
.describe(
"任務完成摘要,簡潔描述實施結果和重要決策(選填,如未提供將自動生成)"
),
2025-04-11 15:45:35 +08:00
});
export async function completeTask({
taskId,
summary,
2025-04-11 15:45:35 +08:00
}: z.infer<typeof completeTaskSchema>) {
const task = await getTaskById(taskId);
if (!task) {
return {
content: [
{
type: "text" as const,
text: `## 系統錯誤\n\n找不到ID為 \`${taskId}\` 的任務。請使用「list_tasks」工具確認有效的任務ID後再試。`,
},
],
isError: true,
};
}
if (task.status !== TaskStatus.IN_PROGRESS) {
return {
content: [
{
type: "text" as const,
text: `## 狀態錯誤\n\n任務 "${task.name}" (ID: \`${task.id}\`) 當前狀態為 "${task.status}",不是進行中狀態,無法標記為完成。\n\n只有狀態為「進行中」的任務才能標記為完成。請先使用「execute_task」工具開始任務執行。`,
},
],
isError: true,
};
}
// 處理摘要信息
let taskSummary = summary;
if (!taskSummary) {
// 自動生成摘要
taskSummary = generateTaskSummary(task.name, task.description);
}
// 更新任務狀態為已完成,並添加摘要
2025-04-11 15:45:35 +08:00
await updateTaskStatus(taskId, TaskStatus.COMPLETED);
await updateTaskSummary(taskId, taskSummary);
2025-04-11 15:45:35 +08:00
return {
content: [
{
type: "text" as const,
text: `## 任務完成確認\n\n任務 "${task.name}" (ID: \`${
task.id
}\`) 已於 ${new Date().toISOString()} 成功標記為完成。\n\n## 任務摘要要求\n\n請提供此次完成任務的摘要總結包含以下關鍵要點\n\n1. 任務目標與主要成果\n2. 實施的解決方案要點\n3. 遇到的主要挑戰及解決方法\n\n**重要提示:** 請在當前回應中提供任務摘要總結。完成本次任務摘要後,請等待用戶明確指示後再繼續執行其他任務。請勿自動開始執行下一個任務。\n\n如果用戶要求連續執行任務請使用「execute_task」工具開始執行下一個任務。`,
2025-04-11 15:45:35 +08:00
},
],
};
}
// 刪除任務工具
export const deleteTaskSchema = z.object({
taskId: z
.string()
.uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
.describe("待刪除任務的唯一標識符必須是系統中存在且未完成的任務ID"),
});
export async function deleteTask({ taskId }: z.infer<typeof deleteTaskSchema>) {
const task = await getTaskById(taskId);
if (!task) {
return {
content: [
{
type: "text" as const,
text: `## 系統錯誤\n\n找不到ID為 \`${taskId}\` 的任務。請使用「list_tasks」工具確認有效的任務ID後再試。`,
},
],
isError: true,
};
}
if (task.status === TaskStatus.COMPLETED) {
return {
content: [
{
type: "text" as const,
text: `## 操作被拒絕\n\n任務 "${task.name}" (ID: \`${task.id}\`) 已完成,不允許刪除已完成的任務。\n\n如需清理任務請聯絡系統管理員。`,
},
],
isError: true,
};
}
const result = await modelDeleteTask(taskId);
return {
content: [
{
type: "text" as const,
text: `## ${result.success ? "操作成功" : "操作失敗"}\n\n${
result.message
}\n\n${
result.success
? `任務 "${task.name}" (ID: \`${task.id}\`) 已成功從系統中刪除。`
: ""
}`,
},
],
isError: !result.success,
};
}
// 清除所有任務工具
export const clearAllTasksSchema = z.object({
confirm: z
.boolean()
.refine((val) => val === true, {
message:
"必須明確確認清除操作,請將 confirm 參數設置為 true 以確認此危險操作",
})
.describe("確認刪除所有未完成的任務(此操作不可逆)"),
});
export async function clearAllTasks({
confirm,
}: z.infer<typeof clearAllTasksSchema>) {
// 安全檢查:如果沒有確認,則拒絕操作
if (!confirm) {
return {
content: [
{
type: "text" as const,
text: `## 操作取消\n\n未確認清除操作。如要清除所有任務請將 confirm 參數設為 true。\n\n⚠ 警告:此操作將刪除所有未完成的任務,且無法恢復。請謹慎操作。`,
},
],
};
}
// 檢查是否真的有任務需要清除
const allTasks = await getAllTasks();
if (allTasks.length === 0) {
return {
content: [
{
type: "text" as const,
text: `## 操作提示\n\n系統中沒有任何任務需要清除。`,
},
],
};
}
// 執行清除操作
const result = await modelClearAllTasks();
return {
content: [
{
type: "text" as const,
text: `## ${result.success ? "操作成功" : "操作失敗"}\n\n${
result.message
}${
result.backupFile
? `\n\n系統已自動創建備份文件: \`${result.backupFile}\``
: ""
}`,
},
],
isError: !result.success,
};
}
// 更新任務內容工具
export const updateTaskContentSchema = z
.object({
taskId: z
.string()
.uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
.describe("待更新任務的唯一標識符必須是系統中存在且未完成的任務ID"),
name: z
.string()
.min(5, {
message: "任務名稱太短,請提供更清晰明確的名稱以便識別任務目的",
})
.max(100, { message: "任務名稱過長請保持簡潔不超過100個字符" })
.optional()
.describe("任務的新名稱(選填)"),
description: z
.string()
.min(20, {
message: "任務描述太簡短,請提供更詳細的描述,包含實施要點和驗收標準",
})
.optional()
.describe("任務的新描述內容(選填)"),
notes: z.string().optional().describe("任務的新補充說明(選填)"),
relatedFiles: z
.array(
z.object({
path: z
.string()
.min(1, { message: "文件路徑不能為空,請提供有效的文件路徑" })
.describe("文件路徑,可以是相對於項目根目錄的路徑或絕對路徑"),
type: z
.enum([
RelatedFileType.TO_MODIFY,
RelatedFileType.REFERENCE,
RelatedFileType.CREATE,
RelatedFileType.DEPENDENCY,
RelatedFileType.OTHER,
])
.describe("文件與任務的關係類型"),
description: z.string().optional().describe("文件的補充描述(選填)"),
lineStart: z
.number()
.int()
.positive()
.optional()
.describe("相關代碼區塊的起始行(選填)"),
lineEnd: z
.number()
.int()
.positive()
.optional()
.describe("相關代碼區塊的結束行(選填)"),
})
)
.optional()
.describe("與任務相關的文件列表(選填)"),
})
.refine(
(data) => {
// 確保行號有效:如果有起始行,就必須有結束行,反之亦然
if (data.relatedFiles) {
for (const file of data.relatedFiles) {
if (
(file.lineStart && !file.lineEnd) ||
(!file.lineStart && file.lineEnd)
) {
return false;
}
// 確保起始行小於結束行
if (file.lineStart && file.lineEnd && file.lineStart > file.lineEnd) {
return false;
}
}
}
// 確保至少有一個字段被更新
return !!(
data.name ||
data.description ||
data.notes ||
(data.relatedFiles && data.relatedFiles.length > 0)
);
},
{
message:
"更新請求無效1. 行號設置必須同時包含起始行和結束行且起始行必須小於結束行2. 至少需要更新一個字段(名稱、描述、注記或相關文件)",
path: ["relatedFiles"],
}
);
export async function updateTaskContent({
taskId,
name,
description,
notes,
relatedFiles,
}: z.infer<typeof updateTaskContentSchema>) {
// 獲取任務以檢查它是否存在
const task = await getTaskById(taskId);
if (!task) {
return {
content: [
{
type: "text" as const,
text: `## 系統錯誤\n\n找不到ID為 \`${taskId}\` 的任務。請使用「list_tasks」工具確認有效的任務ID後再試。`,
},
],
isError: true,
};
}
// 記錄要更新的任務和內容
let updateSummary = `準備更新任務:${task.name} (ID: ${task.id})`;
if (name) updateSummary += `,新名稱:${name}`;
if (description) updateSummary += `,更新描述`;
if (notes) updateSummary += `,更新注記`;
if (relatedFiles)
updateSummary += `,更新相關文件 (${relatedFiles.length} 個)`;
// 執行更新操作
const result = await modelUpdateTaskContent(taskId, {
name,
description,
notes,
relatedFiles,
});
// 構建響應消息
const responseTitle = result.success ? "操作成功" : "操作失敗";
let responseMessage = result.message;
if (result.success && result.task) {
// 顯示更新後的任務詳情
responseMessage += "\n\n### 更新後的任務詳情\n";
responseMessage += `- **名稱:** ${result.task.name}\n`;
responseMessage += `- **描述:** ${result.task.description.substring(
0,
100
)}${result.task.description.length > 100 ? "..." : ""}\n`;
if (result.task.notes) {
responseMessage += `- **注記:** ${result.task.notes.substring(0, 100)}${
result.task.notes.length > 100 ? "..." : ""
}\n`;
}
responseMessage += `- **狀態:** ${result.task.status}\n`;
responseMessage += `- **更新時間:** ${new Date(
result.task.updatedAt
).toISOString()}\n`;
// 顯示相關文件信息
if (result.task.relatedFiles && result.task.relatedFiles.length > 0) {
responseMessage += `- **相關文件:** ${result.task.relatedFiles.length}\n`;
// 按文件類型分組
const filesByType = result.task.relatedFiles.reduce((acc, file) => {
if (!acc[file.type]) {
acc[file.type] = [];
}
acc[file.type].push(file);
return acc;
}, {} as Record<string, RelatedFile[]>);
for (const [type, files] of Object.entries(filesByType)) {
responseMessage += ` - ${type} (${files.length} 個): `;
responseMessage += files.map((file) => `\`${file.path}\``).join(", ");
responseMessage += "\n";
}
}
}
return {
content: [
{
type: "text" as const,
text: `## ${responseTitle}\n\n${responseMessage}`,
},
],
isError: !result.success,
};
}
// 更新任務相關文件工具
export const updateTaskRelatedFilesSchema = z
.object({
taskId: z
.string()
.uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
.describe("待更新任務的唯一標識符必須是系統中存在且未完成的任務ID"),
relatedFiles: z
.array(
z.object({
path: z
.string()
.min(1, { message: "文件路徑不能為空,請提供有效的文件路徑" })
.describe("文件路徑,可以是相對於項目根目錄的路徑或絕對路徑"),
type: z
.enum([
RelatedFileType.TO_MODIFY,
RelatedFileType.REFERENCE,
RelatedFileType.CREATE,
RelatedFileType.DEPENDENCY,
RelatedFileType.OTHER,
])
.describe("文件與任務的關係類型"),
description: z.string().optional().describe("文件的補充描述(選填)"),
lineStart: z
.number()
.int()
.positive()
.optional()
.describe("相關代碼區塊的起始行(選填)"),
lineEnd: z
.number()
.int()
.positive()
.optional()
.describe("相關代碼區塊的結束行(選填)"),
})
)
.min(1, { message: "至少需要提供一個相關文件,請確保文件列表不為空" })
.describe("與任務相關的文件列表"),
})
.refine(
(data) => {
// 檢查文件路徑是否有重複
const pathSet = new Set();
for (const file of data.relatedFiles) {
if (pathSet.has(file.path)) {
return false;
}
pathSet.add(file.path);
}
return true;
},
{
message: "文件列表中存在重複的文件路徑,請確保每個文件路徑是唯一的",
path: ["relatedFiles"],
}
)
.refine(
(data) => {
// 確保行號有效:如果有起始行,就必須有結束行,反之亦然
for (const file of data.relatedFiles) {
if (
(file.lineStart && !file.lineEnd) ||
(!file.lineStart && file.lineEnd)
) {
return false;
}
// 確保起始行小於結束行
if (file.lineStart && file.lineEnd && file.lineStart > file.lineEnd) {
return false;
}
}
return true;
},
{
message:
"行號設置無效:必須同時設置起始行和結束行,且起始行必須小於結束行",
path: ["relatedFiles"],
}
);
export async function updateTaskRelatedFiles({
taskId,
relatedFiles,
}: z.infer<typeof updateTaskRelatedFilesSchema>) {
// 獲取任務以檢查它是否存在
const task = await getTaskById(taskId);
if (!task) {
return {
content: [
{
type: "text" as const,
text: `## 系統錯誤\n\n找不到ID為 \`${taskId}\` 的任務。請使用「list_tasks」工具確認有效的任務ID後再試。`,
},
],
isError: true,
};
}
// 記錄要更新的任務和相關文件
const fileTypeCount = relatedFiles.reduce((acc, file) => {
acc[file.type] = (acc[file.type] || 0) + 1;
return acc;
}, {} as Record<string, number>);
const fileTypeSummary = Object.entries(fileTypeCount)
.map(([type, count]) => `${type} ${count}`)
.join("");
// 執行更新操作
const result = await modelUpdateTaskRelatedFiles(taskId, relatedFiles);
// 構建響應消息
const responseTitle = result.success ? "操作成功" : "操作失敗";
let responseMessage = result.message;
if (result.success && result.task && result.task.relatedFiles) {
// 顯示更新後的相關文件列表
responseMessage += "\n\n### 任務相關文件列表\n";
// 按文件類型分組顯示
const filesByType = result.task.relatedFiles.reduce((acc, file) => {
acc[file.type] = acc[file.type] || [];
acc[file.type].push(file);
return acc;
}, {} as Record<string, RelatedFile[]>);
for (const [type, files] of Object.entries(filesByType)) {
responseMessage += `\n#### ${type} (${files.length} 個)\n`;
files.forEach((file, index) => {
responseMessage += `${index + 1}. \`${file.path}\`${
file.description ? ` - ${file.description}` : ""
}${
file.lineStart && file.lineEnd
? ` (行 ${file.lineStart}-${file.lineEnd})`
: ""
}\n`;
});
}
}
return {
content: [
{
type: "text" as const,
text: `## ${responseTitle}\n\n${responseMessage}`,
},
],
isError: !result.success,
};
}
// 格式化單個任務的詳細資訊
const formatTaskDetails = (task: Task) => {
let details = `### ${task.name}\n**ID:** \`${task.id}\`\n**描述:** ${task.description}\n`;
if (task.notes) {
details += `**注記:** ${task.notes}\n`;
}
details += `**狀態:** ${task.status}\n`;
if (task.dependencies.length > 0) {
const depIds = task.dependencies
.map((dep: TaskDependency) => `\`${dep.taskId}\``)
.join(", ");
details += `**依賴任務:** ${depIds}\n`;
}
// 添加相關文件信息
if (task.relatedFiles && task.relatedFiles.length > 0) {
details += `**相關文件:** ${task.relatedFiles.length}\n`;
// 按文件類型分組
const filesByType = task.relatedFiles.reduce(
(acc: Record<string, RelatedFile[]>, file: RelatedFile) => {
if (!acc[file.type]) {
acc[file.type] = [];
}
acc[file.type].push(file);
return acc;
},
{} as Record<string, RelatedFile[]>
);
for (const [type, files] of Object.entries(filesByType)) {
details += ` - ${type} (${files.length} 個): `;
details += files
.map((file: RelatedFile) => `\`${file.path}\``)
.join(", ");
details += "\n";
}
}
details += `**創建時間:** ${new Date(task.createdAt).toISOString()}\n`;
details += `**更新時間:** ${new Date(task.updatedAt).toISOString()}\n`;
if (task.completedAt) {
details += `**完成時間:** ${new Date(task.completedAt).toISOString()}\n`;
}
if (task.summary) {
details += `**完成摘要:** ${task.summary}\n`;
}
return details;
};