@credal/actions 0.2.158 → 0.2.160

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.
@@ -574,9 +574,33 @@ export const jiraGetJiraIssuesByQueryOutputSchema = z.object({
574
574
  name: z.string().optional(),
575
575
  category: z.string().optional(),
576
576
  }),
577
- assignee: z.string().nullable().describe("Email of the assignee, if any").optional(),
578
- reporter: z.string().nullable().describe("Email of the reporter, if any").optional(),
579
- creator: z.string().nullable().describe("Email of the creator, if any").optional(),
577
+ assignee: z
578
+ .object({
579
+ id: z.string().describe("The assignee ID").optional(),
580
+ name: z.string().describe("The assignee name").optional(),
581
+ email: z.string().describe("The assignee email").optional(),
582
+ })
583
+ .nullable()
584
+ .describe("The issue assignee")
585
+ .optional(),
586
+ reporter: z
587
+ .object({
588
+ id: z.string().describe("The reporter ID").optional(),
589
+ name: z.string().describe("The reporter name").optional(),
590
+ email: z.string().describe("The reporter email").optional(),
591
+ })
592
+ .nullable()
593
+ .describe("The issue reporter")
594
+ .optional(),
595
+ creator: z
596
+ .object({
597
+ id: z.string().describe("The creator ID").optional(),
598
+ name: z.string().describe("The creator name").optional(),
599
+ email: z.string().describe("The creator email").optional(),
600
+ })
601
+ .nullable()
602
+ .describe("The issue creator")
603
+ .optional(),
580
604
  created: z.string().datetime({ offset: true }),
581
605
  updated: z.string().datetime({ offset: true }),
582
606
  resolution: z.string().nullable().optional(),
@@ -766,9 +790,33 @@ export const jiraOrgGetJiraIssuesByQueryOutputSchema = z.object({
766
790
  name: z.string().optional(),
767
791
  category: z.string().optional(),
768
792
  }),
769
- assignee: z.string().nullable().describe("Email of the assignee, if any").optional(),
770
- reporter: z.string().nullable().describe("Email of the reporter, if any").optional(),
771
- creator: z.string().nullable().describe("Email of the creator, if any").optional(),
793
+ assignee: z
794
+ .object({
795
+ id: z.string().describe("The assignee ID").optional(),
796
+ name: z.string().describe("The assignee name").optional(),
797
+ email: z.string().describe("The assignee email").optional(),
798
+ })
799
+ .nullable()
800
+ .describe("The issue assignee")
801
+ .optional(),
802
+ reporter: z
803
+ .object({
804
+ id: z.string().describe("The reporter ID").optional(),
805
+ name: z.string().describe("The reporter name").optional(),
806
+ email: z.string().describe("The reporter email").optional(),
807
+ })
808
+ .nullable()
809
+ .describe("The issue reporter")
810
+ .optional(),
811
+ creator: z
812
+ .object({
813
+ id: z.string().describe("The creator ID").optional(),
814
+ name: z.string().describe("The creator name").optional(),
815
+ email: z.string().describe("The creator email").optional(),
816
+ })
817
+ .nullable()
818
+ .describe("The issue creator")
819
+ .optional(),
772
820
  created: z.string().datetime({ offset: true }),
773
821
  updated: z.string().datetime({ offset: true }),
774
822
  resolution: z.string().nullable().optional(),
@@ -958,9 +1006,33 @@ export const jiraDataCenterGetJiraIssuesByQueryOutputSchema = z.object({
958
1006
  name: z.string().optional(),
959
1007
  category: z.string().optional(),
960
1008
  }),
