@agllama/mcp 0.1.0 → 0.1.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.
Files changed (93) hide show
  1. package/README.md +161 -162
  2. package/dist/api-client.d.ts +45 -2
  3. package/dist/api-client.d.ts.map +1 -1
  4. package/dist/api-client.js +108 -2
  5. package/dist/api-client.js.map +1 -1
  6. package/dist/server.d.ts.map +1 -1
  7. package/dist/server.js +140 -1
  8. package/dist/server.js.map +1 -1
  9. package/dist/tools/backlog.d.ts +13 -7
  10. package/dist/tools/backlog.d.ts.map +1 -1
  11. package/dist/tools/backlog.js +59 -9
  12. package/dist/tools/backlog.js.map +1 -1
  13. package/dist/tools/boardConfig.d.ts +65 -0
  14. package/dist/tools/boardConfig.d.ts.map +1 -0
  15. package/dist/tools/boardConfig.js +150 -0
  16. package/dist/tools/boardConfig.js.map +1 -0
  17. package/dist/tools/boardTemplates.d.ts +47 -0
  18. package/dist/tools/boardTemplates.d.ts.map +1 -0
  19. package/dist/tools/boardTemplates.js +119 -0
  20. package/dist/tools/boardTemplates.js.map +1 -0
  21. package/dist/tools/boards.d.ts +20 -20
  22. package/dist/tools/boards.d.ts.map +1 -1
  23. package/dist/tools/boards.js +121 -19
  24. package/dist/tools/boards.js.map +1 -1
  25. package/dist/tools/comments.d.ts +24 -24
  26. package/dist/tools/comments.d.ts.map +1 -1
  27. package/dist/tools/comments.js +136 -23
  28. package/dist/tools/comments.js.map +1 -1
  29. package/dist/tools/connect.d.ts.map +1 -1
  30. package/dist/tools/connect.js +7 -18
  31. package/dist/tools/connect.js.map +1 -1
  32. package/dist/tools/context.d.ts +10 -7
  33. package/dist/tools/context.d.ts.map +1 -1
  34. package/dist/tools/context.js +57 -7
  35. package/dist/tools/context.js.map +1 -1
  36. package/dist/tools/documents.d.ts +99 -0
  37. package/dist/tools/documents.d.ts.map +1 -0
  38. package/dist/tools/documents.js +252 -0
  39. package/dist/tools/documents.js.map +1 -0
  40. package/dist/tools/help.d.ts.map +1 -1
  41. package/dist/tools/help.js +70 -6
  42. package/dist/tools/help.js.map +1 -1
  43. package/dist/tools/index.d.ts +4 -0
  44. package/dist/tools/index.d.ts.map +1 -1
  45. package/dist/tools/index.js +4 -0
  46. package/dist/tools/index.js.map +1 -1
  47. package/dist/tools/issueLinks.d.ts +12 -12
  48. package/dist/tools/issueLinks.d.ts.map +1 -1
  49. package/dist/tools/issueLinks.js +69 -12
  50. package/dist/tools/issueLinks.js.map +1 -1
  51. package/dist/tools/issues.d.ts +208 -28
  52. package/dist/tools/issues.d.ts.map +1 -1
  53. package/dist/tools/issues.js +483 -35
  54. package/dist/tools/issues.js.map +1 -1
  55. package/dist/tools/labels.d.ts +18 -18
  56. package/dist/tools/labels.d.ts.map +1 -1
  57. package/dist/tools/labels.js +102 -17
  58. package/dist/tools/labels.js.map +1 -1
  59. package/dist/tools/members.d.ts.map +1 -1
  60. package/dist/tools/members.js +2 -2
  61. package/dist/tools/members.js.map +1 -1
  62. package/dist/tools/organizations.d.ts.map +1 -1
  63. package/dist/tools/organizations.js +8 -8
  64. package/dist/tools/organizations.js.map +1 -1
  65. package/dist/tools/projects.d.ts.map +1 -1
  66. package/dist/tools/projects.js +11 -11
  67. package/dist/tools/projects.js.map +1 -1
  68. package/dist/tools/search.d.ts +4 -4
  69. package/dist/tools/search.d.ts.map +1 -1
  70. package/dist/tools/search.js +28 -5
  71. package/dist/tools/search.js.map +1 -1
  72. package/dist/tools/session.d.ts +38 -0
  73. package/dist/tools/session.d.ts.map +1 -0
  74. package/dist/tools/session.js +158 -0
  75. package/dist/tools/session.js.map +1 -0
  76. package/dist/tools/sprints.d.ts +18 -18
  77. package/dist/tools/sprints.d.ts.map +1 -1
  78. package/dist/tools/sprints.js +115 -30
  79. package/dist/tools/sprints.js.map +1 -1
  80. package/dist/tools/status.d.ts +6 -6
  81. package/dist/tools/status.d.ts.map +1 -1
  82. package/dist/tools/status.js +45 -8
  83. package/dist/tools/status.js.map +1 -1
  84. package/dist/tools/workflows.d.ts.map +1 -1
  85. package/dist/tools/workflows.js +19 -19
  86. package/dist/tools/workflows.js.map +1 -1
  87. package/dist/types.d.ts +123 -1
  88. package/dist/types.d.ts.map +1 -1
  89. package/dist/utils/column-instructions.d.ts +21 -0
  90. package/dist/utils/column-instructions.d.ts.map +1 -0
  91. package/dist/utils/column-instructions.js +54 -0
  92. package/dist/utils/column-instructions.js.map +1 -0
  93. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"issues.d.ts","sourceRoot":"","sources":["../../src/tools/issues.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,eAAO,MAAM,gBAAgB,oBAAoB,CAAC;AAElD,eAAO,MAAM,uBAAuB,6JAC6C,CAAC;AAElF,eAAO,MAAM,kBAAkB;;;;;;;;;;;;EAI7B,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAEnE,wBAAsB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,CAmC/E;AAMD,eAAO,MAAM,mBAAmB,uBAAuB,CAAC;AAExD,eAAO,MAAM,0BAA0B,4QAMsB,CAAC;AAE9D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkBhC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEzE,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAuEjB;AAMD,eAAO,MAAM,mBAAmB,uBAAuB,CAAC;AAExD,eAAO,MAAM,0BAA0B,wJAE4B,CAAC;AAEpE,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0BhC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEzE,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAgFjB;AAMD,eAAO,MAAM,mBAAmB,uBAAuB,CAAC;AAExD,eAAO,MAAM,0BAA0B,mIACsB,CAAC;AAE9D,eAAO,MAAM,qBAAqB;;;;;;;;;;;;EAIhC,CAAC;AAEH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEzE,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,oBAAoB,GAC1B,OAAO,CAAC,MAAM,CAAC,CAmCjB"}
