runline 0.2.1 → 0.2.2

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 (189) hide show
  1. package/dist/plugins/actionNetwork/src/index.js +118 -25
  2. package/dist/plugins/activeCampaign/src/index.js +184 -38
  3. package/dist/plugins/adalo/src/index.js +40 -8
  4. package/dist/plugins/affinity/src/index.js +100 -20
  5. package/dist/plugins/agileCrm/src/index.js +115 -27
  6. package/dist/plugins/airtable/src/index.js +94 -19
  7. package/dist/plugins/airtop/src/index.js +266 -62
  8. package/dist/plugins/apiTemplateIo/src/index.js +25 -5
  9. package/dist/plugins/asana/src/index.js +195 -41
  10. package/dist/plugins/autopilot/src/index.js +39 -8
  11. package/dist/plugins/bambooHr/src/index.js +109 -22
  12. package/dist/plugins/bannerbear/src/index.js +36 -8
  13. package/dist/plugins/baserow/src/index.js +35 -7
  14. package/dist/plugins/beeminder/src/index.js +198 -40
  15. package/dist/plugins/bitly/src/index.js +46 -10
  16. package/dist/plugins/bitwarden/src/index.js +167 -36
  17. package/dist/plugins/box/src/index.js +172 -37
  18. package/dist/plugins/brandfetch/src/index.js +5 -1
  19. package/dist/plugins/brevo/src/index.js +136 -29
  20. package/dist/plugins/bubble/src/index.js +76 -17
  21. package/dist/plugins/chargebee/src/index.js +35 -7
  22. package/dist/plugins/circleci/src/index.js +50 -10
  23. package/dist/plugins/ciscoWebex/src/index.js +131 -27
  24. package/dist/plugins/clearbit/src/index.js +76 -17
  25. package/dist/plugins/clickup/src/index.js +500 -107
  26. package/dist/plugins/clockify/src/index.js +229 -47
  27. package/dist/plugins/cloudflare/src/index.js +28 -6
  28. package/dist/plugins/cockpit/src/index.js +54 -12
  29. package/dist/plugins/coda/src/index.js +81 -19
  30. package/dist/plugins/coingecko/src/index.js +157 -33
  31. package/dist/plugins/contentful/src/index.js +85 -17
  32. package/dist/plugins/convertkit/src/index.js +74 -18
  33. package/dist/plugins/copper/src/index.js +59 -11
  34. package/dist/plugins/cortex/src/index.js +55 -13
  35. package/dist/plugins/currents/src/index.js +310 -71
  36. package/dist/plugins/customerIo/src/index.js +112 -23
  37. package/dist/plugins/databricks/src/index.js +549 -115
  38. package/dist/plugins/deepl/src/index.js +26 -6
  39. package/dist/plugins/demio/src/index.js +56 -11
  40. package/dist/plugins/dhl/src/index.js +16 -3
  41. package/dist/plugins/discord/src/index.js +141 -31
  42. package/dist/plugins/discourse/src/index.js +136 -31
  43. package/dist/plugins/disqus/src/index.js +96 -20
  44. package/dist/plugins/docker/src/index.js +20 -4
  45. package/dist/plugins/drift/src/index.js +19 -5
  46. package/dist/plugins/dropbox/src/index.js +139 -30
  47. package/dist/plugins/dropcontact/src/index.js +21 -4
  48. package/dist/plugins/egoi/src/index.js +61 -15
  49. package/dist/plugins/elasticsearch/src/index.js +59 -13
  50. package/dist/plugins/emelia/src/index.js +95 -19
  51. package/dist/plugins/erpnext/src/index.js +74 -15
  52. package/dist/plugins/facebookGraph/src/index.js +52 -11
  53. package/dist/plugins/freshdesk/src/index.js +220 -48
  54. package/dist/plugins/freshservice/src/index.js +39 -9
  55. package/dist/plugins/freshworksCrm/src/index.js +58 -12
  56. package/dist/plugins/getresponse/src/index.js +87 -18
  57. package/dist/plugins/ghost/src/index.js +114 -26
  58. package/dist/plugins/github/src/index.js +483 -109
  59. package/dist/plugins/gitlab/src/index.js +193 -45
  60. package/dist/plugins/gong/src/index.js +68 -14
  61. package/dist/plugins/gotify/src/index.js +43 -9
  62. package/dist/plugins/gotowebinar/src/index.js +233 -47
  63. package/dist/plugins/grafana/src/index.js +92 -21
  64. package/dist/plugins/graphql/src/index.js +38 -8
  65. package/dist/plugins/grist/src/index.js +52 -10
  66. package/dist/plugins/hackernews/src/index.js +32 -6
  67. package/dist/plugins/halopsa/src/index.js +131 -26
  68. package/dist/plugins/harvest/src/index.js +182 -42
  69. package/dist/plugins/helpscout/src/index.js +153 -31
  70. package/dist/plugins/highlevel/src/index.js +291 -58
  71. package/dist/plugins/homeAssistant/src/index.js +124 -26
  72. package/dist/plugins/hubspot/src/index.js +163 -29
  73. package/dist/plugins/humanticAi/src/index.js +54 -5
  74. package/dist/plugins/hunter/src/index.js +21 -4
  75. package/dist/plugins/intercom/src/index.js +95 -20
  76. package/dist/plugins/iterable/src/index.js +96 -20
  77. package/dist/plugins/jenkins/src/index.js +75 -17
  78. package/dist/plugins/jira/src/index.js +193 -43
  79. package/dist/plugins/keap/src/index.js +222 -56
  80. package/dist/plugins/kobotoolbox/src/index.js +113 -25
  81. package/dist/plugins/lemlist/src/index.js +79 -18
  82. package/dist/plugins/linear/src/index.js +86 -19
  83. package/dist/plugins/lingvanex/src/index.js +38 -8
  84. package/dist/plugins/linkedin/src/index.js +37 -8
  85. package/dist/plugins/lonescale/src/index.js +41 -9
  86. package/dist/plugins/magento/src/index.js +98 -27
  87. package/dist/plugins/mailcheck/src/index.js +11 -2
  88. package/dist/plugins/mailchimp/src/index.js +193 -42
  89. package/dist/plugins/mailerlite/src/index.js +61 -12
  90. package/dist/plugins/mailgun/src/index.js +39 -7
  91. package/dist/plugins/mailjet/src/index.js +141 -30
  92. package/dist/plugins/mandrill/src/index.js +67 -14
  93. package/dist/plugins/marketstack/src/index.js +56 -10
  94. package/dist/plugins/matrix/src/index.js +97 -20
  95. package/dist/plugins/mattermost/src/index.js +124 -26
  96. package/dist/plugins/mautic/src/index.js +129 -26
  97. package/dist/plugins/medium/src/index.js +64 -13
  98. package/dist/plugins/messagebird/src/index.js +80 -15
  99. package/dist/plugins/metabase/src/index.js +57 -12
  100. package/dist/plugins/misp/src/index.js +135 -33
  101. package/dist/plugins/mocean/src/index.js +33 -7
  102. package/dist/plugins/monday/src/index.js +97 -23
  103. package/dist/plugins/monicaCrm/src/index.js +112 -23
  104. package/dist/plugins/msg91/src/index.js +11 -2
  105. package/dist/plugins/nasa/src/index.js +108 -21
  106. package/dist/plugins/netlify/src/index.js +28 -6
  107. package/dist/plugins/netscalerAdc/src/index.js +144 -29
  108. package/dist/plugins/nextcloud/src/index.js +103 -20
  109. package/dist/plugins/nocodb/src/index.js +57 -11
  110. package/dist/plugins/notion/src/index.js +148 -37
  111. package/dist/plugins/npm/src/index.js +59 -12
  112. package/dist/plugins/odoo/src/index.js +102 -20
  113. package/dist/plugins/okta/src/index.js +50 -10
  114. package/dist/plugins/oneSimpleApi/src/index.js +84 -17
  115. package/dist/plugins/onfleet/src/index.js +139 -32
  116. package/dist/plugins/openThesaurus/src/index.js +46 -9
  117. package/dist/plugins/openweathermap/src/index.js +31 -6
  118. package/dist/plugins/oura/src/index.js +36 -7
  119. package/dist/plugins/paddle/src/index.js +80 -17
  120. package/dist/plugins/pagerduty/src/index.js +53 -12
  121. package/dist/plugins/paypal/src/index.js +51 -11
  122. package/dist/plugins/peekalink/src/index.js +12 -3
  123. package/dist/plugins/phantombuster/src/index.js +39 -8
  124. package/dist/plugins/philipsHue/src/index.js +64 -13
  125. package/dist/plugins/pipedrive/src/index.js +167 -45
  126. package/dist/plugins/plivo/src/index.js +43 -8
  127. package/dist/plugins/postbin/src/index.js +9 -2
  128. package/dist/plugins/posthog/src/index.js +50 -13
  129. package/dist/plugins/profitwell/src/index.js +24 -5
  130. package/dist/plugins/pushbullet/src/index.js +45 -9
  131. package/dist/plugins/pushcut/src/index.js +31 -6
  132. package/dist/plugins/pushover/src/index.js +51 -10
  133. package/dist/plugins/quickbase/src/index.js +66 -13
  134. package/dist/plugins/quickbooks/src/index.js +86 -19
  135. package/dist/plugins/quickchart/src/index.js +35 -7
  136. package/dist/plugins/raindrop/src/index.js +54 -13
  137. package/dist/plugins/reddit/src/index.js +73 -18
  138. package/dist/plugins/rocketchat/src/index.js +47 -9
  139. package/dist/plugins/rundeck/src/index.js +26 -5
  140. package/dist/plugins/salesforce/src/index.js +161 -31
  141. package/dist/plugins/salesmate/src/index.js +75 -16
  142. package/dist/plugins/securityScorecard/src/index.js +73 -15
  143. package/dist/plugins/segment/src/index.js +21 -4
  144. package/dist/plugins/sendgrid/src/index.js +102 -24
  145. package/dist/plugins/sendy/src/index.js +54 -11
  146. package/dist/plugins/sentry/src/index.js +174 -34
  147. package/dist/plugins/servicenow/src/index.js +120 -27
  148. package/dist/plugins/shopify/src/index.js +53 -12
  149. package/dist/plugins/signl4/src/index.js +16 -3
  150. package/dist/plugins/slack/src/index.js +407 -105
  151. package/dist/plugins/sms77/src/index.js +26 -5
  152. package/dist/plugins/splunk/src/index.js +186 -45
  153. package/dist/plugins/spotify/src/index.js +265 -66
  154. package/dist/plugins/stackby/src/index.js +18 -6
  155. package/dist/plugins/storyblok/src/index.js +57 -11
  156. package/dist/plugins/strapi/src/index.js +63 -12
  157. package/dist/plugins/strava/src/index.js +58 -13
  158. package/dist/plugins/stripe/src/index.js +143 -30
  159. package/dist/plugins/supabase/src/index.js +49 -10
  160. package/dist/plugins/syncromsp/src/index.js +245 -67
  161. package/dist/plugins/tapfiliate/src/index.js +57 -14
  162. package/dist/plugins/telegram/src/index.js +202 -39
  163. package/dist/plugins/thehive/src/index.js +271 -66
  164. package/dist/plugins/thehiveProject/src/index.js +457 -89
  165. package/dist/plugins/todoist/src/index.js +326 -77
  166. package/dist/plugins/travisci/src/index.js +35 -8
  167. package/dist/plugins/trello/src/index.js +204 -46
  168. package/dist/plugins/twake/src/index.js +10 -2
  169. package/dist/plugins/twilio/src/index.js +56 -11
  170. package/dist/plugins/twist/src/index.js +241 -48
  171. package/dist/plugins/twitter/src/index.js +128 -30
  172. package/dist/plugins/unleashedSoftware/src/index.js +30 -6
  173. package/dist/plugins/uplead/src/index.js +9 -2
  174. package/dist/plugins/uproc/src/index.js +31 -6
  175. package/dist/plugins/uptimerobot/src/index.js +119 -25
  176. package/dist/plugins/urlscanio/src/index.js +25 -6
  177. package/dist/plugins/vero/src/index.js +68 -13
  178. package/dist/plugins/vonage/src/index.js +32 -6
  179. package/dist/plugins/wekan/src/index.js +297 -52
  180. package/dist/plugins/woocommerce/src/index.js +57 -12
  181. package/dist/plugins/wordpress/src/index.js +94 -18
  182. package/dist/plugins/xero/src/index.js +79 -13
  183. package/dist/plugins/yourls/src/index.js +33 -6
  184. package/dist/plugins/zammad/src/index.js +139 -36
  185. package/dist/plugins/zendesk/src/index.js +201 -48
  186. package/dist/plugins/zoho/src/index.js +88 -21
  187. package/dist/plugins/zoom/src/index.js +41 -7
  188. package/dist/plugins/zulip/src/index.js +101 -20
  189. package/package.json +1 -1