961
- assignee: z.string().nullable().describe("Email of the assignee, if any").optional(),
962
- reporter: z.string().nullable().describe("Email of the reporter, if any").optional(),
963
- creator: z.string().nullable().describe("Email of the creator, if any").optional(),
1009
+ assignee: z
1010
+ .object({
1011
+ id: z.string().describe("The assignee ID").optional(),
1012
+ name: z.string().describe("The assignee name").optional(),
1013
+ email: z.string().describe("The assignee email").optional(),
1014
+ })
1015
+ .nullable()
1016
+ .describe("The issue assignee")
1017
+ .optional(),
1018
+ reporter: z
1019
+ .object({
1020
+ id: z.string().describe("The reporter ID").optional(),
1021
+ name: z.string().describe("The reporter name").optional(),
1022
+ email: z.string().describe("The reporter email").optional(),
1023
+ })
1024
+ .nullable()
1025
+ .describe("The issue reporter")
1026
+ .optional(),
1027
+ creator: z
1028
+ .object({
1029
+ id: z.string().describe("The creator ID").optional(),
1030
+ name: z.string().describe("The creator name").optional(),
1031
+ email: z.string().describe("The creator email").optional(),
1032
+ })
1033
+ .nullable()
1034
+ .describe("The issue creator")
1035
+ .optional(),
964
1036
  created: z.string().datetime({ offset: true }),
965
1037
  updated: z.string().datetime({ offset: true }),
966
1038
  resolution: z.string().nullable().optional(),
@@ -1081,6 +1153,7 @@ export const zendeskCreateZendeskTicketParamsSchema = z.object({
1081
1153
  subject: z.string().describe("The subject of the ticket"),
1082
1154
  body: z.string().describe("The body of the ticket").optional(),
1083
1155
  subdomain: z.string().describe("The subdomain of the Zendesk account"),
1156
+ groupId: z.number().describe("The ID of the group to assign the ticket to").optional(),
1084
1157
  });
