@jagadeesh52423/atlassian-mcp-server 1.1.1 → 1.1.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.
Files changed (97) hide show
  1. package/dist/formatters/adf-formatter.d.ts +30 -2
  2. package/dist/formatters/adf-formatter.d.ts.map +1 -1
  3. package/dist/formatters/adf-formatter.js +423 -107
  4. package/dist/formatters/adf-formatter.js.map +1 -1
  5. package/dist/formatters/index.d.ts +1 -1
  6. package/dist/formatters/index.d.ts.map +1 -1
  7. package/dist/formatters/index.js +1 -1
  8. package/dist/formatters/index.js.map +1 -1
  9. package/dist/handlers/base-handler.d.ts +5 -0
  10. package/dist/handlers/base-handler.d.ts.map +1 -0
  11. package/dist/handlers/base-handler.js +7 -0
  12. package/dist/handlers/base-handler.js.map +1 -0
  13. package/dist/handlers/bitbucket-handlers.d.ts +2 -1
  14. package/dist/handlers/bitbucket-handlers.d.ts.map +1 -1
  15. package/dist/handlers/bitbucket-handlers.js +31 -191
  16. package/dist/handlers/bitbucket-handlers.js.map +1 -1
  17. package/dist/handlers/confluence-handlers.d.ts +2 -1
  18. package/dist/handlers/confluence-handlers.d.ts.map +1 -1
  19. package/dist/handlers/confluence-handlers.js +46 -243
  20. package/dist/handlers/confluence-handlers.js.map +1 -1
  21. package/dist/handlers/jira-handlers.d.ts +9 -1
  22. package/dist/handlers/jira-handlers.d.ts.map +1 -1
  23. package/dist/handlers/jira-handlers.js +144 -575
  24. package/dist/handlers/jira-handlers.js.map +1 -1
  25. package/dist/index.js +111 -189
  26. package/dist/index.js.map +1 -1
  27. package/dist/registry/tool-registry.d.ts +11 -0
  28. package/dist/registry/tool-registry.d.ts.map +1 -0
  29. package/dist/registry/tool-registry.js +24 -0
  30. package/dist/registry/tool-registry.js.map +1 -0
  31. package/dist/services/bitbucket.d.ts +2 -0
  32. package/dist/services/bitbucket.d.ts.map +1 -1
  33. package/dist/services/bitbucket.js +22 -74
  34. package/dist/services/bitbucket.js.map +1 -1
  35. package/dist/services/confluence.d.ts.map +1 -1
  36. package/dist/services/confluence.js +5 -4
  37. package/dist/services/confluence.js.map +1 -1
  38. package/dist/services/jira/agile.d.ts +33 -0
  39. package/dist/services/jira/agile.d.ts.map +1 -0
  40. package/dist/services/jira/agile.js +118 -0
  41. package/dist/services/jira/agile.js.map +1 -0
  42. package/dist/services/jira/attachments.d.ts +7 -0
  43. package/dist/services/jira/attachments.d.ts.map +1 -0
  44. package/dist/services/jira/attachments.js +26 -0
  45. package/dist/services/jira/attachments.js.map +1 -0
  46. package/dist/services/jira/base.d.ts +9 -0
  47. package/dist/services/jira/base.d.ts.map +1 -0
  48. package/dist/services/jira/base.js +11 -0
  49. package/dist/services/jira/base.js.map +1 -0
  50. package/dist/services/jira/comments.d.ts +8 -0
  51. package/dist/services/jira/comments.d.ts.map +1 -0
  52. package/dist/services/jira/comments.js +33 -0
  53. package/dist/services/jira/comments.js.map +1 -0
  54. package/dist/services/jira/issues.d.ts +32 -0
  55. package/dist/services/jira/issues.d.ts.map +1 -0
  56. package/dist/services/jira/issues.js +177 -0
  57. package/dist/services/jira/issues.js.map +1 -0
  58. package/dist/services/jira/labels.d.ts +7 -0
  59. package/dist/services/jira/labels.d.ts.map +1 -0
  60. package/dist/services/jira/labels.js +21 -0
  61. package/dist/services/jira/labels.js.map +1 -0
  62. package/dist/services/jira/links.d.ts +9 -0
  63. package/dist/services/jira/links.d.ts.map +1 -0
  64. package/dist/services/jira/links.js +55 -0
  65. package/dist/services/jira/links.js.map +1 -0
  66. package/dist/services/jira/metadata.d.ts +8 -0
  67. package/dist/services/jira/metadata.d.ts.map +1 -0
  68. package/dist/services/jira/metadata.js +32 -0
  69. package/dist/services/jira/metadata.js.map +1 -0
  70. package/dist/services/jira/subtasks.d.ts +9 -0
  71. package/dist/services/jira/subtasks.d.ts.map +1 -0
  72. package/dist/services/jira/subtasks.js +32 -0
  73. package/dist/services/jira/subtasks.js.map +1 -0
  74. package/dist/services/jira/transitions.d.ts +16 -0
  75. package/dist/services/jira/transitions.d.ts.map +1 -0
  76. package/dist/services/jira/transitions.js +203 -0
  77. package/dist/services/jira/transitions.js.map +1 -0
  78. package/dist/services/jira/versions.d.ts +19 -0
  79. package/dist/services/jira/versions.d.ts.map +1 -0
  80. package/dist/services/jira/versions.js +62 -0
  81. package/dist/services/jira/versions.js.map +1 -0
  82. package/dist/services/jira/watchers.d.ts +7 -0
  83. package/dist/services/jira/watchers.d.ts.map +1 -0
  84. package/dist/services/jira/watchers.js +23 -0
  85. package/dist/services/jira/watchers.js.map +1 -0
  86. package/dist/services/jira/worklogs.d.ts +8 -0
  87. package/dist/services/jira/worklogs.d.ts.map +1 -0
  88. package/dist/services/jira/worklogs.js +37 -0
  89. package/dist/services/jira/worklogs.js.map +1 -0
  90. package/dist/services/jira.d.ts +58 -103
  91. package/dist/services/jira.d.ts.map +1 -1
  92. package/dist/services/jira.js +100 -1481
  93. package/dist/services/jira.js.map +1 -1
  94. package/dist/tools/jira-tools.d.ts.map +1 -1
  95. package/dist/tools/jira-tools.js +35 -3
  96. package/dist/tools/jira-tools.js.map +1 -1
  97. package/package.json +1 -1
@@ -1,46 +1,60 @@
1
1
  import { successResponse, jsonResponse, errorResponse, ERROR_TIPS, } from '../error-handler.js';
2
2
  import { ICONS } from '../constants.js';
3
+ import { BaseHandler } from './base-handler.js';
3
4
  /**
4
5
  * Jira tool handlers
5
6
  */
