@commandable/integration-data 0.0.6 → 0.0.7

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 (220) hide show
  1. package/dist/credentials-index.d.ts.map +1 -1
  2. package/dist/credentials-index.js +119 -0
  3. package/dist/credentials-index.js.map +1 -1
  4. package/dist/index.d.ts +2 -2
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/loader.d.ts +33 -0
  9. package/dist/loader.d.ts.map +1 -1
  10. package/dist/loader.js +36 -4
  11. package/dist/loader.js.map +1 -1
  12. package/integrations/__tests__/liveHarness.ts +16 -3
  13. package/integrations/airtable/.env.test +9 -0
  14. package/integrations/airtable/.env.test.example +11 -0
  15. package/integrations/airtable/README.md +27 -0
  16. package/integrations/airtable/__tests__/get_handlers.test.ts +43 -5
  17. package/integrations/confluence/.env.test +25 -0
  18. package/integrations/confluence/.env.test.example +36 -0
  19. package/integrations/confluence/README.md +28 -0
  20. package/integrations/confluence/__tests__/get_handlers.test.ts +121 -0
  21. package/integrations/confluence/__tests__/usage_parity.test.ts +14 -0
  22. package/integrations/confluence/__tests__/write_handlers.test.ts +131 -0
  23. package/integrations/confluence/credentials.json +39 -0
  24. package/integrations/confluence/credentials_hint.md +4 -0
  25. package/integrations/confluence/credentials_hint_api_token.md +9 -0
  26. package/integrations/confluence/credentials_hint_oauth_token.md +8 -0
  27. package/integrations/confluence/handlers/add_comment.js +19 -0
  28. package/integrations/confluence/handlers/add_label.js +16 -0
  29. package/integrations/confluence/handlers/create_page.js +22 -0
  30. package/integrations/confluence/handlers/delete_page.js +17 -0
  31. package/integrations/confluence/handlers/get_comments.js +33 -0
  32. package/integrations/confluence/handlers/get_page_children.js +30 -0
  33. package/integrations/confluence/handlers/get_space.js +22 -0
  34. package/integrations/confluence/handlers/list_spaces.js +39 -0
  35. package/integrations/confluence/handlers/read_page.js +49 -0
  36. package/integrations/confluence/handlers/search_pages.js +42 -0
  37. package/integrations/confluence/handlers/update_page.js +42 -0
  38. package/integrations/confluence/manifest.json +85 -0
  39. package/integrations/confluence/prompt.md +55 -0
  40. package/integrations/confluence/schemas/add_comment.json +22 -0
  41. package/integrations/confluence/schemas/add_label.json +19 -0
  42. package/integrations/confluence/schemas/create_page.json +33 -0
  43. package/integrations/confluence/schemas/delete_page.json +23 -0
  44. package/integrations/confluence/schemas/empty.json +6 -0
  45. package/integrations/confluence/schemas/get_comments.json +24 -0
  46. package/integrations/confluence/schemas/get_page_children.json +28 -0
  47. package/integrations/confluence/schemas/get_space.json +18 -0
  48. package/integrations/confluence/schemas/list_spaces.json +36 -0
  49. package/integrations/confluence/schemas/read_page.json +28 -0
  50. package/integrations/confluence/schemas/search_pages.json +26 -0
  51. package/integrations/confluence/schemas/update_page.json +31 -0
  52. package/integrations/github/.env.test +16 -0
  53. package/integrations/github/.env.test.example +17 -0
  54. package/integrations/github/README.md +75 -0
  55. package/integrations/github/__tests__/get_handlers.test.ts +5 -5
  56. package/integrations/github/__tests__/write_handlers.test.ts +176 -58
  57. package/integrations/github/handlers/create_file.js +46 -0
  58. package/integrations/github/handlers/delete_file.js +14 -1
  59. package/integrations/github/handlers/edit_file.js +52 -0
  60. package/integrations/github/handlers/edit_files.js +107 -0
  61. package/integrations/github/manifest.json +74 -47
  62. package/integrations/github/prompt.md +36 -0
  63. package/integrations/github/schemas/create_file.json +13 -0
  64. package/integrations/github/schemas/delete_file.json +2 -2
  65. package/integrations/github/schemas/edit_file.json +26 -0
  66. package/integrations/github/schemas/edit_files.json +39 -0
  67. package/integrations/google-calendar/.env.test.example +11 -0
  68. package/integrations/google-calendar/README.md +41 -0
  69. package/integrations/google-calendar/__tests__/write_and_admin_handlers.test.ts +7 -7
  70. package/integrations/google-calendar/manifest.json +27 -17
  71. package/integrations/google-docs/README.md +30 -0
  72. package/integrations/google-drive/README.md +26 -0
  73. package/integrations/google-gmail/.env.test.example +11 -0
  74. package/integrations/google-gmail/README.md +49 -0
  75. package/integrations/google-gmail/handlers/create_draft_email.js +1 -1
  76. package/integrations/google-gmail/handlers/read_email.js +1 -1
  77. package/integrations/google-gmail/handlers/send_email.js +1 -1
  78. package/integrations/google-gmail/manifest.json +36 -25
  79. package/integrations/google-sheet/README.md +27 -0
  80. package/integrations/google-slides/README.md +28 -0
  81. package/integrations/hubspot/.env.test.example +20 -0
  82. package/integrations/hubspot/README.md +48 -0
  83. package/integrations/hubspot/__tests__/get_handlers.test.ts +151 -0
  84. package/integrations/hubspot/__tests__/usage_parity.test.ts +10 -0
  85. package/integrations/hubspot/__tests__/write_handlers.test.ts +244 -0
  86. package/integrations/hubspot/credentials.json +48 -0
  87. package/integrations/hubspot/credentials_hint.md +20 -0
  88. package/integrations/hubspot/credentials_hint_oauth_token.md +16 -0
  89. package/integrations/hubspot/handlers/archive_company.js +13 -0
  90. package/integrations/hubspot/handlers/archive_contact.js +13 -0
  91. package/integrations/hubspot/handlers/archive_deal.js +13 -0
  92. package/integrations/hubspot/handlers/archive_ticket.js +13 -0
  93. package/integrations/hubspot/handlers/create_association.js +18 -0
  94. package/integrations/hubspot/handlers/create_company.js +13 -0
  95. package/integrations/hubspot/handlers/create_contact.js +14 -0
  96. package/integrations/hubspot/handlers/create_deal.js +16 -0
  97. package/integrations/hubspot/handlers/create_note.js +44 -0
  98. package/integrations/hubspot/handlers/create_task.js +48 -0
  99. package/integrations/hubspot/handlers/create_ticket.js +15 -0
  100. package/integrations/hubspot/handlers/get_associations.js +14 -0
  101. package/integrations/hubspot/handlers/get_company.js +18 -0
  102. package/integrations/hubspot/handlers/get_contact.js +18 -0
  103. package/integrations/hubspot/handlers/get_deal.js +18 -0
  104. package/integrations/hubspot/handlers/get_ticket.js +20 -0
  105. package/integrations/hubspot/handlers/list_owners.js +12 -0
  106. package/integrations/hubspot/handlers/list_pipelines.js +5 -0
  107. package/integrations/hubspot/handlers/list_properties.js +11 -0
  108. package/integrations/hubspot/handlers/remove_association.js +22 -0
  109. package/integrations/hubspot/handlers/search_companies.js +43 -0
  110. package/integrations/hubspot/handlers/search_contacts.js +43 -0
  111. package/integrations/hubspot/handlers/search_deals.js +43 -0
  112. package/integrations/hubspot/handlers/search_notes.js +43 -0
  113. package/integrations/hubspot/handlers/search_tasks.js +43 -0
  114. package/integrations/hubspot/handlers/search_tickets.js +43 -0
  115. package/integrations/hubspot/handlers/update_company.js +13 -0
  116. package/integrations/hubspot/handlers/update_contact.js +14 -0
  117. package/integrations/hubspot/handlers/update_deal.js +16 -0
  118. package/integrations/hubspot/handlers/update_task.js +17 -0
  119. package/integrations/hubspot/handlers/update_ticket.js +15 -0
  120. package/integrations/hubspot/manifest.json +230 -0
  121. package/integrations/hubspot/prompt.md +69 -0
  122. package/integrations/hubspot/schemas/archive_company.json +13 -0
  123. package/integrations/hubspot/schemas/archive_contact.json +13 -0
  124. package/integrations/hubspot/schemas/archive_deal.json +9 -0
  125. package/integrations/hubspot/schemas/archive_ticket.json +9 -0
  126. package/integrations/hubspot/schemas/create_association.json +24 -0
  127. package/integrations/hubspot/schemas/create_company.json +14 -0
  128. package/integrations/hubspot/schemas/create_contact.json +15 -0
  129. package/integrations/hubspot/schemas/create_deal.json +20 -0
  130. package/integrations/hubspot/schemas/create_note.json +37 -0
  131. package/integrations/hubspot/schemas/create_task.json +51 -0
  132. package/integrations/hubspot/schemas/create_ticket.json +16 -0
  133. package/integrations/hubspot/schemas/empty.json +6 -0
  134. package/integrations/hubspot/schemas/get_associations.json +30 -0
  135. package/integrations/hubspot/schemas/get_company.json +27 -0
  136. package/integrations/hubspot/schemas/get_contact.json +27 -0
  137. package/integrations/hubspot/schemas/get_deal.json +20 -0
  138. package/integrations/hubspot/schemas/get_ticket.json +20 -0
  139. package/integrations/hubspot/schemas/list_owners.json +25 -0
  140. package/integrations/hubspot/schemas/list_pipelines.json +13 -0
  141. package/integrations/hubspot/schemas/list_properties.json +17 -0
  142. package/integrations/hubspot/schemas/remove_association.json +24 -0
  143. package/integrations/hubspot/schemas/search_companies.json +56 -0
  144. package/integrations/hubspot/schemas/search_contacts.json +56 -0
  145. package/integrations/hubspot/schemas/search_deals.json +43 -0
  146. package/integrations/hubspot/schemas/search_notes.json +43 -0
  147. package/integrations/hubspot/schemas/search_tasks.json +43 -0
  148. package/integrations/hubspot/schemas/search_tickets.json +43 -0
  149. package/integrations/hubspot/schemas/update_company.json +20 -0
  150. package/integrations/hubspot/schemas/update_contact.json +21 -0
  151. package/integrations/hubspot/schemas/update_deal.json +19 -0
  152. package/integrations/hubspot/schemas/update_task.json +31 -0
  153. package/integrations/hubspot/schemas/update_ticket.json +18 -0
  154. package/integrations/jira/.env.test +46 -0
  155. package/integrations/jira/.env.test.example +41 -0
  156. package/integrations/jira/README.md +46 -0
  157. package/integrations/jira/__tests__/get_handlers.test.ts +193 -0
  158. package/integrations/jira/__tests__/usage_parity.test.ts +14 -0
  159. package/integrations/jira/__tests__/write_handlers.test.ts +157 -0
  160. package/integrations/jira/credentials.json +39 -0
  161. package/integrations/jira/credentials_hint.md +4 -0
  162. package/integrations/jira/credentials_hint_api_token.md +6 -0
  163. package/integrations/jira/credentials_hint_oauth_token.md +6 -0
  164. package/integrations/jira/handlers/add_comment.js +9 -0
  165. package/integrations/jira/handlers/assign_issue.js +11 -0
  166. package/integrations/jira/handlers/create_issue.js +37 -0
  167. package/integrations/jira/handlers/create_sprint.js +19 -0
  168. package/integrations/jira/handlers/delete_issue.js +10 -0
  169. package/integrations/jira/handlers/get_backlog_issues.js +13 -0
  170. package/integrations/jira/handlers/get_board.js +6 -0
  171. package/integrations/jira/handlers/get_issue.js +63 -0
  172. package/integrations/jira/handlers/get_issue_comments.js +31 -0
  173. package/integrations/jira/handlers/get_myself.js +14 -0
  174. package/integrations/jira/handlers/get_project.js +28 -0
  175. package/integrations/jira/handlers/get_sprint.js +5 -0
  176. package/integrations/jira/handlers/get_sprint_issues.js +13 -0
  177. package/integrations/jira/handlers/get_transitions.js +23 -0
  178. package/integrations/jira/handlers/list_boards.js +34 -0
  179. package/integrations/jira/handlers/list_projects.js +29 -0
  180. package/integrations/jira/handlers/list_sprints.js +29 -0
  181. package/integrations/jira/handlers/move_issues_to_sprint.js +11 -0
  182. package/integrations/jira/handlers/search_issues.js +43 -0
  183. package/integrations/jira/handlers/search_users.js +21 -0
  184. package/integrations/jira/handlers/transition_issue.js +44 -0
  185. package/integrations/jira/handlers/update_issue.js +40 -0
  186. package/integrations/jira/handlers/update_sprint.js +20 -0
  187. package/integrations/jira/manifest.json +204 -0
  188. package/integrations/jira/prompt.md +80 -0
  189. package/integrations/jira/schemas/add_comment.json +16 -0
  190. package/integrations/jira/schemas/assign_issue.json +16 -0
  191. package/integrations/jira/schemas/create_issue.json +49 -0
  192. package/integrations/jira/schemas/create_sprint.json +29 -0
  193. package/integrations/jira/schemas/delete_issue.json +12 -0
  194. package/integrations/jira/schemas/empty.json +6 -0
  195. package/integrations/jira/schemas/get_backlog_issues.json +33 -0
  196. package/integrations/jira/schemas/get_board.json +13 -0
  197. package/integrations/jira/schemas/get_issue.json +23 -0
  198. package/integrations/jira/schemas/get_issue_comments.json +23 -0
  199. package/integrations/jira/schemas/get_project.json +17 -0
  200. package/integrations/jira/schemas/get_sprint.json +13 -0
  201. package/integrations/jira/schemas/get_sprint_issues.json +33 -0
  202. package/integrations/jira/schemas/get_transitions.json +12 -0
  203. package/integrations/jira/schemas/list_boards.json +27 -0
  204. package/integrations/jira/schemas/list_projects.json +22 -0
  205. package/integrations/jira/schemas/list_sprints.json +29 -0
  206. package/integrations/jira/schemas/move_issues_to_sprint.json +19 -0
  207. package/integrations/jira/schemas/search_issues.json +28 -0
  208. package/integrations/jira/schemas/search_users.json +18 -0
  209. package/integrations/jira/schemas/transition_issue.json +38 -0
  210. package/integrations/jira/schemas/update_issue.json +47 -0
  211. package/integrations/jira/schemas/update_sprint.json +33 -0
  212. package/integrations/new_integration_prompt.md +173 -2
  213. package/integrations/notion/.env.test +10 -0
  214. package/integrations/notion/.env.test.example +13 -0
  215. package/integrations/notion/README.md +42 -0
  216. package/integrations/notion/manifest.json +64 -35
  217. package/integrations/trello/.env.test +6 -0
  218. package/integrations/trello/.env.test.example +9 -0
  219. package/integrations/trello/README.md +50 -0
  220. package/package.json +7 -3