1
+ {"version":3,"file":"issues.d.ts","sourceRoot":"","sources":["../../src/tools/issues.ts"],"names":[],"mappings":"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"}
@@ -1,24 +1,58 @@
1
1
  import { z } from 'zod';
2
2
  import { getApiClient, LlamaApiError } from '../api-client.js';
3
+ import { getColumnInstructionsForStatus } from '../utils/column-instructions.js';
4
+ import { getSessionDefaults } from './session.js';
3
5
  // ============================================
4
6
  // Get Issue
5
7
  // ============================================
6
8
  export const getIssueToolName = 'llama_get_issue';
7
9
  export const getIssueToolDescription = `Get full details for a specific issue by its key (e.g., "PROJ-123").
8
- Returns complete issue information including description, comments, and history.`;
10
+ Returns complete issue information including description, comments, and history. Uses session defaults if orgSlug/projectKey not provided.`;
9
11
  export const getIssueToolSchema = z.object({
10
- orgSlug: z.string().describe('Organization slug'),
11
- projectKey: z.string().describe('Project key'),
12
+ orgSlug: z
13
+ .string()
14
+ .optional()
15
+ .describe('Organization slug (uses session default if not provided)'),
16
+ projectKey: z
17
+ .string()
18
+ .optional()
19
+ .describe('Project key (uses session default if not provided)'),
12
20
  issueKey: z.string().describe('Issue key (e.g., "PROJ-123")'),
13
21
  });
14
22
  export async function executeGetIssue(input) {
15
23
  try {
24
+ const session = await getSessionDefaults();
25
+ const orgSlug = input.orgSlug ?? session?.orgSlug;
26
+ const projectKey = input.projectKey ?? session?.projectKey;
27
+ if (!orgSlug) {
28
+ return JSON.stringify({
29
+ success: false,
30
+ error: 'orgSlug is required. Either provide it or set session context with llama_set_context first.',
31
+ });
32
+ }
33
+ if (!projectKey) {
34
+ return JSON.stringify({
35
+ success: false,
36
+ error: 'projectKey is required. Either provide it or set session context with llama_set_context first.',
37
+ });
38
+ }
16
39
  const client = getApiClient();
17
- const issue = await client.getIssue(input.orgSlug, input.projectKey, input.issueKey);
40
+ // Record tool call
41
+ try {
42
+ await client.recordToolCall('llama_get_issue', {
43
+ orgSlug,
44
+ projectKey,
45
+ issueKey: input.issueKey,
46
+ });
47
+ }
48
+ catch {
49
+ // Ignore recording errors
50
+ }
51
+ const issue = await client.getIssue(orgSlug, projectKey, input.issueKey);
18
52
  return JSON.stringify({
19
53
  success: true,
20
54
  issue,
21
- }, null, 2);
55
+ });
22
56
  }
23
57
  catch (error) {
24
58
  if (error instanceof LlamaApiError) {
@@ -26,12 +60,12 @@ export async function executeGetIssue(input) {
26
60
  success: false,
27
61
  error: `Failed to get issue: ${error.message}`,
28
62
  statusCode: error.statusCode,
29
- }, null, 2);
63
+ });
30
64
  }
31
65
  return JSON.stringify({
32
66
  success: false,
33
67
  error: error instanceof Error ? error.message : 'Unknown error',
34
- }, null, 2);
68
+ });
35
69
  }
36
70
  }
37
71
  // ============================================
@@ -43,11 +77,19 @@ export const createIssueToolDescription = `Create a new issue in Llama.
43
77
  Issue types: EPIC, STORY, TASK, BUG, SUBTASK
