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,280 @@
1
+ const BASE_URL = "https://api.airtable.com/v0";
2
+ async function apiRequest(token, method, endpoint, body, qs) {
3
+ const url = new URL(`${BASE_URL}/${endpoint}`);
4
+ if (qs) {
5
+ for (const [k, v] of Object.entries(qs)) {
6
+ if (v === undefined)
7
+ continue;
8
+ if (Array.isArray(v)) {
9
+ for (const item of v)
10
+ url.searchParams.append(`${k}[]`, String(item));
11
+ }
12
+ else {
13
+ url.searchParams.set(k, String(v));
14
+ }
15
+ }
16
+ }
17
+ const opts = {
18
+ method,
19
+ headers: {
20
+ "Content-Type": "application/json",
21
+ Authorization: `Bearer ${token}`,
22
+ },
23
+ };
24
+ if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE") {
25
+ opts.body = JSON.stringify(body);
26
+ }
27
+ const res = await fetch(url.toString(), opts);
28
+ if (!res.ok) {
29
+ const text = await res.text();
30
+ throw new Error(`Airtable API error ${res.status}: ${text}`);
31
+ }
32
+ if (res.status === 204)
33
+ return { success: true };
34
+ return res.json();
35
+ }
36
+ async function paginateRecords(token, endpoint, qs, limit) {
37
+ const results = [];
38
+ const _qs = { pageSize: 100, ...qs };
39
+ let offset;
40
+ while (true) {
41
+ if (offset)
42
+ _qs.offset = offset;
43
+ const data = (await apiRequest(token, "GET", endpoint, undefined, _qs));
44
+ results.push(...data.records);
45
+ if (limit && results.length >= limit)
46
+ return results.slice(0, limit);
47
+ if (!data.offset)
48
+ break;
49
+ offset = data.offset;
50
+ }
51
+ return results;
52
+ }
53
+ /** Airtable limits batch writes to 10 records at a time */
54
+ async function batchWrite(token, method, endpoint, records, extraBody) {
55
+ const results = [];
56
+ const batchSize = 10;
57
+ for (let i = 0; i < records.length; i += batchSize) {
58
+ const batch = records.slice(i, i + batchSize);
59
+ const body = { ...extraBody, records: batch };
60
+ const data = (await apiRequest(token, method, endpoint, body));
61
+ results.push(...data.records);
62
+ }
63
+ return results;
64
+ }
65
+ function getToken(ctx) {
66
+ return ctx.connection.config.token;
67
+ }
68
+ export default function airtable(rl) {
69
+ rl.setName("airtable");
70
+ rl.setVersion("0.1.0");
71
+ rl.setConnectionSchema({
72
+ token: {
73
+ type: "string",
74
+ required: true,
75
+ description: "Airtable personal access token or API key",
76
+ env: "AIRTABLE_TOKEN",
77
+ },
78
+ });
79
+ // ── Base ────────────────────────────────────────────
80
+ rl.registerAction("base.list", {
81
+ description: "List all accessible bases",
82
+ inputSchema: {
83
+ limit: { type: "number", required: false, description: "Max results to return" },
84
+ },
85
+ async execute(input, ctx) {
86
+ const { limit } = input ?? {};
87
+ const token = getToken(ctx);
88
+ const results = [];
89
+ let offset;
90
+ while (true) {
91
+ const qs = {};
92
+ if (offset)
93
+ qs.offset = offset;
94
+ const data = (await apiRequest(token, "GET", "meta/bases", undefined, qs));
95
+ results.push(...data.bases);
96
+ if (limit && results.length >= limit)
97
+ return results.slice(0, limit);
98
+ if (!data.offset)
99
+ break;
100
+ offset = data.offset;
101
+ }
102
+ return results;
103
+ },
104
+ });
105
+ rl.registerAction("base.getSchema", {
106
+ description: "Get the schema (tables and fields) of a base",
107
+ inputSchema: {
108
+ baseId: { type: "string", required: true, description: "Base ID (e.g. appXXXXXXXXXXXXXX)" },
109
+ },
110
+ async execute(input, ctx) {
111
+ const { baseId } = input;
112
+ return apiRequest(getToken(ctx), "GET", `meta/bases/${baseId}/tables`);
113
+ },
114
+ });
115
+ // ── Record ──────────────────────────────────────────
116
+ rl.registerAction("record.create", {
117
+ description: "Create a record in a table",
118
+ inputSchema: {
119
+ baseId: { type: "string", required: true, description: "Base ID" },
120
+ tableId: { type: "string", required: true, description: "Table ID or name" },
121
+ fields: { type: "object", required: true, description: "Field values as key-value pairs" },
122
+ typecast: {
123
+ type: "boolean",
124
+ required: false,
125
+ description: "Automatically convert field values to appropriate types",
126
+ },
127
+ },
128
+ async execute(input, ctx) {
129
+ const { baseId, tableId, fields, typecast } = input;
130
+ const body = { fields };
131
+ if (typecast)
132
+ body.typecast = true;
133
+ return apiRequest(getToken(ctx), "POST", `${baseId}/${tableId}`, body);
134
+ },
135
+ });
136
+ rl.registerAction("record.createMany", {
137
+ description: "Create multiple records in a table (batched in groups of 10)",
138
+ inputSchema: {
139
+ baseId: { type: "string", required: true, description: "Base ID" },
140
+ tableId: { type: "string", required: true, description: "Table ID or name" },
141
+ records: {
142
+ type: "array",
143
+ required: true,
144
+ description: "Array of { fields: { ... } } objects",
145
+ },
146
+ typecast: { type: "boolean", required: false, description: "Auto-typecast values" },
147
+ },
148
+ async execute(input, ctx) {
149
+ const { baseId, tableId, records, typecast } = input;
150
+ const extra = {};
151
+ if (typecast)
152
+ extra.typecast = true;
153
+ return batchWrite(getToken(ctx), "POST", `${baseId}/${tableId}`, records, extra);
154
+ },
155
+ });
156
+ rl.registerAction("record.get", {
157
+ description: "Get a single record by ID",
158
+ inputSchema: {
159
+ baseId: { type: "string", required: true, description: "Base ID" },
160
+ tableId: { type: "string", required: true, description: "Table ID or name" },
161
+ recordId: { type: "string", required: true, description: "Record ID (e.g. recXXX)" },
162
+ },
163
+ async execute(input, ctx) {
164
+ const { baseId, tableId, recordId } = input;
165
+ return apiRequest(getToken(ctx), "GET", `${baseId}/${tableId}/${recordId}`);
166
+ },
167
+ });
168
+ rl.registerAction("record.search", {
169
+ description: "Search/list records with optional formula filter and sorting",
170
+ inputSchema: {
171
+ baseId: { type: "string", required: true, description: "Base ID" },
172
+ tableId: { type: "string", required: true, description: "Table ID or name" },
173
+ filterByFormula: {
174
+ type: "string",
175
+ required: false,
176
+ description: "Airtable formula to filter records",
177
+ },
178
+ fields: {
179
+ type: "array",
180
+ required: false,
181
+ description: "Array of field names to include in response",
182
+ },
183
+ sort: {
184
+ type: "array",
185
+ required: false,
186
+ description: "Array of { field, direction } objects (direction: 'asc' or 'desc')",
187
+ },
188
+ view: { type: "string", required: false, description: "View ID or name" },
189
+ limit: { type: "number", required: false, description: "Max records to return" },
190
+ },
191
+ async execute(input, ctx) {
192
+ const { baseId, tableId, filterByFormula, fields, sort, view, limit } = input;
193
+ const qs = {};
194
+ if (filterByFormula)
195
+ qs.filterByFormula = filterByFormula;
196
+ if (fields)
197
+ qs.fields = fields;
198
+ if (sort)
199
+ qs.sort = sort;
200
+ if (view)
201
+ qs.view = view;
202
+ if (limit && !filterByFormula)
203
+ qs.maxRecords = limit;
204
+ return paginateRecords(getToken(ctx), `${baseId}/${tableId}`, qs, limit);
205
+ },
206
+ });
207
+ rl.registerAction("record.update", {
208
+ description: "Update a record by ID (PATCH — only updates specified fields)",
209
+ inputSchema: {
210
+ baseId: { type: "string", required: true, description: "Base ID" },
211
+ tableId: { type: "string", required: true, description: "Table ID or name" },
212
+ recordId: { type: "string", required: true, description: "Record ID" },
213
+ fields: { type: "object", required: true, description: "Fields to update" },
214
+ typecast: { type: "boolean", required: false, description: "Auto-typecast values" },
215
+ },
216
+ async execute(input, ctx) {
217
+ const { baseId, tableId, recordId, fields, typecast } = input;
218
+ const body = { fields };
219
+ if (typecast)
220
+ body.typecast = true;
221
+ return apiRequest(getToken(ctx), "PATCH", `${baseId}/${tableId}/${recordId}`, body);
222
+ },
223
+ });
224
+ rl.registerAction("record.updateMany", {
225
+ description: "Update multiple records (batched in groups of 10)",
226
+ inputSchema: {
227
+ baseId: { type: "string", required: true, description: "Base ID" },
228
+ tableId: { type: "string", required: true, description: "Table ID or name" },
229
+ records: {
230
+ type: "array",
231
+ required: true,
232
+ description: "Array of { id, fields: { ... } } objects",
233
+ },
234
+ typecast: { type: "boolean", required: false, description: "Auto-typecast values" },
235
+ },
236
+ async execute(input, ctx) {
237
+ const { baseId, tableId, records, typecast } = input;
238
+ const extra = {};
239
+ if (typecast)
240
+ extra.typecast = true;
241
+ return batchWrite(getToken(ctx), "PATCH", `${baseId}/${tableId}`, records, extra);
242
+ },
243
+ });
244
+ rl.registerAction("record.upsert", {
245
+ description: "Create or update a record based on matching fields (uses Airtable's performUpsert)",
246
+ inputSchema: {
247
+ baseId: { type: "string", required: true, description: "Base ID" },
248
+ tableId: { type: "string", required: true, description: "Table ID or name" },
249
+ fields: { type: "object", required: true, description: "Field values" },
250
+ fieldsToMergeOn: {
251
+ type: "array",
252
+ required: true,
253
+ description: "Field names to match on for upsert",
254
+ },
255
+ typecast: { type: "boolean", required: false, description: "Auto-typecast values" },
256
+ },
257
+ async execute(input, ctx) {
258
+ const { baseId, tableId, fields, fieldsToMergeOn, typecast } = input;
259
+ const body = {
260
+ records: [{ fields }],
261
+ performUpsert: { fieldsToMergeOn },
262
+ };
263
+ if (typecast)
264
+ body.typecast = true;
265
+ return apiRequest(getToken(ctx), "PATCH", `${baseId}/${tableId}`, body);
266
+ },
267
+ });
268
+ rl.registerAction("record.delete", {
269
+ description: "Delete a record by ID",
270
+ inputSchema: {
271
+ baseId: { type: "string", required: true, description: "Base ID" },
272
+ tableId: { type: "string", required: true, description: "Table ID or name" },
273
+ recordId: { type: "string", required: true, description: "Record ID" },
274
+ },
275
+ async execute(input, ctx) {
276
+ const { baseId, tableId, recordId } = input;
277
+ return apiRequest(getToken(ctx), "DELETE", `${baseId}/${tableId}/${recordId}`);
278
+ },
279
+ });
280
+ }