@zzp123/mcp-zentao 1.12.0 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +49 -0
- package/dist/api/zentaoApi.d.ts +27 -2
- package/dist/api/zentaoApi.js +115 -23
- package/dist/index.js +135 -13
- package/dist/types/zentao.d.ts +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,55 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.14.0] - 2025-11-07
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **完整的用户需求(Requirement)支持** 🎯
|
|
12
|
+
- 扩展 Story API,统一支持软件需求(story)和用户需求(requirement)
|
|
13
|
+
- 所有现有 story 工具现已支持两种需求类型,自动识别
|
|
14
|
+
- 新增4个专用的 requirement 工具:
|
|
15
|
+
- `createRequirement`: 创建用户需求
|
|
16
|
+
- `getRequirementDetail`: 获取用户需求详情
|
|
17
|
+
- `changeRequirement`: 修改用户需求
|
|
18
|
+
- `deleteRequirement`: 删除用户需求
|
|
19
|
+
- `createStory` 工具新增 `type` 参数,可选择创建 story 或 requirement
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- **更新现有需求工具描述**
|
|
23
|
+
- `getStoryDetail`: 现支持 story 和 requirement 两种类型,自动识别
|
|
24
|
+
- `changeStory`: 现支持 story 和 requirement 两种类型,自动识别
|
|
25
|
+
- `deleteStory`: 现支持 story 和 requirement 两种类型,自动识别
|
|
26
|
+
- `getProductStories`: 返回的列表可能包含两种类型的需求
|
|
27
|
+
|
|
28
|
+
### Improved
|
|
29
|
+
- **更好的语义化**
|
|
30
|
+
- 专用的 requirement 工具提供更清晰的意图表达
|
|
31
|
+
- 统一接口底层实现,减少代码重复
|
|
32
|
+
- 符合禅道 API v2.0 的最新扩展
|
|
33
|
+
|
|
34
|
+
## [1.13.0] - 2025-11-07
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
- **产品和需求列表字段过滤功能** 📦
|
|
38
|
+
- 为 `getProducts` 添加 `fields` 参数支持
|
|
39
|
+
- 为 `getProductStories` 添加 `fields` 参数支持
|
|
40
|
+
- 支持三种字段级别:
|
|
41
|
+
- `basic`: 基本信息(产品:id, name, code, status;需求:id, title, assignedTo, openedBy)
|
|
42
|
+
- `default`: 默认信息(产品:包含 PO/QD/RD 等;需求:包含 status/stage/pri 等,**默认使用**)
|
|
43
|
+
- `full`: 完整信息(所有字段)
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
- **优化列表接口默认返回数据**
|
|
47
|
+
- 产品列表默认使用 `default` 字段级别,返回核心管理信息
|
|
48
|
+
- 需求列表默认使用 `basic` 字段级别,只返回最基本的4个字段
|
|
49
|
+
- 显著减少数据传输量,提升列表查询响应速度
|
|
50
|
+
|
|
51
|
+
### Improved
|
|
52
|
+
- **性能优化**
|
|
53
|
+
- 列表接口数据量大幅减少,特别适合快速浏览和搜索场景
|
|
54
|
+
- 减少不必要的字段传输,降低网络开销
|
|
55
|
+
- 需要详细信息时可按需设置 `fields='full'`
|
|
56
|
+
|
|
8
57
|
## [1.12.0] - 2025-11-07
|
|
9
58
|
|
|
10
59
|
### Added
|
package/dist/api/zentaoApi.d.ts
CHANGED
|
@@ -8,7 +8,24 @@ export declare class ZentaoAPI {
|
|
|
8
8
|
private request;
|
|
9
9
|
getMyTasks(status?: TaskStatus): Promise<Task[]>;
|
|
10
10
|
getTaskDetail(taskId: number): Promise<Task>;
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* 过滤产品字段
|
|
13
|
+
* @param product 原始产品对象
|
|
14
|
+
* @param fields 字段级别
|
|
15
|
+
*/
|
|
16
|
+
private filterProductFields;
|
|
17
|
+
/**
|
|
18
|
+
* 过滤需求字段
|
|
19
|
+
* @param story 原始需求对象
|
|
20
|
+
* @param fields 字段级别
|
|
21
|
+
*/
|
|
22
|
+
private filterStoryFields;
|
|
23
|
+
/**
|
|
24
|
+
* 获取产品列表
|
|
25
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'default')
|
|
26
|
+
* @returns Promise<产品列表>
|
|
27
|
+
*/
|
|
28
|
+
getProducts(fields?: 'basic' | 'default' | 'full'): Promise<Product[]>;
|
|
12
29
|
/**
|
|
13
30
|
* 过滤 Bug 字段
|
|
14
31
|
* @param bug 原始 Bug 对象
|
|
@@ -88,7 +105,15 @@ export declare class ZentaoAPI {
|
|
|
88
105
|
deleteTask(taskId: number): Promise<{
|
|
89
106
|
message: string;
|
|
90
107
|
}>;
|
|
91
|
-
|
|
108
|
+
/**
|
|
109
|
+
* 获取产品需求列表
|
|
110
|
+
* @param productId 产品ID
|
|
111
|
+
* @param page 页码(从1开始,默认1)
|
|
112
|
+
* @param limit 每页数量(默认20,最大100)
|
|
113
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'basic')
|
|
114
|
+
* @returns Promise<需求列表及分页信息>
|
|
115
|
+
*/
|
|
116
|
+
getProductStories(productId: number, page?: number, limit?: number, fields?: 'basic' | 'default' | 'full'): Promise<{
|
|
92
117
|
page: number;
|
|
93
118
|
total: number;
|
|
94
119
|
limit: number;
|
package/dist/api/zentaoApi.js
CHANGED
|
@@ -91,20 +91,95 @@ export class ZentaoAPI {
|
|
|
91
91
|
throw error;
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
|
-
|
|
94
|
+
/**
|
|
95
|
+
* 过滤产品字段
|
|
96
|
+
* @param product 原始产品对象
|
|
97
|
+
* @param fields 字段级别
|
|
98
|
+
*/
|
|
99
|
+
filterProductFields(product, fields) {
|
|
100
|
+
if (fields === 'full') {
|
|
101
|
+
return product;
|
|
102
|
+
}
|
|
103
|
+
if (fields === 'basic') {
|
|
104
|
+
// 基本信息:只返回核心字段
|
|
105
|
+
return {
|
|
106
|
+
id: product.id,
|
|
107
|
+
name: product.name,
|
|
108
|
+
code: product.code,
|
|
109
|
+
status: product.status
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// default: 默认字段(id, 名称, 状态, 负责人)
|
|
113
|
+
return {
|
|
114
|
+
id: product.id,
|
|
115
|
+
name: product.name,
|
|
116
|
+
code: product.code,
|
|
117
|
+
status: product.status,
|
|
118
|
+
type: product.type,
|
|
119
|
+
PO: product.PO,
|
|
120
|
+
QD: product.QD,
|
|
121
|
+
RD: product.RD,
|
|
122
|
+
createdBy: product.createdBy,
|
|
123
|
+
createdDate: product.createdDate
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* 过滤需求字段
|
|
128
|
+
* @param story 原始需求对象
|
|
129
|
+
* @param fields 字段级别
|
|
130
|
+
*/
|
|
131
|
+
filterStoryFields(story, fields) {
|
|
132
|
+
if (fields === 'full') {
|
|
133
|
+
return story;
|
|
134
|
+
}
|
|
135
|
+
if (fields === 'basic') {
|
|
136
|
+
// 基本信息:只返回核心字段
|
|
137
|
+
return {
|
|
138
|
+
id: story.id,
|
|
139
|
+
title: story.title,
|
|
140
|
+
assignedTo: story.assignedTo,
|
|
141
|
+
openedBy: story.openedBy
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
// default: 默认字段(id, 标题, 状态, 指派人, 创建人)
|
|
145
|
+
return {
|
|
146
|
+
id: story.id,
|
|
147
|
+
title: story.title,
|
|
148
|
+
status: story.status,
|
|
149
|
+
stage: story.stage,
|
|
150
|
+
pri: story.pri,
|
|
151
|
+
assignedTo: story.assignedTo,
|
|
152
|
+
openedBy: story.openedBy,
|
|
153
|
+
openedDate: story.openedDate,
|
|
154
|
+
estimate: story.estimate,
|
|
155
|
+
product: story.product,
|
|
156
|
+
plan: story.plan
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* 获取产品列表
|
|
161
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'default')
|
|
162
|
+
* @returns Promise<产品列表>
|
|
163
|
+
*/
|
|
164
|
+
async getProducts(fields) {
|
|
95
165
|
try {
|
|
96
|
-
|
|
166
|
+
const finalFields = fields || 'default';
|
|
167
|
+
console.log(`正在获取产品列表 (fields=${finalFields})...`);
|
|
97
168
|
const response = await this.request('GET', '/products');
|
|
98
169
|
console.log('产品列表响应:', response);
|
|
170
|
+
let products = [];
|
|
99
171
|
if (Array.isArray(response)) {
|
|
100
|
-
|
|
172
|
+
products = response;
|
|
101
173
|
}
|
|
102
|
-
else if (response && typeof response === 'object') {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
174
|
+
else if (response && typeof response === 'object' && Array.isArray(response.products)) {
|
|
175
|
+
products = response.products;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
throw new Error(`获取产品列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
106
179
|
}
|
|
107
|
-
|
|
180
|
+
// 应用字段过滤
|
|
181
|
+
const filteredProducts = products.map(product => this.filterProductFields(product, finalFields));
|
|
182
|
+
return filteredProducts;
|
|
108
183
|
}
|
|
109
184
|
catch (error) {
|
|
110
185
|
console.error('获取产品列表失败:', error);
|
|
@@ -746,38 +821,55 @@ export class ZentaoAPI {
|
|
|
746
821
|
throw error;
|
|
747
822
|
}
|
|
748
823
|
}
|
|
749
|
-
|
|
824
|
+
/**
|
|
825
|
+
* 获取产品需求列表
|
|
826
|
+
* @param productId 产品ID
|
|
827
|
+
* @param page 页码(从1开始,默认1)
|
|
828
|
+
* @param limit 每页数量(默认20,最大100)
|
|
829
|
+
* @param fields 返回字段级别('basic'基本/'default'默认/'full'完整,默认'basic')
|
|
830
|
+
* @returns Promise<需求列表及分页信息>
|
|
831
|
+
*/
|
|
832
|
+
async getProductStories(productId, page, limit, fields) {
|
|
750
833
|
try {
|
|
751
834
|
// 默认每页20条,最多100条
|
|
752
835
|
const finalLimit = limit ? Math.min(limit, 100) : 20;
|
|
753
836
|
const finalPage = page || 1;
|
|
754
|
-
|
|
837
|
+
const finalFields = fields || 'basic'; // 默认只返回基本字段
|
|
838
|
+
console.log(`正在获取产品 ${productId} 的需求列表 (page=${finalPage}, limit=${finalLimit}, fields=${finalFields})...`);
|
|
755
839
|
// 构建查询参数
|
|
756
840
|
const queryParams = new URLSearchParams();
|
|
757
841
|
queryParams.append('page', finalPage.toString());
|
|
758
842
|
queryParams.append('limit', finalLimit.toString());
|
|
759
843
|
const response = await this.request('GET', `/products/${productId}/stories?${queryParams.toString()}`);
|
|
760
844
|
console.log(`产品需求列表响应: 获取到 ${response.stories?.length || 0} 条数据`);
|
|
845
|
+
let stories = [];
|
|
846
|
+
if (Array.isArray(response)) {
|
|
847
|
+
stories = response;
|
|
848
|
+
}
|
|
849
|
+
else if (response && typeof response === 'object' && Array.isArray(response.stories)) {
|
|
850
|
+
stories = response.stories;
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
throw new Error(`获取产品需求列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
854
|
+
}
|
|
855
|
+
// 应用字段过滤
|
|
856
|
+
const filteredStories = stories.map(story => this.filterStoryFields(story, finalFields));
|
|
761
857
|
if (Array.isArray(response)) {
|
|
762
|
-
// 如果返回的是数组,转换为标准格式
|
|
763
858
|
return {
|
|
764
859
|
page: finalPage,
|
|
765
|
-
total:
|
|
860
|
+
total: filteredStories.length,
|
|
766
861
|
limit: finalLimit,
|
|
767
|
-
stories:
|
|
862
|
+
stories: filteredStories
|
|
768
863
|
};
|
|
769
864
|
}
|
|
770
|
-
else
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
};
|
|
778
|
-
}
|
|
865
|
+
else {
|
|
866
|
+
return {
|
|
867
|
+
page: response.page || finalPage,
|
|
868
|
+
total: response.total || filteredStories.length,
|
|
869
|
+
limit: response.limit || finalLimit,
|
|
870
|
+
stories: filteredStories
|
|
871
|
+
};
|
|
779
872
|
}
|
|
780
|
-
throw new Error(`获取产品需求列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
781
873
|
}
|
|
782
874
|
catch (error) {
|
|
783
875
|
console.error('获取产品需求列表失败:', error);
|
package/dist/index.js
CHANGED
|
@@ -78,10 +78,12 @@ server.tool("getTaskDetail", {
|
|
|
78
78
|
};
|
|
79
79
|
});
|
|
80
80
|
// Add getProducts tool
|
|
81
|
-
server.tool("getProducts",
|
|
81
|
+
server.tool("getProducts", "获取产品列表 - 只返回核心字段(id, 名称, 负责人)", {
|
|
82
|
+
fields: z.enum(['basic', 'default', 'full']).optional().describe("返回字段级别:'basic'(id/名称/状态)、'default'(+负责人/创建人,默认)、'full'(完整字段)")
|
|
83
|
+
}, async ({ fields }) => {
|
|
82
84
|
if (!zentaoApi)
|
|
83
85
|
throw new Error("Please initialize Zentao API first");
|
|
84
|
-
const products = await zentaoApi.getProducts();
|
|
86
|
+
const products = await zentaoApi.getProducts(fields);
|
|
85
87
|
return {
|
|
86
88
|
content: [{ type: "text", text: JSON.stringify(products, null, 2) }]
|
|
87
89
|
};
|
|
@@ -333,10 +335,11 @@ server.tool("createTask", {
|
|
|
333
335
|
};
|
|
334
336
|
});
|
|
335
337
|
// Add createStory tool
|
|
336
|
-
server.tool("createStory", {
|
|
338
|
+
server.tool("createStory", "创建需求 - 支持创建软件需求(story)或用户需求(requirement)", {
|
|
337
339
|
title: z.string(),
|
|
338
340
|
product: z.number(),
|
|
339
341
|
pri: z.number(),
|
|
342
|
+
type: z.enum(['story', 'requirement']).optional().describe("需求类型:story=软件需求,requirement=用户需求,默认为story"),
|
|
340
343
|
category: z.string().optional(),
|
|
341
344
|
spec: z.string().optional(),
|
|
342
345
|
verify: z.string().optional(),
|
|
@@ -344,13 +347,14 @@ server.tool("createStory", {
|
|
|
344
347
|
sourceNote: z.string().optional(),
|
|
345
348
|
estimate: z.number().optional(),
|
|
346
349
|
keywords: z.string().optional()
|
|
347
|
-
}, async ({ title, product, pri, category, spec, verify, source, sourceNote, estimate, keywords }) => {
|
|
350
|
+
}, async ({ title, product, pri, type, category, spec, verify, source, sourceNote, estimate, keywords }) => {
|
|
348
351
|
if (!zentaoApi)
|
|
349
352
|
throw new Error("Please initialize Zentao API first");
|
|
350
353
|
const story = await zentaoApi.createStory({
|
|
351
354
|
title,
|
|
352
355
|
product,
|
|
353
356
|
pri,
|
|
357
|
+
type,
|
|
354
358
|
category,
|
|
355
359
|
spec,
|
|
356
360
|
verify,
|
|
@@ -463,8 +467,8 @@ server.tool("getProjectReleases", {
|
|
|
463
467
|
};
|
|
464
468
|
});
|
|
465
469
|
// Add getStoryDetail tool
|
|
466
|
-
server.tool("getStoryDetail", {
|
|
467
|
-
storyId: z.number(),
|
|
470
|
+
server.tool("getStoryDetail", "获取需求详情 - 支持软件需求(story)和用户需求(requirement),自动识别类型", {
|
|
471
|
+
storyId: z.number().describe("需求ID(可以是story或requirement类型)"),
|
|
468
472
|
fields: z.enum(['basic', 'detail', 'full']).optional().describe(`
|
|
469
473
|
字段级别:
|
|
470
474
|
- basic: 基本信息(id, title, status, stage, pri等核心字段)
|
|
@@ -583,8 +587,8 @@ server.tool("getProjects", {
|
|
|
583
587
|
};
|
|
584
588
|
});
|
|
585
589
|
// Add changeStory tool
|
|
586
|
-
server.tool("changeStory", "需求变更 -
|
|
587
|
-
storyId: z.number().describe("需求ID"),
|
|
590
|
+
server.tool("changeStory", "需求变更 - 支持软件需求(story)和用户需求(requirement),自动识别类型。支持对象或JSON字符串格式", {
|
|
591
|
+
storyId: z.number().describe("需求ID(可以是story或requirement类型)"),
|
|
588
592
|
update: z.union([
|
|
589
593
|
z.object({
|
|
590
594
|
// 基本信息
|
|
@@ -669,14 +673,15 @@ server.tool("deleteTask", {
|
|
|
669
673
|
};
|
|
670
674
|
});
|
|
671
675
|
// Add getProductStories tool
|
|
672
|
-
server.tool("getProductStories", {
|
|
676
|
+
server.tool("getProductStories", "获取产品需求列表 - 包含软件需求(story)和用户需求(requirement),默认只返回核心字段(id, 标题, 指派人, 创建人)", {
|
|
673
677
|
productId: z.number(),
|
|
674
678
|
page: z.number().optional().describe("页码,从1开始,默认为1"),
|
|
675
|
-
limit: z.number().optional().describe("每页数量,默认20,最大100")
|
|
676
|
-
|
|
679
|
+
limit: z.number().optional().describe("每页数量,默认20,最大100"),
|
|
680
|
+
fields: z.enum(['basic', 'default', 'full']).optional().describe("字段级别:\n- basic: 基本信息(id, title, assignedTo, openedBy)\n- default: 常用信息(包含basic + status, stage, pri等)\n- full: 完整信息(所有字段)")
|
|
681
|
+
}, async ({ productId, page, limit, fields }) => {
|
|
677
682
|
if (!zentaoApi)
|
|
678
683
|
throw new Error("Please initialize Zentao API first");
|
|
679
|
-
const result = await zentaoApi.getProductStories(productId, page, limit);
|
|
684
|
+
const result = await zentaoApi.getProductStories(productId, page, limit, fields);
|
|
680
685
|
// 返回分页信息和数据
|
|
681
686
|
const summary = {
|
|
682
687
|
summary: `当前第 ${result.page} 页,共 ${result.total} 条需求,本页显示 ${result.stories.length} 条`,
|
|
@@ -828,11 +833,128 @@ server.tool("deleteExecution", { executionId: z.number() }, async ({ executionId
|
|
|
828
833
|
return { content: [{ type: "text", text: JSON.stringify(await zentaoApi.deleteExecution(executionId), null, 2) }] };
|
|
829
834
|
});
|
|
830
835
|
// Story tools
|
|
831
|
-
server.tool("deleteStory",
|
|
836
|
+
server.tool("deleteStory", "删除需求 - 支持软件需求(story)和用户需求(requirement),自动识别类型", {
|
|
837
|
+
storyId: z.number().describe("需求ID(可以是story或requirement类型)")
|
|
838
|
+
}, async ({ storyId }) => {
|
|
832
839
|
if (!zentaoApi)
|
|
833
840
|
throw new Error("Please initialize Zentao API first");
|
|
834
841
|
return { content: [{ type: "text", text: JSON.stringify(await zentaoApi.deleteStory(storyId), null, 2) }] };
|
|
835
842
|
});
|
|
843
|
+
// Requirement tools (用户需求专用工具 - 提供更好的语义化)
|
|
844
|
+
server.tool("createRequirement", "创建用户需求(requirement) - 用户需求的专用接口,提供更好的语义化", {
|
|
845
|
+
title: z.string(),
|
|
846
|
+
product: z.number(),
|
|
847
|
+
pri: z.number(),
|
|
848
|
+
category: z.string().optional(),
|
|
849
|
+
spec: z.string().optional(),
|
|
850
|
+
verify: z.string().optional(),
|
|
851
|
+
source: z.string().optional(),
|
|
852
|
+
sourceNote: z.string().optional(),
|
|
853
|
+
estimate: z.number().optional(),
|
|
854
|
+
keywords: z.string().optional()
|
|
855
|
+
}, async ({ title, product, pri, category, spec, verify, source, sourceNote, estimate, keywords }) => {
|
|
856
|
+
if (!zentaoApi)
|
|
857
|
+
throw new Error("Please initialize Zentao API first");
|
|
858
|
+
// 调用 createStory 但强制设置 type='requirement'
|
|
859
|
+
const requirement = await zentaoApi.createStory({
|
|
860
|
+
title,
|
|
861
|
+
product,
|
|
862
|
+
pri,
|
|
863
|
+
type: 'requirement',
|
|
864
|
+
category,
|
|
865
|
+
spec,
|
|
866
|
+
verify,
|
|
867
|
+
source,
|
|
868
|
+
sourceNote,
|
|
869
|
+
estimate,
|
|
870
|
+
keywords
|
|
871
|
+
});
|
|
872
|
+
return {
|
|
873
|
+
content: [{ type: "text", text: JSON.stringify(requirement, null, 2) }]
|
|
874
|
+
};
|
|
875
|
+
});
|
|
876
|
+
server.tool("getRequirementDetail", "获取用户需求详情 - 用户需求的专用接口,提供更好的语义化", {
|
|
877
|
+
requirementId: z.number().describe("用户需求ID"),
|
|
878
|
+
fields: z.enum(['basic', 'detail', 'full']).optional().describe(`
|
|
879
|
+
字段级别:
|
|
880
|
+
- basic: 基本信息(id, title, status, stage, pri等核心字段)
|
|
881
|
+
- detail: 详细信息(包含spec和verify,但不包含executions/tasks/stages/children等关联数据)
|
|
882
|
+
- full: 完整信息(包含所有字段,默认值)
|
|
883
|
+
`.trim())
|
|
884
|
+
}, async ({ requirementId, fields }) => {
|
|
885
|
+
if (!zentaoApi)
|
|
886
|
+
throw new Error("Please initialize Zentao API first");
|
|
887
|
+
const requirement = await zentaoApi.getStoryDetail(requirementId, fields);
|
|
888
|
+
const result = {
|
|
889
|
+
fieldLevel: fields || 'full',
|
|
890
|
+
requirement: requirement
|
|
891
|
+
};
|
|
892
|
+
if (fields === 'basic') {
|
|
893
|
+
result.note = '仅显示基本信息,如需完整内容请使用 fields=detail 或 fields=full';
|
|
894
|
+
}
|
|
895
|
+
else if (fields === 'detail') {
|
|
896
|
+
result.note = '显示详细信息但不包含关联数据(executions/tasks/stages/children),如需完整内容请使用 fields=full';
|
|
897
|
+
}
|
|
898
|
+
return {
|
|
899
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
900
|
+
};
|
|
901
|
+
});
|
|
902
|
+
server.tool("changeRequirement", "用户需求变更 - 用户需求的专用接口,提供更好的语义化", {
|
|
903
|
+
requirementId: z.number().describe("用户需求ID"),
|
|
904
|
+
update: z.union([
|
|
905
|
+
z.object({
|
|
906
|
+
title: z.string().optional(),
|
|
907
|
+
product: z.number().optional(),
|
|
908
|
+
parent: z.number().optional(),
|
|
909
|
+
module: z.number().optional(),
|
|
910
|
+
pri: z.number().optional(),
|
|
911
|
+
category: z.string().optional(),
|
|
912
|
+
spec: z.string().optional(),
|
|
913
|
+
verify: z.string().optional(),
|
|
914
|
+
source: z.string().optional(),
|
|
915
|
+
sourceNote: z.string().optional(),
|
|
916
|
+
estimate: z.number().optional(),
|
|
917
|
+
keywords: z.string().optional(),
|
|
918
|
+
assignedTo: z.string().optional(),
|
|
919
|
+
reviewer: z.array(z.string()).optional(),
|
|
920
|
+
comment: z.string().optional()
|
|
921
|
+
}),
|
|
922
|
+
z.string().describe("JSON字符串格式的更新内容")
|
|
923
|
+
]).describe(`
|
|
924
|
+
更新用户需求(使用 PUT /stories/:id 接口)
|
|
925
|
+
|
|
926
|
+
此工具使用标准的"修改需求其他字段"接口(PUT /stories/:id),支持修改多个字段。
|
|
927
|
+
自动处理评审人问题,无需手动设置 needNotReview。
|
|
928
|
+
|
|
929
|
+
支持对象或JSON字符串格式。
|
|
930
|
+
`.trim())
|
|
931
|
+
}, async ({ requirementId, update }) => {
|
|
932
|
+
if (!zentaoApi)
|
|
933
|
+
throw new Error("Please initialize Zentao API first");
|
|
934
|
+
let updateData;
|
|
935
|
+
if (typeof update === 'string') {
|
|
936
|
+
try {
|
|
937
|
+
updateData = JSON.parse(update);
|
|
938
|
+
}
|
|
939
|
+
catch (e) {
|
|
940
|
+
throw new Error('Invalid JSON string for update parameter');
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
else {
|
|
944
|
+
updateData = update;
|
|
945
|
+
}
|
|
946
|
+
const requirement = await zentaoApi.changeStory(requirementId, updateData);
|
|
947
|
+
return {
|
|
948
|
+
content: [{ type: "text", text: JSON.stringify(requirement, null, 2) }]
|
|
949
|
+
};
|
|
950
|
+
});
|
|
951
|
+
server.tool("deleteRequirement", "删除用户需求 - 用户需求的专用接口,提供更好的语义化", {
|
|
952
|
+
requirementId: z.number().describe("用户需求ID")
|
|
953
|
+
}, async ({ requirementId }) => {
|
|
954
|
+
if (!zentaoApi)
|
|
955
|
+
throw new Error("Please initialize Zentao API first");
|
|
956
|
+
return { content: [{ type: "text", text: JSON.stringify(await zentaoApi.deleteStory(requirementId), null, 2) }] };
|
|
957
|
+
});
|
|
836
958
|
// Bug tools
|
|
837
959
|
server.tool("updateBug", {
|
|
838
960
|
bugId: z.number(),
|
package/dist/types/zentao.d.ts
CHANGED