runline 0.2.1 → 0.3.0

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 (203) hide show
  1. package/dist/commands/auth.d.ts +7 -0
  2. package/dist/commands/auth.js +96 -0
  3. package/dist/config/loader.d.ts +11 -0
  4. package/dist/config/loader.js +46 -0
  5. package/dist/core/engine.js +7 -1
  6. package/dist/core/oauth.d.ts +46 -0
  7. package/dist/core/oauth.js +145 -0
  8. package/dist/index.d.ts +4 -2
  9. package/dist/index.js +2 -1
  10. package/dist/main.js +28 -0
  11. package/dist/plugin/api.d.ts +7 -1
  12. package/dist/plugin/api.js +7 -0
  13. package/dist/plugin/types.d.ts +47 -0
  14. package/dist/plugins/actionNetwork/src/index.js +118 -25
  15. package/dist/plugins/activeCampaign/src/index.js +184 -38
  16. package/dist/plugins/adalo/src/index.js +40 -8
  17. package/dist/plugins/affinity/src/index.js +100 -20
  18. package/dist/plugins/agileCrm/src/index.js +115 -27
  19. package/dist/plugins/airtable/src/index.js +94 -19
  20. package/dist/plugins/airtop/src/index.js +266 -62
  21. package/dist/plugins/apiTemplateIo/src/index.js +25 -5
  22. package/dist/plugins/asana/src/index.js +195 -41
  23. package/dist/plugins/autopilot/src/index.js +39 -8
  24. package/dist/plugins/bambooHr/src/index.js +109 -22
  25. package/dist/plugins/bannerbear/src/index.js +36 -8
  26. package/dist/plugins/baserow/src/index.js +35 -7
  27. package/dist/plugins/beeminder/src/index.js +198 -40
  28. package/dist/plugins/bitly/src/index.js +46 -10
  29. package/dist/plugins/bitwarden/src/index.js +167 -36
  30. package/dist/plugins/box/src/index.js +172 -37
  31. package/dist/plugins/brandfetch/src/index.js +5 -1
  32. package/dist/plugins/brevo/src/index.js +136 -29
  33. package/dist/plugins/bubble/src/index.js +76 -17
  34. package/dist/plugins/chargebee/src/index.js +35 -7
  35. package/dist/plugins/circleci/src/index.js +50 -10
  36. package/dist/plugins/ciscoWebex/src/index.js +131 -27
  37. package/dist/plugins/clearbit/src/index.js +76 -17
  38. package/dist/plugins/clickup/src/index.js +500 -107
  39. package/dist/plugins/clockify/src/index.js +229 -47
  40. package/dist/plugins/cloudflare/src/index.js +28 -6
  41. package/dist/plugins/cockpit/src/index.js +54 -12
  42. package/dist/plugins/coda/src/index.js +81 -19
  43. package/dist/plugins/coingecko/src/index.js +157 -33
  44. package/dist/plugins/contentful/src/index.js +85 -17
  45. package/dist/plugins/convertkit/src/index.js +74 -18
  46. package/dist/plugins/copper/src/index.js +59 -11
  47. package/dist/plugins/cortex/src/index.js +55 -13
  48. package/dist/plugins/currents/src/index.js +310 -71
  49. package/dist/plugins/customerIo/src/index.js +112 -23
  50. package/dist/plugins/databricks/src/index.js +549 -115
  51. package/dist/plugins/deepl/src/index.js +26 -6
  52. package/dist/plugins/demio/src/index.js +56 -11
  53. package/dist/plugins/dhl/src/index.js +16 -3
  54. package/dist/plugins/discord/src/index.js +141 -31
  55. package/dist/plugins/discourse/src/index.js +136 -31
  56. package/dist/plugins/disqus/src/index.js +96 -20
  57. package/dist/plugins/docker/src/index.js +20 -4
  58. package/dist/plugins/drift/src/index.js +19 -5
  59. package/dist/plugins/dropbox/src/index.js +139 -30
  60. package/dist/plugins/dropcontact/src/index.js +21 -4
  61. package/dist/plugins/egoi/src/index.js +61 -15
  62. package/dist/plugins/elasticsearch/src/index.js +59 -13
  63. package/dist/plugins/emelia/src/index.js +95 -19
  64. package/dist/plugins/erpnext/src/index.js +74 -15
  65. package/dist/plugins/facebookGraph/src/index.js +52 -11
  66. package/dist/plugins/freshdesk/src/index.js +220 -48
  67. package/dist/plugins/freshservice/src/index.js +39 -9
  68. package/dist/plugins/freshworksCrm/src/index.js +58 -12
  69. package/dist/plugins/getresponse/src/index.js +87 -18
  70. package/dist/plugins/ghost/src/index.js +114 -26
  71. package/dist/plugins/github/src/index.js +483 -109
  72. package/dist/plugins/gitlab/src/index.js +193 -45
  73. package/dist/plugins/gmail/src/index.js +1075 -0
  74. package/dist/plugins/gong/src/index.js +68 -14
  75. package/dist/plugins/gotify/src/index.js +43 -9
  76. package/dist/plugins/gotowebinar/src/index.js +233 -47
  77. package/dist/plugins/grafana/src/index.js +92 -21
  78. package/dist/plugins/graphql/src/index.js +38 -8
  79. package/dist/plugins/grist/src/index.js +52 -10
  80. package/dist/plugins/hackernews/src/index.js +32 -6
  81. package/dist/plugins/halopsa/src/index.js +131 -26
  82. package/dist/plugins/harvest/src/index.js +182 -42
  83. package/dist/plugins/helpscout/src/index.js +153 -31
  84. package/dist/plugins/highlevel/src/index.js +291 -58
  85. package/dist/plugins/homeAssistant/src/index.js +124 -26
  86. package/dist/plugins/hubspot/src/index.js +163 -29
  87. package/dist/plugins/humanticAi/src/index.js +54 -5
  88. package/dist/plugins/hunter/src/index.js +21 -4
  89. package/dist/plugins/intercom/src/index.js +95 -20
  90. package/dist/plugins/iterable/src/index.js +96 -20
  91. package/dist/plugins/jenkins/src/index.js +75 -17
  92. package/dist/plugins/jira/src/index.js +193 -43
  93. package/dist/plugins/keap/src/index.js +222 -56
  94. package/dist/plugins/kobotoolbox/src/index.js +113 -25
  95. package/dist/plugins/lemlist/src/index.js +79 -18
  96. package/dist/plugins/linear/src/index.js +86 -19
  97. package/dist/plugins/lingvanex/src/index.js +38 -8
  98. package/dist/plugins/linkedin/src/index.js +37 -8
  99. package/dist/plugins/lonescale/src/index.js +41 -9
  100. package/dist/plugins/magento/src/index.js +98 -27
  101. package/dist/plugins/mailcheck/src/index.js +11 -2
  102. package/dist/plugins/mailchimp/src/index.js +193 -42
  103. package/dist/plugins/mailerlite/src/index.js +61 -12
  104. package/dist/plugins/mailgun/src/index.js +39 -7
  105. package/dist/plugins/mailjet/src/index.js +141 -30
  106. package/dist/plugins/mandrill/src/index.js +67 -14
  107. package/dist/plugins/marketstack/src/index.js +56 -10
  108. package/dist/plugins/matrix/src/index.js +97 -20
  109. package/dist/plugins/mattermost/src/index.js +124 -26
  110. package/dist/plugins/mautic/src/index.js +129 -26
  111. package/dist/plugins/medium/src/index.js +64 -13
  112. package/dist/plugins/messagebird/src/index.js +80 -15
  113. package/dist/plugins/metabase/src/index.js +57 -12
  114. package/dist/plugins/misp/src/index.js +135 -33
  115. package/dist/plugins/mocean/src/index.js +33 -7
  116. package/dist/plugins/monday/src/index.js +97 -23
  117. package/dist/plugins/monicaCrm/src/index.js +112 -23
  118. package/dist/plugins/msg91/src/index.js +11 -2
  119. package/dist/plugins/nasa/src/index.js +108 -21
  120. package/dist/plugins/netlify/src/index.js +28 -6
  121. package/dist/plugins/netscalerAdc/src/index.js +144 -29
  122. package/dist/plugins/nextcloud/src/index.js +103 -20
  123. package/dist/plugins/nocodb/src/index.js +57 -11
  124. package/dist/plugins/notion/src/index.js +148 -37
  125. package/dist/plugins/npm/src/index.js +59 -12
  126. package/dist/plugins/odoo/src/index.js +102 -20
  127. package/dist/plugins/okta/src/index.js +50 -10
  128. package/dist/plugins/oneSimpleApi/src/index.js +84 -17
  129. package/dist/plugins/onfleet/src/index.js +139 -32
  130. package/dist/plugins/openThesaurus/src/index.js +46 -9
  131. package/dist/plugins/openweathermap/src/index.js +31 -6
  132. package/dist/plugins/oura/src/index.js +36 -7
  133. package/dist/plugins/paddle/src/index.js +80 -17
  134. package/dist/plugins/pagerduty/src/index.js +53 -12
  135. package/dist/plugins/paypal/src/index.js +51 -11
  136. package/dist/plugins/peekalink/src/index.js +12 -3
  137. package/dist/plugins/phantombuster/src/index.js +39 -8
  138. package/dist/plugins/philipsHue/src/index.js +64 -13
  139. package/dist/plugins/pipedrive/src/index.js +167 -45
  140. package/dist/plugins/plivo/src/index.js +43 -8
  141. package/dist/plugins/postbin/src/index.js +9 -2
  142. package/dist/plugins/posthog/src/index.js +50 -13
  143. package/dist/plugins/profitwell/src/index.js +24 -5
  144. package/dist/plugins/pushbullet/src/index.js +45 -9
  145. package/dist/plugins/pushcut/src/index.js +31 -6
  146. package/dist/plugins/pushover/src/index.js +51 -10
  147. package/dist/plugins/quickbase/src/index.js +66 -13
  148. package/dist/plugins/quickbooks/src/index.js +86 -19
  149. package/dist/plugins/quickchart/src/index.js +35 -7
  150. package/dist/plugins/raindrop/src/index.js +54 -13
  151. package/dist/plugins/reddit/src/index.js +73 -18
  152. package/dist/plugins/rocketchat/src/index.js +47 -9
  153. package/dist/plugins/rundeck/src/index.js +26 -5
  154. package/dist/plugins/salesforce/src/index.js +161 -31
  155. package/dist/plugins/salesmate/src/index.js +75 -16
  156. package/dist/plugins/securityScorecard/src/index.js +73 -15
  157. package/dist/plugins/segment/src/index.js +21 -4
  158. package/dist/plugins/sendgrid/src/index.js +102 -24
  159. package/dist/plugins/sendy/src/index.js +54 -11
  160. package/dist/plugins/sentry/src/index.js +174 -34
  161. package/dist/plugins/servicenow/src/index.js +120 -27
  162. package/dist/plugins/shopify/src/index.js +53 -12
  163. package/dist/plugins/signl4/src/index.js +16 -3
  164. package/dist/plugins/slack/src/index.js +407 -105
  165. package/dist/plugins/sms77/src/index.js +26 -5
  166. package/dist/plugins/splunk/src/index.js +186 -45
  167. package/dist/plugins/spotify/src/index.js +265 -66
  168. package/dist/plugins/stackby/src/index.js +18 -6
  169. package/dist/plugins/storyblok/src/index.js +57 -11
  170. package/dist/plugins/strapi/src/index.js +63 -12
  171. package/dist/plugins/strava/src/index.js +58 -13
  172. package/dist/plugins/stripe/src/index.js +143 -30
  173. package/dist/plugins/supabase/src/index.js +49 -10
  174. package/dist/plugins/syncromsp/src/index.js +245 -67
  175. package/dist/plugins/tapfiliate/src/index.js +57 -14
  176. package/dist/plugins/telegram/src/index.js +202 -39
  177. package/dist/plugins/thehive/src/index.js +271 -66
  178. package/dist/plugins/thehiveProject/src/index.js +457 -89
  179. package/dist/plugins/todoist/src/index.js +326 -77
  180. package/dist/plugins/travisci/src/index.js +35 -8
  181. package/dist/plugins/trello/src/index.js +204 -46
  182. package/dist/plugins/twake/src/index.js +10 -2
  183. package/dist/plugins/twilio/src/index.js +56 -11
  184. package/dist/plugins/twist/src/index.js +241 -48
  185. package/dist/plugins/twitter/src/index.js +128 -30
  186. package/dist/plugins/unleashedSoftware/src/index.js +30 -6
  187. package/dist/plugins/uplead/src/index.js +9 -2
  188. package/dist/plugins/uproc/src/index.js +31 -6
  189. package/dist/plugins/uptimerobot/src/index.js +119 -25
  190. package/dist/plugins/urlscanio/src/index.js +25 -6
  191. package/dist/plugins/vero/src/index.js +68 -13
  192. package/dist/plugins/vonage/src/index.js +32 -6
  193. package/dist/plugins/wekan/src/index.js +297 -52
  194. package/dist/plugins/woocommerce/src/index.js +57 -12
  195. package/dist/plugins/wordpress/src/index.js +94 -18
  196. package/dist/plugins/xero/src/index.js +79 -13
  197. package/dist/plugins/yourls/src/index.js +33 -6
  198. package/dist/plugins/zammad/src/index.js +139 -36
  199. package/dist/plugins/zendesk/src/index.js +201 -48
  200. package/dist/plugins/zoho/src/index.js +88 -21
  201. package/dist/plugins/zoom/src/index.js +41 -7
  202. package/dist/plugins/zulip/src/index.js +101 -20
  203. package/package.json +3 -1