@@ -9,9 +9,17 @@ async function apiRequest(token, accountId, method, endpoint, body, qs) {
9
9
  }
10
10
  const opts = {
11
11
  method,
12
- headers: { Authorization: `Bearer ${token}`, "Harvest-Account-Id": accountId, "Content-Type": "application/json", "User-Agent": "Runline" },
12
+ headers: {
13
+ Authorization: `Bearer ${token}`,
14
+ "Harvest-Account-Id": accountId,
15
+ "Content-Type": "application/json",
16
+ "User-Agent": "Runline",
17
+ },
13
18
  };
14
- if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE")
19
+ if (body &&
20
+ Object.keys(body).length > 0 &&
21
+ method !== "GET" &&
22
+ method !== "DELETE")
15
23
  opts.body = JSON.stringify(body);
16
24
  const res = await fetch(url.toString(), opts);
17
25
  if (!res.ok)
@@ -21,47 +29,103 @@ async function apiRequest(token, accountId, method, endpoint, body, qs) {
21
29
  return res.json();
22
30
  }
23
31
  function getConn(ctx) {
24
- return { token: ctx.connection.config.token, accountId: ctx.connection.config.accountId };
32
+ return {
33
+ token: ctx.connection.config.token,
34
+ accountId: ctx.connection.config.accountId,
35
+ };
25
36
  }