1085
1158
  export const zendeskCreateZendeskTicketOutputSchema = z.object({
1086
1159
  ticketId: z.string().describe("The ID of the ticket created"),
@@ -0,0 +1,8 @@
1
+ import type { jiraGetJiraIssuesByQueryFunction } from "../../autogen/types.js";
2
+ /**
3
+ * Get Jira issues from Jira Data Center
4
+ * Uses startAt parameter to paginate through the results while
5
+ * getJiraIssuesByQuery uses nextPageToken parameter to paginate through the results.
6
+ */
7
+ declare const getJiraDCIssuesByQuery: jiraGetJiraIssuesByQueryFunction;
8
+ export default getJiraDCIssuesByQuery;
@@ -0,0 +1,139 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { axiosClient } from "../../util/axiosClient.js";
11
+ import { getJiraApiConfig, getErrorMessage, extractPlainText } from "./utils.js";
12
+ const DEFAULT_LIMIT = 100;
13
+ /**
14
+ * Get Jira issues from Jira Data Center
15
+ * Uses startAt parameter to paginate through the results while
16
+ * getJiraIssuesByQuery uses nextPageToken parameter to paginate through the results.
17
+ */
18
+ const getJiraDCIssuesByQuery = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
19
+ const { authToken } = authParams;
20
+ const { query, limit } = params;
21
+ const { apiUrl, browseUrl, strategy } = getJiraApiConfig(authParams);
22
+ if (!authToken) {
23
+ throw new Error("Auth token is required");
24
+ }
25
+ const fields = [
26
+ "key",
27
+ "id",
28
+ "project",
29
+ "issuetype",
30
+ "summary",
31
+ "description",
32
+ "status",
33
+ "assignee",
34
+ "reporter",
35
+ "creator",
36
+ "created",
37
+ "updated",
38
+ "resolution",
39
+ "duedate",
40
+ "timeoriginalestimate",
41
+ "timespent",
42
+ "aggregatetimeoriginalestimate",
43
+ ];
44
+ const searchEndpoint = strategy.getSearchEndpoint();
45
+ const requestedLimit = limit !== null && limit !== void 0 ? limit : DEFAULT_LIMIT;
46
+ const allIssues = [];
47
+ let startAt = 0;
48
+ try {
49
+ // Keep fetching pages until we have all requested issues
50
+ while (allIssues.length < requestedLimit) {
51
+ // Calculate how many results to fetch in this request
52
+ const remainingIssues = requestedLimit - allIssues.length;
53
+ const maxResults = Math.min(remainingIssues, DEFAULT_LIMIT);
54
+ const queryParams = new URLSearchParams();
55
+ queryParams.set("jql", query);
56
+ queryParams.set("maxResults", String(maxResults));
57
+ queryParams.set("startAt", String(startAt));
58
+ queryParams.set("fields", fields.join(","));
59
+ const fullApiUrl = `${apiUrl}${searchEndpoint}?${queryParams.toString()}`;
60
+ const response = yield axiosClient.get(fullApiUrl, {
61
+ headers: {
62
+ Authorization: `Bearer ${authToken}`,
63
+ Accept: "application/json",
64
+ },
65
+ });
66
+ const { issues, total } = response.data;
67
+ allIssues.push(...issues);
68
+ if (allIssues.length >= total || issues.length === 0) {
69
+ break;
70
+ }
71
+ startAt += issues.length;
72
+ }
73
+ return {
74
+ results: allIssues.map(issue => {
75
+ const { id, key, fields } = issue;
76
+ const { summary, description, project, issuetype, status, assignee, reporter, creator, created, updated, resolution, duedate, } = fields;
77
+ const ticketUrl = `${browseUrl}/browse/${key}`;
78
+ return {
79
+ name: key,
80
+ url: ticketUrl,
81
+ contents: {
82
+ id,
83
+ key,
84
+ summary,
85
+ description: extractPlainText(description),
86
+ project: {
87
+ id: project.id,
88
+ key: project.key,
89
+ name: project.name,
90
+ },
91
+ issueType: {
92
+ id: issuetype.id,
93
+ name: issuetype.name,
94
+ },
95
+ status: {
96
+ id: status.id,
97
+ name: status.name,
98
+ category: status.statusCategory.name,
99
+ },
100
+ assignee: assignee
101
+ ? {
102
+ id: assignee.accountId,
103
+ name: assignee.displayName,
104
+ email: assignee.emailAddress,
105
+ }
106
+ : null,
107
+ reporter: reporter
108
+ ? {
109
+ id: reporter.accountId,
110
+ name: reporter.displayName,
111
+ email: reporter.emailAddress,
112
+ }
113
+ : null,
114
+ creator: creator
115
+ ? {
116
+ id: creator.accountId,
117
+ name: creator.displayName,
118
+ email: creator.emailAddress,
119
+ }
120
+ : null,
121
+ created,
122
+ updated,
123
+ resolution: (resolution === null || resolution === void 0 ? void 0 : resolution.name) || null,
124
+ dueDate: duedate || null,
125
+ url: ticketUrl,
126
+ },
127
+ };
128
+ }),
129
+ };
130
+ }
131
+ catch (error) {
132
+ console.error("Error retrieving Jira issues:", error);
133
+ return {
134
+ results: [],
135
+ error: getErrorMessage(error),
136
+ };
137
+ }
138
+ });
139
+ export default getJiraDCIssuesByQuery;
@@ -7,36 +7,24 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
7
7
  step((generator = generator.apply(thisArg, _arguments || [])).next());
8
8
  });
9
9
  };
10
- import { axiosClient } from "../../util/axiosClient.js";
11
- import { getJiraApiConfig, getErrorMessage } from "./utils.js";
10
+ import { Version3Client } from "jira.js";
11
+ import { getJiraApiConfig, getErrorMessage, extractPlainText, getUserInfoFromAccountId } from "./utils.js";
12
12
  const DEFAULT_LIMIT = 100;
13
- function extractPlainText(adf) {
14
- if (!adf || adf.type !== "doc" || !Array.isArray(adf.content))
15
- return "";
16
- return adf.content
17
- .map(block => {
18
- if (block.type === "paragraph" && Array.isArray(block.content)) {
19
- return block.content.map(inline => { var _a; return (_a = inline.text) !== null && _a !== void 0 ? _a : ""; }).join("");
20
- }
21
- return "";
22
- })
23
- .join("\n")
24
- .trim();
25
- }
26
13
  const getJiraIssuesByQuery = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
27
- const { authToken } = authParams;
14
+ const { authToken, cloudId } = authParams;
28
15
  const { query, limit } = params;
