@zackbart/connecta 0.35.0 → 0.36.1

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 (102) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/README.md +8 -4
  3. package/bin/version.mjs +1 -1
  4. package/dist/auth/downstream-oauth.js +71 -79
  5. package/dist/auth/static-oauth.js +104 -26
  6. package/dist/connectors/api-connector.d.ts +17 -0
  7. package/dist/connectors/api-connector.js +3 -1
  8. package/dist/http/client.js +1 -1
  9. package/dist/http/hatch-paging.js +2 -2
  10. package/dist/http/paging.js +3 -89
  11. package/dist/http/provider.js +1 -2
  12. package/dist/http/services.js +1 -1
  13. package/dist/http/tools.js +1 -27
  14. package/dist/operator-ui/contract.d.ts +1 -0
  15. package/dist/operator-ui/generated.js +4 -4
  16. package/dist/program-writes.js +0 -1
  17. package/dist/providers/_shared/google/kit.js +29 -139
  18. package/dist/providers/_shared/rest/kit.js +4 -404
  19. package/dist/providers/_shared/sensitive-fields.js +0 -16
  20. package/dist/providers/breeze/api.js +2 -2
  21. package/dist/providers/ccb/api.js +1 -1
  22. package/dist/providers/cloudflare/api.js +8 -8
  23. package/dist/providers/cloudflare/lib/config.d.ts +2 -1
  24. package/dist/providers/docs/api.js +1 -1
  25. package/dist/providers/docs/tools.js +1 -2
  26. package/dist/providers/drive/api.js +2 -2
  27. package/dist/providers/drive/lib/hatch.js +1 -1
  28. package/dist/providers/drive/tools.js +1 -1
  29. package/dist/providers/forms/api.js +1 -1
  30. package/dist/providers/forms/lib/hatch.js +1 -1
  31. package/dist/providers/forms/tools.js +2 -3
  32. package/dist/providers/github/api.js +1 -1
  33. package/dist/providers/github/lib/discovery.js +2 -2
  34. package/dist/providers/gmail/api.js +1 -1
  35. package/dist/providers/gmail/tools.js +2 -2
  36. package/dist/providers/granola/api.js +155 -0
  37. package/dist/providers/granola/index.d.ts +10 -0
  38. package/dist/providers/granola/index.js +68 -0
  39. package/dist/providers/granola/openapi.generated.js +30 -0
  40. package/dist/providers/granola/safety.js +37 -0
  41. package/dist/providers/granola/skill.generated.js +5 -0
  42. package/dist/providers/granola/tools.js +2 -0
  43. package/dist/providers/overflow/api.js +26 -26
  44. package/dist/providers/planning-center/api.js +4 -4
  45. package/dist/providers/planning-center/lib/constants.d.ts +1 -1
  46. package/dist/providers/planning-center/lib/json-api.js +2 -2
  47. package/dist/providers/quickbooks/api.js +299 -0
  48. package/dist/providers/quickbooks/index.d.ts +13 -0
  49. package/dist/providers/quickbooks/index.js +93 -0
  50. package/dist/providers/quickbooks/lib/query.js +118 -0
  51. package/dist/providers/quickbooks/lib/writes.js +168 -0
  52. package/dist/providers/quickbooks/safety.js +222 -0
  53. package/dist/providers/quickbooks/skill.generated.js +5 -0
  54. package/dist/providers/quickbooks/tools.js +117 -0
  55. package/dist/providers/sheets/api.js +1 -1
  56. package/dist/providers/sheets/lib/hatch.js +2 -2
  57. package/dist/providers/sheets/lib/requests.js +1 -1
  58. package/dist/providers/sheets/tools.js +1 -2
  59. package/dist/providers/slides/api.js +1 -1
  60. package/dist/providers/slides/tools.js +2 -2
  61. package/dist/providers/stripe/api.js +7 -7
  62. package/dist/providers/tithely/api.js +2 -2
  63. package/dist/providers/vercel/api.js +12 -12
  64. package/dist/providers/vercel/index.js +1 -2
  65. package/dist/providers/vercel/lib/pin.js +1 -1
  66. package/dist/routes/mcp.js +1 -1
  67. package/dist/routes/oauth.js +3 -0
  68. package/dist/runtime/admission.js +0 -12
  69. package/dist/runtime/call.js +0 -4
  70. package/dist/skills.js +0 -1
  71. package/dist/storage/keys.js +2 -3
  72. package/dist/types.d.ts +2 -0
  73. package/dist/ui.d.ts +1 -1
  74. package/dist/ui.js +0 -1
  75. package/dist/version.d.ts +1 -1
  76. package/dist/version.js +1 -1
  77. package/documentation/README.md +1 -0
  78. package/documentation/architecture.md +249 -366
  79. package/documentation/auth.md +56 -19
  80. package/documentation/code-mode.md +6 -6
  81. package/documentation/integrating.md +1 -1
  82. package/documentation/meta-tools.md +6 -3
  83. package/documentation/operator-tests.md +11 -2
  84. package/documentation/operator-ui.md +17 -5
  85. package/documentation/providers.md +492 -0
  86. package/package.json +12 -9
  87. package/templates/node/package.json +1 -1
  88. package/dist/operator-ui/agents.d.ts +0 -75
  89. package/dist/operator-ui/agents.js +0 -114
  90. package/dist/operator-ui/config-summary.js +0 -566
  91. package/dist/operator-ui/connection-map.js +0 -378
  92. package/dist/operator-ui/endpoints.js +0 -212
  93. package/dist/operator-ui/fix-prompts.d.ts +0 -18
  94. package/dist/operator-ui/fix-prompts.js +0 -79
  95. package/dist/operator-ui/health.js +0 -52
  96. package/dist/operator-ui/member-page.js +0 -97
  97. package/dist/operator-ui/overview.js +0 -126
  98. package/dist/operator-ui/setup-commands.js +0 -47
  99. package/dist/operator-ui/view.d.ts +0 -378
  100. package/dist/operator-ui/view.js +0 -631
  101. package/dist/providers/_shared/rest/dispatch.js +0 -21
  102. package/dist/providers/_shared/rest/tools.js +0 -592
