runline 0.1.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 (230) hide show
  1. package/.pi/extensions/runline-context/index.ts +135 -0
  2. package/.pi/extensions/runline-context/package.json +17 -0
  3. package/README.md +273 -0
  4. package/dist/commands/actions.d.ts +3 -0
  5. package/dist/commands/actions.js +43 -0
  6. package/dist/commands/connection.d.ts +11 -0
  7. package/dist/commands/connection.js +56 -0
  8. package/dist/commands/exec.d.ts +5 -0
  9. package/dist/commands/exec.js +46 -0
  10. package/dist/commands/init.d.ts +4 -0
  11. package/dist/commands/init.js +26 -0
  12. package/dist/commands/plugin.d.ts +10 -0
  13. package/dist/commands/plugin.js +57 -0
  14. package/dist/config/index.d.ts +3 -0
  15. package/dist/config/index.js +2 -0
  16. package/dist/config/loader.d.ts +11 -0
  17. package/dist/config/loader.js +82 -0
  18. package/dist/config/types.d.ts +9 -0
  19. package/dist/config/types.js +5 -0
  20. package/dist/core/engine.d.ts +21 -0
  21. package/dist/core/engine.js +280 -0
  22. package/dist/index.d.ts +16 -0
  23. package/dist/index.js +9 -0
  24. package/dist/main.d.ts +2 -0
  25. package/dist/main.js +127 -0
  26. package/dist/plugin/api.d.ts +32 -0
  27. package/dist/plugin/api.js +68 -0
  28. package/dist/plugin/installer.d.ts +27 -0
  29. package/dist/plugin/installer.js +181 -0
  30. package/dist/plugin/loader.d.ts +13 -0
  31. package/dist/plugin/loader.js +164 -0
  32. package/dist/plugin/registry.d.ts +18 -0
  33. package/dist/plugin/registry.js +43 -0
  34. package/dist/plugin/types.d.ts +40 -0
  35. package/dist/plugin/types.js +1 -0
  36. package/dist/plugins/actionNetwork/src/index.js +353 -0
  37. package/dist/plugins/activeCampaign/src/index.js +711 -0
  38. package/dist/plugins/adalo/src/index.js +131 -0
  39. package/dist/plugins/affinity/src/index.js +279 -0
  40. package/dist/plugins/agileCrm/src/index.js +415 -0
  41. package/dist/plugins/airtable/src/index.js +280 -0
  42. package/dist/plugins/airtop/src/index.js +527 -0
  43. package/dist/plugins/apiTemplateIo/src/index.js +86 -0
  44. package/dist/plugins/asana/src/index.js +413 -0
  45. package/dist/plugins/autopilot/src/index.js +203 -0
  46. package/dist/plugins/bambooHr/src/index.js +252 -0
  47. package/dist/plugins/bannerbear/src/index.js +100 -0
  48. package/dist/plugins/baserow/src/index.js +180 -0
  49. package/dist/plugins/beeminder/src/index.js +298 -0
  50. package/dist/plugins/bitly/src/index.js +107 -0
  51. package/dist/plugins/bitwarden/src/index.js +383 -0
  52. package/dist/plugins/box/src/index.js +300 -0
  53. package/dist/plugins/brandfetch/src/index.js +80 -0
  54. package/dist/plugins/brevo/src/index.js +305 -0
  55. package/dist/plugins/bubble/src/index.js +181 -0
  56. package/dist/plugins/chargebee/src/index.js +126 -0
  57. package/dist/plugins/circleci/src/index.js +111 -0
  58. package/dist/plugins/ciscoWebex/src/index.js +245 -0
  59. package/dist/plugins/clearbit/src/index.js +103 -0
  60. package/dist/plugins/clickup/src/index.js +1043 -0
  61. package/dist/plugins/clockify/src/index.js +443 -0
  62. package/dist/plugins/cloudflare/src/index.js +93 -0
  63. package/dist/plugins/cockpit/src/index.js +131 -0
  64. package/dist/plugins/coda/src/index.js +327 -0
  65. package/dist/plugins/coingecko/src/index.js +244 -0
  66. package/dist/plugins/contentful/src/index.js +146 -0
  67. package/dist/plugins/convertkit/src/index.js +270 -0
  68. package/dist/plugins/copper/src/index.js +140 -0
  69. package/dist/plugins/cortex/src/index.js +147 -0
  70. package/dist/plugins/currents/src/index.js +405 -0
  71. package/dist/plugins/customerIo/src/index.js +184 -0
  72. package/dist/plugins/databricks/src/index.js +342 -0
  73. package/dist/plugins/deepl/src/index.js +87 -0
  74. package/dist/plugins/demio/src/index.js +111 -0
  75. package/dist/plugins/dhl/src/index.js +40 -0
  76. package/dist/plugins/discord/src/index.js +275 -0
  77. package/dist/plugins/discourse/src/index.js +273 -0
  78. package/dist/plugins/disqus/src/index.js +145 -0
  79. package/dist/plugins/docker/src/index.js +76 -0
  80. package/dist/plugins/drift/src/index.js +89 -0
  81. package/dist/plugins/dropbox/src/index.js +159 -0
  82. package/dist/plugins/dropcontact/src/index.js +59 -0
  83. package/dist/plugins/egoi/src/index.js +151 -0
  84. package/dist/plugins/elasticsearch/src/index.js +157 -0
  85. package/dist/plugins/emelia/src/index.js +174 -0
  86. package/dist/plugins/erpnext/src/index.js +121 -0
  87. package/dist/plugins/facebookGraph/src/index.js +57 -0
  88. package/dist/plugins/freshdesk/src/index.js +320 -0
  89. package/dist/plugins/freshservice/src/index.js +146 -0
  90. package/dist/plugins/freshworksCrm/src/index.js +149 -0
  91. package/dist/plugins/getresponse/src/index.js +140 -0
  92. package/dist/plugins/ghost/src/index.js +192 -0
  93. package/dist/plugins/github/src/index.js +630 -0
  94. package/dist/plugins/gitlab/src/index.js +358 -0
  95. package/dist/plugins/gong/src/index.js +126 -0
  96. package/dist/plugins/gotify/src/index.js +77 -0
  97. package/dist/plugins/gotowebinar/src/index.js +316 -0
  98. package/dist/plugins/grafana/src/index.js +250 -0
  99. package/dist/plugins/graphql/src/index.js +78 -0
  100. package/dist/plugins/grist/src/index.js +106 -0
  101. package/dist/plugins/hackernews/src/index.js +89 -0
  102. package/dist/plugins/halopsa/src/index.js +79 -0
  103. package/dist/plugins/harvest/src/index.js +163 -0
  104. package/dist/plugins/helpscout/src/index.js +176 -0
  105. package/dist/plugins/highlevel/src/index.js +172 -0
  106. package/dist/plugins/homeAssistant/src/index.js +148 -0
  107. package/dist/plugins/hubspot/src/index.js +176 -0
  108. package/dist/plugins/humanticAi/src/index.js +60 -0
  109. package/dist/plugins/hunter/src/index.js +59 -0
  110. package/dist/plugins/intercom/src/index.js +156 -0
  111. package/dist/plugins/iterable/src/index.js +139 -0
  112. package/dist/plugins/jenkins/src/index.js +132 -0
  113. package/dist/plugins/jira/src/index.js +229 -0
  114. package/dist/plugins/keap/src/index.js +502 -0
  115. package/dist/plugins/kobotoolbox/src/index.js +281 -0
  116. package/dist/plugins/lemlist/src/index.js +231 -0
  117. package/dist/plugins/linear/src/index.js +133 -0
  118. package/dist/plugins/lingvanex/src/index.js +31 -0
  119. package/dist/plugins/linkedin/src/index.js +80 -0
  120. package/dist/plugins/lonescale/src/index.js +119 -0
  121. package/dist/plugins/magento/src/index.js +300 -0
  122. package/dist/plugins/mailcheck/src/index.js +27 -0
  123. package/dist/plugins/mailchimp/src/index.js +321 -0
  124. package/dist/plugins/mailerlite/src/index.js +123 -0
  125. package/dist/plugins/mailgun/src/index.js +48 -0
  126. package/dist/plugins/mailjet/src/index.js +155 -0
  127. package/dist/plugins/mandrill/src/index.js +145 -0
  128. package/dist/plugins/marketstack/src/index.js +97 -0
  129. package/dist/plugins/matrix/src/index.js +194 -0
  130. package/dist/plugins/mattermost/src/index.js +331 -0
  131. package/dist/plugins/mautic/src/index.js +311 -0
  132. package/dist/plugins/medium/src/index.js +77 -0
  133. package/dist/plugins/messagebird/src/index.js +57 -0
  134. package/dist/plugins/metabase/src/index.js +130 -0
  135. package/dist/plugins/misp/src/index.js +476 -0
  136. package/dist/plugins/mocean/src/index.js +67 -0
  137. package/dist/plugins/monday/src/index.js +231 -0
  138. package/dist/plugins/monicaCrm/src/index.js +52 -0
  139. package/dist/plugins/msg91/src/index.js +31 -0
  140. package/dist/plugins/nasa/src/index.js +146 -0
  141. package/dist/plugins/netlify/src/index.js +151 -0
  142. package/dist/plugins/netscalerAdc/src/index.js +131 -0
  143. package/dist/plugins/nextcloud/src/index.js +263 -0
  144. package/dist/plugins/nocodb/src/index.js +130 -0
  145. package/dist/plugins/notion/src/index.js +112 -0
  146. package/dist/plugins/npm/src/index.js +104 -0
  147. package/dist/plugins/odoo/src/index.js +157 -0
  148. package/dist/plugins/okta/src/index.js +141 -0
  149. package/dist/plugins/oneSimpleApi/src/index.js +155 -0
  150. package/dist/plugins/onfleet/src/index.js +254 -0
  151. package/dist/plugins/openThesaurus/src/index.js +32 -0
  152. package/dist/plugins/openweathermap/src/index.js +60 -0
  153. package/dist/plugins/oura/src/index.js +62 -0
  154. package/dist/plugins/paddle/src/index.js +247 -0
  155. package/dist/plugins/pagerduty/src/index.js +201 -0
  156. package/dist/plugins/paypal/src/index.js +106 -0
  157. package/dist/plugins/peekalink/src/index.js +35 -0
  158. package/dist/plugins/phantombuster/src/index.js +94 -0
  159. package/dist/plugins/philipsHue/src/index.js +98 -0
  160. package/dist/plugins/pipedrive/src/index.js +169 -0
  161. package/dist/plugins/plivo/src/index.js +66 -0
  162. package/dist/plugins/postbin/src/index.js +93 -0
  163. package/dist/plugins/posthog/src/index.js +113 -0
  164. package/dist/plugins/profitwell/src/index.js +50 -0
  165. package/dist/plugins/pushbullet/src/index.js +102 -0
  166. package/dist/plugins/pushcut/src/index.js +39 -0
  167. package/dist/plugins/pushover/src/index.js +65 -0
  168. package/dist/plugins/quickbase/src/index.js +153 -0
  169. package/dist/plugins/quickbooks/src/index.js +73 -0
  170. package/dist/plugins/quickchart/src/index.js +36 -0
  171. package/dist/plugins/raindrop/src/index.js +209 -0
  172. package/dist/plugins/reddit/src/index.js +185 -0
  173. package/dist/plugins/rocketchat/src/index.js +53 -0
  174. package/dist/plugins/rundeck/src/index.js +62 -0
  175. package/dist/plugins/salesforce/src/index.js +94 -0
  176. package/dist/plugins/salesmate/src/index.js +83 -0
  177. package/dist/plugins/securityScorecard/src/index.js +200 -0
  178. package/dist/plugins/segment/src/index.js +125 -0
  179. package/dist/plugins/sendgrid/src/index.js +187 -0
  180. package/dist/plugins/sendy/src/index.js +138 -0
  181. package/dist/plugins/sentry/src/index.js +233 -0
  182. package/dist/plugins/servicenow/src/index.js +108 -0
  183. package/dist/plugins/shopify/src/index.js +222 -0
  184. package/dist/plugins/signl4/src/index.js +61 -0
  185. package/dist/plugins/slack/src/index.js +236 -0
  186. package/dist/plugins/sms77/src/index.js +63 -0
  187. package/dist/plugins/splunk/src/index.js +207 -0
  188. package/dist/plugins/spotify/src/index.js +188 -0
  189. package/dist/plugins/stackby/src/index.js +82 -0
  190. package/dist/plugins/storyblok/src/index.js +141 -0
  191. package/dist/plugins/strapi/src/index.js +152 -0
  192. package/dist/plugins/strava/src/index.js +137 -0
  193. package/dist/plugins/stripe/src/index.js +222 -0
  194. package/dist/plugins/supabase/src/index.js +121 -0
  195. package/dist/plugins/syncromsp/src/index.js +255 -0
  196. package/dist/plugins/tapfiliate/src/index.js +125 -0
  197. package/dist/plugins/telegram/src/index.js +233 -0
  198. package/dist/plugins/thehive/src/index.js +142 -0
  199. package/dist/plugins/thehiveProject/src/index.js +194 -0
  200. package/dist/plugins/todoist/src/index.js +244 -0
  201. package/dist/plugins/travisci/src/index.js +71 -0
  202. package/dist/plugins/trello/src/index.js +341 -0
  203. package/dist/plugins/twake/src/index.js +40 -0
  204. package/dist/plugins/twilio/src/index.js +75 -0
  205. package/dist/plugins/twist/src/index.js +90 -0
  206. package/dist/plugins/twitter/src/index.js +123 -0
  207. package/dist/plugins/unleashedSoftware/src/index.js +84 -0
  208. package/dist/plugins/uplead/src/index.js +59 -0
  209. package/dist/plugins/uproc/src/index.js +34 -0
  210. package/dist/plugins/uptimerobot/src/index.js +264 -0
  211. package/dist/plugins/urlscanio/src/index.js +64 -0
  212. package/dist/plugins/vero/src/index.js +80 -0
  213. package/dist/plugins/vonage/src/index.js +42 -0
  214. package/dist/plugins/wekan/src/index.js +91 -0
  215. package/dist/plugins/woocommerce/src/index.js +92 -0
  216. package/dist/plugins/wordpress/src/index.js +121 -0
  217. package/dist/plugins/xero/src/index.js +136 -0
  218. package/dist/plugins/yourls/src/index.js +56 -0
  219. package/dist/plugins/zammad/src/index.js +91 -0
  220. package/dist/plugins/zendesk/src/index.js +137 -0
  221. package/dist/plugins/zoho/src/index.js +85 -0
  222. package/dist/plugins/zoom/src/index.js +122 -0
  223. package/dist/plugins/zulip/src/index.js +170 -0
  224. package/dist/sdk.d.ts +38 -0
  225. package/dist/sdk.js +105 -0
  226. package/dist/utils/cli.d.ts +13 -0
  227. package/dist/utils/cli.js +32 -0
  228. package/dist/utils/output.d.ts +4 -0
  229. package/dist/utils/output.js +13 -0
  230. package/package.json +57 -0