44
78
  Priority levels: CRITICAL, HIGH, MEDIUM (default), LOW, TRIVIAL
45
79
 
46
- For subtasks, provide the parentKey of the parent issue.
47
- To add to a sprint, provide the sprintId from llama_context.`;
80
+ **IMPORTANT: SUBTASK type REQUIRES parentKey** - You must provide the parent issue key (e.g., "PROJ-123") when creating a subtask. The parent must be a STORY, TASK, or BUG.
81
+
82
+ To add to a sprint, provide the sprintId from llama_context.
83
+ Uses session defaults if orgSlug/projectKey not provided.`;
48
84
  export const createIssueToolSchema = z.object({
49
- orgSlug: z.string().describe('Organization slug'),
50
- projectKey: z.string().describe('Project key'),
85
+ orgSlug: z
86
+ .string()
87
+ .optional()
88
+ .describe('Organization slug (uses session default if not provided)'),
89
+ projectKey: z
90
+ .string()
91
+ .optional()
92
+ .describe('Project key (uses session default if not provided)'),
51
93
  summary: z.string().describe('Issue title/summary'),
52
94
  description: z.string().optional().describe('Detailed description (markdown supported)'),
53
95
  type: z
@@ -59,33 +101,67 @@ export const createIssueToolSchema = z.object({
59
101
  .describe('Priority level (default: MEDIUM)'),
60
102
  assigneeId: z.string().optional().describe('User ID to assign the issue to'),
61
103
  sprintId: z.string().optional().describe('Sprint ID to add the issue to'),
62
- parentKey: z.string().optional().describe('Parent issue key for subtasks (SUBTASK only)'),
104
+ parentKey: z.string().optional().describe('Parent issue key - REQUIRED for SUBTASK type (e.g., "PROJ-123"). Parent must be STORY, TASK, or BUG.'),
63
105
  epicKey: z.string().optional().describe('Epic issue key to link this issue to (for STORY, TASK, BUG)'),
64
106
  estimate: z.number().optional().describe('Story points estimate'),
65
107
  labels: z.array(z.string()).optional().describe('Labels to attach'),
66
108
  });
67
109
  export async function executeCreateIssue(input) {
68
110
  try {
111
+ const session = await getSessionDefaults();
112
+ const orgSlug = input.orgSlug ?? session?.orgSlug;
113
+ const projectKey = input.projectKey ?? session?.projectKey;
114
+ if (!orgSlug) {
115
+ return JSON.stringify({
116
+ success: false,
117
+ error: 'orgSlug is required. Either provide it or set session context with llama_set_context first.',
118
+ });
119
+ }
120
+ if (!projectKey) {
121
+ return JSON.stringify({
122
+ success: false,
123
+ error: 'projectKey is required. Either provide it or set session context with llama_set_context first.',
124
+ });
125
+ }
69
126
  const client = getApiClient();
127
+ // Validate SUBTASK requires parentKey
128
+ if (input.type === 'SUBTASK' && !input.parentKey) {
129
+ return JSON.stringify({
130
+ success: false,
131
+ error: 'SUBTASK type requires parentKey. You must specify the parent issue key (e.g., "PROJ-123") when creating a subtask. The parent must be a STORY, TASK, or BUG.',
132
+ });
133
+ }
70
134
  // Resolve epicKey to parentId if provided
71
135
  let parentId;
72
136
  if (input.epicKey) {
73
137
  // Look up the Epic to get its ID
74
- const epic = await client.getIssue(input.orgSlug, input.projectKey, input.epicKey);
138
+ const epic = await client.getIssue(orgSlug, projectKey, input.epicKey);
75
139
  if (epic.type !== 'EPIC') {
76
140
  return JSON.stringify({
77
141
  success: false,
78
142
  error: `Issue ${input.epicKey} is not an Epic (type: ${epic.type})`,
79
- }, null, 2);
143
+ });
80
144
  }
81
145
  parentId = epic.id;
82
146
  }
83
147
  else if (input.parentKey) {
84
148
  // For subtasks, look up the parent to get its ID
85
- const parent = await client.getIssue(input.orgSlug, input.projectKey, input.parentKey);
149
+ const parent = await client.getIssue(orgSlug, projectKey, input.parentKey);
86
150
  parentId = parent.id;
87
151
  }
88
- const issue = await client.createIssue(input.orgSlug, input.projectKey, {
152
+ // Record tool call
153
+ try {
154
+ await client.recordToolCall('llama_create_issue', {
155
+ orgSlug,
156
+ projectKey,
157
+ summary: input.summary,
158
+ type: input.type,
159
+ });
160
+ }
161
+ catch {
162
+ // Ignore recording errors
163
+ }
164
+ const issue = await client.createIssue(orgSlug, projectKey, {
89
165
  summary: input.summary,
90
166
  description: input.description,
91
167
  type: input.type,
@@ -106,7 +182,7 @@ export async function executeCreateIssue(input) {
106
182
  status: issue.status,
107
183
  priority: issue.priority,
108
184
  },
109
- }, null, 2);
185
+ });
110
186
  }
111
187
  catch (error) {
112
188
  if (error instanceof LlamaApiError) {
@@ -114,12 +190,12 @@ export async function executeCreateIssue(input) {
114
190
  success: false,
115
191
  error: `Failed to create issue: ${error.message}`,
116
192
  statusCode: error.statusCode,
117
- }, null, 2);
193
+ });
118
194
  }
