@zzp123/mcp-zentao 1.7.4 → 1.8.1
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 +17 -0
- package/dist/api/zentaoApi.d.ts +22 -6
- package/dist/api/zentaoApi.js +151 -22
- package/dist/index.js +115 -28
- package/dist/services/bugService.js +2 -2
- package/dist/types/zentao.d.ts +2 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,23 @@ 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.8.0] - 2025-11-06
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **重构需求变更接口命名**
|
|
12
|
+
- 将 `updateStory` 工具重命名为 `changeStory`,更准确地反映其功能
|
|
13
|
+
- 将 `UpdateStoryRequest` 类型重命名为 `ChangeStoryRequest`
|
|
14
|
+
- 将 `updateStory` API方法重命名为 `changeStory`
|
|
15
|
+
- 使用功能完整的"修改需求其他字段"接口替代功能有限的"变更需求"接口
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- 向后兼容的类型别名:`UpdateStoryRequest` 作为 `ChangeStoryRequest` 的别名
|
|
19
|
+
|
|
20
|
+
### Technical
|
|
21
|
+
- 统一需求变更相关的命名规范
|
|
22
|
+
- 保持向后兼容性,旧的类型名称仍然可用
|
|
23
|
+
- 所有测试通过,确保重构不影响现有功能
|
|
24
|
+
|
|
8
25
|
## [1.7.4] - 2025-11-06
|
|
9
26
|
|
|
10
27
|
### Fixed
|
package/dist/api/zentaoApi.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AssignFeedbackRequest, Bug, BugStatus, Build, CloseFeedbackRequest, CreateBuildRequest, CreateBugRequest, CreateExecutionRequest, CreateFeedbackRequest, CreatePlanRequest, CreateProductRequest, CreateProgramRequest, CreateProjectRequest, CreateStoryRequest, CreateTaskRequest, CreateTestCaseRequest, CreateTicketRequest, CreateUserRequest, Execution, Feedback, FileUploadResponse, ModulesResponse, ModuleType, Plan, Product, Program, Project, Release, ResolveBugRequest, Story, Task, TaskStatus, TaskUpdate, TestCase, Ticket, UpdateBuildRequest, UpdateBugRequest, UpdateExecutionRequest, UpdateFeedbackRequest, UpdatePlanRequest, UpdateProductRequest, UpdateProgramRequest, UpdateProjectRequest,
|
|
1
|
+
import { AssignFeedbackRequest, Bug, BugStatus, Build, CloseFeedbackRequest, CreateBuildRequest, CreateBugRequest, CreateExecutionRequest, CreateFeedbackRequest, CreatePlanRequest, CreateProductRequest, CreateProgramRequest, CreateProjectRequest, CreateStoryRequest, CreateTaskRequest, CreateTestCaseRequest, CreateTicketRequest, CreateUserRequest, Execution, Feedback, FileUploadResponse, ModulesResponse, ModuleType, Plan, Product, Program, Project, Release, ResolveBugRequest, Story, Task, TaskStatus, TaskUpdate, TestCase, Ticket, UpdateBuildRequest, UpdateBugRequest, UpdateExecutionRequest, UpdateFeedbackRequest, UpdatePlanRequest, UpdateProductRequest, UpdateProgramRequest, UpdateProjectRequest, ChangeStoryRequest, UpdateTestCaseRequest, UpdateTicketRequest, UpdateUserRequest, UploadFileRequest, UserDetail, ZentaoConfig } from '../types/zentao';
|
|
2
2
|
export declare class ZentaoAPI {
|
|
3
3
|
private config;
|
|
4
4
|
private client;
|
|
@@ -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,21 @@ 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[]>;
|
|
36
|
-
|
|
47
|
+
changeStory(storyId: number, update: ChangeStoryRequest): Promise<Story>;
|
|
37
48
|
deleteTask(taskId: number): Promise<{
|
|
38
49
|
message: string;
|
|
39
50
|
}>;
|
|
40
|
-
getProductStories(productId: number): Promise<
|
|
51
|
+
getProductStories(productId: number, page?: number, limit?: number): Promise<{
|
|
52
|
+
page: number;
|
|
53
|
+
total: number;
|
|
54
|
+
limit: number;
|
|
55
|
+
stories: Story[];
|
|
56
|
+
}>;
|
|
41
57
|
getProgramDetail(programId: number): Promise<Program>;
|
|
42
58
|
createProgram(program: CreateProgramRequest): Promise<Program>;
|
|
43
59
|
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,9 @@ export class ZentaoAPI {
|
|
|
495
606
|
throw error;
|
|
496
607
|
}
|
|
497
608
|
}
|
|
498
|
-
async
|
|
609
|
+
async changeStory(storyId, update) {
|
|
499
610
|
try {
|
|
500
|
-
console.log(
|
|
611
|
+
console.log(`正在变更需求 ${storyId}...`);
|
|
501
612
|
// 自动处理评审人问题
|
|
502
613
|
const updateData = { ...update };
|
|
503
614
|
// 如果用户没有设置评审人,也没有指定无需评审,则自动跳过评审
|
|
@@ -506,11 +617,11 @@ export class ZentaoAPI {
|
|
|
506
617
|
console.log('自动设置needNotReview=true以跳过评审要求');
|
|
507
618
|
}
|
|
508
619
|
const response = await this.request('PUT', `/stories/${storyId}`, undefined, updateData);
|
|
509
|
-
console.log('
|
|
620
|
+
console.log('变更需求响应:', response);
|
|
510
621
|
return response;
|
|
511
622
|
}
|
|
512
623
|
catch (error) {
|
|
513
|
-
console.error('
|
|
624
|
+
console.error('变更需求失败:', error);
|
|
514
625
|
throw error;
|
|
515
626
|
}
|
|
516
627
|
}
|
|
@@ -526,17 +637,35 @@ export class ZentaoAPI {
|
|
|
526
637
|
throw error;
|
|
527
638
|
}
|
|
528
639
|
}
|
|
529
|
-
async getProductStories(productId) {
|
|
640
|
+
async getProductStories(productId, page, limit) {
|
|
530
641
|
try {
|
|
531
|
-
|
|
532
|
-
const
|
|
533
|
-
|
|
642
|
+
// 默认每页20条,最多100条
|
|
643
|
+
const finalLimit = limit ? Math.min(limit, 100) : 20;
|
|
644
|
+
const finalPage = page || 1;
|
|
645
|
+
console.log(`正在获取产品 ${productId} 的需求列表 (page=${finalPage}, limit=${finalLimit})...`);
|
|
646
|
+
// 构建查询参数
|
|
647
|
+
const queryParams = new URLSearchParams();
|
|
648
|
+
queryParams.append('page', finalPage.toString());
|
|
649
|
+
queryParams.append('limit', finalLimit.toString());
|
|
650
|
+
const response = await this.request('GET', `/products/${productId}/stories?${queryParams.toString()}`);
|
|
651
|
+
console.log(`产品需求列表响应: 获取到 ${response.stories?.length || 0} 条数据`);
|
|
534
652
|
if (Array.isArray(response)) {
|
|
535
|
-
|
|
653
|
+
// 如果返回的是数组,转换为标准格式
|
|
654
|
+
return {
|
|
655
|
+
page: finalPage,
|
|
656
|
+
total: response.length,
|
|
657
|
+
limit: finalLimit,
|
|
658
|
+
stories: response
|
|
659
|
+
};
|
|
536
660
|
}
|
|
537
661
|
else if (response && typeof response === 'object') {
|
|
538
662
|
if (Array.isArray(response.stories)) {
|
|
539
|
-
return
|
|
663
|
+
return {
|
|
664
|
+
page: response.page || finalPage,
|
|
665
|
+
total: response.total || response.stories.length,
|
|
666
|
+
limit: response.limit || finalLimit,
|
|
667
|
+
stories: response.stories
|
|
668
|
+
};
|
|
540
669
|
}
|
|
541
670
|
}
|
|
542
671
|
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
|
|
@@ -460,8 +534,8 @@ server.tool("getProjects", {
|
|
|
460
534
|
content: [{ type: "text", text: JSON.stringify(projects, null, 2) }]
|
|
461
535
|
};
|
|
462
536
|
});
|
|
463
|
-
// Add
|
|
464
|
-
server.tool("
|
|
537
|
+
// Add changeStory tool
|
|
538
|
+
server.tool("changeStory", {
|
|
465
539
|
storyId: z.number(),
|
|
466
540
|
update: z.union([
|
|
467
541
|
z.object({
|
|
@@ -507,7 +581,7 @@ server.tool("updateStory", {
|
|
|
507
581
|
comment: z.string().optional()
|
|
508
582
|
}),
|
|
509
583
|
z.string()
|
|
510
|
-
]).describe("
|
|
584
|
+
]).describe("需求变更字段 - 支持对象或JSON字符串格式")
|
|
511
585
|
}, async ({ storyId, update }) => {
|
|
512
586
|
if (!zentaoApi)
|
|
513
587
|
throw new Error("Please initialize Zentao API first");
|
|
@@ -524,7 +598,7 @@ server.tool("updateStory", {
|
|
|
524
598
|
else {
|
|
525
599
|
updateData = update;
|
|
526
600
|
}
|
|
527
|
-
const story = await zentaoApi.
|
|
601
|
+
const story = await zentaoApi.changeStory(storyId, updateData);
|
|
528
602
|
return {
|
|
529
603
|
content: [{ type: "text", text: JSON.stringify(story, null, 2) }]
|
|
530
604
|
};
|
|
@@ -542,13 +616,26 @@ server.tool("deleteTask", {
|
|
|
542
616
|
});
|
|
543
617
|
// Add getProductStories tool
|
|
544
618
|
server.tool("getProductStories", {
|
|
545
|
-
productId: z.number()
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
619
|
+
productId: z.number(),
|
|
620
|
+
page: z.number().optional().describe("页码,从1开始,默认为1"),
|
|
621
|
+
limit: z.number().optional().describe("每页数量,默认20,最大100")
|
|
622
|
+
}, async ({ productId, page, limit }) => {
|
|
623
|
+
if (!zentaoApi)
|
|
624
|
+
throw new Error("Please initialize Zentao API first");
|
|
625
|
+
const result = await zentaoApi.getProductStories(productId, page, limit);
|
|
626
|
+
// 返回分页信息和数据
|
|
627
|
+
const summary = {
|
|
628
|
+
summary: `当前第 ${result.page} 页,共 ${result.total} 条需求,本页显示 ${result.stories.length} 条`,
|
|
629
|
+
pagination: {
|
|
630
|
+
page: result.page,
|
|
631
|
+
limit: result.limit,
|
|
632
|
+
total: result.total,
|
|
633
|
+
totalPages: Math.ceil(result.total / result.limit)
|
|
634
|
+
},
|
|
635
|
+
stories: result.stories
|
|
636
|
+
};
|
|
550
637
|
return {
|
|
551
|
-
content: [{ type: "text", text: JSON.stringify(
|
|
638
|
+
content: [{ type: "text", text: JSON.stringify(summary, null, 2) }]
|
|
552
639
|
};
|
|
553
640
|
});
|
|
554
641
|
// 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);
|
package/dist/types/zentao.d.ts
CHANGED
|
@@ -256,7 +256,7 @@ export interface Project {
|
|
|
256
256
|
PM: string | User;
|
|
257
257
|
progress: number;
|
|
258
258
|
}
|
|
259
|
-
export interface
|
|
259
|
+
export interface ChangeStoryRequest {
|
|
260
260
|
title?: string;
|
|
261
261
|
product?: number;
|
|
262
262
|
parent?: number;
|
|
@@ -287,6 +287,7 @@ export interface UpdateStoryRequest {
|
|
|
287
287
|
verify?: string;
|
|
288
288
|
comment?: string;
|
|
289
289
|
}
|
|
290
|
+
export type UpdateStoryRequest = ChangeStoryRequest;
|
|
290
291
|
export interface CreateProgramRequest {
|
|
291
292
|
name?: string;
|
|
292
293
|
parent?: string;
|