6
- export class JiraHandlers {
7
+ export class JiraHandlers extends BaseHandler {
7
8
  service;
8
9
  constructor(service) {
10
+ super();
9
11
  this.service = service;
10
12
  }
11
13
  async searchIssues(args) {
12
14
  const { query, assignee, status, project, labels, reporter, createdAfter, updatedAfter, jql, fields, limit } = args;
13
- try {
14
- const issues = await this.service.searchIssues({ query, assignee, status, project, labels, reporter, createdAfter, updatedAfter, jql, fields, limit });
15
- return jsonResponse(issues);
15
+ if (fields !== undefined && !Array.isArray(fields)) {
16
+ return errorResponse(new Error('Invalid fields parameter'), {
17
+ operation: 'Failed to search Jira issues',
18
+ params: {},
19
+ tip: 'The "fields" parameter must be an array of strings, e.g. ["summary", "status", "customfield_10020"]. Do not pass it as a string.',
20
+ });
16
21
  }
17
- catch (error) {
18
- return errorResponse(error, {
22
+ if (labels !== undefined && !Array.isArray(labels)) {
23
+ return errorResponse(new Error('Invalid labels parameter'), {
19
24
  operation: 'Failed to search Jira issues',
20
- params: { Query: query || 'none', Assignee: assignee || 'none', JQL: jql || 'none', Limit: limit || 50 },
21
- tip: ERROR_TIPS.JIRA_SEARCH,
25
+ params: {},
26
+ tip: 'The "labels" parameter must be an array of strings, e.g. ["bug", "urgent"]. Do not pass it as a string.',
22
27
  });
23
28
  }
29
+ return this.handle(() => this.service.searchIssues({ query, assignee, status, project, labels, reporter, createdAfter, updatedAfter, jql, fields, limit }), { operation: 'Failed to search Jira issues', params: { Query: query || 'none', Assignee: assignee || 'none', JQL: jql || 'none', Limit: limit || 50 }, tip: ERROR_TIPS.JIRA_SEARCH }, jsonResponse);
24
30
  }
25
31
  async getIssue(args) {
26
- const { issueKey } = args;
27
- try {
28
- const issue = await this.service.getIssue(issueKey);
29
- return jsonResponse(issue);
30
- }
31
- catch (error) {
32
- return errorResponse(error, {
32
+ const { issueKey, fields } = args;
33
+ if (fields !== undefined && !Array.isArray(fields)) {
34
+ return errorResponse(new Error('Invalid fields parameter'), {
33
35
  operation: 'Failed to get Jira issue',
34
36
  params: { 'Issue Key': issueKey },
35
- tip: ERROR_TIPS.JIRA_ISSUE_VIEW,
37
+ tip: 'The "fields" parameter must be an array of strings, e.g. ["summary", "status", "customfield_10020"]. Do not pass it as a string.',
36
38
  });
37
39
  }
40
+ return this.handle(() => this.service.getIssue(issueKey, fields), { operation: 'Failed to get Jira issue', params: { 'Issue Key': issueKey, Fields: fields?.join(', ') || 'default' }, tip: ERROR_TIPS.JIRA_ISSUE_VIEW }, jsonResponse);
38
41
  }
39
42
  async createIssue(args) {
40
43
  const { projectKey, summary, description, issueType, duedate, priority, labels, components, assignee, customFields } = args;
41
- try {
42
- const additionalFields = { duedate, priority, labels, components, assignee, customFields };
43
- const issue = await this.service.createIssue(projectKey, summary, description, issueType, additionalFields);
44
+ return this.handle(() => this.service.createIssue(projectKey, summary, description, issueType, { duedate, priority, labels, components, assignee, customFields }), {
45
+ operation: 'Failed to create Jira issue',
46
+ params: {
47
+ Project: projectKey,
48
+ Summary: summary,
49
+ 'Issue Type': issueType || 'Task',
50
+ 'Due Date': duedate || 'none',
51
+ Priority: priority || 'none',
52
+ Labels: labels?.join(', ') || 'none',
53
+ Components: components?.join(', ') || 'none',
54
+ Assignee: assignee || 'none',
55
+ },
56
+ tip: ERROR_TIPS.JIRA_ISSUE_CREATE + ' For custom fields, ensure field IDs are correct.',
57
+ }, (issue) => {
44
58
  const optionalFields = [];
45
59
  if (duedate)
46
60
  optionalFields.push(`${ICONS.DATE} **Due Date:** ${duedate}`);
@@ -62,28 +76,15 @@ export class JiraHandlers {
62
76
  `${ICONS.DATE} **Created:** ${new Date(issue.created).toLocaleString()}${optionalFieldsText}\n\n` +
63
77
  `${ICONS.DESCRIPTION} **Description:** Successfully created with provided content\n\n` +
64
78
  `${ICONS.LINK} **Issue URL:** [View Issue](https://${domain}/browse/${issue.key})`);
65
- }
66
- catch (error) {
67
- return errorResponse(error, {
68
- operation: 'Failed to create Jira issue',
69
- params: {
70
- Project: projectKey,
71
- Summary: summary,
72
- 'Issue Type': issueType || 'Task',
73
- 'Due Date': duedate || 'none',
74
- Priority: priority || 'none',
75
- Labels: labels?.join(', ') || 'none',
76
- Components: components?.join(', ') || 'none',
77
- Assignee: assignee || 'none',
78
- },
79
- tip: ERROR_TIPS.JIRA_ISSUE_CREATE + ' For custom fields, ensure field IDs are correct.',
80
- });
81
- }
79
+ });
82
80
  }
83
81
  async updateIssue(args) {
84
- const { issueKey, summary, description, assignee } = args;
85
- try {
86
- const issue = await this.service.updateIssue(issueKey, { summary, description, assignee });
82
+ const { issueKey, summary, description, assignee, customFields } = args;
83
+ return this.handle(() => this.service.updateIssue(issueKey, { summary, description, assignee, customFields }), {
84
+ operation: `Failed to update Jira issue ${issueKey}`,
85
+ params: { Summary: summary || 'unchanged', Description: description || 'unchanged', Assignee: assignee || 'unchanged' },
86
+ tip: ERROR_TIPS.JIRA_ISSUE_EDIT,
87
+ }, (issue) => {
87
88
  const updatedFields = [];
88
89
  if (summary)
89
90
  updatedFields.push(`${ICONS.SUMMARY} **Summary:** Updated to "${issue.summary}"`);
@@ -91,6 +92,8 @@ export class JiraHandlers {
91
92
  updatedFields.push(`${ICONS.DESCRIPTION} **Description:** Updated successfully`);
92
93
  if (assignee)
93
94
  updatedFields.push(`${ICONS.ASSIGNEE} **Assignee:** ${issue.assignee || assignee}`);
95
+ if (customFields)
96
+ updatedFields.push(`**Custom Fields:** ${Object.keys(customFields).join(', ')} updated`);
94
97
  const updatedFieldsText = updatedFields.length > 0 ? `\n\n**Updated Fields:**\n${updatedFields.join('\n')}` : '';
95
98
  const domain = process.env.JIRA_DOMAIN || process.env.ATLASSIAN_DOMAIN || 'your-domain.atlassian.net';
96
99
  return successResponse(`${ICONS.SUCCESS} **Jira Issue Updated Successfully**\n\n` +
@@ -98,91 +101,30 @@ export class JiraHandlers {
98
101
  `${ICONS.STATUS} **Current Status:** ${issue.status}\n` +
99
102
  `${ICONS.DATE} **Last Updated:** ${new Date(issue.updated).toLocaleString()}${updatedFieldsText}\n\n` +
100
103
  `${ICONS.LINK} **Issue URL:** [View Issue](https://${domain}/browse/${issue.key})`);
101
- }
102
- catch (error) {
103
- return errorResponse(error, {
104
- operation: `Failed to update Jira issue ${issueKey}`,
105
- params: {
106
- Summary: summary || 'unchanged',
107
- Description: description || 'unchanged',
108
- Assignee: assignee || 'unchanged',
109
- },
110
- tip: ERROR_TIPS.JIRA_ISSUE_EDIT,
111
- });
112
- }
104
+ });
113
105
  }
114
106
  async addComment(args) {
115
107
  const { issueKey, comment } = args;
116
- try {
117
- await this.service.addComment(issueKey, comment);
118
- return successResponse(`Comment added to issue ${issueKey}`);
119
- }
120
- catch (error) {
121
- return errorResponse(error, {
122
- operation: 'Failed to add comment to Jira issue',
123
- params: { 'Issue Key': issueKey, Comment: comment.substring(0, 100) + '...' },
124
- tip: ERROR_TIPS.JIRA_COMMENT,
125
- });
126
- }
108
+ return this.handle(() => this.service.addComment(issueKey, comment), { operation: 'Failed to add comment to Jira issue', params: { 'Issue Key': issueKey, Comment: comment.substring(0, 100) + '...' }, tip: ERROR_TIPS.JIRA_COMMENT }, () => successResponse(`Comment added to issue ${issueKey}`));
127
109
  }
128
110
  async getComments(args) {
129
111
  const { issueKey } = args;
130
- try {
131
- const comments = await this.service.getComments(issueKey);
132
- return jsonResponse(comments);
133
- }
134
- catch (error) {
135
- return errorResponse(error, {
136
- operation: 'Failed to get comments for Jira issue',
137
- params: { 'Issue Key': issueKey },
138
- tip: ERROR_TIPS.JIRA_ISSUE_VIEW,
139
- });
140
- }
112
+ return this.handle(() => this.service.getComments(issueKey), { operation: 'Failed to get comments for Jira issue', params: { 'Issue Key': issueKey }, tip: ERROR_TIPS.JIRA_ISSUE_VIEW }, jsonResponse);
141
113
  }
142
114
  async updateComment(args) {
143
115
  const { issueKey, commentId, comment } = args;
144
- try {
145
- const result = await this.service.updateComment(issueKey, commentId, comment);
146
- return successResponse(`${ICONS.SUCCESS} Comment ${commentId} updated successfully on issue ${issueKey}\n\n${JSON.stringify(result, null, 2)}`);
147
- }
148
- catch (error) {
149
- return errorResponse(error, {
150
- operation: 'Failed to update comment on Jira issue',
151
- params: { 'Issue Key': issueKey, 'Comment ID': commentId },
152
- tip: 'Check if the comment exists, you are the author, and you have permission to edit it.',
153
- });
154
- }
116
+ return this.handle(() => this.service.updateComment(issueKey, commentId, comment), { operation: 'Failed to update comment on Jira issue', params: { 'Issue Key': issueKey, 'Comment ID': commentId }, tip: 'Check if the comment exists, you are the author, and you have permission to edit it.' }, (result) => successResponse(`${ICONS.SUCCESS} Comment ${commentId} updated successfully on issue ${issueKey}\n\n${JSON.stringify(result, null, 2)}`));
155
117
  }
156
118
  async deleteComment(args) {
157
119
  const { issueKey, commentId } = args;
158
- try {
159
- await this.service.deleteComment(issueKey, commentId);
160
- return successResponse(`${ICONS.SUCCESS} Comment ${commentId} deleted successfully from issue ${issueKey}`);
161
- }
162
- catch (error) {
163
- return errorResponse(error, {
164
- operation: 'Failed to delete comment from Jira issue',
165
- params: { 'Issue Key': issueKey, 'Comment ID': commentId },
166
- tip: 'Check if the comment exists and you have permission to delete it.',
167
- });
168
- }
120
+ return this.handle(() => this.service.deleteComment(issueKey, commentId), { operation: 'Failed to delete comment from Jira issue', params: { 'Issue Key': issueKey, 'Comment ID': commentId }, tip: 'Check if the comment exists and you have permission to delete it.' }, () => successResponse(`${ICONS.SUCCESS} Comment ${commentId} deleted successfully from issue ${issueKey}`));
169
121
  }
170
122
  async getProjects() {
171
- try {
172
- const projects = await this.service.getProjects();
173
- return jsonResponse(projects);
174
- }
175
- catch (error) {
176
- return errorResponse(error, {
177
- operation: 'Failed to get Jira projects',
178
- tip: 'Check your Jira permissions and API access.',
179
- });
180
- }
123
+ return this.handle(() => this.service.getProjects(), { operation: 'Failed to get Jira projects', tip: 'Check your Jira permissions and API access.' }, jsonResponse);
181
124
  }
182
125
  async getIssueTransitions(args) {
183
126
  const { issueKey } = args;
184
- try {
185
- const transitions = await this.service.getIssueTransitions(issueKey);
127
+ return this.handle(() => this.service.getIssueTransitions(issueKey), { operation: 'Failed to get transitions for Jira issue', params: { 'Issue Key': issueKey }, tip: ERROR_TIPS.JIRA_ISSUE_VIEW }, (transitions) => {
186
128
  const transitionInfo = transitions.map((t) => ({
187
129
  id: t.id,
188
130
  name: t.name,
@@ -191,19 +133,15 @@ export class JiraHandlers {
191
133
  return successResponse(`Available transitions for ${issueKey}:\n\n` +
192
134
  `${transitionInfo.map((t) => `• **${t.name}** (ID: ${t.id}) → ${t.to}`).join('\n')}\n\n` +
193
135
  `Use the transition ID with jira_transition_issue_interactive for smart field handling.`);
194
- }
195
- catch (error) {
196
- return errorResponse(error, {
197
- operation: 'Failed to get transitions for Jira issue',
198
- params: { 'Issue Key': issueKey },
199
- tip: ERROR_TIPS.JIRA_ISSUE_VIEW,
200
- });
201
- }
136
+ });
202
137
  }
203
138
  async transitionIssue(args) {
204
139
  const { issueKey, transitionId, fieldValues } = args;
205
- try {
206
- const result = await this.service.transitionIssue(issueKey, transitionId, fieldValues);
140
+ return this.handle(() => this.service.transitionIssue(issueKey, transitionId, fieldValues), {
141
+ operation: `Failed to transition Jira issue ${issueKey}`,
142
+ params: { 'Transition ID': transitionId, 'Field Values': JSON.stringify(fieldValues || {}, null, 2) },
143
+ tip: ERROR_TIPS.JIRA_TRANSITION,
144
+ }, (result) => {
207
145
  if (result.success) {
208
146
  return successResponse(result.message || `Issue ${issueKey} transitioned successfully`);
209
147
  }
@@ -221,28 +159,16 @@ export class JiraHandlers {
221
159
  return successResponse(`${result.message}\n\n**Required Fields:**\n${fieldInfo}\n\n` +
222
160
  `**Next Steps:**\nUse jira_transition_issue_interactive for automatic field suggestion, or provide fieldValues with the correct field IDs and values.`);
223
161
  }
224
- else {
225
- return {
226
- content: [{ type: 'text', text: result.message || 'Transition failed with unknown error' }],
227
- isError: true,
228
- };
229
- }
230
- }
231
- catch (error) {
232
- return errorResponse(error, {
233
- operation: `Failed to transition Jira issue ${issueKey}`,
234
- params: {
235
- 'Transition ID': transitionId,
236
- 'Field Values': JSON.stringify(fieldValues || {}, null, 2),
237
- },
238
- tip: ERROR_TIPS.JIRA_TRANSITION,
239
- });
240
- }
162
+ return { content: [{ type: 'text', text: result.message || 'Transition failed with unknown error' }], isError: true };
163
+ });
241
164
  }
242
165
  async transitionIssueInteractive(args) {
243
166
  const { issueKey, transitionId, fieldValues } = args;
244
- try {
245
- const result = await this.service.transitionIssueInteractive(issueKey, transitionId, fieldValues);
167
+ return this.handle(() => this.service.transitionIssueInteractive(issueKey, transitionId, fieldValues), {
168
+ operation: `Failed to transition Jira issue ${issueKey} (interactive mode)`,
169
+ params: { 'Transition ID': transitionId, 'Field Values': JSON.stringify(fieldValues || {}, null, 2) },
170
+ tip: ERROR_TIPS.JIRA_TRANSITION,
171
+ }, (result) => {
246
172
  if (result.success) {
247
173
  return successResponse(result.message || `Issue ${issueKey} transitioned successfully`);
248
174
  }
@@ -259,558 +185,201 @@ export class JiraHandlers {
259
185
  }).join('\n\n');
260
186
  return successResponse(`${result.message}\n\n**Fields still requiring input:**\n${fieldInfo}`);
261
187
  }
262
- else {
263
- return {
264
- content: [{ type: 'text', text: result.message || 'Transition failed with unknown error' }],
265
- isError: true,
266
- };
267
- }
268
- }
269
- catch (error) {
270
- return errorResponse(error, {
271
- operation: `Failed to transition Jira issue ${issueKey} (interactive mode)`,
272
- params: {
273
- 'Transition ID': transitionId,
274
- 'Field Values': JSON.stringify(fieldValues || {}, null, 2),
275
- },
276
- tip: ERROR_TIPS.JIRA_TRANSITION,
277
- });
278
- }
188
+ return { content: [{ type: 'text', text: result.message || 'Transition failed with unknown error' }], isError: true };
189
+ });
279
190
  }
280
191
  async getAttachments(args) {
281
192
  const { issueKey } = args;
282
- try {
283
- const attachments = await this.service.getAttachments(issueKey);
284
- return jsonResponse(attachments);
285
- }
286
- catch (error) {
287
- return errorResponse(error, {
288
- operation: 'Failed to get attachments for Jira issue',
289
- params: { 'Issue Key': issueKey },
290
- tip: ERROR_TIPS.JIRA_ISSUE_VIEW,
291
- });
292
- }
193
+ return this.handle(() => this.service.getAttachments(issueKey), { operation: 'Failed to get attachments for Jira issue', params: { 'Issue Key': issueKey }, tip: ERROR_TIPS.JIRA_ISSUE_VIEW }, jsonResponse);
293
194
  }
294
195
  async addAttachment(args) {
295
196
  const { issueKey, filename, fileContent } = args;
296
- try {
297
- const result = await this.service.addAttachment(issueKey, filename, fileContent);
298
- return successResponse(`Attachment "${filename}" added to issue ${issueKey}\n\n${JSON.stringify(result, null, 2)}`);
299
- }
300
- catch (error) {
301
- return errorResponse(error, {
302
- operation: 'Failed to add attachment to Jira issue',
303
- params: { 'Issue Key': issueKey, Filename: filename },
304
- tip: ERROR_TIPS.JIRA_ATTACHMENT,
305
- });
306
- }
197
+ return this.handle(() => this.service.addAttachment(issueKey, filename, fileContent), { operation: 'Failed to add attachment to Jira issue', params: { 'Issue Key': issueKey, Filename: filename }, tip: ERROR_TIPS.JIRA_ATTACHMENT }, (result) => successResponse(`Attachment "${filename}" added to issue ${issueKey}\n\n${JSON.stringify(result, null, 2)}`));
307
198
  }
308
199
  async deleteAttachment(args) {
309
200
  const { attachmentId } = args;
310
- try {
311
- await this.service.deleteAttachment(attachmentId);
312
- return successResponse(`Attachment ${attachmentId} deleted successfully`);
313
- }
314
- catch (error) {
315
- return errorResponse(error, {
316
- operation: 'Failed to delete attachment',
317
- params: { 'Attachment ID': attachmentId },
318
- tip: 'Check if the attachment exists and you have permission to delete it.',
319
- });
320
- }
201
+ return this.handle(() => this.service.deleteAttachment(attachmentId), { operation: 'Failed to delete attachment', params: { 'Attachment ID': attachmentId }, tip: 'Check if the attachment exists and you have permission to delete it.' }, () => successResponse(`Attachment ${attachmentId} deleted successfully`));
321
202
  }
322
203
  async getIssueLinks(args) {
323
204
  const { issueKey } = args;
324
- try {
325
- const links = await this.service.getIssueLinks(issueKey);
326
- return jsonResponse(links);
327
- }
328
- catch (error) {
329
- return errorResponse(error, {
330
- operation: 'Failed to get issue links',
331
- params: { 'Issue Key': issueKey },
332
- tip: ERROR_TIPS.JIRA_ISSUE_VIEW,
333
- });
334
- }
205
+ return this.handle(() => this.service.getIssueLinks(issueKey), { operation: 'Failed to get issue links', params: { 'Issue Key': issueKey }, tip: ERROR_TIPS.JIRA_ISSUE_VIEW }, jsonResponse);
335
206
  }
336
207
  async createIssueLink(args) {
337
208
  const { inwardIssueKey, outwardIssueKey, linkType } = args;
338
- try {
339
- await this.service.createIssueLink(inwardIssueKey, outwardIssueKey, linkType);
340
- return successResponse(`Link created: ${inwardIssueKey} ${linkType} ${outwardIssueKey}`);
341
- }
342
- catch (error) {
343
- return errorResponse(error, {
344
- operation: 'Failed to create issue link',
345
- params: { 'Inward Issue': inwardIssueKey, 'Outward Issue': outwardIssueKey, 'Link Type': linkType },
346
- tip: ERROR_TIPS.JIRA_LINK,
347
- });
348
- }
209
+ return this.handle(() => this.service.createIssueLink(inwardIssueKey, outwardIssueKey, linkType), { operation: 'Failed to create issue link', params: { 'Inward Issue': inwardIssueKey, 'Outward Issue': outwardIssueKey, 'Link Type': linkType }, tip: ERROR_TIPS.JIRA_LINK }, () => successResponse(`Link created: ${inwardIssueKey} ${linkType} ${outwardIssueKey}`));
349
210
  }
350
211
  async deleteIssueLink(args) {
351
212
  const { linkId } = args;
352
- try {
353
- await this.service.deleteIssueLink(linkId);
354
- return successResponse(`Issue link ${linkId} deleted successfully`);
355
- }
356
- catch (error) {
357
- return errorResponse(error, {
358
- operation: 'Failed to delete issue link',
359
- params: { 'Link ID': linkId },
360
- tip: 'Check if the link exists and you have permission to delete it. Use jira_get_issue_links to get link IDs.',
361
- });
362
- }
213
+ return this.handle(() => this.service.deleteIssueLink(linkId), { operation: 'Failed to delete issue link', params: { 'Link ID': linkId }, tip: 'Check if the link exists and you have permission to delete it. Use jira_get_issue_links to get link IDs.' }, () => successResponse(`Issue link ${linkId} deleted successfully`));
363
214
  }
364
215
  async getLinkTypes() {
365
- try {
366
- const linkTypes = await this.service.getIssueLinkTypes();
367
- return jsonResponse(linkTypes);
368
- }
369
- catch (error) {
370
- return errorResponse(error, {
371
- operation: 'Failed to get issue link types',
372
- tip: 'Check your Jira permissions and API access.',
373
- });
374
- }
216
+ return this.handle(() => this.service.getIssueLinkTypes(), { operation: 'Failed to get issue link types', tip: 'Check your Jira permissions and API access.' }, jsonResponse);
375
217
  }
376
218
  async getWorklogs(args) {
377
219
  const { issueKey } = args;
378
- try {
379
- const worklogs = await this.service.getWorkLogs(issueKey);
380
- return jsonResponse(worklogs);
381
- }
382
- catch (error) {
383
- return errorResponse(error, {
384
- operation: 'Failed to get work logs',
385
- params: { 'Issue Key': issueKey },
386
- tip: ERROR_TIPS.JIRA_ISSUE_VIEW,
387
- });
388
- }
220
+ return this.handle(() => this.service.getWorkLogs(issueKey), { operation: 'Failed to get work logs', params: { 'Issue Key': issueKey }, tip: ERROR_TIPS.JIRA_ISSUE_VIEW }, jsonResponse);
389
221
  }
390
222
  async addWorklog(args) {
391
223
  const { issueKey, timeSpentSeconds, comment, started } = args;
392
- try {
393
- const result = await this.service.addWorkLog(issueKey, timeSpentSeconds, comment, started);
224
+ return this.handle(() => this.service.addWorkLog(issueKey, timeSpentSeconds, comment, started), { operation: 'Failed to add work log', params: { 'Issue Key': issueKey, 'Time Spent': `${timeSpentSeconds}s`, Comment: comment || 'none' }, tip: ERROR_TIPS.JIRA_WORKLOG }, (result) => {
394
225
  const hours = Math.floor(timeSpentSeconds / 3600);
395
226
  const minutes = Math.floor((timeSpentSeconds % 3600) / 60);
396
227
  return successResponse(`Work log added to ${issueKey}\nTime spent: ${hours}h ${minutes}m\n\n${JSON.stringify(result, null, 2)}`);
397
- }
398
- catch (error) {
399
- return errorResponse(error, {
400
- operation: 'Failed to add work log',
401
- params: { 'Issue Key': issueKey, 'Time Spent': `${timeSpentSeconds}s`, Comment: comment || 'none' },
402
- tip: ERROR_TIPS.JIRA_WORKLOG,
403
- });
404
- }
228
+ });
405
229
  }
406
230
  async updateWorklog(args) {
407
231
  const { issueKey, worklogId, timeSpentSeconds, comment } = args;
408
- try {
409
- const result = await this.service.updateWorkLog(issueKey, worklogId, timeSpentSeconds, comment);
410
- return successResponse(`Work log ${worklogId} updated\n\n${JSON.stringify(result, null, 2)}`);
411
- }
412
- catch (error) {
413
- return errorResponse(error, {
414
- operation: 'Failed to update work log',
415
- params: { 'Issue Key': issueKey, 'Worklog ID': worklogId },
416
- tip: ERROR_TIPS.JIRA_WORKLOG,
417
- });
418
- }
232
+ return this.handle(() => this.service.updateWorkLog(issueKey, worklogId, timeSpentSeconds, comment), { operation: 'Failed to update work log', params: { 'Issue Key': issueKey, 'Worklog ID': worklogId }, tip: ERROR_TIPS.JIRA_WORKLOG }, (result) => successResponse(`Work log ${worklogId} updated\n\n${JSON.stringify(result, null, 2)}`));
419
233
  }
420
234
  async deleteWorklog(args) {
421
235
  const { issueKey, worklogId } = args;
422
- try {
423
- await this.service.deleteWorkLog(issueKey, worklogId);
424
- return successResponse(`Work log ${worklogId} deleted from ${issueKey}`);
425
- }
426
- catch (error) {
427
- return errorResponse(error, {
428
- operation: 'Failed to delete work log',
429
- params: { 'Issue Key': issueKey, 'Worklog ID': worklogId },
430
- tip: ERROR_TIPS.JIRA_WORKLOG,
431
- });
432
- }
236
+ return this.handle(() => this.service.deleteWorkLog(issueKey, worklogId), { operation: 'Failed to delete work log', params: { 'Issue Key': issueKey, 'Worklog ID': worklogId }, tip: ERROR_TIPS.JIRA_WORKLOG }, () => successResponse(`Work log ${worklogId} deleted from ${issueKey}`));
433
237
  }
434
238
  async getWatchers(args) {
435
239
  const { issueKey } = args;
436
- try {
437
- const watchers = await this.service.getWatchers(issueKey);
438
- return jsonResponse(watchers);
439
- }
440
- catch (error) {
441
- return errorResponse(error, {
442
- operation: 'Failed to get watchers',
443
- params: { 'Issue Key': issueKey },
444
- tip: ERROR_TIPS.JIRA_ISSUE_VIEW,
445
- });
446
- }
240
+ return this.handle(() => this.service.getWatchers(issueKey), { operation: 'Failed to get watchers', params: { 'Issue Key': issueKey }, tip: ERROR_TIPS.JIRA_ISSUE_VIEW }, jsonResponse);
447
241
  }
448
242
  async addWatcher(args) {
449
243
  const { issueKey, accountId } = args;
450
- try {
451
- await this.service.addWatcher(issueKey, accountId);
452
- return successResponse(`Watcher added to ${issueKey}`);
453
- }
454
- catch (error) {
455
- return errorResponse(error, {
456
- operation: 'Failed to add watcher',
457
- params: { 'Issue Key': issueKey, 'Account ID': accountId },
458
- tip: ERROR_TIPS.JIRA_WATCHER,
459
- });
460
- }
244
+ return this.handle(() => this.service.addWatcher(issueKey, accountId), { operation: 'Failed to add watcher', params: { 'Issue Key': issueKey, 'Account ID': accountId }, tip: ERROR_TIPS.JIRA_WATCHER }, () => successResponse(`Watcher added to ${issueKey}`));
461
245
  }
462
246
  async removeWatcher(args) {
463
247
  const { issueKey, accountId } = args;
464
- try {
465
- await this.service.removeWatcher(issueKey, accountId);
466
- return successResponse(`Watcher removed from ${issueKey}`);
467
- }
468
- catch (error) {
469
- return errorResponse(error, {
470
- operation: 'Failed to remove watcher',
471
- params: { 'Issue Key': issueKey, 'Account ID': accountId },
472
- tip: 'Check if the issue exists and you have permission to remove watchers.',
473
- });
474
- }
248
+ return this.handle(() => this.service.removeWatcher(issueKey, accountId), { operation: 'Failed to remove watcher', params: { 'Issue Key': issueKey, 'Account ID': accountId }, tip: 'Check if the issue exists and you have permission to remove watchers.' }, () => successResponse(`Watcher removed from ${issueKey}`));
475
249
  }
476
250
  async getSubtasks(args) {
477
251
  const { issueKey } = args;
478
- try {
479
- const subtasks = await this.service.getSubTasks(issueKey);
480
- return jsonResponse(subtasks);
481
- }
482
- catch (error) {
483
- return errorResponse(error, {
484
- operation: 'Failed to get sub-tasks',
485
- params: { 'Issue Key': issueKey },
486
- tip: ERROR_TIPS.JIRA_ISSUE_VIEW,
487
- });
488
- }
252
+ return this.handle(() => this.service.getSubTasks(issueKey), { operation: 'Failed to get sub-tasks', params: { 'Issue Key': issueKey }, tip: ERROR_TIPS.JIRA_ISSUE_VIEW }, jsonResponse);
489
253
  }
490
254
  async createSubtask(args) {
491
255
  const { parentKey, summary, description } = args;
492
- try {
493
- const subtask = await this.service.createSubTask(parentKey, summary, description);
494
- return successResponse(`Sub-task created: ${subtask.key}\n\n${JSON.stringify(subtask, null, 2)}`);
495
- }
496
- catch (error) {
497
- return errorResponse(error, {
498
- operation: 'Failed to create sub-task',
499
- params: { 'Parent Key': parentKey, Summary: summary },
500
- tip: ERROR_TIPS.JIRA_SUBTASK,
501
- });
502
- }
256
+ return this.handle(() => this.service.createSubTask(parentKey, summary, description), { operation: 'Failed to create sub-task', params: { 'Parent Key': parentKey, Summary: summary }, tip: ERROR_TIPS.JIRA_SUBTASK }, (subtask) => successResponse(`Sub-task created: ${subtask.key}\n\n${JSON.stringify(subtask, null, 2)}`));
503
257
  }
504
258
  async getIssueHistory(args) {
505
259
  const { issueKey } = args;
506
- try {
507
- const history = await this.service.getIssueHistory(issueKey);
508
- return jsonResponse(history);
509
- }
510
- catch (error) {
511
- return errorResponse(error, {
512
- operation: 'Failed to get issue history',
513
- params: { 'Issue Key': issueKey },
514
- tip: ERROR_TIPS.JIRA_ISSUE_VIEW,
515
- });
516
- }
260
+ return this.handle(() => this.service.getIssueHistory(issueKey), { operation: 'Failed to get issue history', params: { 'Issue Key': issueKey }, tip: ERROR_TIPS.JIRA_ISSUE_VIEW }, jsonResponse);
517
261
  }
518
262
  async getFields(args) {
519
- const { type } = args;
520
- try {
521
- const filterType = (type === 'standard' || type === 'custom') ? type : undefined;
522
- const fields = await this.service.getFields(filterType);
523
- return jsonResponse(fields);
524
- }
525
- catch (error) {
526
- return errorResponse(error, {
527
- operation: 'Failed to get Jira fields',
528
- tip: 'Check your Jira permissions and API access.',
529
- });
530
- }
263
+ const { type, query } = args;
264
+ const filterType = (type === 'standard' || type === 'custom') ? type : undefined;
265
+ return this.handle(() => this.service.getFields(filterType, query), { operation: 'Failed to get Jira fields', tip: 'Check your Jira permissions and API access.' }, jsonResponse);
531
266
  }
532
267
  async getLabels(args) {
533
268
  const { query, maxResults } = args;
534
- try {
535
- const labels = await this.service.getLabels(query, maxResults);
536
- return jsonResponse(labels);
537
- }
538
- catch (error) {
539
- return errorResponse(error, {
540
- operation: 'Failed to get labels',
541
- params: { Query: query || 'none', 'Max Results': maxResults || 50 },
542
- tip: 'Check your Jira permissions and API access.',
543
- });
544
- }
269
+ return this.handle(() => this.service.getLabels(query, maxResults), { operation: 'Failed to get labels', params: { Query: query || 'none', 'Max Results': maxResults || 50 }, tip: 'Check your Jira permissions and API access.' }, jsonResponse);
545
270
  }
546
271
  async addLabels(args) {
547
272
  const { issueKey, labels } = args;
548
- try {
549
- await this.service.addLabels(issueKey, labels);
550
- return successResponse(`${ICONS.SUCCESS} Labels added to ${issueKey}\n\n` +
551
- `${ICONS.LABELS} **Added:** ${labels.join(', ')}`);
552
- }
553
- catch (error) {
554
- return errorResponse(error, {
555
- operation: `Failed to add labels to ${issueKey}`,
556
- params: { 'Issue Key': issueKey, Labels: labels.join(', ') },
557
- tip: ERROR_TIPS.JIRA_ISSUE_EDIT,
558
- });
559
- }
273
+ return this.handle(() => this.service.addLabels(issueKey, labels), { operation: `Failed to add labels to ${issueKey}`, params: { 'Issue Key': issueKey, Labels: labels.join(', ') }, tip: ERROR_TIPS.JIRA_ISSUE_EDIT }, () => successResponse(`${ICONS.SUCCESS} Labels added to ${issueKey}\n\n` +
274
+ `${ICONS.LABELS} **Added:** ${labels.join(', ')}`));
560
275
  }
561
276
  async removeLabels(args) {
562
277
  const { issueKey, labels } = args;
563
- try {
564
- await this.service.removeLabels(issueKey, labels);
565
- return successResponse(`${ICONS.SUCCESS} Labels removed from ${issueKey}\n\n` +
566
- `${ICONS.LABELS} **Removed:** ${labels.join(', ')}`);
567
- }
568
- catch (error) {
569
- return errorResponse(error, {
570
- operation: `Failed to remove labels from ${issueKey}`,
571
- params: { 'Issue Key': issueKey, Labels: labels.join(', ') },
572
- tip: ERROR_TIPS.JIRA_ISSUE_EDIT,
573
- });
574
- }
278
+ return this.handle(() => this.service.removeLabels(issueKey, labels), { operation: `Failed to remove labels from ${issueKey}`, params: { 'Issue Key': issueKey, Labels: labels.join(', ') }, tip: ERROR_TIPS.JIRA_ISSUE_EDIT }, () => successResponse(`${ICONS.SUCCESS} Labels removed from ${issueKey}\n\n` +
279
+ `${ICONS.LABELS} **Removed:** ${labels.join(', ')}`));
575
280
  }
576
281
  async getAgileBoards(args) {
577
- try {
578
- const boards = await this.service.getAgileBoards(args);
579
- return jsonResponse(boards);
580
- }
581
- catch (error) {
582
- return errorResponse(error, {
583
- operation: 'Failed to get agile boards',
584
- params: { Name: args.name || 'all', Type: args.type || 'all', Project: args.projectKeyOrId || 'all' },
585
- tip: ERROR_TIPS.JIRA_AGILE,
586
- });
587
- }
282
+ return this.handle(() => this.service.getAgileBoards(args), { operation: 'Failed to get agile boards', params: { Name: args.name || 'all', Type: args.type || 'all', Project: args.projectKeyOrId || 'all' }, tip: ERROR_TIPS.JIRA_AGILE }, jsonResponse);
588
283
  }
589
284
  async getBoardIssues(args) {
590
285
  const { boardId, jql, maxResults, startAt } = args;
591
- try {
592
- const result = await this.service.getBoardIssues(boardId, { jql, maxResults, startAt });
593
- return jsonResponse(result);
594
- }
595
- catch (error) {
596
- return errorResponse(error, {
597
- operation: 'Failed to get board issues',
598
- params: { 'Board ID': boardId, JQL: jql || 'none' },
599
- tip: ERROR_TIPS.JIRA_AGILE,
600
- });
601
- }
286
+ return this.handle(() => this.service.getBoardIssues(boardId, { jql, maxResults, startAt }), { operation: 'Failed to get board issues', params: { 'Board ID': boardId, JQL: jql || 'none' }, tip: ERROR_TIPS.JIRA_AGILE }, jsonResponse);
602
287
  }
603
288
  async getSprints(args) {
604
289
  const { boardId, state } = args;
605
- try {
606
- const sprints = await this.service.getSprints(boardId, state);
607
- return jsonResponse(sprints);
608
- }
609
- catch (error) {
610
- return errorResponse(error, {
611
- operation: 'Failed to get sprints',
612
- params: { 'Board ID': boardId, State: state || 'all' },
613
- tip: ERROR_TIPS.JIRA_AGILE,
614
- });
615
- }
290
+ return this.handle(() => this.service.getSprints(boardId, state), { operation: 'Failed to get sprints', params: { 'Board ID': boardId, State: state || 'all' }, tip: ERROR_TIPS.JIRA_AGILE }, jsonResponse);
616
291
  }
617
292
  async getSprintIssues(args) {
618
293
  const { sprintId, jql, maxResults, startAt } = args;
619
- try {
620
- const result = await this.service.getSprintIssues(sprintId, { jql, maxResults, startAt });
621
- return jsonResponse(result);
622
- }
623
- catch (error) {
624
- return errorResponse(error, {
625
- operation: 'Failed to get sprint issues',
626
- params: { 'Sprint ID': sprintId, JQL: jql || 'none' },
627
- tip: ERROR_TIPS.JIRA_AGILE,
294
+ return this.handle(() => this.service.getSprintIssues(sprintId, { jql, maxResults, startAt }), { operation: 'Failed to get sprint issues', params: { 'Sprint ID': sprintId, JQL: jql || 'none' }, tip: ERROR_TIPS.JIRA_AGILE }, jsonResponse);
295
+ }
296
+ async moveIssuesToSprint(args) {
297
+ const { sprintId, issueKeys } = args;
298
+ if (!Array.isArray(issueKeys)) {
299
+ return errorResponse(new Error('Invalid issueKeys parameter'), {
300
+ operation: 'Failed to move issues to sprint',
301
+ params: { 'Sprint ID': sprintId },
302
+ tip: 'The "issueKeys" parameter must be an array of strings, e.g. ["PROJ-123", "PROJ-456"]. Do not pass it as a string.',
628
303
  });
629
304
  }
305
+ return this.handle(() => this.service.moveIssuesToSprint(sprintId, issueKeys), { operation: 'Failed to move issues to sprint', params: { 'Sprint ID': sprintId, Issues: issueKeys.join(', ') }, tip: ERROR_TIPS.JIRA_AGILE }, () => successResponse(`${ICONS.SUCCESS} **Moved ${issueKeys.length} issue(s) to sprint ${sprintId}**\n\n` +
306
+ `**Issues:** ${issueKeys.join(', ')}`));
630
307
  }
631
308
  async batchCreateIssues(args) {
632
309
  const { issues } = args;
633
- try {
634
- const result = await this.service.batchCreateIssues(issues);
310
+ return this.handle(() => this.service.batchCreateIssues(issues), { operation: 'Failed to batch create issues', params: { 'Issue Count': issues.length }, tip: ERROR_TIPS.JIRA_BATCH }, (result) => {
635
311
  const successCount = result.issues?.length || 0;
636
312
  const errorCount = result.errors?.length || 0;
637
313
  return successResponse(`${ICONS.SUCCESS} Batch create completed: ${successCount} created, ${errorCount} errors\n\n${JSON.stringify(result, null, 2)}`);
638
- }
639
- catch (error) {
640
- return errorResponse(error, {
641
- operation: 'Failed to batch create issues',
642
- params: { 'Issue Count': issues.length },
643
- tip: ERROR_TIPS.JIRA_BATCH,
644
- });
645
- }
314
+ });
646
315
  }
647
316
  async getDevStatus(args) {
648
317
  const { issueId, applicationType, dataType } = args;
649
- try {
650
- const result = await this.service.getDevStatus(issueId, applicationType, dataType);
651
- return jsonResponse(result);
652
- }
653
- catch (error) {
654
- return errorResponse(error, {
655
- operation: 'Failed to get dev status',
656
- params: { 'Issue ID': issueId, 'Application Type': applicationType || 'all', 'Data Type': dataType || 'all' },
657
- tip: ERROR_TIPS.JIRA_DEV_STATUS,
658
- });
659
- }
318
+ return this.handle(() => this.service.getDevStatus(issueId, applicationType, dataType), { operation: 'Failed to get dev status', params: { 'Issue ID': issueId, 'Application Type': applicationType || 'all', 'Data Type': dataType || 'all' }, tip: ERROR_TIPS.JIRA_DEV_STATUS }, jsonResponse);
660
319
  }
661
320
  async deleteIssue(args) {
662
321
  const { issueKey, deleteSubtasks } = args;
663
- try {
664
- await this.service.deleteIssue(issueKey, deleteSubtasks);
665
- return successResponse(`${ICONS.SUCCESS} Issue ${issueKey} deleted successfully` +
666
- (deleteSubtasks ? ' (including subtasks)' : ''));
667
- }
668
- catch (error) {
669
- return errorResponse(error, {
670
- operation: `Failed to delete issue ${issueKey}`,
671
- params: { 'Issue Key': issueKey, 'Delete Subtasks': deleteSubtasks || false },
672
- tip: ERROR_TIPS.JIRA_DELETE,
673
- });
674
- }
322
+ return this.handle(() => this.service.deleteIssue(issueKey, deleteSubtasks), { operation: `Failed to delete issue ${issueKey}`, params: { 'Issue Key': issueKey, 'Delete Subtasks': deleteSubtasks || false }, tip: ERROR_TIPS.JIRA_DELETE }, () => successResponse(`${ICONS.SUCCESS} Issue ${issueKey} deleted successfully` +
323
+ (deleteSubtasks ? ' (including subtasks)' : '')));
675
324
  }
676
325
  async lookupUser(args) {
677
326
  const { query } = args;
678
- try {
679
- const users = await this.service.getUsersByQuery(query);
680
- return jsonResponse(users.map((u) => ({
681
- accountId: u.accountId,
682
- displayName: u.displayName,
683
- emailAddress: u.emailAddress || null,
684
- active: u.active,
685
- })));
686
- }
687
- catch (error) {
688
- return errorResponse(error, {
689
- operation: 'Failed to look up user',
690
- params: { Query: query },
691
- tip: 'Check your Jira permissions. Search by display name or email address.',
692
- });
693
- }
327
+ return this.handle(() => this.service.getUsersByQuery(query), { operation: 'Failed to look up user', params: { Query: query }, tip: 'Check your Jira permissions. Search by display name or email address.' }, (users) => jsonResponse(users.map((u) => ({
328
+ accountId: u.accountId,
329
+ displayName: u.displayName,
330
+ emailAddress: u.emailAddress || null,
331
+ active: u.active,
332
+ }))));
694
333
  }
695
334
  async getIssueTypes(args) {
696
335
  const { projectKey } = args;
697
- try {
698
- const issueTypes = await this.service.getIssueTypes(projectKey);
699
- return jsonResponse(issueTypes);
700
- }
701
- catch (error) {
702
- return errorResponse(error, {
703
- operation: 'Failed to get issue types',
704
- params: { 'Project Key': projectKey },
705
- tip: 'Check if the project key exists and you have permission to view it.',
706
- });
707
- }
336
+ return this.handle(() => this.service.getIssueTypes(projectKey), { operation: 'Failed to get issue types', params: { 'Project Key': projectKey }, tip: 'Check if the project key exists and you have permission to view it.' }, jsonResponse);
708
337
  }
709
338
  async createSprint(args) {
710
339
  const { boardId, name, startDate, endDate, goal } = args;
711
- try {
712
- const sprint = await this.service.createSprint(boardId, name, { startDate, endDate, goal });
713
- return successResponse(`${ICONS.SUCCESS} Sprint created successfully\n\n` +
714
- `**ID:** ${sprint.id}\n` +
715
- `**Name:** ${sprint.name}\n` +
716
- `**State:** ${sprint.state}\n` +
717
- (sprint.startDate ? `**Start:** ${sprint.startDate}\n` : '') +
718
- (sprint.endDate ? `**End:** ${sprint.endDate}\n` : '') +
719
- (sprint.goal ? `**Goal:** ${sprint.goal}` : ''));
720
- }
721
- catch (error) {
722
- return errorResponse(error, {
723
- operation: 'Failed to create sprint',
724
- params: { 'Board ID': boardId, Name: name },
725
- tip: ERROR_TIPS.JIRA_AGILE,
726
- });
727
- }
340
+ return this.handle(() => this.service.createSprint(boardId, name, { startDate, endDate, goal }), { operation: 'Failed to create sprint', params: { 'Board ID': boardId, Name: name }, tip: ERROR_TIPS.JIRA_AGILE }, (sprint) => successResponse(`${ICONS.SUCCESS} Sprint created successfully\n\n` +
341
+ `**ID:** ${sprint.id}\n` +
342
+ `**Name:** ${sprint.name}\n` +
343
+ `**State:** ${sprint.state}\n` +
344
+ (sprint.startDate ? `**Start:** ${sprint.startDate}\n` : '') +
345
+ (sprint.endDate ? `**End:** ${sprint.endDate}\n` : '') +
346
+ (sprint.goal ? `**Goal:** ${sprint.goal}` : '')));
728
347
  }
729
348
  async updateSprint(args) {
730
349
  const { sprintId, name, state, startDate, endDate, goal } = args;
731
- try {
732
- const sprint = await this.service.updateSprint(sprintId, { name, state, startDate, endDate, goal });
733
- return successResponse(`${ICONS.SUCCESS} Sprint ${sprintId} updated successfully\n\n` +
734
- `**Name:** ${sprint.name}\n` +
735
- `**State:** ${sprint.state}\n` +
736
- (sprint.startDate ? `**Start:** ${sprint.startDate}\n` : '') +
737
- (sprint.endDate ? `**End:** ${sprint.endDate}\n` : '') +
738
- (sprint.goal ? `**Goal:** ${sprint.goal}` : ''));
739
- }
740
- catch (error) {
741
- return errorResponse(error, {
742
- operation: `Failed to update sprint ${sprintId}`,
743
- params: { 'Sprint ID': sprintId, Name: name || 'unchanged', State: state || 'unchanged' },
744
- tip: ERROR_TIPS.JIRA_AGILE,
745
- });
746
- }
350
+ return this.handle(() => this.service.updateSprint(sprintId, { name, state, startDate, endDate, goal }), { operation: `Failed to update sprint ${sprintId}`, params: { 'Sprint ID': sprintId, Name: name || 'unchanged', State: state || 'unchanged' }, tip: ERROR_TIPS.JIRA_AGILE }, (sprint) => successResponse(`${ICONS.SUCCESS} Sprint ${sprintId} updated successfully\n\n` +
351
+ `**Name:** ${sprint.name}\n` +
352
+ `**State:** ${sprint.state}\n` +
353
+ (sprint.startDate ? `**Start:** ${sprint.startDate}\n` : '') +
354
+ (sprint.endDate ? `**End:** ${sprint.endDate}\n` : '') +
355
+ (sprint.goal ? `**Goal:** ${sprint.goal}` : '')));
747
356
  }
748
357
  async getProjectVersions(args) {
749
358
  const { projectKey } = args;
750
- try {
751
- const versions = await this.service.getProjectVersions(projectKey);
752
- return jsonResponse(versions);
753
- }
754
- catch (error) {
755
- return errorResponse(error, {
756
- operation: 'Failed to get project versions',
757
- params: { 'Project Key': projectKey },
758
- tip: 'Check if the project key exists and you have permission to view versions.',
759
- });
760
- }
359
+ return this.handle(() => this.service.getProjectVersions(projectKey), { operation: 'Failed to get project versions', params: { 'Project Key': projectKey }, tip: 'Check if the project key exists and you have permission to view versions.' }, jsonResponse);
761
360
  }
762
361
  async createVersion(args) {
763
362
  const { projectKey, name, description, startDate, releaseDate, released } = args;
764
- try {
765
- const version = await this.service.createVersion(projectKey, name, { description, startDate, releaseDate, released });
766
- return successResponse(`${ICONS.SUCCESS} Version created successfully\n\n` +
767
- `**ID:** ${version.id}\n` +
768
- `**Name:** ${version.name}\n` +
769
- `**Released:** ${version.released}\n` +
770
- (version.description ? `**Description:** ${version.description}\n` : '') +
771
- (version.startDate ? `**Start Date:** ${version.startDate}\n` : '') +
772
- (version.releaseDate ? `**Release Date:** ${version.releaseDate}` : ''));
773
- }
774
- catch (error) {
775
- return errorResponse(error, {
776
- operation: 'Failed to create version',
777
- params: { 'Project Key': projectKey, Name: name },
778
- tip: 'Check if the project exists and you have permission to manage versions.',
779
- });
780
- }
363
+ return this.handle(() => this.service.createVersion(projectKey, name, { description, startDate, releaseDate, released }), { operation: 'Failed to create version', params: { 'Project Key': projectKey, Name: name }, tip: 'Check if the project exists and you have permission to manage versions.' }, (version) => successResponse(`${ICONS.SUCCESS} Version created successfully\n\n` +
364
+ `**ID:** ${version.id}\n` +
365
+ `**Name:** ${version.name}\n` +
366
+ `**Released:** ${version.released}\n` +
367
+ (version.description ? `**Description:** ${version.description}\n` : '') +
368
+ (version.startDate ? `**Start Date:** ${version.startDate}\n` : '') +
369
+ (version.releaseDate ? `**Release Date:** ${version.releaseDate}` : '')));
781
370
  }
782
371
  async updateVersion(args) {
783
372
  const { versionId, name, description, startDate, releaseDate, released, archived } = args;
784
- try {
785
- const version = await this.service.updateVersion(versionId, { name, description, startDate, releaseDate, released, archived });
786
- return successResponse(`${ICONS.SUCCESS} Version ${versionId} updated successfully\n\n` +
787
- `**Name:** ${version.name}\n` +
788
- `**Released:** ${version.released}\n` +
789
- `**Archived:** ${version.archived}\n` +
790
- (version.description ? `**Description:** ${version.description}\n` : '') +
791
- (version.releaseDate ? `**Release Date:** ${version.releaseDate}` : ''));
792
- }
793
- catch (error) {
794
- return errorResponse(error, {
795
- operation: `Failed to update version ${versionId}`,
796
- params: { 'Version ID': versionId },
797
- tip: 'Check if the version exists and you have permission to manage versions.',
798
- });
799
- }
373
+ return this.handle(() => this.service.updateVersion(versionId, { name, description, startDate, releaseDate, released, archived }), { operation: `Failed to update version ${versionId}`, params: { 'Version ID': versionId }, tip: 'Check if the version exists and you have permission to manage versions.' }, (version) => successResponse(`${ICONS.SUCCESS} Version ${versionId} updated successfully\n\n` +
374
+ `**Name:** ${version.name}\n` +
375
+ `**Released:** ${version.released}\n` +
376
+ `**Archived:** ${version.archived}\n` +
377
+ (version.description ? `**Description:** ${version.description}\n` : '') +
378
+ (version.releaseDate ? `**Release Date:** ${version.releaseDate}` : '')));
800
379
  }
801
380
  async linkToEpic(args) {
802
381
  const { issueKey, epicKey } = args;
803
- try {
804
- await this.service.linkToEpic(issueKey, epicKey);
805
- return successResponse(`${ICONS.SUCCESS} Issue ${issueKey} linked to epic ${epicKey}`);
806
- }
807
- catch (error) {
808
- return errorResponse(error, {
809
- operation: `Failed to link ${issueKey} to epic ${epicKey}`,
810
- params: { 'Issue Key': issueKey, 'Epic Key': epicKey },
811
- tip: 'Check that both issues exist, the epic is actually an Epic type, and you have edit permission.',
812
- });
813
- }
382
+ return this.handle(() => this.service.linkToEpic(issueKey, epicKey), { operation: `Failed to link ${issueKey} to epic ${epicKey}`, params: { 'Issue Key': issueKey, 'Epic Key': epicKey }, tip: 'Check that both issues exist, the epic is actually an Epic type, and you have edit permission.' }, () => successResponse(`${ICONS.SUCCESS} Issue ${issueKey} linked to epic ${epicKey}`));
814
383
  }
815
384
  }
816
385
  //# sourceMappingURL=jira-handlers.js.map