29
- const { apiUrl, browseUrl, strategy } = getJiraApiConfig(authParams);
30
- if (!authToken) {
16
+ const { browseUrl } = getJiraApiConfig(authParams);
17
+ if (!authToken)
31
18
  throw new Error("Auth token is required");
32
- }
19
+ if (!browseUrl)
20
+ throw new Error("Browse URL is required");
21
+ if (!cloudId)
22
+ throw new Error("Cloud ID is required for Jira Cloud");
33
23
  const fields = [
34
- "key",
35
- "id",
36
- "project",
37
- "issuetype",
38
24
  "summary",
39
25
  "description",
26
+ "project",
27
+ "issuetype",
40
28
  "status",
41
29
  "assignee",
42
30
  "reporter",
@@ -49,74 +37,86 @@ const getJiraIssuesByQuery = (_a) => __awaiter(void 0, [_a], void 0, function* (
49
37
  "timespent",
50
38
  "aggregatetimeoriginalestimate",
51
39
  ];
52
- const searchEndpoint = strategy.getSearchEndpoint();
53
40
  const requestedLimit = limit !== null && limit !== void 0 ? limit : DEFAULT_LIMIT;
54
41
  const allIssues = [];
55
- let startAt = 0;
42
+ let nextPageToken = undefined;
56
43
  try {
44
+ // Initialize jira.js client with OAuth 2.0 authentication
45
+ const client = new Version3Client({
46
+ host: `https://api.atlassian.com/ex/jira/${cloudId}`,
47
+ authentication: {
48
+ oauth2: {
49
+ accessToken: authToken,
50
+ },
51
+ },
52
+ });
57
53
  // Keep fetching pages until we have all requested issues
58
54
  while (allIssues.length < requestedLimit) {
59
55
  // Calculate how many results to fetch in this request
60
56
  const remainingIssues = requestedLimit - allIssues.length;
61
57
  const maxResults = Math.min(remainingIssues, DEFAULT_LIMIT);
62
- const queryParams = new URLSearchParams();
63
- queryParams.set("jql", query);
64
- queryParams.set("maxResults", String(maxResults));
65
- queryParams.set("startAt", String(startAt));
66
- queryParams.set("fields", fields.join(","));
67
- const fullApiUrl = `${apiUrl}${searchEndpoint}?${queryParams.toString()}`;
68
- const response = yield axiosClient.get(fullApiUrl, {
69
- headers: {
70
- Authorization: `Bearer ${authToken}`,
71
- Accept: "application/json",
72
- },
58
+ // Use the enhanced search endpoint (recommended)
59
+ const searchResults = yield client.issueSearch.searchForIssuesUsingJqlEnhancedSearch({
60
+ jql: query,
61
+ nextPageToken,
62
+ maxResults,
63
+ fields,
73
64
  });
74
- const { issues, total } = response.data;
75
- allIssues.push(...issues);
76
- if (allIssues.length >= total || issues.length === 0) {
65
+ if (!searchResults.issues || searchResults.issues.length === 0) {
77
66
  break;
78
67
  }
79
- startAt += issues.length;
68
+ allIssues.push(...searchResults.issues);
69
+ // Check if we've reached the end or have enough results
70
+ if (allIssues.length >= requestedLimit || !searchResults.nextPageToken || searchResults.issues.length === 0) {
71
+ break;
72
+ }
73
+ nextPageToken = searchResults.nextPageToken;
80
74
  }
81
- return {
82
- results: allIssues.map(issue => {
83
- const { id, key, fields } = issue;
84
- const { summary, description, project, issuetype, status, assignee, reporter, creator, created, updated, resolution, duedate, } = fields;
85
- const ticketUrl = `${browseUrl}/browse/${key}`;
86
- return {
87
- name: key,
88
- url: ticketUrl,
89
- contents: {
90
- id,
91
- key,
92
- summary,
93
- description: extractPlainText(description),
94
- project: {
95
- id: project.id,
96
- key: project.key,
97
- name: project.name,
98
- },
99
- issueType: {
100
- id: issuetype.id,
101
- name: issuetype.name,
102
- },
103
- status: {
104
- id: status.id,
105
- name: status.name,
106
- category: status.statusCategory.name,
107
- },
108
- assignee: (assignee === null || assignee === void 0 ? void 0 : assignee.emailAddress) || null,
109
- reporter: (reporter === null || reporter === void 0 ? void 0 : reporter.emailAddress) || null,
110
- creator: (creator === null || creator === void 0 ? void 0 : creator.emailAddress) || null,
111
- created,
112
- updated,
113
- resolution: (resolution === null || resolution === void 0 ? void 0 : resolution.name) || null,
114
- dueDate: duedate || null,
115
- url: ticketUrl,
75
+ // Map issues with email addresses
76
+ const results = yield Promise.all(allIssues.map((_a) => __awaiter(void 0, [_a], void 0, function* ({ id, key, fields }) {
77
+ var _b;
78
+ const ticketUrl = `${browseUrl}/browse/${key}`;
79
+ const { summary, description, project, issuetype, status, assignee, reporter, creator, created, updated, resolution, duedate, } = fields;
80
+ // Fetch user info in parallel
81
+ const [assigneeInfo, reporterInfo, creatorInfo] = yield Promise.all([
82
+ getUserInfoFromAccountId(assignee === null || assignee === void 0 ? void 0 : assignee.accountId, client),
83
+ getUserInfoFromAccountId(reporter === null || reporter === void 0 ? void 0 : reporter.accountId, client),
84
+ getUserInfoFromAccountId(creator === null || creator === void 0 ? void 0 : creator.accountId, client),
85
+ ]);
86
+ return {
87
+ name: key,
88
+ url: ticketUrl,
89
+ contents: {
90
+ id,
91
+ key,
92
+ summary,
93
+ description: extractPlainText(description),
94
+ project: {
95
+ id: project === null || project === void 0 ? void 0 : project.id,
96
+ key: project === null || project === void 0 ? void 0 : project.key,
97
+ name: project === null || project === void 0 ? void 0 : project.name,
116
98
  },
117
- };
118
- }),
119
- };
99
+ issueType: {
100
+ id: issuetype === null || issuetype === void 0 ? void 0 : issuetype.id,
101
+ name: issuetype === null || issuetype === void 0 ? void 0 : issuetype.name,
102
+ },
103
+ status: {
104
+ id: status === null || status === void 0 ? void 0 : status.id,
105
+ name: status === null || status === void 0 ? void 0 : status.name,
106
+ category: (_b = status === null || status === void 0 ? void 0 : status.statusCategory) === null || _b === void 0 ? void 0 : _b.name,
107
+ },
108
+ assignee: assigneeInfo,
109
+ reporter: reporterInfo,
110
+ creator: creatorInfo,
111
+ created: created,
112
+ updated: updated,
113
+ resolution: resolution === null || resolution === void 0 ? void 0 : resolution.name,
114
+ dueDate: duedate,
115
+ url: ticketUrl,
116
+ },
117
+ };
118
+ })));
119
+ return { results };
120
120
  }
121
121
  catch (error) {
122
122
  console.error("Error retrieving Jira issues:", error);
@@ -1,3 +1,4 @@
1
+ import type { Version3Client } from "jira.js";
1
2
  export interface JiraApiConfig {
2
3
  apiUrl: string;
3
4
  browseUrl: string;
@@ -9,6 +10,17 @@ export interface JiraServiceDeskApiConfig {
9
10
  browseUrl: string;
10
11
  isDataCenter: boolean;
11
12
  }
13
+ export type JiraADFDoc = {
14
+ type: "doc";
15
+ version: number;
16
+ content: Array<{
17
+ type: string;
18
+ content?: Array<{
19
+ type: string;
20
+ text?: string;
21
+ }>;
22
+ }>;
23
+ };
12
24
  interface JiraHistoryResponse {
13
25
  data?: {
14
26
  values?: unknown[];
@@ -52,4 +64,11 @@ export declare function getRequestTypeCustomFieldId(projectKey: string, apiUrl:
52
64
  fieldId: string | null;
53
65
  message?: string;
54
66
  }>;
67
+ export declare function getUserEmailFromAccountId(accountId: string | undefined, client: Version3Client): Promise<string | undefined>;
68
+ export declare function getUserInfoFromAccountId(accountId: string | undefined, client: Version3Client): Promise<{
69
+ id: string;
70
+ name: string | undefined;
71
+ email: string | undefined;
72
+ } | null>;
73
+ export declare function extractPlainText(adf: unknown): string;
55
74
  export {};
@@ -189,3 +189,54 @@ export function getRequestTypeCustomFieldId(projectKey, apiUrl, authToken) {
189
189
  }
190
190
  });
191
191
  }
192
+ export function getUserEmailFromAccountId(accountId, client) {
193
+ return __awaiter(this, void 0, void 0, function* () {
194
+ if (!accountId)
195
+ return undefined;
196
+ try {
197
+ const userEmail = yield client.users.getUser({ accountId });
198
+ console.log("USER EMAIL: ", userEmail);
199
+ return userEmail.emailAddress;
200
+ }
201
+ catch (error) {
202
+ const axiosError = error;
203
+ console.error("Error fetching user email:", axiosError.message);
204
+ return undefined;
205
+ }
206
+ });
207
+ }
208
+ export function getUserInfoFromAccountId(accountId, client) {
209
+ return __awaiter(this, void 0, void 0, function* () {
210
+ if (!accountId)
211
+ return null;
212
+ try {
213
+ const user = yield client.users.getUser({ accountId });
214
+ return {
215
+ id: user.accountId,
216
+ name: user === null || user === void 0 ? void 0 : user.displayName,
217
+ email: user === null || user === void 0 ? void 0 : user.emailAddress,
218
+ };
219
+ }
220
+ catch (error) {
221
+ const axiosError = error;
222
+ console.error("Error fetching user info:", axiosError.message);
223
+ return null;
224
+ }
225
+ });
226
+ }
227
+ export function extractPlainText(adf) {
228
+ if (!adf || typeof adf !== "object")
229
+ return "";
230
+ const doc = adf;
231
+ if (doc.type !== "doc" || !Array.isArray(doc.content))
232
+ return "";
233
+ return doc.content
234
+ .map((block) => {
235
+ if (block.type === "paragraph" && Array.isArray(block.content)) {
236
+ return block.content.map((inline) => { var _a; return (_a = inline.text) !== null && _a !== void 0 ? _a : ""; }).join("");
237
+ }
238
+ return "";
239
+ })
240
+ .join("\n")
241
+ .trim();
242
+ }
@@ -11,7 +11,7 @@ import { createAxiosClientWithRetries } from "../../util/axiosClient.js";
11
11
  import { MISSING_AUTH_TOKEN } from "../../util/missingAuthConstants.js";
12
12
  const createZendeskTicket = (_a) => __awaiter(void 0, [_a], void 0, function* ({ params, authParams, }) {
13
13
  const { authToken } = authParams;
14
- const { subdomain, subject, body } = params;
14
+ const { subdomain, subject, body, groupId } = params;
15
15
  const url = `https://${subdomain}.zendesk.com/api/v2/tickets.json`;
16
16
  const payload = {
17
17
  ticket: {
@@ -19,6 +19,7 @@ const createZendeskTicket = (_a) => __awaiter(void 0, [_a], void 0, function* ({
19
19
  comment: {
20
20
  body,
21
21
  },
22
+ group_id: groupId,
22
23
  },
23
24
  };
24
25
  if (!authToken) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@credal/actions",
3
- "version": "0.2.158",
3
+ "version": "0.2.160",
4
4
  "type": "module",
5
5
  "description": "AI Actions by Credal AI",
6
6
  "sideEffects": false,
@@ -61,6 +61,7 @@
61
61
  "docx": "^9.3.0",
62
62
  "dotenv": "^16.4.7",
63
63
  "html-to-text": "^9.0.5",
64
+ "jira.js": "^5.2.2",
64
65
  "json-schema-to-zod": "^2.5.0",
65
66
  "jsonwebtoken": "^9.0.2",
66
67
  "limiter": "^3.0.0",