@zzp123/mcp-zentao 1.8.0 → 1.8.2
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/dist/api/zentaoApi.d.ts +30 -4
- package/dist/api/zentaoApi.js +161 -21
- package/dist/index.js +118 -25
- package/dist/services/bugService.js +2 -2
- package/package.json +1 -1
package/dist/api/zentaoApi.d.ts
CHANGED
|
@@ -9,8 +9,19 @@ export declare class ZentaoAPI {
|
|
|
9
9
|
getMyTasks(status?: TaskStatus): Promise<Task[]>;
|
|
10
10
|
getTaskDetail(taskId: number): Promise<Task>;
|
|
11
11
|
getProducts(): Promise<Product[]>;
|
|
12
|
-
getMyBugs(status?: BugStatus, productId?: number): Promise<
|
|
13
|
-
|
|
12
|
+
getMyBugs(status?: BugStatus, productId?: number, page?: number, limit?: number): Promise<{
|
|
13
|
+
page: number;
|
|
14
|
+
total: number;
|
|
15
|
+
limit: number;
|
|
16
|
+
bugs: Bug[];
|
|
17
|
+
}>;
|
|
18
|
+
getProductBugs(productId: number, page?: number, limit?: number, status?: BugStatus): Promise<{
|
|
19
|
+
page: number;
|
|
20
|
+
total: number;
|
|
21
|
+
limit: number;
|
|
22
|
+
bugs: Bug[];
|
|
23
|
+
}>;
|
|
24
|
+
getBugDetail(bugId: number, fields?: 'basic' | 'detail' | 'full'): Promise<any>;
|
|
14
25
|
resolveBug(bugId: number, resolution: ResolveBugRequest): Promise<Bug>;
|
|
15
26
|
updateTask(taskId: number, update: TaskUpdate): Promise<Task>;
|
|
16
27
|
finishTask(taskId: number, update?: TaskUpdate): Promise<Task>;
|
|
@@ -28,16 +39,31 @@ export declare class ZentaoAPI {
|
|
|
28
39
|
linkBugsToPlan(planId: number, bugIds: number[]): Promise<Plan>;
|
|
29
40
|
unlinkBugsFromPlan(planId: number, bugIds: number[]): Promise<Plan>;
|
|
30
41
|
getProjectReleases(projectId: number): Promise<Release[]>;
|
|
31
|
-
getStoryDetail(storyId: number): Promise<
|
|
42
|
+
getStoryDetail(storyId: number, fields?: 'basic' | 'detail' | 'full'): Promise<any>;
|
|
32
43
|
createBug(productId: number, bug: CreateBugRequest): Promise<Bug>;
|
|
33
44
|
getProjectExecutions(projectId: number): Promise<Execution[]>;
|
|
34
45
|
createPlan(productId: number, plan: CreatePlanRequest): Promise<Plan>;
|
|
35
46
|
getProjects(page?: number, limit?: number): Promise<Project[]>;
|
|
47
|
+
/**
|
|
48
|
+
* 修改需求(使用最新的 PUT /stories/:id 接口)
|
|
49
|
+
*
|
|
50
|
+
* 注意:此方法使用"修改需求其他字段"接口(PUT),支持修改29个字段
|
|
51
|
+
* 已废弃:旧的"变更需求"接口(POST /stories/:id/change)仅支持3个字段
|
|
52
|
+
*
|
|
53
|
+
* @param storyId 需求ID
|
|
54
|
+
* @param update 需要更新的字段
|
|
55
|
+
* @returns 更新后的需求信息
|
|
56
|
+
*/
|
|
36
57
|
changeStory(storyId: number, update: ChangeStoryRequest): Promise<Story>;
|
|
37
58
|
deleteTask(taskId: number): Promise<{
|
|
38
59
|
message: string;
|
|
39
60
|
}>;
|
|
40
|
-
getProductStories(productId: number): Promise<
|
|
61
|
+
getProductStories(productId: number, page?: number, limit?: number): Promise<{
|
|
62
|
+
page: number;
|
|
63
|
+
total: number;
|
|
64
|
+
limit: number;
|
|
65
|
+
stories: Story[];
|
|
66
|
+
}>;
|
|
41
67
|
getProgramDetail(programId: number): Promise<Program>;
|
|
42
68
|
createProgram(program: CreateProgramRequest): Promise<Program>;
|
|
43
69
|
updateProgram(programId: number, update: UpdateProgramRequest): Promise<Program>;
|
package/dist/api/zentaoApi.js
CHANGED
|
@@ -111,7 +111,7 @@ export class ZentaoAPI {
|
|
|
111
111
|
throw error;
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
|
-
async getMyBugs(status, productId) {
|
|
114
|
+
async getMyBugs(status, productId, page, limit) {
|
|
115
115
|
if (!productId) {
|
|
116
116
|
// 如果没有提供产品ID,获取第一个可用的产品
|
|
117
117
|
const products = await this.getProducts();
|
|
@@ -121,20 +121,36 @@ export class ZentaoAPI {
|
|
|
121
121
|
productId = products[0].id;
|
|
122
122
|
console.log(`使用第一个可用的产品ID: ${productId}`);
|
|
123
123
|
}
|
|
124
|
+
// 默认每页20条,最多100条
|
|
125
|
+
const finalLimit = limit ? Math.min(limit, 100) : 20;
|
|
126
|
+
const finalPage = page || 1;
|
|
124
127
|
const params = {
|
|
125
128
|
assignedTo: this.config.username,
|
|
126
129
|
status: status || 'all',
|
|
127
|
-
product: productId
|
|
130
|
+
product: productId,
|
|
131
|
+
page: finalPage,
|
|
132
|
+
limit: finalLimit
|
|
128
133
|
};
|
|
129
134
|
try {
|
|
130
|
-
console.log(
|
|
135
|
+
console.log(`正在获取Bug列表 (page=${finalPage}, limit=${finalLimit}),参数:`, params);
|
|
131
136
|
const response = await this.request('GET', '/bugs', params);
|
|
132
|
-
console.log(
|
|
137
|
+
console.log(`Bug列表响应: 获取到 ${response.bugs?.length || 0} 条数据`);
|
|
133
138
|
if (Array.isArray(response)) {
|
|
134
|
-
|
|
139
|
+
// 如果返回的是数组,转换为标准格式
|
|
140
|
+
return {
|
|
141
|
+
page: finalPage,
|
|
142
|
+
total: response.length,
|
|
143
|
+
limit: finalLimit,
|
|
144
|
+
bugs: response
|
|
145
|
+
};
|
|
135
146
|
}
|
|
136
147
|
else if (response && typeof response === 'object' && Array.isArray(response.bugs)) {
|
|
137
|
-
return
|
|
148
|
+
return {
|
|
149
|
+
page: response.page || finalPage,
|
|
150
|
+
total: response.total || response.bugs.length,
|
|
151
|
+
limit: response.limit || finalLimit,
|
|
152
|
+
bugs: response.bugs
|
|
153
|
+
};
|
|
138
154
|
}
|
|
139
155
|
throw new Error(`获取Bug列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
140
156
|
}
|
|
@@ -146,12 +162,80 @@ export class ZentaoAPI {
|
|
|
146
162
|
throw error;
|
|
147
163
|
}
|
|
148
164
|
}
|
|
149
|
-
async
|
|
165
|
+
async getProductBugs(productId, page, limit, status) {
|
|
166
|
+
try {
|
|
167
|
+
// 默认每页20条,最多100条
|
|
168
|
+
const finalLimit = limit ? Math.min(limit, 100) : 20;
|
|
169
|
+
const finalPage = page || 1;
|
|
170
|
+
console.log(`正在获取产品 ${productId} 的Bug列表 (page=${finalPage}, limit=${finalLimit})...`);
|
|
171
|
+
// 构建查询参数
|
|
172
|
+
const queryParams = new URLSearchParams();
|
|
173
|
+
queryParams.append('page', finalPage.toString());
|
|
174
|
+
queryParams.append('limit', finalLimit.toString());
|
|
175
|
+
if (status && status !== 'all') {
|
|
176
|
+
queryParams.append('status', status);
|
|
177
|
+
}
|
|
178
|
+
const response = await this.request('GET', `/products/${productId}/bugs?${queryParams.toString()}`);
|
|
179
|
+
console.log(`产品Bug列表响应: 获取到 ${response.bugs?.length || 0} 条数据`);
|
|
180
|
+
if (Array.isArray(response)) {
|
|
181
|
+
// 如果返回的是数组,转换为标准格式
|
|
182
|
+
return {
|
|
183
|
+
page: finalPage,
|
|
184
|
+
total: response.length,
|
|
185
|
+
limit: finalLimit,
|
|
186
|
+
bugs: response
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
else if (response && typeof response === 'object') {
|
|
190
|
+
if (Array.isArray(response.bugs)) {
|
|
191
|
+
return {
|
|
192
|
+
page: response.page || finalPage,
|
|
193
|
+
total: response.total || response.bugs.length,
|
|
194
|
+
limit: response.limit || finalLimit,
|
|
195
|
+
bugs: response.bugs
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
throw new Error(`获取产品Bug列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
console.error('获取产品Bug列表失败:', error);
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
async getBugDetail(bugId, fields) {
|
|
150
207
|
try {
|
|
151
|
-
console.log(`正在获取Bug ${bugId}
|
|
208
|
+
console.log(`正在获取Bug ${bugId} 的详情 (fields=${fields || 'full'})...`);
|
|
152
209
|
const response = await this.request('GET', `/bugs/${bugId}`);
|
|
153
210
|
console.log('Bug详情响应:', response);
|
|
154
|
-
|
|
211
|
+
// 根据 fields 参数过滤返回的字段
|
|
212
|
+
const fieldLevel = fields || 'full';
|
|
213
|
+
if (fieldLevel === 'basic') {
|
|
214
|
+
// 基本信息:只返回核心字段
|
|
215
|
+
return {
|
|
216
|
+
id: response.id,
|
|
217
|
+
title: response.title,
|
|
218
|
+
product: response.product,
|
|
219
|
+
module: response.module,
|
|
220
|
+
status: response.status,
|
|
221
|
+
severity: response.severity,
|
|
222
|
+
pri: response.pri,
|
|
223
|
+
type: response.type,
|
|
224
|
+
assignedTo: response.assignedTo,
|
|
225
|
+
openedBy: response.openedBy,
|
|
226
|
+
openedDate: response.openedDate,
|
|
227
|
+
deadline: response.deadline
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
else if (fieldLevel === 'detail') {
|
|
231
|
+
// 详细信息:包含步骤描述,但排除不常用字段
|
|
232
|
+
const { files, cases, linkBugs, ...detailData } = response;
|
|
233
|
+
return detailData;
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
// 完整信息:返回所有字段
|
|
237
|
+
return response;
|
|
238
|
+
}
|
|
155
239
|
}
|
|
156
240
|
catch (error) {
|
|
157
241
|
console.error('获取Bug详情失败:', error);
|
|
@@ -414,12 +498,39 @@ export class ZentaoAPI {
|
|
|
414
498
|
throw error;
|
|
415
499
|
}
|
|
416
500
|
}
|
|
417
|
-
async getStoryDetail(storyId) {
|
|
501
|
+
async getStoryDetail(storyId, fields) {
|
|
418
502
|
try {
|
|
419
|
-
console.log(`正在获取需求 ${storyId}
|
|
503
|
+
console.log(`正在获取需求 ${storyId} 的详情 (fields=${fields || 'full'})...`);
|
|
420
504
|
const response = await this.request('GET', `/stories/${storyId}`);
|
|
421
505
|
console.log('需求详情响应:', response);
|
|
422
|
-
|
|
506
|
+
// 根据 fields 参数过滤返回的字段
|
|
507
|
+
const fieldLevel = fields || 'full';
|
|
508
|
+
if (fieldLevel === 'basic') {
|
|
509
|
+
// 基本信息:只返回核心字段
|
|
510
|
+
return {
|
|
511
|
+
id: response.id,
|
|
512
|
+
title: response.title,
|
|
513
|
+
product: response.product,
|
|
514
|
+
module: response.module,
|
|
515
|
+
status: response.status,
|
|
516
|
+
stage: response.stage,
|
|
517
|
+
pri: response.pri,
|
|
518
|
+
category: response.category,
|
|
519
|
+
estimate: response.estimate,
|
|
520
|
+
assignedTo: response.assignedTo,
|
|
521
|
+
openedBy: response.openedBy,
|
|
522
|
+
openedDate: response.openedDate
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
else if (fieldLevel === 'detail') {
|
|
526
|
+
// 详细信息:包含描述和验收标准,但不包含关联数据
|
|
527
|
+
const { executions, tasks, stages, children, ...detailData } = response;
|
|
528
|
+
return detailData;
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
// 完整信息:返回所有字段
|
|
532
|
+
return response;
|
|
533
|
+
}
|
|
423
534
|
}
|
|
424
535
|
catch (error) {
|
|
425
536
|
console.error('获取需求详情失败:', error);
|
|
@@ -495,9 +606,19 @@ export class ZentaoAPI {
|
|
|
495
606
|
throw error;
|
|
496
607
|
}
|
|
497
608
|
}
|
|
609
|
+
/**
|
|
610
|
+
* 修改需求(使用最新的 PUT /stories/:id 接口)
|
|
611
|
+
*
|
|
612
|
+
* 注意:此方法使用"修改需求其他字段"接口(PUT),支持修改29个字段
|
|
613
|
+
* 已废弃:旧的"变更需求"接口(POST /stories/:id/change)仅支持3个字段
|
|
614
|
+
*
|
|
615
|
+
* @param storyId 需求ID
|
|
616
|
+
* @param update 需要更新的字段
|
|
617
|
+
* @returns 更新后的需求信息
|
|
618
|
+
*/
|
|
498
619
|
async changeStory(storyId, update) {
|
|
499
620
|
try {
|
|
500
|
-
console.log(
|
|
621
|
+
console.log(`正在修改需求 ${storyId} (使用 PUT 接口)...`);
|
|
501
622
|
// 自动处理评审人问题
|
|
502
623
|
const updateData = { ...update };
|
|
503
624
|
// 如果用户没有设置评审人,也没有指定无需评审,则自动跳过评审
|
|
@@ -505,12 +626,13 @@ export class ZentaoAPI {
|
|
|
505
626
|
updateData.needNotReview = true;
|
|
506
627
|
console.log('自动设置needNotReview=true以跳过评审要求');
|
|
507
628
|
}
|
|
629
|
+
// 使用 PUT /stories/:id 接口(功能完整的"修改需求其他字段"接口)
|
|
508
630
|
const response = await this.request('PUT', `/stories/${storyId}`, undefined, updateData);
|
|
509
|
-
console.log('
|
|
631
|
+
console.log('修改需求响应:', response);
|
|
510
632
|
return response;
|
|
511
633
|
}
|
|
512
634
|
catch (error) {
|
|
513
|
-
console.error('
|
|
635
|
+
console.error('修改需求失败:', error);
|
|
514
636
|
throw error;
|
|
515
637
|
}
|
|
516
638
|
}
|
|
@@ -526,17 +648,35 @@ export class ZentaoAPI {
|
|
|
526
648
|
throw error;
|
|
527
649
|
}
|
|
528
650
|
}
|
|
529
|
-
async getProductStories(productId) {
|
|
651
|
+
async getProductStories(productId, page, limit) {
|
|
530
652
|
try {
|
|
531
|
-
|
|
532
|
-
const
|
|
533
|
-
|
|
653
|
+
// 默认每页20条,最多100条
|
|
654
|
+
const finalLimit = limit ? Math.min(limit, 100) : 20;
|
|
655
|
+
const finalPage = page || 1;
|
|
656
|
+
console.log(`正在获取产品 ${productId} 的需求列表 (page=${finalPage}, limit=${finalLimit})...`);
|
|
657
|
+
// 构建查询参数
|
|
658
|
+
const queryParams = new URLSearchParams();
|
|
659
|
+
queryParams.append('page', finalPage.toString());
|
|
660
|
+
queryParams.append('limit', finalLimit.toString());
|
|
661
|
+
const response = await this.request('GET', `/products/${productId}/stories?${queryParams.toString()}`);
|
|
662
|
+
console.log(`产品需求列表响应: 获取到 ${response.stories?.length || 0} 条数据`);
|
|
534
663
|
if (Array.isArray(response)) {
|
|
535
|
-
|
|
664
|
+
// 如果返回的是数组,转换为标准格式
|
|
665
|
+
return {
|
|
666
|
+
page: finalPage,
|
|
667
|
+
total: response.length,
|
|
668
|
+
limit: finalLimit,
|
|
669
|
+
stories: response
|
|
670
|
+
};
|
|
536
671
|
}
|
|
537
672
|
else if (response && typeof response === 'object') {
|
|
538
673
|
if (Array.isArray(response.stories)) {
|
|
539
|
-
return
|
|
674
|
+
return {
|
|
675
|
+
page: response.page || finalPage,
|
|
676
|
+
total: response.total || response.stories.length,
|
|
677
|
+
limit: response.limit || finalLimit,
|
|
678
|
+
stories: response.stories
|
|
679
|
+
};
|
|
540
680
|
}
|
|
541
681
|
}
|
|
542
682
|
throw new Error(`获取产品需求列表失败: 响应格式不正确 ${JSON.stringify(response)}`);
|
package/dist/index.js
CHANGED
|
@@ -89,24 +89,80 @@ server.tool("getProducts", {}, async () => {
|
|
|
89
89
|
// Add getMyBugs tool
|
|
90
90
|
server.tool("getMyBugs", {
|
|
91
91
|
status: z.enum(['active', 'resolved', 'closed', 'all']).optional(),
|
|
92
|
-
productId: z.number().optional()
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
productId: z.number().optional(),
|
|
93
|
+
page: z.number().optional().describe("页码,从1开始,默认为1"),
|
|
94
|
+
limit: z.number().optional().describe("每页数量,默认20,最大100")
|
|
95
|
+
}, async ({ status, productId, page, limit }) => {
|
|
96
|
+
if (!zentaoApi)
|
|
97
|
+
throw new Error("Please initialize Zentao API first");
|
|
98
|
+
const result = await zentaoApi.getMyBugs(status, productId, page, limit);
|
|
99
|
+
// 返回分页信息和数据
|
|
100
|
+
const summary = {
|
|
101
|
+
summary: `当前第 ${result.page} 页,共 ${result.total} 个Bug,本页显示 ${result.bugs.length} 个`,
|
|
102
|
+
pagination: {
|
|
103
|
+
page: result.page,
|
|
104
|
+
limit: result.limit,
|
|
105
|
+
total: result.total,
|
|
106
|
+
totalPages: Math.ceil(result.total / result.limit)
|
|
107
|
+
},
|
|
108
|
+
bugs: result.bugs
|
|
109
|
+
};
|
|
110
|
+
return {
|
|
111
|
+
content: [{ type: "text", text: JSON.stringify(summary, null, 2) }]
|
|
112
|
+
};
|
|
113
|
+
});
|
|
114
|
+
// Add getProductBugs tool
|
|
115
|
+
server.tool("getProductBugs", {
|
|
116
|
+
productId: z.number(),
|
|
117
|
+
page: z.number().optional().describe("页码,从1开始,默认为1"),
|
|
118
|
+
limit: z.number().optional().describe("每页数量,默认20,最大100"),
|
|
119
|
+
status: z.enum(['active', 'resolved', 'closed', 'all']).optional()
|
|
120
|
+
}, async ({ productId, page, limit, status }) => {
|
|
121
|
+
if (!zentaoApi)
|
|
122
|
+
throw new Error("Please initialize Zentao API first");
|
|
123
|
+
const result = await zentaoApi.getProductBugs(productId, page, limit, status);
|
|
124
|
+
// 返回分页信息和数据
|
|
125
|
+
const summary = {
|
|
126
|
+
summary: `当前第 ${result.page} 页,共 ${result.total} 个Bug,本页显示 ${result.bugs.length} 个`,
|
|
127
|
+
pagination: {
|
|
128
|
+
page: result.page,
|
|
129
|
+
limit: result.limit,
|
|
130
|
+
total: result.total,
|
|
131
|
+
totalPages: Math.ceil(result.total / result.limit)
|
|
132
|
+
},
|
|
133
|
+
bugs: result.bugs
|
|
134
|
+
};
|
|
97
135
|
return {
|
|
98
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
136
|
+
content: [{ type: "text", text: JSON.stringify(summary, null, 2) }]
|
|
99
137
|
};
|
|
100
138
|
});
|
|
101
139
|
// Add getBugDetail tool
|
|
102
140
|
server.tool("getBugDetail", {
|
|
103
|
-
bugId: z.number()
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
141
|
+
bugId: z.number(),
|
|
142
|
+
fields: z.enum(['basic', 'detail', 'full']).optional().describe(`
|
|
143
|
+
字段级别:
|
|
144
|
+
- basic: 基本信息(id, title, status, severity, pri等核心字段)
|
|
145
|
+
- detail: 详细信息(包含steps步骤,但不包含files/cases/linkBugs等关联数据)
|
|
146
|
+
- full: 完整信息(包含所有字段,默认值)
|
|
147
|
+
`.trim())
|
|
148
|
+
}, async ({ bugId, fields }) => {
|
|
149
|
+
if (!zentaoApi)
|
|
150
|
+
throw new Error("Please initialize Zentao API first");
|
|
151
|
+
const bug = await zentaoApi.getBugDetail(bugId, fields);
|
|
152
|
+
// 添加说明信息
|
|
153
|
+
const result = {
|
|
154
|
+
fieldLevel: fields || 'full',
|
|
155
|
+
bug: bug
|
|
156
|
+
};
|
|
157
|
+
// 根据字段级别添加提示
|
|
158
|
+
if (fields === 'basic') {
|
|
159
|
+
result.note = '仅显示基本信息,如需完整内容请使用 fields=detail 或 fields=full';
|
|
160
|
+
}
|
|
161
|
+
else if (fields === 'detail') {
|
|
162
|
+
result.note = '显示详细信息但不包含关联数据(files/cases/linkBugs),如需完整内容请使用 fields=full';
|
|
163
|
+
}
|
|
108
164
|
return {
|
|
109
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
165
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
110
166
|
};
|
|
111
167
|
});
|
|
112
168
|
// Add resolveBug tool
|
|
@@ -360,13 +416,31 @@ server.tool("getProjectReleases", {
|
|
|
360
416
|
});
|
|
361
417
|
// Add getStoryDetail tool
|
|
362
418
|
server.tool("getStoryDetail", {
|
|
363
|
-
storyId: z.number()
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
419
|
+
storyId: z.number(),
|
|
420
|
+
fields: z.enum(['basic', 'detail', 'full']).optional().describe(`
|
|
421
|
+
字段级别:
|
|
422
|
+
- basic: 基本信息(id, title, status, stage, pri等核心字段)
|
|
423
|
+
- detail: 详细信息(包含spec和verify,但不包含executions/tasks/stages/children等关联数据)
|
|
424
|
+
- full: 完整信息(包含所有字段,默认值)
|
|
425
|
+
`.trim())
|
|
426
|
+
}, async ({ storyId, fields }) => {
|
|
427
|
+
if (!zentaoApi)
|
|
428
|
+
throw new Error("Please initialize Zentao API first");
|
|
429
|
+
const story = await zentaoApi.getStoryDetail(storyId, fields);
|
|
430
|
+
// 添加说明信息
|
|
431
|
+
const result = {
|
|
432
|
+
fieldLevel: fields || 'full',
|
|
433
|
+
story: story
|
|
434
|
+
};
|
|
435
|
+
// 根据字段级别添加提示
|
|
436
|
+
if (fields === 'basic') {
|
|
437
|
+
result.note = '仅显示基本信息,如需完整内容请使用 fields=detail 或 fields=full';
|
|
438
|
+
}
|
|
439
|
+
else if (fields === 'detail') {
|
|
440
|
+
result.note = '显示详细信息但不包含关联数据(executions/tasks/stages/children),如需完整内容请使用 fields=full';
|
|
441
|
+
}
|
|
368
442
|
return {
|
|
369
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
443
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
370
444
|
};
|
|
371
445
|
});
|
|
372
446
|
// Add createBug tool
|
|
@@ -507,7 +581,13 @@ server.tool("changeStory", {
|
|
|
507
581
|
comment: z.string().optional()
|
|
508
582
|
}),
|
|
509
583
|
z.string()
|
|
510
|
-
]).describe(
|
|
584
|
+
]).describe(`修改需求字段(使用最新 PUT 接口)
|
|
585
|
+
|
|
586
|
+
此工具使用"修改需求其他字段"接口(PUT /stories/:id),支持修改29个字段。
|
|
587
|
+
已废弃旧的"变更需求"接口(POST /stories/:id/change),该接口仅支持3个字段。
|
|
588
|
+
|
|
589
|
+
支持对象或JSON字符串格式。
|
|
590
|
+
`.trim())
|
|
511
591
|
}, async ({ storyId, update }) => {
|
|
512
592
|
if (!zentaoApi)
|
|
513
593
|
throw new Error("Please initialize Zentao API first");
|
|
@@ -542,13 +622,26 @@ server.tool("deleteTask", {
|
|
|
542
622
|
});
|
|
543
623
|
// Add getProductStories tool
|
|
544
624
|
server.tool("getProductStories", {
|
|
545
|
-
productId: z.number()
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
625
|
+
productId: z.number(),
|
|
626
|
+
page: z.number().optional().describe("页码,从1开始,默认为1"),
|
|
627
|
+
limit: z.number().optional().describe("每页数量,默认20,最大100")
|
|
628
|
+
}, async ({ productId, page, limit }) => {
|
|
629
|
+
if (!zentaoApi)
|
|
630
|
+
throw new Error("Please initialize Zentao API first");
|
|
631
|
+
const result = await zentaoApi.getProductStories(productId, page, limit);
|
|
632
|
+
// 返回分页信息和数据
|
|
633
|
+
const summary = {
|
|
634
|
+
summary: `当前第 ${result.page} 页,共 ${result.total} 条需求,本页显示 ${result.stories.length} 条`,
|
|
635
|
+
pagination: {
|
|
636
|
+
page: result.page,
|
|
637
|
+
limit: result.limit,
|
|
638
|
+
total: result.total,
|
|
639
|
+
totalPages: Math.ceil(result.total / result.limit)
|
|
640
|
+
},
|
|
641
|
+
stories: result.stories
|
|
642
|
+
};
|
|
550
643
|
return {
|
|
551
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
644
|
+
content: [{ type: "text", text: JSON.stringify(summary, null, 2) }]
|
|
552
645
|
};
|
|
553
646
|
});
|
|
554
647
|
// Program tools
|
|
@@ -5,8 +5,8 @@ export class BugService {
|
|
|
5
5
|
this.api = api;
|
|
6
6
|
}
|
|
7
7
|
async getMyBugs(status) {
|
|
8
|
-
const
|
|
9
|
-
return bugs.map(bug => this.enrichBugData(bug));
|
|
8
|
+
const result = await this.api.getMyBugs(status);
|
|
9
|
+
return result.bugs.map((bug) => this.enrichBugData(bug));
|
|
10
10
|
}
|
|
11
11
|
async getBugDetail(bugId) {
|
|
12
12
|
const bug = await this.api.getBugDetail(bugId);
|