@anura-gate/watcher-jira 0.2.4 → 0.2.6

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.
@@ -209,6 +209,97 @@ class GateJiraWatcher extends EventEmitter {
209
209
  this._jiraHeaders.Authorization = `Bearer ${accessToken}`;
210
210
  }
211
211
 
212
+ // -- Public: Direct Jira Actions ------------------------------------
213
+ // Convenience methods that call the Jira API directly (no GATE queue).
214
+ // Useful when you want the agent to act immediately.
215
+
216
+ /**
217
+ * Post a comment on a Jira issue.
218
+ * @param {string} issueKey — e.g. "PROJ-123"
219
+ * @param {string} text — Comment body (plain text)
220
+ */
221
+ async postComment(issueKey, text) {
222
+ const res = await this._jiraPost(`/rest/api/3/issue/${issueKey}/comment`, {
223
+ body: {
224
+ type: "doc",
225
+ version: 1,
226
+ content: [{ type: "paragraph", content: [{ type: "text", text }] }],
227
+ },
228
+ });
229
+ if (!res.ok) throw new Error(res.data?.errorMessages?.[0] || `Failed to post comment (${res.status})`);
230
+ return res.data;
231
+ }
232
+
233
+ /**
234
+ * Create a new Jira issue.
235
+ * @param {object} opts
236
+ * @param {string} opts.project — Project key (e.g. "PROJ")
237
+ * @param {string} opts.summary — Issue title
238
+ * @param {string} [opts.description] — Issue description (plain text)
239
+ * @param {string} [opts.issueType] — Issue type (default: "Task")
240
+ * @param {string} [opts.priority] — Priority name (e.g. "High")
241
+ * @param {string} [opts.assignee] — Atlassian account ID
242
+ * @param {string[]} [opts.labels] — Labels
243
+ */
244
+ async createIssue(opts) {
245
+ const fields = {
246
+ project: { key: opts.project },
247
+ summary: opts.summary,
248
+ issuetype: { name: opts.issueType || "Task" },
249
+ };
250
+ if (opts.description) {
251
+ fields.description = {
252
+ type: "doc",
253
+ version: 1,
254
+ content: [{ type: "paragraph", content: [{ type: "text", text: opts.description }] }],
255
+ };
256
+ }
257
+ if (opts.assignee) fields.assignee = { accountId: opts.assignee };
258
+ if (opts.priority) fields.priority = { name: opts.priority };
259
+ if (opts.labels) fields.labels = opts.labels;
260
+
261
+ const res = await this._jiraPost("/rest/api/3/issue", { fields });
262
+ if (!res.ok) throw new Error(res.data?.errorMessages?.[0] || `Failed to create issue (${res.status})`);
263
+ return res.data;
264
+ }
265
+
266
+ /**
267
+ * Transition a Jira issue to a new status.
268
+ * @param {string} issueKey — e.g. "PROJ-123"
269
+ * @param {string} transitionName — Target status name (e.g. "Done", "In Progress")
270
+ */
271
+ async transitionIssue(issueKey, transitionName) {
272
+ const transRes = await this._jiraGet(`/rest/api/3/issue/${issueKey}/transitions`);
273
+ if (!transRes.ok) throw new Error("Failed to fetch transitions");
274
+
275
+ const transition = transRes.data.transitions?.find(
276
+ (t) => t.name.toLowerCase() === transitionName.toLowerCase()
277
+ );
278
+ if (!transition) {
279
+ const available = (transRes.data.transitions || []).map((t) => t.name).join(", ");
280
+ throw new Error(`Transition "${transitionName}" not found. Available: ${available}`);
281
+ }
282
+
283
+ const res = await this._jiraPost(`/rest/api/3/issue/${issueKey}/transitions`, {
284
+ transition: { id: transition.id },
285
+ });
286
+ if (!res.ok) throw new Error(res.data?.errorMessages?.[0] || `Failed to transition (${res.status})`);
287
+ return { transitioned: true, to: transitionName };
288
+ }
289
+
290
+ /**
291
+ * Assign a Jira issue.
292
+ * @param {string} issueKey — e.g. "PROJ-123"
293
+ * @param {string|null} accountId — Atlassian account ID, or null to unassign
294
+ */
295
+ async assignIssue(issueKey, accountId) {
296
+ const res = await this._jiraPut(`/rest/api/3/issue/${issueKey}/assignee`, {
297
+ accountId: accountId || null,
298
+ });
299
+ if (!res.ok) throw new Error(res.data?.errorMessages?.[0] || `Failed to assign (${res.status})`);
300
+ return { assigned: true, assignee: accountId };
301
+ }
302
+
212
303
  // -- Internal: Jira API -------------------------------------------
213
304
 
214
305
  _jiraUrl(path) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@anura-gate/watcher-jira",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "description": "GATE Watcher — Self-hosted Jira event monitor with OAuth 2.0. Credentials never leave your machine.",
5
5
  "main": "index.js",
6
6
  "bin": {