@zackbart/connecta 0.40.0 → 0.42.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.
- package/CHANGELOG.md +148 -0
- package/bin/connecta.mjs +26 -17
- package/bin/meta-tool-names.d.mts +3 -1
- package/bin/meta-tool-names.mjs +4 -1
- package/bin/version.mjs +1 -1
- package/dist/activity.d.ts +32 -5
- package/dist/activity.js +32 -6
- package/dist/advertised-schema.js +15 -0
- package/dist/agent-observation.js +24 -2
- package/dist/agent-routes.js +33 -44
- package/dist/auth/clerk.d.ts +6 -1
- package/dist/auth/clerk.js +16 -0
- package/dist/auth/cloudflare-access.js +49 -7
- package/dist/auth/downstream-oauth/consent.js +79 -29
- package/dist/auth/downstream-oauth/grant-store.js +58 -7
- package/dist/auth/downstream-oauth/refresh-coordinator.js +4 -1
- package/dist/auth/downstream-oauth/refresh-records.js +6 -5
- package/dist/auth/downstream-oauth.js +15 -4
- package/dist/auth/oauth-request-not-sent.js +4 -0
- package/dist/auth/static-oauth.js +77 -39
- package/dist/auth-elicitation.js +118 -61
- package/dist/authorization-handoff.js +36 -3
- package/dist/catalog-cache.js +352 -43
- package/dist/catalog-freshness.js +25 -0
- package/dist/catalog-service.js +408 -78
- package/dist/catalog.js +216 -62
- package/dist/config-defaults.d.ts +2 -1
- package/dist/config-defaults.js +4 -1
- package/dist/config.d.ts +53 -21
- package/dist/config.js +56 -17
- package/dist/connectors/remote-mcp/call.js +1 -1
- package/dist/connectors/remote-mcp/catalog.js +52 -28
- package/dist/connectors/remote-mcp/connection.js +113 -22
- package/dist/connectors/remote-mcp/oauth.js +2 -2
- package/dist/connectors/remote-mcp/resources.js +5 -2
- package/dist/connectors/remote-mcp/transport.js +24 -6
- package/dist/connectors/remote-mcp.js +14 -5
- package/dist/credential-contract.d.ts +3 -1
- package/dist/describe-config.d.ts +4 -2
- package/dist/describe-config.js +1 -0
- package/dist/discovery-health.js +26 -11
- package/dist/downstream-input.js +11 -2
- package/dist/errors.d.ts +60 -4
- package/dist/errors.js +88 -3
- package/dist/execute.js +491 -202
- package/dist/executor-admission.js +2 -0
- package/dist/executor-contract.js +6 -0
- package/dist/executor-result.js +3 -3
- package/dist/executors/quickjs-child.js +14 -5
- package/dist/executors/quickjs-runtime.d.ts +2 -0
- package/dist/executors/quickjs-runtime.js +37 -20
- package/dist/executors/quickjs.js +24 -7
- package/dist/guarded-transport.js +2 -0
- package/dist/guest-functions.js +5 -4
- package/dist/guest-runtime.js +37 -1
- package/dist/guest-types.d.ts +18 -0
- package/dist/http/client.js +14 -2
- package/dist/http/errors.js +9 -4
- package/dist/http/fields.js +17 -5
- package/dist/http/hatch.js +11 -3
- package/dist/http/node-transport.js +110 -4
- package/dist/http/oauth.js +17 -6
- package/dist/http/paging.js +1 -1
- package/dist/http/provider.js +2 -6
- package/dist/http/vendor.js +6 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +15 -21
- package/dist/invocation-failure.js +28 -0
- package/dist/invocation.js +167 -64
- package/dist/membership.d.ts +1 -1
- package/dist/meta-output.js +24 -18
- package/dist/meta-tool-names.d.ts +1 -1
- package/dist/meta-tool-names.js +1 -1
- package/dist/meta-tools.js +286 -73
- package/dist/module-contracts.d.ts +3 -1
- package/dist/native-recovery.js +4 -1
- package/dist/native-tools.js +177 -55
- package/dist/node.d.ts +7 -0
- package/dist/node.js +85 -4
- package/dist/oauth-handoff.js +53 -43
- package/dist/operation-activity.js +104 -0
- package/dist/operation-vocabulary.js +6 -0
- package/dist/operator-record.d.ts +9 -1
- package/dist/operator-record.js +16 -0
- package/dist/operator-ui/generated.js +2 -2
- package/dist/program-result.js +2 -0
- package/dist/program-source.js +1 -1
- package/dist/program-writes.js +112 -19
- package/dist/provider.d.ts +1 -14
- package/dist/provider.js +0 -3
- package/dist/providers/_shared/google/kit.js +2 -2
- package/dist/providers/_shared/google/workspace.d.ts +1 -1
- package/dist/providers/breeze/api.js +2 -2
- package/dist/providers/breeze/index.js +1 -1
- package/dist/providers/breeze/skill.generated.js +1 -1
- package/dist/providers/ccb/api.js +2 -2
- package/dist/providers/ccb/index.js +1 -1
- package/dist/providers/ccb/skill.generated.js +1 -1
- package/dist/providers/cloudflare/api.js +2 -2
- package/dist/providers/cloudflare/index.js +3 -1
- package/dist/providers/cloudflare/skill.generated.js +1 -1
- package/dist/providers/docs/index.js +1 -1
- package/dist/providers/docs/skill.generated.js +1 -1
- package/dist/providers/drive/index.js +1 -1
- package/dist/providers/drive/skill.generated.js +1 -1
- package/dist/providers/forms/index.js +2 -1
- package/dist/providers/forms/skill.generated.js +1 -1
- package/dist/providers/github/api.js +98 -6
- package/dist/providers/github/index.js +8 -3
- package/dist/providers/github/lib/auth.d.ts +3 -1
- package/dist/providers/github/lib/auth.js +43 -12
- package/dist/providers/github/lib/discovery.js +11 -1
- package/dist/providers/github/lib/operations.js +8 -0
- package/dist/providers/github/safety.js +39 -0
- package/dist/providers/github/skill.generated.js +1 -1
- package/dist/providers/github/tools.js +12 -5
- package/dist/providers/gmail/index.js +2 -1
- package/dist/providers/gmail/skill.generated.js +1 -1
- package/dist/providers/granola/index.js +1 -1
- package/dist/providers/granola/skill.generated.js +1 -1
- package/dist/providers/overflow/index.js +3 -1
- package/dist/providers/overflow/skill.generated.js +1 -1
- package/dist/providers/planning-center/index.js +12 -6
- package/dist/providers/planning-center/lib/constants.d.ts +1 -1
- package/dist/providers/planning-center/skill.generated.js +1 -1
- package/dist/providers/quickbooks/api.js +28 -25
- package/dist/providers/quickbooks/index.js +3 -6
- package/dist/providers/quickbooks/lib/writes.js +55 -0
- package/dist/providers/quickbooks/safety.js +17 -5
- package/dist/providers/quickbooks/skill.generated.js +1 -1
- package/dist/providers/sheets/index.js +2 -1
- package/dist/providers/sheets/skill.generated.js +1 -1
- package/dist/providers/slides/index.js +3 -3
- package/dist/providers/slides/skill.generated.js +1 -1
- package/dist/providers/stripe/index.js +2 -2
- package/dist/providers/stripe/skill.generated.js +1 -1
- package/dist/providers/tithely/index.js +2 -1
- package/dist/providers/tithely/skill.generated.js +1 -1
- package/dist/providers/vercel/api.js +3 -2
- package/dist/providers/vercel/skill.generated.js +1 -1
- package/dist/registry.d.ts +36 -4
- package/dist/registry.js +142 -30
- package/dist/resource-read.js +21 -2
- package/dist/result-preview.js +210 -0
- package/dist/result-seal.js +168 -0
- package/dist/route-names.js +53 -0
- package/dist/routes/activity-context.js +1 -0
- package/dist/routes/activity-disclosure.js +26 -4
- package/dist/routes/activity.js +2 -1
- package/dist/routes/connect.js +21 -13
- package/dist/routes/mcp.js +83 -35
- package/dist/routes/shared.d.ts +6 -0
- package/dist/routes/ui-config.js +1 -1
- package/dist/routes/ui-data.js +3 -2
- package/dist/runtime/call.js +15 -10
- package/dist/runtime/native-storage.js +12 -0
- package/dist/runtime/request-reads.js +66 -14
- package/dist/runtime/request-scope.js +38 -2
- package/dist/runtime/run.js +4 -1
- package/dist/sent-secrets.d.ts +20 -0
- package/dist/sent-secrets.js +49 -1
- package/dist/skill-origin.js +16 -0
- package/dist/skills.js +213 -57
- package/dist/storage/d1-driver.js +33 -5
- package/dist/storage/keys.js +16 -7
- package/dist/storage/sql-native.js +60 -3
- package/dist/storage/sql.js +6 -0
- package/dist/timing-trace.js +84 -0
- package/dist/tool-safety.d.ts +33 -0
- package/dist/tool-safety.js +51 -15
- package/dist/types.d.ts +36 -0
- package/dist/url-safety.js +38 -20
- package/dist/usage-guide.js +14 -13
- package/dist/utility-recovery.js +33 -0
- package/dist/validate.js +29 -10
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/worker.js +60 -15
- package/documentation/architecture.md +152 -43
- package/documentation/auth.md +160 -53
- package/documentation/code-mode.md +396 -119
- package/documentation/deploying.md +35 -10
- package/documentation/hosted-mcp-migration.md +9 -3
- package/documentation/integrating.md +27 -5
- package/documentation/meta-tools.md +761 -157
- package/documentation/operating.md +91 -4
- package/documentation/operator-ui.md +51 -2
- package/documentation/providers.md +34 -20
- package/examples/worker/README.md +3 -3
- package/guides/how-it-works.md +2 -1
- package/guides/safety-and-trust.md +1 -3
- package/package.json +10 -8
- package/templates/node/AGENTS.md +3 -3
- package/templates/node/README.md +1 -1
- package/templates/node/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
2
|
export const skill = {
|
|
3
|
-
"content": "## Accessible meeting records\n\nWorkspace keys reach public workspace notes and spaces explicitly enabled for\nGranola API access. Folder permissions inherit their space's setting. They do\nnot grant unrelated private notes. Only notes with a generated AI summary and\ntranscript appear; a missing result does not establish that a meeting never\nhappened. The owner's private handwritten notes are null for workspace keys.\n\nDiscover actual note, folder and space IDs. API IDs use not_, fol_ and spa_\nprefixes; a web-link UUID, title or human name is not an API ID. Notes can\nbelong to several folders and spaces; folder parent_folder_id describes the\nhierarchy and space_id joins a folder to its space. Folder filtering includes\ndescendant folders. Null space_id can also mean an inaccessible space.\n\nOperation search searches the API contract, not meeting content. The REST API\noffers date, folder and space filters, with no natural-language meeting search.\nFilter accessible notes and inspect their contents to answer a topic question;\ndisclose the period and scope examined.\n\n## Transcript interpretation\n\nInline transcripts are optional. If including one fails with HTTP 413\n(TRANSCRIPT_TOO_LARGE), read note details without include and retrieve the\nseparate transcript endpoint through its complete continuation sequence. No\npartial transcript proves a complete quotation or count. An empty page can\nstill have a continuation; follow the returned paging state.\n\nSpeaker source describes the audio input, not a person's identity. macOS may\ndistinguish microphone from speaker audio. iOS currently uses microphone and\nmay supply anonymous diarization labels; do not invent attendee attribution.\nPreserve start/end timestamps when quoting. Summaries are AI-generated, so\nconfirm important wording against the transcript. Return only the relevant\npassages and identifying meeting metadata.\n\n## Conventions\n\n- **
|
|
3
|
+
"content": "## Accessible meeting records\n\nWorkspace keys reach public workspace notes and spaces explicitly enabled for\nGranola API access. Folder permissions inherit their space's setting. They do\nnot grant unrelated private notes. Only notes with a generated AI summary and\ntranscript appear; a missing result does not establish that a meeting never\nhappened. The owner's private handwritten notes are null for workspace keys.\n\nDiscover actual note, folder and space IDs. API IDs use not_, fol_ and spa_\nprefixes; a web-link UUID, title or human name is not an API ID. Notes can\nbelong to several folders and spaces; folder parent_folder_id describes the\nhierarchy and space_id joins a folder to its space. Folder filtering includes\ndescendant folders. Null space_id can also mean an inaccessible space.\n\nOperation search searches the API contract, not meeting content. The REST API\noffers date, folder and space filters, with no natural-language meeting search.\nFilter accessible notes and inspect their contents to answer a topic question;\ndisclose the period and scope examined.\n\n## Transcript interpretation\n\nInline transcripts are optional. If including one fails with HTTP 413\n(TRANSCRIPT_TOO_LARGE), read note details without include and retrieve the\nseparate transcript endpoint through its complete continuation sequence. No\npartial transcript proves a complete quotation or count. An empty page can\nstill have a continuation; follow the returned paging state.\n\nSpeaker source describes the audio input, not a person's identity. macOS may\ndistinguish microphone from speaker audio. iOS currently uses microphone and\nmay supply anonymous diarization labels; do not invent attendee attribution.\nPreserve start/end timestamps when quoting. Summaries are AI-generated, so\nconfirm important wording against the transcript. Return only the relevant\npassages and identifying meeting metadata.\n\n## Conventions\n\n- **Hatch:** `granola_api_search` finds operations, `granola_api_details` shows one contract, `granola_api_read` calls a reviewed read. 13 operations are refused by design; use `granola_api_details` with the method and path to see each summary and refusal, even for methods outside the read/write schemas.\n- **Errors:** An unknown id, or one these credentials cannot reach, fails as `connector_call_failed`; this API does not tell the two apart.",
|
|
4
4
|
"instructionsHeading": "Workspace instructions"
|
|
5
5
|
};
|
|
@@ -68,6 +68,8 @@ export const overflow = defineApiProvider({
|
|
|
68
68
|
pageSize: { default: DEFAULT_PAGE_SIZE, max: MAX_PAGE_SIZE },
|
|
69
69
|
credential: API_KEY_CREDENTIAL,
|
|
70
70
|
authenticate,
|
|
71
|
+
// docs.overflow.co/api-reference/authentication: "Public identifier"; x-api-key is the secret.
|
|
72
|
+
publicIdentifierHeaders: ["x-client-id"],
|
|
71
73
|
admit,
|
|
72
74
|
errors,
|
|
73
75
|
idempotencyKey: false,
|
|
@@ -87,7 +89,7 @@ export const overflow = defineApiProvider({
|
|
|
87
89
|
? [`Paged lists return ${options.defaultPageSize} items by default on this connection.`]
|
|
88
90
|
: []),
|
|
89
91
|
],
|
|
90
|
-
summary: "
|
|
92
|
+
summary: "Load for giving statuses, money units, donor joins and deposit reconciliation.",
|
|
91
93
|
required: true,
|
|
92
94
|
}),
|
|
93
95
|
hatch: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
2
|
export const skill = {
|
|
3
|
-
"content": "## Giving records and joins\n\nDonor ids join profiles, contributions, subscriptions and payment methods.\nCampaigns and subcampaigns allocate gifts; locations identify campuses.\nResolve names to ids before editing a donor or moving money. There is no funds\nendpoint: fund and sub-fund identifiers occur only in payment authorization.\nA donor profile owned by a donor account cannot be edited through this API;\nwhen reads work but its edit is denied, changing the credential does not fix it.\n\nTap groups contain devices and point to destinations. A tap is engagement,\nnot a gift; use contributions to establish giving.\n\n## Money and final status\n\nRead the unit per field. Values named `InCents` are cents, including deposits,\nrefunds, chargebacks and payment authorization. Subscription `amount` is\nin dollars. Contribution and saved-method charge `amount` have no stated unit\nin the public schema: establish it from a known gift before reporting a sum\nor authorizing a charge. Do not assume every numeric amount uses the same unit.\n\nA gift is final at `PAID_OUT` for `CASH`, `CONFIRMED` for manual cash or crypto,\n`CONTRIBUTION_RECEIVED` or `BILLED` for stock, and `CONTRIBUTION_RECEIVED` for\nDAF. A status bucket is coarser than those asset-specific states. Polling by\nupdated date finds later state changes; initiated date identifies when a donor gave.\n\n## Reconcile a deposit\n\nFind the bank payout, inspect its summary totals, then its line items.\nEach line item's `referenceId` names a contribution, refund or chargeback\naccording to its type; contributions can also carry a `depositId`.\nKeep gross, fee and net cent amounts separate and convert only for presentation.\nAn eligible cash gift under $1,000 is refunded with `POST /contributions/{contributionId}/initiate-refund`, which takes no body; its string acknowledgement means the refund started.\nA refund request starts processing; verify the gift or refund before claiming\nthat funds have reached the donor. Canceling a recurring gift stops future\npayments and does not refund earlier gifts.\n\n## Reduce donor and delivery data\n\nGiving history and donor contact details are personal data. Aggregate or join\ninside code and return names, email, phone and address only when the task needs\nthem. Lean contribution rows carry donor identity; the full donor lookup\ncarries contact details. Webhook delivery logs can include delivered donor\npayloads and the receiving server's response: select the status, response code\nand error needed for diagnosis instead of returning those payloads wholesale.\n\n## Conventions\n\n- **
|
|
3
|
+
"content": "## Giving records and joins\n\nDonor ids join profiles, contributions, subscriptions and payment methods.\nCampaigns and subcampaigns allocate gifts; locations identify campuses.\nResolve names to ids before editing a donor or moving money. There is no funds\nendpoint: fund and sub-fund identifiers occur only in payment authorization.\nA donor profile owned by a donor account cannot be edited through this API;\nwhen reads work but its edit is denied, changing the credential does not fix it.\n\nTap groups contain devices and point to destinations. A tap is engagement,\nnot a gift; use contributions to establish giving.\n\n## Money and final status\n\nRead the unit per field. Values named `InCents` are cents, including deposits,\nrefunds, chargebacks and payment authorization. Subscription `amount` is\nin dollars. Contribution and saved-method charge `amount` have no stated unit\nin the public schema: establish it from a known gift before reporting a sum\nor authorizing a charge. Do not assume every numeric amount uses the same unit.\n\nA gift is final at `PAID_OUT` for `CASH`, `CONFIRMED` for manual cash or crypto,\n`CONTRIBUTION_RECEIVED` or `BILLED` for stock, and `CONTRIBUTION_RECEIVED` for\nDAF. A status bucket is coarser than those asset-specific states. Polling by\nupdated date finds later state changes; initiated date identifies when a donor gave.\n\n## Reconcile a deposit\n\nFind the bank payout, inspect its summary totals, then its line items.\nEach line item's `referenceId` names a contribution, refund or chargeback\naccording to its type; contributions can also carry a `depositId`.\nKeep gross, fee and net cent amounts separate and convert only for presentation.\nAn eligible cash gift under $1,000 is refunded with `POST /contributions/{contributionId}/initiate-refund`, which takes no body; its string acknowledgement means the refund started.\nA refund request starts processing; verify the gift or refund before claiming\nthat funds have reached the donor. Canceling a recurring gift stops future\npayments and does not refund earlier gifts.\n\n## Reduce donor and delivery data\n\nGiving history and donor contact details are personal data. Aggregate or join\ninside code and return names, email, phone and address only when the task needs\nthem. Lean contribution rows carry donor identity; the full donor lookup\ncarries contact details. Webhook delivery logs can include delivered donor\npayloads and the receiving server's response: select the status, response code\nand error needed for diagnosis instead of returning those payloads wholesale.\n\n## Conventions\n\n- **Hatch:** `overflow_api_search` finds operations, `overflow_api_details` shows one contract, `overflow_api_read` calls a reviewed read and `overflow_api_write` a reviewed write.\n- **Errors:** `not_found` means the record does not exist; this API tells absence from a permission gap.",
|
|
4
4
|
"instructionsHeading": "Nonprofit instructions"
|
|
5
5
|
};
|
|
@@ -36,15 +36,21 @@ export const planningCenter = defineApiProvider({
|
|
|
36
36
|
safety: () => safety,
|
|
37
37
|
probe,
|
|
38
38
|
blocks: {
|
|
39
|
-
keys: [...PLANNING_CENTER_APPS, "lists", "limited"],
|
|
40
|
-
select: (options) =>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
keys: [...PLANNING_CENTER_APPS, "lists", "limited", "people-writes", "giving-writes", "api-writes"],
|
|
40
|
+
select: (options) => {
|
|
41
|
+
const apps = PLANNING_CENTER_APPS.filter((app) => !excludedApps(options.excludeApps).has(app));
|
|
42
|
+
return [
|
|
43
|
+
...apps,
|
|
44
|
+
excludedApps(options.excludeApps).size === 0 ? "lists" : "limited",
|
|
45
|
+
...(options.readOnly
|
|
46
|
+
? []
|
|
47
|
+
: ["people", "giving", "api"].filter((app) => apps.includes(app)).map((app) => `${app}-writes`)),
|
|
48
|
+
];
|
|
49
|
+
},
|
|
44
50
|
},
|
|
45
51
|
guide: (options) => ({
|
|
46
52
|
heading: "Planning Center usage",
|
|
47
|
-
summary: "
|
|
53
|
+
summary: "Load when joining Planning Center products by person id or interpreting dates, units, roles and statuses.",
|
|
48
54
|
required: true,
|
|
49
55
|
context: [
|
|
50
56
|
`Purpose: ${options.purpose.trim()}`,
|
|
@@ -55,4 +55,4 @@ export declare const PLANNING_CENTER_MAX_RESPONSE_BYTES: number;
|
|
|
55
55
|
*/
|
|
56
56
|
export declare const PLANNING_CENTER_ADMISSION: ConnectorCallAdmissionPolicy;
|
|
57
57
|
/** Planning Center refuses a request without a descriptive one (HTTP 403). */
|
|
58
|
-
export declare const DEFAULT_USER_AGENT = "connecta/0.
|
|
58
|
+
export declare const DEFAULT_USER_AGENT = "connecta/0.42.0 (+https://github.com/zackbart/connecta)";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
2
|
export const skill = {
|
|
3
|
-
"content": "## Identity first\n\
|
|
3
|
+
"content": "## Identity first\n\nThe People person id joins products; names repeat, so join on `person_id`.\nMemberships, scheduled people and workflow cards have their own ids. `get_me`\ngives the organization's time zone: bare dates mean its local day, and exact\nboundaries need an offset. Name filters are exact unless the value ends in `%`.\n\nAn old person id may be merged: read `/people/v2/person_mergers` with\n`where[person_to_remove_id]` and follow `person_to_keep_id`. An empty history\ndoes not prove no merge happened.\n\nPastoral data: reduce inside `execute_code` and return aggregates unless the task\nneeds named people. Named reads omit some fields; read the indexed record when the\ntask needs them.\n\n<!-- when: people -->\n## People\n\nWorkflow cards join people to a workflow and its ordered steps. Custom values and\nform answers need their field records for names and types.\n<!-- end -->\n\n<!-- when: people-writes -->\nAn omitted attribute stays; `null` clears it. Archiving is reversible; deleting a\nprofile is permanent. Resolve the card id and its person id before acting on a\nworkflow card. Promoting completes a step; skipping moves on without completing\nit. Card notes and profile notes are different records, and note categories can\nnotify subscribers. No named form-submission tool exists; the generic hatch\nadmits that endpoint as a destructive operation.\n<!-- end -->\n\n<!-- when: lists -->\nSaved lists are only as fresh as their last refresh. Refreshing can fire\nautomations, such as adding someone to a workflow, so it is a write even for a count.\n<!-- end -->\n\n<!-- when: services -->\n## Services\n\nResolve the service type before a dated plan; plan times define its service dates.\nA cut `get_plan` section reads through its indexed items or team-members path. Item\ndurations are seconds. Schedule status: `C` confirmed, `U` unconfirmed, `D`\ndeclined. Preparing a notification and sending it are different actions. Services\ncannot upload a file through this connection.\n<!-- end -->\n\n<!-- when: groups -->\n## Groups\n\nMemberships distinguish leaders from members but carry no person attributes;\n`include=person` supplies names, and the person id supplies contact details.\n<!-- end -->\n\n<!-- when: check-ins -->\n## Check-Ins\n\nAn event recurs; its period is a dated occurrence. Period counts are the efficient\nattendance answer. Date filters use the period start, not the check-in creation time.\n<!-- end -->\n\n<!-- when: calendar -->\n## Calendar\n\nEvent instances expand recurrence. A booking can return a `BookedEvent` stub when\nthe user lacks access to its event.\n<!-- end -->\n\n<!-- when: registrations -->\n## Registrations\n\nAttendee records join to People and separate active, waitlisted and canceled attendees.\n<!-- end -->\n\n<!-- when: giving -->\n## Giving\n\nAmounts are integer cents with a currency. Designations split a donation across\nfunds, so never count a donation once per designation. Recurring schedules and the\ndonations they produce are different records. Named giving tools only read.\n<!-- end -->\n\n<!-- when: giving-writes -->\nCreating, editing or refunding a donation or committing a batch changes financial\nrecords.\n<!-- end -->\n\n<!-- when: publishing -->\n## Publishing\n\nA Church Center link and a media resource are different records; use the one the\ntask asks for.\n<!-- end -->\n\n<!-- when: webhooks -->\n## Webhooks\n\nSigning keys, private destinations and event payloads stay withheld; status and\nevent metadata remain available for audits.\n<!-- end -->\n\n<!-- when: api -->\n## Organization API\n\nToken inventory never returns values.\n<!-- end -->\n\n<!-- when: api-writes -->\nRevoking a token is a write that may break another integration, including this\nconnection.\n<!-- end -->\n\n<!-- when: limited -->\n## Product boundary\n\nSome products are unavailable. A new webhook subscription must name a reachable\nproduct's event. Stored workflow cards, notes, custom fields and form answers stay\nreadable and may contain copied information; provenance is not inferred.\n<!-- end -->\n\n## Conventions\n\n- **Hatch:** `pco_api_search` finds operations, `pco_api_details` shows one contract, `pco_api_read` calls a reviewed read and `pco_api_write` a reviewed write. 2 operations are refused by design; use `pco_api_details` with the method and path to see each summary and refusal, even for methods outside the read/write schemas.\n- **Errors:** `not_found` means the record does not exist; this API tells absence from a permission gap. `conflict` means: HTTP 409 for duplicate records in People.",
|
|
4
4
|
"instructionsHeading": "Organization instructions"
|
|
5
5
|
};
|
|
@@ -58,32 +58,35 @@ export const customerWrite = post("writeCustomer", "/customer", {
|
|
|
58
58
|
}).annotate(Summary, "Create a customer or sparsely update naming fields through named tools only");
|
|
59
59
|
export const invoiceWrite = post("createInvoice", "/invoice", {
|
|
60
60
|
query: { minorversion: Schema.Literal("75"), requestid: Schema.String },
|
|
61
|
-
payload: Schema.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
61
|
+
payload: Schema.Union([
|
|
62
|
+
Schema.Struct({
|
|
63
|
+
CustomerRef: Schema.Struct({ value: PublicId }),
|
|
64
|
+
CurrencyRef: Schema.Struct({ value: Schema.String }),
|
|
65
|
+
ExchangeRate: Schema.Number,
|
|
66
|
+
TxnDate: Schema.String,
|
|
67
|
+
DueDate: Schema.String,
|
|
68
|
+
DocNumber: Schema.String,
|
|
69
|
+
Line: Schema.Array(Schema.Struct({
|
|
70
|
+
Amount: Schema.Number,
|
|
71
|
+
DetailType: Schema.Literal("SalesItemLineDetail"),
|
|
72
|
+
SalesItemLineDetail: Schema.Struct({
|
|
73
|
+
ItemRef: Schema.Struct({ value: PublicId }),
|
|
74
|
+
Qty: Schema.Literal(1),
|
|
75
|
+
UnitPrice: Schema.Number,
|
|
76
|
+
}),
|
|
77
|
+
})),
|
|
78
|
+
EmailStatus: Schema.Literal("NotSet"),
|
|
79
|
+
AllowIPNPayment: Schema.Literal(false),
|
|
80
|
+
AllowOnlinePayment: Schema.Literal(false),
|
|
81
|
+
AllowOnlineCreditCardPayment: Schema.Literal(false),
|
|
82
|
+
AllowOnlineACHPayment: Schema.Literal(false),
|
|
83
|
+
AllowOnlinePayPalPayment: Schema.Literal(false),
|
|
84
|
+
AllowOnlineAffirmPayment: Schema.Literal(false),
|
|
85
|
+
}),
|
|
86
|
+
Schema.Struct({ Id: PublicId, SyncToken, sparse: Schema.Literal(true), DocNumber: Schema.String }),
|
|
87
|
+
]),
|
|
85
88
|
success: Schema.Struct({ Invoice: RecordShape }),
|
|
86
|
-
}).annotate(Summary, "Create
|
|
89
|
+
}).annotate(Summary, "Create an unsent service invoice or sparsely update an eligible unsent invoice number through named tools only");
|
|
87
90
|
export const QuickBooksApi = vendor("QuickBooks Online", companyInfo, queryRecords, customerWrite, invoiceWrite, ...Object.values(recordReads), ...Object.values(reportReads));
|
|
88
91
|
export const QUICKBOOKS_INDEX = vendorIndex(QuickBooksApi, {
|
|
89
92
|
prefix: "quickbooks",
|
|
@@ -54,15 +54,16 @@ export const quickbooks = defineApiProvider({
|
|
|
54
54
|
}),
|
|
55
55
|
describe: () => "Connected to the configured QuickBooks Online company.",
|
|
56
56
|
},
|
|
57
|
+
blocks: { keys: ["writes"], select: (options) => (options.readOnly === false ? ["writes"] : []) },
|
|
57
58
|
guide: (options) => ({
|
|
58
59
|
context: [
|
|
59
60
|
`Company ${options.realmId}, ${options.environment}: ${options.purpose}`,
|
|
60
61
|
options.readOnly === false
|
|
61
62
|
? "Bounded named writes are enabled. The API hatch remains read-only."
|
|
62
|
-
: "This connection is read-only
|
|
63
|
+
: "This connection is read-only; named writes are unavailable.",
|
|
63
64
|
"Contact details, bank/card/tax identifiers, credentials and private links are withheld on every read.",
|
|
64
65
|
],
|
|
65
|
-
summary: "QuickBooks
|
|
66
|
+
summary: "Load for QuickBooks accounting reads and enabled customer or service-invoice writes.",
|
|
66
67
|
required: true,
|
|
67
68
|
}),
|
|
68
69
|
hatch: {
|
|
@@ -85,9 +86,5 @@ export const quickbooks = defineApiProvider({
|
|
|
85
86
|
configurable: true,
|
|
86
87
|
});
|
|
87
88
|
},
|
|
88
|
-
transformGuide: (guide) => ({
|
|
89
|
-
...guide,
|
|
90
|
-
content: guide.content.replace("Writes take no idempotency key.", "Every named write requires requestId, sent as Intuit's requestid query parameter; no idempotencyKey header argument is accepted."),
|
|
91
|
-
}),
|
|
92
89
|
tools: quickbooksTools,
|
|
93
90
|
});
|
|
@@ -85,6 +85,61 @@ export function quickbooksWrites(connection, realmId) {
|
|
|
85
85
|
.send(customerWrite, { query: { ...version, requestid: requestId }, payload: { ...body, sparse: true } })
|
|
86
86
|
.pipe(Effect.map(({ data }) => namedRecord(object(data)["Customer"]))),
|
|
87
87
|
}),
|
|
88
|
+
write(connection, {
|
|
89
|
+
name: "update_unsent_invoice",
|
|
90
|
+
destructive: true,
|
|
91
|
+
idempotent: false,
|
|
92
|
+
description: "Sparsely change only DocNumber on an observed unsent US-company USD invoice. Requires caller-observed Id and SyncToken. Preflight refuses unknown, send-ready, delivered or payment-enabled state and stale versions. No delivery/payment settings are changed. Reconcile unknown outcomes by reading the Id; never replay.",
|
|
93
|
+
input: Schema.Struct({
|
|
94
|
+
requestId: RequestId,
|
|
95
|
+
Id: PublicId,
|
|
96
|
+
SyncToken,
|
|
97
|
+
docNumber: Schema.String.check(matches("^[A-Za-z0-9][A-Za-z0-9_-]{0,20}$")),
|
|
98
|
+
}),
|
|
99
|
+
check: (args, problems) => {
|
|
100
|
+
if (args.docNumber === "AUTO_GENERATE")
|
|
101
|
+
problems.add("docNumber", "an explicit document number other than AUTO_GENERATE");
|
|
102
|
+
},
|
|
103
|
+
output: NamedRecordShape,
|
|
104
|
+
writeSteps: { company: "once", invoice: "once", write: "once" },
|
|
105
|
+
run: (args) => Effect.gen(function* () {
|
|
106
|
+
const company = object(object((yield* connection.send(companyInfo, { params: { id: realmId }, query: version }, { step: "company", effect: "read" })).data)["CompanyInfo"]);
|
|
107
|
+
if (company["Id"] !== realmId || company["Country"] !== "US")
|
|
108
|
+
return yield* refuse("Invoice number updates require a verified US company.");
|
|
109
|
+
yield* charge;
|
|
110
|
+
const invoice = object(object((yield* connection.send(recordReads["invoices"], { params: { id: args.Id }, query: version }, { step: "invoice", effect: "read" })).data)["Invoice"]);
|
|
111
|
+
if (invoice["Id"] !== args.Id || invoice["SyncToken"] !== args.SyncToken)
|
|
112
|
+
return yield* refuse("Invoice version changed; read and review the current invoice before a new intent.");
|
|
113
|
+
if (invoice["EmailStatus"] !== "NotSet" ||
|
|
114
|
+
invoice["DeliveryInfo"] !== undefined ||
|
|
115
|
+
object(invoice["CurrencyRef"])["value"] !== "USD" ||
|
|
116
|
+
![
|
|
117
|
+
"AllowIPNPayment",
|
|
118
|
+
"AllowOnlinePayment",
|
|
119
|
+
"AllowOnlineCreditCardPayment",
|
|
120
|
+
"AllowOnlineACHPayment",
|
|
121
|
+
"AllowOnlinePayPalPayment",
|
|
122
|
+
"AllowOnlineAffirmPayment",
|
|
123
|
+
].every((key) => invoice[key] === false))
|
|
124
|
+
return yield* refuse("Only observed unsent USD invoices with explicit NotSet, no delivery information and all payment flags false qualify. Unknown state is refused.");
|
|
125
|
+
yield* charge;
|
|
126
|
+
const { data, status } = yield* connection.send(invoiceWrite, {
|
|
127
|
+
query: { ...version, requestid: args.requestId },
|
|
128
|
+
payload: { Id: args.Id, SyncToken: args.SyncToken, sparse: true, DocNumber: args.docNumber },
|
|
129
|
+
});
|
|
130
|
+
const updated = object(object(data)["Invoice"]);
|
|
131
|
+
if (updated["Id"] !== args.Id ||
|
|
132
|
+
updated["DocNumber"] !== args.docNumber ||
|
|
133
|
+
updated["SyncToken"] === args.SyncToken)
|
|
134
|
+
return yield* Effect.fail(new StatusFailure({
|
|
135
|
+
status,
|
|
136
|
+
headers: new Headers(),
|
|
137
|
+
body: undefined,
|
|
138
|
+
operation: { method: "POST", template: "/invoice" },
|
|
139
|
+
}));
|
|
140
|
+
return namedRecord(updated);
|
|
141
|
+
}),
|
|
142
|
+
}),
|
|
88
143
|
write(connection, {
|
|
89
144
|
name: "create_invoice",
|
|
90
145
|
destructive: true,
|
|
@@ -3,6 +3,13 @@ import { ConnectorCallError } from "../../errors.js";
|
|
|
3
3
|
import { withholdEmbeddedUrls } from "../_shared/rest/value-safety.js";
|
|
4
4
|
import { QUICKBOOKS_INDEX } from "./api.js";
|
|
5
5
|
const scalars = [
|
|
6
|
+
"EmailStatus",
|
|
7
|
+
"AllowIPNPayment",
|
|
8
|
+
"AllowOnlinePayment",
|
|
9
|
+
"AllowOnlineCreditCardPayment",
|
|
10
|
+
"AllowOnlineACHPayment",
|
|
11
|
+
"AllowOnlinePayPalPayment",
|
|
12
|
+
"AllowOnlineAffirmPayment",
|
|
6
13
|
"Id",
|
|
7
14
|
"SyncToken",
|
|
8
15
|
"DisplayName",
|
|
@@ -72,6 +79,7 @@ export const RecordShape = Schema.Struct({
|
|
|
72
79
|
...optional(scalars),
|
|
73
80
|
...optional(references),
|
|
74
81
|
...optional(details),
|
|
82
|
+
DeliveryInfo: Schema.optionalKey(Schema.Unknown),
|
|
75
83
|
MetaData: Schema.optionalKey(Schema.Unknown),
|
|
76
84
|
Line: Schema.optionalKey(Schema.Unknown),
|
|
77
85
|
LinkedTxn: Schema.optionalKey(Schema.Unknown),
|
|
@@ -128,6 +136,8 @@ function safeRecord(value) {
|
|
|
128
136
|
for (const key of references)
|
|
129
137
|
if (source[key])
|
|
130
138
|
out[key] = pick(source[key], ["value", "name", "type"]);
|
|
139
|
+
if (source["DeliveryInfo"] !== undefined)
|
|
140
|
+
out["DeliveryInfo"] = pick(source["DeliveryInfo"], ["DeliveryType", "DeliveryTime"]);
|
|
131
141
|
if (source["MetaData"])
|
|
132
142
|
out["MetaData"] = pick(source["MetaData"], ["CreateTime", "LastUpdatedTime"]);
|
|
133
143
|
for (const key of details)
|
|
@@ -197,11 +207,13 @@ function recordPath(path) {
|
|
|
197
207
|
return recordPath(rest);
|
|
198
208
|
const picked = head === "MetaData"
|
|
199
209
|
? ["CreateTime", "LastUpdatedTime"]
|
|
200
|
-
: head === "
|
|
201
|
-
? ["
|
|
202
|
-
:
|
|
203
|
-
? ["
|
|
204
|
-
:
|
|
210
|
+
: head === "DeliveryInfo"
|
|
211
|
+
? ["DeliveryType", "DeliveryTime"]
|
|
212
|
+
: head === "LinkedTxn"
|
|
213
|
+
? ["TxnId", "TxnType", "TxnLineId"]
|
|
214
|
+
: references.includes(head)
|
|
215
|
+
? ["value", "name", "type"]
|
|
216
|
+
: undefined;
|
|
205
217
|
if (!picked)
|
|
206
218
|
return "dropped";
|
|
207
219
|
if (rest.length === 0)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
2
|
export const skill = {
|
|
3
|
-
"content": "##
|
|
3
|
+
"content": "## Identity and joins\n\n`Id` identifies a record within this company and record family. `DocNumber` is a\nlabel that can repeat; never use it as an Id. `SyncToken` is the public record\nversion, not a credential. References carry the target Id in `value`: invoice\n`CustomerRef`, bill `VendorRef`, payment `Line.LinkedTxn`.\n\nPayment and BillPayment are accounting records; reading one executes nothing.\nDesktop, Payments, Payroll and attachments are outside this connection.\n\n## Money, time and reports\n\nAmounts are decimal currency units, not cents. Never sum unlike currencies;\npreserve `CurrencyRef` and `ExchangeRate`. `TxnDate` is an accounting date, not\na UTC instant; `MetaData` timestamps carry their own offset. Customer and vendor\nsearches omit inactive records unless `Active` selects them.\n\nReports are trees. Read column metadata with row values, because order and\nlabels can change. Empty amounts mean no value, not zero. Do not flatten sections\nor add totals to their component rows. Before comparing reports, check period,\nbasis, currency and `NoReportData`. Aging is an as-of snapshot, not a transaction\nrange.\n\nReturn aggregates and the few records the task needs, not full customer or\nvendor directories.\n\n<!-- when: writes -->\n## Writes\n\nDeletes, voids, email delivery, charges, refunds and other accounting writes are\nunavailable. `DisplayName` must be unique across customers, vendors and employees.\n\n**requestId.** Keep it stable for one exact intent and unique across requests\nand tools for this company. It never permits replay, and it is neither a lookup\nnor a lasting duplicate guarantee. Never generate a fresh one to repeat an intent\nthat may have committed.\n\n**create_invoice** creates a real transaction, never a draft, and creates no\ncustomer or item implicitly. First observe an active customer with its\n`CurrencyRef` and active Service item Ids. Nothing is defaulted, and amounts are\nstrings with exactly two decimals. QuickBooks computes taxes and totals, so inspect\nthe returned currency, rate and totals; line sums do not promise an untaxed total.\nCompany tax rules may still reject it. Preflight reads are not an atomic snapshot,\nand each spends call-admission budget. Contradictory returned values mean an\nunknown outcome.\n\n**Email.** No email or send operation exists; creation fixes `NotSet` and false\npayment flags, so it does not ask Intuit to email the invoice.\n`update_unsent_invoice` changes only `DocNumber` and refuses missing, send-ready\nor delivered state. `NotSet` cannot prove no earlier delivery occurred.\n\n**Stale versions.** A conflict never fetches or overwrites a newer version. Read\nand review the record before proposing another update.\n\n**Unknown outcome: reconcile, never resend.**\n\n- Customer: search the exact `DisplayName`, including inactive records.\n- Invoice: search `DocNumber` plus `CustomerRef`, then inspect currency, dates,\n lines and amounts. `DocNumber` alone proves nothing.\n- Update: read the known Id and its version.\n\nReport any ambiguity before considering another create.\n<!-- end -->\n\n## Conventions\n\n- **Hatch:** `quickbooks_api_search` finds operations, `quickbooks_api_details` shows one contract, `quickbooks_api_read` calls a reviewed read. 3 operations are refused by design; use `quickbooks_api_details` with the method and path to see each summary and refusal, even for methods outside the read/write schemas.\n- **Errors:** An unknown id, or one these credentials cannot reach, fails as `connector_call_failed`; this API does not tell the two apart. `conflict` means: Intuit fault 5010 for a stale SyncToken; Intuit fault 6240 for a duplicate DisplayName.",
|
|
4
4
|
"instructionsHeading": "Company instructions"
|
|
5
5
|
};
|
|
@@ -100,6 +100,7 @@ export const sheets = defineApiProvider({
|
|
|
100
100
|
errors,
|
|
101
101
|
safety: () => safety,
|
|
102
102
|
probe,
|
|
103
|
+
blocks: { keys: ["writes"], select: (options) => (options.readOnly ? [] : ["writes"]) },
|
|
103
104
|
guide: (options) => ({
|
|
104
105
|
context: [
|
|
105
106
|
`Purpose: ${options.purpose}`,
|
|
@@ -110,7 +111,7 @@ export const sheets = defineApiProvider({
|
|
|
110
111
|
...(options.readOnly ? ["This connection is read-only."] : []),
|
|
111
112
|
],
|
|
112
113
|
instructions: options.instructions,
|
|
113
|
-
summary: "
|
|
114
|
+
summary: "Load for spreadsheet A1 ranges, paged cells, RAW/USER_ENTERED writes and formatting.",
|
|
114
115
|
// Whose spreadsheets they are, how Drive finds them, and the cell-write
|
|
115
116
|
// meanings of null and "" are conventions no schema carries.
|
|
116
117
|
required: true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
2
|
export const skill = {
|
|
3
|
-
"content": "## Find the workbook and resolve ranges\n\nSheets starts from a spreadsheet id. A spreadsheet id the person gives works\nas is; search Drive only for a name. The Drive file id is\nthe spreadsheet id. Moving, sharing and trashing the file also belong to Drive.\nRead `get_spreadsheet` first to resolve sheet titles, numeric sheet ids and named\nranges before writing. Sheet id zero is valid; a tab's position is not its id.\n\nA1 ranges use sheet titles; structural GridRanges use numeric sheet ids with\nzero-based, end-exclusive row and column indexes. Quote titles containing\nspaces or punctuation and double apostrophes: `'Alice''s costs'!A1:D7`.\nA bare title may resolve to a named range; quote it to address the whole tab.\n\n## Read cell meaning\n\nDisplayed values reflect spreadsheet locale and number formats. Use\nunformatted numbers for arithmetic and formulas when inspecting expressions.\nDate serials count days from 1899-12-30; interpret dates using the workbook's\ntime zone. Trailing empty rows and cells may be absent. An empty range is a\nvalid result, not proof that the sheet is missing.\n\nWhole-row content reads can resume partway through a range. A named range or\nwhole-sheet reference may be re-read and earlier rows skipped; rowOffset is\nrelative to Google's echoed range. Reduce amounts inside execute_code before\nreturning them. Read an oversized cell separately to recover its full text.\n\n## Edit and reconcile\n\nUse RAW for external data; USER_ENTERED can turn leading equals signs into\nformulas. In cell writes, null leaves a cell unchanged and an empty string\nclears it. Clearing preserves formatting and validation. `append_values` is\npinned to INSERT_ROWS and inserts rows after the detected table. A vendor append using\nOVERWRITE can replace existing cells below that table.\n\nRead just before replacing another person's cells. Sheets has no revision\nprecondition or replay key: concurrent edits can be overwritten. After an\nuncertain append, read the target table and identify the row before adding\nanything missing. After an uncertain workbook create, search Drive by title\nbefore creating another workbook.\n\nStructural batches apply atomically, but can delete rows, sheets or\nprotections. An oversized reply may be summarized after the edit saved;\ninspect the workbook to recover details. Preview comment mutations and\nexternal data-source configuration, refresh and administration are outside\nthis connection. Developer-metadata searches and data-filter reads are\nread-only even though their wire method is POST.\n\n## Conventions\n\n- **
|
|
3
|
+
"content": "## Find the workbook and resolve ranges\n\nSheets starts from a spreadsheet id. A spreadsheet id the person gives works\nas is; search Drive only for a name. The Drive file id is\nthe spreadsheet id. Moving, sharing and trashing the file also belong to Drive.\nRead `get_spreadsheet` first to resolve sheet titles, numeric sheet ids and named\nranges before writing. Sheet id zero is valid; a tab's position is not its id.\n\nA1 ranges use sheet titles; structural GridRanges use numeric sheet ids with\nzero-based, end-exclusive row and column indexes. Quote titles containing\nspaces or punctuation and double apostrophes: `'Alice''s costs'!A1:D7`.\nA bare title may resolve to a named range; quote it to address the whole tab.\n\n## Read cell meaning\n\nDisplayed values reflect spreadsheet locale and number formats. Use\nunformatted numbers for arithmetic and formulas when inspecting expressions.\nDate serials count days from 1899-12-30; interpret dates using the workbook's\ntime zone. Trailing empty rows and cells may be absent. An empty range is a\nvalid result, not proof that the sheet is missing.\n\nWhole-row content reads can resume partway through a range. A named range or\nwhole-sheet reference may be re-read and earlier rows skipped; rowOffset is\nrelative to Google's echoed range. Reduce amounts inside execute_code before\nreturning them. Read an oversized cell separately to recover its full text.\n\n<!-- when: writes -->\n## Edit and reconcile\n\nUse RAW for external data; USER_ENTERED can turn leading equals signs into\nformulas. In cell writes, null leaves a cell unchanged and an empty string\nclears it. Clearing preserves formatting and validation. `append_values` is\npinned to INSERT_ROWS and inserts rows after the detected table. A vendor append using\nOVERWRITE can replace existing cells below that table.\n\nRead just before replacing another person's cells. Sheets has no revision\nprecondition or replay key: concurrent edits can be overwritten. After an\nuncertain append, read the target table and identify the row before adding\nanything missing. After an uncertain workbook create, search Drive by title\nbefore creating another workbook.\n\nStructural batches apply atomically, but can delete rows, sheets or\nprotections. An oversized reply may be summarized after the edit saved;\ninspect the workbook to recover details. Preview comment mutations and\nexternal data-source configuration, refresh and administration are outside\nthis connection. Developer-metadata searches and data-filter reads are\nread-only even though their wire method is POST.\n<!-- end -->\n\n## Conventions\n\n- **Hatch:** `sheets_api_search` finds operations, `sheets_api_details` shows one contract, `sheets_api_read` calls a reviewed read and `sheets_api_write` a reviewed write.\n- **Errors:** An unknown id, or one these credentials cannot reach, fails as `connector_call_failed`; this API does not tell the two apart.",
|
|
4
4
|
"instructionsHeading": "Connection instructions"
|
|
5
5
|
};
|
|
@@ -122,15 +122,15 @@ export const slides = defineApiProvider({
|
|
|
122
122
|
binding: ({ connection }) => slidesBinding(connection),
|
|
123
123
|
},
|
|
124
124
|
probe,
|
|
125
|
+
blocks: { keys: ["writes"], select: (options) => (options.readOnly ? [] : ["writes"]) },
|
|
125
126
|
guide: (options) => ({
|
|
126
127
|
context: [
|
|
127
128
|
`Purpose: ${options.purpose}`,
|
|
128
129
|
"Workspace delegation is configured. Each call acts as the account deployment code maps the caller to; an agent uses its pool owner unless one shared account is configured. No argument selects a subject.",
|
|
129
|
-
"
|
|
130
|
-
"Generic thumbnails/preview links are refused; get_slide_thumbnail is the reviewed short-lived-link workflow. The generic batch retains only the 49 shipped request kinds; no extra preview methods are admitted.",
|
|
130
|
+
"The generic batch retains only the 49 shipped request kinds.",
|
|
131
131
|
...(options.readOnly ? ["This connection is read-only; writes are refused."] : []),
|
|
132
132
|
],
|
|
133
|
-
summary: "
|
|
133
|
+
summary: "Load for deck text, notes, layouts, comments and guarded Slides edits.",
|
|
134
134
|
required: true,
|
|
135
135
|
}),
|
|
136
136
|
tools: slidesTools,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
2
|
export const skill = {
|
|
3
|
-
"content": "## Find and read
|
|
3
|
+
"content": "## Find and read\n\nSlides cannot search decks: use Drive, the id in `/presentation/d/<id>/`, or an\nid the person gives, which works as is. Finding a deck does not grant access.\nSlide `index` is zero-based. Before filling a new slide, resolve placeholders\nwith `list_layouts` and `get_page`.\n\nContinuation is per content kind: `textCursor` or `elementsCursor` goes to\n`get_page` with that slide's id, `notesCursor` with its `notesPageId`,\n`layoutsCursor` to `list_layouts`. Cursors bind to the deck's revision, so a\nchanged deck needs a fresh read. Follow them even when a result has fewer rows\nthan requested.\n\n`slides_api_read` covers styles, transforms and full structure. It returns\n`{status,data}` with the vendor presentation in `data`; a program call nests that\nin its own `data`. In operation details, presentations.get names its path\nparameter `presentationsId`; pages and batch updates use `presentationId`. Spell\ncolons literally and encode other reserved characters within one id segment.\n\n`get_slide_thumbnail` returns a link that opens as the delegated person: keep it\nprivate. Generic thumbnail and preview operations are refused.\n\n`commentId` names a thread; its posts have their own `postId`. Speaker-note\ncomments belong to the notes page. A view-only account may be refused; that is not\nan empty list.\n\n<!-- when: writes -->\n## Edit at the version you read\n\nPass the `revisionId` you read as the write precondition; each write returns the\nnext one. It is a precondition, not a replay key. On `conflict`, re-read, rebuild\nthe requests and send them with the new id. A failure saying the write applied\nmeans Google answered 2xx: re-read, never repeat. `create_slide` adds no text, so\nread its placeholder ids first. No Slides tool shares, moves or deletes the file.\n\nThe generic batch is `POST /presentations/<id>:batchUpdate` with\n`body: {requests, writeControl: {requiredRevisionId}}`, under the same guards.\n\n## Comments save separately\n\nComments notify people as in the editor. When one edit changes the deck and\ncomments, send one `batch_update_presentation` under one `requiredRevisionId`;\ncomment changes are Request kinds. Slides saves the two parts separately, so success\ncan leave comments unconfirmed. If `commentUpdateState` is not `ALL_SAVED`, or the\nresult says saves are unconfirmed: read the deck and `list_comments`, report each\npart as saved or unconfirmed, keep every created id, and resend neither the batch\nnor its comment part. The write hatch reports this state in envelope `warnings`,\neven when `fields` narrows.\n<!-- end -->\n\n## Conventions\n\n- **Hatch:** `slides_api_search` finds operations, `slides_api_details` shows one contract, `slides_api_read` calls a reviewed read and `slides_api_write` a reviewed write. 1 operation is refused by design; use `slides_api_details` with the method and path to see each summary and refusal, even for methods outside the read/write schemas.\n- **Errors:** An unknown id, or one these credentials cannot reach, fails as `connector_call_failed`; this API does not tell the two apart. `conflict` means: A revision-guarded batch update returned ABORTED or FAILED_PRECONDITION with HTTP 400 or 409; The content or revision bound to a named continuation cursor changed; restart the read.",
|
|
4
4
|
"instructionsHeading": "Connection instructions"
|
|
5
5
|
};
|
|
@@ -53,8 +53,8 @@ function usageGuide(options) {
|
|
|
53
53
|
return {
|
|
54
54
|
heading: "Stripe usage",
|
|
55
55
|
summary: options.mode === "production"
|
|
56
|
-
? "
|
|
57
|
-
: "
|
|
56
|
+
? "Load for live Stripe payments, refunds and invoices; real money, resolve ids before acting."
|
|
57
|
+
: "Load for sandbox Stripe payments, refunds and invoices; test data, resolve ids before acting.",
|
|
58
58
|
context: [
|
|
59
59
|
`Mode: ${options.mode}. Connector purpose: ${options.purpose}`,
|
|
60
60
|
copy.warning,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
2
|
export const skill = {
|
|
3
|
-
"content": "## Account and money\n\nBefore investigating a payment or moving money, confirm the account and mode\nwith `get_stripe_account_info`. A Connect account's objects belong to that\naccount, rather than the platform's account. Sandbox objects do not establish anything about live\ncustomers, revenue or payouts.\n\nResolve ids before acting. Stripe ids identify types: `cus_` customer, `sub_`\nsubscription, `ch_` charge, `pi_` PaymentIntent, `in_` invoice and `acct_`\naccount. A plausible-looking id can refer to a different object or to nobody.\n\nAmounts are integers in the currency's minor unit: 1099 is 10.99 USD, while\n10 is 10 JPY. Keep currencies separate when totaling balances or payments.\n\n## Payment investigations\n\nA PaymentIntent's `latest_charge` joins it to the charge holding the payment's\n`outcome`, `failure_code` and `failure_message`. Follow that reference to\nexplain a decline. Search supports a documented field set for each resource;\ncharge search has no `payment_intent` field. Resolve the parent and follow its\nreference when the needed relationship is not searchable.\n\nSearch is eventually consistent; use a direct object read to reconcile a\nrecent write. A POST's idempotency key identifies the exact operation and\nparameters. Stripe v1 may prune keys after 24 hours, so reconcile the object\nbefore attempting the operation outside that window. A new key can create a\nsecond payment or refund.\n\nIn v1 requests, an empty string (`\"\"`) or `null` unsets a field.\n\n## Data reduction and boundaries\n\nKeep only the customer and payment facts the question needs. Reduce lists to\ncounts, totals or matching records before returning them to the conversation.\nUse the account and balance summaries when their projections answer the task;\nother account fields and balance transactions are available through the API.\n\nCredential creation, customer/account sign-in links, secret payload expansions,\nfull Issuing card details, file uploads and the meter-event stream are outside\nthis connection's surface. Use the Dashboard or application server for those\nflows. Single meter events remain available. A guest Checkout payment page is\navailable only when it is unbound to a Customer or Account and cannot manage\nsaved payment methods; use a payment link or hosted invoice for other cases.\n\n## Conventions\n\n- **
|
|
3
|
+
"content": "## Account and money\n\nBefore investigating a payment or moving money, confirm the account and mode\nwith `get_stripe_account_info`. A Connect account's objects belong to that\naccount, rather than the platform's account. Sandbox objects do not establish anything about live\ncustomers, revenue or payouts.\n\nResolve ids before acting. Stripe ids identify types: `cus_` customer, `sub_`\nsubscription, `ch_` charge, `pi_` PaymentIntent, `in_` invoice and `acct_`\naccount. A plausible-looking id can refer to a different object or to nobody.\n\nAmounts are integers in the currency's minor unit: 1099 is 10.99 USD, while\n10 is 10 JPY. Keep currencies separate when totaling balances or payments.\n\n## Payment investigations\n\nA PaymentIntent's `latest_charge` joins it to the charge holding the payment's\n`outcome`, `failure_code` and `failure_message`. Follow that reference to\nexplain a decline. Search supports a documented field set for each resource;\ncharge search has no `payment_intent` field. Resolve the parent and follow its\nreference when the needed relationship is not searchable.\n\nSearch is eventually consistent; use a direct object read to reconcile a\nrecent write. A POST's idempotency key identifies the exact operation and\nparameters. Stripe v1 may prune keys after 24 hours, so reconcile the object\nbefore attempting the operation outside that window. A new key can create a\nsecond payment or refund.\n\nIn v1 requests, an empty string (`\"\"`) or `null` unsets a field.\n\n## Data reduction and boundaries\n\nKeep only the customer and payment facts the question needs. Reduce lists to\ncounts, totals or matching records before returning them to the conversation.\nUse the account and balance summaries when their projections answer the task;\nother account fields and balance transactions are available through the API.\n\nCredential creation, customer/account sign-in links, secret payload expansions,\nfull Issuing card details, file uploads and the meter-event stream are outside\nthis connection's surface. Use the Dashboard or application server for those\nflows. Single meter events remain available. A guest Checkout payment page is\navailable only when it is unbound to a Customer or Account and cannot manage\nsaved payment methods; use a payment link or hosted invoice for other cases.\n\n## Conventions\n\n- **Hatch:** `stripe_api_search` finds operations, `stripe_api_details` shows one contract, `stripe_api_read` calls a reviewed read and `stripe_api_write` a reviewed write. 15 operations are refused by design; use `stripe_api_details` with the method and path to see each summary and refusal, even for methods outside the read/write schemas.\n- **Writes:** a write that takes `idempotencyKey` may be repeated with the same key and arguments while the vendor retains it.\n- **Errors:** `not_found` means the record does not exist; this API tells absence from a permission gap. `conflict` means: HTTP 409 when the request conflicts with another request, including a concurrent use of the same idempotency key; HTTP 429 with code lock_timeout when another request holds the object's lock.",
|
|
4
4
|
"instructionsHeading": "Account instructions"
|
|
5
5
|
};
|
|
@@ -73,7 +73,7 @@ function usageGuide(options) {
|
|
|
73
73
|
? [`List tools return ${options.defaultPageSize} rows by default on this connection.`]
|
|
74
74
|
: []),
|
|
75
75
|
],
|
|
76
|
-
summary:
|
|
76
|
+
summary: "Load for giving records, donor joins, cents, ISO dates and guarded writes.",
|
|
77
77
|
// Required: the reduction rule for donor data and the id joins live only
|
|
78
78
|
// in the guide. No schema can carry either.
|
|
79
79
|
required: true,
|
|
@@ -81,6 +81,7 @@ function usageGuide(options) {
|
|
|
81
81
|
}
|
|
82
82
|
/** A maintained Tithe.ly giving connection over the v1 REST API. */
|
|
83
83
|
export const tithely = defineApiProvider({
|
|
84
|
+
blocks: { keys: ["writes"], select: (options) => (options.readOnly ? [] : ["writes"]) },
|
|
84
85
|
name: "tithely",
|
|
85
86
|
title: "Tithe.ly",
|
|
86
87
|
readme: "Tithe.ly",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Generated by scripts/generate-providers.mjs; do not edit.
|
|
2
2
|
export const skill = {
|
|
3
|
-
"content": "## Giving data is pastoral\n\nDonor names, emails, addresses, and gift amounts are pastoral data. Reduce\ninside `execute_code`: page, filter, and total there, and return the\naggregate (sums by fund, month, or donor count), not donor rows, unless the\ntask needs named people.\n\n## Ids and joins\n\n- Ids carry their kind: `org_` organization, `user_` donor account, `ch_`\n charge, `rc_` recurring gift, `pm_` payment method. Read them from the list\n tools; never guess one.\n- Tithe.ly lists charges and recurring gifts only for one organization or one\n donor, so pass `organizationId` or `accountId`.\n- A charge carries its donor's name and email, its organization's name, and\n its payment method, so most joins need no second read.\n- `list_accounts` covers every account these keys can see; `scope: \"api\"`\n narrows it to accounts created through this API.\n- The named reads project Tithe.ly's records. A field a projection omits, such\n as an account's phone and postal address, comes back from `tithely_api_read`\n on that record's path.\n\n## Money, dates and funds\n\n- A fund is a Tithe.ly giving type: `giving_type` in Tithe.ly's records,\n `fund` in projections.\n- Projections give amounts as integer `…Cents` and dates as ISO 8601 UTC\n `…At`. Tithe.ly's own records, from `tithely_api_read`, keep string cents\n and Unix seconds.\n- `depositedAt` may be `\"pending\"`. There is no deposits resource: net amount\n and fees live on each charge.\n- A charge a recurring gift produced has `recurring: true`; a one-time gift\n has `recurring: false`.\n\n## Writes\n\n- Every write moves money or changes a donor's records. Bodies are form\n fields in integer cents and Unix seconds.\n- `POST /refunds/{charge_id}` refunds a whole charge.\n `DELETE /recurring/{recurring_id}` stops future charges and refunds nothing.\n- Card and bank tokens, which `POST /charge-once` and `POST /payment-methods`\n need, come only from Tithely.js in a donor's browser. An agent cannot\n create one.\n- Tithe.ly reports most refusals as HTTP 200 with `status: \"fail\"` and a\n reason but no code. They arrive as `connector_call_failed`; read the reason\n before deciding what to do next.\n\n## Not available\n\nOnly Tithe.ly's API v1 is reachable; its undocumented v2 is not.\n\n## Conventions\n\n- **
|
|
3
|
+
"content": "## Giving data is pastoral\n\nDonor names, emails, addresses, and gift amounts are pastoral data. Reduce\ninside `execute_code`: page, filter, and total there, and return the\naggregate (sums by fund, month, or donor count), not donor rows, unless the\ntask needs named people.\n\n## Ids and joins\n\n- Ids carry their kind: `org_` organization, `user_` donor account, `ch_`\n charge, `rc_` recurring gift, `pm_` payment method. Read them from the list\n tools; never guess one.\n- Tithe.ly lists charges and recurring gifts only for one organization or one\n donor, so pass `organizationId` or `accountId`.\n- A charge carries its donor's name and email, its organization's name, and\n its payment method, so most joins need no second read.\n- `list_accounts` covers every account these keys can see; `scope: \"api\"`\n narrows it to accounts created through this API.\n- The named reads project Tithe.ly's records. A field a projection omits, such\n as an account's phone and postal address, comes back from `tithely_api_read`\n on that record's path.\n\n## Money, dates and funds\n\n- A fund is a Tithe.ly giving type: `giving_type` in Tithe.ly's records,\n `fund` in projections.\n- Projections give amounts as integer `…Cents` and dates as ISO 8601 UTC\n `…At`. Tithe.ly's own records, from `tithely_api_read`, keep string cents\n and Unix seconds.\n- `depositedAt` may be `\"pending\"`. There is no deposits resource: net amount\n and fees live on each charge.\n- A charge a recurring gift produced has `recurring: true`; a one-time gift\n has `recurring: false`.\n\n<!-- when: writes -->\n## Writes\n\n- Every write moves money or changes a donor's records. Bodies are form\n fields in integer cents and Unix seconds.\n- `POST /refunds/{charge_id}` refunds a whole charge.\n `DELETE /recurring/{recurring_id}` stops future charges and refunds nothing.\n- Card and bank tokens, which `POST /charge-once` and `POST /payment-methods`\n need, come only from Tithely.js in a donor's browser. An agent cannot\n create one.\n- Tithe.ly reports most refusals as HTTP 200 with `status: \"fail\"` and a\n reason but no code. They arrive as `connector_call_failed`; read the reason\n before deciding what to do next.\n<!-- end -->\n\n## Not available\n\nOnly Tithe.ly's API v1 is reachable; its undocumented v2 is not.\n\n## Conventions\n\n- **Hatch:** `tithely_api_search` finds operations, `tithely_api_details` shows one contract, `tithely_api_read` calls a reviewed read and `tithely_api_write` a reviewed write.\n- **Errors:** An unknown id, or one these credentials cannot reach, fails as `connector_call_failed`; this API does not tell the two apart.",
|
|
4
4
|
"instructionsHeading": "Account instructions"
|
|
5
5
|
};
|