runline 0.11.6 → 0.13.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 (256) hide show
  1. package/dist/commands/actions.js +3 -1
  2. package/dist/core/engine.js +3 -0
  3. package/dist/index.d.ts +1 -1
  4. package/dist/plugin/api.d.ts +2 -1
  5. package/dist/plugin/types.d.ts +2 -0
  6. package/dist/plugins/_shared/googleSchemas.js +23 -0
  7. package/dist/plugins/actionNetwork/src/index.js +23 -0
  8. package/dist/plugins/activeCampaign/src/index.js +48 -0
  9. package/dist/plugins/adalo/src/index.js +5 -0
  10. package/dist/plugins/affinity/src/index.js +16 -0
  11. package/dist/plugins/agileCrm/src/index.js +15 -0
  12. package/dist/plugins/airtable/src/index.js +10 -0
  13. package/dist/plugins/airtop/src/index.js +24 -0
  14. package/dist/plugins/apiTemplateIo/src/index.js +4 -0
  15. package/dist/plugins/asana/src/index.js +22 -0
  16. package/dist/plugins/autopilot/src/index.js +11 -0
  17. package/dist/plugins/bambooHr/src/index.js +11 -0
  18. package/dist/plugins/bannerbear/src/index.js +4 -0
  19. package/dist/plugins/baserow/src/index.js +8 -0
  20. package/dist/plugins/beeminder/src/index.js +18 -0
  21. package/dist/plugins/bitly/src/index.js +3 -0
  22. package/dist/plugins/bitwarden/src/index.js +19 -0
  23. package/dist/plugins/box/src/index.js +11 -0
  24. package/dist/plugins/brandfetch/src/index.js +5 -0
  25. package/dist/plugins/brevo/src/index.js +15 -0
  26. package/dist/plugins/bubble/src/index.js +5 -0
  27. package/dist/plugins/chargebee/src/index.js +5 -0
  28. package/dist/plugins/circleci/src/index.js +3 -0
  29. package/dist/plugins/ciscoWebex/src/index.js +10 -0
  30. package/dist/plugins/clearbit/src/index.js +3 -0
  31. package/dist/plugins/clickup/src/index.js +61 -0
  32. package/dist/plugins/clockify/src/index.js +25 -0
  33. package/dist/plugins/cloudflare/src/index.js +4 -0
  34. package/dist/plugins/cockpit/src/index.js +5 -0
  35. package/dist/plugins/coda/src/index.js +18 -0
  36. package/dist/plugins/coingecko/src/index.js +10 -0
  37. package/dist/plugins/contentful/src/index.js +7 -0
  38. package/dist/plugins/convertkit/src/index.js +16 -0
  39. package/dist/plugins/copper/src/index.js +7 -0
  40. package/dist/plugins/cortex/src/index.js +4 -0
  41. package/dist/plugins/currents/src/index.js +22 -0
  42. package/dist/plugins/customerIo/src/index.js +9 -0
  43. package/dist/plugins/databricks/src/index.js +34 -0
  44. package/dist/plugins/deepl/src/index.js +2 -0
  45. package/dist/plugins/demio/src/index.js +4 -0
  46. package/dist/plugins/dhl/src/index.js +1 -0
  47. package/dist/plugins/discord/src/index.js +13 -0
  48. package/dist/plugins/discourse/src/index.js +16 -0
  49. package/dist/plugins/disqus/src/index.js +4 -0
  50. package/dist/plugins/docker/src/index.js +5 -0
  51. package/dist/plugins/drift/src/index.js +5 -0
  52. package/dist/plugins/dropbox/src/index.js +9 -0
  53. package/dist/plugins/dropcontact/src/index.js +2 -0
  54. package/dist/plugins/egoi/src/index.js +4 -0
  55. package/dist/plugins/elasticsearch/src/index.js +9 -0
  56. package/dist/plugins/emelia/src/index.js +9 -0
  57. package/dist/plugins/erpnext/src/index.js +5 -0
  58. package/dist/plugins/facebookGraph/src/index.js +1 -0
  59. package/dist/plugins/freshdesk/src/index.js +10 -0
  60. package/dist/plugins/freshservice/src/index.js +7 -0
  61. package/dist/plugins/freshworksCrm/src/index.js +7 -0
  62. package/dist/plugins/getresponse/src/index.js +5 -0
  63. package/dist/plugins/ghost/src/index.js +5 -0
  64. package/dist/plugins/github/src/index.js +37 -0
  65. package/dist/plugins/gitlab/src/index.js +17 -0
  66. package/dist/plugins/gmail/src/index.js +200 -184
  67. package/dist/plugins/gong/src/index.js +4 -0
  68. package/dist/plugins/googleAppsScript/src/index.js +98 -43
  69. package/dist/plugins/googleCalendar/src/index.js +329 -250
  70. package/dist/plugins/googleContacts/src/index.js +144 -145
  71. package/dist/plugins/googleDocs/src/documents.js +31 -38
  72. package/dist/plugins/googleDocs/src/formatting.js +51 -47
  73. package/dist/plugins/googleDocs/src/images.js +23 -26
  74. package/dist/plugins/googleDocs/src/shared.js +55 -0
  75. package/dist/plugins/googleDocs/src/structure.js +111 -123
  76. package/dist/plugins/googleDocs/src/tables.js +103 -154
  77. package/dist/plugins/googleDocs/src/tabs.js +27 -23
  78. package/dist/plugins/googleDocs/src/text.js +106 -136
  79. package/dist/plugins/googleDrive/src/index.js +461 -408
  80. package/dist/plugins/googleImage/src/index.js +14 -16
  81. package/dist/plugins/googleSheets/src/index.js +527 -339
  82. package/dist/plugins/googleSlides/src/index.js +92 -72
  83. package/dist/plugins/googleTasks/src/index.js +94 -92
  84. package/dist/plugins/gotify/src/index.js +3 -0
  85. package/dist/plugins/gotowebinar/src/index.js +20 -0
  86. package/dist/plugins/grafana/src/index.js +17 -0
  87. package/dist/plugins/graphql/src/index.js +2 -0
  88. package/dist/plugins/grist/src/index.js +4 -0
  89. package/dist/plugins/hackernews/src/index.js +6 -0
  90. package/dist/plugins/halopsa/src/index.js +5 -0
  91. package/dist/plugins/harvest/src/index.js +14 -0
  92. package/dist/plugins/helpscout/src/index.js +13 -0
  93. package/dist/plugins/highlevel/src/index.js +17 -0
  94. package/dist/plugins/homeAssistant/src/index.js +13 -0
  95. package/dist/plugins/hubspot/src/index.js +14 -0
  96. package/dist/plugins/humanticAi/src/index.js +3 -0
  97. package/dist/plugins/hunter/src/index.js +3 -0
  98. package/dist/plugins/intercom/src/index.js +10 -0
  99. package/dist/plugins/iterable/src/index.js +6 -0
  100. package/dist/plugins/jenkins/src/index.js +11 -0
  101. package/dist/plugins/jira/src/index.js +16 -0
  102. package/dist/plugins/keap/src/index.js +28 -0
  103. package/dist/plugins/kobotoolbox/src/index.js +17 -0
  104. package/dist/plugins/lemlist/src/index.js +15 -0
  105. package/dist/plugins/linear/src/attachments.js +6 -0
  106. package/dist/plugins/linear/src/comments.js +5 -0
  107. package/dist/plugins/linear/src/cycles.js +2 -0
  108. package/dist/plugins/linear/src/initiatives.js +5 -0
  109. package/dist/plugins/linear/src/issues.js +14 -0
  110. package/dist/plugins/linear/src/labels.js +5 -0
  111. package/dist/plugins/linear/src/organization.js +1 -0
  112. package/dist/plugins/linear/src/projects.js +11 -0
  113. package/dist/plugins/linear/src/shared.js +2 -0
  114. package/dist/plugins/linear/src/states.js +2 -0
  115. package/dist/plugins/linear/src/teams.js +3 -0
  116. package/dist/plugins/linear/src/users.js +2 -0
  117. package/dist/plugins/linear/src/views.js +4 -0
  118. package/dist/plugins/linear/src/webhooks.js +4 -0
  119. package/dist/plugins/lingvanex/src/index.js +1 -0
  120. package/dist/plugins/linkedin/src/index.js +1 -0
  121. package/dist/plugins/lonescale/src/index.js +4 -0
  122. package/dist/plugins/magento/src/index.js +15 -0
  123. package/dist/plugins/mailcheck/src/index.js +1 -0
  124. package/dist/plugins/mailchimp/src/index.js +14 -0
  125. package/dist/plugins/mailerlite/src/index.js +4 -0
  126. package/dist/plugins/mailgun/src/index.js +1 -0
  127. package/dist/plugins/mailjet/src/index.js +3 -0
  128. package/dist/plugins/mandrill/src/index.js +2 -0
  129. package/dist/plugins/marketstack/src/index.js +3 -0
  130. package/dist/plugins/matrix/src/index.js +10 -0
  131. package/dist/plugins/mattermost/src/index.js +19 -0
  132. package/dist/plugins/mautic/src/index.js +20 -0
  133. package/dist/plugins/medium/src/index.js +3 -0
  134. package/dist/plugins/messagebird/src/index.js +2 -0
  135. package/dist/plugins/metabase/src/index.js +10 -0
  136. package/dist/plugins/microsoftCalendar/src/index.js +2 -0
  137. package/dist/plugins/microsoftFiles/src/index.js +5 -0
  138. package/dist/plugins/microsoftMail/src/index.js +4 -0
  139. package/dist/plugins/misp/src/index.js +44 -0
  140. package/dist/plugins/mocean/src/index.js +2 -0
  141. package/dist/plugins/monday/src/index.js +18 -0
  142. package/dist/plugins/monicaCrm/src/index.js +5 -0
  143. package/dist/plugins/msg91/src/index.js +1 -0
  144. package/dist/plugins/nasa/src/index.js +7 -0
  145. package/dist/plugins/netlify/src/index.js +7 -0
  146. package/dist/plugins/netscalerAdc/src/index.js +3 -0
  147. package/dist/plugins/nextcloud/src/index.js +13 -0
  148. package/dist/plugins/nocodb/src/index.js +5 -0
  149. package/dist/plugins/node/src/index.js +38 -0
  150. package/dist/plugins/notion/src/index.js +14 -0
  151. package/dist/plugins/npm/src/index.js +5 -0
  152. package/dist/plugins/odoo/src/index.js +6 -0
  153. package/dist/plugins/okta/src/index.js +5 -0
  154. package/dist/plugins/oneSimpleApi/src/index.js +10 -0
  155. package/dist/plugins/onfleet/src/index.js +24 -0
  156. package/dist/plugins/openThesaurus/src/index.js +1 -0
  157. package/dist/plugins/openai/src/index.js +1 -0
  158. package/dist/plugins/openweathermap/src/index.js +2 -0
  159. package/dist/plugins/oura/src/index.js +2 -0
  160. package/dist/plugins/paddle/src/index.js +9 -0
  161. package/dist/plugins/pagerduty/src/index.js +9 -0
  162. package/dist/plugins/parallel/src/index.js +1 -0
  163. package/dist/plugins/paypal/src/index.js +4 -0
  164. package/dist/plugins/peekalink/src/index.js +2 -0
  165. package/dist/plugins/phantombuster/src/index.js +5 -0
  166. package/dist/plugins/philipsHue/src/index.js +4 -0
  167. package/dist/plugins/pipedrive/src/index.js +14 -0
  168. package/dist/plugins/plivo/src/index.js +3 -0
  169. package/dist/plugins/postbin/src/index.js +6 -0
  170. package/dist/plugins/posthog/src/index.js +5 -0
  171. package/dist/plugins/profitwell/src/index.js +2 -0
  172. package/dist/plugins/pushbullet/src/index.js +4 -0
  173. package/dist/plugins/pushcut/src/index.js +1 -0
  174. package/dist/plugins/pushover/src/index.js +1 -0
  175. package/dist/plugins/quickbase/src/index.js +8 -0
  176. package/dist/plugins/quickbooks/src/index.js +5 -0
  177. package/dist/plugins/quickchart/src/index.js +1 -0
  178. package/dist/plugins/raindrop/src/index.js +13 -0
  179. package/dist/plugins/recraft/src/index.js +1 -0
  180. package/dist/plugins/reddit/src/index.js +10 -0
  181. package/dist/plugins/replicate/src/index.js +1 -0
  182. package/dist/plugins/rocketchat/src/index.js +1 -0
  183. package/dist/plugins/rundeck/src/index.js +2 -0
  184. package/dist/plugins/salesforce/src/metadata.js +4 -0
  185. package/dist/plugins/salesforce/src/query.js +5 -0
  186. package/dist/plugins/salesforce/src/sobjects.js +12 -0
  187. package/dist/plugins/salesmate/src/index.js +5 -0
  188. package/dist/plugins/securityScorecard/src/index.js +14 -0
  189. package/dist/plugins/segment/src/index.js +4 -0
  190. package/dist/plugins/sendgrid/src/index.js +10 -0
  191. package/dist/plugins/sendy/src/index.js +6 -0
  192. package/dist/plugins/sentry/src/index.js +24 -0
  193. package/dist/plugins/servicenow/src/index.js +10 -0
  194. package/dist/plugins/shiftLabs/src/index.js +6 -0
  195. package/dist/plugins/shiftLabs/src/issues.js +4 -0
  196. package/dist/plugins/shiftLabs/src/pages.js +10 -0
  197. package/dist/plugins/shiftLabs/src/shared.js +2 -0
  198. package/dist/plugins/shiftLabs/src/transcription.js +203 -0
  199. package/dist/plugins/shopify/src/index.js +10 -0
  200. package/dist/plugins/signl4/src/index.js +2 -0
  201. package/dist/plugins/slack/src/index.js +38 -0
  202. package/dist/plugins/sms77/src/index.js +2 -0
  203. package/dist/plugins/splunk/src/index.js +16 -0
  204. package/dist/plugins/spotify/src/index.js +30 -0
  205. package/dist/plugins/stackby/src/index.js +4 -0
  206. package/dist/plugins/steel/src/browser.js +7 -0
  207. package/dist/plugins/steel/src/captchas.js +3 -0
  208. package/dist/plugins/steel/src/credentials.js +4 -0
  209. package/dist/plugins/steel/src/extensions.js +5 -0
  210. package/dist/plugins/steel/src/files.js +10 -0
  211. package/dist/plugins/steel/src/profiles.js +4 -0
  212. package/dist/plugins/steel/src/sessions.js +11 -0
  213. package/dist/plugins/storyblok/src/index.js +7 -0
  214. package/dist/plugins/strapi/src/index.js +5 -0
  215. package/dist/plugins/strava/src/index.js +6 -0
  216. package/dist/plugins/stripe/src/index.js +20 -0
  217. package/dist/plugins/supabase/src/index.js +5 -0
  218. package/dist/plugins/syncromsp/src/index.js +20 -0
  219. package/dist/plugins/tapfiliate/src/index.js +11 -0
  220. package/dist/plugins/telegram/src/index.js +21 -0
  221. package/dist/plugins/thehive/src/index.js +23 -0
  222. package/dist/plugins/thehiveProject/src/index.js +31 -0
  223. package/dist/plugins/todoist/src/index.js +31 -0
  224. package/dist/plugins/together/src/index.js +1 -0
  225. package/dist/plugins/travisci/src/index.js +5 -0
  226. package/dist/plugins/trello/src/index.js +37 -0
  227. package/dist/plugins/twake/src/index.js +1 -0
  228. package/dist/plugins/twilio/src/index.js +2 -0
  229. package/dist/plugins/twist/src/index.js +22 -0
  230. package/dist/plugins/twitter/src/index.js +8 -0
  231. package/dist/plugins/unleashedSoftware/src/index.js +3 -0
  232. package/dist/plugins/uplead/src/index.js +2 -0
  233. package/dist/plugins/uproc/src/index.js +1 -0
  234. package/dist/plugins/uptimerobot/src/index.js +22 -0
  235. package/dist/plugins/urlscanio/src/index.js +3 -0
  236. package/dist/plugins/vercel/src/account.js +1 -0
  237. package/dist/plugins/vercel/src/deployments.js +5 -0
  238. package/dist/plugins/vercel/src/env.js +4 -0
  239. package/dist/plugins/vercel/src/projects.js +2 -0
  240. package/dist/plugins/vercel/src/shared.js +1 -0
  241. package/dist/plugins/vero/src/index.js +6 -0
  242. package/dist/plugins/vonage/src/index.js +1 -0
  243. package/dist/plugins/wekan/src/index.js +24 -0
  244. package/dist/plugins/woocommerce/src/index.js +5 -0
  245. package/dist/plugins/wordpress/src/index.js +10 -0
  246. package/dist/plugins/xai/src/index.js +1 -0
  247. package/dist/plugins/xero/src/index.js +8 -0
  248. package/dist/plugins/yourls/src/index.js +3 -0
  249. package/dist/plugins/zammad/src/index.js +12 -0
  250. package/dist/plugins/zendesk/src/index.js +18 -0
  251. package/dist/plugins/zoho/src/index.js +6 -0
  252. package/dist/plugins/zoom/src/index.js +5 -0
  253. package/dist/plugins/zulip/src/index.js +15 -0
  254. package/dist/sdk.d.ts +2 -1
  255. package/dist/sdk.js +1 -0
  256. package/package.json +1 -1