@@ -13,7 +13,15 @@ async function api(token, method, path, body, qs) {
13
13
  url.searchParams.set(k, String(v));
14
14
  }
15
15
  }
16
- const init = { method, headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", Accept: "application/json", Version: "2021-07-28" } };
16
+ const init = {
17
+ method,
18
+ headers: {
19
+ Authorization: `Bearer ${token}`,
20
+ "Content-Type": "application/json",
21
+ Accept: "application/json",
22
+ Version: "2021-07-28",
23
+ },
24
+ };
17
25
  if (body && Object.keys(body).length > 0)
18
26
  init.body = JSON.stringify(body);
19
27
  const res = await fetch(url.toString(), init);
@@ -26,24 +34,83 @@ export default function highlevel(rl) {
26
34
  rl.setName("highlevel");
27
35
  rl.setVersion("0.1.0");
28
36
  rl.setConnectionSchema({
29
- accessToken: { type: "string", required: true, description: "OAuth2 access token", env: "HIGHLEVEL_ACCESS_TOKEN" },
30
- locationId: { type: "string", required: true, description: "Location ID", env: "HIGHLEVEL_LOCATION_ID" },
37
+ accessToken: {
38
+ type: "string",
39
+ required: true,
40
+ description: "OAuth2 access token",
41
+ env: "HIGHLEVEL_ACCESS_TOKEN",
42
+ },
43
+ locationId: {
44
+ type: "string",
45
+ required: true,
46
+ description: "Location ID",
47
+ env: "HIGHLEVEL_LOCATION_ID",
48
+ },
31
49
  });
32
50
  // ── Contact ─────────────────────────────────────────
33
- rl.registerAction("contact.upsert", { description: "Create or update a contact (upsert by email/phone)",
34
- inputSchema: { email: { type: "string", required: false }, phone: { type: "string", required: false }, firstName: { type: "string", required: false }, lastName: { type: "string", required: false }, name: { type: "string", required: false }, address1: { type: "string", required: false }, city: { type: "string", required: false }, state: { type: "string", required: false }, postalCode: { type: "string", required: false }, website: { type: "string", required: false }, tags: { type: "object", required: false, description: "Array of tag strings" }, timezone: { type: "string", required: false }, dnd: { type: "boolean", required: false }, source: { type: "string", required: false }, customFields: { type: "object", required: false, description: "Array of {id, field_value}" } },
51
+ rl.registerAction("contact.upsert", {
52
+ description: "Create or update a contact (upsert by email/phone)",
53
+ inputSchema: {
54
+ email: { type: "string", required: false },
55
+ phone: { type: "string", required: false },
56
+ firstName: { type: "string", required: false },
57
+ lastName: { type: "string", required: false },
58
+ name: { type: "string", required: false },
59
+ address1: { type: "string", required: false },
60
+ city: { type: "string", required: false },
61
+ state: { type: "string", required: false },
62
+ postalCode: { type: "string", required: false },
63
+ website: { type: "string", required: false },
64
+ tags: {
65
+ type: "object",
66
+ required: false,
67
+ description: "Array of tag strings",
68
+ },
69
+ timezone: { type: "string", required: false },
70
+ dnd: { type: "boolean", required: false },
71
+ source: { type: "string", required: false },
72
+ customFields: {
73
+ type: "object",
74
+ required: false,
75
+ description: "Array of {id, field_value}",
76
+ },
77
+ },
35
78
  async execute(input, ctx) {
36
79
  const { token, locationId } = getConn(ctx);
37
80
  const body = { ...input, locationId };
38
81
  if (typeof body.tags === "string")
39
- body.tags = body.tags.split(",").map((t) => t.trim());
40
- const res = await api(token, "POST", "/contacts/upsert/", body);
82
+ body.tags = body.tags
83
+ .split(",")
84
+ .map((t) => t.trim());
85
+ const res = (await api(token, "POST", "/contacts/upsert/", body));
41
86
  return res.contact ?? res;
42
- } });
43
- rl.registerAction("contact.get", { description: "Get a contact by ID", inputSchema: { id: { type: "string", required: true } },
44
- async execute(input, ctx) { const { token } = getConn(ctx); const res = await api(token, "GET", `/contacts/${input.id}/`); return res.contact ?? res; } });
45
- rl.registerAction("contact.list", { description: "List contacts",
46
- inputSchema: { limit: { type: "number", required: false }, query: { type: "string", required: false, description: "Search by name, phone, email, tags, company" }, sortBy: { type: "string", required: false, description: "date_added or date_updated" }, order: { type: "string", required: false, description: "asc or desc" } },
87
+ },
88
+ });
89
+ rl.registerAction("contact.get", {
90
+ description: "Get a contact by ID",
91
+ inputSchema: { id: { type: "string", required: true } },
92
+ async execute(input, ctx) {
93
+ const { token } = getConn(ctx);
94
+ const res = (await api(token, "GET", `/contacts/${input.id}/`));
95
+ return res.contact ?? res;
96
+ },
97
+ });
98
+ rl.registerAction("contact.list", {
99
+ description: "List contacts",
100
+ inputSchema: {
101
+ limit: { type: "number", required: false },
102
+ query: {
103
+ type: "string",
104
+ required: false,
105
+ description: "Search by name, phone, email, tags, company",
106
+ },
107
+ sortBy: {
108
+ type: "string",
109
+ required: false,
110
+ description: "date_added or date_updated",
111
+ },
112
+ order: { type: "string", required: false, description: "asc or desc" },
113
+ },
47
114
  async execute(input, ctx) {
48
115
  const { token, locationId } = getConn(ctx);
49
116
  const p = (input ?? {});
@@ -56,24 +123,70 @@ export default function highlevel(rl) {
56
123
  qs.sortBy = p.sortBy;
57
124
  if (p.order)
58
125
  qs.order = p.order;
59
- const res = await api(token, "GET", "/contacts/", undefined, qs);
126
+ const res = (await api(token, "GET", "/contacts/", undefined, qs));
60
127
  return res.contacts ?? res;
61
- } });
62
- rl.registerAction("contact.update", { description: "Update a contact",
63
- inputSchema: { id: { type: "string", required: true }, email: { type: "string", required: false }, phone: { type: "string", required: false }, firstName: { type: "string", required: false }, lastName: { type: "string", required: false }, name: { type: "string", required: false }, address1: { type: "string", required: false }, city: { type: "string", required: false }, state: { type: "string", required: false }, postalCode: { type: "string", required: false }, website: { type: "string", required: false }, tags: { type: "object", required: false }, timezone: { type: "string", required: false }, customFields: { type: "object", required: false } },
128
+ },
129
+ });
130
+ rl.registerAction("contact.update", {
131
+ description: "Update a contact",
132
+ inputSchema: {
133
+ id: { type: "string", required: true },
134
+ email: { type: "string", required: false },
135
+ phone: { type: "string", required: false },
136
+ firstName: { type: "string", required: false },
137
+ lastName: { type: "string", required: false },
138
+ name: { type: "string", required: false },
139
+ address1: { type: "string", required: false },
140
+ city: { type: "string", required: false },
141
+ state: { type: "string", required: false },
142
+ postalCode: { type: "string", required: false },
143
+ website: { type: "string", required: false },
144
+ tags: { type: "object", required: false },
145
+ timezone: { type: "string", required: false },
146
+ customFields: { type: "object", required: false },
147
+ },
64
148
  async execute(input, ctx) {
65
149
  const { token } = getConn(ctx);
66
150
  const { id, ...body } = input;
67
151
  if (typeof body.tags === "string")
68
- body.tags = body.tags.split(",").map((t) => t.trim());
69
- const res = await api(token, "PUT", `/contacts/${id}/`, body);
152
+ body.tags = body.tags
153
+ .split(",")
154
+ .map((t) => t.trim());
155
+ const res = (await api(token, "PUT", `/contacts/${id}/`, body));
70
156
  return res.contact ?? res;
71
- } });
72
- rl.registerAction("contact.delete", { description: "Delete a contact", inputSchema: { id: { type: "string", required: true } },
73
- async execute(input, ctx) { const { token } = getConn(ctx); await api(token, "DELETE", `/contacts/${input.id}/`); return { success: true }; } });
157
+ },
158
+ });
159
+ rl.registerAction("contact.delete", {
160
+ description: "Delete a contact",
161
+ inputSchema: { id: { type: "string", required: true } },
162
+ async execute(input, ctx) {
163
+ const { token } = getConn(ctx);
164
+ await api(token, "DELETE", `/contacts/${input.id}/`);
165
+ return { success: true };
166
+ },
167
+ });
74
168
  // ── Opportunity ─────────────────────────────────────
