@zackbart/connecta 0.34.1 → 0.36.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 (441) hide show
  1. package/CHANGELOG.md +418 -0
  2. package/README.md +65 -105
  3. package/SECURITY.md +3 -2
  4. package/bin/connecta.mjs +41 -16
  5. package/bin/version.mjs +1 -1
  6. package/dist/access-tokens.d.ts +2 -1
  7. package/dist/access-tokens.js +66 -30
  8. package/dist/activity.d.ts +1 -1
  9. package/dist/activity.js +2 -0
  10. package/dist/agent-config.d.ts +23 -0
  11. package/dist/agent-config.js +59 -0
  12. package/dist/agent-description.js +16 -0
  13. package/dist/agent-identity.js +4 -4
  14. package/dist/agent-observation.js +39 -0
  15. package/dist/auth/clerk-sdk/client.d.ts +2 -0
  16. package/dist/auth/clerk-sdk/generated.js +554 -563
  17. package/dist/auth/clerk-transport.js +70 -3
  18. package/dist/auth/clerk.d.ts +13 -0
  19. package/dist/auth/clerk.js +653 -246
  20. package/dist/auth/cloudflare-access.js +46 -42
  21. package/dist/auth/downstream-client-metadata.js +2 -2
  22. package/dist/auth/downstream-oauth.js +2044 -1161
  23. package/dist/auth/downstream-revocation.js +88 -88
  24. package/dist/auth/native-call.js +20 -0
  25. package/dist/auth/native.js +184 -0
  26. package/dist/auth/oauth-start-reset.js +11 -5
  27. package/dist/auth/oauth-token-response.js +121 -102
  28. package/dist/auth/oauth-v2-migration.js +97 -78
  29. package/dist/auth/renewable-grant.js +10 -0
  30. package/dist/auth/static-oauth.js +751 -281
  31. package/dist/auth/vercel-agent.js +266 -0
  32. package/dist/auth-admission.js +204 -0
  33. package/dist/auth-elicitation.js +350 -241
  34. package/dist/authorization-handoff.js +164 -90
  35. package/dist/call-admission-context.js +3 -10
  36. package/dist/call-admission.js +2 -0
  37. package/dist/call-classification.js +9 -0
  38. package/dist/call-recovery.js +32 -13
  39. package/dist/canonical-json.js +8 -0
  40. package/dist/catalog-cache.js +369 -213
  41. package/dist/catalog-service.js +659 -530
  42. package/dist/catalog.js +5 -1
  43. package/dist/concurrency.js +0 -25
  44. package/dist/config-defaults.d.ts +1 -0
  45. package/dist/config-defaults.js +1 -0
  46. package/dist/config-schema.d.ts +3 -1
  47. package/dist/config-schema.js +13 -3
  48. package/dist/config.d.ts +40 -6
  49. package/dist/config.js +40 -26
  50. package/dist/connector-caller.d.ts +4 -0
  51. package/dist/connector-caller.js +17 -4
  52. package/dist/connectors/api-connector.d.ts +29 -7
  53. package/dist/connectors/api-connector.js +145 -57
  54. package/dist/connectors/guarded-fetch.d.ts +51 -17
  55. package/dist/connectors/guarded-fetch.js +215 -121
  56. package/dist/connectors/negotiation-cache.js +20 -10
  57. package/dist/connectors/remote-mcp.d.ts +10 -30
  58. package/dist/connectors/remote-mcp.js +955 -563
  59. package/dist/d1.js +10 -243
  60. package/dist/derived-context.js +5 -0
  61. package/dist/describe-config.d.ts +3 -1
  62. package/dist/describe-config.js +2 -0
  63. package/dist/downstream-input.js +347 -260
  64. package/dist/errors.d.ts +87 -6
  65. package/dist/errors.js +114 -4
  66. package/dist/execute.js +87 -50
  67. package/dist/executor-admission.js +3 -0
  68. package/dist/executors/quickjs.js +163 -112
  69. package/dist/guarded-transport.js +50 -0
  70. package/dist/guest-runtime.js +1 -1
  71. package/dist/http/client.js +439 -0
  72. package/dist/http/errors.js +558 -0
  73. package/dist/http/fields.js +49 -0
  74. package/dist/http/hatch-paging.js +318 -0
  75. package/dist/http/hatch.js +1279 -0
  76. package/dist/http/json-schema.js +267 -0
  77. package/dist/http/node-transport.js +241 -0
  78. package/dist/http/oauth.js +162 -0
  79. package/dist/http/paging.js +227 -0
  80. package/dist/http/provider.js +221 -0
  81. package/dist/http/safety.js +82 -0
  82. package/dist/http/services.js +79 -0
  83. package/dist/http/tools.js +379 -0
  84. package/dist/http/vendor-index.js +138 -0
  85. package/dist/http/vendor.js +448 -0
  86. package/dist/http/write-request.js +66 -0
  87. package/dist/http-policy.d.ts +11 -0
  88. package/dist/http-policy.js +45 -0
  89. package/dist/inbound-credential.js +1 -1
  90. package/dist/index.d.ts +2 -2
  91. package/dist/index.js +4 -0
  92. package/dist/invocation-auth.js +30 -19
  93. package/dist/invocation.js +218 -85
  94. package/dist/mcp-result.js +0 -4
  95. package/dist/membership.d.ts +4 -0
  96. package/dist/meta-output.js +1 -1
  97. package/dist/meta-tools.js +531 -406
  98. package/dist/native-recovery.js +52 -0
  99. package/dist/native-tools.js +382 -0
  100. package/dist/node.d.ts +4 -3
  101. package/dist/node.js +45 -8
  102. package/dist/oauth-handoff.js +177 -104
  103. package/dist/oauth-partition.js +6 -20
  104. package/dist/oauth-sealing.js +6 -7
  105. package/dist/operation-vocabulary.js +101 -0
  106. package/dist/operator-record.d.ts +2 -2
  107. package/dist/operator-record.js +17 -4
  108. package/dist/operator-ui/contract.d.ts +8 -3
  109. package/dist/operator-ui/generated.js +4 -4
  110. package/dist/operator-ui/model.d.ts +2 -3
  111. package/dist/program-writes.js +47 -26
  112. package/dist/provider-call-facts.d.ts +115 -0
  113. package/dist/provider-call-facts.js +182 -0
  114. package/dist/provider-call.d.ts +112 -0
  115. package/dist/provider-call.js +271 -0
  116. package/dist/provider.d.ts +65 -31
  117. package/dist/provider.js +116 -39
  118. package/dist/providers/_shared/google/hatch.js +91 -0
  119. package/dist/providers/_shared/google/kit.js +427 -0
  120. package/dist/providers/_shared/google/result-size.js +15 -2
  121. package/dist/providers/_shared/google/service-account.d.ts +2 -1
  122. package/dist/providers/_shared/google/service-account.js +8 -4
  123. package/dist/providers/_shared/google/workspace.d.ts +6 -210
  124. package/dist/providers/_shared/google/workspace.js +6 -425
  125. package/dist/providers/_shared/rest/compact-index.js +86 -0
  126. package/dist/providers/_shared/rest/kit.js +146 -0
  127. package/dist/providers/_shared/rest/operation-index.js +230 -14
  128. package/dist/providers/_shared/rest/response-media.js +11 -0
  129. package/dist/providers/_shared/rest/value-safety.js +353 -195
  130. package/dist/providers/_shared/sensitive-fields.js +27 -0
  131. package/dist/providers/breeze/api.js +584 -0
  132. package/dist/providers/breeze/index.d.ts +1 -3
  133. package/dist/providers/breeze/index.js +67 -1420
  134. package/dist/providers/breeze/openapi.generated.js +60 -0
  135. package/dist/providers/breeze/skill.generated.js +2 -6
  136. package/dist/providers/breeze/tools.js +696 -0
  137. package/dist/providers/ccb/api.js +496 -0
  138. package/dist/providers/ccb/index.d.ts +15 -37
  139. package/dist/providers/ccb/index.js +77 -1702
  140. package/dist/providers/ccb/lib/constants.d.ts +34 -0
  141. package/dist/providers/ccb/lib/constants.js +74 -0
  142. package/dist/providers/ccb/lib/guide.js +9 -0
  143. package/dist/providers/ccb/lib/verdicts.js +387 -0
  144. package/dist/providers/ccb/openapi.generated.js +397 -0
  145. package/dist/providers/ccb/safety.js +295 -0
  146. package/dist/providers/ccb/skill.generated.js +2 -6
  147. package/dist/providers/ccb/tools.js +853 -0
  148. package/dist/providers/cloudflare/api.js +1066 -0
  149. package/dist/providers/cloudflare/index.d.ts +5 -22
  150. package/dist/providers/cloudflare/index.js +79 -197
  151. package/dist/providers/cloudflare/lib/config.d.ts +16 -0
  152. package/dist/providers/cloudflare/lib/config.js +2 -0
  153. package/dist/providers/cloudflare/lib/discovery.js +29 -0
  154. package/dist/providers/cloudflare/{graphql.js → lib/graphql.js} +1 -1
  155. package/dist/providers/cloudflare/lib/hatch.js +103 -0
  156. package/dist/providers/cloudflare/lib/path-bounds.js +28 -0
  157. package/dist/providers/cloudflare/lib/response-media.js +75 -0
  158. package/dist/providers/cloudflare/openapi.generated.js +4 -3
  159. package/dist/providers/cloudflare/{value-safety.js → safety.js} +487 -0
  160. package/dist/providers/cloudflare/skill.generated.js +2 -10
  161. package/dist/providers/cloudflare/tools.js +360 -0
  162. package/dist/providers/docs/api.js +51 -0
  163. package/dist/providers/docs/index.d.ts +1 -12
  164. package/dist/providers/docs/index.js +53 -1165
  165. package/dist/providers/docs/lib/constants.d.ts +18 -0
  166. package/dist/providers/docs/lib/constants.js +18 -0
  167. package/dist/providers/docs/lib/discovery.js +26 -0
  168. package/dist/providers/docs/lib/requests.js +48 -0
  169. package/dist/providers/docs/lib/schemas.js +168 -0
  170. package/dist/providers/docs/openapi.generated.js +16 -0
  171. package/dist/providers/docs/safety.js +54 -0
  172. package/dist/providers/docs/skill.generated.js +2 -6
  173. package/dist/providers/docs/tools.js +801 -0
  174. package/dist/providers/drive/api.js +177 -0
  175. package/dist/providers/drive/index.d.ts +1 -12
  176. package/dist/providers/drive/index.js +38 -1448
  177. package/dist/providers/drive/lib/constants.d.ts +6 -0
  178. package/dist/providers/drive/lib/constants.js +6 -0
  179. package/dist/providers/drive/lib/contracts.js +532 -0
  180. package/dist/providers/drive/lib/hatch.js +197 -0
  181. package/dist/providers/drive/openapi.generated.js +77 -0
  182. package/dist/providers/drive/safety.js +90 -0
  183. package/dist/providers/drive/skill.generated.js +2 -6
  184. package/dist/providers/drive/tools.js +1290 -0
  185. package/dist/providers/forms/api.js +71 -0
  186. package/dist/providers/forms/index.d.ts +1 -12
  187. package/dist/providers/forms/index.js +49 -1145
  188. package/dist/providers/forms/lib/constants.d.ts +14 -0
  189. package/dist/providers/forms/lib/constants.js +19 -0
  190. package/dist/providers/forms/lib/hatch.js +72 -0
  191. package/dist/providers/forms/openapi.generated.js +23 -0
  192. package/dist/providers/forms/safety.js +34 -0
  193. package/dist/providers/forms/skill.generated.js +2 -8
  194. package/dist/providers/forms/tools.js +1023 -0
  195. package/dist/providers/github/api.js +150 -0
  196. package/dist/providers/github/index.d.ts +4 -5
  197. package/dist/providers/github/index.js +30 -87
  198. package/dist/providers/github/{auth.d.ts → lib/auth.d.ts} +5 -3
  199. package/dist/providers/github/{auth.js → lib/auth.js} +40 -43
  200. package/dist/providers/github/lib/discovery.js +132 -0
  201. package/dist/providers/github/lib/operations.js +58 -0
  202. package/dist/providers/github/{scope.d.ts → lib/scope.d.ts} +2 -0
  203. package/dist/providers/github/{scope.js → lib/scope.js} +25 -1
  204. package/dist/providers/github/openapi.generated.js +1216 -0
  205. package/dist/providers/github/safety.js +216 -0
  206. package/dist/providers/github/skill.generated.js +2 -5
  207. package/dist/providers/github/tools.js +506 -0
  208. package/dist/providers/gmail/api.js +114 -0
  209. package/dist/providers/gmail/index.d.ts +1 -12
  210. package/dist/providers/gmail/index.js +73 -1621
  211. package/dist/providers/gmail/lib/constants.d.ts +13 -0
  212. package/dist/providers/gmail/lib/constants.js +16 -0
  213. package/dist/providers/gmail/lib/index.js +173 -0
  214. package/dist/providers/gmail/lib/schemas.js +176 -0
  215. package/dist/providers/gmail/lib/threading.js +120 -0
  216. package/dist/providers/gmail/openapi.generated.js +92 -0
  217. package/dist/providers/gmail/safety.js +21 -0
  218. package/dist/providers/gmail/skill.generated.js +2 -6
  219. package/dist/providers/gmail/tools.js +1435 -0
  220. package/dist/providers/overflow/api.js +1008 -0
  221. package/dist/providers/overflow/index.d.ts +1 -17
  222. package/dist/providers/overflow/index.js +60 -1488
  223. package/dist/providers/overflow/skill.generated.js +2 -5
  224. package/dist/providers/overflow/tools.js +873 -0
  225. package/dist/providers/planning-center/api.js +467 -0
  226. package/dist/providers/planning-center/index.d.ts +4 -35
  227. package/dist/providers/planning-center/index.js +69 -2445
  228. package/dist/providers/planning-center/lib/constants.d.ts +58 -0
  229. package/dist/providers/planning-center/lib/constants.js +83 -0
  230. package/dist/providers/planning-center/lib/discovery.js +40 -0
  231. package/dist/providers/planning-center/lib/guide.js +39 -0
  232. package/dist/providers/planning-center/lib/json-api.js +83 -0
  233. package/dist/providers/planning-center/lib/verdicts.js +1758 -0
  234. package/dist/providers/planning-center/openapi.generated.js +1764 -0
  235. package/dist/providers/planning-center/safety.js +188 -0
  236. package/dist/providers/planning-center/skill.generated.js +2 -27
  237. package/dist/providers/planning-center/tools.js +1010 -0
  238. package/dist/providers/quickbooks/api.js +299 -0
  239. package/dist/providers/quickbooks/index.d.ts +13 -0
  240. package/dist/providers/quickbooks/index.js +93 -0
  241. package/dist/providers/quickbooks/lib/query.js +118 -0
  242. package/dist/providers/quickbooks/lib/writes.js +168 -0
  243. package/dist/providers/quickbooks/safety.js +222 -0
  244. package/dist/providers/quickbooks/skill.generated.js +5 -0
  245. package/dist/providers/quickbooks/tools.js +117 -0
  246. package/dist/providers/sheets/api.js +133 -0
  247. package/dist/providers/sheets/index.d.ts +4 -16
  248. package/dist/providers/sheets/index.js +61 -1172
  249. package/dist/providers/sheets/lib/constants.d.ts +14 -0
  250. package/dist/providers/sheets/lib/constants.js +14 -0
  251. package/dist/providers/sheets/lib/hatch.js +163 -0
  252. package/dist/providers/sheets/lib/requests.js +105 -0
  253. package/dist/providers/sheets/lib/schemas.js +138 -0
  254. package/dist/providers/sheets/openapi.generated.js +30 -0
  255. package/dist/providers/sheets/safety.js +27 -0
  256. package/dist/providers/sheets/skill.generated.js +2 -7
  257. package/dist/providers/sheets/tools.js +733 -0
  258. package/dist/providers/slides/api.js +147 -0
  259. package/dist/providers/slides/index.d.ts +2 -10
  260. package/dist/providers/slides/index.js +48 -2555
  261. package/dist/providers/slides/lib/constants.d.ts +11 -0
  262. package/dist/providers/slides/lib/constants.js +11 -0
  263. package/dist/providers/slides/lib/requests.js +60 -0
  264. package/dist/providers/slides/lib/schemas.js +565 -0
  265. package/dist/providers/slides/openapi.generated.js +18 -0
  266. package/dist/providers/slides/skill.generated.js +2 -6
  267. package/dist/providers/slides/tools.js +1968 -0
  268. package/dist/providers/stripe/api.js +401 -0
  269. package/dist/providers/stripe/index.d.ts +5 -27
  270. package/dist/providers/stripe/index.js +74 -210
  271. package/dist/providers/stripe/lib/config.d.ts +4 -0
  272. package/dist/providers/stripe/lib/config.js +2 -0
  273. package/dist/providers/stripe/openapi.generated.js +4 -3
  274. package/dist/providers/stripe/{value-safety.js → safety.js} +5 -5
  275. package/dist/providers/stripe/skill.generated.js +2 -11
  276. package/dist/providers/stripe/tools.js +77 -0
  277. package/dist/providers/tithely/api.js +531 -0
  278. package/dist/providers/tithely/index.d.ts +17 -0
  279. package/dist/providers/tithely/index.js +86 -965
  280. package/dist/providers/tithely/skill.generated.js +2 -5
  281. package/dist/providers/tithely/tools.js +426 -0
  282. package/dist/providers/vercel/api.js +551 -0
  283. package/dist/providers/vercel/index.d.ts +9 -25
  284. package/dist/providers/vercel/index.js +65 -260
  285. package/dist/providers/vercel/lib/config.d.ts +2 -0
  286. package/dist/providers/vercel/lib/config.js +2 -0
  287. package/dist/providers/vercel/lib/index.js +117 -0
  288. package/dist/providers/vercel/lib/logs.js +100 -0
  289. package/dist/providers/vercel/lib/pin.js +270 -0
  290. package/dist/providers/vercel/openapi.generated.js +10 -5
  291. package/dist/providers/vercel/{value-safety.js → safety.js} +247 -38
  292. package/dist/providers/vercel/skill.generated.js +2 -7
  293. package/dist/providers/vercel/tools.js +642 -0
  294. package/dist/redaction-identity.js +47 -0
  295. package/dist/redaction-marker.js +125 -0
  296. package/dist/registry.d.ts +21 -15
  297. package/dist/registry.js +409 -376
  298. package/dist/routes/access-tokens.js +1 -1
  299. package/dist/routes/actor-labels.js +1 -1
  300. package/dist/routes/connect.js +1 -1
  301. package/dist/routes/dispatch.js +103 -0
  302. package/dist/routes/mcp.js +170 -79
  303. package/dist/routes/oauth.js +6 -1
  304. package/dist/routes/operator.js +2 -2
  305. package/dist/routes/shared.d.ts +5 -4
  306. package/dist/routes/shared.js +244 -177
  307. package/dist/routes/skills.js +10 -8
  308. package/dist/routes/ui-config.js +27 -3
  309. package/dist/routes/ui-data.js +21 -20
  310. package/dist/routes/ui.js +1 -1
  311. package/dist/runtime/call-admission.js +0 -26
  312. package/dist/runtime/call-entry.js +30 -0
  313. package/dist/runtime/call.js +552 -0
  314. package/dist/runtime/connector-scope.js +7 -0
  315. package/dist/runtime/credential-probe.js +34 -0
  316. package/dist/runtime/executor.js +40 -0
  317. package/dist/runtime/native-storage.js +63 -0
  318. package/dist/runtime/registry.js +27 -0
  319. package/dist/runtime/request-scope.js +72 -0
  320. package/dist/runtime/run.js +15 -7
  321. package/dist/runtime/shared-read.js +34 -5
  322. package/dist/runtime/storage.js +34 -21
  323. package/dist/sent-secrets.d.ts +194 -37
  324. package/dist/sent-secrets.js +1743 -340
  325. package/dist/server.js +5 -56
  326. package/dist/skills.js +322 -223
  327. package/dist/sqlite.js +15 -14
  328. package/dist/storage/d1-copy.js +255 -0
  329. package/dist/storage/d1-driver.js +15 -0
  330. package/dist/storage/keys.js +28 -0
  331. package/dist/storage/sql-driver.js +88 -0
  332. package/dist/storage/sql-native.js +544 -0
  333. package/dist/storage/sql-schema.d.ts +6 -0
  334. package/dist/storage/sql-schema.js +15 -0
  335. package/dist/storage/sql.d.ts +14 -20
  336. package/dist/storage/sql.js +29 -535
  337. package/dist/timeout.js +0 -26
  338. package/dist/tool-safety.js +20 -10
  339. package/dist/types.d.ts +9 -109
  340. package/dist/ui.d.ts +1 -1
  341. package/dist/ui.js +0 -1
  342. package/dist/upward.js +3 -0
  343. package/dist/usage-guide.js +3 -1
  344. package/dist/validate.d.ts +4 -2
  345. package/dist/validate.js +86 -9
  346. package/dist/version.d.ts +1 -1
  347. package/dist/version.js +1 -1
  348. package/dist/worker.js +312 -292
  349. package/dist/workspace-subject.js +5 -1
  350. package/dist/write-outcome.js +454 -34
  351. package/documentation/README.md +28 -7
  352. package/documentation/architecture.md +2409 -255
  353. package/documentation/auth.md +867 -114
  354. package/documentation/code-mode.md +49 -16
  355. package/documentation/deploying.md +164 -20
  356. package/documentation/hosted-mcp-migration.md +460 -0
  357. package/documentation/integrating.md +129 -144
  358. package/documentation/meta-tools.md +409 -32
  359. package/documentation/operating.md +27 -3
  360. package/documentation/operator-tests.md +3 -0
  361. package/documentation/operator-ui.md +84 -48
  362. package/documentation/provider-auth-migration.md +16 -63
  363. package/documentation/provider-migration-0.29.md +10 -5
  364. package/documentation/provider-migration-0.35.md +975 -0
  365. package/documentation/providers.md +1347 -0
  366. package/examples/worker/AGENTS.md +23 -9
  367. package/examples/worker/README.md +254 -135
  368. package/examples/worker/alchemy.run.ts +116 -0
  369. package/examples/worker/gitignore +10 -0
  370. package/examples/worker/src/connecta.config.ts +23 -21
  371. package/examples/worker/wrangler.jsonc +14 -5
  372. package/guides/connecting-agents.md +157 -0
  373. package/guides/how-it-works.md +156 -0
  374. package/guides/safety-and-trust.md +153 -0
  375. package/package.json +30 -50
  376. package/templates/node/.env.example +3 -0
  377. package/templates/node/README.md +22 -2
  378. package/templates/node/docker-compose.yml +1 -0
  379. package/templates/node/package.json +3 -2
  380. package/templates/node/src/connecta.config.ts +8 -0
  381. package/dist/catalog-drift.d.ts +0 -138
  382. package/dist/catalog-drift.js +0 -578
  383. package/dist/operator-ui/agents.d.ts +0 -74
  384. package/dist/operator-ui/agents.js +0 -104
  385. package/dist/operator-ui/config-summary.js +0 -565
  386. package/dist/operator-ui/connection-map.js +0 -376
  387. package/dist/operator-ui/endpoints.js +0 -221
  388. package/dist/operator-ui/fix-prompts.d.ts +0 -18
  389. package/dist/operator-ui/fix-prompts.js +0 -87
  390. package/dist/operator-ui/health.js +0 -52
  391. package/dist/operator-ui/member-page.js +0 -97
  392. package/dist/operator-ui/overview.js +0 -123
  393. package/dist/operator-ui/setup-commands.js +0 -51
  394. package/dist/operator-ui/view.d.ts +0 -401
  395. package/dist/operator-ui/view.js +0 -705
  396. package/dist/providers/_shared/request-token.js +0 -83
  397. package/dist/providers/_shared/rest/dispatch.js +0 -41
  398. package/dist/providers/_shared/rest/operation-index.d.ts +0 -133
  399. package/dist/providers/_shared/rest/tools.d.ts +0 -141
  400. package/dist/providers/_shared/rest/tools.js +0 -569
  401. package/dist/providers/_shared/rest/value-safety.d.ts +0 -201
  402. package/dist/providers/basecamp/index.d.ts +0 -45
  403. package/dist/providers/basecamp/index.js +0 -997
  404. package/dist/providers/basecamp/skill.generated.js +0 -9
  405. package/dist/providers/cloudflare/rest.d.ts +0 -37
  406. package/dist/providers/cloudflare/rest.js +0 -1097
  407. package/dist/providers/github/hosted.js +0 -218
  408. package/dist/providers/github/rest.js +0 -321
  409. package/dist/providers/infisical/index.d.ts +0 -7
  410. package/dist/providers/infisical/index.js +0 -713
  411. package/dist/providers/infisical/skill.generated.js +0 -8
  412. package/dist/providers/intercom/index.d.ts +0 -24
  413. package/dist/providers/intercom/index.js +0 -121
  414. package/dist/providers/intercom/skill.generated.js +0 -8
  415. package/dist/providers/linear/index.d.ts +0 -55
  416. package/dist/providers/linear/index.js +0 -537
  417. package/dist/providers/linear/skill.generated.js +0 -8
  418. package/dist/providers/mixpanel/index.d.ts +0 -59
  419. package/dist/providers/mixpanel/index.js +0 -472
  420. package/dist/providers/mixpanel/operations.js +0 -20
  421. package/dist/providers/mixpanel/rest.js +0 -603
  422. package/dist/providers/mixpanel/skill.generated.js +0 -10
  423. package/dist/providers/mixpanel/value-safety.js +0 -16
  424. package/dist/providers/notion/index.d.ts +0 -67
  425. package/dist/providers/notion/index.js +0 -368
  426. package/dist/providers/notion/openapi.generated.js +0 -75
  427. package/dist/providers/notion/rest.d.ts +0 -24
  428. package/dist/providers/notion/rest.js +0 -1226
  429. package/dist/providers/notion/skill.generated.js +0 -11
  430. package/dist/providers/notion/value-safety.js +0 -56
  431. package/dist/providers/revenuecat/index.d.ts +0 -51
  432. package/dist/providers/revenuecat/index.js +0 -697
  433. package/dist/providers/revenuecat/skill.generated.js +0 -11
  434. package/dist/providers/stripe/rest.d.ts +0 -14
  435. package/dist/providers/stripe/rest.js +0 -402
  436. package/dist/providers/vercel/rest.d.ts +0 -20
  437. package/dist/providers/vercel/rest.js +0 -1020
  438. package/dist/providers/wispr-flow/index.d.ts +0 -14
  439. package/dist/providers/wispr-flow/index.js +0 -117
  440. package/dist/providers/wispr-flow/skill.generated.js +0 -8
  441. /package/dist/providers/github/{key.js → lib/key.js} +0 -0