26
37
  function hv(ctx, method, endpoint, body, qs) {
27
38
  const { token, accountId } = getConn(ctx);
28
39
  return apiRequest(token, accountId, method, endpoint, body, qs);
29
40
  }
30
41
  function unwrapList(data, key) {
31
- if (data && typeof data === "object" && key in data)
42
+ if (data &&
43
+ typeof data === "object" &&
44
+ key in data)
32
45
  return data[key];
33
46
  return data;
34
47
  }
35
48
  function registerCrud(rl, resource, apiPath, listKey) {
36
49
  rl.registerAction(`${resource}.create`, {
37
- description: `Create a ${resource}`, inputSchema: { properties: { type: "object", required: true, description: `${resource} data` } },
38
- async execute(input, ctx) { return hv(ctx, "POST", apiPath, input.properties); },
50
+ description: `Create a ${resource}`,
51
+ inputSchema: {
52
+ properties: {
53
+ type: "object",
54
+ required: true,
55
+ description: `${resource} data`,
56
+ },
57
+ },
58
+ async execute(input, ctx) {
59
+ return hv(ctx, "POST", apiPath, input.properties);
60
+ },
39
61
  });
40
62
  rl.registerAction(`${resource}.get`, {
41
- description: `Get a ${resource}`, inputSchema: { id: { type: "number", required: true, description: `${resource} ID` } },
42
- async execute(input, ctx) { return hv(ctx, "GET", `${apiPath}/${input.id}`); },
63
+ description: `Get a ${resource}`,
64
+ inputSchema: {
65
+ id: { type: "number", required: true, description: `${resource} ID` },
66
+ },
67
+ async execute(input, ctx) {
68
+ return hv(ctx, "GET", `${apiPath}/${input.id}`);
69
+ },
43
70
  });
44
71
  rl.registerAction(`${resource}.list`, {
45
- description: `List ${resource}s`, inputSchema: { limit: { type: "number", required: false, description: "Max results" }, page: { type: "number", required: false, description: "Page" } },
46
- async execute(input, ctx) { const { limit, page } = (input ?? {}); const qs = {}; if (limit)
47
- qs.per_page = limit; if (page)
48
- qs.page = page; return unwrapList(await hv(ctx, "GET", apiPath, undefined, qs), listKey); },
72
+ description: `List ${resource}s`,
73
+ inputSchema: {
74
+ limit: { type: "number", required: false, description: "Max results" },
75
+ page: { type: "number", required: false, description: "Page" },
76
+ },
77
+ async execute(input, ctx) {
78
+ const { limit, page } = (input ?? {});
79
+ const qs = {};
80
+ if (limit)
81
+ qs.per_page = limit;
82
+ if (page)
83
+ qs.page = page;
84
+ return unwrapList(await hv(ctx, "GET", apiPath, undefined, qs), listKey);
85
+ },
49
86
  });
50
87
  rl.registerAction(`${resource}.update`, {
51
- description: `Update a ${resource}`, inputSchema: { id: { type: "number", required: true, description: `${resource} ID` }, properties: { type: "object", required: true, description: "Fields to update" } },
52
- async execute(input, ctx) { const { id, properties } = input; return hv(ctx, "PATCH", `${apiPath}/${id}`, properties); },
88
+ description: `Update a ${resource}`,
89
+ inputSchema: {
90
+ id: { type: "number", required: true, description: `${resource} ID` },
91
+ properties: {
92
+ type: "object",
93
+ required: true,
94
+ description: "Fields to update",
95
+ },
96
+ },
97
+ async execute(input, ctx) {
98
+ const { id, properties } = input;
99
+ return hv(ctx, "PATCH", `${apiPath}/${id}`, properties);
100
+ },
53
101
  });
54
102
  rl.registerAction(`${resource}.delete`, {
55
- description: `Delete a ${resource}`, inputSchema: { id: { type: "number", required: true, description: `${resource} ID` } },
56
- async execute(input, ctx) { await hv(ctx, "DELETE", `${apiPath}/${input.id}`); return { success: true }; },
103
+ description: `Delete a ${resource}`,
104
+ inputSchema: {
105
+ id: { type: "number", required: true, description: `${resource} ID` },
106
+ },
107
+ async execute(input, ctx) {
108
+ await hv(ctx, "DELETE", `${apiPath}/${input.id}`);
109
+ return { success: true };
110
+ },
57
111
  });
58
112
  }