@@ -0,0 +1,157 @@
1
+ import { afterAll, beforeAll, describe, expect, it } from 'vitest'
2
+ import { createCredentialStore, createIntegrationNode, createProxy, createToolbox, hasEnv, safeCleanup } from '../../__tests__/liveHarness.js'
3
+
4
+ // LIVE Jira write tests using credentials
5
+ //
6
+ // Required for write tests:
7
+ // - JIRA_TEST_PROJECT_KEY
8
+ //
9
+ // Variant: api_token
10
+ // - JIRA_DOMAIN
11
+ // - JIRA_EMAIL
12
+ // - JIRA_API_TOKEN
13
+ //
14
+ // Optional:
15
+ // - JIRA_TEST_TRANSITION_NAME (enables transition_issue)
16
+ // - JIRA_TEST_BOARD_ID (enables sprint roundtrip: create_sprint -> update_sprint -> move_issues_to_sprint -> update_sprint)
17
+
18
+ const env = process.env as Record<string, string | undefined>
19
+
20
+ const suiteOrSkip = (hasEnv('JIRA_DOMAIN', 'JIRA_EMAIL', 'JIRA_API_TOKEN') && hasEnv('JIRA_TEST_PROJECT_KEY'))
21
+ ? describe
22
+ : describe.skip
23
+
24
+ suiteOrSkip('jira write handlers (live)', () => {
25
+ describe('variant: api_token', () => {
26
+ const ctx: {
27
+ createdIssueKey?: string
28
+ createdSprintId?: number
29
+ } = {}
30
+
31
+ let jira: ReturnType<typeof createToolbox>
32
+
33
+ beforeAll(async () => {
34
+ const credentialStore = createCredentialStore(async () => ({
35
+ domain: env.JIRA_DOMAIN!,
36
+ email: env.JIRA_EMAIL!,
37
+ apiToken: env.JIRA_API_TOKEN!,
38
+ }))
39
+ const proxy = createProxy(credentialStore)
40
+ jira = createToolbox('jira', proxy, createIntegrationNode('jira', { label: 'Jira', credentialId: 'jira-creds', credentialVariant: 'api_token' }), 'api_token')
41
+ }, 60000)
42
+
43
+ afterAll(async () => {
44
+ await safeCleanup(async () => {
45
+ if (!ctx.createdSprintId)
46
+ return
47
+ const update_sprint = jira.write('update_sprint')
48
+ await update_sprint({ sprintId: ctx.createdSprintId, state: 'closed' })
49
+ })
50
+ await safeCleanup(async () => {
51
+ if (!ctx.createdIssueKey)
52
+ return
53
+ const delete_issue = jira.write('delete_issue')
54
+ await delete_issue({ issueIdOrKey: ctx.createdIssueKey })
55
+ })
56
+ }, 60000)
57
+
58
+ it('create_issue -> get_issue -> update_issue -> add_comment -> get_issue_comments (and optional assign/transition) roundtrip', async () => {
59
+ const get_myself = jira.read('get_myself')
60
+ const me = await get_myself({})
61
+ expect(me?.accountId).toBeTruthy()
62
+
63
+ const get_project = jira.read('get_project')
64
+ const project = await get_project({ projectIdOrKey: env.JIRA_TEST_PROJECT_KEY, expandIssueTypes: true })
65
+ const issueTypes = Array.isArray(project?.issueTypes) ? project.issueTypes : []
66
+ const picked = issueTypes.find((t: any) => t && t.subtask === false) || issueTypes[0]
67
+ if (!picked?.id && !picked?.name)
68
+ return expect(true).toBe(true)
69
+
70
+ const create_issue = jira.write('create_issue')
71
+ const created = await create_issue({
72
+ projectKey: env.JIRA_TEST_PROJECT_KEY,
73
+ issueTypeId: picked?.id || undefined,
74
+ issueTypeName: picked?.id ? undefined : (picked?.name || undefined),
75
+ summary: `CmdTest ${Date.now()}`,
76
+ descriptionText: 'Created by integration tests.',
77
+ assigneeAccountId: me.accountId,
78
+ labels: ['cmdtest'],
79
+ })
80
+ const issueKey = created?.key || created?.id
81
+ expect(issueKey).toBeTruthy()
82
+ ctx.createdIssueKey = created?.key || created?.id
83
+
84
+ const get_issue = jira.read('get_issue')
85
+ const got = await get_issue({ issueIdOrKey: issueKey })
86
+ expect(got?.key).toBeTruthy()
87
+
88
+ const update_issue = jira.write('update_issue')
89
+ const updated = await update_issue({
90
+ issueIdOrKey: issueKey,
91
+ summary: `CmdTest Updated ${Date.now()}`,
92
+ descriptionText: 'Updated by integration tests.',
93
+ })
94
+ expect(updated?.success === true || updated).toBeTruthy()
95
+
96
+ const add_comment = jira.write('add_comment')
97
+ const commentText = `Test comment ${Date.now()}`
98
+ const comment = await add_comment({ issueIdOrKey: issueKey, bodyText: commentText })
99
+ expect(comment?.id).toBeTruthy()
100
+
101
+ const get_issue_comments = jira.read('get_issue_comments')
102
+ const comments = await get_issue_comments({ issueIdOrKey: issueKey, maxResults: 20 })
103
+ const found = (comments?.comments || []).some((c: any) =>
104
+ (c?.bodyMarkdown && String(c.bodyMarkdown).includes('Test comment'))
105
+ || (c?.bodyText && String(c.bodyText).includes('Test comment')),
106
+ )
107
+ expect(found).toBe(true)
108
+
109
+ const assign_issue = jira.write('assign_issue')
110
+ const assigned = await assign_issue({ issueIdOrKey: issueKey, accountId: me.accountId })
111
+ expect(assigned?.success === true || assigned).toBeTruthy()
112
+ const unassigned = await assign_issue({ issueIdOrKey: issueKey, accountId: null })
113
+ expect(unassigned?.success === true || unassigned).toBeTruthy()
114
+
115
+ if (env.JIRA_TEST_TRANSITION_NAME) {
116
+ const transition_issue = jira.write('transition_issue')
117
+ const transitioned = await transition_issue({
118
+ issueIdOrKey: issueKey,
119
+ transitionName: env.JIRA_TEST_TRANSITION_NAME,
120
+ commentText: 'Transitioned by integration tests.',
121
+ })
122
+ expect(transitioned?.success === true || transitioned).toBeTruthy()
123
+ }
124
+ }, 120000)
125
+
126
+ it('sprint roundtrip: create_sprint -> update_sprint (start) -> move_issues_to_sprint -> update_sprint (close) (optional)', async () => {
127
+ if (!env.JIRA_TEST_BOARD_ID || !ctx.createdIssueKey)
128
+ return expect(true).toBe(true)
129
+ const boardId = Number(env.JIRA_TEST_BOARD_ID)
130
+ if (!Number.isFinite(boardId))
131
+ return expect(true).toBe(true)
132
+
133
+ const create_sprint = jira.write('create_sprint')
134
+ const name = `CmdTest Sprint ${Date.now()}`
135
+ const sprint = await create_sprint({ boardId, name })
136
+ const sprintId = sprint?.id
137
+ expect(typeof sprintId).toBe('number')
138
+ ctx.createdSprintId = sprintId
139
+
140
+ const update_sprint = jira.write('update_sprint')
141
+ const today = new Date().toISOString().slice(0, 10)
142
+ const twoWeeks = new Date(Date.now() + 14 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10)
143
+ const started = await update_sprint({ sprintId, state: 'active', startDate: today, endDate: twoWeeks })
144
+ expect(started?.state === 'active' || started?.id === sprintId || started).toBeTruthy()
145
+
146
+ const move_issues_to_sprint = jira.write('move_issues_to_sprint')
147
+ const moved = await move_issues_to_sprint({ sprintId, issueKeys: [ctx.createdIssueKey] })
148
+ expect(moved?.success === true || moved).toBeTruthy()
149
+
150
+ const closed = await update_sprint({ sprintId, state: 'closed' })
151
+ expect(closed?.state === 'closed' || closed?.id === sprintId || closed).toBeTruthy()
152
+ ctx.createdSprintId = undefined
153
+ }, 120000)
154
+
155
+ })
156
+ })
157
+
@@ -0,0 +1,39 @@
1
+ {
2
+ "variants": {
3
+ "api_token": {
4
+ "label": "API Token (Email + Token)",
5
+ "schema": {
6
+ "type": "object",
7
+ "properties": {
8
+ "domain": {
9
+ "type": "string",
10
+ "title": "Jira site domain",
11
+ "description": "The subdomain of your Jira Cloud site. Example: for https://mycompany.atlassian.net, enter 'mycompany'."
12
+ },
13
+ "email": {
14
+ "type": "string",
15
+ "title": "Atlassian account email",
16
+ "description": "Email address of the Atlassian account that owns the API token."
17
+ },
18
+ "apiToken": {
19
+ "type": "string",
20
+ "title": "Atlassian API token",
21
+ "description": "Atlassian API token for Jira Cloud. The server will convert this into the required Basic auth header."
22
+ }
23
+ },
24
+ "required": ["domain", "email", "apiToken"],
25
+ "additionalProperties": false
26
+ },
27
+ "baseUrlTemplate": "https://{{domain}}.atlassian.net",
28
+ "injection": {
29
+ "headers": {
30
+ "Authorization": "Basic {{basicAuth}}",
31
+ "Accept": "application/json"
32
+ }
33
+ },
34
+ "preprocess": "jira_api_token"
35
+ }
36
+ },
37
+ "default": "api_token"
38
+ }
39
+
@@ -0,0 +1,4 @@
1
+ Recommended: use **API Token (Email + Token)** unless you specifically need OAuth.
2
+
3
+ If you have multiple credential variants available, select one and follow its setup instructions.
4
+
@@ -0,0 +1,6 @@
1
+ 1. Open your Jira Cloud site in the browser (it looks like `https://YOUR_DOMAIN.atlassian.net`).
2
+ 2. Copy `YOUR_DOMAIN` (the subdomain) and use it as `domain`.
3
+ 3. Create an Atlassian API token at `https://id.atlassian.com/manage-profile/security/api-tokens`.
4
+ 4. Use the same Atlassian account email as `email` and paste the token as `apiToken`.
5
+ 5. Ensure the Atlassian account has access to the Jira projects you want to work with.
6
+
@@ -0,0 +1,6 @@
1
+ 1. Create an OAuth 2.0 (3LO) app in the Atlassian developer console.
2
+ 2. Add Jira scopes (typical minimum): `read:jira-work`, `write:jira-work`, `read:jira-user` (and `offline_access` if you want refresh tokens).
3
+ 3. Complete the OAuth flow to obtain an access token.
4
+ 4. Discover your `cloudId` by calling `GET https://api.atlassian.com/oauth/token/accessible-resources` with `Authorization: Bearer <access_token>` and using the returned `id`.
5
+ 5. Paste `cloudId` and the current OAuth `token` here.
6
+
@@ -0,0 +1,9 @@
1
+ async (input) => {
2
+ const res = await integration.fetch(`/rest/api/3/issue/${encodeURIComponent(input.issueIdOrKey)}/comment`, {
3
+ method: 'POST',
4
+ body: { body: utils.adf?.fromMarkdown(input.bodyText) },
5
+ })
6
+
7
+ return await res.json()
8
+ }
9
+
@@ -0,0 +1,11 @@
1
+ async (input) => {
2
+ const res = await integration.fetch(`/rest/api/3/issue/${encodeURIComponent(input.issueIdOrKey)}/assignee`, {
3
+ method: 'PUT',
4
+ body: { accountId: input.accountId },
5
+ })
6
+
7
+ if (res.status === 204)
8
+ return { success: true }
9
+ return await res.json()
10
+ }
11
+
@@ -0,0 +1,37 @@
1
+ async (input) => {
2
+ const fields = {
3
+ project: { key: input.projectKey },
4
+ summary: input.summary,
5
+ }
6
+
7
+ if (input.descriptionText)
8
+ fields.description = utils.adf?.fromMarkdown(input.descriptionText)
9
+
10
+ if (input.issueTypeId) {
11
+ fields.issuetype = { id: String(input.issueTypeId) }
12
+ }
13
+ else if (input.issueTypeName) {
14
+ fields.issuetype = { name: String(input.issueTypeName) }
15
+ }
16
+ else {
17
+ throw new Error(`Missing issue type. Provide issueTypeId or issueTypeName (call get_project to discover available issue types).`)
18
+ }
19
+
20
+ if (input.priorityId)
21
+ fields.priority = { id: input.priorityId }
22
+ else if (input.priorityName)
23
+ fields.priority = { name: input.priorityName }
24
+
25
+ if (Array.isArray(input.labels))
26
+ fields.labels = input.labels
27
+
28
+ if (input.assigneeAccountId)
29
+ fields.assignee = { accountId: input.assigneeAccountId }
30
+
31
+ const res = await integration.fetch('/rest/api/3/issue', {
32
+ method: 'POST',
33
+ body: { fields },
34
+ })
35
+
36
+ return await res.json()
37
+ }
@@ -0,0 +1,19 @@
1
+ async (input) => {
2
+ const body = {
3
+ originBoardId: input.boardId,
4
+ name: input.name,
5
+ }
6
+ if (input.startDate)
7
+ body.startDate = input.startDate
8
+ if (input.endDate)
9
+ body.endDate = input.endDate
10
+ if (input.goal)
11
+ body.goal = input.goal
12
+
13
+ const res = await integration.fetch('/rest/agile/1.0/sprint', {
14
+ method: 'POST',
15
+ body,
16
+ })
17
+ return await res.json()
18
+ }
19
+
@@ -0,0 +1,10 @@
1
+ async (input) => {
2
+ const res = await integration.fetch(`/rest/api/3/issue/${encodeURIComponent(input.issueIdOrKey)}`, {
3
+ method: 'DELETE',
4
+ })
5
+
6
+ if (res.status === 204)
7
+ return { success: true }
8
+ return await res.json()
9
+ }
10
+
@@ -0,0 +1,13 @@
1
+ async (input) => {
2
+ const params = new URLSearchParams()
3
+ if (input.jql)
4
+ params.set('jql', input.jql)
5
+ if (Array.isArray(input.fields) && input.fields.length)
6
+ params.set('fields', input.fields.join(','))
7
+ params.set('startAt', String(input.startAt ?? 0))
8
+ params.set('maxResults', String(input.maxResults ?? 50))
9
+
10
+ const res = await integration.fetch(`/rest/agile/1.0/board/${encodeURIComponent(String(input.boardId))}/backlog?${params.toString()}`)
11
+ return await res.json()
12
+ }
13
+
@@ -0,0 +1,6 @@
1
+ async (input) => {
2
+ const res = await integration.fetch(`/rest/agile/1.0/board/${encodeURIComponent(String(input.boardId))}`)
3
+ const data = await res.json()
4
+ return data
5
+ }
6
+
@@ -0,0 +1,63 @@
1
+ async (input) => {
2
+ const defaultFields = [
3
+ 'summary',
4
+ 'status',
5
+ 'assignee',
6
+ 'priority',
7
+ 'issuetype',
8
+ 'project',
9
+ 'description',
10
+ 'created',
11
+ 'updated',
12
+ 'labels',
13
+ ]
14
+
15
+ const fields = Array.isArray(input.fields) && input.fields.length ? input.fields : defaultFields
16
+ const params = new URLSearchParams()
17
+ if (fields?.length)
18
+ params.set('fields', fields.join(','))
19
+ if (Array.isArray(input.expand) && input.expand.length)
20
+ params.set('expand', input.expand.join(','))
21
+
22
+ const path = `/rest/api/3/issue/${encodeURIComponent(input.issueIdOrKey)}${params.toString() ? `?${params.toString()}` : ''}`
23
+ const res = await integration.fetch(path)
24
+ const data = await res.json()
25
+
26
+ const descAdf = data?.fields?.description
27
+ const descMarkdown = utils.adf?.toMarkdown(descAdf) || ''
28
+ const descText = descMarkdown ? '' : (utils.adf?.toPlainText(descAdf) || '')
29
+
30
+ return {
31
+ id: data.id ?? null,
32
+ key: data.key ?? null,
33
+ self: data.self ?? null,
34
+ summary: data.fields?.summary ?? null,
35
+ status: data.fields?.status
36
+ ? {
37
+ id: data.fields.status.id ?? null,
38
+ name: data.fields.status.name ?? null,
39
+ category: data.fields.status.statusCategory
40
+ ? {
41
+ key: data.fields.status.statusCategory.key ?? null,
42
+ name: data.fields.status.statusCategory.name ?? null,
43
+ }
44
+ : null,
45
+ }
46
+ : null,
47
+ assignee: data.fields?.assignee
48
+ ? {
49
+ accountId: data.fields.assignee.accountId ?? null,
50
+ displayName: data.fields.assignee.displayName ?? null,
51
+ }
52
+ : null,
53
+ priority: data.fields?.priority ? { id: data.fields.priority.id ?? null, name: data.fields.priority.name ?? null } : null,
54
+ issueType: data.fields?.issuetype ? { id: data.fields.issuetype.id ?? null, name: data.fields.issuetype.name ?? null } : null,
55
+ project: data.fields?.project ? { id: data.fields.project.id ?? null, key: data.fields.project.key ?? null, name: data.fields.project.name ?? null } : null,
56
+ labels: Array.isArray(data.fields?.labels) ? data.fields.labels : [],
57
+ descriptionMarkdown: descMarkdown || null,
58
+ descriptionText: descMarkdown ? null : (descText || null),
59
+ created: data.fields?.created ?? null,
60
+ updated: data.fields?.updated ?? null,
61
+ }
62
+ }
63
+
@@ -0,0 +1,31 @@
1
+ async (input) => {
2
+ const params = new URLSearchParams()
3
+ params.set('startAt', String(input.startAt ?? 0))
4
+ params.set('maxResults', String(input.maxResults ?? 50))
5
+
6
+ const path = `/rest/api/3/issue/${encodeURIComponent(input.issueIdOrKey)}/comment?${params.toString()}`
7
+ const res = await integration.fetch(path)
8
+ const data = await res.json()
9
+ const comments = Array.isArray(data.comments) ? data.comments : []
10
+
11
+ return {
12
+ startAt: data.startAt ?? (input.startAt ?? 0),
13
+ maxResults: data.maxResults ?? (input.maxResults ?? 50),
14
+ total: data.total ?? comments.length,
15
+ comments: comments.map((c) => {
16
+ const md = utils.adf?.toMarkdown(c.body) || ''
17
+ const text = md ? '' : (utils.adf?.toPlainText(c.body) || '')
18
+ return {
19
+ id: c.id ?? null,
20
+ created: c.created ?? null,
21
+ updated: c.updated ?? null,
22
+ author: c.author
23
+ ? { accountId: c.author.accountId ?? null, displayName: c.author.displayName ?? null }
24
+ : null,
25
+ bodyMarkdown: md || null,
26
+ bodyText: md ? null : (text || null),
27
+ }
28
+ }),
29
+ }
30
+ }
31
+
@@ -0,0 +1,14 @@
1
+ async (_input) => {
2
+ const res = await integration.fetch('/rest/api/3/myself')
3
+ const data = await res.json()
4
+
5
+ return {
6
+ accountId: data.accountId ?? null,
7
+ displayName: data.displayName ?? null,
8
+ active: data.active ?? null,
9
+ timeZone: data.timeZone ?? null,
10
+ locale: data.locale ?? null,
11
+ emailAddress: data.emailAddress ?? null,
12
+ }
13
+ }
14
+
@@ -0,0 +1,28 @@
1
+ async (input) => {
2
+ const params = new URLSearchParams()
3
+ if (input.expandIssueTypes !== false)
4
+ params.set('expand', 'issueTypes')
5
+
6
+ const path = `/rest/api/3/project/${encodeURIComponent(input.projectIdOrKey)}${params.toString() ? `?${params.toString()}` : ''}`
7
+ const res = await integration.fetch(path)
8
+ const data = await res.json()
9
+
10
+ const issueTypes = Array.isArray(data.issueTypes) ? data.issueTypes : []
11
+
12
+ return {
13
+ id: data.id ?? null,
14
+ key: data.key ?? null,
15
+ name: data.name ?? null,
16
+ projectTypeKey: data.projectTypeKey ?? null,
17
+ simplified: data.simplified ?? null,
18
+ style: data.style ?? null,
19
+ isPrivate: data.isPrivate ?? null,
20
+ issueTypes: issueTypes.map(t => ({
21
+ id: t.id ?? null,
22
+ name: t.name ?? null,
23
+ description: t.description ?? null,
24
+ subtask: t.subtask ?? null,
25
+ })),
26
+ }
27
+ }
28
+
@@ -0,0 +1,5 @@
1
+ async (input) => {
2
+ const res = await integration.fetch(`/rest/agile/1.0/sprint/${encodeURIComponent(String(input.sprintId))}`)
3
+ return await res.json()
4
+ }
5
+
@@ -0,0 +1,13 @@
1
+ async (input) => {
2
+ const params = new URLSearchParams()
3
+ if (input.jql)
4
+ params.set('jql', input.jql)
5
+ if (Array.isArray(input.fields) && input.fields.length)
6
+ params.set('fields', input.fields.join(','))
7
+ params.set('startAt', String(input.startAt ?? 0))
8
+ params.set('maxResults', String(input.maxResults ?? 50))
9
+
10
+ const res = await integration.fetch(`/rest/agile/1.0/sprint/${encodeURIComponent(String(input.sprintId))}/issue?${params.toString()}`)
11
+ return await res.json()
12
+ }
13
+
@@ -0,0 +1,23 @@
1
+ async (input) => {
2
+ const path = `/rest/api/3/issue/${encodeURIComponent(input.issueIdOrKey)}/transitions`
3
+ const res = await integration.fetch(path)
4
+ const data = await res.json()
5
+ const transitions = Array.isArray(data.transitions) ? data.transitions : []
6
+
7
+ return {
8
+ transitions: transitions.map(t => ({
9
+ id: t.id ?? null,
10
+ name: t.name ?? null,
11
+ to: t.to
12
+ ? {
13
+ id: t.to.id ?? null,
14
+ name: t.to.name ?? null,
15
+ statusCategory: t.to.statusCategory
16
+ ? { key: t.to.statusCategory.key ?? null, name: t.to.statusCategory.name ?? null }
17
+ : null,
18
+ }
19
+ : null,
20
+ })),
21
+ }
22
+ }
23
+
@@ -0,0 +1,34 @@
1
+ async (input) => {
2
+ const params = new URLSearchParams()
3
+ if (input?.projectKeyOrId)
4
+ params.set('projectKeyOrId', input.projectKeyOrId)
5
+ if (input?.type)
6
+ params.set('type', input.type)
7
+ params.set('startAt', String(input?.startAt ?? 0))
8
+ params.set('maxResults', String(input?.maxResults ?? 50))
9
+
10
+ const res = await integration.fetch(`/rest/agile/1.0/board?${params.toString()}`)
11
+ const data = await res.json()
12
+ const values = Array.isArray(data.values) ? data.values : []
13
+
14
+ return {
15
+ startAt: data.startAt ?? (input?.startAt ?? 0),
16
+ maxResults: data.maxResults ?? (input?.maxResults ?? 50),
17
+ total: data.total ?? values.length,
18
+ isLast: Boolean(data.isLast),
19
+ boards: values.map(b => ({
20
+ id: b.id ?? null,
21
+ name: b.name ?? null,
22
+ type: b.type ?? null,
23
+ location: b.location
24
+ ? {
25
+ projectId: b.location.projectId ?? null,
26
+ projectKey: b.location.projectKey ?? null,
27
+ projectName: b.location.projectName ?? null,
28
+ }
29
+ : null,
30
+ self: b.self ?? null,
31
+ })),
32
+ }
33
+ }
34
+
@@ -0,0 +1,29 @@
1
+ async (input) => {
2
+ const params = new URLSearchParams()
3
+ if (input?.query)
4
+ params.set('query', input.query)
5
+ params.set('startAt', String(input?.startAt ?? 0))
6
+ params.set('maxResults', String(input?.maxResults ?? 50))
7
+
8
+ const path = `/rest/api/3/project/search?${params.toString()}`
9
+ const res = await integration.fetch(path)
10
+ const data = await res.json()
11
+ const values = Array.isArray(data.values) ? data.values : []
12
+
13
+ return {
14
+ startAt: data.startAt ?? (input?.startAt ?? 0),
15
+ maxResults: data.maxResults ?? (input?.maxResults ?? 50),
16
+ total: data.total ?? values.length,
17
+ isLast: Boolean(data.isLast),
18
+ projects: values.map(p => ({
19
+ id: p.id ?? null,
20
+ key: p.key ?? null,
21
+ name: p.name ?? null,
22
+ projectTypeKey: p.projectTypeKey ?? null,
23
+ simplified: p.simplified ?? null,
24
+ style: p.style ?? null,
25
+ isPrivate: p.isPrivate ?? null,
26
+ })),
27
+ }
28
+ }
29
+
@@ -0,0 +1,29 @@
1
+ async (input) => {
2
+ const params = new URLSearchParams()
3
+ if (Array.isArray(input.state) && input.state.length)
4
+ params.set('state', input.state.join(','))
5
+ params.set('startAt', String(input.startAt ?? 0))
6
+ params.set('maxResults', String(input.maxResults ?? 50))
7
+
8
+ const res = await integration.fetch(`/rest/agile/1.0/board/${encodeURIComponent(String(input.boardId))}/sprint?${params.toString()}`)
9
+ const data = await res.json()
10
+ const values = Array.isArray(data.values) ? data.values : []
11
+
12
+ return {
13
+ startAt: data.startAt ?? (input.startAt ?? 0),
14
+ maxResults: data.maxResults ?? (input.maxResults ?? 50),
15
+ total: data.total ?? values.length,
16
+ isLast: Boolean(data.isLast),
17
+ sprints: values.map(s => ({
18
+ id: s.id ?? null,
19
+ name: s.name ?? null,
20
+ state: s.state ?? null,
21
+ goal: s.goal ?? null,
22
+ startDate: s.startDate ?? null,
23
+ endDate: s.endDate ?? null,
24
+ completeDate: s.completeDate ?? null,
25
+ self: s.self ?? null,
26
+ })),
27
+ }
28
+ }
29
+
@@ -0,0 +1,11 @@
1
+ async (input) => {
2
+ const res = await integration.fetch(`/rest/agile/1.0/sprint/${encodeURIComponent(String(input.sprintId))}/issue`, {
3
+ method: 'POST',
4
+ body: { issues: input.issueKeys },
5
+ })
6
+
7
+ if (res.status === 204)
8
+ return { success: true }
9
+ return await res.json()
10
+ }
11
+
@@ -0,0 +1,43 @@
1
+ async (input) => {
2
+ const body = {
3
+ jql: input.jql,
4
+ maxResults: input.maxResults ?? 50,
5
+ }
6
+
7
+ if (Array.isArray(input.fields) && input.fields.length)
8
+ body.fields = input.fields
9
+ if (input.nextPageToken)
10
+ body.nextPageToken = input.nextPageToken
11
+
12
+ const res = await integration.fetch('/rest/api/3/search/jql', {
13
+ method: 'POST',
14
+ body,
15
+ })
16
+
17
+ const data = await res.json()
18
+ const issues = Array.isArray(data.issues) ? data.issues : []
19
+
20
+ return {
21
+ isLast: Boolean(data.isLast),
22
+ nextPageToken: data.nextPageToken ?? null,
23
+ issues: issues.map((i) => ({
24
+ id: i.id,
25
+ key: i.key,
26
+ summary: i.fields?.summary ?? null,
27
+ status: i.fields?.status?.name ?? null,
28
+ assignee: i.fields?.assignee
29
+ ? {
30
+ accountId: i.fields.assignee.accountId ?? null,
31
+ displayName: i.fields.assignee.displayName ?? null,
32
+ }
33
+ : null,
34
+ priority: i.fields?.priority?.name ?? null,
35
+ issueType: i.fields?.issuetype?.name ?? null,
36
+ project: i.fields?.project
37
+ ? { key: i.fields.project.key ?? null, name: i.fields.project.name ?? null }
38
+ : null,
39
+ updated: i.fields?.updated ?? null,
40
+ })),
41
+ }
42
+ }
43
+