@@ -0,0 +1,254 @@
1
+ const BASE = "https://onfleet.com/api/v2";
2
+ async function apiRequest(apiKey, method, endpoint, body, qs) {
3
+ const url = new URL(`${BASE}/${endpoint}`);
4
+ if (qs) {
5
+ for (const [k, v] of Object.entries(qs)) {
6
+ if (v !== undefined && v !== null)
7
+ url.searchParams.set(k, String(v));
8
+ }
9
+ }
10
+ const init = {
11
+ method,
12
+ headers: {
13
+ Authorization: `Basic ${btoa(`${apiKey}:`)}`,
14
+ "Content-Type": "application/json",
15
+ "User-Agent": "runline-onfleet",
16
+ },
17
+ };
18
+ if (body !== undefined && method !== "GET")
19
+ init.body = JSON.stringify(body);
20
+ const res = await fetch(url.toString(), init);
21
+ if (!res.ok)
22
+ throw new Error(`Onfleet error ${res.status}: ${await res.text()}`);
23
+ const text = await res.text();
24
+ return text ? JSON.parse(text) : {};
25
+ }
26
+ function registerCrud(rl, resource, plural, key, createSchema) {
27
+ rl.registerAction(`${resource}.create`, {
28
+ description: `Create a ${resource}`,
29
+ inputSchema: createSchema,
30
+ async execute(input, ctx) { return apiRequest(key(ctx), "POST", plural, input); },
31
+ });
32
+ rl.registerAction(`${resource}.get`, {
33
+ description: `Get a ${resource} by ID`,
34
+ inputSchema: { id: { type: "string", required: true } },
35
+ async execute(input, ctx) { return apiRequest(key(ctx), "GET", `${plural}/${input.id}`); },
36
+ });
37
+ rl.registerAction(`${resource}.list`, {
38
+ description: `List ${plural}`,
39
+ inputSchema: { limit: { type: "number", required: false } },
40
+ async execute(input, ctx) {
41
+ const data = (await apiRequest(key(ctx), "GET", plural));
42
+ const p = (input ?? {});
43
+ return p.limit ? data.slice(0, p.limit) : data;
44
+ },
45
+ });
46
+ rl.registerAction(`${resource}.update`, {
47
+ description: `Update a ${resource}`,
48
+ inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true } },
49
+ async execute(input, ctx) {
50
+ const p = input;
51
+ return apiRequest(key(ctx), "PUT", `${plural}/${p.id}`, p.data);
52
+ },
53
+ });
54
+ rl.registerAction(`${resource}.delete`, {
55
+ description: `Delete a ${resource}`,
56
+ inputSchema: { id: { type: "string", required: true } },
57
+ async execute(input, ctx) {
58
+ await apiRequest(key(ctx), "DELETE", `${plural}/${input.id}`);
59
+ return { success: true };
60
+ },
61
+ });
62
+ }
63
+ export default function onfleet(rl) {
64
+ rl.setName("onfleet");
65
+ rl.setVersion("0.1.0");
66
+ rl.setConnectionSchema({ apiKey: { type: "string", required: true, description: "Onfleet API key", env: "ONFLEET_API_KEY" } });
67
+ const key = (ctx) => ctx.connection.config.apiKey;
68
+ // ── Organization ────────────────────────────────────
69
+ rl.registerAction("organization.get", {
70
+ description: "Get organization details",
71
+ inputSchema: {},
72
+ async execute(_input, ctx) { return apiRequest(key(ctx), "GET", "organization"); },
73
+ });
74
+ // ── Task ────────────────────────────────────────────
75
+ rl.registerAction("task.create", {
76
+ description: "Create a task",
77
+ inputSchema: {
78
+ destination: { type: "object", required: true, description: "{ address: { unparsed: string } } or { address: { number, street, city, country } }" },
79
+ recipients: { type: "object", required: false, description: "Array of { name, phone }" },
80
+ completeAfter: { type: "number", required: false, description: "Unix ms timestamp" },
81
+ completeBefore: { type: "number", required: false, description: "Unix ms timestamp" },
82
+ notes: { type: "string", required: false },
83
+ },
84
+ async execute(input, ctx) { return apiRequest(key(ctx), "POST", "tasks", input); },
85
+ });
86
+ rl.registerAction("task.get", {
87
+ description: "Get a task by ID",
88
+ inputSchema: { id: { type: "string", required: true } },
89
+ async execute(input, ctx) {
90
+ const id = input.id;
91
+ const path = id.length <= 8 ? `tasks/shortId/${id}` : `tasks/${id}`;
92
+ return apiRequest(key(ctx), "GET", path);
93
+ },
94
+ });
95
+ rl.registerAction("task.list", {
96
+ description: "List tasks",
97
+ inputSchema: { from: { type: "number", required: false, description: "Unix ms start" }, to: { type: "number", required: false }, limit: { type: "number", required: false } },
98
+ async execute(input, ctx) {
99
+ const p = (input ?? {});
100
+ const qs = {};
101
+ if (p.from)
102
+ qs.from = p.from;
103
+ else
104
+ qs.from = Date.now() - 604800000;
105
+ if (p.to)
106
+ qs.to = p.to;
107
+ const data = (await apiRequest(key(ctx), "GET", "tasks/all", undefined, qs));
108
+ const tasks = data.tasks;
109
+ return p.limit ? tasks.slice(0, p.limit) : tasks;
110
+ },
111
+ });
112
+ rl.registerAction("task.update", {
113
+ description: "Update a task",
114
+ inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true } },
115
+ async execute(input, ctx) {
116
+ const p = input;
117
+ return apiRequest(key(ctx), "PUT", `tasks/${p.id}`, p.data);
118
+ },
119
+ });
120
+ rl.registerAction("task.delete", {
121
+ description: "Delete a task",
122
+ inputSchema: { id: { type: "string", required: true } },
123
+ async execute(input, ctx) {
124
+ await apiRequest(key(ctx), "DELETE", `tasks/${input.id}`);
125
+ return { success: true };
126
+ },
127
+ });
128
+ rl.registerAction("task.complete", {
129
+ description: "Force-complete a task",
130
+ inputSchema: { id: { type: "string", required: true }, success: { type: "boolean", required: true }, notes: { type: "string", required: false } },
131
+ async execute(input, ctx) {
132
+ const p = input;
133
+ const body = { completionDetails: { success: p.success } };
134
+ if (p.notes)
135
+ body.completionDetails.notes = p.notes;
136
+ await apiRequest(key(ctx), "POST", `tasks/${p.id}/complete`, body);
137
+ return { success: true };
138
+ },
139
+ });
140
+ // ── Worker ──────────────────────────────────────────
141
+ registerCrud(rl, "worker", "workers", key, {
142
+ name: { type: "string", required: true },
143
+ phone: { type: "string", required: true },
144
+ teams: { type: "object", required: true, description: "Array of team IDs" },
145
+ });
146
+ // ── Admin ───────────────────────────────────────────
147
+ registerCrud(rl, "admin", "admins", key, {
148
+ name: { type: "string", required: true },
149
+ email: { type: "string", required: true },
150
+ });
151
+ // ── Hub ─────────────────────────────────────────────
152
+ rl.registerAction("hub.create", {
153
+ description: "Create a hub",
154
+ inputSchema: { name: { type: "string", required: true }, address: { type: "object", required: true } },
155
+ async execute(input, ctx) { return apiRequest(key(ctx), "POST", "hubs", input); },
156
+ });
157
+ rl.registerAction("hub.list", {
158
+ description: "List hubs",
159
+ inputSchema: { limit: { type: "number", required: false } },
160
+ async execute(input, ctx) {
161
+ const data = (await apiRequest(key(ctx), "GET", "hubs"));
162
+ const p = (input ?? {});
163
+ return p.limit ? data.slice(0, p.limit) : data;
164
+ },
165
+ });
166
+ rl.registerAction("hub.update", {
167
+ description: "Update a hub",
168
+ inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true } },
169
+ async execute(input, ctx) {
170
+ const p = input;
171
+ return apiRequest(key(ctx), "PUT", `hubs/${p.id}`, p.data);
172
+ },
173
+ });
174
+ // ── Team ────────────────────────────────────────────
175
+ registerCrud(rl, "team", "teams", key, {
176
+ name: { type: "string", required: true },
177
+ workers: { type: "object", required: true, description: "Array of worker IDs" },
178
+ managers: { type: "object", required: true, description: "Array of admin IDs" },
179
+ });
180
+ // ── Recipient ───────────────────────────────────────
181
+ rl.registerAction("recipient.create", {
182
+ description: "Create a recipient",
183
+ inputSchema: { name: { type: "string", required: true }, phone: { type: "string", required: true }, notes: { type: "string", required: false } },
184
+ async execute(input, ctx) { return apiRequest(key(ctx), "POST", "recipients", input); },
185
+ });
186
+ rl.registerAction("recipient.get", {
187
+ description: "Get a recipient by ID",
188
+ inputSchema: { id: { type: "string", required: true } },
189
+ async execute(input, ctx) { return apiRequest(key(ctx), "GET", `recipients/${input.id}`); },
190
+ });
191
+ rl.registerAction("recipient.update", {
192
+ description: "Update a recipient",
193
+ inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: true } },
194
+ async execute(input, ctx) {
195
+ const p = input;
196
+ return apiRequest(key(ctx), "PUT", `recipients/${p.id}`, p.data);
197
+ },
198
+ });
199
+ // ── Container ────────────────────────────────────────
200
+ rl.registerAction("container.get", {
201
+ description: "Get a container by type and ID",
202
+ inputSchema: {
203
+ containerType: { type: "string", required: true, description: "workers, teams, or organizations" },
204
+ containerId: { type: "string", required: true },
205
+ },
206
+ async execute(input, ctx) {
207
+ const p = input;
208
+ return apiRequest(key(ctx), "GET", `containers/${p.containerType}/${p.containerId}`);
209
+ },
210
+ });
211
+ rl.registerAction("container.updateTasks", {
212
+ description: "Update tasks in a container",
213
+ inputSchema: {
214
+ containerType: { type: "string", required: true, description: "workers, teams, or organizations" },
215
+ containerId: { type: "string", required: true },
216
+ tasks: { type: "object", required: true, description: "Array of task IDs" },
217
+ },
218
+ async execute(input, ctx) {
219
+ const p = input;
220
+ return apiRequest(key(ctx), "PUT", `containers/${p.containerType}/${p.containerId}`, { tasks: p.tasks });
221
+ },
222
+ });
223
+ rl.registerAction("team.getTimeEstimates", {
224
+ description: "Get driver time estimates for a team",
225
+ inputSchema: {
226
+ id: { type: "string", required: true },
227
+ dropoffLocation: { type: "string", required: false, description: "lng,lat" },
228
+ pickupLocation: { type: "string", required: false, description: "lng,lat" },
229
+ },
230
+ async execute(input, ctx) {
231
+ const { id, ...qs } = input;
232
+ return apiRequest(key(ctx), "GET", `teams/${id}/estimate`, undefined, qs);
233
+ },
234
+ });
235
+ rl.registerAction("team.autoDispatch", {
236
+ description: "Auto-dispatch tasks for a team",
237
+ inputSchema: { id: { type: "string", required: true }, data: { type: "object", required: false } },
238
+ async execute(input, ctx) {
239
+ const p = input;
240
+ return apiRequest(key(ctx), "POST", `teams/${p.id}/dispatch`, p.data ?? {});
241
+ },
242
+ });
243
+ // ── Destination ─────────────────────────────────────
244
+ rl.registerAction("destination.create", {
245
+ description: "Create a destination",
246
+ inputSchema: { address: { type: "object", required: true, description: "{ unparsed: string } or { number, street, city, country }" } },
247
+ async execute(input, ctx) { return apiRequest(key(ctx), "POST", "destinations", input); },
248
+ });
249
+ rl.registerAction("destination.get", {
250
+ description: "Get a destination by ID",
251
+ inputSchema: { id: { type: "string", required: true } },
252
+ async execute(input, ctx) { return apiRequest(key(ctx), "GET", `destinations/${input.id}`); },
253
+ });
254
+ }
@@ -0,0 +1,32 @@
1
+ export default function openThesaurus(rl) {
2
+ rl.setName("openThesaurus");
3
+ rl.setVersion("0.1.0");
4
+ rl.setConnectionSchema({});
5
+ rl.registerAction("synonyms.get", {
6
+ description: "Get synonyms for a German word (OpenThesaurus API, no auth required)",
7
+ inputSchema: {
8
+ text: { type: "string", required: true, description: "German word to look up" },
9
+ baseform: { type: "boolean", required: false, description: "Return base form of search term" },
10
+ similar: { type: "boolean", required: false, description: "Return similarly written words" },
11
+ startswith: { type: "boolean", required: false, description: "Only match words starting with term" },
12
+ substring: { type: "boolean", required: false, description: "Match partial words" },
13
+ subsynsets: { type: "boolean", required: false, description: "Include sub-terms" },
14
+ supersynsets: { type: "boolean", required: false, description: "Include generic terms" },
15
+ },
16
+ async execute(input) {
17
+ const p = (input ?? {});
18
+ const url = new URL("https://www.openthesaurus.de/synonyme/search");
19
+ url.searchParams.set("q", p.text);
20
+ url.searchParams.set("format", "application/json");
21
+ for (const key of ["baseform", "similar", "startswith", "substring", "subsynsets", "supersynsets"]) {
22
+ if (p[key])
23
+ url.searchParams.set(key, "true");
24
+ }
25
+ const res = await fetch(url.toString(), { headers: { "User-Agent": "runline" } });
26
+ if (!res.ok)
27
+ throw new Error(`OpenThesaurus error ${res.status}: ${await res.text()}`);
28
+ const data = (await res.json());
29
+ return data.synsets;
30
+ },
31
+ });
32
+ }
@@ -0,0 +1,60 @@
1
+ const BASE = "https://api.openweathermap.org/data/2.5";
2
+ const locationSchema = {
3
+ cityName: { type: "string", required: false, description: "City name (e.g. berlin,de)" },
4
+ cityId: { type: "number", required: false, description: "City ID from OpenWeatherMap" },
5
+ lat: { type: "string", required: false, description: "Latitude" },
6
+ lon: { type: "string", required: false, description: "Longitude" },
7
+ zip: { type: "string", required: false, description: "Zip code (e.g. 10115,de)" },
8
+ units: { type: "string", required: false, description: "Units: metric (default), imperial, standard" },
9
+ lang: { type: "string", required: false, description: "Language code (e.g. en, de)" },
10
+ };
11
+ function buildQs(apiKey, input) {
12
+ const qs = new URLSearchParams();
13
+ qs.set("APPID", apiKey);
14
+ qs.set("units", input.units ?? "metric");
15
+ if (input.cityName)
16
+ qs.set("q", input.cityName);
17
+ else if (input.cityId)
18
+ qs.set("id", String(input.cityId));
19
+ else if (input.lat && input.lon) {
20
+ qs.set("lat", input.lat);
21
+ qs.set("lon", input.lon);
22
+ }
23
+ else if (input.zip)
24
+ qs.set("zip", input.zip);
25
+ if (input.lang)
26
+ qs.set("lang", input.lang);
27
+ return qs;
28
+ }
29
+ export default function openWeatherMap(rl) {
30
+ rl.setName("openweathermap");
31
+ rl.setVersion("0.1.0");
32
+ rl.setConnectionSchema({
33
+ apiKey: { type: "string", required: true, description: "OpenWeatherMap API key", env: "OPENWEATHERMAP_API_KEY" },
34
+ });
35
+ const key = (ctx) => ctx.connection.config.apiKey;
36
+ rl.registerAction("weather.current", {
37
+ description: "Get current weather data for a location",
38
+ inputSchema: locationSchema,
39
+ async execute(input, ctx) {
40
+ const p = (input ?? {});
41
+ const qs = buildQs(key(ctx), p);
42
+ const res = await fetch(`${BASE}/weather?${qs.toString()}`);
43
+ if (!res.ok)
44
+ throw new Error(`OpenWeatherMap error ${res.status}: ${await res.text()}`);
45
+ return res.json();
46
+ },
47
+ });
48
+ rl.registerAction("weather.forecast5day", {
49
+ description: "Get 5-day / 3-hour weather forecast for a location",
50
+ inputSchema: locationSchema,
51
+ async execute(input, ctx) {
52
+ const p = (input ?? {});
53
+ const qs = buildQs(key(ctx), p);
54
+ const res = await fetch(`${BASE}/forecast?${qs.toString()}`);
55
+ if (!res.ok)
56
+ throw new Error(`OpenWeatherMap error ${res.status}: ${await res.text()}`);
57
+ return res.json();
58
+ },
59
+ });
60
+ }
@@ -0,0 +1,62 @@
1
+ const BASE = "https://api.ouraring.com/v2";
2
+ async function apiRequest(token, endpoint, qs = {}) {
3
+ const url = new URL(`${BASE}${endpoint}`);
4
+ for (const [k, v] of Object.entries(qs)) {
5
+ if (v !== undefined && v !== null)
6
+ url.searchParams.set(k, String(v));
7
+ }
8
+ const res = await fetch(url.toString(), {
9
+ headers: { Authorization: `Bearer ${token}` },
10
+ });
11
+ if (!res.ok)
12
+ throw new Error(`Oura API error ${res.status}: ${await res.text()}`);
13
+ return res.json();
14
+ }
15
+ function formatDate(d) {
16
+ if (!d)
17
+ return undefined;
18
+ return String(d).split("T")[0];
19
+ }
20
+ export default function oura(rl) {
21
+ rl.setName("oura");
22
+ rl.setVersion("0.1.0");
23
+ rl.setConnectionSchema({
24
+ accessToken: { type: "string", required: true, description: "Oura personal access token", env: "OURA_ACCESS_TOKEN" },
25
+ });
26
+ const key = (ctx) => ctx.connection.config.accessToken;
27
+ rl.registerAction("profile.get", {
28
+ description: "Get the user's personal information",
29
+ inputSchema: {},
30
+ async execute(_input, ctx) {
31
+ return apiRequest(key(ctx), "/usercollection/personal_info");
32
+ },
33
+ });
34
+ const summaryEndpoints = [
35
+ { name: "summary.activity", path: "/usercollection/daily_activity", description: "Get daily activity summary" },
36
+ { name: "summary.readiness", path: "/usercollection/daily_readiness", description: "Get daily readiness summary" },
37
+ { name: "summary.sleep", path: "/usercollection/daily_sleep", description: "Get daily sleep summary" },
38
+ ];
39
+ for (const ep of summaryEndpoints) {
40
+ rl.registerAction(ep.name, {
41
+ description: ep.description,
42
+ inputSchema: {
43
+ startDate: { type: "string", required: false, description: "Start date (YYYY-MM-DD), defaults to a week ago" },
44
+ endDate: { type: "string", required: false, description: "End date (YYYY-MM-DD), defaults to today" },
45
+ limit: { type: "number", required: false, description: "Max results (default all)" },
46
+ },
47
+ async execute(input, ctx) {
48
+ const p = (input ?? {});
49
+ const qs = {};
50
+ if (p.startDate)
51
+ qs.start_date = formatDate(p.startDate);
52
+ if (p.endDate)
53
+ qs.end_date = formatDate(p.endDate);
54
+ const data = (await apiRequest(key(ctx), ep.path, qs));
55
+ let items = (data.data ?? []);
56
+ if (p.limit)
57
+ items = items.slice(0, p.limit);
58
+ return items;
59
+ },
60
+ });
61
+ }
62
+ }
@@ -0,0 +1,247 @@
1
+ function getConn(ctx) {
2
+ const c = ctx.connection.config;
3
+ const sandbox = c.sandbox;
4
+ const base = sandbox ? "https://sandbox-vendors.paddle.com/api" : "https://vendors.paddle.com/api";
5
+ return { base, vendorId: c.vendorId, vendorAuthCode: c.vendorAuthCode };
6
+ }
7
+ async function apiRequest(conn, endpoint, body = {}) {
8
+ body.vendor_id = conn.vendorId;
9
+ body.vendor_auth_code = conn.vendorAuthCode;
10
+ const res = await fetch(`${conn.base}${endpoint}`, {
11
+ method: "POST",
12
+ headers: { "Content-Type": "application/json" },
13
+ body: JSON.stringify(body),
14
+ });
15
+ if (!res.ok)
16
+ throw new Error(`Paddle API error ${res.status}: ${await res.text()}`);
17
+ const json = (await res.json());
18
+ if (!json.success)
19
+ throw new Error(`Paddle API error: ${JSON.stringify(json.error ?? json)}`);
20
+ return json.response;
21
+ }
22
+ async function paginate(conn, endpoint, body = {}) {
23
+ const all = [];
24
+ body.results_per_page = 200;
25
+ body.page = 1;
26
+ let items;
27
+ do {
28
+ const resp = await apiRequest(conn, endpoint, { ...body });
29
+ items = Array.isArray(resp) ? resp : [];
30
+ all.push(...items);
31
+ body.page = body.page + 1;
32
+ } while (items.length === 200);
33
+ return all;
34
+ }
35
+ export default function paddle(rl) {
36
+ rl.setName("paddle");
37
+ rl.setVersion("0.1.0");
38
+ rl.setConnectionSchema({
39
+ vendorId: { type: "string", required: true, description: "Paddle Vendor ID", env: "PADDLE_VENDOR_ID" },
40
+ vendorAuthCode: { type: "string", required: true, description: "Paddle Vendor Auth Code", env: "PADDLE_VENDOR_AUTH_CODE" },
41
+ sandbox: { type: "boolean", required: false, description: "Use sandbox environment (default false)" },
42
+ });
43
+ // ── Coupon ──────────────────────────────────────────
44
+ rl.registerAction("coupon.create", {
45
+ description: "Create a coupon",
46
+ inputSchema: {
47
+ couponType: { type: "string", required: true, description: "product or checkout" },
48
+ discountType: { type: "string", required: true, description: "flat or percentage" },
49
+ discountAmount: { type: "number", required: true },
50
+ productIds: { type: "string", required: false, description: "Comma-separated product IDs (for product coupon type)" },
51
+ currency: { type: "string", required: false, description: "Currency code (required for flat discount)" },
52
+ allowedUses: { type: "number", required: false },
53
+ couponCode: { type: "string", required: false },
54
+ couponPrefix: { type: "string", required: false },
55
+ expires: { type: "string", required: false, description: "Expiry date YYYY-MM-DD" },
56
+ group: { type: "string", required: false },
57
+ recurring: { type: "boolean", required: false },
58
+ numberOfCoupons: { type: "number", required: false },
59
+ description: { type: "string", required: false },
60
+ },
61
+ async execute(input, ctx) {
62
+ const p = (input ?? {});
63
+ const body = {
64
+ coupon_type: p.couponType, discount_type: p.discountType, discount_amount: p.discountAmount,
65
+ };
66
+ if (p.productIds)
67
+ body.product_ids = p.productIds;
68
+ if (p.currency)
69
+ body.currency = p.currency;
70
+ if (p.allowedUses)
71
+ body.allowed_uses = p.allowedUses;
72
+ if (p.couponCode)
73
+ body.coupon_code = p.couponCode;
74
+ if (p.couponPrefix)
75
+ body.coupon_prefix = p.couponPrefix;
76
+ if (p.expires)
77
+ body.expires = p.expires;
78
+ if (p.group)
79
+ body.group = p.group;
80
+ if (p.recurring !== undefined)
81
+ body.recurring = p.recurring ? 1 : 0;
82
+ if (p.numberOfCoupons)
83
+ body.num_coupons = p.numberOfCoupons;
84
+ if (p.description)
85
+ body.description = p.description;
86
+ const resp = (await apiRequest(getConn(ctx), "/2.1/product/create_coupon", body));
87
+ return resp.coupon_codes;
88
+ },
89
+ });
90
+ rl.registerAction("coupon.list", {
91
+ description: "List coupons for a product",
92
+ inputSchema: {
93
+ productId: { type: "string", required: true, description: "Product ID" },
94
+ limit: { type: "number", required: false },
95
+ },
96
+ async execute(input, ctx) {
97
+ const p = (input ?? {});
98
+ const resp = (await apiRequest(getConn(ctx), "/2.0/product/list_coupons", { product_id: p.productId }));
99
+ if (p.limit)
100
+ return resp.slice(0, p.limit);
101
+ return resp;
102
+ },
103
+ });
104
+ rl.registerAction("coupon.update", {
105
+ description: "Update a coupon by code or group",
106
+ inputSchema: {
107
+ couponCode: { type: "string", required: false, description: "Coupon code to update" },
108
+ group: { type: "string", required: false, description: "Group name to update" },
109
+ newCouponCode: { type: "string", required: false },
110
+ newGroup: { type: "string", required: false },
111
+ allowedUses: { type: "number", required: false },
112
+ currency: { type: "string", required: false },
113
+ discountAmount: { type: "number", required: false },
114
+ expires: { type: "string", required: false },
115
+ productIds: { type: "string", required: false },
116
+ recurring: { type: "boolean", required: false },
117
+ },
118
+ async execute(input, ctx) {
119
+ const p = (input ?? {});
120
+ const body = {};
121
+ if (p.couponCode)
122
+ body.coupon_code = p.couponCode;
123
+ if (p.group)
124
+ body.group = p.group;
125
+ if (p.newCouponCode)
126
+ body.new_coupon_code = p.newCouponCode;
127
+ if (p.newGroup)
128
+ body.new_group = p.newGroup;
129
+ if (p.allowedUses)
130
+ body.allowed_uses = p.allowedUses;
131
+ if (p.currency)
132
+ body.currency = p.currency;
133
+ if (p.discountAmount)
134
+ body.discount_amount = p.discountAmount;
135
+ if (p.expires)
136
+ body.expires = p.expires;
137
+ if (p.productIds)
138
+ body.product_ids = p.productIds;
139
+ if (p.recurring !== undefined)
140
+ body.recurring = p.recurring ? 1 : 0;
141
+ return apiRequest(getConn(ctx), "/2.1/product/update_coupon", body);
142
+ },
143
+ });
144
+ // ── Payment ─────────────────────────────────────────
145
+ rl.registerAction("payment.list", {
146
+ description: "List subscription payments",
147
+ inputSchema: {
148
+ subscriptionId: { type: "number", required: false },
149
+ plan: { type: "string", required: false },
150
+ state: { type: "string", required: false },
151
+ isPaid: { type: "boolean", required: false },
152
+ from: { type: "string", required: false, description: "YYYY-MM-DD" },
153
+ to: { type: "string", required: false, description: "YYYY-MM-DD" },
154
+ limit: { type: "number", required: false },
155
+ },
156
+ async execute(input, ctx) {
157
+ const p = (input ?? {});
158
+ const body = {};
159
+ if (p.subscriptionId)
160
+ body.subscription_id = p.subscriptionId;
161
+ if (p.plan)
162
+ body.plan = p.plan;
163
+ if (p.state)
164
+ body.state = p.state;
165
+ if (p.isPaid !== undefined)
166
+ body.is_paid = p.isPaid ? 1 : 0;
167
+ if (p.from)
168
+ body.from = p.from;
169
+ if (p.to)
170
+ body.to = p.to;
171
+ const resp = (await apiRequest(getConn(ctx), "/2.0/subscription/payments", body));
172
+ if (p.limit)
173
+ return resp.slice(0, p.limit);
174
+ return resp;
175
+ },
176
+ });
177
+ rl.registerAction("payment.reschedule", {
178
+ description: "Reschedule a payment",
179
+ inputSchema: {
180
+ paymentId: { type: "number", required: true },
181
+ date: { type: "string", required: true, description: "New payment date YYYY-MM-DD" },
182
+ },
183
+ async execute(input, ctx) {
184
+ const { paymentId, date } = input;
185
+ return apiRequest(getConn(ctx), "/2.0/subscription/payments_reschedule", { payment_id: paymentId, date });
186
+ },
187
+ });
188
+ // ── Plan ────────────────────────────────────────────
189
+ rl.registerAction("plan.get", {
190
+ description: "Get a subscription plan by ID",
191
+ inputSchema: { planId: { type: "string", required: true } },
192
+ async execute(input, ctx) {
193
+ const { planId } = input;
194
+ return apiRequest(getConn(ctx), "/2.0/subscription/plans", { plan: planId });
195
+ },
196
+ });
197
+ rl.registerAction("plan.list", {
198
+ description: "List all subscription plans",
199
+ inputSchema: { limit: { type: "number", required: false } },
200
+ async execute(input, ctx) {
201
+ const resp = (await apiRequest(getConn(ctx), "/2.0/subscription/plans"));
202
+ const limit = input?.limit;
203
+ if (limit)
204
+ return resp.slice(0, limit);
205
+ return resp;
206
+ },
207
+ });
208
+ // ── Product ─────────────────────────────────────────
209
+ rl.registerAction("product.list", {
210
+ description: "List all products",
211
+ inputSchema: { limit: { type: "number", required: false } },
212
+ async execute(input, ctx) {
213
+ const resp = (await apiRequest(getConn(ctx), "/2.0/product/get_products"));
214
+ const products = (resp.products ?? resp);
215
+ const limit = input?.limit;
216
+ if (limit)
217
+ return products.slice(0, limit);
218
+ return products;
219
+ },
220
+ });
221
+ // ── User ────────────────────────────────────────────
222
+ rl.registerAction("user.list", {
223
+ description: "List subscription users",
224
+ inputSchema: {
225
+ state: { type: "string", required: false, description: "active, past_due, trialing, paused, deleted" },
226
+ planId: { type: "string", required: false },
227
+ subscriptionId: { type: "string", required: false },
228
+ limit: { type: "number", required: false },
229
+ },
230
+ async execute(input, ctx) {
231
+ const p = (input ?? {});
232
+ const conn = getConn(ctx);
233
+ const body = {};
234
+ if (p.state)
235
+ body.state = p.state;
236
+ if (p.planId)
237
+ body.plan_id = p.planId;
238
+ if (p.subscriptionId)
239
+ body.subscription_id = p.subscriptionId;
240
+ if (p.limit) {
241
+ body.results_per_page = p.limit;
242
+ return apiRequest(conn, "/2.0/subscription/users", body);
243
+ }
244
+ return paginate(conn, "/2.0/subscription/users", body);
245
+ },
246
+ });
247
+ }