75
- rl.registerAction("opportunity.create", { description: "Create an opportunity",
76
- inputSchema: { contactId: { type: "string", required: true }, name: { type: "string", required: true }, status: { type: "string", required: true, description: "open, won, lost, or abandoned" }, pipelineId: { type: "string", required: true }, stageId: { type: "string", required: false, description: "Pipeline stage ID" }, monetaryValue: { type: "number", required: false }, assignedTo: { type: "string", required: false }, companyName: { type: "string", required: false }, tags: { type: "object", required: false } },
169
+ rl.registerAction("opportunity.create", {
170
+ description: "Create an opportunity",
171
+ inputSchema: {
172
+ contactId: { type: "string", required: true },
173
+ name: { type: "string", required: true },
174
+ status: {
175
+ type: "string",
176
+ required: true,
177
+ description: "open, won, lost, or abandoned",
178
+ },
179
+ pipelineId: { type: "string", required: true },
180
+ stageId: {
181
+ type: "string",
182
+ required: false,
183
+ description: "Pipeline stage ID",
184
+ },
185
+ monetaryValue: { type: "number", required: false },
186
+ assignedTo: { type: "string", required: false },
187
+ companyName: { type: "string", required: false },
188
+ tags: { type: "object", required: false },
189
+ },
77
190
  async execute(input, ctx) {
78
191
  const { token, locationId } = getConn(ctx);
79
192
  const body = { ...input, locationId };
@@ -82,13 +195,32 @@ export default function highlevel(rl) {
82
195
  delete body.stageId;
83
196
  }
84
197
  if (typeof body.tags === "string")
85
- body.tags = body.tags.split(",").map((t) => t.trim());
198
+ body.tags = body.tags
199
+ .split(",")
200
+ .map((t) => t.trim());
86
201
  return api(token, "POST", "/opportunities/", body);
87
- } });
88
- rl.registerAction("opportunity.get", { description: "Get an opportunity", inputSchema: { id: { type: "string", required: true } },
89
- async execute(input, ctx) { const { token } = getConn(ctx); return api(token, "GET", `/opportunities/${input.id}`); } });
90
- rl.registerAction("opportunity.list", { description: "List opportunities",
91
- inputSchema: { limit: { type: "number", required: false }, pipelineId: { type: "string", required: false }, stageId: { type: "string", required: false }, status: { type: "string", required: false }, assignedTo: { type: "string", required: false }, query: { type: "string", required: false }, startDate: { type: "string", required: false }, endDate: { type: "string", required: false } },
202
+ },
203
+ });
204
+ rl.registerAction("opportunity.get", {
205
+ description: "Get an opportunity",
206
+ inputSchema: { id: { type: "string", required: true } },
207
+ async execute(input, ctx) {
208
+ const { token } = getConn(ctx);
209
+ return api(token, "GET", `/opportunities/${input.id}`);
210
+ },
211
+ });
212
+ rl.registerAction("opportunity.list", {
213
+ description: "List opportunities",
214
+ inputSchema: {
215
+ limit: { type: "number", required: false },
216
+ pipelineId: { type: "string", required: false },
217
+ stageId: { type: "string", required: false },
218
+ status: { type: "string", required: false },
219
+ assignedTo: { type: "string", required: false },
220
+ query: { type: "string", required: false },
221
+ startDate: { type: "string", required: false },
222
+ endDate: { type: "string", required: false },
223
+ },
92
224
  async execute(input, ctx) {
93
225
  const { token, locationId } = getConn(ctx);
94
226
  const p = (input ?? {});
@@ -109,11 +241,21 @@ export default function highlevel(rl) {
109
241
  qs.startDate = new Date(p.startDate).getTime();
110
242
  if (p.endDate)
111
243
  qs.endDate = new Date(p.endDate).getTime();
112
- const res = await api(token, "GET", "/opportunities/search", undefined, qs);
244
+ const res = (await api(token, "GET", "/opportunities/search", undefined, qs));
113
245
  return res.opportunities ?? res;
114
- } });
115
- rl.registerAction("opportunity.update", { description: "Update an opportunity",
116
- inputSchema: { id: { type: "string", required: true }, name: { type: "string", required: false }, status: { type: "string", required: false }, pipelineId: { type: "string", required: false }, stageId: { type: "string", required: false }, monetaryValue: { type: "number", required: false }, assignedTo: { type: "string", required: false } },
246
+ },
247
+ });
248
+ rl.registerAction("opportunity.update", {
249
+ description: "Update an opportunity",
250
+ inputSchema: {
251
+ id: { type: "string", required: true },
252
+ name: { type: "string", required: false },
253
+ status: { type: "string", required: false },
254
+ pipelineId: { type: "string", required: false },
255
+ stageId: { type: "string", required: false },
256
+ monetaryValue: { type: "number", required: false },
257
+ assignedTo: { type: "string", required: false },
258
+ },
117
259
  async execute(input, ctx) {
118
260
  const { token } = getConn(ctx);
119
261
  const { id, ...body } = input;
@@ -122,51 +264,142 @@ export default function highlevel(rl) {
122
264
  delete body.stageId;
123
265
  }
124
266
  return api(token, "PUT", `/opportunities/${id}`, body);
125
- } });
126
- rl.registerAction("opportunity.delete", { description: "Delete an opportunity", inputSchema: { id: { type: "string", required: true } },
127
- async execute(input, ctx) { const { token } = getConn(ctx); await api(token, "DELETE", `/opportunities/${input.id}`); return { success: true }; } });
267
+ },
268
+ });
269
+ rl.registerAction("opportunity.delete", {
270
+ description: "Delete an opportunity",
271
+ inputSchema: { id: { type: "string", required: true } },
272
+ async execute(input, ctx) {
273
+ const { token } = getConn(ctx);
274
+ await api(token, "DELETE", `/opportunities/${input.id}`);
275
+ return { success: true };
276
+ },
277
+ });
128
278
  // ── Task (scoped to contact) ────────────────────────