119
195
  return JSON.stringify({
120
196
  success: false,
121
197
  error: error instanceof Error ? error.message : 'Unknown error',
122
- }, null, 2);
198
+ });
123
199
  }
124
200
  }
125
201
  // ============================================
@@ -128,10 +204,17 @@ export async function executeCreateIssue(input) {
128
204
  export const updateIssueToolName = 'llama_update_issue';
129
205
  export const updateIssueToolDescription = `Update an existing issue's fields.
130
206
  Only include the fields you want to change.
131
- Set assigneeId or sprintId to null to unassign/remove from sprint.`;
207
+ Set assigneeId or sprintId to null to unassign/remove from sprint.
208
+ Uses session defaults if orgSlug/projectKey not provided.`;
132
209
  export const updateIssueToolSchema = z.object({
133
- orgSlug: z.string().describe('Organization slug'),
134
- projectKey: z.string().describe('Project key'),
210
+ orgSlug: z
211
+ .string()
212
+ .optional()
213
+ .describe('Organization slug (uses session default if not provided)'),
214
+ projectKey: z
215
+ .string()
216
+ .optional()
217
+ .describe('Project key (uses session default if not provided)'),
135
218
  issueKey: z.string().describe('Issue key to update'),
136
219
  summary: z.string().optional().describe('New summary'),
137
220
  description: z.string().optional().describe('New description'),
@@ -158,7 +241,22 @@ export const updateIssueToolSchema = z.object({
158
241
  });
159
242
  export async function executeUpdateIssue(input) {
160
243
  try {
161
- const { orgSlug, projectKey, issueKey, ...updates } = input;
244
+ const session = await getSessionDefaults();
245
+ const orgSlug = input.orgSlug ?? session?.orgSlug;
246
+ const projectKey = input.projectKey ?? session?.projectKey;
247
+ if (!orgSlug) {
248
+ return JSON.stringify({
249
+ success: false,
250
+ error: 'orgSlug is required. Either provide it or set session context with llama_set_context first.',
251
+ });
252
+ }
253
+ if (!projectKey) {
254
+ return JSON.stringify({
255
+ success: false,
256
+ error: 'projectKey is required. Either provide it or set session context with llama_set_context first.',
257
+ });
258
+ }
259
+ const { issueKey, ...updates } = input;
162
260
  const client = getApiClient();
163
261
  // Build update object with only provided fields
164
262
  const updateFields = {};
@@ -192,13 +290,30 @@ export async function executeUpdateIssue(input) {
192
290
  return JSON.stringify({
193
291
  success: false,
194
292
  error: `Issue ${updates.epicKey} is not an Epic (type: ${epic.type})`,
195
- }, null, 2);
293
+ });
196
294
  }
197
295
  updateFields.parentId = epic.id;
198
296
  }
199
297
  }
298
+ // Record tool call
299
+ try {
300
+ await client.recordToolCall('llama_update_issue', {
301
+ orgSlug,
302
+ projectKey,
303
+ issueKey,
304
+ updates: Object.keys(updateFields),
305
+ });
306
+ }
307
+ catch {
308
+ // Ignore recording errors
309
+ }
200
310
  const issue = await client.updateIssue(orgSlug, projectKey, issueKey, updateFields);
201
- return JSON.stringify({
311
+ // Check if status was changed and get column instructions
312
+ let columnInstructions = null;
313
+ if (updates.statusId !== undefined) {
314
+ columnInstructions = await getColumnInstructionsForStatus(orgSlug, projectKey, updates.statusId);
315
+ }
316
+ const response = {
202
317
  success: true,
203
318
  message: `Updated issue ${issue.key}`,
204
319
  issue: {
@@ -209,7 +324,12 @@ export async function executeUpdateIssue(input) {
209
324
  priority: issue.priority,
210
325
  assignee: issue.assignee,
211
326
  },
212
- }, null, 2);
327
+ };
328
+ // Add column instructions if they exist
329
+ if (columnInstructions) {
330
+ response.columnInstructions = columnInstructions;
331
+ }
332
+ return JSON.stringify(response);
213
333
  }
214
334
  catch (error) {
215
335
  if (error instanceof LlamaApiError) {
@@ -217,12 +337,12 @@ export async function executeUpdateIssue(input) {
217
337
  success: false,
218
338
  error: `Failed to update issue: ${error.message}`,
219
339
  statusCode: error.statusCode,
220
- }, null, 2);
340
+ });
221
341
  }
222
342
  return JSON.stringify({
223
343
  success: false,
224
344
  error: error instanceof Error ? error.message : 'Unknown error',
225
- }, null, 2);
345
+ });
226
346
  }
227
347
  }
228
348
  // ============================================
@@ -230,20 +350,53 @@ export async function executeUpdateIssue(input) {
230
350
  // ============================================
231
351
  export const deleteIssueToolName = 'llama_delete_issue';
232
352
  export const deleteIssueToolDescription = `Soft-delete an issue. The issue can be restored later if needed.
233
- Use with caution - this action removes the issue from views.`;
353
+ Use with caution - this action removes the issue from views.
354
+ Uses session defaults if orgSlug/projectKey not provided.`;
234
355
  export const deleteIssueToolSchema = z.object({
235
- orgSlug: z.string().describe('Organization slug'),
236
- projectKey: z.string().describe('Project key'),
356
+ orgSlug: z
357
+ .string()
358
+ .optional()
359
+ .describe('Organization slug (uses session default if not provided)'),
360
+ projectKey: z
361
+ .string()
362
+ .optional()
363
+ .describe('Project key (uses session default if not provided)'),
237
364
  issueKey: z.string().describe('Issue key to delete'),
238
365
  });
239
366
  export async function executeDeleteIssue(input) {
240
367
  try {
368
+ const session = await getSessionDefaults();
369
+ const orgSlug = input.orgSlug ?? session?.orgSlug;
370
+ const projectKey = input.projectKey ?? session?.projectKey;
371
+ if (!orgSlug) {
372
+ return JSON.stringify({
373
+ success: false,
374
+ error: 'orgSlug is required. Either provide it or set session context with llama_set_context first.',
375
+ });
376
+ }
377
+ if (!projectKey) {
378
+ return JSON.stringify({
379
+ success: false,
380
+ error: 'projectKey is required. Either provide it or set session context with llama_set_context first.',
381
+ });
382
+ }
241
383
  const client = getApiClient();
242
- await client.deleteIssue(input.orgSlug, input.projectKey, input.issueKey);
384
+ // Record tool call
385
+ try {
386
+ await client.recordToolCall('llama_delete_issue', {
387
+ orgSlug,
388
+ projectKey,
389
+ issueKey: input.issueKey,
390
+ });
391
+ }
392
+ catch {
393
+ // Ignore recording errors
394
+ }
395
+ await client.deleteIssue(orgSlug, projectKey, input.issueKey);
243
396
  return JSON.stringify({
244
397
  success: true,
245
398
  message: `Deleted issue ${input.issueKey}`,
246
- }, null, 2);
399
+ });
247
400
  }