@@ -22,7 +22,9 @@
22
22
  * the bare ID and normalize. The response always includes a
23
23
  * convenience `contactId` field stripped from `resourceName`.
24
24
  */
25
+ import * as t from "typebox";
25
26
  import { googleAccessToken } from "../../_shared/googleAuth.js";
27
+ import { Id, NonEmptyString, PositiveInteger, stringEnum, } from "../../_shared/googleSchemas.js";
26
28
  // ─── Fields ─────────────────────────────────────────────────────
27
29
  /**
28
30
  * Every `personFields` value supported by People API get/list calls.
@@ -279,6 +281,128 @@ function attachContactId(obj) {
279
281
  }
280
282
  // ─── Plugin ──────────────────────────────────────────────────────
281
283
  const SCOPES = ["https://www.googleapis.com/auth/contacts"];
284
+ const strictObject = (properties, options = {}) => t.Object(properties, { ...options, additionalProperties: false });
285
+ const optionalString = (description) => t.Optional(t.String(description ? { description } : {}));
286
+ const optionalBoolean = t.Optional(t.Boolean());
287
+ const personField = stringEnum([...ALL_PERSON_FIELDS, "*"]);
288
+ const personFields = t.Optional(t.Union([t.String(), t.Array(personField, { minItems: 1 })]));
289
+ const structuredDate = strictObject({
290
+ year: t.Optional(t.Integer({ minimum: 0 })),
291
+ month: t.Integer({ minimum: 1, maximum: 12 }),
292
+ day: t.Integer({ minimum: 1, maximum: 31 }),
293
+ });
294
+ const contactDate = t.Union([NonEmptyString, structuredDate]);
295
+ const typedValue = strictObject({
296
+ value: NonEmptyString,
297
+ type: optionalString(),
298
+ });
299
+ const relation = strictObject({
300
+ person: NonEmptyString,
301
+ type: optionalString(),
302
+ });
303
+ const contactEvent = strictObject({
304
+ date: contactDate,
305
+ type: optionalString(),
306
+ });
307
+ const userDefined = strictObject({ key: NonEmptyString, value: t.String() });
308
+ // These two People API resources are intentionally extensible. Known fields are
309
+ // typed, while additional provider fields remain available for forward
310
+ // compatibility and parity with the plugin's existing passthrough behavior.
311
+ const address = t.Object({
312
+ formattedValue: optionalString(),
313
+ type: optionalString(),
314
+ poBox: optionalString(),
315
+ streetAddress: optionalString(),
316
+ extendedAddress: optionalString(),
317
+ city: optionalString(),
318
+ region: optionalString(),
319
+ postalCode: optionalString(),
320
+ country: optionalString(),
321
+ countryCode: optionalString(),
322
+ }, { additionalProperties: true });
323
+ const organization = t.Object({
324
+ name: optionalString(),
325
+ title: optionalString(),
326
+ department: optionalString(),
327
+ type: optionalString(),
328
+ symbol: optionalString(),
329
+ domain: optionalString(),
330
+ location: optionalString(),
331
+ jobDescription: optionalString(),
332
+ phoneticName: optionalString(),
333
+ costCenter: optionalString(),
334
+ fullTimeEquivalentMillipercent: t.Optional(t.Integer({ minimum: 0, maximum: 100_000 })),
335
+ startDate: t.Optional(structuredDate),
336
+ endDate: t.Optional(structuredDate),
337
+ current: optionalBoolean,
338
+ }, { additionalProperties: true });
339
+ const clientData = strictObject({ key: NonEmptyString, value: t.String() });
340
+ const contactWritableFields = {
341
+ givenName: optionalString(),
342
+ familyName: optionalString(),
343
+ middleName: optionalString(),
344
+ honorificPrefix: optionalString(),
345
+ honorificSuffix: optionalString(),
346
+ phoneNumbers: t.Optional(t.Array(typedValue)),
347
+ emailAddresses: t.Optional(t.Array(typedValue)),
348
+ addresses: t.Optional(t.Array(address)),
349
+ organizations: t.Optional(t.Array(organization)),
350
+ relations: t.Optional(t.Array(relation)),
351
+ urls: t.Optional(t.Array(typedValue)),
352
+ events: t.Optional(t.Array(contactEvent)),
353
+ birthday: t.Optional(contactDate),
354
+ biography: optionalString(),
355
+ userDefined: t.Optional(t.Array(userDefined)),
356
+ groups: t.Optional(t.Array(NonEmptyString)),
357
+ };
358
+ const writableContactKeys = Object.keys(contactWritableFields);
359
+ const contactSchemas = {
360
+ create: strictObject(contactWritableFields),
361
+ get: strictObject({ contactId: Id, fields: personFields }),
362
+ list: strictObject({
363
+ query: optionalString(),
364
+ fields: personFields,
365
+ sortOrder: t.Optional(stringEnum([
366
+ "LAST_MODIFIED_ASCENDING",
367
+ "LAST_MODIFIED_DESCENDING",
368
+ "FIRST_NAME_ASCENDING",
369
+ "LAST_NAME_ASCENDING",
370
+ ])),
371
+ returnAll: optionalBoolean,
372
+ maxResults: t.Optional(PositiveInteger),
373
+ pageToken: optionalString(),
374
+ }),
375
+ update: strictObject({
376
+ contactId: Id,
377
+ etag: optionalString(),
378
+ fields: personFields,
379
+ ...contactWritableFields,
380
+ }, { anyOf: writableContactKeys.map((key) => ({ required: [key] })) }),
381
+ delete: strictObject({ contactId: Id }),
382
+ };
383
+ const groupSchemas = {
384
+ list: strictObject({
385
+ returnAll: optionalBoolean,
386
+ maxResults: t.Optional(PositiveInteger),
387
+ pageToken: optionalString(),
388
+ syncToken: optionalString(),
389
+ }),
390
+ get: strictObject({
391
+ groupId: Id,
392
+ maxMembers: t.Optional(t.Integer({ minimum: 0 })),
393
+ }),
394
+ create: strictObject({
395
+ name: NonEmptyString,
396
+ clientData: t.Optional(t.Array(clientData)),
397
+ }),
398
+ update: strictObject({
399
+ groupId: Id,
400
+ name: optionalString(),
401
+ clientData: t.Optional(t.Array(clientData)),
402
+ etag: optionalString(),
403
+ }, { anyOf: [{ required: ["name"] }, { required: ["clientData"] }] }),
404
+ delete: strictObject({ groupId: Id, deleteContacts: optionalBoolean }),
405
+ };
282
406
  export default function googleContacts(rl) {
283
407
  rl.setName("googleContacts");
284
408
  rl.setVersion("0.1.0");
@@ -326,61 +450,9 @@ export default function googleContacts(rl) {
326
450
  });
327
451
  // ── Contact ───────────────────────────────────────────
328
452
  rl.registerAction("contact.create", {
453
+ access: "write",
329
454
  description: "Create a new contact",
330
- inputSchema: {
331
- givenName: { type: "string", required: false },
332
- familyName: { type: "string", required: false },
333
- middleName: { type: "string", required: false },
334
- honorificPrefix: { type: "string", required: false },
335
- honorificSuffix: { type: "string", required: false },
336
- phoneNumbers: {
337
- type: "array",
338
- required: false,
339
- description: "[{value, type?}]",
340
- },
341
- emailAddresses: {
342
- type: "array",
343
- required: false,
344
- description: "[{value, type?}]",
345
- },
346
- addresses: {
347
- type: "array",
348
- required: false,
349
- description: "[{formattedValue?, streetAddress?, city?, region?, postalCode?, country?, type?}]",
350
- },
351
- organizations: {
352
- type: "array",
353
- required: false,
354
- description: "[{name, title?, department?, type?}]",
355
- },
356
- relations: {
357
- type: "array",
358
- required: false,
359
- description: "[{person, type?}]",
360
- },
361
- urls: { type: "array", required: false },
362
- events: {
363
- type: "array",
364
- required: false,
365
- description: "[{date, type?}] — date can be ISO string or {year, month, day}",
366
- },
367
- birthday: {
368
- type: "string",
369
- required: false,
370
- description: "ISO date string or {year, month, day}",
371
- },
372
- biography: { type: "string", required: false },
373
- userDefined: {
374
- type: "array",
375
- required: false,
376
- description: "[{key, value}] — custom key/value pairs",
377
- },
378
- groups: {
379
- type: "array",
380
- required: false,
381
- description: "Group IDs or full contactGroups/… resource names",
382
- },
383
- },
455
+ inputSchema: contactSchemas.create,
384
456
  async execute(input, ctx) {
385
457
  const p = (input ?? {});
386
458
  const { body } = buildPersonBody(p);
@@ -389,19 +461,9 @@ export default function googleContacts(rl) {
389
461
  },
390
462
  });
391
463
  rl.registerAction("contact.get", {
464
+ access: "read",
392
465
  description: "Get a contact by ID",
393
- inputSchema: {
394
- contactId: {
395
- type: "string",
396
- required: true,
397
- description: "Bare ID or full people/… resource name",
398
- },
399
- fields: {
400
- type: "string",
401
- required: false,
402
- description: "'*' (all), comma-separated string, or array of People-API field names (default: names, emailAddresses, phoneNumbers)",
403
- },
404
- },
466
+ inputSchema: contactSchemas.get,
405
467
  async execute(input, ctx) {
406
468
  const p = (input ?? {});
407
469
  const resource = normalizeContactResource(p.contactId);
@@ -410,23 +472,9 @@ export default function googleContacts(rl) {
410
472
  },
411
473
  });
412
474
  rl.registerAction("contact.list", {
475
+ access: "read",
413
476
  description: "List contacts (people/me/connections) or search them. When `query` is set, hits people:searchContacts; otherwise returns the user's connections.",
414
- inputSchema: {
415
- query: {
416
- type: "string",
417
- required: false,
418
- description: "If set, uses people:searchContacts instead of connections.list",
419
- },
420
- fields: { type: "string", required: false },
421
- sortOrder: {
422
- type: "string",
423
- required: false,
424
- description: "LAST_MODIFIED_ASCENDING | LAST_MODIFIED_DESCENDING | FIRST_NAME_ASCENDING | LAST_NAME_ASCENDING (connections.list only)",
425
- },
426
- returnAll: { type: "boolean", required: false },
427
- maxResults: { type: "number", required: false },
428
- pageToken: { type: "string", required: false },
429
- },
477
+ inputSchema: contactSchemas.list,
430
478
  async execute(input, ctx) {
431
479
  const p = (input ?? {});
432
480
  const useSearch = typeof p.query === "string" && p.query.length > 0;
@@ -479,37 +527,9 @@ export default function googleContacts(rl) {
479
527
  },
480
528
  });
481
529
  rl.registerAction("contact.update", {
530
+ access: "write",
482
531
  description: "Update a contact. Only supplied fields are sent; etag is resolved automatically if not provided.",
483
- inputSchema: {
484
- contactId: { type: "string", required: true },
485
- etag: {
486
- type: "string",
487
- required: false,
488
- description: "Optimistic-concurrency tag. If omitted, the plugin fetches the latest etag first.",
489
- },
490
- fields: {
491
- type: "string",
492
- required: false,
493
- description: "personFields projection on the response (same semantics as contact.get)",
494
- },
495
- // Writable fields
496
- givenName: { type: "string", required: false },
497
- familyName: { type: "string", required: false },
498
- middleName: { type: "string", required: false },
499
- honorificPrefix: { type: "string", required: false },
500
- honorificSuffix: { type: "string", required: false },
501
- phoneNumbers: { type: "array", required: false },
502
- emailAddresses: { type: "array", required: false },
503
- addresses: { type: "array", required: false },
504
- organizations: { type: "array", required: false },
505
- relations: { type: "array", required: false },
506
- urls: { type: "array", required: false },
507
- events: { type: "array", required: false },
508
- birthday: { type: "string", required: false },
509
- biography: { type: "string", required: false },
510
- userDefined: { type: "array", required: false },
511
- groups: { type: "array", required: false },
512
- },
532
+ inputSchema: contactSchemas.update,
513
533
  async execute(input, ctx) {
514
534
  const p = (input ?? {});
515
535
  const resource = normalizeContactResource(p.contactId);
@@ -533,8 +553,9 @@ export default function googleContacts(rl) {
533
553
  },
534
554
  });
535
555
  rl.registerAction("contact.delete", {
556
+ access: "write",
536
557
  description: "Delete a contact",
537
- inputSchema: { contactId: { type: "string", required: true } },
558
+ inputSchema: contactSchemas.delete,
538
559
  async execute(input, ctx) {
539
560
  const p = (input ?? {});
540
561
  const resource = normalizeContactResource(p.contactId);
@@ -544,13 +565,9 @@ export default function googleContacts(rl) {
544
565
  });
545
566
  // ── Contact groups ────────────────────────────────────
546
567
  rl.registerAction("group.list", {
568
+ access: "read",
547
569
  description: "List contact groups (including system groups like 'myContacts' and 'starred')",
548
- inputSchema: {
549
- returnAll: { type: "boolean", required: false },
550
- maxResults: { type: "number", required: false },
551
- pageToken: { type: "string", required: false },
552
- syncToken: { type: "string", required: false },
553
- },
570
+ inputSchema: groupSchemas.list,
554
571
  async execute(input, ctx) {
555
572
  const p = (input ?? {});
556
573
  const qs = {};
@@ -567,15 +584,9 @@ export default function googleContacts(rl) {
567
584
  },
568
585
  });
569
586
  rl.registerAction("group.get", {
587
+ access: "read",
570
588
  description: "Get a contact group by ID",
571
- inputSchema: {
572
- groupId: { type: "string", required: true },
573
- maxMembers: {
574
- type: "number",
575
- required: false,
576
- description: "Include up to N member resourceNames in the response",
577
- },
578
- },
589
+ inputSchema: groupSchemas.get,
579
590
  async execute(input, ctx) {
580
591
  const p = (input ?? {});
581
592
  const resource = normalizeGroupResource(p.groupId);
@@ -586,15 +597,9 @@ export default function googleContacts(rl) {
586
597
  },
587
598
  });
588
599
  rl.registerAction("group.create", {
600
+ access: "write",
589
601
  description: "Create a contact group",
590
- inputSchema: {
591
- name: { type: "string", required: true },
592
- clientData: {
593
- type: "array",
594
- required: false,
595
- description: "[{key, value}] — app-private metadata",
596
- },
597
- },
602
+ inputSchema: groupSchemas.create,
598
603
  async execute(input, ctx) {
599
604
  const p = (input ?? {});
600
605
  const body = {
@@ -607,13 +612,9 @@ export default function googleContacts(rl) {
607
612
  },
608
613
  });
609
614
  rl.registerAction("group.update", {
615
+ access: "write",
610
616
  description: "Update a contact group. Pass a fresh `etag` or let the plugin resolve it automatically.",
611
- inputSchema: {
612
- groupId: { type: "string", required: true },
613
- name: { type: "string", required: false },
614
- clientData: { type: "array", required: false },
615
- etag: { type: "string", required: false },
616
- },
617
+ inputSchema: groupSchemas.update,
617
618
  async execute(input, ctx) {
618
619
  const p = (input ?? {});
619
620
  const resource = normalizeGroupResource(p.groupId);
@@ -642,11 +643,9 @@ export default function googleContacts(rl) {
642
643
  },
643
644
  });
644
645
  rl.registerAction("group.delete", {
646
+ access: "write",
645
647
  description: "Delete a contact group. Pass `deleteContacts=true` to also delete every contact in the group.",
646
- inputSchema: {
647
- groupId: { type: "string", required: true },
648
- deleteContacts: { type: "boolean", required: false },
649
- },
648
+ inputSchema: groupSchemas.delete,
650
649
  async execute(input, ctx) {
651
650
  const p = (input ?? {});
652
651
  const resource = normalizeGroupResource(p.groupId);
@@ -1,15 +1,16 @@
1
- import { DRIVE_BASE, docsRequest, extractDocumentId, flattenBodyText, } from "./shared.js";
1
+ import * as t from "typebox";
2
+ import { DocumentInput, DRIVE_BASE, docsRequest, extractDocumentId, flattenBodyText, RawGoogleObject, STRICT_OBJECT, WriteControl, } from "./shared.js";
2
3
  export function registerDocumentsActions(rl) {
3
4
  rl.registerAction("document.create", {
5
+ access: "write",
4
6
  description: "Create a new Google Doc, optionally in a specific Drive folder (goes through the Drive API; needs drive.file scope).",
5
- inputSchema: {
6
- title: { type: "string", required: true },
7
- folderId: {
8
- type: "string",
9
- required: false,
7
+ inputSchema: t.Object({
8
+ title: t.String({ minLength: 1 }),
9
+ folderId: t.Optional(t.String({
10
+ minLength: 1,
10
11
  description: "Parent folder in Drive. Omit to place in My Drive root.",
11
- },
12
- },
12
+ })),
13
+ }, STRICT_OBJECT),
13
14
  async execute(input, ctx) {
14
15
  const p = (input ?? {});
15
16
  const body = {
@@ -23,35 +24,30 @@ export function registerDocumentsActions(rl) {
23
24
  },
24
25
  });
25
26
  rl.registerAction("document.createBlank", {
27
+ access: "write",
26
28
  description: "Create a blank Google Doc through the native Docs API. Use document.create when you need Drive folder placement.",
27
- inputSchema: {
28
- title: { type: "string", required: true },
29
- },
29
+ inputSchema: t.Object({ title: t.String({ minLength: 1 }) }, STRICT_OBJECT),
30
30
  async execute(input, ctx) {
31
31
  const p = (input ?? {});
32
32
  return docsRequest(ctx, "POST", "/documents", { title: p.title });
33
33
  },
34
34
  });
35
35
  rl.registerAction("document.get", {
36
+ access: "read",
36
37
  description: "Get a document. Accepts a bare ID or a docs.google.com URL. `simple=true` collapses the body to plain text.",
37
- inputSchema: {
38
- document: {
39
- type: "string",
40
- required: true,
41
- description: "Document ID or URL",
42
- },
43
- simple: { type: "boolean", required: false },
44
- suggestionsViewMode: {
45
- type: "string",
46
- required: false,
47
- description: "DEFAULT_FOR_CURRENT_ACCESS | SUGGESTIONS_INLINE | PREVIEW_SUGGESTIONS_ACCEPTED | PREVIEW_WITHOUT_SUGGESTIONS",
48
- },
49
- includeTabsContent: {
50
- type: "boolean",
51
- required: false,
52
- description: "Return content for all tabs in document.tabs instead of only first-tab legacy fields.",
53
- },
54
- },
38
+ inputSchema: t.Object({
39
+ ...DocumentInput,
40
+ simple: t.Optional(t.Boolean()),
41
+ suggestionsViewMode: t.Optional(t.Union([
42
+ t.Literal("DEFAULT_FOR_CURRENT_ACCESS"),
43
+ t.Literal("SUGGESTIONS_INLINE"),
44
+ t.Literal("PREVIEW_SUGGESTIONS_ACCEPTED"),
45
+ t.Literal("PREVIEW_WITHOUT_SUGGESTIONS"),
46
+ ])),
47
+ includeTabsContent: t.Optional(t.Boolean({
48
+ description: "Return content for all tabs instead of only first-tab legacy fields.",
49
+ })),
50
+ }, STRICT_OBJECT),
55
51
  async execute(input, ctx) {
56
52
  const p = (input ?? {});
57
53
  const documentId = extractDocumentId(p.document);
@@ -67,16 +63,13 @@ export function registerDocumentsActions(rl) {
67
63
  },
68
64
  });
69
65
  rl.registerAction("document.batchUpdate", {
66
+ access: "write",
70
67
  description: "Raw passthrough to documents.batchUpdate — pass a full `requests` array for atomic multi-edit operations.",
71
- inputSchema: {
72
- document: { type: "string", required: true },
73
- requests: { type: "array", required: true },
74
- writeControl: {
75
- type: "object",
76
- required: false,
77
- description: "{requiredRevisionId} | {targetRevisionId}",
78
- },
79
- },
68
+ inputSchema: t.Object({
69
+ ...DocumentInput,
70
+ requests: t.Array(RawGoogleObject, { minItems: 1 }),
71
+ writeControl: t.Optional(WriteControl),
72
+ }, STRICT_OBJECT),
80
73
  async execute(input, ctx) {
81
74
  const p = (input ?? {});
82
75
  const documentId = extractDocumentId(p.document);
@@ -1,39 +1,50 @@
1
- import { compact, extractDocumentId, runBatchUpdate } from "./shared.js";
1
+ import * as t from "typebox";
2
+ import { compact, DocumentInput, extractDocumentId, PositivePoints, RangeInput, RawGoogleObject, runBatchUpdate, STRICT_OBJECT, } from "./shared.js";
2
3
  export function registerFormattingActions(rl) {
3
4
  rl.registerAction("document.updateParagraphStyle", {
5
+ access: "write",
4
6
  description: "Apply paragraph styling (alignment, named style, indents, spacing, direction) to the paragraphs intersecting the range.",
5
- inputSchema: {
6
- document: { type: "string", required: true },
7
- startIndex: { type: "number", required: true },
8
- endIndex: { type: "number", required: true },
9
- alignment: {
10
- type: "string",
11
- required: false,
12
- description: "START | CENTER | END | JUSTIFIED",
13
- },
14
- namedStyleType: {
15
- type: "string",
16
- required: false,
17
- description: "NORMAL_TEXT | TITLE | SUBTITLE | HEADING_1 .. HEADING_6",
18
- },
19
- direction: {
20
- type: "string",
21
- required: false,
22
- description: "LEFT_TO_RIGHT | RIGHT_TO_LEFT",
23
- },
24
- indentFirstLinePt: { type: "number", required: false },
25
- indentStartPt: { type: "number", required: false },
26
- indentEndPt: { type: "number", required: false },
27
- spaceAbovePt: { type: "number", required: false },
28
- spaceBelowPt: { type: "number", required: false },
29
- lineSpacing: {
30
- type: "number",
31
- required: false,
32
- description: "Percentage; 100 = single, 150 = 1.5x.",
33
- },
34
- segmentId: { type: "string", required: false },
35
- tabId: { type: "string", required: false },
36
- },
7
+ inputSchema: t.Object({
8
+ ...DocumentInput,
9
+ ...RangeInput,
10
+ alignment: t.Optional(t.Union([
11
+ t.Literal("START"),
12
+ t.Literal("CENTER"),
13
+ t.Literal("END"),
14
+ t.Literal("JUSTIFIED"),
15
+ ])),
16
+ namedStyleType: t.Optional(t.Union([
17
+ t.Literal("NORMAL_TEXT"),
18
+ t.Literal("TITLE"),
19
+ t.Literal("SUBTITLE"),
20
+ t.Literal("HEADING_1"),
21
+ t.Literal("HEADING_2"),
22
+ t.Literal("HEADING_3"),
23
+ t.Literal("HEADING_4"),
24
+ t.Literal("HEADING_5"),
25
+ t.Literal("HEADING_6"),
26
+ ])),
27
+ direction: t.Optional(t.Union([t.Literal("LEFT_TO_RIGHT"), t.Literal("RIGHT_TO_LEFT")])),
28
+ indentFirstLinePt: t.Optional(PositivePoints),
29
+ indentStartPt: t.Optional(PositivePoints),
30
+ indentEndPt: t.Optional(PositivePoints),
31
+ spaceAbovePt: t.Optional(PositivePoints),
32
+ spaceBelowPt: t.Optional(PositivePoints),
33
+ lineSpacing: t.Optional(t.Number({ minimum: 0 })),
34
+ }, {
35
+ ...STRICT_OBJECT,
36
+ anyOf: [
37
+ { required: ["alignment"] },
38
+ { required: ["namedStyleType"] },
39
+ { required: ["direction"] },
40
+ { required: ["indentFirstLinePt"] },
41
+ { required: ["indentStartPt"] },
42
+ { required: ["indentEndPt"] },
43
+ { required: ["spaceAbovePt"] },
44
+ { required: ["spaceBelowPt"] },
45
+ { required: ["lineSpacing"] },
46
+ ],
47
+ }),
37
48
  async execute(input, ctx) {
38
49
  const p = (input ?? {});
39
50
  const documentId = extractDocumentId(p.document);
@@ -96,21 +107,14 @@ export function registerFormattingActions(rl) {
96
107
  },
97
108
  });
98
109
  rl.registerAction("document.updateNamedStyle", {
110
+ access: "write",
99
111
  description: "Update a named style such as NORMAL_TEXT, TITLE, or HEADING_1 using a Docs API NamedStyle object.",
100
- inputSchema: {
101
- document: { type: "string", required: true },
102
- namedStyle: {
103
- type: "object",
104
- required: true,
105
- description: "Docs API NamedStyle object. Must include namedStyleType.",
106
- },
107
- fields: {
108
- type: "string",
109
- required: true,
110
- description: "Field mask such as textStyle.bold or paragraphStyle.alignment.",
111
- },
112
- tabId: { type: "string", required: false },
113
- },
112
+ inputSchema: t.Object({
113
+ ...DocumentInput,
114
+ namedStyle: RawGoogleObject,
115
+ fields: t.String({ minLength: 1 }),
116
+ tabId: t.Optional(t.String({ minLength: 1 })),
117
+ }, STRICT_OBJECT),
114
118
  async execute(input, ctx) {
115
119
  const p = (input ?? {});
116
120
  const documentId = extractDocumentId(p.document);
@@ -1,21 +1,21 @@
1
- import { buildLocation, extractDocumentId, runBatchUpdate } from "./shared.js";
1
+ import * as t from "typebox";
2
+ import { buildLocation, DocumentInput, extractDocumentId, LOCATION_REQUIREMENT, LocationInput, PositivePoints, runBatchUpdate, STRICT_OBJECT, } from "./shared.js";
3
+ const PublicImageUri = t.String({
4
+ minLength: 1,
5
+ pattern: "^https?://",
6
+ description: "Publicly fetchable HTTP(S) image URI",
7
+ });
2
8
  export function registerImagesActions(rl) {
3
9
  rl.registerAction("document.insertInlineImage", {
10
+ access: "write",
4
11
  description: "Insert an inline image at the given location. `uri` must point to a publicly fetchable image.",
5
- inputSchema: {
6
- document: { type: "string", required: true },
7
- locationKind: {
8
- type: "string",
9
- required: false,
10
- description: "location (default; requires index) | endOfSegmentLocation",
11
- },
12
- index: { type: "number", required: false },
13
- uri: { type: "string", required: true },
14
- widthPt: { type: "number", required: false },
15
- heightPt: { type: "number", required: false },
16
- segmentId: { type: "string", required: false },
17
- tabId: { type: "string", required: false },
18
- },
12
+ inputSchema: t.Object({
13
+ ...DocumentInput,
14
+ ...LocationInput,
15
+ uri: PublicImageUri,
16
+ widthPt: t.Optional(PositivePoints),
17
+ heightPt: t.Optional(PositivePoints),
18
+ }, { ...STRICT_OBJECT, anyOf: LOCATION_REQUIREMENT }),
19
19
  async execute(input, ctx) {
20
20
  const p = (input ?? {});
21
21
  const documentId = extractDocumentId(p.document);
@@ -36,18 +36,15 @@ export function registerImagesActions(rl) {
36
36
  },
37
37
  });
38
38
  rl.registerAction("document.replaceImage", {
39
+ access: "write",
39
40
  description: "Replace an existing image (identified by its inline-object id) with a new image from a publicly fetchable URI.",
40
- inputSchema: {
41
- document: { type: "string", required: true },
42
- imageObjectId: { type: "string", required: true },
43
- uri: { type: "string", required: true },
44
- imageReplaceMethod: {
45
- type: "string",
46
- required: false,
47
- description: "CENTER_CROP (default) | (others as Docs API adds them)",
48
- },
49
- tabId: { type: "string", required: false },
50
- },
41
+ inputSchema: t.Object({
42
+ ...DocumentInput,
43
+ imageObjectId: t.String({ minLength: 1 }),
44
+ uri: PublicImageUri,
45
+ imageReplaceMethod: t.Optional(t.Literal("CENTER_CROP")),
46
+ tabId: t.Optional(t.String({ minLength: 1 })),
47
+ }, STRICT_OBJECT),
51
48
  async execute(input, ctx) {
52
49
  const p = (input ?? {});
53
50
  const documentId = extractDocumentId(p.document);