129
- rl.registerAction("task.create", { description: "Create a task for a contact",
130
- inputSchema: { contactId: { type: "string", required: true }, title: { type: "string", required: true }, dueDate: { type: "string", required: true, description: "ISO datetime" }, completed: { type: "boolean", required: false }, body: { type: "string", required: false }, assignedTo: { type: "string", required: false } },
279
+ rl.registerAction("task.create", {
280
+ description: "Create a task for a contact",
281
+ inputSchema: {
282
+ contactId: { type: "string", required: true },
283
+ title: { type: "string", required: true },
284
+ dueDate: { type: "string", required: true, description: "ISO datetime" },
285
+ completed: { type: "boolean", required: false },
286
+ body: { type: "string", required: false },
287
+ assignedTo: { type: "string", required: false },
288
+ },
131
289
  async execute(input, ctx) {
132
290
  const { token } = getConn(ctx);
133
291
  const { contactId, ...body } = input;
134
292
  return api(token, "POST", `/contacts/${contactId}/tasks/`, body);
135
- } });
136
- rl.registerAction("task.get", { description: "Get a task",
137
- inputSchema: { contactId: { type: "string", required: true }, taskId: { type: "string", required: true } },
138
- async execute(input, ctx) { const { token } = getConn(ctx); const p = input; return api(token, "GET", `/contacts/${p.contactId}/tasks/${p.taskId}/`); } });
139
- rl.registerAction("task.list", { description: "List tasks for a contact",
293
+ },
294
+ });
295
+ rl.registerAction("task.get", {
296
+ description: "Get a task",
297
+ inputSchema: {
298
+ contactId: { type: "string", required: true },
299
+ taskId: { type: "string", required: true },
300
+ },
301
+ async execute(input, ctx) {
302
+ const { token } = getConn(ctx);
303
+ const p = input;
304
+ return api(token, "GET", `/contacts/${p.contactId}/tasks/${p.taskId}/`);
305
+ },
306
+ });
307
+ rl.registerAction("task.list", {
308
+ description: "List tasks for a contact",
140
309
  inputSchema: { contactId: { type: "string", required: true } },
141
310
  async execute(input, ctx) {
142
311
  const { token } = getConn(ctx);
143
- const res = await api(token, "GET", `/contacts/${input.contactId}/tasks/`);
312
+ const res = (await api(token, "GET", `/contacts/${input.contactId}/tasks/`));
144
313
  return res.tasks ?? res;
145
- } });
146
- rl.registerAction("task.update", { description: "Update a task",
147
- inputSchema: { contactId: { type: "string", required: true }, taskId: { type: "string", required: true }, title: { type: "string", required: false }, dueDate: { type: "string", required: false }, completed: { type: "boolean", required: false }, body: { type: "string", required: false }, assignedTo: { type: "string", required: false } },
314
+ },
315
+ });
316
+ rl.registerAction("task.update", {
317
+ description: "Update a task",
318
+ inputSchema: {
319
+ contactId: { type: "string", required: true },
320
+ taskId: { type: "string", required: true },
321
+ title: { type: "string", required: false },
322
+ dueDate: { type: "string", required: false },
323
+ completed: { type: "boolean", required: false },
324
+ body: { type: "string", required: false },
325
+ assignedTo: { type: "string", required: false },
326
+ },
148
327
  async execute(input, ctx) {
149
328
  const { token } = getConn(ctx);
150
329
  const { contactId, taskId, ...body } = input;
151
330
  return api(token, "PUT", `/contacts/${contactId}/tasks/${taskId}/`, body);
152
- } });
153
- rl.registerAction("task.delete", { description: "Delete a task",
154
- inputSchema: { contactId: { type: "string", required: true }, taskId: { type: "string", required: true } },
155
- async execute(input, ctx) { const { token } = getConn(ctx); const p = input; await api(token, "DELETE", `/contacts/${p.contactId}/tasks/${p.taskId}/`); return { success: true }; } });
331
+ },
332
+ });
333
+ rl.registerAction("task.delete", {
334
+ description: "Delete a task",
335
+ inputSchema: {
336
+ contactId: { type: "string", required: true },
337
+ taskId: { type: "string", required: true },
338
+ },
339
+ async execute(input, ctx) {
340
+ const { token } = getConn(ctx);
341
+ const p = input;
342
+ await api(token, "DELETE", `/contacts/${p.contactId}/tasks/${p.taskId}/`);
343
+ return { success: true };
344
+ },
345
+ });
156
346
  // ── Calendar ────────────────────────────────────────
