更新 API 參考文檔,新增目錄及詳細的核心任務管理 API 說明,包括任務規劃、分析、反思、拆分、列出、執行及驗證功能,並強化參數驗證規則以提升用戶體驗。同時,更新工具函數以加入錯誤處理,確保輸入的有效性與一致性。

This commit is contained in:
siage 2025-04-12 00:17:05 +08:00
parent 611eb12534
commit 95628091fb
4 changed files with 593 additions and 161 deletions

View File

@ -2,7 +2,215 @@
本文檔提供蝦米任務管理器的 API 參考,包含所有可用工具的詳細說明和參數列表。 本文檔提供蝦米任務管理器的 API 參考,包含所有可用工具的詳細說明和參數列表。
## 新增功能 ## 目錄
- [核心任務管理 API](#核心任務管理-api)
- [任務管理 API](#任務管理-api)
- [工作日誌功能](#工作日誌功能)
## 核心任務管理 API
### 1. 任務規劃
#### `plan_task`
初始化並詳細規劃任務流程,建立明確的目標與成功標準。
**參數:**
| 參數名 | 類型 | 必填 | 描述 |
| ------------ | ------ | ---- | ------------------------------------------------------ |
| description | string | 是 | 完整詳細的任務問題描述,應包含任務目標、背景及預期成果 |
| requirements | string | 否 | 任務的特定技術要求、業務約束條件或品質標準(選填) |
**返回:**
- 成功:返回結構化的任務規劃結果
- 失敗:返回錯誤訊息,說明失敗原因
**使用範例:**
```javascript
const planResult = await mcp.mcp_shrimp_task_manager.plan_task({
description:
"開發一個用戶註冊功能,包含表單驗證、數據存儲和電子郵件確認流程。",
requirements: "必須符合GDPR數據保護規定支持多語言並通過所有安全測試。",
});
```
### 2. 任務分析
#### `analyze_task`
深入分析任務需求並系統性檢查代碼庫,評估技術可行性與潛在風險。
**參數:**
| 參數名 | 類型 | 必填 | 描述 |
| ---------------- | ------ | ---- | ------------------------------------------------------------ |
| summary | string | 是 | 結構化的任務摘要,包含任務目標、範圍與關鍵技術挑戰 |
| initialConcept | string | 是 | 初步解答構想,包含技術方案、架構設計和實施策略 |
| previousAnalysis | string | 否 | 前次迭代的分析結果,用於持續改進方案(僅在重新分析時需提供) |
**返回:**
- 成功:返回詳細的任務分析結果
- 失敗:返回錯誤訊息,說明失敗原因
**使用範例:**
```javascript
const analysisResult = await mcp.mcp_shrimp_task_manager.analyze_task({
summary: "開發用戶身份驗證模塊,包含登入、註冊和密碼重設功能",
initialConcept: "計劃使用JWT進行身份驗證實現無狀態API設計...",
});
```
### 3. 方案反思
#### `reflect_task`
批判性審查分析結果,評估方案完整性並識別優化機會,確保解決方案符合最佳實踐。
**參數:**
| 參數名 | 類型 | 必填 | 描述 |
| -------- | ------ | ---- | ------------------------------------------------------------ |
| summary | string | 是 | 結構化的任務摘要,保持與分析階段一致以確保連續性 |
| analysis | string | 是 | 完整詳盡的技術分析結果,包括所有技術細節、依賴組件和實施方案 |
**返回:**
- 成功:返回方案改進建議和優化機會
- 失敗:返回錯誤訊息,說明失敗原因
**使用範例:**
```javascript
const reflectionResult = await mcp.mcp_shrimp_task_manager.reflect_task({
summary: "開發用戶身份驗證模塊,包含登入、註冊和密碼重設功能",
analysis: "詳細的技術分析結果包括JWT實現方式、安全考量等...",
});
```
### 4. 任務拆分
#### `split_tasks`
將複雜任務分解為獨立且可追蹤的子任務,建立明確的依賴關係和優先順序。
**參數:**
| 參數名 | 類型 | 必填 | 描述 |
| ----------- | ------- | ---- | --------------------------------------------------------------------------- |
| isOverwrite | boolean | 是 | 任務覆蓋模式選擇true清除並覆蓋所有現有任務false保留現有任務並新增 |
| tasks | array | 是 | 結構化的任務清單,每個任務應保持原子性且有明確的完成標準 |
**tasks 對象屬性:**
| 屬性名 | 類型 | 必填 | 描述 |
| ------------ | ------ | ---- | ------------------------------------------------ |
| name | string | 是 | 簡潔明確的任務名稱,應能清晰表達任務目的 |
| description | string | 是 | 詳細的任務描述,包含實施要點、技術細節和驗收標準 |
| notes | string | 否 | 補充說明、特殊處理要求或實施建議(選填) |
| dependencies | array | 否 | 此任務依賴的前置任務 ID 或任務名稱列表 |
**返回:**
- 成功:返回創建的任務列表
- 失敗:返回錯誤訊息,說明失敗原因
**使用範例:**
```javascript
const tasksResult = await mcp.mcp_shrimp_task_manager.split_tasks({
isOverwrite: false,
tasks: [
{
name: "設計用戶數據模型",
description: "定義用戶實體的數據結構和驗證規則...",
notes: "參考現有的權限模型",
dependencies: [],
},
{
name: "實現用戶註冊API",
description: "開發註冊端點,處理表單驗證和數據存儲...",
dependencies: ["設計用戶數據模型"],
},
],
});
```
### 5. 任務列表
#### `list_tasks`
生成結構化任務清單,包含完整狀態追蹤、優先級和依賴關係。
**參數:** 無
**返回:**
- 成功:返回系統中所有任務的結構化清單
- 失敗:返回錯誤訊息,說明失敗原因
**使用範例:**
```javascript
const tasksList = await mcp.mcp_shrimp_task_manager.list_tasks();
```
### 6. 任務執行
#### `execute_task`
按照預定義計劃執行特定任務,確保每個步驟的輸出符合質量標準。
**參數:**
| 參數名 | 類型 | 必填 | 描述 |
| ------ | ------ | ---- | ----------------------------------------------------- |
| taskId | string | 是 | 待執行任務的唯一標識符,必須是系統中存在的有效任務 ID |
**返回:**
- 成功:返回任務執行指南和上下文
- 失敗:返回錯誤訊息,說明失敗原因
**使用範例:**
```javascript
const executeResult = await mcp.mcp_shrimp_task_manager.execute_task({
taskId: "task-uuid-here",
});
```
### 7. 任務驗證
#### `verify_task`
全面驗證任務完成度,確保所有需求與技術標準都已滿足,並無遺漏細節。
**參數:**
| 參數名 | 類型 | 必填 | 描述 |
| ------ | ------ | ---- | ----------------------------------------------------- |
| taskId | string | 是 | 待驗證任務的唯一標識符,必須是系統中存在的有效任務 ID |
**返回:**
- 成功:返回任務驗證評估結果
- 失敗:返回錯誤訊息,說明失敗原因
**使用範例:**
```javascript
const verifyResult = await mcp.mcp_shrimp_task_manager.verify_task({
taskId: "task-uuid-here",
});
```
## 任務管理 API
### 1. 刪除任務功能 ### 1. 刪除任務功能
@ -269,18 +477,4 @@ const clearResult = await mcp.mcp_shrimp_task_manager.clear_conversation_log({
}); });
``` ```
## 完整 API 列表 ## 實用工具函數
除了上述新增功能外,蝦米任務管理器還提供以下核心功能:
1. **開始規劃**`plan_task`
2. **分析問題**`analyze_task`
3. **反思構想**`reflect_task`
4. **拆分任務**`split_tasks`
5. **列出任務**`list_tasks`
6. **執行任務**`execute_task`
7. **檢驗任務**`verify_task`
8. **完成任務**`complete_task`
9. **刪除任務**`delete_task`
10. **查詢日誌**`list_conversation_log`
11. **清除日誌**`clear_conversation_log`

View File

@ -58,13 +58,17 @@ async function main() {
version: "1.0.0", version: "1.0.0",
}); });
// 註冊工具 - 使用已定義的schema物件 // 註冊工具 - 使用已定義的schema物件,並添加內嵌錯誤處理
server.tool( server.tool(
"plan_task", "plan_task",
"初始化並詳細規劃任務流程,建立明確的目標與成功標準", "初始化並詳細規劃任務流程,建立明確的目標與成功標準",
{ {
description: z description: z
.string() .string()
.min(10, {
message:
"任務描述不能少於10個字符請提供更詳細的描述以確保任務目標明確",
})
.describe("完整詳細的任務問題描述,應包含任務目標、背景及預期成果"), .describe("完整詳細的任務問題描述,應包含任務目標、背景及預期成果"),
requirements: z requirements: z
.string() .string()
@ -82,9 +86,17 @@ async function main() {
{ {
summary: z summary: z
.string() .string()
.min(20, {
message:
"任務摘要太短,請提供更詳細的摘要,包含任務目標、範圍與關鍵技術挑戰",
})
.describe("結構化的任務摘要,包含任務目標、範圍與關鍵技術挑戰"), .describe("結構化的任務摘要,包含任務目標、範圍與關鍵技術挑戰"),
initialConcept: z initialConcept: z
.string() .string()
.min(50, {
message:
"初步解答構想過於簡短,請提供更完整的技術方案和實施策略詳情",
})
.describe("初步解答構想,包含技術方案、架構設計和實施策略"), .describe("初步解答構想,包含技術方案、架構設計和實施策略"),
previousAnalysis: z previousAnalysis: z
.string() .string()
@ -104,9 +116,17 @@ async function main() {
{ {
summary: z summary: z
.string() .string()
.min(20, {
message:
"任務摘要太短,請確保包含完整的任務目標和範圍以維持分析連續性",
})
.describe("結構化的任務摘要,保持與分析階段一致以確保連續性"), .describe("結構化的任務摘要,保持與分析階段一致以確保連續性"),
analysis: z analysis: z
.string() .string()
.min(100, {
message:
"技術分析結果過於簡略,請提供更詳盡的技術細節、依賴組件和實施方案說明",
})
.describe( .describe(
"完整詳盡的技術分析結果,包括所有技術細節、依賴組件和實施方案" "完整詳盡的技術分析結果,包括所有技術細節、依賴組件和實施方案"
), ),
@ -130,9 +150,20 @@ async function main() {
z.object({ z.object({
name: z name: z
.string() .string()
.min(5, {
message:
"任務名稱太短,請提供更清晰明確的名稱以便識別任務目的",
})
.max(100, {
message: "任務名稱過長請保持簡潔不超過100個字符",
})
.describe("簡潔明確的任務名稱,應能清晰表達任務目的"), .describe("簡潔明確的任務名稱,應能清晰表達任務目的"),
description: z description: z
.string() .string()
.min(20, {
message:
"任務描述太短,請詳細說明實施要點、技術細節和驗收標準",
})
.describe("詳細的任務描述,包含實施要點、技術細節和驗收標準"), .describe("詳細的任務描述,包含實施要點、技術細節和驗收標準"),
notes: z notes: z
.string() .string()
@ -157,7 +188,7 @@ async function main() {
"list_tasks", "list_tasks",
"生成結構化任務清單,包含完整狀態追蹤、優先級和依賴關係", "生成結構化任務清單,包含完整狀態追蹤、優先級和依賴關係",
{}, {},
async () => { async (args) => {
return await listTasks(); return await listTasks();
} }
); );
@ -347,7 +378,7 @@ async function main() {
} }
); );
// 註冊提示 // 註冊提示 - 使用同樣的錯誤處理模式
server.prompt( server.prompt(
"plan_task_prompt", "plan_task_prompt",
"生成結構化的新任務規劃,包含明確目標、評估標準與執行步驟", "生成結構化的新任務規劃,包含明確目標、評估標準與執行步驟",
@ -364,7 +395,7 @@ async function main() {
.describe("相關代碼片段或文件路徑(選填)"), .describe("相關代碼片段或文件路徑(選填)"),
}, },
async (args) => { async (args) => {
return planTaskPrompt(args); return await planTaskPrompt(args);
} }
); );

View File

@ -11,30 +11,70 @@ import { getTaskById } from "../models/taskModel.js";
import { ListConversationLogArgs } from "../types/index.js"; import { ListConversationLogArgs } from "../types/index.js";
// 列出對話日誌工具 // 列出對話日誌工具
export const listConversationLogSchema = z.object({ export const listConversationLogSchema = z
taskId: z.string().optional().describe("按任務 ID 過濾對話記錄(選填)"), .object({
startDate: z taskId: z
.string() .string()
.optional() .uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
.describe("起始日期過濾,格式為 ISO 日期字串(選填)"), .optional()
endDate: z .describe("按任務 ID 過濾對話記錄(選填)"),
.string() startDate: z
.optional() .string()
.describe("結束日期過濾,格式為 ISO 日期字串(選填)"), .refine(
limit: z (val) => {
.number() const date = new Date(val);
.int() return !isNaN(date.getTime());
.positive() },
.max(100) {
.default(20) message:
.describe("返回結果數量限制,最大 100預設20"), "起始日期格式無效請使用ISO日期格式例如2025-04-11T12:13:49.751Z",
offset: z }
.number() )
.int() .optional()
.nonnegative() .describe("起始日期過濾,格式為 ISO 日期字串(選填)"),
.default(0) endDate: z
.describe("分頁偏移量預設0"), .string()
}); .refine(
(val) => {
const date = new Date(val);
return !isNaN(date.getTime());
},
{
message:
"結束日期格式無效請使用ISO日期格式例如2025-04-11T12:13:49.751Z",
}
)
.optional()
.describe("結束日期過濾,格式為 ISO 日期字串(選填)"),
limit: z
.number()
.int({ message: "限制必須是整數" })
.positive({ message: "限制必須是正數" })
.max(100, { message: "限制不能超過100條記錄" })
.default(20)
.describe("返回結果數量限制,最大 100預設20"),
offset: z
.number()
.int({ message: "偏移量必須是整數" })
.nonnegative({ message: "偏移量不能為負數" })
.default(0)
.describe("分頁偏移量預設0"),
})
.refine(
(data) => {
// 驗證起始日期和結束日期的順序
if (data.startDate && data.endDate) {
const start = new Date(data.startDate);
const end = new Date(data.endDate);
return start <= end;
}
return true;
},
{
message: "起始日期必須早於或等於結束日期",
path: ["endDate"],
}
);
export async function listConversationLog({ export async function listConversationLog({
taskId, taskId,
@ -171,7 +211,13 @@ export async function listConversationLog({
// 清除所有對話日誌工具 // 清除所有對話日誌工具
export const clearConversationLogSchema = z.object({ export const clearConversationLogSchema = z.object({
confirm: z.boolean().describe("確認刪除所有日誌記錄(此操作不可逆)"), confirm: z
.boolean()
.refine((val) => val === true, {
message:
"必須明確確認清除操作,請將 confirm 參數設置為 true 以確認此危險操作",
})
.describe("確認刪除所有日誌記錄(此操作不可逆)"),
}); });
export async function clearConversationLog({ export async function clearConversationLog({
@ -314,18 +360,23 @@ export async function listArchivedLogs({
export const readArchivedLogSchema = z.object({ export const readArchivedLogSchema = z.object({
filename: z filename: z
.string() .string()
.min(1, { message: "文件名不能為空" })
.refine((val) => val.match(/^conversation_log_[\d-]+T[\d-]+\.json$/), {
message:
"無效的歸檔日誌文件名,正確格式為 'conversation_log_[timestamp].json'",
})
.describe("歸檔日誌文件名,格式為 'conversation_log_[timestamp].json'"), .describe("歸檔日誌文件名,格式為 'conversation_log_[timestamp].json'"),
limit: z limit: z
.number() .number()
.int() .int({ message: "限制必須是整數" })
.positive() .positive({ message: "限制必須是正數" })
.max(100) .max(100, { message: "限制不能超過100條記錄" })
.default(50) .default(50)
.describe("返回結果數量限制,最大 100預設50"), .describe("返回結果數量限制,最大 100預設50"),
offset: z offset: z
.number() .number()
.int() .int({ message: "偏移量必須是整數" })
.nonnegative() .nonnegative({ message: "偏移量不能為負數" })
.default(0) .default(0)
.describe("分頁起始位置預設0"), .describe("分頁起始位置預設0"),
}); });

View File

@ -35,6 +35,9 @@ import { loadTaskRelatedFiles } from "../utils/fileLoader.js";
export const planTaskSchema = z.object({ export const planTaskSchema = z.object({
description: z description: z
.string() .string()
.min(10, {
message: "任務描述不能少於10個字符請提供更詳細的描述以確保任務目標明確",
})
.describe("完整詳細的任務問題描述,應包含任務目標、背景及預期成果"), .describe("完整詳細的任務問題描述,應包含任務目標、背景及預期成果"),
requirements: z requirements: z
.string() .string()
@ -89,9 +92,16 @@ export async function planTask({
export const analyzeTaskSchema = z.object({ export const analyzeTaskSchema = z.object({
summary: z summary: z
.string() .string()
.min(20, {
message:
"任務摘要太短,請提供更詳細的摘要,包含任務目標、範圍與關鍵技術挑戰",
})
.describe("結構化的任務摘要,包含任務目標、範圍與關鍵技術挑戰"), .describe("結構化的任務摘要,包含任務目標、範圍與關鍵技術挑戰"),
initialConcept: z initialConcept: z
.string() .string()
.min(50, {
message: "初步解答構想過於簡短,請提供更完整的技術方案和實施策略詳情",
})
.describe("初步解答構想,包含技術方案、架構設計和實施策略"), .describe("初步解答構想,包含技術方案、架構設計和實施策略"),
previousAnalysis: z previousAnalysis: z
.string() .string()
@ -147,14 +157,27 @@ export async function analyzeTask({
} }
// 反思構想工具 // 反思構想工具
export const reflectTaskSchema = z.object({ export const reflectTaskSchema = z
summary: z .object({
.string() summary: z
.describe("結構化的任務摘要,保持與分析階段一致以確保連續性"), .string()
analysis: z .min(20, {
.string() message: "任務摘要太短,請確保包含完整的任務目標和範圍以維持分析連續性",
.describe("完整詳盡的技術分析結果,包括所有技術細節、依賴組件和實施方案"), })
}); .describe("結構化的任務摘要,保持與分析階段一致以確保連續性"),
analysis: z
.string()
.min(100, {
message:
"技術分析結果過於簡略,請提供更詳盡的技術細節、依賴組件和實施方案說明",
})
.describe("完整詳盡的技術分析結果,包括所有技術細節、依賴組件和實施方案"),
})
.refine((data) => data.summary.length * 3 <= data.analysis.length, {
message:
"分析內容應該比摘要更詳細建議分析部分至少是摘要長度的3倍以提供足夠的技術深度",
path: ["analysis"],
});
export async function reflectTask({ export async function reflectTask({
summary, summary,
@ -204,33 +227,62 @@ export async function reflectTask({
} }
// 拆分任務工具 // 拆分任務工具
export const splitTasksSchema = z.object({ export const splitTasksSchema = z
isOverwrite: z .object({
.boolean() isOverwrite: z
.describe( .boolean()
"任務覆蓋模式選擇true清除並覆蓋所有現有任務false保留現有任務並新增" .describe(
), "任務覆蓋模式選擇true清除並覆蓋所有現有任務false保留現有任務並新增"
tasks: z ),
.array( tasks: z
z.object({ .array(
name: z.string().describe("簡潔明確的任務名稱,應能清晰表達任務目的"), z.object({
description: z name: z
.string() .string()
.describe("詳細的任務描述,包含實施要點、技術細節和驗收標準"), .min(5, {
notes: z message: "任務名稱太短,請提供更清晰明確的名稱以便識別任務目的",
.string() })
.optional() .max(100, { message: "任務名稱過長請保持簡潔不超過100個字符" })
.describe("補充說明、特殊處理要求或實施建議(選填)"), .describe("簡潔明確的任務名稱,應能清晰表達任務目的"),
dependencies: z description: z
.array(z.string()) .string()
.optional() .min(20, {
.describe( message:
"此任務依賴的前置任務ID或任務名稱列表支持兩種引用方式名稱引用更直觀" "任務描述太簡短,請提供更詳細的描述,包含實施要點和驗收標準",
), })
}) .describe("詳細的任務描述,包含實施要點、技術細節和驗收標準"),
) notes: z
.describe("結構化的任務清單,每個任務應保持原子性且有明確的完成標準"), .string()
}); .optional()
.describe("補充說明、特殊處理要求或實施建議(選填)"),
dependencies: z
.array(z.string())
.optional()
.describe(
"此任務依賴的前置任務ID或任務名稱列表支持兩種引用方式名稱引用更直觀"
),
})
)
.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"],
}
);
export async function splitTasks({ export async function splitTasks({
isOverwrite, isOverwrite,
@ -398,6 +450,7 @@ export async function listTasks() {
export const executeTaskSchema = z.object({ export const executeTaskSchema = z.object({
taskId: z taskId: z
.string() .string()
.uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
.describe("待執行任務的唯一標識符必須是系統中存在的有效任務ID"), .describe("待執行任務的唯一標識符必須是系統中存在的有效任務ID"),
}); });
@ -811,6 +864,7 @@ export async function executeTask({
export const verifyTaskSchema = z.object({ export const verifyTaskSchema = z.object({
taskId: z taskId: z
.string() .string()
.uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
.describe("待驗證任務的唯一標識符必須是狀態為「進行中」的有效任務ID"), .describe("待驗證任務的唯一標識符必須是狀態為「進行中」的有效任務ID"),
}); });
@ -911,11 +965,15 @@ export async function verifyTask({ taskId }: z.infer<typeof verifyTaskSchema>) {
export const completeTaskSchema = z.object({ export const completeTaskSchema = z.object({
taskId: z taskId: z
.string() .string()
.uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
.describe( .describe(
"待標記為完成的任務唯一標識符必須是狀態為「進行中」的有效任務ID" "待標記為完成的任務唯一標識符必須是狀態為「進行中」的有效任務ID"
), ),
summary: z summary: z
.string() .string()
.min(30, {
message: "任務摘要太簡短,請提供更詳細的完成報告,包含實施結果和主要決策",
})
.optional() .optional()
.describe( .describe(
"任務完成摘要,簡潔描述實施結果和重要決策(選填,如未提供將自動生成)" "任務完成摘要,簡潔描述實施結果和重要決策(選填,如未提供將自動生成)"
@ -1021,6 +1079,7 @@ export async function completeTask({
export const deleteTaskSchema = z.object({ export const deleteTaskSchema = z.object({
taskId: z taskId: z
.string() .string()
.uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
.describe("待刪除任務的唯一標識符必須是系統中存在且未完成的任務ID"), .describe("待刪除任務的唯一標識符必須是系統中存在且未完成的任務ID"),
}); });
@ -1122,7 +1181,13 @@ export async function deleteTask({ taskId }: z.infer<typeof deleteTaskSchema>) {
// 清除所有任務工具 // 清除所有任務工具
export const clearAllTasksSchema = z.object({ export const clearAllTasksSchema = z.object({
confirm: z.boolean().describe("確認刪除所有未完成的任務(此操作不可逆)"), confirm: z
.boolean()
.refine((val) => val === true, {
message:
"必須明確確認清除操作,請將 confirm 參數設置為 true 以確認此危險操作",
})
.describe("確認刪除所有未完成的任務(此操作不可逆)"),
}); });
export async function clearAllTasks({ export async function clearAllTasks({
@ -1212,46 +1277,93 @@ export async function clearAllTasks({
} }
// 更新任務內容工具 // 更新任務內容工具
export const updateTaskContentSchema = z.object({ export const updateTaskContentSchema = z
taskId: z .object({
.string() taskId: z
.describe("待更新任務的唯一標識符必須是系統中存在且未完成的任務ID"), .string()
name: z.string().optional().describe("任務的新名稱(選填)"), .uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
description: z.string().optional().describe("任務的新描述內容(選填)"), .describe("待更新任務的唯一標識符必須是系統中存在且未完成的任務ID"),
notes: z.string().optional().describe("任務的新補充說明(選填)"), name: z
relatedFiles: z .string()
.array( .min(5, {
z.object({ message: "任務名稱太短,請提供更清晰明確的名稱以便識別任務目的",
path: z
.string()
.describe("文件路徑,可以是相對於項目根目錄的路徑或絕對路徑"),
type: z
.enum([
RelatedFileType.TO_MODIFY,
RelatedFileType.REFERENCE,
RelatedFileType.OUTPUT,
RelatedFileType.DEPENDENCY,
RelatedFileType.OTHER,
])
.describe("文件與任務的關係類型"),
description: z.string().optional().describe("文件的補充描述(選填)"),
lineStart: z
.number()
.int()
.positive()
.optional()
.describe("相關代碼區塊的起始行(選填)"),
lineEnd: z
.number()
.int()
.positive()
.optional()
.describe("相關代碼區塊的結束行(選填)"),
}) })
) .max(100, { message: "任務名稱過長請保持簡潔不超過100個字符" })
.optional() .optional()
.describe("與任務相關的文件列表(選填)"), .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.OUTPUT,
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({ export async function updateTaskContent({
taskId, taskId,
@ -1385,42 +1497,86 @@ export async function updateTaskContent({
} }
// 更新任務相關文件工具 // 更新任務相關文件工具
export const updateTaskRelatedFilesSchema = z.object({ export const updateTaskRelatedFilesSchema = z
taskId: z .object({
.string() taskId: z
.describe("待更新任務的唯一標識符必須是系統中存在且未完成的任務ID"), .string()
relatedFiles: z .uuid({ message: "任務ID格式無效請提供有效的UUID格式" })
.array( .describe("待更新任務的唯一標識符必須是系統中存在且未完成的任務ID"),
z.object({ relatedFiles: z
path: z .array(
.string() z.object({
.describe("文件路徑,可以是相對於項目根目錄的路徑或絕對路徑"), path: z
type: z .string()
.enum([ .min(1, { message: "文件路徑不能為空,請提供有效的文件路徑" })
RelatedFileType.TO_MODIFY, .describe("文件路徑,可以是相對於項目根目錄的路徑或絕對路徑"),
RelatedFileType.REFERENCE, type: z
RelatedFileType.OUTPUT, .enum([
RelatedFileType.DEPENDENCY, RelatedFileType.TO_MODIFY,
RelatedFileType.OTHER, RelatedFileType.REFERENCE,
]) RelatedFileType.OUTPUT,
.describe("文件與任務的關係類型"), RelatedFileType.DEPENDENCY,
description: z.string().optional().describe("文件的補充描述(選填)"), RelatedFileType.OTHER,
lineStart: z ])
.number() .describe("文件與任務的關係類型"),
.int() description: z.string().optional().describe("文件的補充描述(選填)"),
.positive() lineStart: z
.optional() .number()
.describe("相關代碼區塊的起始行(選填)"), .int()
lineEnd: z .positive()
.number() .optional()
.int() .describe("相關代碼區塊的起始行(選填)"),
.positive() lineEnd: z
.optional() .number()
.describe("相關代碼區塊的結束行(選填)"), .int()
}) .positive()
) .optional()
.describe("與任務相關的文件列表"), .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({ export async function updateTaskRelatedFiles({
taskId, taskId,