@@ -0,0 +1,733 @@
1
+ // Google Sheets named projections, bounded cell reads and guarded writes.
2
+ import { Effect, Option, Schema } from "effect";
3
+ import { ConnectorCallError } from "../../errors.js";
4
+ import { Refusal } from "../../http/errors.js";
5
+ import { googleClient, googleFailureMessage, googleOutcomeOf } from "../_shared/google/kit.js";
6
+ import { clampText, jsonBytes, RESULT_BUDGET_BYTES } from "../_shared/google/result-size.js";
7
+ import { encodeForAgent, redactBeforeCut } from "../../sent-secrets.js";
8
+ import { read, write } from "../../http/tools.js";
9
+ import { boundCursor } from "../../http/paging.js";
10
+ import { fieldsInput, fieldsProblem, selectFields } from "../../http/fields.js";
11
+ import { Operation } from "../../runtime/call.js";
12
+ import { sheetsIndex } from "./lib/hatch.js";
13
+ import { SHEETS_ADMITTED_KINDS, SHEETS_REFUSED_KINDS, sheetsExternalDataProblem } from "./lib/requests.js";
14
+ import { inputs, outputs } from "./lib/schemas.js";
15
+ /** Cells per page of get_values: connecta's cap, since Sheets has no paging. */
16
+ const DEFAULT_PAGE_CELLS = 2_000;
17
+ const MAX_PAGE_CELLS = 10_000;
18
+ /**
19
+ * Bytes per page of get_values as serialized, beside the cell count: a page
20
+ * has to be deliverable, and cells say nothing about size — 60 cells of 5,000
21
+ * characters already outgrow the QuickJS executor's host bridge. The default
22
+ * is the Workspace providers' shared result budget, so an execute_code
23
+ * program always receives a default page; unlike that budget's envelope
24
+ * allowance, maxBytes bounds the whole page, fields and cursor included. A
25
+ * direct call_tool caller may ask for more, up to 4 MiB: base64 in the result
26
+ * stash makes that about 5.6 MiB, under the stash's default 8 MiB, so an
27
+ * oversized page still pages through connecta.result rather than being dropped.
28
+ */
29
+ const DEFAULT_PAGE_BYTES = RESULT_BUDGET_BYTES;
30
+ const MAX_PAGE_BYTES = 4 * 1024 * 1024;
31
+ /**
32
+ * Characters a read keeps per cell by default. A cell holds at most 50,000
33
+ * (Sheets' own limit), so `maxCellChars` at that ceiling always reads one whole.
34
+ */
35
+ const DEFAULT_CELL_CHARS = 5_000;
36
+ const MAX_CELL_CHARS = 50_000;
37
+ /** Rows and cells one write may carry: connecta's cap, under Google's 10 MB request. */
38
+ const MAX_WRITE_CELLS = 50_000;
39
+ /** Named ranges a metadata read lists before reporting a size cut. */
40
+ const MAX_NAMED_RANGES = 200;
41
+ function asRecord(value) {
42
+ return value && typeof value === "object" && !Array.isArray(value) ? value : {};
43
+ }
44
+ function asArray(value) {
45
+ return Array.isArray(value) ? value : [];
46
+ }
47
+ function compact(value) {
48
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
49
+ }
50
+ function text(value) {
51
+ return typeof value === "string" && value !== "" ? value : undefined;
52
+ }
53
+ function integer(value) {
54
+ return typeof value === "number" && Number.isInteger(value) ? value : undefined;
55
+ }
56
+ /** A 0-based column index as its A1 letters: 0 → A, 26 → AA. */
57
+ function columnLetters(index) {
58
+ let letters = "";
59
+ for (let rest = index + 1; rest > 0; rest = Math.floor((rest - 1) / 26)) {
60
+ letters = String.fromCharCode(65 + ((rest - 1) % 26)) + letters;
61
+ }
62
+ return letters;
63
+ }
64
+ /**
65
+ * A sheet title as A1, always single-quoted. Bare, a whole-sheet range is
66
+ * indistinguishable from a named range of the same name — and Google resolves
67
+ * the named range first, so `Sheet1` handed to clear_values could clear
68
+ * something else. No named range can contain a quote, so quoted cannot.
69
+ */
70
+ function sheetPrefix(title) {
71
+ return `'${title.replace(/'/g, "''")}'`;
72
+ }
73
+ /**
74
+ * A GridRange as A1, or `undefined` for a shape A1 cannot say. Google leaves
75
+ * a zero index out of the JSON, and a missing start index means "from the
76
+ * first", so both read as 0; a missing end means "to the edge".
77
+ */
78
+ function gridRangeA1(range, title) {
79
+ if (title === undefined)
80
+ return undefined;
81
+ const startRow = integer(range["startRowIndex"]) ?? 0;
82
+ const startColumn = integer(range["startColumnIndex"]) ?? 0;
83
+ const endRow = integer(range["endRowIndex"]);
84
+ const endColumn = integer(range["endColumnIndex"]);
85
+ const prefix = sheetPrefix(title);
86
+ if (endRow === undefined && endColumn === undefined) {
87
+ return startRow === 0 && startColumn === 0 ? prefix : undefined;
88
+ }
89
+ if (endColumn === undefined) {
90
+ return startColumn === 0 ? `${prefix}!${startRow + 1}:${endRow}` : undefined;
91
+ }
92
+ const start = `${columnLetters(startColumn)}${startRow + 1}`;
93
+ return `${prefix}!${start}:${columnLetters(endColumn - 1)}${endRow ?? ""}`;
94
+ }
95
+ function valuesCursorArgs(args) {
96
+ return {
97
+ spreadsheetId: args["spreadsheetId"],
98
+ ranges: args["ranges"],
99
+ valueRenderOption: args["valueRenderOption"] ?? null,
100
+ dateTimeRenderOption: args["dateTimeRenderOption"] ?? null,
101
+ };
102
+ }
103
+ function encodeCursor(ctx, args, cursor) {
104
+ return boundCursor.encode("get_values", valuesCursorArgs(args), JSON.stringify(cursor), (json) => encodeForAgent(ctx, json, { url: true, claims: true }));
105
+ }
106
+ function decodeCursor(value, ranges) {
107
+ let parsed;
108
+ try {
109
+ parsed = JSON.parse(value);
110
+ }
111
+ catch {
112
+ parsed = undefined;
113
+ }
114
+ const cursor = asRecord(parsed), index = integer(cursor["i"]), skip = integer(cursor["s"]);
115
+ if (Object.keys(cursor).length !== 2 ||
116
+ index === undefined ||
117
+ index < 0 ||
118
+ index >= ranges.length ||
119
+ skip === undefined ||
120
+ skip < 0 ||
121
+ !Number.isSafeInteger(skip)) {
122
+ throw new ConnectorCallError("invalid_args", "Pass the get_values page.nextCursor back unchanged with the same spreadsheet, ranges and render options.");
123
+ }
124
+ return { i: index, s: skip };
125
+ }
126
+ /**
127
+ * The caller's own range past its first `rows` rows, when the range says
128
+ * where it starts: `Sheet1!C5:F100` → `Sheet1!C8:F100`, `B:D` → `B4:D`. A
129
+ * sheet title, a named range, or R1C1 does not, and is resent whole with the
130
+ * rows skipped instead — correct, but it re-reads what earlier pages did.
131
+ */
132
+ function rangeAfter(range, rows) {
133
+ if (rows === 0)
134
+ return range;
135
+ const match = /^(.*!)?([A-Z]+)(\d+)?:([A-Z]+)(\d+)?$/.exec(range);
136
+ if (!match)
137
+ return undefined;
138
+ const [, prefix = "", startColumn, startRow, endColumn, endRow] = match;
139
+ if (startRow === undefined && endRow !== undefined)
140
+ return undefined;
141
+ const first = Number(startRow ?? 1);
142
+ if (endRow !== undefined && first > Number(endRow))
143
+ return undefined;
144
+ const start = first + rows;
145
+ if (endRow !== undefined && start > Number(endRow))
146
+ return undefined;
147
+ return `${prefix}${startColumn}${start}:${endColumn}${endRow ?? ""}`;
148
+ }
149
+ /** A cell as read, cut at `max` characters with a marker saying how to read the rest. Every
150
+ * secret the request sent is replaced first: a cut through an echo leaves a fragment. */
151
+ function cappedCell(ctx, whole, max, cut) {
152
+ if (typeof whole !== "string" || whole.length <= max)
153
+ return whole;
154
+ const value = redactBeforeCut(ctx, whole);
155
+ if (value.length <= max)
156
+ return value;
157
+ cut.cells += 1;
158
+ return `${value.slice(0, max)}[… ${value.length - max} more characters truncated; read this cell alone with maxCellChars up to ${MAX_CELL_CHARS} for the rest]`;
159
+ }
160
+ /** Refuse a row no page of `budget` bytes can hold, rather than overrun the cap. */
161
+ function rowTooLarge(range, row, needed, budget) {
162
+ return new ConnectorCallError("invalid_args", `Row ${row} of ${range} needs a page of ${needed} bytes with the page's own fields, more than this page's maxBytes of ${budget}; narrow the range's columns or lower maxCellChars${raiseBytes(needed)}.`);
163
+ }
164
+ /** Refuse a page too small for even one range's own fields. */
165
+ function pageTooSmall(range, needed, budget) {
166
+ return new ConnectorCallError("invalid_args", `A page reporting ${range} needs ${needed} bytes before any of its rows, more than this page's maxBytes of ${budget}; shorten the range${raiseBytes(needed)}.`);
167
+ }
168
+ function raiseBytes(needed) {
169
+ if (needed > MAX_PAGE_BYTES)
170
+ return "";
171
+ return needed <= DEFAULT_PAGE_BYTES
172
+ ? `, or raise maxBytes to at least ${needed}`
173
+ : `, or raise maxBytes to at least ${needed} (above ${DEFAULT_PAGE_BYTES}, only for a direct call_tool read: execute_code cannot receive it)`;
174
+ }
175
+ /** Refuse a row no page of `budget` cells can hold, rather than overrun the cap. */
176
+ function rowTooWide(range, row, width, budget) {
177
+ const fix = width <= MAX_PAGE_CELLS
178
+ ? `raise maxCells to at least ${width}, or narrow the range's columns`
179
+ : `narrow the range's columns; a page holds at most ${MAX_PAGE_CELLS} cells`;
180
+ return new ConnectorCallError("invalid_args", `Row ${row} of ${range} has ${width} cells, more than this page's maxCells of ${budget}; ${fix}.`);
181
+ }
182
+ // --- Writing values ---------------------------------------------------------------
183
+ /** Refuse a write past connecta's per-call cell cap before anything is sent. */
184
+ function checkWriteSize(blocks) {
185
+ let cells = 0;
186
+ for (const block of blocks)
187
+ for (const row of block)
188
+ cells += row.length;
189
+ if (cells > MAX_WRITE_CELLS) {
190
+ throw new ConnectorCallError("invalid_args", `This write carries ${cells} cells; connecta sends at most ${MAX_WRITE_CELLS} per call (Google's own request limit is larger). Split it into several calls. Nothing was written.`);
191
+ }
192
+ }
193
+ function projectUpdate(value) {
194
+ const update = asRecord(value);
195
+ return compact({
196
+ updatedRange: text(update["updatedRange"]),
197
+ updatedRows: integer(update["updatedRows"]) ?? 0,
198
+ updatedColumns: integer(update["updatedColumns"]) ?? 0,
199
+ updatedCells: integer(update["updatedCells"]) ?? 0,
200
+ });
201
+ }
202
+ /** Refuse a raw request that is not exactly one known kind, unsent. */
203
+ function checkRequestKinds(requests) {
204
+ for (const request of requests)
205
+ for (const kind of Object.keys(asRecord(request)))
206
+ if (Object.hasOwn(SHEETS_REFUSED_KINDS, kind))
207
+ throw new ConnectorCallError("invalid_args", SHEETS_REFUSED_KINDS[kind]);
208
+ const problem = sheetsExternalDataProblem(requests);
209
+ if (problem)
210
+ throw new ConnectorCallError("invalid_args", problem);
211
+ requests.forEach((request, index) => {
212
+ const kinds = Object.keys(asRecord(request));
213
+ if (kinds.length !== 1 || !SHEETS_ADMITTED_KINDS.includes(kinds[0])) {
214
+ throw new ConnectorCallError("invalid_args", `requests[${index}] must set exactly one Sheets Request kind (addSheet, repeatCell, deleteDimension, …); it sets ${kinds.length === 0 ? "none" : kinds.slice(0, 3).join(", ")}. Nothing was sent.`);
215
+ }
216
+ });
217
+ }
218
+ /**
219
+ * A write whose outcome is unknown — sent, and then anything but an answer
220
+ * Google refused it with: a reply that broke off, no reply, a redirect, or a
221
+ * 5xx after receiving it — told what to read before trying again, for the
222
+ * writes where the shared "re-read before repeating it" has nothing to re-read
223
+ * or where repeating does harm. The advice claims nothing either way; only
224
+ * the client's own message says "probably applied", and only for a 2xx whose
225
+ * body broke off. A refusal, and anything never sent, passes through as the
226
+ * client mapped it.
227
+ */
228
+ function uncertainWrite(connection, advice, write) {
229
+ return write.pipe(Effect.catch((failure) => {
230
+ const outcome = googleOutcomeOf(failure);
231
+ return outcome?.dispatched && outcome.phase !== "refused"
232
+ ? googleFailureMessage(connection, failure, (message) => `${message} ${advice}`)
233
+ : Effect.fail(failure);
234
+ }));
235
+ }
236
+ // --- Raw batchUpdate replies -----------------------------------------------------
237
+ /** A string kept in a reply summary, cut so a long one cannot crowd out ids. */
238
+ const SUMMARY_TEXT_BYTES = 256;
239
+ /** The scalar fields of an object — ids, titles, counts — and nothing nested. */
240
+ function scalarsOf(ctx, value) {
241
+ const scalars = {};
242
+ for (const [key, field] of Object.entries(asRecord(value))) {
243
+ if (typeof field === "string") {
244
+ scalars[key] = clampText(ctx, field, SUMMARY_TEXT_BYTES, (dropped) => `[… ${dropped} more characters]`);
245
+ }
246
+ else if (typeof field === "number" || typeof field === "boolean") {
247
+ scalars[key] = field;
248
+ }
249
+ }
250
+ return Object.keys(scalars).length > 0 ? scalars : undefined;
251
+ }
252
+ /**
253
+ * One reply reduced to its kind and the scalars an agent acts on next: a new
254
+ * sheet's id and title, a chart's id, findReplace's counts. Google's replies
255
+ * put those at the top of the kind's body or one object down (`properties`,
256
+ * `chart`, `namedRange`); arrays and anything deeper are dropped.
257
+ */
258
+ function summarizeReply(ctx, reply) {
259
+ const kind = Object.keys(reply)[0];
260
+ if (kind === undefined)
261
+ return {};
262
+ const body = asRecord(reply[kind]);
263
+ const nested = {};
264
+ for (const [key, field] of Object.entries(body)) {
265
+ if (field && typeof field === "object" && !Array.isArray(field))
266
+ nested[key] = scalarsOf(ctx, field);
267
+ }
268
+ return compact({ kind, ...scalarsOf(ctx, body), ...compact(nested) });
269
+ }
270
+ /**
271
+ * A batchUpdate result that can be delivered. The write has already applied,
272
+ * so whatever does not fit is summarized, never dropped silently and never
273
+ * reported as a failure: replies are kept whole, in order, while the ones
274
+ * after them still fit as summaries; the rest become summaries; and a reply
275
+ * set too large even for that leaves the counts and where to re-read.
276
+ */
277
+ function deliverableReplies(ctx, spreadsheetId, replies, requestCount) {
278
+ const whole = { spreadsheetId, replies };
279
+ if (jsonBytes(whole) <= RESULT_BUDGET_BYTES)
280
+ return whole;
281
+ const note = `All ${requestCount} requests applied. Replies too large to return here are cut to their kind, ids, and counts; read the spreadsheet with get_spreadsheet or get_values for the rest. Do not send the requests again.`;
282
+ const summaries = replies.map((reply) => summarizeReply(ctx, reply));
283
+ // What every reply from index i on costs as a summary, comma included.
284
+ const rest = Array.from({ length: replies.length + 1 }, () => 0);
285
+ for (let index = replies.length - 1; index >= 0; index -= 1) {
286
+ rest[index] = rest[index + 1] + jsonBytes(summaries[index]) + 1;
287
+ }
288
+ let bytes = jsonBytes({ spreadsheetId, replies: [], truncated: ["replies[]"], note });
289
+ if (bytes + rest[0] <= RESULT_BUDGET_BYTES) {
290
+ const kept = [];
291
+ let summarized = 0;
292
+ replies.forEach((reply, index) => {
293
+ const size = jsonBytes(reply) + 1;
294
+ if (summarized === 0 && bytes + size + rest[index + 1] <= RESULT_BUDGET_BYTES) {
295
+ bytes += size;
296
+ kept.push(reply);
297
+ }
298
+ else {
299
+ summarized += 1;
300
+ kept.push(summaries[index]);
301
+ }
302
+ });
303
+ return { spreadsheetId, replies: kept, truncated: ["replies[]"], note };
304
+ }
305
+ return {
306
+ spreadsheetId,
307
+ replies: [],
308
+ truncated: ["replies[]"],
309
+ note: `All ${requestCount} requests applied, but their ${replies.length} replies are too large to return even summarized. Read the spreadsheet with get_spreadsheet or get_values to see the result. Do not send the requests again.`,
310
+ };
311
+ }
312
+ function projectSheet(value) {
313
+ const properties = asRecord(asRecord(value)["properties"]);
314
+ const grid = asRecord(properties["gridProperties"]);
315
+ return compact({
316
+ // The first sheet's id is 0, which Google leaves out of the JSON.
317
+ sheetId: integer(properties["sheetId"]) ?? 0,
318
+ title: text(properties["title"]),
319
+ index: integer(properties["index"]) ?? 0,
320
+ type: text(properties["sheetType"]),
321
+ hidden: properties["hidden"] === true ? true : undefined,
322
+ rowCount: integer(grid["rowCount"]),
323
+ columnCount: integer(grid["columnCount"]),
324
+ frozenRowCount: integer(grid["frozenRowCount"]),
325
+ frozenColumnCount: integer(grid["frozenColumnCount"]),
326
+ });
327
+ }
328
+ /** The metadata get_spreadsheet reads: no grid data, no formatting. */
329
+ const SPREADSHEET_FIELDS = [
330
+ "spreadsheetId",
331
+ "spreadsheetUrl",
332
+ "properties(title,locale,timeZone)",
333
+ "sheets.properties(sheetId,title,index,sheetType,hidden,gridProperties(rowCount,columnCount,frozenRowCount,frozenColumnCount))",
334
+ "namedRanges(namedRangeId,name,range)",
335
+ ].join(",");
336
+ // --- Tools ------------------------------------------------------------------------
337
+ export function sheetsTools({ connection }) {
338
+ const client = googleClient(connection, sheetsIndex);
339
+ const readOnly = { readOnlyHint: true };
340
+ // Additive: nothing that existed is lost. Writes require a writable
341
+ // endpoint: call_destructive_tool or a program. The host controls approval.
342
+ const additive = { readOnlyHint: false, destructiveHint: false };
343
+ const destructive = { readOnlyHint: false, destructiveHint: true };
344
+ const spreadsheetPath = (args) => `/spreadsheets/${encodeURIComponent(String(args["spreadsheetId"]))}`;
345
+ const declarations = [
346
+ {
347
+ name: "get_spreadsheet",
348
+ description: "Get a spreadsheet's title, sheets (ids, titles, grid sizes), and named ranges as A1, never cell values. To find one by name, search Drive; Sheets cannot list.",
349
+ annotations: readOnly,
350
+ input: inputs.get_spreadsheet,
351
+ output: outputs.get_spreadsheet,
352
+ run: (args) => Effect.gen(function* () {
353
+ const spreadsheet = asRecord(yield* client.json({
354
+ method: "GET",
355
+ path: spreadsheetPath(args),
356
+ template: "/spreadsheets/{spreadsheetId}",
357
+ query: { fields: SPREADSHEET_FIELDS },
358
+ }));
359
+ const properties = asRecord(spreadsheet["properties"]);
360
+ const sheets = asArray(spreadsheet["sheets"]).map(projectSheet);
361
+ const titles = new Map(sheets.map((sheet) => [sheet["sheetId"], sheet["title"]]));
362
+ const named = asArray(spreadsheet["namedRanges"]);
363
+ return compact({
364
+ spreadsheetId: text(spreadsheet["spreadsheetId"]) ?? args["spreadsheetId"],
365
+ title: text(properties["title"]),
366
+ url: text(spreadsheet["spreadsheetUrl"]),
367
+ locale: text(properties["locale"]),
368
+ timeZone: text(properties["timeZone"]),
369
+ sheets,
370
+ namedRanges: named.length > 0
371
+ ? named.slice(0, MAX_NAMED_RANGES).map((value) => {
372
+ const entry = asRecord(value);
373
+ const range = asRecord(entry["range"]);
374
+ const sheetId = integer(range["sheetId"]) ?? 0;
375
+ return compact({
376
+ namedRangeId: text(entry["namedRangeId"]),
377
+ name: text(entry["name"]),
378
+ sheetId,
379
+ range: gridRangeA1(range, titles.get(sheetId)),
380
+ });
381
+ })
382
+ : undefined,
383
+ truncated: named.length > MAX_NAMED_RANGES ? ["namedRanges[]"] : undefined,
384
+ });
385
+ }),
386
+ },
387
+ {
388
+ name: "get_values",
389
+ description: "Read cell values from one or more A1 ranges as rows, paged by cell count. Long cells are cut with a marker; no formatting, notes, or formulas unless asked.",
390
+ annotations: readOnly,
391
+ input: inputs.get_values,
392
+ output: outputs.get_values,
393
+ run: (args, ctx) => Effect.gen(function* () {
394
+ const ranges = args["ranges"];
395
+ const budget = args["maxCells"] ?? DEFAULT_PAGE_CELLS;
396
+ const byteBudget = args["maxBytes"] ?? DEFAULT_PAGE_BYTES;
397
+ const cellChars = args["maxCellChars"] ?? DEFAULT_CELL_CHARS;
398
+ const resume = typeof args["cursor"] === "string"
399
+ ? decodeCursor(yield* boundCursor.decode("get_values", valuesCursorArgs(args), args["cursor"]), ranges)
400
+ : { i: 0, s: 0 };
401
+ // Every range sent is the caller's own, or the caller's own rewritten
402
+ // to start further down; nothing in the cursor names a range.
403
+ const rewritten = rangeAfter(ranges[resume.i], resume.s);
404
+ const sent = [rewritten ?? ranges[resume.i], ...ranges.slice(resume.i + 1)];
405
+ const skip = rewritten === undefined ? resume.s : 0;
406
+ const response = asRecord(yield* client.json({
407
+ method: "GET",
408
+ path: `${spreadsheetPath(args)}/values:batchGet`,
409
+ template: "/spreadsheets/{spreadsheetId}/values:batchGet",
410
+ query: {
411
+ ranges: sent,
412
+ majorDimension: "ROWS",
413
+ valueRenderOption: args["valueRenderOption"],
414
+ dateTimeRenderOption: args["dateTimeRenderOption"],
415
+ },
416
+ }));
417
+ const spreadsheetId = text(response["spreadsheetId"]) ?? args["spreadsheetId"];
418
+ const valueRanges = [];
419
+ const cut = { cells: 0 };
420
+ let cells = 0;
421
+ // maxBytes bounds the whole page as serialized, not just its cells. The
422
+ // envelope is reserved first at its largest: both counts at their
423
+ // ceiling and the longest cursor this call could end with.
424
+ let bytes = jsonBytes({
425
+ spreadsheetId,
426
+ valueRanges: [],
427
+ cellCount: MAX_PAGE_CELLS,
428
+ truncated: ["valueRanges[].values"],
429
+ page: {
430
+ hasMore: false,
431
+ nextCursor: yield* encodeCursor(ctx, args, { i: ranges.length - 1, s: Number.MAX_SAFE_INTEGER }),
432
+ },
433
+ });
434
+ let next;
435
+ const returned = asArray(response["valueRanges"]);
436
+ for (let index = 0; index < returned.length && next === undefined; index += 1) {
437
+ const valueRange = asRecord(returned[index]);
438
+ // Rows of the caller's range earlier pages returned, and of those,
439
+ // how many Google sent again and this page drops.
440
+ const before = index === 0 ? resume.s : 0;
441
+ const dropped = index === 0 ? skip : 0;
442
+ const rows = asArray(valueRange["values"]).slice(dropped);
443
+ const echoed = text(valueRange["range"]) ?? sent[index];
444
+ const entry = (kept) => compact({
445
+ range: echoed,
446
+ rowOffset: dropped > 0 ? dropped : undefined,
447
+ values: kept,
448
+ rowCount: kept.length,
449
+ });
450
+ // This range's own fields at their largest, and the comma before it;
451
+ // an empty range costs them too.
452
+ const fields = jsonBytes(compact({
453
+ range: echoed,
454
+ rowOffset: dropped > 0 ? dropped : undefined,
455
+ values: [],
456
+ rowCount: rows.length,
457
+ })) + 1;
458
+ if (bytes + fields > byteBudget) {
459
+ if (valueRanges.length === 0)
460
+ throw pageTooSmall(echoed, bytes + fields, byteBudget);
461
+ next = { i: resume.i + index, s: before };
462
+ break;
463
+ }
464
+ bytes += fields;
465
+ const kept = [];
466
+ for (const row of rows) {
467
+ const empty = valueRanges.length === 0 && kept.length === 0;
468
+ // An empty row still costs one cell, so every page makes progress.
469
+ const width = Math.max(1, asArray(row).length);
470
+ if (cells + width > budget) {
471
+ if (cells === 0)
472
+ throw rowTooWide(echoed, dropped + kept.length + 1, width, budget);
473
+ break;
474
+ }
475
+ const rowCut = { cells: 0 };
476
+ const capped = asArray(row).map((cell) => cappedCell(ctx, cell, cellChars, rowCut));
477
+ // The row as serialized, plus the comma before it.
478
+ const size = jsonBytes(capped) + 1;
479
+ if (bytes + size > byteBudget) {
480
+ if (empty)
481
+ throw rowTooLarge(echoed, dropped + 1, bytes + size, byteBudget);
482
+ break;
483
+ }
484
+ cells += width;
485
+ bytes += size;
486
+ cut.cells += rowCut.cells;
487
+ kept.push(capped);
488
+ }
489
+ if (kept.length < rows.length) {
490
+ next = { i: resume.i + index, s: before + kept.length };
491
+ // A range this page never reached is not reported half-read; the
492
+ // next page starts it.
493
+ if (kept.length > 0)
494
+ valueRanges.push(entry(kept));
495
+ break;
496
+ }
497
+ valueRanges.push(entry(kept));
498
+ if (cells >= budget && index + 1 < returned.length) {
499
+ next = { i: resume.i + index + 1, s: 0 };
500
+ }
501
+ }
502
+ const nextCursor = next ? yield* encodeCursor(ctx, args, next) : null;
503
+ return compact({
504
+ spreadsheetId,
505
+ valueRanges,
506
+ cellCount: cells,
507
+ truncated: cut.cells > 0 || next ? ["valueRanges[].values"] : undefined,
508
+ page: compact({ hasMore: nextCursor !== null, nextCursor: nextCursor ?? undefined }),
509
+ });
510
+ }),
511
+ },
512
+ {
513
+ name: "update_values",
514
+ description: "Write rows of values into one A1 range, overwriting what is there. Cells past the given rows are untouched; to add rows below a table use append_values.",
515
+ annotations: destructive,
516
+ input: inputs.update_values,
517
+ output: outputs.update_values,
518
+ run: (args) => Effect.gen(function* () {
519
+ checkWriteSize([args["values"]]);
520
+ const response = asRecord(yield* client.json({
521
+ method: "POST",
522
+ path: `${spreadsheetPath(args)}/values:batchUpdate`,
523
+ template: "/spreadsheets/{spreadsheetId}/values:batchUpdate",
524
+ body: {
525
+ valueInputOption: args["valueInputOption"],
526
+ data: [{ range: args["range"], majorDimension: "ROWS", values: args["values"] }],
527
+ includeValuesInResponse: false,
528
+ },
529
+ }));
530
+ return {
531
+ spreadsheetId: text(response["spreadsheetId"]) ?? args["spreadsheetId"],
532
+ ...projectUpdate(asArray(response["responses"])[0]),
533
+ };
534
+ }),
535
+ },
536
+ {
537
+ name: "batch_update_values",
538
+ description: "Write values into several A1 ranges in one call, overwriting each. All succeed or none do. For formatting or structure use batch_update_spreadsheet.",
539
+ annotations: destructive,
540
+ input: inputs.batch_update_values,
541
+ output: outputs.batch_update_values,
542
+ run: (args) => Effect.gen(function* () {
543
+ const data = asArray(args["data"]).map(asRecord);
544
+ checkWriteSize(data.map((entry) => entry["values"]));
545
+ const response = asRecord(yield* client.json({
546
+ method: "POST",
547
+ path: `${spreadsheetPath(args)}/values:batchUpdate`,
548
+ template: "/spreadsheets/{spreadsheetId}/values:batchUpdate",
549
+ body: {
550
+ valueInputOption: args["valueInputOption"],
551
+ data: data.map((entry) => ({ range: entry["range"], majorDimension: "ROWS", values: entry["values"] })),
552
+ includeValuesInResponse: false,
553
+ },
554
+ }));
555
+ return {
556
+ spreadsheetId: text(response["spreadsheetId"]) ?? args["spreadsheetId"],
557
+ totalUpdatedRows: integer(response["totalUpdatedRows"]) ?? 0,
558
+ totalUpdatedColumns: integer(response["totalUpdatedColumns"]) ?? 0,
559
+ totalUpdatedCells: integer(response["totalUpdatedCells"]) ?? 0,
560
+ totalUpdatedSheets: integer(response["totalUpdatedSheets"]) ?? 0,
561
+ updates: asArray(response["responses"]).map(projectUpdate),
562
+ };
563
+ }),
564
+ },
565
+ {
566
+ name: "append_values",
567
+ description: "Append rows after the last row of the table in an A1 range, inserting new rows so nothing below is overwritten. Returns where they landed.",
568
+ annotations: additive,
569
+ input: inputs.append_values,
570
+ output: outputs.append_values,
571
+ run: (args) => Effect.gen(function* () {
572
+ checkWriteSize([args["values"]]);
573
+ const response = asRecord(
574
+ // A second call after one that landed adds the rows twice.
575
+ yield* uncertainWrite(connection, "Appending again would add the rows a second time if the first append landed: read the table with get_values and append only what is missing.", client.json({
576
+ method: "POST",
577
+ path: `${spreadsheetPath(args)}/values/${encodeURIComponent(String(args["range"]))}:append`,
578
+ template: "/spreadsheets/{spreadsheetId}/values/{range}:append",
579
+ query: {
580
+ valueInputOption: args["valueInputOption"],
581
+ // Pinned: OVERWRITE writes over whatever sits below the table.
582
+ insertDataOption: "INSERT_ROWS",
583
+ includeValuesInResponse: false,
584
+ },
585
+ body: { majorDimension: "ROWS", values: args["values"] },
586
+ })));
587
+ return compact({
588
+ spreadsheetId: text(response["spreadsheetId"]) ?? args["spreadsheetId"],
589
+ tableRange: text(response["tableRange"]),
590
+ ...projectUpdate(response["updates"]),
591
+ });
592
+ }),
593
+ },
594
+ {
595
+ name: "clear_values",
596
+ description: "Clear the values in one or more A1 ranges, keeping formatting, notes, and validation. The values are gone; nothing is deleted or shifted.",
597
+ annotations: destructive,
598
+ input: inputs.clear_values,
599
+ output: outputs.clear_values,
600
+ run: (args) => Effect.gen(function* () {
601
+ const response = asRecord(yield* client.json({
602
+ method: "POST",
603
+ path: `${spreadsheetPath(args)}/values:batchClear`,
604
+ template: "/spreadsheets/{spreadsheetId}/values:batchClear",
605
+ body: { ranges: args["ranges"] },
606
+ }));
607
+ return {
608
+ spreadsheetId: text(response["spreadsheetId"]) ?? args["spreadsheetId"],
609
+ clearedRanges: asArray(response["clearedRanges"]).filter((range) => typeof range === "string"),
610
+ };
611
+ }),
612
+ },
613
+ {
614
+ name: "create_spreadsheet",
615
+ description: "Create a new spreadsheet in the user's My Drive root, optionally with named sheets. It is not shared or moved; that is Drive's job.",
616
+ annotations: additive,
617
+ input: inputs.create_spreadsheet,
618
+ output: outputs.create_spreadsheet,
619
+ run: (args) => Effect.gen(function* () {
620
+ const titles = args["sheetTitles"];
621
+ const spreadsheet = asRecord(
622
+ // A spreadsheet that may exist has no id to re-read; only its title
623
+ // can find it, and Sheets cannot search.
624
+ yield* uncertainWrite(connection, "Search Drive for this title before creating it again, or a second spreadsheet results.", client.json({
625
+ method: "POST",
626
+ path: "/spreadsheets",
627
+ template: "/spreadsheets",
628
+ query: { fields: "spreadsheetId,spreadsheetUrl,properties.title,sheets.properties(sheetId,title)" },
629
+ body: compact({
630
+ properties: { title: args["title"] },
631
+ sheets: titles?.map((title) => ({ properties: { title } })),
632
+ }),
633
+ })));
634
+ return compact({
635
+ spreadsheetId: text(spreadsheet["spreadsheetId"]),
636
+ title: text(asRecord(spreadsheet["properties"])["title"]),
637
+ url: text(spreadsheet["spreadsheetUrl"]),
638
+ sheets: asArray(spreadsheet["sheets"]).map((sheet) => {
639
+ const { sheetId, title } = projectSheet(sheet);
640
+ return compact({ sheetId, title });
641
+ }),
642
+ });
643
+ }),
644
+ },
645
+ {
646
+ name: "add_sheet",
647
+ description: "Add a new, empty sheet tab to a spreadsheet. Fails if the title is taken; it never renames, replaces, or copies an existing sheet.",
648
+ annotations: additive,
649
+ input: inputs.add_sheet,
650
+ output: outputs.add_sheet,
651
+ run: (args) => Effect.gen(function* () {
652
+ const grid = compact({ rowCount: args["rowCount"], columnCount: args["columnCount"] });
653
+ const response = asRecord(yield* client.json({
654
+ method: "POST",
655
+ path: `${spreadsheetPath(args)}:batchUpdate`,
656
+ template: "/spreadsheets/{spreadsheetId}:batchUpdate",
657
+ body: {
658
+ requests: [
659
+ {
660
+ addSheet: {
661
+ properties: compact({
662
+ title: args["title"],
663
+ index: args["index"],
664
+ gridProperties: Object.keys(grid).length > 0 ? grid : undefined,
665
+ }),
666
+ },
667
+ },
668
+ ],
669
+ },
670
+ }));
671
+ const added = asRecord(asRecord(asArray(response["replies"])[0])["addSheet"]);
672
+ return {
673
+ spreadsheetId: text(response["spreadsheetId"]) ?? args["spreadsheetId"],
674
+ ...projectSheet(added),
675
+ };
676
+ }),
677
+ },
678
+ {
679
+ name: "batch_update_spreadsheet",
680
+ description: "Apply Sheets batchUpdate requests — formatting, merges, sorts, deleting sheets or rows, protections — atomically. This named structural workflow can destroy data.",
681
+ // Destructive, whatever the requests are: they can delete sheets, rows,
682
+ // ranges, and protections, and connecta does not read them to guess.
683
+ annotations: destructive,
684
+ input: inputs.batch_update_spreadsheet,
685
+ output: outputs.batch_update_spreadsheet,
686
+ run: (args, ctx) => Effect.gen(function* () {
687
+ checkRequestKinds(args["requests"]);
688
+ const response = asRecord(yield* client.json({
689
+ method: "POST",
690
+ path: `${spreadsheetPath(args)}:batchUpdate`,
691
+ template: "/spreadsheets/{spreadsheetId}:batchUpdate",
692
+ body: { requests: args["requests"], includeSpreadsheetInResponse: false },
693
+ }));
694
+ return deliverableReplies(ctx, text(response["spreadsheetId"]) ?? args["spreadsheetId"], asArray(response["replies"]).map(asRecord), asArray(args["requests"]).length);
695
+ }),
696
+ },
697
+ ];
698
+ return declarations.map((declaration) => {
699
+ const spec = {
700
+ name: declaration.name,
701
+ description: declaration.description,
702
+ input: declaration.input,
703
+ output: declaration.output,
704
+ run: (args) => Effect.gen(function* () {
705
+ const current = yield* Effect.serviceOption(Operation);
706
+ if (Option.isNone(current) || !current.value)
707
+ return yield* Effect.die(new Error("Sheets tools require a call context."));
708
+ return yield* declaration.run(args, current.value);
709
+ }).pipe(Effect.catchDefect((defect) => defect instanceof ConnectorCallError ? Effect.fail(new Refusal({ error: defect })) : Effect.die(defect))),
710
+ };
711
+ if (!declaration.annotations.readOnlyHint)
712
+ return write(connection, { ...spec, destructive: declaration.annotations.destructiveHint });
713
+ return read(connection, {
714
+ ...spec,
715
+ input: Schema.Struct({
716
+ ...declaration.input.fields,
717
+ fields: Schema.optionalKey(fieldsInput("Dot paths to keep; truncation and content continuation metadata remain available.")),
718
+ }),
719
+ run: (args) => Effect.gen(function* () {
720
+ const { fields, ...rest } = args;
721
+ const problem = fieldsProblem(fields, new Set(Object.keys(declaration.output.fields)), "the Sheets result");
722
+ if (problem)
723
+ return yield* Effect.fail(new Refusal({ error: problem }));
724
+ const result = yield* spec.run(rest);
725
+ return {
726
+ ...selectFields(result, fields),
727
+ ...(result["truncated"] ? { truncated: result["truncated"] } : {}),
728
+ ...(declaration.name === "get_values" ? { page: result["page"] } : {}),
729
+ };
730
+ }),
731
+ });
732
+ });
733
+ }