@cloudglab/zentao-cli 0.1.3

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.
Files changed (187) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/MCP_ZENTAO_REBUILD_PLAN.md +505 -0
  3. package/README.md +319 -0
  4. package/dist/api/bug.d.ts +32 -0
  5. package/dist/api/bug.js +85 -0
  6. package/dist/api/bug.js.map +1 -0
  7. package/dist/api/build.d.ts +31 -0
  8. package/dist/api/build.js +21 -0
  9. package/dist/api/build.js.map +1 -0
  10. package/dist/api/comment.d.ts +20 -0
  11. package/dist/api/comment.js +47 -0
  12. package/dist/api/comment.js.map +1 -0
  13. package/dist/api/development-context.d.ts +14 -0
  14. package/dist/api/development-context.js +35 -0
  15. package/dist/api/development-context.js.map +1 -0
  16. package/dist/api/execution.d.ts +46 -0
  17. package/dist/api/execution.js +47 -0
  18. package/dist/api/execution.js.map +1 -0
  19. package/dist/api/index.d.ts +43 -0
  20. package/dist/api/index.js +46 -0
  21. package/dist/api/index.js.map +1 -0
  22. package/dist/api/plan.d.ts +18 -0
  23. package/dist/api/plan.js +33 -0
  24. package/dist/api/plan.js.map +1 -0
  25. package/dist/api/product.d.ts +7 -0
  26. package/dist/api/product.js +14 -0
  27. package/dist/api/product.js.map +1 -0
  28. package/dist/api/program.d.ts +7 -0
  29. package/dist/api/program.js +14 -0
  30. package/dist/api/program.js.map +1 -0
  31. package/dist/api/project.d.ts +8 -0
  32. package/dist/api/project.js +15 -0
  33. package/dist/api/project.js.map +1 -0
  34. package/dist/api/relation.d.ts +17 -0
  35. package/dist/api/relation.js +66 -0
  36. package/dist/api/relation.js.map +1 -0
  37. package/dist/api/release.d.ts +6 -0
  38. package/dist/api/release.js +11 -0
  39. package/dist/api/release.js.map +1 -0
  40. package/dist/api/search.d.ts +17 -0
  41. package/dist/api/search.js +168 -0
  42. package/dist/api/search.js.map +1 -0
  43. package/dist/api/statistics.d.ts +13 -0
  44. package/dist/api/statistics.js +67 -0
  45. package/dist/api/statistics.js.map +1 -0
  46. package/dist/api/story.d.ts +14 -0
  47. package/dist/api/story.js +23 -0
  48. package/dist/api/story.js.map +1 -0
  49. package/dist/api/task.d.ts +17 -0
  50. package/dist/api/task.js +37 -0
  51. package/dist/api/task.js.map +1 -0
  52. package/dist/api/testcase.d.ts +51 -0
  53. package/dist/api/testcase.js +31 -0
  54. package/dist/api/testcase.js.map +1 -0
  55. package/dist/api/testtask.d.ts +41 -0
  56. package/dist/api/testtask.js +34 -0
  57. package/dist/api/testtask.js.map +1 -0
  58. package/dist/api/user.d.ts +6 -0
  59. package/dist/api/user.js +9 -0
  60. package/dist/api/user.js.map +1 -0
  61. package/dist/bin/zentao-dev.d.ts +2 -0
  62. package/dist/bin/zentao-dev.js +8 -0
  63. package/dist/bin/zentao-dev.js.map +1 -0
  64. package/dist/bin/zentao-pm.d.ts +2 -0
  65. package/dist/bin/zentao-pm.js +8 -0
  66. package/dist/bin/zentao-pm.js.map +1 -0
  67. package/dist/bin/zentao-qa.d.ts +2 -0
  68. package/dist/bin/zentao-qa.js +8 -0
  69. package/dist/bin/zentao-qa.js.map +1 -0
  70. package/dist/bin/zentao.d.ts +2 -0
  71. package/dist/bin/zentao.js +8 -0
  72. package/dist/bin/zentao.js.map +1 -0
  73. package/dist/cli.d.ts +1 -0
  74. package/dist/cli.js +74 -0
  75. package/dist/cli.js.map +1 -0
  76. package/dist/core/api-provider.d.ts +3 -0
  77. package/dist/core/api-provider.js +17 -0
  78. package/dist/core/api-provider.js.map +1 -0
  79. package/dist/core/auth.d.ts +13 -0
  80. package/dist/core/auth.js +90 -0
  81. package/dist/core/auth.js.map +1 -0
  82. package/dist/core/cli-registry.d.ts +18 -0
  83. package/dist/core/cli-registry.js +128 -0
  84. package/dist/core/cli-registry.js.map +1 -0
  85. package/dist/core/config.d.ts +7 -0
  86. package/dist/core/config.js +58 -0
  87. package/dist/core/config.js.map +1 -0
  88. package/dist/core/http.d.ts +12 -0
  89. package/dist/core/http.js +50 -0
  90. package/dist/core/http.js.map +1 -0
  91. package/dist/core/list-result.d.ts +14 -0
  92. package/dist/core/list-result.js +59 -0
  93. package/dist/core/list-result.js.map +1 -0
  94. package/dist/core/pagination.d.ts +9 -0
  95. package/dist/core/pagination.js +12 -0
  96. package/dist/core/pagination.js.map +1 -0
  97. package/dist/core/roles.d.ts +4 -0
  98. package/dist/core/roles.js +13 -0
  99. package/dist/core/roles.js.map +1 -0
  100. package/dist/core/tool-registry.d.ts +3 -0
  101. package/dist/core/tool-registry.js +77 -0
  102. package/dist/core/tool-registry.js.map +1 -0
  103. package/dist/core/write-guard.d.ts +25 -0
  104. package/dist/core/write-guard.js +53 -0
  105. package/dist/core/write-guard.js.map +1 -0
  106. package/dist/index.d.ts +3 -0
  107. package/dist/index.js +3 -0
  108. package/dist/index.js.map +1 -0
  109. package/dist/tools/bug.d.ts +2 -0
  110. package/dist/tools/bug.js +41 -0
  111. package/dist/tools/bug.js.map +1 -0
  112. package/dist/tools/build.d.ts +2 -0
  113. package/dist/tools/build.js +8 -0
  114. package/dist/tools/build.js.map +1 -0
  115. package/dist/tools/comment.d.ts +2 -0
  116. package/dist/tools/comment.js +23 -0
  117. package/dist/tools/comment.js.map +1 -0
  118. package/dist/tools/context.d.ts +2 -0
  119. package/dist/tools/context.js +11 -0
  120. package/dist/tools/context.js.map +1 -0
  121. package/dist/tools/execution.d.ts +2 -0
  122. package/dist/tools/execution.js +21 -0
  123. package/dist/tools/execution.js.map +1 -0
  124. package/dist/tools/init.d.ts +2 -0
  125. package/dist/tools/init.js +28 -0
  126. package/dist/tools/init.js.map +1 -0
  127. package/dist/tools/phase3a.d.ts +4 -0
  128. package/dist/tools/phase3a.js +123 -0
  129. package/dist/tools/phase3a.js.map +1 -0
  130. package/dist/tools/phase3b.d.ts +5 -0
  131. package/dist/tools/phase3b.js +161 -0
  132. package/dist/tools/phase3b.js.map +1 -0
  133. package/dist/tools/plan.d.ts +2 -0
  134. package/dist/tools/plan.js +14 -0
  135. package/dist/tools/plan.js.map +1 -0
  136. package/dist/tools/product.d.ts +2 -0
  137. package/dist/tools/product.js +10 -0
  138. package/dist/tools/product.js.map +1 -0
  139. package/dist/tools/profile.d.ts +2 -0
  140. package/dist/tools/profile.js +6 -0
  141. package/dist/tools/profile.js.map +1 -0
  142. package/dist/tools/program.d.ts +2 -0
  143. package/dist/tools/program.js +8 -0
  144. package/dist/tools/program.js.map +1 -0
  145. package/dist/tools/project.d.ts +2 -0
  146. package/dist/tools/project.js +13 -0
  147. package/dist/tools/project.js.map +1 -0
  148. package/dist/tools/relation.d.ts +2 -0
  149. package/dist/tools/relation.js +13 -0
  150. package/dist/tools/relation.js.map +1 -0
  151. package/dist/tools/release.d.ts +2 -0
  152. package/dist/tools/release.js +7 -0
  153. package/dist/tools/release.js.map +1 -0
  154. package/dist/tools/search.d.ts +2 -0
  155. package/dist/tools/search.js +18 -0
  156. package/dist/tools/search.js.map +1 -0
  157. package/dist/tools/shared.d.ts +2 -0
  158. package/dist/tools/shared.js +11 -0
  159. package/dist/tools/shared.js.map +1 -0
  160. package/dist/tools/statistics.d.ts +2 -0
  161. package/dist/tools/statistics.js +10 -0
  162. package/dist/tools/statistics.js.map +1 -0
  163. package/dist/tools/story.d.ts +2 -0
  164. package/dist/tools/story.js +14 -0
  165. package/dist/tools/story.js.map +1 -0
  166. package/dist/tools/task.d.ts +2 -0
  167. package/dist/tools/task.js +48 -0
  168. package/dist/tools/task.js.map +1 -0
  169. package/dist/tools/testcase.d.ts +2 -0
  170. package/dist/tools/testcase.js +16 -0
  171. package/dist/tools/testcase.js.map +1 -0
  172. package/dist/tools/testtask.d.ts +2 -0
  173. package/dist/tools/testtask.js +14 -0
  174. package/dist/tools/testtask.js.map +1 -0
  175. package/dist/types/common.d.ts +15 -0
  176. package/dist/types/common.js +2 -0
  177. package/dist/types/common.js.map +1 -0
  178. package/dist/types/zentao.d.ts +42 -0
  179. package/dist/types/zentao.js +2 -0
  180. package/dist/types/zentao.js.map +1 -0
  181. package/dist/utils/json.d.ts +2 -0
  182. package/dist/utils/json.js +27 -0
  183. package/dist/utils/json.js.map +1 -0
  184. package/dist/version.d.ts +1 -0
  185. package/dist/version.js +2 -0
  186. package/dist/version.js.map +1 -0
  187. package/package.json +48 -0