248
401
  catch (error) {
249
402
  if (error instanceof LlamaApiError) {
@@ -251,12 +404,307 @@ export async function executeDeleteIssue(input) {
251
404
  success: false,
252
405
  error: `Failed to delete issue: ${error.message}`,
253
406
  statusCode: error.statusCode,
254
- }, null, 2);
407
+ });
255
408
  }
256
409
  return JSON.stringify({
257
410
  success: false,
258
411
  error: error instanceof Error ? error.message : 'Unknown error',
259
- }, null, 2);
412
+ });
413
+ }
414
+ }
415
+ // ============================================
416
+ // Batch Create Issues
417
+ // ============================================
418
+ export const batchCreateIssuesToolName = 'llama_batch_create_issues';
419
+ export const batchCreateIssuesToolDescription = `Create multiple issues in one call (max 20).
420
+ Returns individual success/failure for each issue.
421
+ Uses session defaults if orgSlug/projectKey not provided.
422
+
423
+ **IMPORTANT: SUBTASK type REQUIRES parentKey** - When creating subtasks, you must provide the parentKey field.
424
+
425
+ Example:
426
+ issues: [
427
+ { summary: "Issue 1", type: "TASK" },
428
+ { summary: "Issue 2", type: "BUG", priority: "HIGH" },
429
+ { summary: "Subtask 1", type: "SUBTASK", parentKey: "PROJ-1" }
430
+ ]`;
431
+ export const batchCreateIssuesToolSchema = z.object({
432
+ orgSlug: z
433
+ .string()
434
+ .optional()
435
+ .describe('Organization slug (uses session default if not provided)'),
436
+ projectKey: z
437
+ .string()
438
+ .optional()
439
+ .describe('Project key (uses session default if not provided)'),
440
+ issues: z
441
+ .array(z.object({
442
+ summary: z.string().describe('Issue title/summary'),
443
+ type: z.enum(['EPIC', 'STORY', 'TASK', 'BUG', 'SUBTASK']).describe('Issue type'),
444
+ description: z.string().optional().nullable().describe('Description (markdown)'),
445
+ priority: z
446
+ .enum(['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'TRIVIAL'])
447
+ .optional()
448
+ .describe('Priority (default: MEDIUM)'),
449
+ assigneeId: z.string().optional().nullable().describe('Assignee user ID'),
450
+ sprintId: z.string().optional().nullable().describe('Sprint ID'),
451
+ estimate: z.number().optional().nullable().describe('Story points'),
452
+ labels: z.array(z.string()).optional().describe('Labels'),
453
+ epicKey: z.string().optional().nullable().describe('Epic key to link to (for STORY, TASK, BUG)'),
454
+ parentKey: z.string().optional().nullable().describe('Parent issue key - REQUIRED for SUBTASK type'),
455
+ }))
456
+ .min(1)
457
+ .max(20)
458
+ .describe('Issues to create (max 20)'),
459
+ });
460
+ export async function executeBatchCreateIssues(input) {
461
+ try {
462
+ const session = await getSessionDefaults();
463
+ const orgSlug = input.orgSlug ?? session?.orgSlug;
464
+ const projectKey = input.projectKey ?? session?.projectKey;
465
+ if (!orgSlug) {
466
+ return JSON.stringify({
467
+ success: false,
468
+ error: 'orgSlug is required. Either provide it or set session context with llama_set_context first.',
469
+ });
470
+ }
471
+ if (!projectKey) {
472
+ return JSON.stringify({
473
+ success: false,
474
+ error: 'projectKey is required. Either provide it or set session context with llama_set_context first.',
475
+ });
476
+ }
477
+ const client = getApiClient();
478
+ // Validate SUBTASK issues have parentKey
479
+ const subtasksWithoutParent = input.issues.filter((i) => i.type === 'SUBTASK' && !i.parentKey);
480
+ if (subtasksWithoutParent.length > 0) {
481
+ return JSON.stringify({
482
+ success: false,
483
+ error: `SUBTASK type requires parentKey. The following issues are missing parentKey: ${subtasksWithoutParent.map((i) => i.summary).join(', ')}`,
484
+ });
485
+ }
486
+ // Record tool call
487
+ try {
488
+ await client.recordToolCall('llama_batch_create_issues', {
489
+ orgSlug,
490
+ projectKey,
491
+ count: input.issues.length,
492
+ });
493
+ }
494
+ catch {
495
+ // Ignore recording errors
496
+ }
497
+ const issues = input.issues.map((i) => ({
498
+ summary: i.summary,
499
+ type: i.type,
500
+ description: i.description,
501
+ priority: i.priority,
502
+ assigneeId: i.assigneeId,
503
+ sprintId: i.sprintId,
504
+ estimate: i.estimate,
505
+ labels: i.labels,
506
+ epicKey: i.epicKey,
507
+ parentKey: i.parentKey,
508
+ }));
509
+ const result = await client.batchCreateIssues(orgSlug, projectKey, issues);
510
+ return JSON.stringify({
511
+ success: true,
512
+ message: `Created ${result.succeeded} of ${result.total} issues`,
513
+ ...result,
514
+ });
515
+ }
516
+ catch (error) {
517
+ if (error instanceof LlamaApiError) {
518
+ return JSON.stringify({
519
+ success: false,
520
+ error: `Failed to batch create issues: ${error.message}`,
521
+ statusCode: error.statusCode,
522
+ });
523
+ }
524
+ return JSON.stringify({
525
+ success: false,
526
+ error: error instanceof Error ? error.message : 'Unknown error',
527
+ });
528
+ }
529
+ }
530
+ // ============================================
531
+ // Batch Update Status
532
+ // ============================================
533
+ export const batchUpdateStatusToolName = 'llama_batch_update_status';
534
+ export const batchUpdateStatusToolDescription = `Move multiple issues to the same status in one call (max 50).
535
+ Returns individual success/failure for each issue.
536
+ Uses session defaults if orgSlug/projectKey not provided.
537
+
538
+ First use llama_context to get valid status IDs.`;
539
+ export const batchUpdateStatusToolSchema = z.object({
540
+ orgSlug: z
541
+ .string()
542
+ .optional()
543
+ .describe('Organization slug (uses session default if not provided)'),
544
+ projectKey: z
545
+ .string()
546
+ .optional()
547
+ .describe('Project key (uses session default if not provided)'),
548
+ issueKeys: z
549
+ .array(z.string())
550
+ .min(1)
551
+ .max(50)
552
+ .describe('Issue keys to update (max 50)'),
553
+ statusId: z.string().describe('Target status ID (from llama_context)'),
554
+ });
555
+ export async function executeBatchUpdateStatus(input) {
556
+ try {
557
+ const session = await getSessionDefaults();
558
+ const orgSlug = input.orgSlug ?? session?.orgSlug;
559
+ const projectKey = input.projectKey ?? session?.projectKey;
560
+ if (!orgSlug) {
561
+ return JSON.stringify({
562
+ success: false,
563
+ error: 'orgSlug is required. Either provide it or set session context with llama_set_context first.',
564
+ });
565
+ }
566
+ if (!projectKey) {
567
+ return JSON.stringify({
568
+ success: false,
569
+ error: 'projectKey is required. Either provide it or set session context with llama_set_context first.',
570
+ });
571
+ }
572
+ const client = getApiClient();
573
+ // Record tool call
574
+ try {
575
+ await client.recordToolCall('llama_batch_update_status', {
576
+ orgSlug,
577
+ projectKey,
578
+ count: input.issueKeys.length,
579
+ statusId: input.statusId,
580
+ });
581
+ }
582
+ catch {
583
+ // Ignore recording errors
584
+ }
585
+ const result = await client.batchUpdateStatus(orgSlug, projectKey, input.issueKeys, input.statusId);
586
+ return JSON.stringify({
587
+ success: true,
588
+ message: `Updated ${result.succeeded} of ${result.total} issues`,
589
+ ...result,
590
+ });
591
+ }
592
+ catch (error) {
593
+ if (error instanceof LlamaApiError) {
594
+ return JSON.stringify({
595
+ success: false,
596
+ error: `Failed to batch update status: ${error.message}`,
597
+ statusCode: error.statusCode,
598
+ });
599
+ }
600
+ return JSON.stringify({
601
+ success: false,
602
+ error: error instanceof Error ? error.message : 'Unknown error',
603
+ });
604
+ }
605
+ }
606
+ // ============================================
607
+ // Batch Update Issues
608
+ // ============================================
609
+ export const batchUpdateIssuesToolName = 'llama_batch_update_issues';
610
+ export const batchUpdateIssuesToolDescription = `Update multiple issues with different field changes (max 50).
611
+ Returns individual success/failure for each issue.
612
+ Uses session defaults if orgSlug/projectKey not provided.
613
+
614
+ Example:
615
+ updates: [
616
+ { issueKey: "PROJ-1", fields: { priority: "HIGH" } },
617
+ { issueKey: "PROJ-2", fields: { assigneeId: "user-id", estimate: 5 } }
618
+ ]`;
619
+ export const batchUpdateIssuesToolSchema = z.object({
620
+ orgSlug: z
621
+ .string()
622
+ .optional()
623
+ .describe('Organization slug (uses session default if not provided)'),
624
+ projectKey: z
625
+ .string()
626
+ .optional()
627
+ .describe('Project key (uses session default if not provided)'),
628
+ updates: z
629
+ .array(z.object({
630
+ issueKey: z.string().describe('Issue key to update'),
631
+ fields: z.object({
632
+ summary: z.string().optional().describe('New summary'),
633
+ description: z.string().optional().nullable().describe('New description'),
634
+ priority: z
635
+ .enum(['CRITICAL', 'HIGH', 'MEDIUM', 'LOW', 'TRIVIAL'])
636
+ .optional()
637
+ .describe('New priority'),
638
+ assigneeId: z.string().optional().nullable().describe('Assignee ID or null'),
639
+ sprintId: z.string().optional().nullable().describe('Sprint ID or null'),
640
+ estimate: z.number().optional().nullable().describe('Story points'),
641
+ labels: z.array(z.string()).optional().describe('Replace all labels'),
642
+ }),
643
+ }))
644
+ .min(1)
645
+ .max(50)
646
+ .describe('Updates to apply (max 50)'),
647
+ });
648
+ export async function executeBatchUpdateIssues(input) {
649
+ try {
650
+ const session = await getSessionDefaults();
651
+ const orgSlug = input.orgSlug ?? session?.orgSlug;
652
+ const projectKey = input.projectKey ?? session?.projectKey;
653
+ if (!orgSlug) {
654
+ return JSON.stringify({
655
+ success: false,
656
+ error: 'orgSlug is required. Either provide it or set session context with llama_set_context first.',
657
+ });
658
+ }
659
+ if (!projectKey) {
660
+ return JSON.stringify({
661
+ success: false,
662
+ error: 'projectKey is required. Either provide it or set session context with llama_set_context first.',
663
+ });
664
+ }
665
+ const client = getApiClient();
666
+ // Record tool call
667
+ try {
668
+ await client.recordToolCall('llama_batch_update_issues', {
669
+ orgSlug,
670
+ projectKey,
671
+ count: input.updates.length,
672
+ });
673
+ }
674
+ catch {
675
+ // Ignore recording errors
676
+ }
677
+ const updates = input.updates.map((u) => ({
678
+ issueKey: u.issueKey,
679
+ fields: {
680
+ summary: u.fields.summary,
681
+ description: u.fields.description,
682
+ priority: u.fields.priority,
683
+ assigneeId: u.fields.assigneeId,
684
+ sprintId: u.fields.sprintId,
685
+ estimate: u.fields.estimate,
686
+ labels: u.fields.labels,
687
+ },
688
+ }));
689
+ const result = await client.batchUpdateIssues(orgSlug, projectKey, updates);
690
+ return JSON.stringify({
691
+ success: true,
692
+ message: `Updated ${result.succeeded} of ${result.total} issues`,
693
+ ...result,
694
+ });
695
+ }
696
+ catch (error) {
697
+ if (error instanceof LlamaApiError) {
698
+ return JSON.stringify({
699
+ success: false,
700
+ error: `Failed to batch update issues: ${error.message}`,
701
+ statusCode: error.statusCode,
702
+ });
703
+ }
704
+ return JSON.stringify({
705
+ success: false,
706
+ error: error instanceof Error ? error.message : 'Unknown error',
707
+ });
260
708
  }
261
709
  }
262
710
  //# sourceMappingURL=issues.js.map