@@ -7,6 +7,361 @@ roster](./integrating.md#add-or-remove-a-connector) covers the general
7
7
  procedure and the providers not listed here. Agent guidance for each
8
8
  provider ships with its connection's usage guide, not here.
9
9
 
10
+ ## Granola
11
+
12
+ ```ts
13
+ import { granola } from "@zackbart/connecta/providers/granola";
14
+
15
+ const notes = granola("granola", { purpose: "Shared workspace meeting notes" });
16
+ ```
17
+
18
+ Use a **workspace API key**, created by a Business or Enterprise workspace
19
+ admin in Granola desktop Settings → Connectors → Workspace API keys → Create
20
+ new key. Save it in this connection's credential slot through the operator UI;
21
+ configure an encrypted vault as described in [shared credentials](./auth.md#connect-a-shared-credential).
22
+ The shared, single-secret field is `value`. The provider fixes the origin to
23
+ `https://public-api.granola.ai`, uses bearer authentication, and exposes reads
24
+ only. It accepts `purpose`, optional `title`, `instructions`, and
25
+ `maxResultBytes` and the common `readOnly` restriction. Even `readOnly: false`
26
+ exposes only the five reviewed reads; it accepts no inline secret, origin override, personal auth
27
+ scope, or option enabling writes.
28
+
29
+ Workspace keys belong to the workspace, survive their creator leaving and do
30
+ not expire; an admin can revoke them. They reach public notes and spaces with
31
+ Granola API access enabled. For an existing space an admin uses Integrations →
32
+ Granola API → Allow access with a workspace API key. Folders inherit the space
33
+ setting. Workspace ownership does not grant unrelated private notes or the
34
+ owner's private handwritten notes. Discover accessible IDs before filtering.
35
+ Only notes with a generated summary and transcript are returned; a 404 does
36
+ not prove absence. A successful credential test confirms accessible spaces,
37
+ not the key's ownership type or access to every meeting. Granola enforces
38
+ these permissions; Connecta cannot infer workspace versus personal key type
39
+ from the secret. Do not substitute a personal API key or MCP OAuth token.
40
+
41
+ The REST surface is `granola_api_search`, `granola_api_details`, and
42
+ `granola_api_read`. Search discovers API operations, not meeting content.
43
+ Reads cover `/v1/notes`, `/v1/notes/{note_id}`,
44
+ `/v1/notes/{note_id}/transcript`, `/v1/folders`, and `/v1/spaces`. Use API IDs
45
+ (`not_`, `fol_`, `spa_`), not UUIDs copied from web links. Date/folder/space
46
+ filters and response `fields` narrowing follow the reviewed operation details.
47
+ Audit, legal holds, webhook management and writes are refused, even if their
48
+ contracts appear in operation discovery.
49
+
50
+ Omit `query.cursor` on the first read. Continue with `page.nextCursor` as the
51
+ top-level `cursor`, retaining the path and query filters. Continuations are
52
+ bound to that request and are not raw Granola tokens. The vendor uses
53
+ `query.page_size`: notes/folders/spaces default to 10 with maximum 30;
54
+ transcripts default to 50 with maximum 100. Empty pages can have more data.
55
+ No total count is inferred. HTTP 413 when using `include: "transcript"`
56
+ requires a new note-detail read without include and paged transcript reads;
57
+ the provider sends no hidden fallback requests. Photo download URLs grant
58
+ unauthenticated access and are always withheld. Meeting text and sent
59
+ credentials cross the same value-safety boundary before selection or paging.
60
+
61
+ Granola documents 25 requests per 5-second burst and 5 requests/second
62
+ sustained, shared across the workspace key's scope. The default per-runtime
63
+ admission is 25 calls in a rolling 5-second window with concurrency 2. Other
64
+ processes and integrations share the vendor allowance; the local counter
65
+ cannot enforce a workspace-wide limit. A 429 returns `rate_limited` and
66
+ Retry-After when supplied (otherwise a 5-second hint); calls are not retried
67
+ automatically. Requests have a 30-second deadline and 4 MiB response ceiling.
68
+ Oversized responses fail without presenting a partial success; inline result
69
+ cuts retain the standard `truncated` paths.
70
+
71
+ For hosted Granola MCP, use a distinct generic `remoteMcp()` connection to
72
+ `https://mcp.granola.ai/mcp` with its user OAuth or enterprise-managed
73
+ authorization. Granola MCP does not accept workspace API keys or service
74
+ accounts. Its natural-language search is not a REST-provider capability.
75
+ See [Granola's workspace-key guide](https://docs.granola.ai/help-center/sharing/integrations/granola-api#workspace-api-keys)
76
+ and [API overview](https://docs.granola.ai/introduction).
77
+
78
+ ### Migrate a deployment-local Granola API adapter
79
+
80
+ Replace the local `api("granola", …)` construction with
81
+ `granola("granola", { purpose: "Shared workspace meeting notes" })`, retaining
82
+ the same encrypted vault, encryption key, connector ID, shared owner and
83
+ single-secret `value` field. The provider reuses that credential without
84
+ copying it. Existing addresses `granola.granola_api_search`,
85
+ `granola.granola_api_details`, and `granola.granola_api_read` remain stable.
86
+ Keep existing pool references to `granola`. A differently named or personal
87
+ credential field requires the operator to save a workspace key in the shared
88
+ slot; do not read out or copy stored secrets through an agent.
89
+
90
+ Compare local argument contracts before replacing the factory: the maintained
91
+ search is operation discovery, details uses an indexed operation, and read
92
+ uses a relative path and query. Replace raw `query.cursor` continuations with
93
+ the bound top-level `cursor`, and start new pagination sequences after the
94
+ upgrade. Responses use `{ status, data, page? }`. Remove local write tools or
95
+ natural-language-search assumptions; do not keep duplicate factories with the
96
+ same connector ID. If a local adapter used other tool names, update its
97
+ callers explicitly. No data migration or downstream write is required.
98
+
99
+ ## API sources and tool inventory
100
+
101
+ Maintained providers pair reviewed API contracts and indexes with Connecta's
102
+ adapters and tools. Sources include upstream OpenAPI,
103
+ Google Discovery conversions, reviewed HTML/documentation conversions and
104
+ hand-authored endpoint contracts. Tithe.ly and Overflow use endpoint checks
105
+ without vendored OpenAPI documents. `remoteMcp()` discovers live server tools
106
+ instead.
107
+
108
+ QuickBooks Online uses a restricted hand-authored Accounting API contract with
109
+ manual vendor review; its read hatch cannot execute arbitrary query SQL.
110
+
111
+ These generated reference catalogs separate named workflows from API tools
112
+ and reads from writes. API search/details inspect indexed contracts, including
113
+ refused operations. Raw read/write calls accept only reviewed operations within
114
+ configured scope and safety rules. Gmail has no generic write tool.
115
+
116
+ Addresses use your connector ID: Stripe configured as `billing` exposes
117
+ `billing.stripe_api_read`. Configuration, credentials and read-only policy affect
118
+ availability. Planning Center labels identify required products. Use live
119
+ discovery for your deployment's catalog.
120
+
121
+ <!-- provider-inventory:start -->
122
+
123
+ <details>
124
+ <summary>Breeze ChMS (15 tools)</summary>
125
+
126
+ [Setup](#breeze-chms). **API source:** [Reviewed HTML/documentation conversion](https://app.breezechms.com/api).
127
+
128
+ - **Named reads:** `get_account_summary`, `get_person`, `list_attendance`, `list_contributions`, `list_events`, `list_funds`, `list_people`, `list_profile_fields`, `list_tags`.
129
+ - **Named writes:** `add_person`, `update_person`.
130
+ - **API reads:** `breeze_api_details`, `breeze_api_read`, `breeze_api_search`.
131
+ - **API writes:** `breeze_api_write`.
132
+
133
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/breeze).
134
+
135
+ </details>
136
+
137
+ <details>
138
+ <summary>Church Community Builder (20 tools)</summary>
139
+
140
+ [Setup](#church-community-builder). **API source:** [Upstream OpenAPI](https://docs.pushpay.io/chms-v2/openapi/chms-api-specs.json?download=1).
141
+
142
+ - **Named reads:** `get_event_attendance`, `get_event`, `get_family`, `get_giving_metrics`, `get_group`, `get_individual`, `get_me`, `list_event_attendees`, `list_events`, `list_families`, `list_group_members`, `list_groups`, `list_individual_groups`, `list_individual_notes`, `list_individuals`, `search_records`.
143
+ - **Named writes:** None.
144
+ - **API reads:** `ccb_api_details`, `ccb_api_read`, `ccb_api_search`.
145
+ - **API writes:** `ccb_api_write`.
146
+
147
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/ccb).
148
+
149
+ </details>
150
+
151
+ <details>
152
+ <summary>Cloudflare (9 tools)</summary>
153
+
154
+ [Setup](#cloudflare). **API source:** [Upstream OpenAPI](https://raw.githubusercontent.com/cloudflare/api-schemas/main/openapi.json). [Supplemental reviewed contract](https://developers.cloudflare.com/analytics/graphql-api/).
155
+
156
+ - **Named reads:** `graphql_query`, `list_accounts`, `list_zones`, `verify_credential`.
157
+ - **Named writes:** None.
158
+ - **API reads:** `cloudflare_api_details`, `cloudflare_api_read`, `cloudflare_api_search`.
159
+ - **API writes:** `cloudflare_api_upload`, `cloudflare_api_write`.
160
+
161
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/cloudflare).
162
+
163
+ </details>
164
+
165
+ <details>
166
+ <summary>Google Docs (10 tools)</summary>
167
+
168
+ [Setup](#google-docs). **API source:** [Google Discovery conversion](https://docs.googleapis.com/$discovery/rest?version=v1).
169
+
170
+ - **Named reads:** `get_document`.
171
+ - **Named writes:** `append_text`, `batch_update_document`, `create_document`, `insert_text`, `replace_all_text`.
172
+ - **API reads:** `docs_api_details`, `docs_api_read`, `docs_api_search`.
173
+ - **API writes:** `docs_api_write`.
174
+
175
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/docs).
176
+
177
+ </details>
178
+
179
+ <details>
180
+ <summary>Google Drive (21 tools)</summary>
181
+
182
+ [Setup](#google-drive). **API source:** [Google Discovery conversion](https://developers.google.com/workspace/drive/api/reference/rest/v3).
183
+
184
+ - **Named reads:** `get_file_content`, `get_file`, `list_folder_items`, `list_permissions`, `list_shared_drives`, `search_files`.
185
+ - **Named writes:** `copy_file`, `create_file`, `create_folder`, `delete_permission`, `move_file`, `restore_file`, `share_file`, `trash_file`, `update_file_content`, `update_file`, `update_permission`.
186
+ - **API reads:** `drive_api_details`, `drive_api_read`, `drive_api_search`.
187
+ - **API writes:** `drive_api_write`.
188
+
189
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/drive).
190
+
191
+ </details>
192
+
193
+ <details>
194
+ <summary>Google Forms (10 tools)</summary>
195
+
196
+ [Setup](#google-forms). **API source:** [Google Discovery conversion](https://developers.google.com/workspace/forms/api/reference/rest).
197
+
198
+ - **Named reads:** `get_form`, `get_response`, `list_responses`.
199
+ - **Named writes:** `batch_update_form`, `create_form`, `update_form_info`.
200
+ - **API reads:** `forms_api_details`, `forms_api_read`, `forms_api_search`.
201
+ - **API writes:** `forms_api_write`.
202
+
203
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/forms).
204
+
205
+ </details>
206
+
207
+ <details>
208
+ <summary>GitHub (7 tools)</summary>
209
+
210
+ [Setup](#github). **API source:** [Upstream OpenAPI](https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.json).
211
+
212
+ - **Named reads:** `list_scopes`, `search_scoped`.
213
+ - **Named writes:** `merge_pull_request`.
214
+ - **API reads:** `github_api_details`, `github_api_read`, `github_api_search`.
215
+ - **API writes:** `github_api_write`.
216
+
217
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/github).
218
+
219
+ </details>
220
+
221
+ <details>
222
+ <summary>Gmail (12 tools)</summary>
223
+
224
+ [Setup](#gmail). **API source:** [Google Discovery conversion](https://developers.google.com/workspace/gmail/api/reference/rest).
225
+
226
+ - **Named reads:** `get_attachment`, `get_draft`, `get_message`, `get_thread`, `list_drafts`, `list_labels`, `search_threads`.
227
+ - **Named writes:** `create_draft`, `update_draft`.
228
+ - **API reads:** `gmail_api_details`, `gmail_api_read`, `gmail_api_search`.
229
+ - **API writes:** None.
230
+
231
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/gmail).
232
+
233
+ </details>
234
+
235
+ <details>
236
+ <summary>Granola (3 tools)</summary>
237
+
238
+ [Setup](#granola). **API source:** [Upstream OpenAPI](https://docs.granola.ai/api-reference/openapi.json).
239
+
240
+ - **Named reads:** None.
241
+ - **Named writes:** None.
242
+ - **API reads:** `granola_api_details`, `granola_api_read`, `granola_api_search`.
243
+ - **API writes:** None.
244
+
245
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/granola).
246
+
247
+ </details>
248
+
249
+ <details>
250
+ <summary>Overflow (17 tools)</summary>
251
+
252
+ [Setup](#overflow). **API source:** Hand-authored endpoint contracts; [upstream endpoint checks](https://server.stage.overflow.co/api/docs/openapi.json). No vendored OpenAPI document.
253
+
254
+ - **Named reads:** `get_contribution`, `get_deposit_summary`, `get_deposit`, `get_donor`, `list_campaigns`, `list_chargebacks`, `list_contributions`, `list_deposits`, `list_donors`, `list_locations`, `list_payment_methods`, `list_refunds`, `list_subscriptions`.
255
+ - **Named writes:** None.
256
+ - **API reads:** `overflow_api_details`, `overflow_api_read`, `overflow_api_search`.
257
+ - **API writes:** `overflow_api_write`.
258
+
259
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/overflow).
260
+
261
+ </details>
262
+
263
+ <details>
264
+ <summary>Planning Center (27 tools)</summary>
265
+
266
+ [Setup](#planning-center). **API source:** Composed upstream OpenAPI contracts: [/people/v2](https://developer.planning.center/docs/#/people/2026-06-04), [/services/v2](https://developer.planning.center/docs/#/services/2018-11-01), [/groups/v2](https://developer.planning.center/docs/#/groups/2023-07-10), [/check-ins/v2](https://developer.planning.center/docs/#/check-ins/2025-05-28), [/calendar/v2](https://developer.planning.center/docs/#/calendar/2026-06-22), [/registrations/v2](https://developer.planning.center/docs/#/registrations/2025-05-01), [/giving/v2](https://developer.planning.center/docs/#/giving/2019-10-18), [/publishing/v2](https://developer.planning.center/docs/#/publishing/2024-03-25), [/webhooks/v2](https://developer.planning.center/docs/#/webhooks/2022-10-20), [/api/v2](https://developer.planning.center/docs/#/api/2026-09-24).
267
+
268
+ - **Named reads:** `get_me`, `get_person`, `get_plan` (services enabled), `list_donations` (giving enabled), `list_funds` (giving enabled), `list_group_memberships` (groups enabled), `list_groups` (groups enabled), `list_person_field_data`, `list_person_notes`, `list_person_schedules` (services enabled), `list_plans` (services enabled), `list_service_types` (services enabled), `list_teams` (services enabled), `list_workflow_cards`, `list_workflows`, `search_people`.
269
+ - **Named writes:** `add_group_member` (groups enabled), `add_person_note`, `add_workflow_card`, `apply_workflow_card_action`, `create_person`, `schedule_plan_person` (services enabled), `update_person`.
270
+ - **API reads:** `pco_api_details`, `pco_api_read`, `pco_api_search`.
271
+ - **API writes:** `pco_api_write`.
272
+
273
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/planning-center).
274
+
275
+ </details>
276
+
277
+ <details>
278
+ <summary>QuickBooks Online (10 tools)</summary>
279
+
280
+ [Setup](#quickbooks-online). **API source:** Hand-authored endpoint contracts. No vendored OpenAPI document.
281
+
282
+ - **Named reads:** `get_company_info`, `get_record`, `get_report`, `search_records`.
283
+ - **Named writes:** `create_customer`, `create_invoice`, `update_customer`.
284
+ - **API reads:** `quickbooks_api_details`, `quickbooks_api_read`, `quickbooks_api_search`.
285
+ - **API writes:** None.
286
+
287
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/quickbooks).
288
+
289
+ </details>
290
+
291
+ <details>
292
+ <summary>Google Sheets (13 tools)</summary>
293
+
294
+ [Setup](#google-sheets). **API source:** [Google Discovery conversion](https://developers.google.com/workspace/sheets/api/reference/rest).
295
+
296
+ - **Named reads:** `get_spreadsheet`, `get_values`.
297
+ - **Named writes:** `add_sheet`, `append_values`, `batch_update_spreadsheet`, `batch_update_values`, `clear_values`, `create_spreadsheet`, `update_values`.
298
+ - **API reads:** `sheets_api_details`, `sheets_api_read`, `sheets_api_search`.
299
+ - **API writes:** `sheets_api_write`.
300
+
301
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/sheets).
302
+
303
+ </details>
304
+
305
+ <details>
306
+ <summary>Google Slides (19 tools)</summary>
307
+
308
+ [Setup](#google-slides). **API source:** [Google Discovery conversion](https://developers.google.com/workspace/slides/api/reference/rest).
309
+
310
+ - **Named reads:** `get_page`, `get_presentation`, `get_slide_thumbnail`, `list_comments`, `list_layouts`.
311
+ - **Named writes:** `batch_update_presentation`, `create_comment_reply`, `create_comment`, `create_presentation`, `create_slide`, `delete_comment_reply`, `delete_comment`, `replace_all_text`, `update_comment_post`, `update_comment_thread`.
312
+ - **API reads:** `slides_api_details`, `slides_api_read`, `slides_api_search`.
313
+ - **API writes:** `slides_api_write`.
314
+
315
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/slides).
316
+
317
+ </details>
318
+
319
+ <details>
320
+ <summary>Stripe (6 tools)</summary>
321
+
322
+ [Setup](#stripe). **API source:** [Upstream OpenAPI](https://raw.githubusercontent.com/stripe/openapi/master/latest/openapi.spec3.json).
323
+
324
+ - **Named reads:** `get_balance_summary`, `get_stripe_account_info`.
325
+ - **Named writes:** None.
326
+ - **API reads:** `stripe_api_details`, `stripe_api_read`, `stripe_api_search`.
327
+ - **API writes:** `stripe_api_write`.
328
+
329
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/stripe).
330
+
331
+ </details>
332
+
333
+ <details>
334
+ <summary>Tithe.ly (11 tools)</summary>
335
+
336
+ [Setup](#tithely). **API source:** Hand-authored endpoint contracts; [upstream endpoint checks](https://docs.tithe.ly/reference/). No vendored OpenAPI document.
337
+
338
+ - **Named reads:** `get_charge`, `get_recurring_charge`, `list_accounts`, `list_charges`, `list_organizations`, `list_payment_methods`, `list_recurring_charges`.
339
+ - **Named writes:** None.
340
+ - **API reads:** `tithely_api_details`, `tithely_api_read`, `tithely_api_search`.
341
+ - **API writes:** `tithely_api_write`.
342
+
343
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/tithely).
344
+
345
+ </details>
346
+
347
+ <details>
348
+ <summary>Vercel (11 tools)</summary>
349
+
350
+ [Setup](#vercel). **API source:** [Upstream OpenAPI](https://openapi.vercel.sh/).
351
+
352
+ - **Named reads:** `get_deployment_build_logs`, `get_runtime_logs`, `list_project_env_vars`, `list_teams`.
353
+ - **Named writes:** `update_project_env_var`, `upsert_project_env_var`.
354
+ - **API reads:** `vercel_api_details`, `vercel_api_read`, `vercel_api_search`.
355
+ - **API writes:** `vercel_api_upload`, `vercel_api_write`.
356
+
357
+ **Contributor evidence (optional):** [contracts, adapters and review](https://github.com/zackbart/connecta/tree/main/src/providers/vercel).
358
+
359
+ </details>
360
+
361
+ <!-- provider-inventory:end -->
362
+
363
+ ## API operation discovery and boundaries
364
+
10
365
  Standard API operation search accepts resource nouns, actions and conversational
11
366
  phrasing. A leading create/add/update/edit/make/set/apply/change/rename/send/delete/remove/cancel/stop
12
367
  with an object prefers reviewed writes and keeps later read words as nouns, as in
@@ -963,3 +1318,140 @@ body and `result.page` carries continuation. Resource keys, decryption JWTs and
963
1318
  private download destinations remain withheld on named and hatch responses.
964
1319
  A 404 does not prove absence. Auxiliary lookup failures send no move; an actual
965
1320
  write failure can have an unknown outcome and requires a read before repetition.
1321
+
1322
+ ## QuickBooks Online
1323
+
1324
+ Available from 0.36.0. Use the deployment's own Intuit app and configure one
1325
+ fixed QuickBooks Online company per connector. Multiple companies need separate
1326
+ connector IDs and separate consent; tool arguments cannot select another
1327
+ company or environment.
1328
+
1329
+ ```ts
1330
+ import { quickbooks } from "@zackbart/connecta/providers/quickbooks";
1331
+
1332
+ const accounting = quickbooks("accounting", {
1333
+ purpose: "Company accounting reports and invoice reconciliation",
1334
+ realmId: process.env.QUICKBOOKS_REALM_ID!,
1335
+ environment: "sandbox",
1336
+ clientId: process.env.QUICKBOOKS_CLIENT_ID!,
1337
+ clientSecret: process.env.QUICKBOOKS_CLIENT_SECRET!,
1338
+ });
1339
+ ```
1340
+
1341
+ Create an Intuit QuickBooks Online app, enable the Accounting API and obtain
1342
+ the client ID and secret for the selected environment. Sandbox and production
1343
+ credentials are separate. Register
1344
+ `<publicUrl>/oauth/callback/accounting` as an exact redirect URI. Set the
1345
+ numeric company/realm ID in deployment configuration, then connect through
1346
+ the operator UI or `authorize_connector`. After valid OAuth state, the callback
1347
+ must contain exactly one `realmId` equal to the configured value before any
1348
+ code exchange. Selecting another company fails authorization. Store app
1349
+ credentials in deployment secrets; token import and endpoint overrides are
1350
+ not supported.
1351
+
1352
+ OAuth defaults to one shared grant; `authScope: "personal"` instead gives each
1353
+ owner a grant for the same fixed company. The requested
1354
+ `com.intuit.quickbooks.accounting` scope permits both reads and writes at Intuit.
1355
+ This provider defaults to `readOnly: true`. Set `readOnly: false` explicitly in
1356
+ deployment code to enable the three bounded named writes below. Connector,
1357
+ endpoint and pool read-only policy still refuses writes before validation or
1358
+ dispatch. It reuses sealed grants, coordinated refresh,
1359
+ rotation and revocation. Access tokens last one hour; refresh authorization
1360
+ requires use within 100 days and expires absolutely after five years. Reconnect
1361
+ when Intuit requires consent again. Do not assume refresh extends the absolute
1362
+ window or infer expiry from provider-specific fields.
1363
+
1364
+ `get_company_info`, `search_records`, `get_record` and `get_report` are the
1365
+ named reads. The reviewed record families are customers, vendors, accounts,
1366
+ items, invoices, bills, received accounting payments and bill payments.
1367
+ `search_records` accepts at most eight structured AND filters and returns up to
1368
+ 100 rows per page (25 by default; configurable with `defaultPageSize`). Its
1369
+ signed continuation binds the original arguments, company, environment,
1370
+ connector and credential owner. Continue with unchanged arguments and cursor.
1371
+ Search is not a snapshot; concurrent accounting changes can alter later pages.
1372
+
1373
+ Reports are allowlisted to ProfitAndLoss, BalanceSheet, CashFlow,
1374
+ AgedReceivables and AgedPayables. P&L and Cash Flow accept `start_date`; all
1375
+ accept `end_date` (translated to `report_date` with `aging_method: "Report_Date"`
1376
+ for AR/AP aging). P&L and Balance Sheet accept `accounting_method` (`Cash` or
1377
+ `Accrual`). No verified currency override is exposed; inspect the returned
1378
+ Header.Currency and never combine unlike currencies. Unsupported combinations fail before
1379
+ dispatch. Report Header, Columns and nested Rows retain section identity,
1380
+ column metadata and empty amount strings. Check the returned period, basis
1381
+ and currency; an empty amount is never converted to zero. Responses use the
1382
+ modernized report service in effect since August 31, 2026. Requests explicitly
1383
+ use the supported minor-version floor 75.
1384
+
1385
+ `quickbooks_api_search` and `quickbooks_api_details` inspect reviewed
1386
+ operations. `quickbooks_api_read` reaches only indexed record/company/report
1387
+ GETs inside this company's configured host and path. `/query` is refused;
1388
+ use the named structured search. Unreviewed entities, arbitrary SQL, URL,
1389
+ realm, scope and token overrides and arbitrary writes are unavailable. Desktop,
1390
+ Payments and Payroll APIs are outside this provider.
1391
+
1392
+ With `readOnly: false`, `create_customer` accepts only DisplayName and optional
1393
+ CompanyName. `update_customer` requires caller-observed Id and SyncToken and
1394
+ uses `sparse: true` for those naming fields; a stale version fails without a
1395
+ version fetch or overwrite. DisplayName must be unique across customers,
1396
+ vendors and employees.
1397
+
1398
+ `create_invoice` creates a real accounting transaction, never a draft, only
1399
+ for a verified US company and a customer using USD. The reviewed autosend
1400
+ contract is US-specific; the initial money contract uses two-decimal USD
1401
+ units. It requires an observed active customer, currency USD, an explicit positive
1402
+ exchange rate, transaction/due dates, DocNumber and 1–20 active Service-item
1403
+ lines. Amounts are positive decimal-unit strings with exactly two fractional
1404
+ digits, at most 999999999.99 per line. Every line explicitly supplies one unit
1405
+ and its price. Preflight reads verify the fixed company Country is US, then
1406
+ recheck the customer currency and item type and activity; they are not an atomic snapshot. No default prices, dates or rates,
1407
+ and no implicit customer/item creation, are used. QuickBooks computes taxes and
1408
+ totals, and locale/company rules may reject the narrow request. Inspect the
1409
+ returned CurrencyRef, ExchangeRate and totals.
1410
+ Each request after the first charges the same call-admission budget before
1411
+ dispatch. Returned references, dates, rate and service prices must match the
1412
+ admitted intent; contradictions produce an unknown, non-retryable outcome.
1413
+
1414
+ Creation fixes EmailStatus to `NotSet` and IPN/online/card/ACH/PayPal/Affirm
1415
+ payment flags to false, accepts no email fields, and never calls a send endpoint.
1416
+ Intuit's documented autosend path requires company opt-in, enabled online
1417
+ payments and `NeedToSend` with BillEmail; the fixed creation body withholds
1418
+ those request conditions. Invoice updates remain unavailable because retaining
1419
+ an existing send-ready state is not established safe, and resetting that state
1420
+ would change existing payment settings. Deletes, voids, delivery, payment
1421
+ execution, batch and other accounting writes remain unavailable. The API hatch
1422
+ refuses POSTs even when named writes are enabled.
1423
+
1424
+ Sparse field preservation, a current SyncToken and requestid do not establish
1425
+ that an invoice update cannot send email. For example, changing only DueDate
1426
+ on an invoice with NeedToSend and enabled card/ACH payments retains those
1427
+ settings; omitting email fields does not disable them. Do not reset delivery or
1428
+ payment settings to work around the unavailable update, or replace the invoice
1429
+ with a new one. No unsent-only update tool is currently exposed either.
1430
+
1431
+ Each write requires `requestId`, a stable identifier for the exact intent,
1432
+ unique across all requests/tools for this company: 1–50 ASCII letters, digits,
1433
+ underscores or hyphens, beginning with a letter or digit. It is sent as Intuit's
1434
+ `requestid` query parameter with minorversion 75. The vendor recognizes repeated
1435
+ content and ID; no retention duration is established. This never permits
1436
+ Connecta to replay automatically: every dispatched write has one attempt,
1437
+ including 401, timeout, server failure and malformed success.
1438
+
1439
+ Reconcile an unknown create through reads before another intent: customer
1440
+ DisplayName (including inactive matches when relevant), or invoice DocNumber
1441
+ plus CustomerRef and currency, dates, lines and computed amounts. DocNumber may
1442
+ repeat and is not proof by itself. Do not blindly create again with a new ID;
1443
+ report ambiguity. Reconcile unknown updates by the known record Id and version.
1444
+ The requestId supplies no lookup endpoint or permanent retention guarantee.
1445
+
1446
+ All named and hatch responses apply the same closed privacy projection before
1447
+ `fields` narrows it. Public Id and SyncToken versions, accounting references,
1448
+ amounts and minimal display names remain; contact emails/phones/addresses,
1449
+ bank/card/tax identifiers, private notes, credentials and private URLs are
1450
+ withheld. No `sensitiveFields` or `raw` option widens these results. Reduce
1451
+ financial records to task-relevant aggregates before returning them to a user.
1452
+ `maxResultBytes`, `callAdmission` and the standard provider title/instructions
1453
+ options remain available. No default admission budget is declared: account for
1454
+ other integrations sharing the app when configuring one. Intuit documents
1455
+ 500 requests per minute per company and 10 per second per company/app in both
1456
+ environments; after HTTP 429, wait at least 60 seconds. Local admission is per
1457
+ runtime and cannot coordinate other deployments' spending.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zackbart/connecta",
3
- "version": "0.35.0",
3
+ "version": "0.36.1",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "One MCP to rule them all — a single MCP endpoint aggregating many downstream connectors behind a code-first surface of six meta-tools.",
@@ -107,6 +107,10 @@
107
107
  "types": "./dist/providers/gmail/index.d.ts",
108
108
  "import": "./dist/providers/gmail/index.js"
109
109
  },
110
+ "./providers/granola": {
111
+ "types": "./dist/providers/granola/index.d.ts",
112
+ "import": "./dist/providers/granola/index.js"
113
+ },
110
114
  "./providers/overflow": {
111
115
  "types": "./dist/providers/overflow/index.d.ts",
112
116
  "import": "./dist/providers/overflow/index.js"
@@ -115,6 +119,10 @@
115
119
  "types": "./dist/providers/planning-center/index.d.ts",
116
120
  "import": "./dist/providers/planning-center/index.js"
117
121
  },
122
+ "./providers/quickbooks": {
123
+ "types": "./dist/providers/quickbooks/index.d.ts",
124
+ "import": "./dist/providers/quickbooks/index.js"
125
+ },
118
126
  "./providers/sheets": {
119
127
  "types": "./dist/providers/sheets/index.d.ts",
120
128
  "import": "./dist/providers/sheets/index.js"
@@ -167,8 +175,6 @@
167
175
  "test:browser:install": "playwright install chromium",
168
176
  "test:browser": "playwright test",
169
177
  "test:browser:snapshots": "node scripts/update-operator-snapshots.mjs",
170
- "goldens:update": "node scripts/update-goldens.mjs",
171
- "pregoldens:update": "node scripts/generate-version.mjs && pnpm run build:operator-ui",
172
178
  "pretest:browser:snapshots": "pnpm run build:operator-ui",
173
179
  "test:node": "vitest run --config vitest.config.node.ts",
174
180
  "test:workers": "vitest run --project workers",
@@ -185,9 +191,11 @@
185
191
  "eval:selftest": "tsx eval/selftest.ts",
186
192
  "eval:agent": "tsx eval/run-agent.ts",
187
193
  "eval:smoke": "tsx eval/run-smoke.ts",
194
+ "eval:outcomes": "tsx eval/run-outcomes.ts",
195
+ "preeval:outcomes": "node scripts/generate-version.mjs && pnpm run build:operator-ui",
188
196
  "eval:perf": "tsx eval/run-perf.ts",
189
197
  "eval:report": "tsx eval/report.ts",
190
- "check:static": "node --test scripts/check-provider-exemptions.test.mjs && pnpm run format:check && pnpm run check:providers-generated && pnpm run check:docs && pnpm run check:changes && pnpm run check:operator-ui && pnpm run check:clerk-sdk && pnpm run check:lint && pnpm run check:unused && pnpm run typecheck",
198
+ "check:static": "pnpm run format:check && pnpm run check:providers-generated && pnpm run check:docs && pnpm run check:changes && pnpm run check:operator-ui && pnpm run check:clerk-sdk && pnpm run check:lint && pnpm run check:unused && pnpm run typecheck",
191
199
  "check:build": "pnpm run build && pnpm run check:declarations && pnpm run check:bundle",
192
200
  "check:fast": "pnpm run check:static && vitest run --config vitest.config.node.ts --changed origin/main --passWithNoTests",
193
201
  "check": "pnpm run check:static && pnpm run test && pnpm run check:build",
@@ -252,11 +260,7 @@
252
260
  "@fontsource-variable/jetbrains-mono": "^5.3.0",
253
261
  "@playwright/test": "^1.62.0",
254
262
  "@radix-ui/react-dialog": "^1.2.0",
255
- "@radix-ui/react-slot": "^1.4.0",
256
263
  "@radix-ui/react-tabs": "^1.1.22",
257
- "@tailwindcss/node": "^4.3.3",
258
- "@tailwindcss/oxide": "^4.3.3",
259
- "@tanstack/react-query": "^5.104.1",
260
264
  "@tanstack/react-router": "^1.170.41",
261
265
  "@types/node": "^22.0.0",
262
266
  "@types/react": "^19.3.0",
@@ -270,7 +274,6 @@
270
274
  "quickjs-emscripten": "^0.32.0",
271
275
  "react": "^19.3.0",
272
276
  "react-dom": "^19.3.0",
273
- "tailwindcss": "^4.3.3",
274
277
  "tsx": "^4.23.1",
275
278
  "typescript": "^5.9.3",
276
279
  "undici": "6.29.1",
@@ -18,7 +18,7 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@clerk/backend": "^3.12.0",
21
- "@zackbart/connecta": "0.35.0",
21
+ "@zackbart/connecta": "0.36.1",
22
22
  "quickjs-emscripten": "0.32.0",
23
23
  "undici": "6.29.1"
24
24
  },
@@ -1,75 +0,0 @@
1
- import type { OperatorAgent, OperatorUiContractV2 } from "./contract.js";
2
- import { type Notice, type RequestFailureFacts, type Tone } from "./view.js";
3
- /**
4
- * The Tokens page's rows, computed from the slot list and contract v2 alone.
5
- * Agents are declared in code: a row's only controls are its token's issue,
6
- * rotate and revoke, so nothing here creates, renames or rebinds one.
7
- */
8
- /** One declared agent's token slot, as `GET /ui/access-tokens` returns it. */
9
- export type AgentSlot = ({
10
- name: string;
11
- state: "none";
12
- } | {
13
- name: string;
14
- state: "issued";
15
- issuedAt: string;
16
- } | {
17
- name: string;
18
- state: "revoked";
19
- revokedAt: string;
20
- }) & {
21
- /**
22
- * The route's opaque slot revision; it changes on every slot commit (P3b,
23
- * #837). A slot read without one is unresolved and never acted on.
24
- */
25
- revision?: string;
26
- };
27
- /** Issue and rotate are the same request; the slot's state names it. */
28
- export type SlotAction = "issue" | "rotate" | "revoke";
29
- export interface AgentRow {
30
- name: string;
31
- /** Pools it belongs to, from `agents[].pools`; empty when the contract does not list it. */
32
- pools: string[];
33
- credentialTypes: OperatorAgent["credentialTypes"];
34
- slot: AgentSlot | null;
35
- /**
36
- * Whether `slot` comes from the live slot list. Only a live slot can be
37
- * acted on: one known only from the contract may be stale, so its controls
38
- * are disabled until a refresh lists it.
39
- */
40
- live: boolean;
41
- /** Why its controls are off, or null when they work. */
42
- blocked: string | null;
43
- /** Its latest activity row; null is "never" (or history that is off). */
44
- lastSeenAt: string | null;
45
- actions: SlotAction[];
46
- }
47
- export declare function slotActions(slot: Pick<AgentSlot, "state">): SlotAction[];
48
- /**
49
- * One agent's slot, resolved once for both what the row shows and what an
50
- * action may do. The live slot list is authoritative; the contract's copy is
51
- * shown only for an agent the list does not have, and is never acted on.
52
- */
53
- export declare function resolveSlot(contract: OperatorUiContractV2 | null, slots: AgentSlot[], name: string): {
54
- slot: AgentSlot;
55
- live: boolean;
56
- } | null;
57
- /**
58
- * One row per declared agent, in the slot list's order, then any agent only
59
- * the contract lists. The contract adds pools and last seen.
60
- */
61
- export declare function agentRows(contract: OperatorUiContractV2 | null, slots: AgentSlot[], unresolved?: readonly string[]): AgentRow[];
62
- export declare function slotBadge(slot: Pick<AgentSlot, "state"> | null): {
63
- label: string;
64
- tone: Tone;
65
- };
66
- /** When the slot last changed, issued or revoked (its badge says which); a dash when it never has. */
67
- export declare function slotSince(slot: AgentSlot | null, format: (value: string) => string): string;
68
- export declare function lastSeenLabel(lastSeenAt: string | null, format: (value: string) => string): string;
69
- /**
70
- * Why a token operation did not land, in fixed sentences keyed by status.
71
- * `outcome_unknown` (503) and `aborted` (499) are failures like any other and
72
- * are never retried for the operator: an unknown rotation returned no secret,
73
- * and only a new, deliberate rotation produces one.
74
- */
75
- export declare function tokenFailureNotice(action: SlotAction, name: string, facts: RequestFailureFacts, productName: string): Notice;