157
- rl.registerAction("calendar.bookAppointment", { description: "Book a calendar appointment",
158
- inputSchema: { calendarId: { type: "string", required: true }, locationId: { type: "string", required: true }, contactId: { type: "string", required: true }, startTime: { type: "string", required: true, description: "ISO datetime with timezone offset" }, endTime: { type: "string", required: false }, title: { type: "string", required: false }, appointmentStatus: { type: "string", required: false, description: "new, confirmed, cancelled, showed, noshow, invalid" }, assignedUserId: { type: "string", required: false }, address: { type: "string", required: false }, toNotify: { type: "boolean", required: false } },
159
- async execute(input, ctx) { const { token } = getConn(ctx); return api(token, "POST", "/calendars/events/appointments", input); } });
160
- rl.registerAction("calendar.getFreeSlots", { description: "Get free slots for a calendar",
161
- inputSchema: { calendarId: { type: "string", required: true }, startDate: { type: "number", required: true, description: "Start date as epoch ms" }, endDate: { type: "number", required: true, description: "End date as epoch ms" }, timezone: { type: "string", required: false }, userId: { type: "string", required: false } },
347
+ rl.registerAction("calendar.bookAppointment", {
348
+ description: "Book a calendar appointment",
349
+ inputSchema: {
350
+ calendarId: { type: "string", required: true },
351
+ locationId: { type: "string", required: true },
352
+ contactId: { type: "string", required: true },
353
+ startTime: {
354
+ type: "string",
355
+ required: true,
356
+ description: "ISO datetime with timezone offset",
357
+ },
358
+ endTime: { type: "string", required: false },
359
+ title: { type: "string", required: false },
360
+ appointmentStatus: {
361
+ type: "string",
362
+ required: false,
363
+ description: "new, confirmed, cancelled, showed, noshow, invalid",
364
+ },
365
+ assignedUserId: { type: "string", required: false },
366
+ address: { type: "string", required: false },
367
+ toNotify: { type: "boolean", required: false },
368
+ },
369
+ async execute(input, ctx) {
370
+ const { token } = getConn(ctx);
371
+ return api(token, "POST", "/calendars/events/appointments", input);
372
+ },
373
+ });
374
+ rl.registerAction("calendar.getFreeSlots", {
375
+ description: "Get free slots for a calendar",
376
+ inputSchema: {
377
+ calendarId: { type: "string", required: true },
378
+ startDate: {
379
+ type: "number",
380
+ required: true,
381
+ description: "Start date as epoch ms",
382
+ },
383
+ endDate: {
384
+ type: "number",
385
+ required: true,
386
+ description: "End date as epoch ms",
387
+ },
388
+ timezone: { type: "string", required: false },
389
+ userId: { type: "string", required: false },
390
+ },
162
391
  async execute(input, ctx) {
163
392
  const { token } = getConn(ctx);
164
393
  const p = input;
165
- const qs = { startDate: p.startDate, endDate: p.endDate };
394
+ const qs = {
395
+ startDate: p.startDate,
396
+ endDate: p.endDate,
397
+ };
166
398
  if (p.timezone)
167
399
  qs.timezone = p.timezone;
168
400
  if (p.userId)
169
401
  qs.userId = p.userId;
170
402
  return api(token, "GET", `/calendars/${p.calendarId}/free-slots`, undefined, qs);
171
- } });
403
+ },
404
+ });
172
405
  }
