v0.7.25: new tools, gmail send fixes, email lifecycle adjustments#5490
Conversation
markSpanForError only recorded the top-level exception message, so a fetch() failure showed up as the generic "TypeError: fetch failed" with no indication of the real cause (ENOTFOUND, ECONNREFUSED, etc). Use describeError to walk the cause chain and set it as the span status message and an error.code attribute.
…ing (#5474) * feat(tinybird): validate integration against API, add job-status polling, scope block outputs - Validated all 6 existing tools against Tinybird's live REST API docs - Added tinybird_get_job tool to poll async import/delete jobs - Scoped block outputs with per-operation condition * fix(tinybird): align token-scope descriptions with Tinybird's plural scope names - events/query/query_pipe used singular DATASOURCE:/PIPE: scope names; Tinybird's Token API uses plural DATASOURCES:/PIPES: - append_datasource now notes DATASOURCES:APPEND also suffices, not just CREATE
…#5469) * feat(dub): expand link coverage and fix cross-operation param leakage - add tenantId/folderId/trackConversion support and conversions output to link tools - add cursor pagination (startingAfter/endingBefore) to list_links, logo param to get_qr_code - add list_domains, list_tags, create_tag, list_folders tools - fix block param leakage where an unset field on one operation inherited a stale value left over from another operation * fix(dub): stop trackConversion from resetting existing links on update - only send trackConversion true or omit it, matching linkRewrite/linkArchived's partial-PATCH-safe pattern, so a routine update_link no longer silently disables conversion tracking on an existing link - include trackConversion in the cross-operation reset block so it can't leak a stale value into non-mutation operations either
* fix(github): fix response bugs and add missing endpoint coverage - Fix unauthenticated internal sub-fetch in pr.ts (list_pr_files) that 401'd on private repos and burned anon rate limits - Fix hardcoded/placeholder output fields in add_labels, delete_comment, delete_file - Handle 409 (sha mismatch) in merge_pr in addition to 405 - Loosen request_reviewers.reviewers to optional (team-only reviews) - Add items schema to get_commit parents array output - Add github_get_readme, github_create_pr_review, github_get_latest_release, github_list_tags (+ v2 variants) * fix(github): address review findings on pr.ts and delete_comment.ts - pr.ts: surface a real failure instead of silently returning success:true with an empty files array when the files sub-fetch fails; unify the sub-fetch Accept header with the rest of the file - delete_comment: success now tracks the actual deletion outcome instead of being hardcoded true * fix(github): guard new tools against non-2xx GitHub responses list_tags, get_readme, get_latest_release, and create_pr_review (v1 + v2) now check response.ok before parsing the payload as success data, returning success:false with a real error message instead of crashing on .map() or silently returning undefined fields when GitHub returns a 404/422/etc.
…haring tools (#5468) * fix(dropbox): align integration with Dropbox API docs, add revision/sharing tools - fix search root-path bug: Dropbox requires "" not "/" for root, same fix already applied to list_folder - fix create_shared_link to return the existing link's metadata (url) when Dropbox reports shared_link_already_exists with matching settings, instead of just erroring - fix upload route autorename default (was true, Dropbox's documented default is false) - trim() all path/fromPath/toPath/rev params to guard against copy-pasted whitespace - mark nullable output fields (id, size, path_display, etc.) optional: true so folder/deleted items don't imply always-present file fields - widen path_display/path_lower types to optional, matching the real API - add dropbox_list_shared_links, dropbox_list_revisions, dropbox_restore tools + block wiring, filling gaps flagged during the audit (revision history/version recovery, and a companion to create_shared_link for looking up existing links) * style(dropbox): use ?? instead of || for boolean defaults in list_shared_links Consistency nit from Greptile review - matches the ?? pattern already used by every other transformResponse in this PR. * fix(dropbox): mark path_display/path_lower optional everywhere for consistency Greptile flagged that path_display was left required in list_folder.ts and list_revisions.ts despite being widened to optional in types.ts and most other output schemas in this PR. Fixed those two plus create_folder.ts, restore.ts, upload.ts, and list_shared_links.ts, which had the same gap. * fix(dropbox): list_shared_links path omission + list_revisions pagination Cursor Bugbot flagged two real gaps: - list_shared_links sent path: "" for root/all, but Dropbox only returns every link account-wide when path is omitted entirely; "" scopes to the root folder specifically. Now omits the field for root/empty/"/" input. - list_revisions exposed hasMore but no way to actually fetch more pages (Dropbox's before_rev cursor). Added a beforeRev param + advanced-mode block field. A third flagged issue (create_shared_link's error.shared_link_already_exists.metadata path) was verified against the official sharing.stone spec and confirmed correct as-is - replied on the PR thread with the citation, no change needed. * fix(dropbox): correct shared_link_already_exists JSON path The prior fix read data.error.shared_link_already_exists.metadata, which is wrong per Stone's own JSON serialization rules: a union member whose payload is a struct (SharedLinkMetadata) flattens that struct's fields alongside ".tag" rather than nesting under a wrapper key. The real shape is data.error.shared_link_already_exists directly (with an extra ".tag" field mixed in) - there is no nested .metadata key, so the existing-link fast path never fired before this fix. Also marks list_shared_links' expires output optional, matching every other optional field in this PR and the SharedLinkMetadata spec. * fix(dropbox): wire cursor pagination for List Shared Links in the block The dropbox_list_shared_links tool already accepted a cursor param, but the block never exposed it, so a workflow couldn't page past the first batch when hasMore was true. Adds an advanced-mode cursor subBlock + input entry, mirroring List Revisions' beforeRev field added in the same PR.
…#5475) * feat(gitlab): add release and branch-compare tools, remove dead types - Add gitlab_delete_branch, gitlab_compare_branches, gitlab_list_releases, gitlab_create_release tools + block wiring (fills gaps found during a full validate-integration pass against live GitLab API docs) - Remove 12 unexported, zero-consumer types left over from never-implemented tool ideas (labels, users, current-user, branch/notes listing) - Add filePath/branch block outputs that get_file/create_file/update_file already returned but weren't exposed - Broaden state/orderBy param descriptions to list all documented GitLab values * fix(gitlab): expose all tool-returned fields as block outputs - Add total, size, ref, blobId, lastCommitId, mergeRequestIid, changesCount, approvedBy, protected, id, status to the block outputs map — these fields are already returned by their respective tools but weren't declared as outputs - Add missing 'title' value to list_issues orderBy description * fix(gitlab): drop empty entries when splitting release milestones Trailing/extra commas in the milestones input (e.g. "v1, ,v2") would produce an empty string entry, which the GitLab API rejects.
…ode/error-report support (#5470) * fix(brightdata): align integration with live API docs, add markdown/mode/error-report support - fix Discover numResults docs (max 20, not 1000) and contentFormat value ("md" not "markdown", which the API always rejected) - add Discover mode param (standard/deep/fast/zeroRanking) - add markdown output support to Web Unlocker scrape_url via data_format - add include_errors support to scrape_dataset, matching sync_scrape - add .trim() on datasetId in scrape_dataset/sync_scrape URLs - add wandConfig on complex fields, tighten block output descriptions * fix(brightdata): default mode field to empty so it's opt-in like other advanced params Greptile flagged that mode shipped with a non-empty default ('standard'), causing it to be sent on every Discover call unlike the sibling dataFormat field which uses an empty/None default and only sends when the user opts in. Aligns mode with that same pattern.
…5472) * fix(discord): align tools with live API docs, add missing endpoints - fix ban_member deprecated delete_message_days -> delete_message_seconds - fix get_server phantom member_count/channels outputs, add with_counts support - fix create_thread missing type field causing silent private-thread default - fix delete_channel to return the deleted channel body - fix get_pinned_messages to use the current (non-deprecated) pins endpoint and drop an unused required serverId param - add .trim() on all URL-interpolated IDs and bot tokens across every tool - add discord_list_channels, discord_list_roles, discord_get_pinned_messages, discord_bulk_delete_messages - fix block subBlock required flags (userId, content, messageId) to match each operation's actual tool requirements - remove orphaned Discord OAuth scope descriptions (Discord uses bot tokens, not OAuth) * fix(discord): guard against whitespace-only messageId in create_thread Cursor Bugbot found that a whitespace-only messageId was treated as present (truthy), routing to the message-thread URL and trimming to an empty path segment instead of creating a standalone thread. * fix(discord): guard whitespace userId, add pins pagination - remove_reaction: whitespace-only userId no longer breaks the /@me fallback (Cursor Bugbot) - get_pinned_messages: add limit/before query params so pins beyond the first page (max 50) can be retrieved (Cursor Bugbot) - export DiscordMessage type and properly type pinned-message mapping * fix(discord): clamp shared limit subBlock to 1-50 for pinned messages The limit subBlock is shared between discord_get_messages (max 100) and discord_get_pinned_messages (max 50 per Discord's API), so a value carried over from the messages operation could exceed the pins endpoint's max and trigger a 400. Clamp at both the block dispatcher and the tool's request builder. * fix(discord): validate 2-100 message count before bulk delete Discord's bulk-delete endpoint requires 2-100 message IDs; forwarding an out-of-range count produced an opaque Discord API error instead of a clear preflight message.
…puts live from deployed start (#5453) * feat(custom-block): move management to enterprise settings; derive inputs live from deployed start * fix(custom-block): key custom-blocks query by workspaceId (react-query audit) * fix(custom-block): restore icon on discard instead of clearing the saved image * fix(custom-block): track create-flow dirty state and reset selections on discard * fix(custom-block): merge placeholders for id-less start fields; compare inputs by authored data only * improvement(custom-block): dedup input-mapping helper, reuse SettingsResourceRow + shared reserved-param set * fix(custom-block): keep disabled blocks resolvable so placed instances fail loudly instead of vanishing * fix(custom-block): derive fields for disabled blocks so edits keep placeholders; reseed edit form after async load * fix(custom-block): scope publish workspace picker to the current org
…ng endpoints (#5477) * fix(microsoft-teams): align tools with live Graph API docs, add missing endpoints - fix list_channel_members/list_team_members falling back to userId when email is missing - add $top=50 pagination to read_channel for parity with read_chat - add list_teams, list_chats, list_channels, list_chat_members tools so agents can discover ids without the UI selectors - all new tools use only existing granted scopes (Team.ReadBasic.All, Chat.ReadBasic, Channel.ReadBasic.All) — no new OAuth scopes requested * fix(microsoft-teams): surface pagination truncation via hasMore flag - add hasMore output (derived from @odata.nextLink presence) to list_teams, list_chats, list_channels, list_chat_members so agents can detect truncated results instead of trusting the count field as a total - do NOT add $top to list_teams' joinedTeams request — Graph docs explicitly state this endpoint does not support OData query parameters, so it would silently no-op
…ags (#5479) * fix(gmail): stop wrapping draft/send HTML body in per-paragraph <p> tags * fix(gmail): use <br> instead of CSS white-space for line breaks white-space: pre-wrap has inconsistent email-client support (including Gmail for non-Google accounts per caniemail.com); <br> is the client-agnostic standard for plain-text-to-HTML line breaks.
…sted support + CRUD coverage (#5476) * fix(posthog): validate integration against live API docs, add self-hosted support + CRUD coverage Fix missing response.ok checks across ~36 tools that silently treated error bodies as success. Fix delete_feature_flag ignoring failure responses, evaluate_flags targeting the undocumented /decide endpoint without the required api_key body field, and batch_events reporting a hardcoded events_processed count. Add self-hosted host support (utils.ts) alongside the existing US/EU region selector, and complete CRUD coverage with 5 new tools: update_insight, update_cohort, update_experiment, delete_survey, create_dashboard. * fix(posthog): remove dead response.ok checks, fix real schema/endpoint bugs The prior commit added if (!response.ok) branches inside transformResponse across ~40 tool files. This is dead code — tools/index.ts already throws on non-2xx (and error-payload) responses before transformResponse is ever invoked, so transformResponse only ever receives already-successful responses. Reverted to the idiomatic no-error-branch pattern used elsewhere in the codebase (e.g. hunter/email_verifier.ts), and added a posthog-errors errorExtractor so the framework's own error throw surfaces PostHog's real {type, code, detail, attr} error shape instead of a generic status message. Verified against PostHog's live OpenAPI schema, fixed real bugs: - delete_feature_flag: DELETE always returns 405 (hard delete not allowed); switched to PATCH with deleted: true - delete_person: no single-person DELETE endpoint exists; switched to POST .../persons/bulk_delete/ with ids: [personId] - create_annotation: insight_short_id is read-only on create; the writable field is dashboard_id - removed nonexistent fields (experiment variants, insight filters/saved) not present in the current schema - added missing trailing slashes on feature-flag/experiment URLs * fix(posthog): reject unsafe self-hosted host values (SSRF) The self-hosted host field accepted any string and only stripped trailing slashes before prepending https://, so a workflow could point it at loopback/private/link-local addresses (e.g. cloud instance- metadata endpoints) and the executor would make a real server-side request to it. Reuse the shared validateExternalUrl SSRF guard, same pattern already used for Convex's custom deployment URL (tools/convex/utils.ts); the tool executor separately re-validates with DNS resolution and pins the resolved IP for the actual request. Also drop an unused params arg in evaluate_flags' headers function. * fix(posthog): fail loudly instead of silently dropping data on bad JSON params Several tools caught JSON.parse failures on user-supplied filter/query/ parameters strings and silently substituted {} or null, which would wipe the corresponding field on the PATCH/create request instead of surfacing an error (Cursor Bugbot flagged this for update_cohort, update_experiment, update_insight; the same pattern existed in their create_* / update_feature_flag / evaluate_flags counterparts, fixed for consistency). Now throws a descriptive error, matching the existing convention in tools/notion/query_database.ts. Also fixes batch_events: the request body silently sent an empty batch on invalid JSON, and transformResponse always reported "captured successfully" even when PostHog's response indicated failure (data.status !== 1). * fix(posthog): mark region required for update_experiment posthog_update_experiment was the only experiment operation missing from the region field's required-condition list; the other three (create/get/list) already require it. Region is unconditionally visible on this block (no condition key gates it), so this was a required-ness inconsistency rather than a functional bug, but users updating an EU experiment should still be prompted to select the region explicitly rather than relying on the default. * fix(posthog): fix cross-field value leakage and false-success reports Merges update_insight's query subblock into the same insightQuery id already used by create_insight (Cursor flagged: it previously reused the 'query' subblock id shared by posthog_query's HogQL field and the cohort query fields, so switching operations could carry a stale HogQL/cohort-JSON value into an insight PATCH). Matches the existing merged-condition pattern used elsewhere in this block instead of duplicating the subblock id. Also fixes two more false-success reports in the same class as the batch_events/delete_feature_flag fixes: capture_event now checks the ingest response's status field (same {"status": 1} contract as /batch/) instead of unconditionally returning success, and delete_person now reports failure when persons_deleted is 0 instead of always success: true.
…ails (#5487) * improvement(email): reply-to help@sim.ai for lifecycle and billing emails - onboarding follow-up (5-day), payment-failed, and abandoned-checkout emails now reply-to the shared help inbox instead of a personal address - added getHelpEmailAddress() and reused it in the help route to remove the duplicated inline expression * fix(email): address Greptile review feedback - add a sendEmail assertion locking in the payment-failure email's replyTo - clarify getPersonalEmailFrom() JSDoc so it doesn't overstate replyTo's scope
…ols (#5480) * feat(bigquery): validate integration against live API docs, add dataset/table lifecycle + query-result tools - Cross-checked existing query/list_datasets/list_tables/get_table/insert_rows tools against BigQuery REST v2 docs; no critical issues found - Added 6 new tools covered by the existing bigquery OAuth scope: create/delete dataset, create/delete table, list table data, get query results - Wired new operations into the block (subblocks, conditions, tools.config), registry, and barrel exports * fix(bigquery): address Greptile + Cursor Bugbot review findings - create_table: guard JSON.parse on the schema field with a clear error, trim tableReference IDs in the request body - create_dataset: trim datasetId in the request body - block: stop leaking a stale query "location" value into create_dataset when datasetLocation is empty; clarify pageToken output description covers list_table_data and get_query_results too * fix(bigquery): address second round of Cursor Bugbot findings - create_table: validate parsed schema is a non-empty array of field objects with a name, not just syntactically valid JSON - get_query_results: guard timeoutMs with Number.isFinite before appending to the query string, matching maxResults * fix(bigquery): final alignment pass from independent multi-agent validation - Add missing projectId block output (returned by get_table/create_table/create_dataset but was silently dropped from the block's output schema) - Switch query/rows/schema subBlocks from long-input to code, matching the JSON/SQL field convention used by every other DB integration (clickhouse, mongodb, postgresql, supabase) * fix(bigquery): stop leaking stale datasetId/tableId into create_dataset/create_table Same class of bug as the earlier location leak: params() spread hidden datasetId/tableId from ...rest unconditionally, so a stale value from a previously-selected operation could survive into create_dataset/create_table if the dedicated new-ID field was somehow empty. Gate datasetId/tableId (and location) to the operations that actually use them, via shared op-list constants also reused by the corresponding subblock conditions.
…te+delete tools (#5485) * fix(google-calendar): align with live API docs, add calendar/ACL update+delete tools - remove any types from V2 response typing in get/move/quick_add/instances - add google_calendar_update_calendar (PATCH calendars.patch) - add google_calendar_delete_calendar (DELETE calendars.delete) - add google_calendar_update_acl (PATCH acl.patch) - all new tools covered by existing calendar OAuth scope, no new scopes requested * fix(google-calendar): dedupe GoogleCalendarAclRole type in update_acl.ts export it from types.ts and import instead of redeclaring locally
…ces Nearby Search (#5484) * fix(google-maps): validate integration against live API docs, add Places Nearby Search - add google_maps_places_nearby tool (Places API New, searchNearby) for radius/type-based place discovery - add pageToken support to places_search (text search pagination) - add units param to speed_limits (Roads API KPH/MPH) - wire homeMobileCountryCode/homeMobileNetworkCode subblocks for geolocate - split radius subblock so places_nearby's required radius isn't hidden in advanced mode - add default value to rankPreference dropdown - add missing authMode: AuthMode.ApiKey on the block * fix(google-maps): mark elevation resolution optional per API docs Google's Elevation API omits resolution when it can't be determined, but our output schema declared it as a required number. Also fixes a stale comment calling Speed Limits "deprecated" when it's actually Asset Tracking-license restricted. * fix(google-maps): guard radius NaN parse, surface pageToken delay caveat - radius parsing in transformParams now guards NaN like every other numeric param in this block, so a non-numeric radius no longer silently sends "radius":null to the required Nearby Search field - pageToken description/placeholder now note the required delay before a token becomes valid, per Places Text Search API behavior
… + categories (#5486) * fix(microsoft-planner): align with live Graph API docs, add plan CRUD + categories - fix update_task never returning updated task (missing Prefer: return=representation) - fix wrong @odata.type on task assignments (missing leading #) - fix update_plan/update_plan_details/update_bucket/update_task_details crashing on 204 No Content responses to PATCH (Graph sometimes ignores Prefer header) - add .trim() on path IDs across tools invoked outside the block - add create_plan, update_plan, delete_plan, get_plan_details, update_plan_details tools (If-Match/etag handled correctly on update/delete) - add appliedCategories support on create_task/update_task - all new tools verified against Graph API Permissions tables to require only scopes we already request (Group.ReadWrite.All, Group.Read.All, Tasks.ReadWrite) - regenerate integration docs * fix(microsoft-planner): use Graph-specific error extractor consistently 7 tools were pinned to the generic 'nested-error-object' extractor instead of MICROSOFT_GRAPH_ERRORS, losing Graph's inner-error detail (e.g. ETag mismatch specifics) that sibling Microsoft integrations (Excel, OneDrive, SharePoint) already surface correctly. * fix(microsoft-planner): address Cursor/Greptile round-1 review findings - fix empty priority/percentComplete string coercing to 0 (Number('')) at the block layer, which Planner treats as urgent/0% instead of leaving unset - support removing applied categories on update via a "-category3" prefix, since Graph only clears a label when its key is explicitly set to false - add missing MICROSOFT_GRAPH_ERRORS extractor to delete_plan/get_plan_details * fix(microsoft-planner): don't return a stale etag on 204 update_task response Graph's If-Match update changes the resource's etag even when it returns 204 No Content instead of the updated representation. Returning the request's (now-stale) etag as if it were current would let a chained update silently send a wrong If-Match and fail with 412. Return an empty etag instead so update_task's own etag-required guard forces a re-fetch.
…able metadata tool (#5481) * fix(microsoft-dataverse): align integration with live API docs, add table metadata tool - trim environment URL/entity/record IDs across all tools via shared getDataverseBaseUrl - encodeURIComponent OData $select/$filter/$orderby/$expand values in list_records/get_record - fix $top being silently ignored when Prefer: odata.maxpagesize is also sent - add microsoft_dataverse_get_entity_metadata tool for table/column lookup (covered by existing user_impersonation scope, no new scopes) * fix(microsoft-dataverse): clear stale select subBlock when mapping metadataSelect * fix(microsoft-dataverse): escape OData quotes in entity metadata key, surface JSON parse errors * fix(microsoft-dataverse): fix function alias params, add upload size guard, restore file output back-compat - execute_function: support @p1/@p2 parameter alias query-string bindings for values with reserved characters, per Dataverse Web API function docs - upload-file route: reject files over Dataverse's 128MB single-request upload ceiling with a clear error instead of an opaque API failure - download_file: add canonical `file` output (type: 'file') so downloaded bytes get persisted through Sim's execution file storage like every other file-download tool, while keeping the pre-existing fileContent/fileName/fileSize/mimeType fields for backwards compatibility with existing workflows * improvement(microsoft-dataverse): clarify fileColumn output description
… live API docs (#5483) * fix(aws): align cloudwatch, cloudformation, athena, codepipeline with live API docs - cloudwatch: fix list_metrics pagination (wasn't draining pages past 500), add MaxRecords cap validation to describe_alarms; add describe_alarm_history, filter_log_events, put_log_group_retention - cloudformation: fix get_template missing TemplateStage param, fix invalid ModuleTag in block metadata; add full stack lifecycle tools (create/update/delete/cancel_update_stack, create/describe/execute_change_set, get_template_summary) - athena: fix missing .trim() on query/named-query ID fields; add delete_named_query, batch_get_query_execution, list_databases, list_table_metadata - codepipeline: fix missing rollbackMetadata field in list_pipeline_executions response; add get_pipeline, list_action_executions, disable/enable_stage_transition * fix(aws): require template on cloudformation change-sets, bump route-count baseline - cloudformation create_change_set now rejects requests missing both templateBody and usePreviousTemplate, matching update_stack (Cursor Bugbot finding) - bump check:api-validation route-count baseline 906->917 to reflect the 19 new fully contract-bound routes added in this PR (0 boundary violations) * fix(aws): address Greptile round-1 review findings - cloudwatch describe_alarm_history: always request both MetricAlarm and CompositeAlarm types, even when alarmName is provided (was silently returning empty history for composite alarms queried by name) - cloudformation: add validateAwsRegion refinement to region field on the 7 new write-path contracts (update/delete/cancel-update-stack, create/describe/execute-change-set, get-template-summary), matching the pattern already used elsewhere - cloudformation: destroy the AWS SDK client in a finally block on the same 7 new write routes, matching the pattern used by every other new route in this PR * fix(aws/cloudformation): add missing region validation and client cleanup to create-stack - Add validateAwsRegion refinement to create-stack contract (completes P2 fix from Greptile review) - Wrap AWS SDK call in try/finally with client.destroy() (completes P2 fix from Greptile review) - Aligns create-stack with the pattern used across all 7 other new CloudFormation routes Co-authored-by: Waleed <waleedlatif1@users.noreply.github.com> * fix(aws): final validation pass — bound missing limits, close consistency gaps - cloudformation create_stack: add missing validateAwsRegion refine and client.destroy() finally block, matching sibling write routes - cloudwatch get_metric_statistics: cap statistics array at AWS's 5-item limit - cloudwatch get_log_events: cap limit at AWS's 10,000-record max - athena batch_get_query_execution: surface engineExecutionTimeInMillis/queryPlanningTimeInMillis/queryQueueTimeInMillis, matching the sibling get_query_execution tool's Statistics mapping * fix(aws/athena): destroy AWS SDK client on the 4 new athena routes Cursor Bugbot finding: batch_get_query_execution, delete_named_query, list_databases, and list_table_metadata created an AthenaClient but never called client.destroy(), unlike every other new route in this PR. Wrapped each in try/finally to match. * fix(aws/athena): add validateAwsRegion refinement to the 4 new contracts Greptile finding: delete_named_query, batch_get_query_execution, list_databases, and list_table_metadata accepted any non-empty string for region, unlike every other new contract in this PR. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Waleed <waleedlatif1@users.noreply.github.com>
…oints (#5478) * fix(onedrive): align tools with live Graph API docs, add missing endpoints - wire up search/move/copy/create_share_link tools into block operation switch (were registered but unreachable, would throw 'Invalid OneDrive operation') - fix tools.config.params to remap new canonical subBlock ids to correct tool param names - add onedrive_get_item and onedrive_get_drive_info tools (item metadata, drive quota) — both within existing Files.Read/Files.ReadWrite scope - add missing block inputs/outputs for new operations - alphabetize onedrive registry entries * fix(onedrive): escape single quotes in search query, document embed link type - encodeURIComponent doesn't escape single quotes, breaking the OData string literal for filenames containing an apostrophe - clarify create_share_link's linkType description to include 'embed', which the block UI already exposes as a valid option * fix(onedrive): add real pagination continuation to search - add pageToken param that follows the @odata.nextLink continuation URL directly, so nextPageToken output is actually consumable instead of a dead end - wire pageToken through the block as an advanced-mode field on the search operation * fix(onedrive): prevent SSRF/token exfiltration via search pageToken pageToken was used verbatim as the request URL with no host validation, while the Authorization header is always attached — a crafted pageToken pointing at an attacker-controlled host would leak the OAuth access token. Pin the continuation URL to graph.microsoft.com before using it. * fix(onedrive): make search query optional for pageToken-only continuation requests * fix(onedrive): fix folder-targeting wiring, OData escaping, and downloadUrl selection - upload/create_folder/list all read params.folderSelector/manualFolderId, but the block only ever sends folderId — folder targeting silently fell back to drive root. Consolidate to a single folderId param matching what the block sends (same pattern already used for destinationFolderId on move/copy) - search's percent-encode-then-replace('%27') "escape" is undone by Graph's standard URL-decode-before-parse, so an apostrophe in a query still breaks the OData string literal; list's $filter had no escaping at all. Both now double literal quotes (the correct OData V4 escape) via a shared escapeODataStringLiteral helper before encoding - get_item/list/search all omitted @microsoft.graph.downloadUrl from $select, so webContentLink was always undefined on their outputs; added it - list gains the same pageToken continuation support search already has, and the block's Page Token field is now shown for both operations * fix(onedrive): reuse shared assertGraphNextPageUrl for page-token validation Hostname-only check let http://graph.microsoft.com/... continuation tokens through, which would send the Bearer token over cleartext. Sibling Graph integrations (sharepoint, microsoft_teams, microsoft_planner, microsoft_ad) already share assertGraphNextPageUrl/getGraphNextPageUrl in tools/sharepoint/utils.ts, which checks the full origin (scheme + host). Reuse it in list/search instead of hand-rolling the check twice.
…ved-query CRUD coverage (#5482) * fix(google-vault): validate integration against live API docs, add matter/hold/saved-query CRUD coverage - Fix critical bug: create_matters_export sent the deprecated Query.searchMethod field (deprecated 2019, support ended 2020) instead of method, silently breaking account/org-unit scoped exports - Fix duplicate matterId subBlock id (two definitions collided across operations) - Add matter lifecycle: update, close, reopen, delete, undelete - Add matter collaborator management: add/remove permissions - Add export delete - Add hold update, delete, add/remove held accounts - Add saved query create/list/delete - Bump tool versions to 1.0.0 to match repo convention - Fix docsLink to point at docs.sim.ai instead of the vendor site - All new endpoints are covered by the existing ediscovery + devstorage.read_only OAuth scopes (no new scopes requested) * fix(google-vault): pageToken should be user-or-llm visibility, not hidden Greptile review: hidden is reserved for framework-injected tokens; pageToken in list_saved_queries.ts should be user-or-llm so an agent/user can pass it, matching the pattern used elsewhere for tool-supplied pagination cursors. * fix(google-vault): fail loudly instead of silently clearing hold scope on update Cursor Bugbot: PUT holds/{id} replaces the full resource — a name/query-only update with no accountEmails/orgUnitId would silently drop the hold's custodian coverage. Now throws a clear error directing callers to resend the scope or use add_held_accounts/remove_held_accounts for incremental changes. * fix(google-vault): reject unscoped exports/saved-queries for non-MAIL corpus Independent audit (parallel doc-verification pass): create_matters_export and create_saved_query resolved Query.method to undefined when corpus wasn't MAIL and no accountEmails/orgUnitId was given, silently sending an invalid request (method is a required Query field) instead of a clear error. Now throws with an actionable message before the request is sent. * fix(google-vault): document full-replace semantics on hold update query filters Cursor Bugbot: update_matters_holds only sets query.mailQuery/groupsQuery/ driveQuery when terms/date/shared-drive fields are provided, but the PUT replaces the whole hold — omitting a previously-set filter clears it, not leaves it unchanged. Filters are legitimately optional (a hold may have none), so this can't be hard-required like scope; instead the tool and field descriptions now explicitly state the full-replace behavior and direct callers to resupply current values via Vault List Holds first. * fix(google-vault): isolate stale-value-prone subblocks per operation Cursor Bugbot: consolidating shared subblocks across operations left two cross-contamination risks since a stale value from one operation stays in block state until overwritten: - accountEmails/orgUnitId are checked emails-first with silent either/or priority; sharing them across update_matters_holds and create_saved_query meant a leftover value from a different operation could silently override the intended scope. Gave both operations dedicated fields (updateHoldAccountEmails/updateHoldOrgUnitId, savedQueryAccountEmails/ savedQueryOrgUnitId), remapped in tools.config.params. - matterId presence alone switches google_vault_list_matters between list-all and single-get. Sharing it with every other operation meant a leftover matterId could silently turn "List Matters" into a single-matter fetch. Gave list_matters its own optional listMatterId field. create_matters_holds/create_matters_export keep sharing accountEmails/ orgUnitId as before this PR (pre-existing behavior, not introduced here). * fix(google-vault): isolate list-optional-id fields from required-elsewhere counterparts Cursor Bugbot: exportId/holdId/savedQueryId were shared between their respective list operation (optional filter) and update/delete/held-account operations (required). A stale ID left over from a delete/update on the same block instance would silently narrow the corresponding list operation to a single-resource get instead of listing the collection. Gave each list operation its own dedicated optional field (listExportId, listHoldId, listSavedQueryId), remapped in tools.config.params — same pattern already used for listMatterId. * fix(google-vault): defensively order mutually-exclusive scope spreads Greptile: savedQueryAccountEmails/savedQueryOrgUnitId spread after their updateHold* counterparts, so if both were ever truthy at once the wrong one would silently win. In practice they're mutually exclusive (each only populated while its own single 'operation' value is selected, so at most one pair is ever truthy), but reordering costs nothing and removes any doubt about precedence. * docs: regenerate integration docs Reruns scripts/generate-docs.ts against the current block/tool/trigger registry. Picks up google_vault's new operations plus everything else that had landed on staging without a docs regen (bigquery, google_calendar, google_maps, onedrive, microsoft_teams, gitlab, github, discord, dropbox, and others), plus icon and integrations.json updates.
|
Too many files changed for review. ( Bypass the limit by tagging |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
PR SummaryMedium Risk Overview Integrations: New or expanded actions across AWS (Athena, CloudFormation, CloudWatch, CodePipeline), Google BigQuery (dataset/table lifecycle, query result paging), GitHub/GitLab (PR reviews, releases, branches), Discord, Dropbox, Dub, Bright Data, Attio (attributes, richer note/task/comment shapes), and others (PostHog, Microsoft Teams/Planner/Dataverse/OneDrive, Google Calendar/Maps/Vault). Docs in Docs UI: Other: Gmail send no longer wraps HTML in extra Reviewed by Cursor Bugbot for commit ed1492b. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit ed1492b. Configure here.
| href='data:image/png;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QBMRXhpZgAATU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAQKADAAQAAAABAAAAQAAAAAD/4QnSaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA2LjAuMCI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgcGhvdG9zaG9wOkluc3RydWN0aW9ucz0iRkJNRDBhMDAwYWIyMDEwMDAwOTgwMzAwMDBmMTA0MDAwMDRhMDYwMDAwYTIwNjAwMDBiMTA3MDAwMDQ1MGEwMDAwMmUwYjAwMDBmOTBiMDAwMDMwMGMwMDAwOTgwZTAwMDAiLz4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA8P3hwYWNrZXQgZW5kPSJ3Ij8+AP/tAK5QaG90b3Nob3AgMy4wADhCSU0EBAAAAAAAdhwBWgADGyVHHAIAAAIAAhwCKABiRkJNRDBhMDAwYWIyMDEwMDAwOTgwMzAwMDBmMTA0MDAwMDRh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' | ||
| width='64' | ||
| height='64' | ||
| /> |
There was a problem hiding this comment.
JPEG data labeled as PNG
Low Severity
Several new competitor SVG icons embed raster logos via data:image/png URLs, but the base64 payload begins with the JPEG signature (/9j/). Decoders that trust the declared MIME type can fail to render N8nIcon, MakeIcon, PipedreamIcon, and TinesIcon, leaving blank icons in the docs UI.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit ed1492b. Configure here.


tags (fix(gmail): stop wrapping draft/send HTML body in per-paragraph <p> tags #5479)