@@ -0,0 +1,46 @@
1
+ import type { ZentaoHttpClient } from '../core/http.js';
2
+ import type { ZentaoExecution } from '../types/zentao.js';
3
+ export interface UpdateExecutionInput {
4
+ project?: number;
5
+ name?: string;
6
+ code?: string;
7
+ desc?: string;
8
+ begin?: string;
9
+ end?: string;
10
+ days?: number;
11
+ lifetime?: string;
12
+ PO?: string;
13
+ PM?: string;
14
+ QD?: string;
15
+ RD?: string;
16
+ teamMembers?: string[];
17
+ acl?: string;
18
+ whitelist?: string[];
19
+ }
20
+ export interface ExecutionActionInput {
21
+ comment?: string;
22
+ realBegan?: string;
23
+ realEnd?: string;
24
+ }
25
+ export interface PutoffExecutionInput {
26
+ days: number;
27
+ comment?: string;
28
+ }
29
+ export declare class ExecutionApi {
30
+ private readonly http;
31
+ constructor(http: ZentaoHttpClient);
32
+ getExecutionDetail(executionId: number): Promise<ZentaoExecution>;
33
+ getProjectExecutions(projectId: number): Promise<unknown>;
34
+ getExecutionBuilds(executionId: number): Promise<unknown>;
35
+ getExecutionBugs(executionId: number, params?: {
36
+ page?: number;
37
+ limit?: number;
38
+ status?: string;
39
+ }): Promise<unknown>;
40
+ updateExecution(executionId: number, update: UpdateExecutionInput): Promise<unknown>;
41
+ startExecution(executionId: number, payload?: ExecutionActionInput): Promise<unknown>;
42
+ closeExecution(executionId: number, payload?: ExecutionActionInput): Promise<unknown>;
43
+ suspendExecution(executionId: number, payload?: ExecutionActionInput): Promise<unknown>;
44
+ activateExecution(executionId: number, payload?: ExecutionActionInput): Promise<unknown>;
45
+ putoffExecution(executionId: number, payload: PutoffExecutionInput): Promise<unknown>;
46
+ }
@@ -0,0 +1,47 @@
1
+ import { toServerListResult } from '../core/list-result.js';
2
+ import { normalizePagination } from '../core/pagination.js';
3
+ export class ExecutionApi {
4
+ constructor(http) {
5
+ this.http = http;
6
+ }
7
+ async getExecutionDetail(executionId) {
8
+ return this.http.request('GET', `/executions/${executionId}`);
9
+ }
10
+ async getProjectExecutions(projectId) {
11
+ const response = await this.http.request('GET', `/projects/${projectId}/executions`);
12
+ return toServerListResult(response, ['executions']);
13
+ }
14
+ async getExecutionBuilds(executionId) {
15
+ const response = await this.http.request('GET', `/executions/${executionId}/builds`);
16
+ return toServerListResult(response, ['builds']);
17
+ }
18
+ async getExecutionBugs(executionId, params = {}) {
19
+ const pagination = normalizePagination(params);
20
+ const response = await this.http.request('GET', `/executions/${executionId}/bugs`, {
21
+ params: {
22
+ ...pagination,
23
+ status: params.status,
24
+ },
25
+ });
26
+ return toServerListResult(response, ['bugs'], params);
27
+ }
28
+ async updateExecution(executionId, update) {
29
+ return this.http.request('PUT', `/executions/${executionId}`, { data: update });
30
+ }
31
+ async startExecution(executionId, payload = {}) {
32
+ return this.http.request('POST', `/executions/${executionId}/start`, { data: payload });
33
+ }
34
+ async closeExecution(executionId, payload = {}) {
35
+ return this.http.request('POST', `/executions/${executionId}/close`, { data: payload });
36
+ }
37
+ async suspendExecution(executionId, payload = {}) {
38
+ return this.http.request('POST', `/executions/${executionId}/suspend`, { data: payload });
39
+ }
40
+ async activateExecution(executionId, payload = {}) {
41
+ return this.http.request('POST', `/executions/${executionId}/activate`, { data: payload });
42
+ }
43
+ async putoffExecution(executionId, payload) {
44
+ return this.http.request('POST', `/executions/${executionId}/putoff`, { data: payload });
45
+ }
46
+ }
47
+ //# sourceMappingURL=execution.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"execution.js","sourceRoot":"","sources":["../../src/api/execution.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { BugApi } from './bug.js';
2
+ import { BuildApi } from './build.js';
3
+ import { CommentApi } from './comment.js';
4
+ import { DevelopmentContextApi } from './development-context.js';
5
+ import { ExecutionApi } from './execution.js';
6
+ import { ProductApi } from './product.js';
7
+ import { ProgramApi } from './program.js';
8
+ import { ProjectApi } from './project.js';
9
+ import { PlanApi } from './plan.js';
10
+ import { ReleaseApi } from './release.js';
11
+ import { SearchApi } from './search.js';
12
+ import { RelationApi } from './relation.js';
13
+ import { StatisticsApi } from './statistics.js';
14
+ import { StoryApi } from './story.js';
15
+ import { TaskApi } from './task.js';
16
+ import { TestCaseApi } from './testcase.js';
17
+ import { TestTaskApi } from './testtask.js';
18
+ import { UserApi } from './user.js';
19
+ import { ZentaoHttpClient } from '../core/http.js';
20
+ import type { ZentaoConfig } from '../types/common.js';
21
+ export declare class ZentaoApi {
22
+ readonly http: ZentaoHttpClient;
23
+ readonly task: TaskApi;
24
+ readonly bug: BugApi;
25
+ readonly story: StoryApi;
26
+ readonly execution: ExecutionApi;
27
+ readonly comment: CommentApi;
28
+ readonly user: UserApi;
29
+ readonly statistics: StatisticsApi;
30
+ readonly relation: RelationApi;
31
+ readonly developmentContext: DevelopmentContextApi;
32
+ readonly product: ProductApi;
33
+ readonly project: ProjectApi;
34
+ readonly testcase: TestCaseApi;
35
+ readonly testtask: TestTaskApi;
36
+ readonly program: ProgramApi;
37
+ readonly plan: PlanApi;
38
+ readonly build: BuildApi;
39
+ readonly release: ReleaseApi;
40
+ readonly search: SearchApi;
41
+ constructor(config: ZentaoConfig);
42
+ getToken(): Promise<string>;
43
+ }
@@ -0,0 +1,46 @@
1
+ import { BugApi } from './bug.js';
2
+ import { BuildApi } from './build.js';
3
+ import { CommentApi } from './comment.js';
4
+ import { DevelopmentContextApi } from './development-context.js';
5
+ import { ExecutionApi } from './execution.js';
6
+ import { ProductApi } from './product.js';
7
+ import { ProgramApi } from './program.js';
8
+ import { ProjectApi } from './project.js';
9
+ import { PlanApi } from './plan.js';
10
+ import { ReleaseApi } from './release.js';
11
+ import { SearchApi } from './search.js';
12
+ import { RelationApi } from './relation.js';
13
+ import { StatisticsApi } from './statistics.js';
14
+ import { StoryApi } from './story.js';
15
+ import { TaskApi } from './task.js';
16
+ import { TestCaseApi } from './testcase.js';
17
+ import { TestTaskApi } from './testtask.js';
18
+ import { UserApi } from './user.js';
19
+ import { ZentaoHttpClient } from '../core/http.js';
20
+ export class ZentaoApi {
21
+ constructor(config) {
22
+ this.http = new ZentaoHttpClient(config);
23
+ this.task = new TaskApi(this.http);
24
+ this.bug = new BugApi(this.http);
25
+ this.story = new StoryApi(this.http);
26
+ this.execution = new ExecutionApi(this.http);
27
+ this.comment = new CommentApi(this.http);
28
+ this.user = new UserApi(this.http);
29
+ this.statistics = new StatisticsApi(this.task, this.bug);
30
+ this.relation = new RelationApi(this.bug, this.story);
31
+ this.developmentContext = new DevelopmentContextApi(this.bug, this.story, this.relation);
32
+ this.product = new ProductApi(this.http);
33
+ this.project = new ProjectApi(this.http);
34
+ this.testcase = new TestCaseApi(this.http);
35
+ this.testtask = new TestTaskApi(this.http);
36
+ this.program = new ProgramApi(this.http);
37
+ this.plan = new PlanApi(this.http);
38
+ this.build = new BuildApi(this.http);
39
+ this.release = new ReleaseApi(this.http);
40
+ this.search = new SearchApi(this.product, this.story);
41
+ }
42
+ getToken() {
43
+ return this.http.getToken();
44
+ }
45
+ }
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { ZentaoHttpClient } from '../core/http.js';
2
+ export interface ProductPlanListInput {
3
+ productId: number;
4
+ branch?: string;
5
+ status?: string;
6
+ query?: string;
7
+ order?: string;
8
+ }
9
+ export declare class PlanApi {
10
+ private readonly http;
11
+ constructor(http: ZentaoHttpClient);
12
+ getProductPlans(input: ProductPlanListInput): Promise<unknown>;
13
+ getPlanDetail(planId: number): Promise<unknown>;
14
+ linkStoriesToPlan(planId: number, storyIds: number[]): Promise<unknown>;
15
+ unlinkStoriesFromPlan(planId: number, storyIds: number[]): Promise<unknown>;
16
+ linkBugsToPlan(planId: number, bugIds: number[]): Promise<unknown>;
17
+ unlinkBugsFromPlan(planId: number, bugIds: number[]): Promise<unknown>;
18
+ }
@@ -0,0 +1,33 @@
1
+ import { toServerListResult } from '../core/list-result.js';
2
+ export class PlanApi {
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ async getProductPlans(input) {
7
+ const response = await this.http.request('GET', `/products/${input.productId}/plans`, {
8
+ params: {
9
+ branch: input.branch,
10
+ status: input.status,
11
+ query: input.query,
12
+ order: input.order,
13
+ },
14
+ });
15
+ return toServerListResult(response, ['plans']);
16
+ }
17
+ async getPlanDetail(planId) {
18
+ return this.http.request('GET', `/productplans/${planId}`);
19
+ }
20
+ async linkStoriesToPlan(planId, storyIds) {
21
+ return this.http.request('POST', `/productplans/${planId}/linkstories`, { data: { stories: storyIds } });
22
+ }
23
+ async unlinkStoriesFromPlan(planId, storyIds) {
24
+ return this.http.request('POST', `/productplans/${planId}/unlinkstories`, { data: { stories: storyIds } });
25
+ }
26
+ async linkBugsToPlan(planId, bugIds) {
27
+ return this.http.request('POST', `/productplans/${planId}/linkbugs`, { data: { bugs: bugIds } });
28
+ }
29
+ async unlinkBugsFromPlan(planId, bugIds) {
30
+ return this.http.request('POST', `/productplans/${planId}/unlinkbugs`, { data: { bugs: bugIds } });
31
+ }
32
+ }
33
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/api/plan.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAU5D,MAAM,OAAO,OAAO;IAClB,YAA6B,IAAsB;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAEvD,KAAK,CAAC,eAAe,CAAC,KAA2B;QAC/C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,KAAK,CAAC,SAAS,QAAQ,EAAE;YACpF,MAAM,EAAE;gBACN,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,MAAM,EAAE,KAAK,CAAC,MAAM;gBACpB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,KAAK,EAAE,KAAK,CAAC,KAAK;aACnB;SACF,CAAC,CAAC;QACH,OAAO,kBAAkB,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,MAAc;QAChC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,iBAAiB,MAAM,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,MAAc,EAAE,QAAkB;QACxD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,iBAAiB,MAAM,cAAc,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC3G,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,MAAc,EAAE,QAAkB;QAC5D,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,iBAAiB,MAAM,gBAAgB,EAAE,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;IAC7G,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,MAAc,EAAE,MAAgB;QACnD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,iBAAiB,MAAM,WAAW,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IACnG,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,MAAc,EAAE,MAAgB;QACvD,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,iBAAiB,MAAM,aAAa,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IACrG,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import type { ZentaoHttpClient } from '../core/http.js';
2
+ export declare class ProductApi {
3
+ private readonly http;
4
+ constructor(http: ZentaoHttpClient);
5
+ getProducts(): Promise<unknown>;
6
+ getProductDetail(productId: number): Promise<unknown>;
7
+ }
@@ -0,0 +1,14 @@
1
+ import { toServerListResult } from '../core/list-result.js';
2
+ export class ProductApi {
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ async getProducts() {
7
+ const response = await this.http.request('GET', '/products');
8
+ return toServerListResult(response, ['products']);
9
+ }
10
+ async getProductDetail(productId) {
11
+ return this.http.request('GET', `/products/${productId}`);
12
+ }
13
+ }
14
+ //# sourceMappingURL=product.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product.js","sourceRoot":"","sources":["../../src/api/product.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,OAAO,UAAU;IACrB,YAA6B,IAAsB;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAEvD,KAAK,CAAC,WAAW;QACf,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAC7D,OAAO,kBAAkB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,SAAiB;QACtC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,SAAS,EAAE,CAAC,CAAC;IAC5D,CAAC;CACF"}
@@ -0,0 +1,7 @@
1
+ import type { ZentaoHttpClient } from '../core/http.js';
2
+ export declare class ProgramApi {
3
+ private readonly http;
4
+ constructor(http: ZentaoHttpClient);
5
+ getPrograms(order?: string): Promise<unknown>;
6
+ getProgramDetail(programId: number): Promise<unknown>;
7
+ }
@@ -0,0 +1,14 @@
1
+ import { toServerListResult } from '../core/list-result.js';
2
+ export class ProgramApi {
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ async getPrograms(order) {
7
+ const response = await this.http.request('GET', '/programs', { params: { order } });
8
+ return toServerListResult(response, ['programs']);
9
+ }
10
+ async getProgramDetail(programId) {
11
+ return this.http.request('GET', `/programs/${programId}`);
12
+ }
13
+ }
14
+ //# sourceMappingURL=program.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program.js","sourceRoot":"","sources":["../../src/api/program.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,OAAO,UAAU;IACrB,YAA6B,IAAsB;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAEvD,KAAK,CAAC,WAAW,CAAC,KAAc;QAC9B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;QACpF,OAAO,kBAAkB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,SAAiB;QACtC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,SAAS,EAAE,CAAC,CAAC;IAC5D,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import type { ZentaoHttpClient } from '../core/http.js';
2
+ import { type PaginationInput } from '../core/pagination.js';
3
+ export declare class ProjectApi {
4
+ private readonly http;
5
+ constructor(http: ZentaoHttpClient);
6
+ getProjects(input?: PaginationInput): Promise<unknown>;
7
+ getProjectDetail(projectId: number): Promise<unknown>;
8
+ }
@@ -0,0 +1,15 @@
1
+ import { toServerListResult } from '../core/list-result.js';
2
+ import { normalizePagination } from '../core/pagination.js';
3
+ export class ProjectApi {
4
+ constructor(http) {
5
+ this.http = http;
6
+ }
7
+ async getProjects(input = {}) {
8
+ const response = await this.http.request('GET', '/projects', { params: normalizePagination(input) });
9
+ return toServerListResult(response, ['projects'], input);
10
+ }
11
+ async getProjectDetail(projectId) {
12
+ return this.http.request('GET', `/projects/${projectId}`);
13
+ }
14
+ }
15
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.js","sourceRoot":"","sources":["../../src/api/project.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAwB,MAAM,uBAAuB,CAAC;AAElF,MAAM,OAAO,UAAU;IACrB,YAA6B,IAAsB;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAEvD,KAAK,CAAC,WAAW,CAAC,QAAyB,EAAE;QAC3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,mBAAmB,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACrG,OAAO,kBAAkB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE,KAAK,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,SAAiB;QACtC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,SAAS,EAAE,CAAC,CAAC;IAC5D,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import type { BugApi } from './bug.js';
2
+ import type { StoryApi } from './story.js';
3
+ import type { ZentaoBug, ZentaoStory } from '../types/zentao.js';
4
+ export declare class RelationApi {
5
+ private readonly bugApi;
6
+ private readonly storyApi;
7
+ constructor(bugApi: BugApi, storyApi: StoryApi);
8
+ getBugRelatedStory(bugId: number): Promise<ZentaoStory | null>;
9
+ getStoryRelatedBugs(storyId: number, productId?: number): Promise<{
10
+ source: 'story-detail' | 'product-bugs-scan' | 'not-scanned';
11
+ partial: boolean;
12
+ scanned: number;
13
+ total?: number;
14
+ bugs: ZentaoBug[];
15
+ }>;
16
+ private getAllProductBugs;
17
+ }
@@ -0,0 +1,66 @@
1
+ function toNumber(value) {
2
+ if (typeof value === 'number' && Number.isFinite(value))
3
+ return value;
4
+ if (typeof value === 'string' && value.trim()) {
5
+ const parsed = Number(value);
6
+ return Number.isFinite(parsed) ? parsed : null;
7
+ }
8
+ return null;
9
+ }
10
+ export class RelationApi {
11
+ constructor(bugApi, storyApi) {
12
+ this.bugApi = bugApi;
13
+ this.storyApi = storyApi;
14
+ }
15
+ async getBugRelatedStory(bugId) {
16
+ const bug = await this.bugApi.getBugDetail(bugId);
17
+ const storyId = toNumber(bug.story);
18
+ if (!storyId || storyId <= 0)
19
+ return null;
20
+ return this.storyApi.getStoryDetail(storyId);
21
+ }
22
+ async getStoryRelatedBugs(storyId, productId) {
23
+ const story = await this.storyApi.getStoryDetail(storyId);
24
+ if (Array.isArray(story.bugs) && story.bugs.length > 0) {
25
+ return {
26
+ source: 'story-detail',
27
+ partial: false,
28
+ scanned: story.bugs.length,
29
+ total: story.bugs.length,
30
+ bugs: story.bugs,
31
+ };
32
+ }
33
+ if (!productId) {
34
+ return {
35
+ source: 'not-scanned',
36
+ partial: true,
37
+ scanned: 0,
38
+ bugs: [],
39
+ };
40
+ }
41
+ const allBugs = await this.getAllProductBugs(productId);
42
+ return {
43
+ source: 'product-bugs-scan',
44
+ partial: false,
45
+ scanned: allBugs.length,
46
+ total: allBugs.length,
47
+ bugs: allBugs.filter((bug) => {
48
+ const relatedStoryId = toNumber(bug.story ?? bug.storyID);
49
+ return relatedStoryId === storyId;
50
+ }),
51
+ };
52
+ }
53
+ async getAllProductBugs(productId) {
54
+ const limit = 100;
55
+ const firstPage = await this.bugApi.getProductBugs({ productId, status: 'all', page: 1, limit });
56
+ const bugs = [...firstPage.items];
57
+ const total = firstPage.total ?? bugs.length;
58
+ const totalPages = Math.ceil(total / limit);
59
+ for (let page = 2; page <= totalPages; page += 1) {
60
+ const response = await this.bugApi.getProductBugs({ productId, status: 'all', page, limit });
61
+ bugs.push(...response.items);
62
+ }
63
+ return bugs;
64
+ }
65
+ }
66
+ //# sourceMappingURL=relation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relation.js","sourceRoot":"","sources":["../../src/api/relation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { ZentaoHttpClient } from '../core/http.js';
2
+ export declare class ReleaseApi {
3
+ private readonly http;
4
+ constructor(http: ZentaoHttpClient);
5
+ getProjectReleases(projectId: number): Promise<unknown>;
6
+ }
@@ -0,0 +1,11 @@
1
+ import { toServerListResult } from '../core/list-result.js';
2
+ export class ReleaseApi {
3
+ constructor(http) {
4
+ this.http = http;
5
+ }
6
+ async getProjectReleases(projectId) {
7
+ const response = await this.http.request('GET', `/projects/${projectId}/releases`);
8
+ return toServerListResult(response, ['releases']);
9
+ }
10
+ }
11
+ //# sourceMappingURL=release.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release.js","sourceRoot":"","sources":["../../src/api/release.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,MAAM,OAAO,UAAU;IACrB,YAA6B,IAAsB;QAAtB,SAAI,GAAJ,IAAI,CAAkB;IAAG,CAAC;IAEvD,KAAK,CAAC,kBAAkB,CAAC,SAAiB;QACxC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,aAAa,SAAS,WAAW,CAAC,CAAC;QACnF,OAAO,kBAAkB,CAAC,QAAQ,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC;IACpD,CAAC;CACF"}
@@ -0,0 +1,17 @@
1
+ import type { ProductApi } from './product.js';
2
+ import type { StoryApi } from './story.js';
3
+ export interface SearchStoriesInput {
4
+ keyword: string;
5
+ productId?: number;
6
+ limit?: number;
7
+ deepSearch?: boolean;
8
+ }
9
+ export declare class SearchApi {
10
+ private readonly productApi;
11
+ private readonly storyApi;
12
+ constructor(productApi: ProductApi, storyApi: StoryApi);
13
+ searchStories(input: SearchStoriesInput): Promise<unknown>;
14
+ searchStoriesByProductName(productName: string, keyword: string, input?: Omit<SearchStoriesInput, 'keyword' | 'productId'>): Promise<unknown>;
15
+ private getAllStories;
16
+ private getAllStoriesByProduct;
17
+ }
@@ -0,0 +1,168 @@
1
+ function splitKeywords(keyword) {
2
+ const lower = keyword.toLowerCase();
3
+ const englishWords = lower.match(/[a-z0-9]+(?:-[a-z0-9]+)*/g) ?? [];
4
+ const chineseChars = lower.match(/[\u4e00-\u9fa5]/g) ?? [];
5
+ const keywords = [...englishWords, ...chineseChars];
6
+ return keywords.length > 0 ? keywords : [lower];
7
+ }
8
+ function calculateMatchScore(story, keyword, keywords) {
9
+ let score = 0;
10
+ const title = String(story.title ?? '').toLowerCase();
11
+ const spec = String(story.spec ?? '').toLowerCase();
12
+ const moduleName = String(story.moduleName ?? '').toLowerCase();
13
+ const productName = String(story.productName ?? '').toLowerCase();
14
+ if (title === keyword)
15
+ score += 100;
16
+ else if (title.includes(keyword))
17
+ score += 80;
18
+ else {
19
+ const titleMatches = keywords.filter(k => title.includes(k)).length;
20
+ if (titleMatches > 0)
21
+ score += 60 * (titleMatches / keywords.length);
22
+ }
23
+ if (spec.includes(keyword))
24
+ score += 40;
25
+ else {
26
+ const specMatches = keywords.filter(k => spec.includes(k)).length;
27
+ if (specMatches > 0)
28
+ score += 20 * (specMatches / keywords.length);
29
+ }
30
+ if (moduleName.includes(keyword) || productName.includes(keyword))
31
+ score += 10;
32
+ return score;
33
+ }
34
+ export class SearchApi {
35
+ constructor(productApi, storyApi) {
36
+ this.productApi = productApi;
37
+ this.storyApi = storyApi;
38
+ }
39
+ async searchStories(input) {
40
+ const { keyword, productId, limit = 20, deepSearch = false } = input;
41
+ const storiesResult = await this.getAllStories(productId);
42
+ const stories = storiesResult.items;
43
+ const lowerKeyword = keyword.toLowerCase();
44
+ const keywords = splitKeywords(keyword);
45
+ let deepSearchFailures = 0;
46
+ const scored = stories
47
+ .map(story => ({
48
+ story,
49
+ score: calculateMatchScore(story, lowerKeyword, keywords),
50
+ }))
51
+ .filter(item => item.score > 0);
52
+ if (deepSearch) {
53
+ const candidates = scored
54
+ .filter(item => {
55
+ const title = String(item.story.title ?? '').toLowerCase();
56
+ const spec = String(item.story.spec ?? '').toLowerCase();
57
+ return title.includes(lowerKeyword) && !spec.includes(lowerKeyword) && item.score < 50;
58
+ })
59
+ .slice(0, 10);
60
+ for (const item of candidates) {
61
+ try {
62
+ const detail = await this.storyApi.getStoryDetail(Number(item.story.id));
63
+ const newScore = calculateMatchScore(detail, lowerKeyword, keywords);
64
+ if (newScore > item.score) {
65
+ item.story = detail;
66
+ item.score = newScore;
67
+ }
68
+ }
69
+ catch {
70
+ deepSearchFailures += 1;
71
+ }
72
+ }
73
+ }
74
+ scored.sort((a, b) => b.score - a.score || Number(b.story.id ?? 0) - Number(a.story.id ?? 0));
75
+ return {
76
+ source: productId ? 'product-scoped-search' : 'global-search',
77
+ partial: storiesResult.partial || deepSearchFailures > 0,
78
+ failedProducts: storiesResult.failedProducts,
79
+ scannedProducts: storiesResult.scannedProducts,
80
+ scannedStories: stories.length,
81
+ deepSearchFailures,
82
+ keyword,
83
+ productId: productId ?? null,
84
+ limit,
85
+ totalMatched: scored.length,
86
+ items: scored.slice(0, limit).map(item => ({ ...item.story, matchScore: item.score })),
87
+ };
88
+ }
89
+ async searchStoriesByProductName(productName, keyword, input = {}) {
90
+ const productsResult = await this.productApi.getProducts();
91
+ const matchedProducts = productsResult.items.filter(product => String(product.name ?? '').toLowerCase().includes(productName.toLowerCase()));
92
+ const results = [];
93
+ let partial = false;
94
+ let failedProducts = 0;
95
+ let scannedProducts = 0;
96
+ let deepSearchFailures = 0;
97
+ for (const product of matchedProducts) {
98
+ const productId = Number(product.id);
99
+ scannedProducts += 1;
100
+ try {
101
+ const searchResult = await this.searchStories({ ...input, keyword, productId });
102
+ partial = partial || Boolean(searchResult.partial);
103
+ deepSearchFailures += Number(searchResult.deepSearchFailures ?? 0);
104
+ results.push({
105
+ product: { id: productId, name: product.name },
106
+ result: searchResult,
107
+ });
108
+ }
109
+ catch (error) {
110
+ partial = true;
111
+ failedProducts += 1;
112
+ results.push({
113
+ product: { id: productId, name: product.name },
114
+ error: error instanceof Error ? error.message : String(error),
115
+ });
116
+ }
117
+ }
118
+ return {
119
+ source: 'product-name-search',
120
+ partial,
121
+ failedProducts,
122
+ scannedProducts,
123
+ deepSearchFailures,
124
+ productName,
125
+ keyword,
126
+ matchedProducts: matchedProducts.length,
127
+ items: results,
128
+ };
129
+ }
130
+ async getAllStories(productId) {
131
+ if (productId) {
132
+ return {
133
+ partial: false,
134
+ failedProducts: 0,
135
+ scannedProducts: 1,
136
+ items: await this.getAllStoriesByProduct(productId),
137
+ };
138
+ }
139
+ const productsResult = await this.productApi.getProducts();
140
+ const allStories = [];
141
+ let failedProducts = 0;
142
+ for (const product of productsResult.items) {
143
+ try {
144
+ allStories.push(...await this.getAllStoriesByProduct(Number(product.id)));
145
+ }
146
+ catch {
147
+ failedProducts += 1;
148
+ }
149
+ }
150
+ return {
151
+ partial: failedProducts > 0,
152
+ failedProducts,
153
+ scannedProducts: productsResult.items.length,
154
+ items: allStories,
155
+ };
156
+ }
157
+ async getAllStoriesByProduct(productId) {
158
+ const firstPage = await this.storyApi.getProductStories({ productId, page: 1, limit: 100 });
159
+ const stories = [...firstPage.items];
160
+ const totalPages = Math.ceil((firstPage.total ?? stories.length) / 100);
161
+ for (let page = 2; page <= totalPages; page += 1) {
162
+ const result = await this.storyApi.getProductStories({ productId, page, limit: 100 });
163
+ stories.push(...result.items);
164
+ }
165
+ return stories;
166
+ }
167
+ }
168
+ //# sourceMappingURL=search.js.map