@@ -6,8 +6,17 @@ async function apiRequest(baseUrl, token, method, endpoint, body, qs) {
6
6
  url.searchParams.set(k, String(v));
7
7
  }
8
8
  }
9
- const opts = { method, headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" } };
10
- if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE")
9
+ const opts = {
10
+ method,
11
+ headers: {
12
+ Authorization: `Bearer ${token}`,
13
+ "Content-Type": "application/json",
14
+ },
15
+ };
16
+ if (body &&
17
+ Object.keys(body).length > 0 &&
18
+ method !== "GET" &&
19
+ method !== "DELETE")
11
20
  opts.body = JSON.stringify(body);
12
21
  const res = await fetch(url.toString(), opts);
13
22
  if (!res.ok)
@@ -18,7 +27,10 @@ function getConn(ctx) {
18
27
  const cfg = ctx.connection.config;
19
28
  const ssl = cfg.ssl === true || cfg.ssl === "true";
20
29
  const proto = ssl ? "https" : "http";
21
- return { baseUrl: `${proto}://${cfg.host}:${cfg.port ?? 8123}`, token: cfg.accessToken };
30
+ return {
31
+ baseUrl: `${proto}://${cfg.host}:${cfg.port ?? 8123}`,
32
+ token: cfg.accessToken,
33
+ };
22
34
  }
23
35
  function ha(ctx, method, endpoint, body, qs) {
24
36
  const { baseUrl, token } = getConn(ctx);
@@ -28,29 +40,67 @@ export default function homeAssistant(rl) {
28
40
  rl.setName("homeAssistant");
29
41
  rl.setVersion("0.1.0");
30
42
  rl.setConnectionSchema({
31
- host: { type: "string", required: true, description: "Home Assistant host (e.g. 192.168.1.100)", env: "HASS_HOST" },
32
- port: { type: "number", required: false, description: "Port (default: 8123)", default: "8123" },
33
- ssl: { type: "boolean", required: false, description: "Use HTTPS", default: "false" },
34
- accessToken: { type: "string", required: true, description: "Long-lived access token", env: "HASS_TOKEN" },
43
+ host: {
44
+ type: "string",
45
+ required: true,
46
+ description: "Home Assistant host (e.g. 192.168.1.100)",
47
+ env: "HASS_HOST",
48
+ },
49
+ port: {
50
+ type: "number",
51
+ required: false,
52
+ description: "Port (default: 8123)",
53
+ default: "8123",
54
+ },
55
+ ssl: {
56
+ type: "boolean",
57
+ required: false,
58
+ description: "Use HTTPS",
59
+ default: "false",
60
+ },
61
+ accessToken: {
62
+ type: "string",
63
+ required: true,
64
+ description: "Long-lived access token",
65
+ env: "HASS_TOKEN",
66
+ },
35
67
  });
36
68
  rl.registerAction("config.get", {
37
69
  description: "Get Home Assistant configuration",
38
- async execute(_input, ctx) { return ha(ctx, "GET", "/config"); },
70
+ async execute(_input, ctx) {
71
+ return ha(ctx, "GET", "/config");
72
+ },
39
73
  });
40
74
  rl.registerAction("config.check", {
41
75
  description: "Check if configuration is valid",
42
- async execute(_input, ctx) { return ha(ctx, "POST", "/config/core/check_config"); },
76
+ async execute(_input, ctx) {
77
+ return ha(ctx, "POST", "/config/core/check_config");
78
+ },
43
79
  });
44
80
  rl.registerAction("service.list", {
45
81
  description: "List available services",
46
- async execute(_input, ctx) { return ha(ctx, "GET", "/services"); },
82
+ async execute(_input, ctx) {
83
+ return ha(ctx, "GET", "/services");
84
+ },
47
85
  });
48
86
  rl.registerAction("service.call", {
49
87
  description: "Call a service",
50
88
  inputSchema: {
51
- domain: { type: "string", required: true, description: "Service domain (e.g. light, switch)" },
52
- service: { type: "string", required: true, description: "Service name (e.g. turn_on)" },
53
- serviceData: { type: "object", required: false, description: "Service data (e.g. {entity_id: 'light.kitchen'})" },
89
+ domain: {
90
+ type: "string",
91
+ required: true,
92
+ description: "Service domain (e.g. light, switch)",
93
+ },
94
+ service: {
95
+ type: "string",
96
+ required: true,
97
+ description: "Service name (e.g. turn_on)",
98
+ },
99
+ serviceData: {
100
+ type: "object",
101
+ required: false,
102
+ description: "Service data (e.g. {entity_id: 'light.kitchen'})",
103
+ },
54
104
  },
55
105
  async execute(input, ctx) {
56
106
  const { domain, service, serviceData } = input;
@@ -59,19 +109,33 @@ export default function homeAssistant(rl) {
59
109
  });
60
110
  rl.registerAction("state.list", {
61
111
  description: "List all entity states",
62
- async execute(_input, ctx) { return ha(ctx, "GET", "/states"); },
112
+ async execute(_input, ctx) {
113
+ return ha(ctx, "GET", "/states");
114
+ },
63
115
  });
64
116
  rl.registerAction("state.get", {
65
117
  description: "Get state of an entity",
66
- inputSchema: { entityId: { type: "string", required: true, description: "Entity ID (e.g. light.kitchen)" } },
67
- async execute(input, ctx) { return ha(ctx, "GET", `/states/${input.entityId}`); },
118
+ inputSchema: {
119
+ entityId: {
120
+ type: "string",
121
+ required: true,
122
+ description: "Entity ID (e.g. light.kitchen)",
123
+ },
124
+ },
125
+ async execute(input, ctx) {
126
+ return ha(ctx, "GET", `/states/${input.entityId}`);
127
+ },
68
128
  });
69
129
  rl.registerAction("state.set", {
70
130
  description: "Set/update state of an entity",
71
131
  inputSchema: {
72
132
  entityId: { type: "string", required: true, description: "Entity ID" },
73
133
  state: { type: "string", required: true, description: "New state value" },
74
- attributes: { type: "object", required: false, description: "State attributes" },
134
+ attributes: {
135
+ type: "object",
136
+ required: false,
137
+ description: "State attributes",
138
+ },
75
139
  },
76
140
  async execute(input, ctx) {
77
141
  const { entityId, state, attributes } = input;
@@ -83,7 +147,9 @@ export default function homeAssistant(rl) {
83
147
  });
84
148
  rl.registerAction("event.list", {
85
149
  description: "List event types",
86
- async execute(_input, ctx) { return ha(ctx, "GET", "/events"); },
150
+ async execute(_input, ctx) {
151
+ return ha(ctx, "GET", "/events");
152
+ },
87
153
  });
88
154
  rl.registerAction("event.fire", {
89
155
  description: "Fire an event",
@@ -98,14 +164,28 @@ export default function homeAssistant(rl) {
98
164
  });
99
165
  rl.registerAction("log.getErrors", {
100
166
  description: "Get error log",
101
- async execute(_input, ctx) { return ha(ctx, "GET", "/error_log"); },
167
+ async execute(_input, ctx) {
168
+ return ha(ctx, "GET", "/error_log");
169
+ },
102
170
  });
103
171
  rl.registerAction("log.getLogbook", {
104
172
  description: "Get logbook entries",
105
173
  inputSchema: {
106
- entityId: { type: "string", required: false, description: "Filter by entity ID" },
107
- startTime: { type: "string", required: false, description: "Start time (ISO 8601)" },
108
- endTime: { type: "string", required: false, description: "End time (ISO 8601)" },
174
+ entityId: {
175
+ type: "string",
176
+ required: false,
177
+ description: "Filter by entity ID",
178
+ },
179
+ startTime: {
180
+ type: "string",
181
+ required: false,
182
+ description: "Start time (ISO 8601)",
183
+ },
184
+ endTime: {
185
+ type: "string",
186
+ required: false,
187
+ description: "End time (ISO 8601)",
188
+ },
109
189
  },
110
190
  async execute(input, ctx) {
111
191
  const { entityId, startTime, endTime } = (input ?? {});
@@ -122,14 +202,32 @@ export default function homeAssistant(rl) {
122
202
  });
123
203
  rl.registerAction("template.render", {
124
204
  description: "Render a Jinja2 template",
125
- inputSchema: { template: { type: "string", required: true, description: "Jinja2 template string" } },
126
- async execute(input, ctx) { return ha(ctx, "POST", "/template", { template: input.template }); },
205
+ inputSchema: {
206
+ template: {
207
+ type: "string",
208
+ required: true,
209
+ description: "Jinja2 template string",
210
+ },
211
+ },
212
+ async execute(input, ctx) {
213
+ return ha(ctx, "POST", "/template", {
214
+ template: input.template,
215
+ });
216
+ },
127
217
  });
128
218
  rl.registerAction("history.get", {
129
219
  description: "Get state history for entities",
130
220
  inputSchema: {
131
- entityIds: { type: "string", required: false, description: "Comma-separated entity IDs" },
132
- startTime: { type: "string", required: false, description: "Start time (ISO 8601)" },
221
+ entityIds: {
222
+ type: "string",
223
+ required: false,
224
+ description: "Comma-separated entity IDs",
225
+ },
226
+ startTime: {
227
+ type: "string",
228
+ required: false,
229
+ description: "Start time (ISO 8601)",
230
+ },
133
231
  endTime: { type: "string", required: false, description: "End time" },
134
232
  },
135
233
  async execute(input, ctx) {