59
113
  export default function harvest(rl) {
60
114
  rl.setName("harvest");
61
115
  rl.setVersion("0.1.0");
62
116
  rl.setConnectionSchema({
63
- token: { type: "string", required: true, description: "Harvest personal access token", env: "HARVEST_TOKEN" },
64
- accountId: { type: "string", required: true, description: "Harvest account ID", env: "HARVEST_ACCOUNT_ID" },
117
+ token: {
118
+ type: "string",
119
+ required: true,
120
+ description: "Harvest personal access token",
121
+ env: "HARVEST_TOKEN",
122
+ },
123
+ accountId: {
124
+ type: "string",
125
+ required: true,
126
+ description: "Harvest account ID",
127
+ env: "HARVEST_ACCOUNT_ID",
128
+ },
65
129
  });
66
130
  // Standard CRUD resources
67
131
  registerCrud(rl, "client", "clients", "clients");
@@ -75,7 +139,9 @@ export default function harvest(rl) {
75
139
  registerCrud(rl, "user", "users", "users");
76
140
  rl.registerAction("user.me", {
77
141
  description: "Get the currently authenticated user",
78
- async execute(_input, ctx) { return hv(ctx, "GET", "users/me"); },
142
+ async execute(_input, ctx) {
143
+ return hv(ctx, "GET", "users/me");
144
+ },
79
145
  });
80
146
  // Time entry (special operations)
81
147
  rl.registerAction("timeEntry.create", {
@@ -83,16 +149,40 @@ export default function harvest(rl) {
83
149
  inputSchema: {
84
150
  projectId: { type: "number", required: true, description: "Project ID" },
85
151
  taskId: { type: "number", required: true, description: "Task ID" },
86
- spentDate: { type: "string", required: true, description: "Date (YYYY-MM-DD)" },
87
- hours: { type: "number", required: false, description: "Hours (for duration-based)" },
88
- startedTime: { type: "string", required: false, description: "Start time HH:MM (for start/end)" },
89
- endedTime: { type: "string", required: false, description: "End time HH:MM" },
152
+ spentDate: {
153
+ type: "string",
154
+ required: true,
155
+ description: "Date (YYYY-MM-DD)",
156
+ },
157
+ hours: {
158
+ type: "number",
159
+ required: false,
160
+ description: "Hours (for duration-based)",
161
+ },
162
+ startedTime: {
163
+ type: "string",
164
+ required: false,
165
+ description: "Start time HH:MM (for start/end)",
166
+ },
167
+ endedTime: {
168
+ type: "string",
169
+ required: false,
170
+ description: "End time HH:MM",
171
+ },
90
172
  notes: { type: "string", required: false, description: "Notes" },
91
- userId: { type: "number", required: false, description: "User ID (admin only)" },
173
+ userId: {
174
+ type: "number",
175
+ required: false,
176
+ description: "User ID (admin only)",
177
+ },
92
178
  },
93
179
  async execute(input, ctx) {
94
- const { projectId, taskId, spentDate, hours, startedTime, endedTime, notes, userId } = input;
95
- const body = { project_id: projectId, task_id: taskId, spent_date: spentDate };
180
+ const { projectId, taskId, spentDate, hours, startedTime, endedTime, notes, userId, } = input;
181
+ const body = {
182
+ project_id: projectId,
183
+ task_id: taskId,
184
+ spent_date: spentDate,
185
+ };
96
186
  if (hours !== undefined)
97
187
  body.hours = hours;
98
188
  if (startedTime)
@@ -107,21 +197,43 @@ export default function harvest(rl) {
107
197
  },
108
198
  });
109
199
  rl.registerAction("timeEntry.get", {
110
- description: "Get a time entry", inputSchema: { id: { type: "number", required: true, description: "Time entry ID" } },
111
- async execute(input, ctx) { return hv(ctx, "GET", `time_entries/${input.id}`); },
200
+ description: "Get a time entry",
201
+ inputSchema: {
202
+ id: { type: "number", required: true, description: "Time entry ID" },
203
+ },
204
+ async execute(input, ctx) {
205
+ return hv(ctx, "GET", `time_entries/${input.id}`);
206
+ },
112
207
  });
113
208
  rl.registerAction("timeEntry.list", {
114
209
  description: "List time entries",
115
210
  inputSchema: {
116
211
  limit: { type: "number", required: false, description: "Max results" },
117
212
  page: { type: "number", required: false, description: "Page" },
118
- from: { type: "string", required: false, description: "From date (YYYY-MM-DD)" },
119
- to: { type: "string", required: false, description: "To date (YYYY-MM-DD)" },
120
- userId: { type: "number", required: false, description: "Filter by user" },
121
- projectId: { type: "number", required: false, description: "Filter by project" },
213
+ from: {
214
+ type: "string",
215
+ required: false,
216
+ description: "From date (YYYY-MM-DD)",
217
+ },
218
+ to: {
219
+ type: "string",
220
+ required: false,
221
+ description: "To date (YYYY-MM-DD)",
222
+ },
223
+ userId: {
224
+ type: "number",
225
+ required: false,
226
+ description: "Filter by user",
227
+ },
228
+ projectId: {
229
+ type: "number",
230
+ required: false,
231
+ description: "Filter by project",
232
+ },
122
233
  },
123
234
  async execute(input, ctx) {
124
- const { limit, page, from, to, userId, projectId } = (input ?? {});
235
+ const { limit, page, from, to, userId, projectId } = (input ??
236
+ {});
125
237
  const qs = {};
126
238
  if (limit)
127
239
  qs.per_page = limit;
@@ -140,24 +252,52 @@ export default function harvest(rl) {
140
252
  });
141
253
  rl.registerAction("timeEntry.update", {
142
254
  description: "Update a time entry",
143
- inputSchema: { id: { type: "number", required: true, description: "Time entry ID" }, properties: { type: "object", required: true, description: "Fields to update" } },
144
- async execute(input, ctx) { const { id, properties } = input; return hv(ctx, "PATCH", `time_entries/${id}`, properties); },
255
+ inputSchema: {
256
+ id: { type: "number", required: true, description: "Time entry ID" },
257
+ properties: {
258
+ type: "object",
259
+ required: true,
260
+ description: "Fields to update",
261
+ },
262
+ },
263
+ async execute(input, ctx) {
264
+ const { id, properties } = input;
265
+ return hv(ctx, "PATCH", `time_entries/${id}`, properties);
266
+ },
145
267
  });
146
268
  rl.registerAction("timeEntry.delete", {
147
- description: "Delete a time entry", inputSchema: { id: { type: "number", required: true, description: "Time entry ID" } },
148
- async execute(input, ctx) { await hv(ctx, "DELETE", `time_entries/${input.id}`); return { success: true }; },
269
+ description: "Delete a time entry",
270
+ inputSchema: {
271
+ id: { type: "number", required: true, description: "Time entry ID" },
272
+ },
273
+ async execute(input, ctx) {
274
+ await hv(ctx, "DELETE", `time_entries/${input.id}`);
275
+ return { success: true };
276
+ },
149
277
  });
150
278
  rl.registerAction("timeEntry.restart", {
151
- description: "Restart a stopped time entry", inputSchema: { id: { type: "number", required: true, description: "Time entry ID" } },
152
- async execute(input, ctx) { return hv(ctx, "PATCH", `time_entries/${input.id}/restart`); },
279
+ description: "Restart a stopped time entry",
280
+ inputSchema: {
281
+ id: { type: "number", required: true, description: "Time entry ID" },
282
+ },
283
+ async execute(input, ctx) {
284
+ return hv(ctx, "PATCH", `time_entries/${input.id}/restart`);
285
+ },
153
286
  });
154
287
  rl.registerAction("timeEntry.stop", {
155
- description: "Stop a running time entry", inputSchema: { id: { type: "number", required: true, description: "Time entry ID" } },
156
- async execute(input, ctx) { return hv(ctx, "PATCH", `time_entries/${input.id}/stop`); },
288
+ description: "Stop a running time entry",
289
+ inputSchema: {
290
+ id: { type: "number", required: true, description: "Time entry ID" },
291
+ },
292
+ async execute(input, ctx) {
293
+ return hv(ctx, "PATCH", `time_entries/${input.id}/stop`);
294
+ },
157
295
  });
158
296
  // Company (read-only)
159
297
  rl.registerAction("company.get", {
160
298
  description: "Get company info",
161
- async execute(_input, ctx) { return hv(ctx, "GET", "company"); },
299
+ async execute(_input, ctx) {
300
+ return hv(ctx, "GET", "company");
301
+ },
162
302
  });
163
303
  }
@@ -7,8 +7,17 @@ async function apiRequest(token, method, endpoint, body, qs) {
7
7
  url.searchParams.set(k, String(v));
8
8
  }
9
9
  }
10
- const opts = { method, headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" } };
11
- if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE")
10
+ const opts = {
11
+ method,
12
+ headers: {
13
+ Authorization: `Bearer ${token}`,
14
+ "Content-Type": "application/json",
15
+ },
16
+ };
17
+ if (body &&
18
+ Object.keys(body).length > 0 &&
19
+ method !== "GET" &&
20
+ method !== "DELETE")
12
21
  opts.body = JSON.stringify(body);
13
22
  const res = await fetch(url.toString(), opts);
14
23
  if (!res.ok)
@@ -18,7 +27,9 @@ async function apiRequest(token, method, endpoint, body, qs) {
18
27
  return res.json();
19
28
  }
20
29
  function unwrapEmbedded(data, key) {
21
- if (data && typeof data === "object" && "_embedded" in data) {
30
+ if (data &&
31
+ typeof data === "object" &&
32
+ "_embedded" in data) {
22
33
  return data._embedded[key];
23
34
  }
24
35
  return data;
@@ -27,7 +38,12 @@ export default function helpscout(rl) {
27
38
  rl.setName("helpscout");
28
39
  rl.setVersion("0.1.0");
29
40
  rl.setConnectionSchema({
30
- accessToken: { type: "string", required: true, description: "HelpScout OAuth2 access token", env: "HELPSCOUT_ACCESS_TOKEN" },
41
+ accessToken: {
42
+ type: "string",
43
+ required: true,
44
+ description: "HelpScout OAuth2 access token",
45
+ env: "HELPSCOUT_ACCESS_TOKEN",
46
+ },
31
47
  });
32
48
  const tok = (ctx) => ctx.connection.config.accessToken;
33
49
  // ── Conversation ────────────────────────────────────
@@ -35,16 +51,38 @@ export default function helpscout(rl) {
35
51
  description: "Create a conversation",
36
52
  inputSchema: {
37
53
  subject: { type: "string", required: true, description: "Subject" },
38
- customer: { type: "object", required: true, description: "{email} or {id}" },
54
+ customer: {
55
+ type: "object",
56
+ required: true,
57
+ description: "{email} or {id}",
58
+ },
39
59
  mailboxId: { type: "number", required: true, description: "Mailbox ID" },
40
- type: { type: "string", required: true, description: "email, phone, chat" },
41
- threads: { type: "array", required: true, description: "Array of thread objects [{type, text}]" },
42
- status: { type: "string", required: false, description: "active, pending, closed, spam" },
60
+ type: {
61
+ type: "string",
62
+ required: true,
63
+ description: "email, phone, chat",
64
+ },
65
+ threads: {
66
+ type: "array",
67
+ required: true,
68
+ description: "Array of thread objects [{type, text}]",
69
+ },
70
+ status: {
71
+ type: "string",
72
+ required: false,
73
+ description: "active, pending, closed, spam",
74
+ },
43
75
  tags: { type: "array", required: false, description: "Tag names" },
44
76
  },
45
77
  async execute(input, ctx) {
46
78
  const { subject, customer, mailboxId, type, threads, status, tags } = input;
47
- const body = { subject, customer, mailboxId, type, threads };
79
+ const body = {
80
+ subject,
81
+ customer,
82
+ mailboxId,
83
+ type,
84
+ threads,
85
+ };
48
86
  if (status)
49
87
  body.status = status;
50
88
  if (tags)
@@ -54,14 +92,30 @@ export default function helpscout(rl) {
54
92
  });
55
93
  rl.registerAction("conversation.get", {
56
94
  description: "Get a conversation",
57
- inputSchema: { conversationId: { type: "number", required: true, description: "Conversation ID" } },
58
- async execute(input, ctx) { return apiRequest(tok(ctx), "GET", `/conversations/${input.conversationId}`); },
95
+ inputSchema: {
96
+ conversationId: {
97
+ type: "number",
98
+ required: true,
99
+ description: "Conversation ID",
100
+ },
101
+ },
102
+ async execute(input, ctx) {
103
+ return apiRequest(tok(ctx), "GET", `/conversations/${input.conversationId}`);
104
+ },
59
105
  });
60
106
  rl.registerAction("conversation.list", {
61
107
  description: "List conversations",
62
108
  inputSchema: {
63
- mailboxId: { type: "number", required: false, description: "Filter by mailbox" },
64
- status: { type: "string", required: false, description: "active, pending, closed, spam, all" },
109
+ mailboxId: {
110
+ type: "number",
111
+ required: false,
112
+ description: "Filter by mailbox",
113
+ },
114
+ status: {
115
+ type: "string",
116
+ required: false,
117
+ description: "active, pending, closed, spam, all",
118
+ },
65
119
  limit: { type: "number", required: false, description: "Max results" },
66
120
  page: { type: "number", required: false, description: "Page" },
67
121
  },
@@ -81,8 +135,17 @@ export default function helpscout(rl) {
81
135
  });
82
136
  rl.registerAction("conversation.delete", {
83
137
  description: "Delete a conversation",
84
- inputSchema: { conversationId: { type: "number", required: true, description: "Conversation ID" } },
85
- async execute(input, ctx) { await apiRequest(tok(ctx), "DELETE", `/conversations/${input.conversationId}`); return { success: true }; },
138
+ inputSchema: {
139
+ conversationId: {
140
+ type: "number",
141
+ required: true,
142
+ description: "Conversation ID",
143
+ },
144
+ },
145
+ async execute(input, ctx) {
146
+ await apiRequest(tok(ctx), "DELETE", `/conversations/${input.conversationId}`);
147
+ return { success: true };
148
+ },
86
149
  });
87
150
  // ── Customer ────────────────────────────────────────
88
151
  rl.registerAction("customer.create", {
@@ -90,7 +153,11 @@ export default function helpscout(rl) {
90
153
  inputSchema: {
91
154
  firstName: { type: "string", required: true, description: "First name" },
92
155
  lastName: { type: "string", required: false, description: "Last name" },
93
- emails: { type: "array", required: false, description: "Array of {type, value} email objects" },
156
+ emails: {
157
+ type: "array",
158
+ required: false,
159
+ description: "Array of {type, value} email objects",
160
+ },
94
161
  phones: { type: "array", required: false, description: "Phone objects" },
95
162
  },
96
163
  async execute(input, ctx) {
@@ -107,12 +174,23 @@ export default function helpscout(rl) {
107
174
  });
108
175
  rl.registerAction("customer.get", {
109
176
  description: "Get a customer",
110
- inputSchema: { customerId: { type: "number", required: true, description: "Customer ID" } },
111
- async execute(input, ctx) { return apiRequest(tok(ctx), "GET", `/customers/${input.customerId}`); },
177
+ inputSchema: {
178
+ customerId: {
179
+ type: "number",
180
+ required: true,
181
+ description: "Customer ID",
182
+ },
183
+ },
184
+ async execute(input, ctx) {
185
+ return apiRequest(tok(ctx), "GET", `/customers/${input.customerId}`);
186
+ },
112
187
  });
113
188
  rl.registerAction("customer.list", {
114
189
  description: "List customers",
115
- inputSchema: { limit: { type: "number", required: false, description: "Max results" }, page: { type: "number", required: false, description: "Page" } },
190
+ inputSchema: {
191
+ limit: { type: "number", required: false, description: "Max results" },
192
+ page: { type: "number", required: false, description: "Page" },
193
+ },
116
194
  async execute(input, ctx) {
117
195
  const { limit, page } = (input ?? {});
118
196
  const qs = {};
@@ -126,8 +204,16 @@ export default function helpscout(rl) {
126
204
  rl.registerAction("customer.update", {
127
205
  description: "Update a customer",
128
206
  inputSchema: {
129
- customerId: { type: "number", required: true, description: "Customer ID" },
130
- properties: { type: "object", required: true, description: "Fields to update" },
207
+ customerId: {
208
+ type: "number",
209
+ required: true,
210
+ description: "Customer ID",
211
+ },
212
+ properties: {
213
+ type: "object",
214
+ required: true,
215
+ description: "Fields to update",
216
+ },
131
217
  },
132
218
  async execute(input, ctx) {
133
219
  const { customerId, properties } = input;
@@ -136,27 +222,57 @@ export default function helpscout(rl) {
136
222
  });
137
223
  rl.registerAction("customer.getProperties", {
138
224
  description: "Get custom properties for a customer",
139
- inputSchema: { customerId: { type: "number", required: true, description: "Customer ID" } },
140
- async execute(input, ctx) { return apiRequest(tok(ctx), "GET", `/customers/${input.customerId}/properties`); },
225
+ inputSchema: {
226
+ customerId: {
227
+ type: "number",
228
+ required: true,
229
+ description: "Customer ID",
230
+ },
231
+ },
232
+ async execute(input, ctx) {
233
+ return apiRequest(tok(ctx), "GET", `/customers/${input.customerId}/properties`);
234
+ },
141
235
  });
142
236
  // ── Mailbox ─────────────────────────────────────────
143
237
  rl.registerAction("mailbox.get", {
144
238
  description: "Get a mailbox",
145
- inputSchema: { mailboxId: { type: "number", required: true, description: "Mailbox ID" } },
146
- async execute(input, ctx) { return apiRequest(tok(ctx), "GET", `/mailboxes/${input.mailboxId}`); },
239
+ inputSchema: {
240
+ mailboxId: { type: "number", required: true, description: "Mailbox ID" },
241
+ },
242
+ async execute(input, ctx) {
243
+ return apiRequest(tok(ctx), "GET", `/mailboxes/${input.mailboxId}`);
244
+ },
147
245
  });
148
246
  rl.registerAction("mailbox.list", {
149
247
  description: "List mailboxes",
150
- async execute(_input, ctx) { return unwrapEmbedded(await apiRequest(tok(ctx), "GET", "/mailboxes"), "mailboxes"); },
248
+ async execute(_input, ctx) {
249
+ return unwrapEmbedded(await apiRequest(tok(ctx), "GET", "/mailboxes"), "mailboxes");
250
+ },
151
251
  });
152
252
  // ── Thread ──────────────────────────────────────────
153
253
  rl.registerAction("thread.create", {
154
254
  description: "Create a thread (reply/note) on a conversation",
155
255
  inputSchema: {
156
- conversationId: { type: "number", required: true, description: "Conversation ID" },
157
- type: { type: "string", required: true, description: "reply, note, phone, chat" },
158
- text: { type: "string", required: true, description: "Thread body (HTML)" },
159
- customer: { type: "object", required: false, description: "Customer {email} or {id}" },
256
+ conversationId: {
257
+ type: "number",
258
+ required: true,
259
+ description: "Conversation ID",
260
+ },
261
+ type: {
262
+ type: "string",
263
+ required: true,
264
+ description: "reply, note, phone, chat",
265
+ },
266
+ text: {
267
+ type: "string",
268
+ required: true,
269
+ description: "Thread body (HTML)",
270
+ },
271
+ customer: {
272
+ type: "object",
273
+ required: false,
274
+ description: "Customer {email} or {id}",
275
+ },
160
276
  },
161
277
  async execute(input, ctx) {
162
278
  const { conversationId, type, text, customer } = input;
@@ -168,7 +284,13 @@ export default function helpscout(rl) {
168
284
  });
169
285
  rl.registerAction("thread.list", {
170
286
  description: "List threads in a conversation",
171
- inputSchema: { conversationId: { type: "number", required: true, description: "Conversation ID" } },
287
+ inputSchema: {
288
+ conversationId: {
289
+ type: "number",
290
+ required: true,
291
+ description: "Conversation ID",
292
+ },
293
+ },
172
294
  async execute(input, ctx) {
173
295
  return unwrapEmbedded(await apiRequest(tok(ctx), "GET", `/conversations/${input.conversationId}/threads`), "threads");
174
296
  },