@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,49 @@
1
+ # Gmail
2
+
3
+ **25 tools** across 2 toolsets
4
+
5
+ ![Gmail tests](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/theomccabe/771bd329f303087690c522afa1baa6f3/raw/test-google-gmail.json)
6
+
7
+ ## Credential variants
8
+
9
+ | Variant | Label |
10
+ |---|---|
11
+ | `service_account` | Service Account (recommended) _(default)_ |
12
+ | `oauth_token` | OAuth Access Token (short-lived) |
13
+
14
+ ## Toolsets
15
+
16
+ | Toolset | Description |
17
+ |---|---|
18
+ | `email` | Search, read, compose, and send emails and drafts |
19
+ | `organize` | Label, archive, trash, and delete messages and threads |
20
+
21
+ ## Tools
22
+
23
+ | Tool | Scope | Toolset | Description |
24
+ |---|---|---|---|
25
+ | `get_profile` | read | `email` | Get mailbox profile details for the authenticated user, including email address, messages… |
26
+ | `list_messages` | read | `email` | List message IDs matching a Gmail search query or label filters. Returns only IDs and thr… |
27
+ | `read_email` | read | `email` | Read an email by message ID and return a flat, decoded result with subject, from, to, cc,… |
28
+ | `get_message` | read | `email` | Get the raw Gmail message resource by message ID. Returns the full nested payload includi… |
29
+ | `list_threads` | read | `email` | List thread IDs matching a Gmail search query or label filters. Similar to list_messages … |
30
+ | `get_thread` | read | `email` | Get a full thread resource by thread ID, including all messages in the conversation. Use … |
31
+ | `list_drafts` | read | `email` | List drafts in the mailbox. Returns draft IDs and the nested message ID. Use get_draft to… |
32
+ | `get_draft` | read | `email` | Get a draft by draft ID. Returns the draft object including the nested message resource. … |
33
+ | `send_email` | write | `email` | Send an email by providing flat fields: to, subject, and body. Handles MIME encoding and … |
34
+ | `create_draft_email` | write | `email` | Create a draft email using flat fields: subject, body, and optionally to, cc, bcc. Handle… |
35
+ | `delete_draft` | write | `email` | Permanently delete a draft by its draft ID. Use list_drafts to find draft IDs. This canno… |
36
+ | `send_draft` | write | `email` | Send an existing draft by draft ID, or send a one-off draft payload (provide raw instead … |
37
+ | `list_labels` | read | `organize` | List all labels in the user's mailbox, including system labels (INBOX, SENT, DRAFT, SPAM,… |
38
+ | `get_label` | read | `organize` | Get details for a specific label by its label ID. Returns name, type, visibility settings… |
39
+ | `modify_message` | write | `organize` | Add or remove labels on a single message. Provide addLabelIds, removeLabelIds, or both. C… |
40
+ | `trash_message` | write | `organize` | Move a message to the Trash. The message is not permanently deleted and can be restored w… |
41
+ | `untrash_message` | write | `organize` | Restore a message from Trash back to the Inbox. Use list_messages with labelIds=['TRASH']… |
42
+ | `delete_message` | write | `organize` | Permanently and immediately delete a message by ID. This cannot be undone. For recoverabl… |
43
+ | `modify_thread` | write | `organize` | Add or remove labels on all messages in a thread at once. Provide addLabelIds, removeLabe… |
44
+ | `trash_thread` | write | `organize` | Move an entire thread to Trash. All messages in the thread are trashed. Can be reversed w… |
45
+ | `untrash_thread` | write | `organize` | Restore an entire thread from Trash. Use list_threads with labelIds=['TRASH'] to find tra… |
46
+ | `delete_thread` | write | `organize` | Permanently and immediately delete an entire thread and all its messages. This cannot be … |
47
+ | `create_label` | admin | `organize` | Create a new mailbox label with optional visibility and color settings. Label names must … |
48
+ | `update_label` | admin | `organize` | Update (patch) an existing mailbox label's name, color, or visibility settings by label I… |
49
+ | `delete_label` | admin | `organize` | Permanently delete a mailbox label by label ID. Messages with this label will have it rem… |
@@ -15,7 +15,7 @@ async (input) => {
15
15
  lines.push('Content-Type: text/plain; charset=UTF-8')
16
16
  lines.push('', input.body || '')
17
17
  }
18
- const raw = Buffer.from(lines.join('\r\n')).toString('base64url')
18
+ const raw = btoa(unescape(encodeURIComponent(lines.join('\r\n')))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
19
19
  const message = { raw }
20
20
  if (input.threadId) message.threadId = input.threadId
21
21
 
@@ -12,7 +12,7 @@ async (input) => {
12
12
  const decodeBase64url = (data) => {
13
13
  if (!data) return ''
14
14
  try {
15
- return Buffer.from(data.replace(/-/g, '+').replace(/_/g, '/'), 'base64').toString('utf-8')
15
+ return decodeURIComponent(escape(atob(data.replace(/-/g, '+').replace(/_/g, '/'))))
16
16
  }
17
17
  catch {
18
18
  return ''
@@ -14,7 +14,7 @@ async (input) => {
14
14
  lines.push('', input.body)
15
15
  }
16
16
  const mime = lines.join('\r\n')
17
- const raw = Buffer.from(mime).toString('base64url')
17
+ const raw = btoa(unescape(encodeURIComponent(mime))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '')
18
18
  const body = { raw }
19
19
  if (input.threadId) body.threadId = input.threadId
20
20
  const res = await integration.fetch(`/users/${userId}/messages/send`, { method: 'POST', body })
@@ -1,33 +1,44 @@
1
1
  {
2
2
  "name": "google-gmail",
3
3
  "version": "0.1.0",
4
+ "toolsets": {
5
+ "email": {
6
+ "label": "Email",
7
+ "description": "Search, read, compose, and send emails and drafts"
8
+ },
9
+ "organize": {
10
+ "label": "Organize",
11
+ "description": "Label, archive, trash, and delete messages and threads"
12
+ }
13
+ },
4
14
  "tools": [
5
- { "name": "get_profile", "description": "Get mailbox profile details for the authenticated user, including email address, messages total, threads total, and history ID. Useful for confirming the active account.", "inputSchema": "schemas/get_profile.json", "handler": "handlers/get_profile.js", "scope": "read" },
6
- { "name": "list_labels", "description": "List all labels in the user's mailbox, including system labels (INBOX, SENT, DRAFT, SPAM, TRASH, STARRED, IMPORTANT, UNREAD) and user-created labels. Returns label IDs needed for filtering in list_messages and list_threads.", "inputSchema": "schemas/list_labels.json", "handler": "handlers/list_labels.js", "scope": "read" },
7
- { "name": "get_label", "description": "Get details for a specific label by its label ID. Returns name, type, visibility settings, and message/thread counts. Use list_labels first to find the label ID.", "inputSchema": "schemas/id_label.json", "handler": "handlers/get_label.js", "scope": "read" },
8
- { "name": "list_messages", "description": "List message IDs matching a Gmail search query or label filters. Returns only IDs and threadIds, not full content -- use read_email or get_message to fetch content for specific messages. Supports Gmail query operators: 'is:unread', 'from:user@example.com', 'to:user@example.com', 'subject:keyword', 'has:attachment', 'after:2024/01/01', 'before:2024/12/31', 'newer_than:7d', 'label:INBOX', 'in:sent'. Defaults to 20 results. Use pageToken from the response for the next page.", "inputSchema": "schemas/list_messages.json", "handler": "handlers/list_messages.js", "scope": "read" },
9
- { "name": "read_email", "description": "Read an email by message ID and return a flat, decoded result with subject, from, to, cc, date, snippet, body text, labelIds, and threadId. Use this for reading email content -- it handles base64 decoding and header extraction automatically. For raw API access or advanced format options, use get_message instead.", "inputSchema": "schemas/read_email.json", "handler": "handlers/read_email.js", "scope": "read" },
10
- { "name": "get_message", "description": "Get the raw Gmail message resource by message ID. Returns the full nested payload including base64url-encoded body parts and all headers. For most use cases, prefer read_email which decodes the response into a flat readable format. Use format='minimal' for lightweight ID+threadId+labelIds only, format='metadata' with metadataHeaders for specific headers only.", "inputSchema": "schemas/get_message.json", "handler": "handlers/get_message.js", "scope": "read" },
11
- { "name": "list_threads", "description": "List thread IDs matching a Gmail search query or label filters. Similar to list_messages but grouped by conversation thread. Returns only IDs -- use get_thread to fetch full thread content. Supports the same Gmail query operators as list_messages. Defaults to 20 results. Use pageToken from the response for the next page.", "inputSchema": "schemas/list_threads.json", "handler": "handlers/list_threads.js", "scope": "read" },
12
- { "name": "get_thread", "description": "Get a full thread resource by thread ID, including all messages in the conversation. Use list_threads to find thread IDs. Use format='minimal' to get only message IDs within the thread without full content.", "inputSchema": "schemas/get_thread.json", "handler": "handlers/get_thread.js", "scope": "read" },
13
- { "name": "list_drafts", "description": "List drafts in the mailbox. Returns draft IDs and the nested message ID. Use get_draft to fetch full draft content. Defaults to 20 results. Use pageToken for the next page.", "inputSchema": "schemas/list_drafts.json", "handler": "handlers/list_drafts.js", "scope": "read" },
14
- { "name": "get_draft", "description": "Get a draft by draft ID. Returns the draft object including the nested message resource. Use list_drafts to find draft IDs.", "inputSchema": "schemas/id_draft.json", "handler": "handlers/get_draft.js", "scope": "read" },
15
+ { "name": "get_profile", "description": "Get mailbox profile details for the authenticated user, including email address, messages total, threads total, and history ID. Useful for confirming the active account.", "inputSchema": "schemas/get_profile.json", "handler": "handlers/get_profile.js", "scope": "read", "toolset": "email" },
16
+ { "name": "list_messages", "description": "List message IDs matching a Gmail search query or label filters. Returns only IDs and threadIds, not full content -- use read_email or get_message to fetch content for specific messages. Supports Gmail query operators: 'is:unread', 'from:user@example.com', 'to:user@example.com', 'subject:keyword', 'has:attachment', 'after:2024/01/01', 'before:2024/12/31', 'newer_than:7d', 'label:INBOX', 'in:sent'. Defaults to 20 results. Use pageToken from the response for the next page.", "inputSchema": "schemas/list_messages.json", "handler": "handlers/list_messages.js", "scope": "read", "toolset": "email" },
17
+ { "name": "read_email", "description": "Read an email by message ID and return a flat, decoded result with subject, from, to, cc, date, snippet, body text, labelIds, and threadId. Use this for reading email content -- it handles base64 decoding and header extraction automatically. For raw API access or advanced format options, use get_message instead.", "inputSchema": "schemas/read_email.json", "handler": "handlers/read_email.js", "scope": "read", "toolset": "email" },
18
+ { "name": "get_message", "description": "Get the raw Gmail message resource by message ID. Returns the full nested payload including base64url-encoded body parts and all headers. For most use cases, prefer read_email which decodes the response into a flat readable format. Use format='minimal' for lightweight ID+threadId+labelIds only, format='metadata' with metadataHeaders for specific headers only.", "inputSchema": "schemas/get_message.json", "handler": "handlers/get_message.js", "scope": "read", "toolset": "email" },
19
+ { "name": "list_threads", "description": "List thread IDs matching a Gmail search query or label filters. Similar to list_messages but grouped by conversation thread. Returns only IDs -- use get_thread to fetch full thread content. Supports the same Gmail query operators as list_messages. Defaults to 20 results. Use pageToken from the response for the next page.", "inputSchema": "schemas/list_threads.json", "handler": "handlers/list_threads.js", "scope": "read", "toolset": "email" },
20
+ { "name": "get_thread", "description": "Get a full thread resource by thread ID, including all messages in the conversation. Use list_threads to find thread IDs. Use format='minimal' to get only message IDs within the thread without full content.", "inputSchema": "schemas/get_thread.json", "handler": "handlers/get_thread.js", "scope": "read", "toolset": "email" },
21
+ { "name": "list_drafts", "description": "List drafts in the mailbox. Returns draft IDs and the nested message ID. Use get_draft to fetch full draft content. Defaults to 20 results. Use pageToken for the next page.", "inputSchema": "schemas/list_drafts.json", "handler": "handlers/list_drafts.js", "scope": "read", "toolset": "email" },
22
+ { "name": "get_draft", "description": "Get a draft by draft ID. Returns the draft object including the nested message resource. Use list_drafts to find draft IDs.", "inputSchema": "schemas/id_draft.json", "handler": "handlers/get_draft.js", "scope": "read", "toolset": "email" },
15
23
 
16
- { "name": "send_email", "description": "Send an email by providing flat fields: to, subject, and body. Handles MIME encoding and base64url conversion internally. For replies, provide replyToMessageId (the original message's ID) and threadId to keep the reply in the same conversation thread. Supports plain text and HTML bodies, CC, and BCC.", "inputSchema": "schemas/send_email.json", "handler": "handlers/send_email.js", "scope": "write" },
17
- { "name": "create_draft_email", "description": "Create a draft email using flat fields: subject, body, and optionally to, cc, bcc. Handles MIME encoding internally. The draft is saved but not sent -- use send_draft to send it later. For replies, provide replyToMessageId and threadId. Supports plain text and HTML bodies.", "inputSchema": "schemas/create_draft_email.json", "handler": "handlers/create_draft_email.js", "scope": "write" },
18
- { "name": "delete_draft", "description": "Permanently delete a draft by its draft ID. Use list_drafts to find draft IDs. This cannot be undone.", "inputSchema": "schemas/id_draft.json", "handler": "handlers/delete_draft.js", "scope": "write" },
19
- { "name": "send_draft", "description": "Send an existing draft by draft ID, or send a one-off draft payload (provide raw instead of draftId). One of draftId or raw must be provided. To send a previously created draft, provide only draftId. To send a new message without saving first, use send_email instead.", "inputSchema": "schemas/send_draft.json", "handler": "handlers/send_draft.js", "scope": "write" },
20
- { "name": "modify_message", "description": "Add or remove labels on a single message. Provide addLabelIds, removeLabelIds, or both. Common label IDs: 'INBOX', 'UNREAD', 'STARRED', 'IMPORTANT', 'TRASH', 'SPAM'. To archive a message, remove 'INBOX'. To mark as read, remove 'UNREAD'. Use list_labels to find custom label IDs.", "inputSchema": "schemas/modify_message.json", "handler": "handlers/modify_message.js", "scope": "write" },
21
- { "name": "trash_message", "description": "Move a message to the Trash. The message is not permanently deleted and can be restored with untrash_message. To permanently delete, use delete_message.", "inputSchema": "schemas/id_message.json", "handler": "handlers/trash_message.js", "scope": "write" },
22
- { "name": "untrash_message", "description": "Restore a message from Trash back to the Inbox. Use list_messages with labelIds=['TRASH'] to find trashed message IDs.", "inputSchema": "schemas/id_message.json", "handler": "handlers/untrash_message.js", "scope": "write" },
23
- { "name": "delete_message", "description": "Permanently and immediately delete a message by ID. This cannot be undone. For recoverable deletion, use trash_message instead.", "inputSchema": "schemas/id_message.json", "handler": "handlers/delete_message.js", "scope": "write" },
24
- { "name": "modify_thread", "description": "Add or remove labels on all messages in a thread at once. Provide addLabelIds, removeLabelIds, or both. Common label IDs: 'INBOX', 'UNREAD', 'STARRED', 'IMPORTANT'. To archive a thread, remove 'INBOX'. Use list_labels to find custom label IDs.", "inputSchema": "schemas/modify_thread.json", "handler": "handlers/modify_thread.js", "scope": "write" },
25
- { "name": "trash_thread", "description": "Move an entire thread to Trash. All messages in the thread are trashed. Can be reversed with untrash_thread.", "inputSchema": "schemas/id_thread.json", "handler": "handlers/trash_thread.js", "scope": "write" },
26
- { "name": "untrash_thread", "description": "Restore an entire thread from Trash. Use list_threads with labelIds=['TRASH'] to find trashed thread IDs.", "inputSchema": "schemas/id_thread.json", "handler": "handlers/untrash_thread.js", "scope": "write" },
27
- { "name": "delete_thread", "description": "Permanently and immediately delete an entire thread and all its messages. This cannot be undone. For recoverable deletion, use trash_thread instead.", "inputSchema": "schemas/id_thread.json", "handler": "handlers/delete_thread.js", "scope": "write" },
24
+ { "name": "send_email", "description": "Send an email by providing flat fields: to, subject, and body. Handles MIME encoding and base64url conversion internally. For replies, provide replyToMessageId (the original message's ID) and threadId to keep the reply in the same conversation thread. Supports plain text and HTML bodies, CC, and BCC.", "inputSchema": "schemas/send_email.json", "handler": "handlers/send_email.js", "scope": "write", "toolset": "email" },
25
+ { "name": "create_draft_email", "description": "Create a draft email using flat fields: subject, body, and optionally to, cc, bcc. Handles MIME encoding internally. The draft is saved but not sent -- use send_draft to send it later. For replies, provide replyToMessageId and threadId. Supports plain text and HTML bodies.", "inputSchema": "schemas/create_draft_email.json", "handler": "handlers/create_draft_email.js", "scope": "write", "toolset": "email" },
26
+ { "name": "delete_draft", "description": "Permanently delete a draft by its draft ID. Use list_drafts to find draft IDs. This cannot be undone.", "inputSchema": "schemas/id_draft.json", "handler": "handlers/delete_draft.js", "scope": "write", "toolset": "email" },
27
+ { "name": "send_draft", "description": "Send an existing draft by draft ID, or send a one-off draft payload (provide raw instead of draftId). One of draftId or raw must be provided. To send a previously created draft, provide only draftId. To send a new message without saving first, use send_email instead.", "inputSchema": "schemas/send_draft.json", "handler": "handlers/send_draft.js", "scope": "write", "toolset": "email" },
28
28
 
29
- { "name": "create_label", "description": "Create a new mailbox label with optional visibility and color settings. Label names must be unique. After creating a label, use its returned ID with modify_message or modify_thread to apply it.", "inputSchema": "schemas/create_label.json", "handler": "handlers/create_label.js", "scope": "admin" },
30
- { "name": "update_label", "description": "Update (patch) an existing mailbox label's name, color, or visibility settings by label ID. Use list_labels to find label IDs.", "inputSchema": "schemas/update_label.json", "handler": "handlers/update_label.js", "scope": "admin" },
31
- { "name": "delete_label", "description": "Permanently delete a mailbox label by label ID. Messages with this label will have it removed but will not be deleted. Use list_labels to find label IDs. System labels (INBOX, SENT, etc.) cannot be deleted.", "inputSchema": "schemas/id_label.json", "handler": "handlers/delete_label.js", "scope": "admin" }
29
+ { "name": "list_labels", "description": "List all labels in the user's mailbox, including system labels (INBOX, SENT, DRAFT, SPAM, TRASH, STARRED, IMPORTANT, UNREAD) and user-created labels. Returns label IDs needed for filtering in list_messages and list_threads.", "inputSchema": "schemas/list_labels.json", "handler": "handlers/list_labels.js", "scope": "read", "toolset": "organize" },
30
+ { "name": "get_label", "description": "Get details for a specific label by its label ID. Returns name, type, visibility settings, and message/thread counts. Use list_labels first to find the label ID.", "inputSchema": "schemas/id_label.json", "handler": "handlers/get_label.js", "scope": "read", "toolset": "organize" },
31
+ { "name": "modify_message", "description": "Add or remove labels on a single message. Provide addLabelIds, removeLabelIds, or both. Common label IDs: 'INBOX', 'UNREAD', 'STARRED', 'IMPORTANT', 'TRASH', 'SPAM'. To archive a message, remove 'INBOX'. To mark as read, remove 'UNREAD'. Use list_labels to find custom label IDs.", "inputSchema": "schemas/modify_message.json", "handler": "handlers/modify_message.js", "scope": "write", "toolset": "organize" },
32
+ { "name": "trash_message", "description": "Move a message to the Trash. The message is not permanently deleted and can be restored with untrash_message. To permanently delete, use delete_message.", "inputSchema": "schemas/id_message.json", "handler": "handlers/trash_message.js", "scope": "write", "toolset": "organize" },
33
+ { "name": "untrash_message", "description": "Restore a message from Trash back to the Inbox. Use list_messages with labelIds=['TRASH'] to find trashed message IDs.", "inputSchema": "schemas/id_message.json", "handler": "handlers/untrash_message.js", "scope": "write", "toolset": "organize" },
34
+ { "name": "delete_message", "description": "Permanently and immediately delete a message by ID. This cannot be undone. For recoverable deletion, use trash_message instead.", "inputSchema": "schemas/id_message.json", "handler": "handlers/delete_message.js", "scope": "write", "toolset": "organize" },
35
+ { "name": "modify_thread", "description": "Add or remove labels on all messages in a thread at once. Provide addLabelIds, removeLabelIds, or both. Common label IDs: 'INBOX', 'UNREAD', 'STARRED', 'IMPORTANT'. To archive a thread, remove 'INBOX'. Use list_labels to find custom label IDs.", "inputSchema": "schemas/modify_thread.json", "handler": "handlers/modify_thread.js", "scope": "write", "toolset": "organize" },
36
+ { "name": "trash_thread", "description": "Move an entire thread to Trash. All messages in the thread are trashed. Can be reversed with untrash_thread.", "inputSchema": "schemas/id_thread.json", "handler": "handlers/trash_thread.js", "scope": "write", "toolset": "organize" },
37
+ { "name": "untrash_thread", "description": "Restore an entire thread from Trash. Use list_threads with labelIds=['TRASH'] to find trashed thread IDs.", "inputSchema": "schemas/id_thread.json", "handler": "handlers/untrash_thread.js", "scope": "write", "toolset": "organize" },
38
+ { "name": "delete_thread", "description": "Permanently and immediately delete an entire thread and all its messages. This cannot be undone. For recoverable deletion, use trash_thread instead.", "inputSchema": "schemas/id_thread.json", "handler": "handlers/delete_thread.js", "scope": "write", "toolset": "organize" },
39
+
40
+ { "name": "create_label", "description": "Create a new mailbox label with optional visibility and color settings. Label names must be unique. After creating a label, use its returned ID with modify_message or modify_thread to apply it.", "inputSchema": "schemas/create_label.json", "handler": "handlers/create_label.js", "scope": "admin", "toolset": "organize" },
41
+ { "name": "update_label", "description": "Update (patch) an existing mailbox label's name, color, or visibility settings by label ID. Use list_labels to find label IDs.", "inputSchema": "schemas/update_label.json", "handler": "handlers/update_label.js", "scope": "admin", "toolset": "organize" },
42
+ { "name": "delete_label", "description": "Permanently delete a mailbox label by label ID. Messages with this label will have it removed but will not be deleted. Use list_labels to find label IDs. System labels (INBOX, SENT, etc.) cannot be deleted.", "inputSchema": "schemas/id_label.json", "handler": "handlers/delete_label.js", "scope": "admin", "toolset": "organize" }
32
43
  ]
33
44
  }
@@ -0,0 +1,27 @@
1
+ # Google Sheets
2
+
3
+ **10 tools**
4
+
5
+ ![Google Sheets tests](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/theomccabe/771bd329f303087690c522afa1baa6f3/raw/test-google-sheet.json)
6
+
7
+ ## Credential variants
8
+
9
+ | Variant | Label |
10
+ |---|---|
11
+ | `service_account` | Service Account (recommended) _(default)_ |
12
+ | `oauth_token` | OAuth Access Token (short-lived) |
13
+
14
+ ## Tools
15
+
16
+ | Tool | Scope | Description |
17
+ |---|---|---|
18
+ | `get_spreadsheet` | read | Retrieve spreadsheet metadata including all sheet names, IDs, and properties. Set include… |
19
+ | `read_sheet` | read | Read cell values from a sheet range and return as a Markdown table with A1 column headers… |
20
+ | `create_spreadsheet` | write | Create a new Google Spreadsheet. Accepts a full spreadsheet resource body, allowing you t… |
21
+ | `update_values` | write | Write values to a specific A1 range, replacing existing content. Use valueInputOption='US… |
22
+ | `append_values` | write | Append rows of values after the last row of existing data in a range. Useful for adding n… |
23
+ | `batch_update_values` | write | Write values to multiple A1 ranges in a single API call. More efficient than calling upda… |
24
+ | `clear_values` | write | Clear all values (but not formatting) in the specified A1 range. The cells remain but the… |
25
+ | `batch_clear_values` | write | Clear values from multiple A1 ranges in a single API call. More efficient than calling cl… |
26
+ | `batch_update` | write | Send a spreadsheets.batchUpdate request for structural changes such as addSheet, deleteSh… |
27
+ | `copy_to_spreadsheet` | write | Copy a specific sheet (tab) from one spreadsheet to another. Provide the source spreadshe… |
@@ -0,0 +1,28 @@
1
+ # Google Slides
2
+
3
+ **11 tools**
4
+
5
+ ![Google Slides tests](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/theomccabe/771bd329f303087690c522afa1baa6f3/raw/test-google-slides.json)
6
+
7
+ ## Credential variants
8
+
9
+ | Variant | Label |
10
+ |---|---|
11
+ | `service_account` | Service Account (recommended) _(default)_ |
12
+ | `oauth_token` | OAuth Access Token (short-lived) |
13
+
14
+ ## Tools
15
+
16
+ | Tool | Scope | Description |
17
+ |---|---|---|
18
+ | `read_presentation` | read | Read a Google Slides presentation and return a human-readable summary including the title… |
19
+ | `get_page_thumbnail` | read | Generate a thumbnail image URL for a specific slide (page) in a presentation. Requires th… |
20
+ | `create_presentation` | write | Create a new empty Google Slides presentation with an optional title. Returns the created… |
21
+ | `batch_update` | write | Send a presentations.batchUpdate request for low-level slide modifications. Accepts an ar… |
22
+ | `append_text_to_title_of_slide_index` | write | Append text to the title shape of a specific slide by its 0-based index (slideIndex=0 is … |
23
+ | `replace_text_first_match` | write | Replace the first occurrence of text anywhere in the presentation with new text. Note: th… |
24
+ | `style_text_first_match` | write | Find the first occurrence of text in the presentation and apply a text style to it (bold,… |
25
+ | `insert_shape_after_first_match` | write | Find the first slide containing a text match and insert a rectangle shape on that slide a… |
26
+ | `insert_image_after_first_match` | write | Find the first slide containing a text match and insert an image on that slide from a URL… |
27
+ | `create_slide_after_first_match` | write | Find the first slide containing a text match and create a new blank slide immediately aft… |
28
+ | `set_background_color_for_slide_index` | write | Set the background color for a specific slide by its 0-based index (slideIndex=0 is the f… |
@@ -0,0 +1,20 @@
1
+ # HubSpot live integration tests
2
+ #
3
+ # HUBSPOT_TOKEN is a private app access token.
4
+ # Create one at: https://developers.hubspot.com/docs/api/private-apps
5
+ # Required scopes: crm.objects.contacts.read/write, crm.objects.companies.read/write,
6
+ # crm.objects.deals.read/write, tickets (read/write), notes (read/write)
7
+ HUBSPOT_TOKEN=
8
+ #
9
+ # Optional: seed IDs for read tests (the suite will discover them automatically if omitted)
10
+ HUBSPOT_TEST_CONTACT_ID=
11
+ HUBSPOT_TEST_COMPANY_ID=
12
+ HUBSPOT_TEST_DEAL_ID=
13
+ HUBSPOT_TEST_TICKET_ID=
14
+ #
15
+ # Optional: pipeline/stage IDs for write tests
16
+ # Find these in HubSpot: Settings → CRM → Deals/Tickets → Pipelines
17
+ HUBSPOT_TEST_DEAL_PIPELINE_ID=
18
+ HUBSPOT_TEST_DEAL_STAGE_ID=
19
+ HUBSPOT_TEST_TICKET_PIPELINE_ID=
20
+ HUBSPOT_TEST_TICKET_STAGE_ID=
@@ -0,0 +1,48 @@
1
+ # HubSpot
2
+
3
+ **31 tools**
4
+
5
+ ![HubSpot tests](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/theomccabe/771bd329f303087690c522afa1baa6f3/raw/test-hubspot.json)
6
+
7
+ ## Credential variants
8
+
9
+ | Variant | Label |
10
+ |---|---|
11
+ | `private_app_token` | Private App Token _(default)_ |
12
+ | `oauth_token` | OAuth Access Token |
13
+
14
+ ## Tools
15
+
16
+ | Tool | Scope | Description |
17
+ |---|---|---|
18
+ | `search_contacts` | read | Search for contacts. Use query for simple free-text search, and filters for precise prope… |
19
+ | `get_contact` | read | Get a contact by ID. Use properties to request specific fields, and associations to inclu… |
20
+ | `create_contact` | write | Create a contact. Provide common fields (firstname/lastname/email) and/or a properties ma… |
21
+ | `update_contact` | write | Update a contact by ID. Provide any fields to update as common fields and/or in the prope… |
22
+ | `archive_contact` | write | Archive (delete) a contact by ID. This moves the record to the recycle bin. |
23
+ | `search_companies` | read | Search for companies. Use query for free-text search and filters for property-based filte… |
24
+ | `get_company` | read | Get a company by ID. Use properties to request specific fields, and associations to inclu… |
25
+ | `create_company` | write | Create a company. Provide name/domain and/or a properties map for other HubSpot company p… |
26
+ | `update_company` | write | Update a company by ID. Provide any fields to update as common fields and/or in the prope… |
27
+ | `archive_company` | write | Archive (delete) a company by ID. This moves the record to the recycle bin. |
28
+ | `list_owners` | read | List CRM owners (users) available in the HubSpot account. Useful for assigning owners to … |
29
+ | `list_properties` | read | List properties for an object type (e.g. contacts, companies, deals, tickets). Use this t… |
30
+ | `list_pipelines` | read | List pipelines and stages for an object type (commonly deals or tickets). Use this to fin… |
31
+ | `get_associations` | read | Get associations from a CRM record to another object type. Returns the associated record … |
32
+ | `create_association` | write | Create a default (unlabeled) association between two CRM records. Example: associate a co… |
33
+ | `remove_association` | write | Remove an association between two CRM records. This uses HubSpot's association batch arch… |
34
+ | `search_deals` | read | Search for deals. Use query for free-text search and filters for property-based filtering… |
35
+ | `get_deal` | read | Get a deal by ID. Use properties to request specific fields, and associations to include … |
36
+ | `create_deal` | write | Create a deal. Provide dealname/amount/pipeline/dealstage and/or a properties map for oth… |
37
+ | `update_deal` | write | Update a deal by ID. Common updates include moving stages via dealstage. Fields not provi… |
38
+ | `archive_deal` | write | Archive (delete) a deal by ID. This moves the record to the recycle bin. |
39
+ | `search_tickets` | read | Search for tickets. Use query for free-text search and filters for property-based filteri… |
40
+ | `get_ticket` | read | Get a ticket by ID. Use properties to request specific fields, and associations to includ… |
41
+ | `create_ticket` | write | Create a ticket. Provide subject/content/pipeline/stage and/or a properties map for other… |
42
+ | `update_ticket` | write | Update a ticket by ID. Common updates include changing hs_pipeline_stage. Fields not prov… |
43
+ | `archive_ticket` | write | Archive (delete) a ticket by ID. This moves the record to the recycle bin. |
44
+ | `search_notes` | read | Search notes. Use query for free-text search and filters for precise property-based filte… |
45
+ | `create_note` | write | Create a note and (optionally) associate it to one or more CRM records (contacts, compani… |
46
+ | `search_tasks` | read | Search tasks. Use query for free-text search and filters for precise property-based filte… |
47
+ | `create_task` | write | Create a task and (optionally) associate it to one or more CRM records. Provide subject/b… |
48
+ | `update_task` | write | Update a task by ID. Common updates include setting hs_task_status to COMPLETED. |
@@ -0,0 +1,151 @@
1
+ import { beforeAll, describe, expect, it } from 'vitest'
2
+ import {
3
+ createCredentialStore,
4
+ createIntegrationNode,
5
+ createProxy,
6
+ createToolbox,
7
+ hasEnv,
8
+ } from '../../__tests__/liveHarness.js'
9
+
10
+ // LIVE HubSpot read tests using credentials
11
+ // Required env vars:
12
+ // - HUBSPOT_TOKEN
13
+ //
14
+ // Optional env vars:
15
+ // - HUBSPOT_TEST_CONTACT_ID
16
+ // - HUBSPOT_TEST_COMPANY_ID
17
+ // - HUBSPOT_TEST_DEAL_ID
18
+ // - HUBSPOT_TEST_TICKET_ID
19
+
20
+ const env = process.env as Record<string, string | undefined>
21
+ const suite = hasEnv('HUBSPOT_TOKEN') ? describe : describe.skip
22
+
23
+ suite('hubspot read handlers (live)', () => {
24
+ const ctx: {
25
+ contactId?: string
26
+ companyId?: string
27
+ dealId?: string
28
+ ticketId?: string
29
+ } = {}
30
+
31
+ let read: Record<string, (input: any) => Promise<any>>
32
+
33
+ beforeAll(async () => {
34
+ ctx.contactId = env.HUBSPOT_TEST_CONTACT_ID
35
+ ctx.companyId = env.HUBSPOT_TEST_COMPANY_ID
36
+ ctx.dealId = env.HUBSPOT_TEST_DEAL_ID
37
+ ctx.ticketId = env.HUBSPOT_TEST_TICKET_ID
38
+
39
+ const credentialStore = createCredentialStore(async () => ({ token: env.HUBSPOT_TOKEN || '' }))
40
+ const proxy = createProxy(credentialStore)
41
+ const node = createIntegrationNode('hubspot')
42
+ const toolbox = createToolbox('hubspot', proxy, node)
43
+
44
+ // IMPORTANT: These literal tool-name strings are intentionally present so usage-parity can verify coverage.
45
+ read = {
46
+ search_contacts: toolbox.read('search_contacts'),
47
+ get_contact: toolbox.read('get_contact'),
48
+ search_companies: toolbox.read('search_companies'),
49
+ get_company: toolbox.read('get_company'),
50
+ list_owners: toolbox.read('list_owners'),
51
+ list_properties: toolbox.read('list_properties'),
52
+ list_pipelines: toolbox.read('list_pipelines'),
53
+ get_associations: toolbox.read('get_associations'),
54
+ search_deals: toolbox.read('search_deals'),
55
+ get_deal: toolbox.read('get_deal'),
56
+ search_tickets: toolbox.read('search_tickets'),
57
+ get_ticket: toolbox.read('get_ticket'),
58
+ search_notes: toolbox.read('search_notes'),
59
+ search_tasks: toolbox.read('search_tasks'),
60
+ // read tools in the manifest are limited to those above; remaining tools are write-scoped
61
+ }
62
+
63
+ expect(read).toBeTruthy()
64
+ }, 60000)
65
+
66
+ it('search_contacts returns results (or empty)', async () => {
67
+ const result = await read.search_contacts({ limit: 1 })
68
+ expect(result).toBeTruthy()
69
+ }, 30000)
70
+
71
+ it('search_companies returns results (or empty)', async () => {
72
+ const result = await read.search_companies({ limit: 1 })
73
+ expect(result).toBeTruthy()
74
+ }, 30000)
75
+
76
+ it('list_owners returns owners', async () => {
77
+ const result = await read.list_owners({ limit: 1 })
78
+ expect(result).toBeTruthy()
79
+ }, 30000)
80
+
81
+ it('list_properties(contacts) returns properties', async () => {
82
+ const result = await read.list_properties({ objectType: 'contacts' })
83
+ expect(result).toBeTruthy()
84
+ }, 30000)
85
+
86
+ it('list_pipelines(deals) returns pipelines', async () => {
87
+ const result = await read.list_pipelines({ objectType: 'deals' })
88
+ expect(result).toBeTruthy()
89
+ }, 30000)
90
+
91
+ it('get_contact returns a contact when HUBSPOT_TEST_CONTACT_ID is set', async () => {
92
+ if (!ctx.contactId)
93
+ return expect(true).toBe(true)
94
+ const result = await read.get_contact({ id: ctx.contactId })
95
+ expect(result?.id).toBeTruthy()
96
+ }, 30000)
97
+
98
+ it('get_company returns a company when HUBSPOT_TEST_COMPANY_ID is set', async () => {
99
+ if (!ctx.companyId)
100
+ return expect(true).toBe(true)
101
+ const result = await read.get_company({ id: ctx.companyId })
102
+ expect(result?.id).toBeTruthy()
103
+ }, 30000)
104
+
105
+ it('get_deal returns a deal when HUBSPOT_TEST_DEAL_ID is set', async () => {
106
+ if (!ctx.dealId)
107
+ return expect(true).toBe(true)
108
+ const result = await read.get_deal({ id: ctx.dealId })
109
+ expect(result?.id).toBeTruthy()
110
+ }, 30000)
111
+
112
+ it('get_ticket returns a ticket when HUBSPOT_TEST_TICKET_ID is set', async () => {
113
+ if (!ctx.ticketId)
114
+ return expect(true).toBe(true)
115
+ const result = await read.get_ticket({ id: ctx.ticketId })
116
+ expect(result?.id).toBeTruthy()
117
+ }, 30000)
118
+
119
+ it('search_deals returns results (or empty)', async () => {
120
+ const result = await read.search_deals({ limit: 1 })
121
+ expect(result).toBeTruthy()
122
+ }, 30000)
123
+
124
+ it('search_tickets returns results (or empty)', async () => {
125
+ const result = await read.search_tickets({ limit: 1 })
126
+ expect(result).toBeTruthy()
127
+ }, 30000)
128
+
129
+ it('search_notes returns results (or empty)', async () => {
130
+ const result = await read.search_notes({ limit: 1 })
131
+ expect(result).toBeTruthy()
132
+ }, 30000)
133
+
134
+ it('search_tasks returns results (or empty)', async () => {
135
+ const result = await read.search_tasks({ limit: 1 })
136
+ expect(result).toBeTruthy()
137
+ }, 30000)
138
+
139
+ it('get_associations returns associations when HUBSPOT_TEST_CONTACT_ID is set', async () => {
140
+ if (!ctx.contactId)
141
+ return expect(true).toBe(true)
142
+ const result = await read.get_associations({
143
+ fromObjectType: 'contacts',
144
+ fromObjectId: ctx.contactId,
145
+ toObjectType: 'companies',
146
+ limit: 1,
147
+ })
148
+ expect(result).toBeTruthy()
149
+ }, 30000)
150
+ })
151
+
@@ -0,0 +1,10 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { getMissingToolUsages } from '../../__tests__/usageParity.js'
3
+
4
+ describe('hubspot static usage parity', () => {
5
+ it('every manifest tool is referenced in tests', () => {
6
+ const missing = getMissingToolUsages({ integrationName: 'hubspot', importMetaUrl: import.meta.url })
7
+ expect(missing, `Missing handler usages in tests: ${missing.join(', ')}`).toEqual([])
8
+ })
9
+ })
10
+