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,327 @@
1
+ const BASE_URL = "https://coda.io/apis/v1";
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 && v !== null)
7
+ url.searchParams.set(k, String(v));
8
+ }
9
+ }
10
+ const opts = {
11
+ method,
12
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}` },
13
+ };
14
+ if (body && Object.keys(body).length > 0 && method !== "GET" && method !== "DELETE") {
15
+ opts.body = JSON.stringify(body);
16
+ }
17
+ const res = await fetch(url.toString(), opts);
18
+ if (!res.ok)
19
+ throw new Error(`Coda API error ${res.status}: ${await res.text()}`);
20
+ if (res.status === 204)
21
+ return { success: true };
22
+ return res.json();
23
+ }
24
+ async function paginateAll(token, endpoint, qs, limit) {
25
+ const results = [];
26
+ let pageToken;
27
+ while (true) {
28
+ const q = { ...qs };
29
+ if (pageToken)
30
+ q.pageToken = pageToken;
31
+ const data = (await apiRequest(token, "GET", endpoint, undefined, q));
32
+ const items = data.items ?? [];
33
+ results.push(...items);
34
+ if (limit && results.length >= limit)
35
+ return results.slice(0, limit);
36
+ if (!data.nextPageToken)
37
+ break;
38
+ pageToken = data.nextPageToken;
39
+ }
40
+ return results;
41
+ }
42
+ function getToken(ctx) {
43
+ return ctx.connection.config.accessToken;
44
+ }
45
+ export default function coda(rl) {
46
+ rl.setName("coda");
47
+ rl.setVersion("0.1.0");
48
+ rl.setConnectionSchema({
49
+ accessToken: {
50
+ type: "string",
51
+ required: true,
52
+ description: "Coda API token",
53
+ env: "CODA_ACCESS_TOKEN",
54
+ },
55
+ });
56
+ // ── Table Row ───────────────────────────────────────
57
+ rl.registerAction("table.createRow", {
58
+ description: "Create/upsert a row in a table",
59
+ inputSchema: {
60
+ docId: { type: "string", required: true, description: "Doc ID" },
61
+ tableId: { type: "string", required: true, description: "Table ID" },
62
+ cells: { type: "object", required: true, description: "Column-value pairs" },
63
+ keyColumns: { type: "array", required: false, description: "Key columns for upsert" },
64
+ disableParsing: { type: "boolean", required: false, description: "Disable value parsing" },
65
+ },
66
+ async execute(input, ctx) {
67
+ const { docId, tableId, cells, keyColumns, disableParsing } = input;
68
+ const qs = {};
69
+ if (disableParsing)
70
+ qs.disableParsing = true;
71
+ const row = Object.entries(cells).map(([column, value]) => ({ column, value }));
72
+ const body = { rows: [{ cells: row }] };
73
+ if (keyColumns)
74
+ body.keyColumns = keyColumns;
75
+ return apiRequest(getToken(ctx), "POST", `/docs/${docId}/tables/${tableId}/rows`, body, qs);
76
+ },
77
+ });
78
+ rl.registerAction("table.getRow", {
79
+ description: "Get a row by ID",
80
+ inputSchema: {
81
+ docId: { type: "string", required: true, description: "Doc ID" },
82
+ tableId: { type: "string", required: true, description: "Table ID" },
83
+ rowId: { type: "string", required: true, description: "Row ID or name" },
84
+ useColumnNames: { type: "boolean", required: false, description: "Use column names (default: true)" },
85
+ valueFormat: { type: "string", required: false, description: "Value format: simple, simpleWithArrays, rich" },
86
+ },
87
+ async execute(input, ctx) {
88
+ const { docId, tableId, rowId, useColumnNames = true, valueFormat } = input;
89
+ const qs = { useColumnNames };
90
+ if (valueFormat)
91
+ qs.valueFormat = valueFormat;
92
+ const data = (await apiRequest(getToken(ctx), "GET", `/docs/${docId}/tables/${tableId}/rows/${rowId}`, undefined, qs));
93
+ return { id: data.id, ...data.values };
94
+ },
95
+ });
96
+ rl.registerAction("table.listRows", {
97
+ description: "List rows in a table",
98
+ inputSchema: {
99
+ docId: { type: "string", required: true, description: "Doc ID" },
100
+ tableId: { type: "string", required: true, description: "Table ID" },
101
+ query: { type: "string", required: false, description: "Search query" },
102
+ sortBy: { type: "string", required: false, description: "Sort column" },
103
+ useColumnNames: { type: "boolean", required: false, description: "Use column names (default: true)" },
104
+ valueFormat: { type: "string", required: false, description: "Value format" },
105
+ visibleOnly: { type: "boolean", required: false, description: "Only visible rows" },
106
+ limit: { type: "number", required: false, description: "Max results" },
107
+ },
108
+ async execute(input, ctx) {
109
+ const { docId, tableId, query, sortBy, useColumnNames = true, valueFormat, visibleOnly, limit } = (input ?? {});
110
+ const qs = { useColumnNames };
111
+ if (query)
112
+ qs.query = query;
113
+ if (sortBy)
114
+ qs.sortBy = sortBy;
115
+ if (valueFormat)
116
+ qs.valueFormat = valueFormat;
117
+ if (visibleOnly)
118
+ qs.visibleOnly = visibleOnly;
119
+ const rows = await paginateAll(getToken(ctx), `/docs/${docId}/tables/${tableId}/rows`, qs, limit);
120
+ return rows.map((r) => {
121
+ const row = r;
122
+ return { id: row.id, ...row.values };
123
+ });
124
+ },
125
+ });
126
+ rl.registerAction("table.deleteRow", {
127
+ description: "Delete a row",
128
+ inputSchema: {
129
+ docId: { type: "string", required: true, description: "Doc ID" },
130
+ tableId: { type: "string", required: true, description: "Table ID" },
131
+ rowId: { type: "string", required: true, description: "Row ID" },
132
+ },
133
+ async execute(input, ctx) {
134
+ const { docId, tableId, rowId } = input;
135
+ return apiRequest(getToken(ctx), "DELETE", `/docs/${docId}/tables/${tableId}/rows`, { rowIds: [rowId] });
136
+ },
137
+ });
138
+ rl.registerAction("table.pushButton", {
139
+ description: "Push a button on a row",
140
+ inputSchema: {
141
+ docId: { type: "string", required: true, description: "Doc ID" },
142
+ tableId: { type: "string", required: true, description: "Table ID" },
143
+ rowId: { type: "string", required: true, description: "Row ID" },
144
+ columnId: { type: "string", required: true, description: "Button column ID" },
145
+ },
146
+ async execute(input, ctx) {
147
+ const { docId, tableId, rowId, columnId } = input;
148
+ return apiRequest(getToken(ctx), "POST", `/docs/${docId}/tables/${tableId}/rows/${rowId}/buttons/${columnId}`);
149
+ },
150
+ });
151
+ // ── Table Column ────────────────────────────────────
152
+ rl.registerAction("table.getColumn", {
153
+ description: "Get a column",
154
+ inputSchema: {
155
+ docId: { type: "string", required: true, description: "Doc ID" },
156
+ tableId: { type: "string", required: true, description: "Table ID" },
157
+ columnId: { type: "string", required: true, description: "Column ID" },
158
+ },
159
+ async execute(input, ctx) {
160
+ const { docId, tableId, columnId } = input;
161
+ return apiRequest(getToken(ctx), "GET", `/docs/${docId}/tables/${tableId}/columns/${columnId}`);
162
+ },
163
+ });
164
+ rl.registerAction("table.listColumns", {
165
+ description: "List columns in a table",
166
+ inputSchema: {
167
+ docId: { type: "string", required: true, description: "Doc ID" },
168
+ tableId: { type: "string", required: true, description: "Table ID" },
169
+ limit: { type: "number", required: false, description: "Max results" },
170
+ },
171
+ async execute(input, ctx) {
172
+ const { docId, tableId, limit } = (input ?? {});
173
+ return paginateAll(getToken(ctx), `/docs/${docId}/tables/${tableId}/columns`, undefined, limit);
174
+ },
175
+ });
176
+ // ── Formula ─────────────────────────────────────────
177
+ rl.registerAction("formula.get", {
178
+ description: "Get a formula",
179
+ inputSchema: {
180
+ docId: { type: "string", required: true, description: "Doc ID" },
181
+ formulaId: { type: "string", required: true, description: "Formula ID" },
182
+ },
183
+ async execute(input, ctx) {
184
+ const { docId, formulaId } = input;
185
+ return apiRequest(getToken(ctx), "GET", `/docs/${docId}/formulas/${formulaId}`);
186
+ },
187
+ });
188
+ rl.registerAction("formula.list", {
189
+ description: "List formulas in a doc",
190
+ inputSchema: {
191
+ docId: { type: "string", required: true, description: "Doc ID" },
192
+ limit: { type: "number", required: false, description: "Max results" },
193
+ },
194
+ async execute(input, ctx) {
195
+ const { docId, limit } = (input ?? {});
196
+ return paginateAll(getToken(ctx), `/docs/${docId}/formulas`, undefined, limit);
197
+ },
198
+ });
199
+ // ── Control ─────────────────────────────────────────
200
+ rl.registerAction("control.get", {
201
+ description: "Get a control",
202
+ inputSchema: {
203
+ docId: { type: "string", required: true, description: "Doc ID" },
204
+ controlId: { type: "string", required: true, description: "Control ID" },
205
+ },
206
+ async execute(input, ctx) {
207
+ const { docId, controlId } = input;
208
+ return apiRequest(getToken(ctx), "GET", `/docs/${docId}/controls/${controlId}`);
209
+ },
210
+ });
211
+ rl.registerAction("control.list", {
212
+ description: "List controls in a doc",
213
+ inputSchema: {
214
+ docId: { type: "string", required: true, description: "Doc ID" },
215
+ limit: { type: "number", required: false, description: "Max results" },
216
+ },
217
+ async execute(input, ctx) {
218
+ const { docId, limit } = (input ?? {});
219
+ return paginateAll(getToken(ctx), `/docs/${docId}/controls`, undefined, limit);
220
+ },
221
+ });
222
+ // ── View ────────────────────────────────────────────
223
+ rl.registerAction("view.get", {
224
+ description: "Get a view",
225
+ inputSchema: {
226
+ docId: { type: "string", required: true, description: "Doc ID" },
227
+ viewId: { type: "string", required: true, description: "View ID" },
228
+ },
229
+ async execute(input, ctx) {
230
+ const { docId, viewId } = input;
231
+ return apiRequest(getToken(ctx), "GET", `/docs/${docId}/tables/${viewId}`);
232
+ },
233
+ });
234
+ rl.registerAction("view.list", {
235
+ description: "List views in a doc",
236
+ inputSchema: {
237
+ docId: { type: "string", required: true, description: "Doc ID" },
238
+ limit: { type: "number", required: false, description: "Max results" },
239
+ },
240
+ async execute(input, ctx) {
241
+ const { docId, limit } = (input ?? {});
242
+ return paginateAll(getToken(ctx), `/docs/${docId}/tables`, { tableTypes: "view" }, limit);
243
+ },
244
+ });
245
+ rl.registerAction("view.listRows", {
246
+ description: "List rows in a view",
247
+ inputSchema: {
248
+ docId: { type: "string", required: true, description: "Doc ID" },
249
+ viewId: { type: "string", required: true, description: "View ID" },
250
+ query: { type: "string", required: false, description: "Search query" },
251
+ sortBy: { type: "string", required: false, description: "Sort column" },
252
+ useColumnNames: { type: "boolean", required: false, description: "Use column names (default: true)" },
253
+ valueFormat: { type: "string", required: false, description: "Value format" },
254
+ limit: { type: "number", required: false, description: "Max results" },
255
+ },
256
+ async execute(input, ctx) {
257
+ const { docId, viewId, query, sortBy, useColumnNames = true, valueFormat, limit } = (input ?? {});
258
+ const qs = { useColumnNames };
259
+ if (query)
260
+ qs.query = query;
261
+ if (sortBy)
262
+ qs.sortBy = sortBy;
263
+ if (valueFormat)
264
+ qs.valueFormat = valueFormat;
265
+ const rows = await paginateAll(getToken(ctx), `/docs/${docId}/tables/${viewId}/rows`, qs, limit);
266
+ return rows.map((r) => {
267
+ const row = r;
268
+ return { id: row.id, ...row.values };
269
+ });
270
+ },
271
+ });
272
+ rl.registerAction("view.deleteRow", {
273
+ description: "Delete a row from a view",
274
+ inputSchema: {
275
+ docId: { type: "string", required: true, description: "Doc ID" },
276
+ viewId: { type: "string", required: true, description: "View ID" },
277
+ rowId: { type: "string", required: true, description: "Row ID" },
278
+ },
279
+ async execute(input, ctx) {
280
+ const { docId, viewId, rowId } = input;
281
+ return apiRequest(getToken(ctx), "DELETE", `/docs/${docId}/tables/${viewId}/rows/${rowId}`);
282
+ },
283
+ });
284
+ rl.registerAction("view.updateRow", {
285
+ description: "Update a row in a view",
286
+ inputSchema: {
287
+ docId: { type: "string", required: true, description: "Doc ID" },
288
+ viewId: { type: "string", required: true, description: "View ID" },
289
+ rowId: { type: "string", required: true, description: "Row ID" },
290
+ cells: { type: "object", required: true, description: "Column-value pairs to update" },
291
+ disableParsing: { type: "boolean", required: false, description: "Disable value parsing" },
292
+ },
293
+ async execute(input, ctx) {
294
+ const { docId, viewId, rowId, cells, disableParsing } = input;
295
+ const qs = {};
296
+ if (disableParsing)
297
+ qs.disableParsing = true;
298
+ const row = Object.entries(cells).map(([column, value]) => ({ column, value }));
299
+ return apiRequest(getToken(ctx), "PUT", `/docs/${docId}/tables/${viewId}/rows/${rowId}`, { row: { cells: row } }, qs);
300
+ },
301
+ });
302
+ rl.registerAction("view.pushButton", {
303
+ description: "Push a button on a view row",
304
+ inputSchema: {
305
+ docId: { type: "string", required: true, description: "Doc ID" },
306
+ viewId: { type: "string", required: true, description: "View ID" },
307
+ rowId: { type: "string", required: true, description: "Row ID" },
308
+ columnId: { type: "string", required: true, description: "Button column ID" },
309
+ },
310
+ async execute(input, ctx) {
311
+ const { docId, viewId, rowId, columnId } = input;
312
+ return apiRequest(getToken(ctx), "POST", `/docs/${docId}/tables/${viewId}/rows/${rowId}/buttons/${columnId}`);
313
+ },
314
+ });
315
+ rl.registerAction("view.listColumns", {
316
+ description: "List columns in a view",
317
+ inputSchema: {
318
+ docId: { type: "string", required: true, description: "Doc ID" },
319
+ viewId: { type: "string", required: true, description: "View ID" },
320
+ limit: { type: "number", required: false, description: "Max results" },
321
+ },
322
+ async execute(input, ctx) {
323
+ const { docId, viewId, limit } = (input ?? {});
324
+ return paginateAll(getToken(ctx), `/docs/${docId}/tables/${viewId}/columns`, undefined, limit);
325
+ },
326
+ });
327
+ }
@@ -0,0 +1,244 @@
1
+ const BASE_URL = "https://api.coingecko.com/api/v3";
2
+ async function apiRequest(endpoint, qs, apiKey) {
3
+ const url = new URL(`${BASE_URL}${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 headers = { Accept: "application/json" };
11
+ if (apiKey)
12
+ headers["x-cg-demo-api-key"] = apiKey;
13
+ const res = await fetch(url.toString(), { headers });
14
+ if (!res.ok)
15
+ throw new Error(`CoinGecko API error ${res.status}: ${await res.text()}`);
16
+ return res.json();
17
+ }
18
+ export default function coingecko(rl) {
19
+ rl.setName("coingecko");
20
+ rl.setVersion("0.1.0");
21
+ rl.setConnectionSchema({
22
+ apiKey: {
23
+ type: "string",
24
+ required: false,
25
+ description: "CoinGecko API key (optional for free tier)",
26
+ env: "COINGECKO_API_KEY",
27
+ },
28
+ });
29
+ function getKey(ctx) {
30
+ return ctx.connection.config.apiKey;
31
+ }
32
+ // ── Coin ────────────────────────────────────────────
33
+ rl.registerAction("coin.get", {
34
+ description: "Get detailed coin data by ID or contract address",
35
+ inputSchema: {
36
+ coinId: { type: "string", required: false, description: "Coin ID (e.g. bitcoin)" },
37
+ platformId: { type: "string", required: false, description: "Platform ID for contract lookup" },
38
+ contractAddress: { type: "string", required: false, description: "Contract address" },
39
+ communityData: { type: "boolean", required: false, description: "Include community data" },
40
+ developerData: { type: "boolean", required: false, description: "Include developer data" },
41
+ marketData: { type: "boolean", required: false, description: "Include market data" },
42
+ tickers: { type: "boolean", required: false, description: "Include tickers" },
43
+ },
44
+ async execute(input, ctx) {
45
+ const { coinId, platformId, contractAddress, communityData, developerData, marketData, tickers } = (input ?? {});
46
+ const qs = {
47
+ community_data: communityData ?? false,
48
+ developer_data: developerData ?? false,
49
+ localization: false,
50
+ market_data: marketData ?? false,
51
+ sparkline: false,
52
+ tickers: tickers ?? false,
53
+ };
54
+ if (contractAddress && platformId) {
55
+ return apiRequest(`/coins/${platformId}/contract/${contractAddress}`, qs, getKey(ctx));
56
+ }
57
+ return apiRequest(`/coins/${coinId}`, qs, getKey(ctx));
58
+ },
59
+ });
60
+ rl.registerAction("coin.list", {
61
+ description: "List all supported coins",
62
+ inputSchema: {
63
+ limit: { type: "number", required: false, description: "Max results" },
64
+ },
65
+ async execute(input, ctx) {
66
+ const { limit } = (input ?? {});
67
+ const data = (await apiRequest("/coins/list", undefined, getKey(ctx)));
68
+ if (limit)
69
+ return data.slice(0, limit);
70
+ return data;
71
+ },
72
+ });
73
+ rl.registerAction("coin.market", {
74
+ description: "Get coin market data (price, mcap, volume) for multiple coins",
75
+ inputSchema: {
76
+ vsCurrency: { type: "string", required: true, description: "Quote currency (e.g. usd)" },
77
+ ids: { type: "string", required: false, description: "Comma-separated coin IDs" },
78
+ category: { type: "string", required: false, description: "Category filter" },
79
+ order: { type: "string", required: false, description: "Sort order" },
80
+ priceChangePercentage: { type: "string", required: false, description: "Comma-separated periods (1h,24h,7d,14d,30d,200d,1y)" },
81
+ limit: { type: "number", required: false, description: "Max results (default: 100)" },
82
+ },
83
+ async execute(input, ctx) {
84
+ const { vsCurrency, ids, category, order, priceChangePercentage, limit } = (input ?? {});
85
+ const qs = { vs_currency: vsCurrency };
86
+ if (ids)
87
+ qs.ids = ids;
88
+ if (category)
89
+ qs.category = category;
90
+ if (order)
91
+ qs.order = order;
92
+ if (priceChangePercentage)
93
+ qs.price_change_percentage = priceChangePercentage;
94
+ if (limit)
95
+ qs.per_page = limit;
96
+ return apiRequest("/coins/markets", qs, getKey(ctx));
97
+ },
98
+ });
99
+ rl.registerAction("coin.price", {
100
+ description: "Get simple price for coins",
101
+ inputSchema: {
102
+ ids: { type: "string", required: true, description: "Comma-separated coin IDs" },
103
+ vsCurrencies: { type: "string", required: true, description: "Comma-separated quote currencies" },
104
+ includeMarketCap: { type: "boolean", required: false, description: "Include market cap" },
105
+ include24hrVol: { type: "boolean", required: false, description: "Include 24h volume" },
106
+ include24hrChange: { type: "boolean", required: false, description: "Include 24h change" },
107
+ },
108
+ async execute(input, ctx) {
109
+ const { ids, vsCurrencies, includeMarketCap, include24hrVol, include24hrChange } = (input ?? {});
110
+ const qs = {
111
+ ids,
112
+ vs_currencies: vsCurrencies,
113
+ };
114
+ if (includeMarketCap)
115
+ qs.include_market_cap = true;
116
+ if (include24hrVol)
117
+ qs.include_24hr_vol = true;
118
+ if (include24hrChange)
119
+ qs.include_24hr_change = true;
120
+ return apiRequest("/simple/price", qs, getKey(ctx));
121
+ },
122
+ });
123
+ rl.registerAction("coin.tokenPrice", {
124
+ description: "Get token price by contract address",
125
+ inputSchema: {
126
+ platformId: { type: "string", required: true, description: "Platform ID (e.g. ethereum)" },
127
+ contractAddresses: { type: "string", required: true, description: "Comma-separated contract addresses" },
128
+ vsCurrencies: { type: "string", required: true, description: "Comma-separated quote currencies" },
129
+ },
130
+ async execute(input, ctx) {
131
+ const { platformId, contractAddresses, vsCurrencies } = input;
132
+ return apiRequest(`/simple/token_price/${platformId}`, {
133
+ contract_addresses: contractAddresses,
134
+ vs_currencies: vsCurrencies,
135
+ }, getKey(ctx));
136
+ },
137
+ });
138
+ rl.registerAction("coin.ticker", {
139
+ description: "Get tickers for a coin",
140
+ inputSchema: {
141
+ coinId: { type: "string", required: true, description: "Coin ID" },
142
+ exchangeIds: { type: "string", required: false, description: "Comma-separated exchange IDs" },
143
+ limit: { type: "number", required: false, description: "Max results" },
144
+ },
145
+ async execute(input, ctx) {
146
+ const { coinId, exchangeIds, limit } = (input ?? {});
147
+ const qs = {};
148
+ if (exchangeIds)
149
+ qs.exchange_ids = exchangeIds;
150
+ const data = (await apiRequest(`/coins/${coinId}/tickers`, qs, getKey(ctx)));
151
+ const tickers = data.tickers ?? [];
152
+ if (limit)
153
+ return tickers.slice(0, limit);
154
+ return tickers;
155
+ },
156
+ });
157
+ rl.registerAction("coin.history", {
158
+ description: "Get historical data for a coin on a specific date",
159
+ inputSchema: {
160
+ coinId: { type: "string", required: true, description: "Coin ID" },
161
+ date: { type: "string", required: true, description: "Date (DD-MM-YYYY format)" },
162
+ localization: { type: "boolean", required: false, description: "Include localized languages" },
163
+ },
164
+ async execute(input, ctx) {
165
+ const { coinId, date, localization } = input;
166
+ const qs = { date };
167
+ if (localization !== undefined)
168
+ qs.localization = localization;
169
+ return apiRequest(`/coins/${coinId}/history`, qs, getKey(ctx));
170
+ },
171
+ });
172
+ rl.registerAction("coin.marketChart", {
173
+ description: "Get price, market cap, and volume chart data",
174
+ inputSchema: {
175
+ coinId: { type: "string", required: false, description: "Coin ID" },
176
+ platformId: { type: "string", required: false, description: "Platform ID (for contract)" },
177
+ contractAddress: { type: "string", required: false, description: "Contract address" },
178
+ vsCurrency: { type: "string", required: true, description: "Quote currency" },
179
+ days: { type: "string", required: true, description: "Number of days (1, 7, 14, 30, 90, 180, 365, max)" },
180
+ },
181
+ async execute(input, ctx) {
182
+ const { coinId, platformId, contractAddress, vsCurrency, days } = input;
183
+ const qs = { vs_currency: vsCurrency, days };
184
+ let endpoint;
185
+ if (contractAddress && platformId) {
186
+ endpoint = `/coins/${platformId}/contract/${contractAddress}/market_chart`;
187
+ }
188
+ else {
189
+ endpoint = `/coins/${coinId}/market_chart`;
190
+ }
191
+ const data = (await apiRequest(endpoint, qs, getKey(ctx)));
192
+ const prices = data.prices ?? [];
193
+ return prices.map((p, idx) => ({
194
+ time: new Date(p[0]).toISOString(),
195
+ price: p[1],
196
+ marketCap: (data.market_caps?.[idx] ?? [])[1],
197
+ totalVolume: (data.total_volumes?.[idx] ?? [])[1],
198
+ }));
199
+ },
200
+ });
201
+ rl.registerAction("coin.candlestick", {
202
+ description: "Get OHLC candlestick data",
203
+ inputSchema: {
204
+ coinId: { type: "string", required: true, description: "Coin ID" },
205
+ vsCurrency: { type: "string", required: true, description: "Quote currency" },
206
+ days: { type: "string", required: true, description: "Number of days (1, 7, 14, 30, 90, 180, 365, max)" },
207
+ },
208
+ async execute(input, ctx) {
209
+ const { coinId, vsCurrency, days } = input;
210
+ const data = (await apiRequest(`/coins/${coinId}/ohlc`, {
211
+ vs_currency: vsCurrency,
212
+ days,
213
+ }, getKey(ctx)));
214
+ return data.map(([time, open, high, low, close]) => ({
215
+ time: new Date(time).toISOString(),
216
+ open,
217
+ high,
218
+ low,
219
+ close,
220
+ }));
221
+ },
222
+ });
223
+ // ── Event ───────────────────────────────────────────
224
+ rl.registerAction("event.list", {
225
+ description: "List crypto events",
226
+ inputSchema: {
227
+ countryCode: { type: "string", required: false, description: "Country code filter" },
228
+ type: { type: "string", required: false, description: "Event type filter" },
229
+ limit: { type: "number", required: false, description: "Max results" },
230
+ },
231
+ async execute(input, ctx) {
232
+ const { countryCode, type, limit } = (input ?? {});
233
+ const qs = {};
234
+ if (countryCode)
235
+ qs.country_code = countryCode;
236
+ if (type)
237
+ qs.type = type;
238
+ if (limit)
239
+ qs.per_page = limit;
240
+ const data = (await apiRequest("/events", qs, getKey(ctx)));
241
+ return data.data;
242
+ },
243
+ });
244
+ }