mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
a08da86dff1cbd2d6a19aadee89cdef8b7fe5ef9
5193
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a08da86dff |
feat(wordpress): add category/tag CRUD tools, fix delete-status and dead-field bugs (#5360)
* feat(wordpress): add category/tag CRUD tools, fix delete-status and dead-field bugs
- Add wordpress_{get,update,delete}_category and _tag tools for full taxonomy parity
- Fix `deleted: data.deleted || true` always evaluating true across all 6 delete tools (posts/pages/media/comments/categories/tags)
- Remove dead `force` param from delete_media (endpoint always force-deletes; param had zero effect)
- Remove unwired `hideEmpty` block input
- Normalize search_content perPage/page visibility to user-or-llm for consistency
* fix(wordpress): use ?? instead of || for zero-valued numeric fields in delete_category/tag
count and parent can legitimately be 0 (empty term, top-level category); || was
dropping those values, same antipattern already fixed for `deleted` in this PR.
Flagged independently by Greptile and Cursor Bugbot.
* fix(wordpress): use ?? for zero-valued numeric fields across all delete tools
Same || antipattern already fixed for category/tag delete tools was still
present in delete_post/page/comment/media for id, author, featured_media,
menu_order, parent, post — all legitimately 0 in common cases (no featured
image, top-level page/comment). Found by a final independent validation pass.
* fix(wordpress): don't drop categoryParent=0 (root-level category) in block param mapping
Truthy check on params.categoryParent treated a resolved numeric 0 (root-level,
no parent) as unset. Flagged by Cursor Bugbot on create_category/update_category.
* fix(wordpress): don't clear category/tag description on update when field left blank
description used !== undefined (numeric-field convention) instead of a truthy
check (string-field convention used everywhere else in this codebase, e.g.
update_post/update_page excerpt), so an untouched empty description field
silently wiped existing text on every update. Flagged by Cursor Bugbot.
* fix(wordpress): fix search type/subtype mislabeling, complete I/O exposure gaps
- search_content.ts: type param was mislabeled with subtype's vocabulary
(post/page/attachment); real WP type enum is post/term/post-format. Rewired
the block's Content Type dropdown to map to subtype (which is what
post/page/attachment actually filter), not type.
- Widened subBlock conditions so params already read by tools.config.params
are actually reachable in the UI: commentPostId for list_comments,
categories/tags for list_posts, parent for list_pages.
- Added missing subBlocks for tool params with no UI path: comment
parent/authorName/authorEmail/authorUrl (create_comment), media description
(upload_media), author filter (list_posts).
- Extended the ?? / !== undefined fix (already applied to categoryParent) to
the same class of param across the block: featuredMedia, page parent,
menuOrder, and the new commentParent/listAuthor mappings.
- Fixed featuredMedia/parent truthy-check inconsistency in create_post,
update_post, create_page, update_page, create_category, create_comment
body builders to match the !== undefined convention used elsewhere.
Found by an independent final validation pass across 3 parallel agents.
* fix(wordpress): keep searchType subBlock id to preserve saved-workflow compat
The type/subtype fix should only change which API param the field feeds
(subtype, not type) — renaming the subBlock id to searchSubtype broke
already-saved workflows with a search content-type filter set, since the
block would stop reading the old searchType key. Reverted the id rename,
kept the underlying subtype mapping fix. Flagged by Cursor Bugbot.
* fix(wordpress): remove invalid Attachment search subtype, fix listAuthor input type
- Search Content's "Content Type" dropdown offered Attachment, which maps to
subtype=attachment. WP core's WP_REST_Post_Search_Handler explicitly
excludes attachment from valid subtypes (media isn't searchable via
/search) — selecting it guaranteed a 400 rest_invalid_param. Removed the
option; only Post/Page (the only valid subtypes) remain.
- listAuthor was declared type: 'string' in the inputs catalog despite being
Number()-coerced before use, inconsistent with every other ID-like field
(postId, pageId, categoryId, commentParent, etc. are all 'number').
Found by an independent final pre-merge validation pass, requested before
merge to be certain of full API alignment.
|
||
|
|
7a31871471 |
feat(clerk): expand Clerk integration with org, membership, moderation, and security tools (#5364)
* feat(clerk): expand Clerk integration with org, membership, moderation, and security tools - fix 4 validate-integration warnings: missing .trim() on org/session IDs, incomplete session-status dropdown, missing list_users/list_organizations filter subBlocks - add organization update/delete tools - add organization membership CRUD (list, add, update role, remove) - add organization invitation create/list - add user ban/unban/lock/unlock and OAuth access token retrieval - add allowlist/blocklist identifier management - add JWT template list/get - add actor token create/revoke (impersonation) - add matching webhook triggers for session ended/removed/revoked, organization updated/deleted, and membership updated/deleted - wire all 23 new tools into the block, tool registry, and trigger registry * fix(clerk): I/O completeness fixes from final validation pass - remove dead limit/offset params from list_blocklist_identifiers (Clerk API accepts zero params on this endpoint, verified across 6 spec versions) - expose publicMetadata on OAuth access token output (was silently dropped) - expose inviter email/first/last name (public_inviter_data) on organization invitation create/list outputs - add missing orderBy param to list_organization_invitations |
||
|
|
f33d325a88 |
fix(deps): bump echarts to 6.1.0 to patch XSS vulnerability (#5374)
Fixes GHSA-fgmj-fm8m-jvvx / CVE-2026-45249 — Lines series tooltip rendering could execute raw HTML from series.data[i].name when no custom tooltip.formatter is set. |
||
|
|
070f554047 |
feat(sharepoint): validate against Graph API and add delete/update/download tools (#5369)
* feat(sharepoint): validate against Graph API and add delete/update/download tools - Fix bugs found validating existing tools against live Graph docs: malformed nested $expand syntax in get_list, reversed site-resolution precedence in create_list, unsanitized field fallback in add_list_items, missing URL encoding in read_page, and an incorrect root/serverRelativeUrl field shape - Fix V1 block gaps vs V2: upload_file required flag, missing required on pageName/listDisplayName, wrong site-picker mimeType, dead subBlock refs - Add 8 new tools within already-granted scopes for CRUD completion: delete_list_item, get_list_item, delete_page, update_page, publish_page, download_file, delete_file, get_drive_item - Add opt-in stripAuthOnRedirect option to secureFetchWithPinnedIP so the SharePoint file-download route doesn't resend the bearer token to the preauthenticated redirect target (default off, no behavior change elsewhere) - Dedupe read-only list-item field sanitization into a shared utils helper * fix(sharepoint): encode siteId consistently and fix create_page precedence - URL-encode siteId/groupId everywhere it's interpolated into a Graph request path (Graph site IDs like "host,guid,guid" contain commas that must be encoded) - addresses Cursor Bugbot findings on update_page, delete_page, publish_page, and applies the same fix consistently across every other sharepoint tool for consistency - Fix create_page's site-resolution precedence (was siteSelector before siteId, inconsistent with every sibling tool) * fix(sharepoint): escape HTML in page content and stop fallback from throwing - create_page/update_page only escaped quotes when building innerHtml; add a shared escapeHtml() helper that also escapes &, <, > so page content with angle brackets/ampersands doesn't corrupt the canvas layout - add_list_items' fields fallback (sanitized re-derivation when Graph's response omits fields) could throw on a malformed fallback input after the item was already created successfully; catch and fall back to undefined instead of failing an already-successful response * fix(sharepoint): scope columnDefinitions->pageContent mapping to create_list Both V1 and V2 tools.config.params mapped columnDefinitions onto pageContent whenever columnDefinitions was truthy, with no operation check. Stale list-column JSON left in block state after switching to create_page/ update_page would silently replace the user's intended page text. Gate the mapping on operation === create_list (V1) / sharepoint_create_list (V2). * fix(sharepoint): cap download-file content fetch at MAX_FILE_SIZE Greptile flagged the content fetch as unbounded - a large file would buffer entirely in memory before base64-encoding into the JSON response. Pass maxResponseBytes: MAX_FILE_SIZE (100MB, same constant used by the upload path) to secureFetchWithPinnedIP so oversized files reject early with a clear PayloadSizeLimitError instead of exhausting memory. * fix(sharepoint): close V1 block input/output gaps and encode upload URLs Final validation pass (4 parallel audit agents against live Graph docs) surfaced remaining gaps: - apps/sim/app/api/tools/sharepoint/upload/route.ts: siteId/driveId were not encodeURIComponent-ed in the Graph upload URL, unlike every other sharepoint route/tool - same encoding-gap class fixed everywhere else - read_page.ts: transformResponse recomputed siteId with a raw `||` in 3 spots instead of the optionalTrim(...) || optionalTrim(...) || 'root' precedence used by request.url and every sibling tool - SharepointBlock (V1, legacy/hidden-from-toolbar but still executable for existing saved workflows): listItemFields and listItemId were missing `required` for update_list despite the tool requiring them; maxPages/groupId/includeColumns/includeItems/nextPageUrl subBlocks were entirely absent, making those tool params unreachable from the UI; block-level outputs were missing site/pages/content/totalPages/ nextPageUrl/lists/skippedFiles/skippedCount/errors even though the underlying tools return them - V2 already covered all of these |
||
|
|
acece910b4 |
fix(supabase): remove non-functional SQL introspection, harden storage encoding, add missing endpoints (#5371)
* fix(supabase): remove non-functional SQL introspection path, harden storage URL encoding, add missing storage endpoints
- introspect.ts no longer attempts raw SQL via a nonexistent PostgREST
RPC endpoint (always failed); now uses the OpenAPI-spec path directly
with honest heuristic/best-effort documentation for PK/FK/index fields
- storage tools now trim + URL-encode bucket/path segments before
building request URLs (download, list, get_public_url,
create_signed_url, delete_bucket, delete, and the upload API route)
- storage_create_signed_url guards against a missing signedURL field
in the response instead of silently building a broken URL
- add supabase_storage_create_signed_upload_url, supabase_storage_update_bucket,
and supabase_storage_empty_bucket tools + block wiring
- change insert/upsert `data` param type from 'array' to 'json' to match
actual accepted shapes (array or single object)
- bump tool versions to semver (1.0 -> 1.0.0)
- rewrite a BlockMeta template that implied unsupported Supabase Auth
Admin user-provisioning
(cherry picked from commit 52b655acf59bace806c75c06b4b2cfaebe4b6781)
* fix(supabase): address review feedback on update-bucket, signed upload url, and introspect
- storage_update_bucket now fetches the bucket's current config first
and only overrides isPublic/fileSizeLimit/allowedMimeTypes when the
caller explicitly provides them, instead of silently forcing
public: false on every update (the Storage API's PUT is a full
replace, not a patch)
- storage_create_signed_upload_url and storage_empty_bucket now check
response.ok before surfacing an error, so a non-2xx response reports
Supabase's actual error instead of a misleading parse-side message
- introspect.ts drops the spurious ?select=* query param from the
OpenAPI spec request (meaningless on the root spec endpoint)
(cherry picked from commit 557e4074594464262b2f631ca66272bf60f027f8)
* fix(supabase): tri-state bucket visibility on update, empty-string param coercion, introspect schema header
- introspect.ts now sends Accept-Profile when a schema param is given,
matching the convention used by the other DB tools, so schema-scoped
introspection actually reads from that schema's spec
- storage_update_bucket.ts treats an empty-string param the same as
"not provided" (e.g. an untouched file size limit input no longer
coerces to 0)
- the shared "Public Bucket" dropdown always sent an explicit true/false
for storage_update_bucket (its default masked "not touched"), which
could still flip a public bucket private; added a dedicated
"Keep Current / True / False" control for the update operation so
omitting a choice genuinely omits the isPublic override
(cherry picked from commit c80567b980e9a547b892a222cebee2bd03d89420)
* fix(supabase): check response.ok before parsing storage_create_signed_url
Matches the pattern already applied to the new signed-upload-url tool
this session — a non-2xx response now surfaces Supabase's actual error
message instead of the generic "did not return a signed URL path" one.
(cherry picked from commit 9f40427dd80ec21b4af1e85c9c8218fd961d6931)
* fix(supabase): correct download param semantics, echoed path field, and schema hint mismatch
Found by a second, per-tool parallel validation pass against live Supabase/PostgREST docs and source:
- storage_get_public_url.ts and storage_create_signed_url.ts sent
download=true literally, which Supabase's Storage API treats as a
filename override (renaming the downloaded file to "true") rather
than a boolean flag; forcing a download while keeping the original
filename requires an empty download= value
- storage_create_signed_url.ts also sent download in the POST body,
which the sign endpoint ignores entirely — forcing download only
works as a query param on the returned URL
- storage_create_signed_upload_url.ts read a `path` field from the API
response that doesn't exist there; it now echoes the caller-supplied
path, matching the official storage-js client
- introspect.ts's nullable heuristic didn't disclose that a NOT NULL
column with a default is misreported as nullable (PostgREST omits it
from the OpenAPI required list in that case); documented alongside
the other already-disclosed heuristics, and removed a tautological
schema-filter check left over from an earlier revision
- insert.ts/upsert.ts's `data` param reverted from 'json' back to
'array': the 'json' type mapped to an LLM-facing JSON-schema type of
'object', which contradicted the param's own description ("array of
objects or a single object")
|
||
|
|
943ee27686 |
feat(langsmith): add run update, get run, and feedback tools (#5363)
* v0.6.29: login improvements, posthog telemetry (#4026) * feat(posthog): Add tracking on mothership abort (#4023) Co-authored-by: Theodore Li <theo@sim.ai> * fix(login): fix captcha headers for manual login (#4025) * fix(signup): fix turnstile key loading * fix(login): fix captcha header passing * Catch user already exists, remove login form captcha * feat(langsmith): add run update, get run, and feedback tools - add langsmith_update_run (PATCH /runs/{id}) to complete the create-then-patch tracing lifecycle - add langsmith_get_run (GET /runs/{id}) to read a run back - add langsmith_create_feedback (POST /feedback) to attach scores/corrections to runs - wire all three into the LangSmith block, reusing shared subBlocks across operations - fix feedback-capture template to use real feedback API instead of faking it via tagged runs - switch manual Object.fromEntries filtering to filterUndefined per repo convention * fix(langsmith): reject non-numeric feedback score instead of silently sending null Number() on an invalid score string produces NaN, which serializes to JSON null and would still be sent to LangSmith. Throw instead, matching the existing parseJsonValue error pattern. * fix(langsmith): harden error handling and validation on new run tools - update_run, get_run, create_feedback now check response.ok before parsing/returning, matching the cloudwatch/zoom convention instead of silently returning success on a 4xx/404 - block outputs schema now exposes inputs/outputs for Get Run - update_run requires at least one field to patch, matching the batch-ingest guard for post/patch * fix(langsmith): align get_run/update_run outputs and narrow feedback score type - get_run now also outputs runId (alias of id) so workflows can read the run identifier consistently across all operations on the block - update_run now parses and surfaces the response message instead of discarding the body entirely, matching create_run's pattern - narrow LangsmithCreateFeedbackParams.score to number — the tool param is declared as JSON-schema 'number' and the block's parseScore never produces a boolean, so the wider type was dead and misleading * fix(langsmith): reject empty-string patch fields and empty PATCH bodies - block mapper now normalizes blank name/end_time/status/error inputs to undefined instead of forwarding empty strings, which would clear those fields on the LangSmith run - update_run tool now throws if the filtered PATCH body is empty, guarding direct/programmatic tool calls that bypass the block's own "at least one field" check * fix(langsmith): normalize empty-string patch fields at the tool layer too Direct/agent tool calls bypass the block's own emptyToUndefined guard, so update_run now normalizes blank name/end_time/status/error itself before filtering, matching the block-level fix. --------- Co-authored-by: Theodore Li <theodoreqili@gmail.com> Co-authored-by: Siddharth Ganesan <33737564+Sg312@users.noreply.github.com> Co-authored-by: Vikhyath Mondreti <vikhyathvikku@gmail.com> Co-authored-by: Theodore Li <theo@sim.ai> |
||
|
|
a267a95809 |
fix(vercel): align integration with live Vercel REST API docs (#5370)
* fix(vercel): align integration with live Vercel REST API docs - add missing teamId/slug scoping to 29 tools (deployments, checks, projects, env vars) - add DNS SRV/HTTPS record support (nested srv/https objects) to create/update_dns_record - add decrypt/gitBranch filters to get_env_vars, autoUpdate to rerequest_check - add redirect param to create_alias, comment to create_dns_record - add missing customNameservers/userId/teamId/transferStartedAt fields to list_domains output - wire pagination filters (limit/since/until/search/app) into block subBlocks for list_deployments, list_teams, list_team_members, list_dns_records, list_project_domains - wire previously-unexposed tool params into block UI: withGitRepoInfo, gitSource, forceNew, externalId, rerequestable, output, direction, follow - fix duplicate projectId subBlock id collision between list_deployments and other project-scoped operations - fix teamId scope field incorrectly hidden for check operations * fix(vercel): address review findings on DNS/deployment param handling - fix withGitRepoInfo 'No' dropdown sending withGitRepoInfo=false instead of omitting the param - remove redundant duplicate 'Forward' option from eventsDirection dropdown - fix mxPriority being silently dropped in update_dns_record when record type is left unset * fix(vercel): fix pagination token type mismatch and clarify DNS update UX - fix list_projects nextFrom being stored as a number despite string typing, which threw TypeError on .trim() when chained into a follow-up list_projects call - clarify that the DNS update Value field has no effect on existing SRV/HTTPS records unless Record Type is explicitly reselected * fix(vercel): fix zero-value SRV/HTTPS/MX numeric fields being dropped - SRV weight/port/priority, HTTPS priority, and MX priority use truthy checks that silently drop legitimate 0 values; switch to explicit empty/null checks - add missing MX Priority field to create_dns_record block UI (tool already required it for MX records but there was no way to set it) * fix(vercel): fix stale cross-operation field leaks in block params - fix list_deployments/create_deployment/update_check/list_team_members/update_dns_record/update_env_var conditionally spreading into keys that collide with unrelated operations' non-destructured literal subBlock fields (projectId, deploymentId, target, name, search) - a stale value left over from switching operations in the UI would silently leak into the wrong tool call since the conditional spread only overrides when the current operation's own field has a value - fix now always assigns these keys directly so they deterministically override any stale base value * feat(vercel): close remaining input/output completeness gaps - add missing slug (team-slug) param to 13 domain/DNS/alias tools that were skipped in an earlier fix pass, matching the pattern used everywhere else in this integration - add rootDirectory, nodeVersion, devCommand params to create_project/update_project (verified against Vercel's live OpenAPI spec — high-value fields for monorepo support and runtime pinning) - surface rootDirectory/nodeVersion in get_project/list_projects outputs, since the API already returns them - wire all new fields into the block UI as advanced fields * fix(vercel): fix remaining No->false truthy-string dropdown bugs - checkRerequestable, checkAutoUpdate, envVarsDecrypt dropdowns used id: 'false' for their No option (a truthy non-empty string), causing the conditional spread to always fire and explicitly send false instead of omitting the param - swept the whole file for this pattern; checkBlocking correctly keeps 'false' since it's a required field that's always sent directly, not conditionally * fix(vercel): fix silent project-rename leak in update_project - update_project had no dedicated rename field and just returned base directly, so a stale value from create_deployment's unrelated 'name' subBlock (Project Name for the deployment) could silently flow through and rename a project on update - add a dedicated 'New Project Name' field for update_project, wired with a direct override so it always takes precedence over any stale leaked value |
||
|
|
0507acf2dd |
fix(amplitude): correct wire formats and add funnels/retention analytics (#5355)
* fix(amplitude): validate integration against API docs, add funnels/retention - Fix Identify/Group Identify sending JSON instead of the form-urlencoded body Amplitude requires - Fix Send Event using snake_case product_id/revenue_type instead of Amplitude's camelCase productId/revenueType - Fix Get Revenue parsing a response shape that never matched the real Revenue LTV API - Add EU data residency support across all tools - Add missing filters/formula/segment params to Event Segmentation, groupBy/segment to Active Users and Revenue - Add first_used/last_used to User Activity output, non_active/flow_hidden to List Events output - Add real-time/hourly interval options to Event Segmentation - Add Funnels and Retention tools for conversion and retention analysis - Harden JSON-shape validation across funnels/segmentation/retention (fail loudly on malformed or partial input instead of silently degrading) - Expose every tool output field (user_profile, send_event, user_search) on the block so nothing is unreachable downstream - Update brand colors to current Amplitude guide * fix(amplitude): validate retention brackets, require formula param, add segmentation 2nd group-by - Retention now validates retentionBrackets as a JSON array and requires it when retentionMode is "bracket", matching the block UI's requirement - Event Segmentation now throws if metric is "formula" but no formula is provided, matching the block UI's requirement - Event Segmentation now supports a documented second group-by property via groupBy2/g2 - Corrected Get Active Users' group-by copy — Amplitude's docs don't document a second-property syntax for /api/2/users the way they do for segmentation's g2, so the field no longer overpromises "max two" |
||
|
|
59d6b8a62e |
fix(onepassword): validate integration against API docs, add file downloads (#5365)
* fix(onepassword): validate integration against API docs, add file downloads
- add onepassword_get_item_file tool + route for downloading item file
attachments (SDK items.files.read / Connect files/{id}/content), backed
by newly-exposed item.files metadata on get/create/replace/update item
- fix update_item JSON Patch applying array indices instead of 1Password's
documented field-ID addressing (/fields/{fieldId}/...), which silently
dropped field edits in Service Account mode
- fix Service Account mode's list-vaults/list-items filter to honor SCIM
`eq` exact-match semantics instead of always substring-matching
- expand the create-item category dropdown from 9 to 19 real, creatable
1Password categories (was missing SOFTWARE_LICENSE, EMAIL_ACCOUNT,
MEMBERSHIP, PASSPORT, REWARD_PROGRAM, DRIVER_LICENSE, BANK_ACCOUNT,
MEDICAL_RECORD, OUTDOOR_LICENSE, WIRELESS_ROUTER, SOCIAL_SECURITY_NUMBER)
- replace the block's single opaque `response: json` output with typed,
per-operation output fields matching repo convention
- remove incorrect password-masking on the Vault ID field (not a secret)
- re-export tool types from the onepassword barrel
* fix(onepassword): honor SCIM attribute name in filter matcher
matchesFilter always compared against name/title regardless of the
attribute named in the eq expression, so `id eq "..."` incorrectly
matched against the display name instead of the id.
* fix(onepassword): close output-parity and doc-string gaps from final audit
- restore a deprecated no-op 'response' output so pre-existing saved
workflows referencing it fail soft (empty) instead of hard-erroring
now that per-operation outputs replace it
- add missing block outputs (urls, favorite, version, state,
lastEditedBy) for get/create/replace/update item so all real
FULL_ITEM fields are discoverable as <Block.field> references
- hide Connect Server credential fields for Resolve Secret (Service
Account only) instead of leaving them selectable and silently ignored
- correct two doc-string enum lists that advertised values the API
doesn't return (vault type TRANSFER, item state DELETED)
* fix(onepassword): fix silent data loss in update_item (Service Account mode)
update_item applied user JSON Patch ops (documented/typed against the
Connect-shaped vocabulary get_item returns: label/type/section.id)
directly onto the raw SDK item, whose vocabulary differs (title/
fieldType/sectionId, and SDK category enum strings vs Connect's
SCREAMING_SNAKE_CASE). Most patches beyond /title, /tags/-, and
/fields/{id}/value silently no-opped or could corrupt the item while
still reporting success.
Extracted the Connect->SDK item conversion already used by replace_item
into a shared connectItemToSdkItem helper. update_item now normalizes
the fetched item to Connect shape, applies patches to that, then
converts back before calling items.put() -- matching create/replace's
existing translation pattern.
Found via an adversarial final-verification pass that traced concrete
patch operations by hand against the SDK's actual field vocabulary.
* fix(onepassword): preserve field metadata and empty-title fallback
connectItemToSdkItem rebuilt every field as a bare object, dropping
SDK-only metadata (e.g. password-generation details) that a raw
patch/replace previously left untouched. Now merges onto the existing
SDK field by id before applying the translated properties, and only
starts fields bare when they're genuinely new.
Also restored the || (not ??) fallback on title to match replace_item's
prior behavior of treating an explicitly empty title as "not provided".
|
||
|
|
f658e6dc73 |
fix(tailscale): align tool coverage and outputs with the Tailscale API (#5366)
* fix(tailscale): align tool coverage and outputs with the Tailscale API
- fix list_users profilePicUrl field name (API returns lowercase, was always null)
- add nodeId, keyExpiryDisabled, expires to device outputs
- quote the If-Match header value on ACL updates per API spec
- add set_acl, expire_device_key, suspend_user, delete_user tools
- add wandConfig to dnsServers/searchPaths block fields
- expand BlockMeta skills/templates for ACL and key-expiry workflows
* fix(tailscale): remove phantom magicDNS field from list_dns_nameservers
The GET /tailnet/{tailnet}/dns/nameservers response only returns
{dns: string[]} per the API spec — magicDNS is not part of this
endpoint's response and was always silently false.
* fix(tailscale): extend ToolResponse in expire_device_key response type
Matches the pattern used by the other new tools in this PR
(delete_user, suspend_user).
* fix(tailscale): list_auth_keys now returns all tailnet keys
GET /tailnet/{tailnet}/keys silently scopes to the caller's own
keys unless all=true is passed, contradicting the tool's stated
purpose of listing all auth keys in the tailnet.
|
||
|
|
5966e5cf5a |
feat(similarweb): add page views tool, fix paid referrals field mismatch (#5354)
* feat(similarweb): add page views tool, fix paid referrals field mismatch - Add similarweb_page_views tool (Total Page Views, Desktop & Mobile) - Fix paidReferrals in website overview: API Lite response key is literally "paid _referrals" (space before underscore), not caught by the existing fallback chain, so it always resolved to null - Move startDate/endDate/mainDomainOnly to advanced mode * fix(similarweb): accept both page_views key spellings in page views response Cursor Bugbot and Greptile both flagged the response field as page_views by convention, but SimilarWeb's own docs example response uses pages_views for this specific endpoint. Accept both spellings defensively so the tool works regardless of which is actually returned. |
||
|
|
e7c9a67194 |
fix(algolia): tighten tools.config, add geo/facet search + task-status tool; icon/color tweaks (#5356)
* fix(algolia): fix serialization-time param mutation, add geo/facet search, task status tool
- move all tools.config coercion/remapping out of tool() into a proper params() function so dynamic block references aren't destroyed before variable resolution
- wire facets and getRankingInfo into the search tool so those documented outputs are actually reachable
- add geo-search (aroundLatLng/aroundRadius/insideBoundingBox/insidePolygon) to search and browse_records, matching delete_by_filter
- fix aroundRadius param type (string, not number, since it accepts "all")
- sync batch_operations description with the real action set (delete, clear)
- consolidate list_indices pagination into the shared page/hitsPerPage fields instead of duplicate listPage/listHitsPerPage
- add algolia_get_task_status tool so workflows can poll a taskID instead of guessing when a write is applied
- trim indexName/objectID/destination before building request URLs
- add ranking-tuning and index-snapshot skills to AlgoliaBlockMeta
fix(dropcontact): swap icon to the official wordmark's teal swirl mark, bgColor to match
chore(grafana): bgColor to white to match brand tile convention
* fix(algolia): register subblock-id migration for listPage/listHitsPerPage
CI's subblock-id stability check correctly flagged that consolidating
list_indices pagination into the shared page/hitsPerPage fields would
silently drop values from already-deployed workflows. Add the rename
mapping so existing saved state migrates instead of being lost.
* fix(algolia): remove fabricated pendingTask field from get_task_status
Algolia's Get Task Status response (additionalProperties: false) only
returns `status` (published | notPublished) — pendingTask belongs to
the List Indices response, not this endpoint. Drop it from the tool's
output, response type, and block outputs rather than inventing data.
* fix(algolia): coerce getRankingInfo/createIfNotExists/forwardToReplicas from real booleans, not just strings
A wired <Block.output> boolean (e.g. true) failed the `=== 'true'`
string-only checks and silently flipped to the wrong value. Add a
toBool helper that accepts both the dropdown's string values and a
genuine boolean passed in via a dynamic reference.
fix(dropcontact): render icon with currentColor instead of hardcoded fill
The new teal swirl mark's fill (#0ABA9F) matched the block's bgColor
exactly, making the icon invisible on its own tile. Use currentColor
and set iconColor so the shared tile-contrast logic (getTileIconColorClass)
renders it white-on-teal like the rest of the brand icon system.
* fix(algolia): trim indexName in request bodies, not just URL paths
Greptile caught that search.ts's body-level indexName (sent inside the
multi-query POST body, not URL-encoded) wasn't trimmed like every other
tool's URL-path indexName. Fixed there and in get_records.ts's per-request
indexName default/override, which had the same gap.
* fix(algolia): route list_indices and get_task_status GETs to the -dsn read host
Verified against Algolia's official JS client source
(getDefaultHosts + transporter isRead = useReadTransporter || method === 'GET'):
every GET request routes to the read (-dsn) host, matching the other 14
tools in this integration (get_record, get_settings, etc). Both tools
were incorrectly hitting the write host.
* chore(algolia): regenerate docs to drop stale pendingTask entry
The get_task_status pendingTask output was removed from code in
|
||
|
|
02b1de4faf |
fix(ahrefs): align tool coverage and outputs with the Ahrefs API v3 (#5367)
* fix(ahrefs): align tool coverage and outputs with the Ahrefs API v3 - 5 of 8 tools were missing the required `select` param (API v3 rejects list-endpoint requests without it) and 3 sent a `date` param the endpoint doesn't accept - all list endpoints sent an `offset` param that doesn't exist on any Ahrefs v3 site-explorer endpoint (only `limit` is supported) - domain_rating and backlinks_stats read response fields at the wrong nesting level and always returned zeros; several other tools mapped output fields to column names the API doesn't return (position, url, traffic, backlinks, dofollow_backlinks, http_code) instead of the real ones (best_position, best_position_url, sum_traffic, links_to_target, dofollow_links, http_code_target) - keyword_overview used the wrong endpoint param entirely (`keyword` instead of `keywords`) so it always returned empty - added ahrefs_metrics (site-explorer/metrics) and ahrefs_organic_competitors (site-explorer/organic-competitors) tools - fixed docsLink to point at docs.sim.ai instead of ahrefs.com * fix(ahrefs): default metrics country to us like every other tool Greptile and Cursor Bugbot both flagged that ahrefs_metrics omitted the country when unset, unlike every other country-accepting Ahrefs tool, which silently returns global data instead of US data on direct tool calls. * fix(ahrefs): default history to all_time on backlinks and referring domains Cursor Bugbot flagged that history was only sent when explicitly set, even though the block UI defaults it to all_time — same class of gap as the metrics.ts country fix, applied for direct tool-call consistency. * feat(ahrefs): expose search intent flags on keyword overview Adds the real intents field (informational, navigational, commercial, transactional, branded, local) from keywords-explorer/overview, which was verified valid against the live API docs but not yet surfaced. |
||
|
|
dabb856b9a |
fix(loops): align integration with live API docs, add suppression + get-template tools (#5358)
* fix(loops): align integration with live API docs, add suppression + get-template tools - fix list_transactional_emails endpoint URL (was /transactional, now /transactional-emails) - fix response fields to match actual API schema (createdAt/updatedAt, not the never-existent lastUpdated) - add loops_check_contact_suppression, loops_remove_contact_suppression, loops_get_transactional_email tools - wire new tools into block operations, outputs, and registries - alphabetize tools/registry.ts loops entries * fix(loops): expose contactId output, fix stale tool description - add missing contactId block output for check_contact_suppression (Greptile P1) - fix list_transactional_emails description to mention createdAt (Greptile P2) * fix(loops): restore lastUpdated as backwards-compat alias on list_transactional_emails Final validation pass found that /api/v1/transactional (the endpoint this tool used before this PR) is a real, functional, deprecated Loops endpoint whose schema genuinely returns lastUpdated - it was not a broken/invented field. Migrating to /api/v1/transactional-emails is still correct (current endpoint, better error semantics), but dropping lastUpdated would break any existing workflow reading it from this block's output. Keep it as a deprecated alias of updatedAt alongside the new createdAt/updatedAt fields. * fix(loops): update id output description to cover get_transactional_email |
||
|
|
7fd89bca35 |
fix(brex): surface isPproEnabled in transfer block outputs (#5373)
Tool-level get_transfer/list_transfers already returned is_ppro_enabled (confirmed present on Brex's live Transfer schema), but the block's outputs map didn't declare it, so it was unreachable from the workflow UI. Adds it alongside the other transfer output fields. |
||
|
|
5553c449af |
improvement(brex): fill validate-integration gaps against live API docs (#5362)
- add wandConfig AI-autofill to expense/spend-limit filter subBlocks - surface is_ppro_enabled on get/list transfer tools - surface start_date/end_date/authorization_settings on list_spend_limits to match get_spend_limit |
||
|
|
220da449c9 |
fix(mothership): stop inlining full execution traces for the logs context (#5353)
* fix(mothership): stop inlining full execution traces for the logs context Tagging a run via "Troubleshoot in Chat" (or any @-mention of a logs context) resolved through processExecutionLogFromDb, which materialized the ENTIRE execution trace (every block's input/output, nested tool-call spans) and inlined it directly into the prompt. For any non-trivial run this repeatedly blew the context window, forcing multiple compactions and eventually auto-stopping the agent before it could investigate anything. Every other context resolver in this file already avoids this by sending a lightweight pointer instead of a full inline dump (workflow/blocks/ workflow_block contexts point into the VFS). Logs contexts have no VFS materialization to point at, but the equivalent lightweight mechanism already exists as a tool: query_logs supports incremental disclosure (overview for timing/cost, full for a scoped block's input/output, or pattern to grep the trace) and is already registered for the mothership agent. Now processExecutionLogFromDb sends a compact summary (id, workflow, level, trigger, timing, cost) plus a note pointing the model at query_logs with the executionId, instead of materializing and embedding the trace. Also drops the now-unused executionData column from the select projection, so resolving a logs context no longer fetches a potentially large JSONB blob it never reads. * improvement(mothership): send a bounded block overview instead of a bare tool pointer Follow-up to the previous commit's fix (stop inlining full execution traces). A pure text pointer telling the model to call query_logs made the agent's very first useful action against a tagged run contingent on it noticing and correctly acting on prose in a JSON blob it may only skim — every sibling resolver in this file instead returns a deterministic mechanism (a VFS path) the model reads on demand. There's no VFS materialization for individual execution logs, but the same deterministic signal is available cheaply: toOverview() (the exact projection query_logs's own "overview" view already returns) walks the raw trace spans and produces a compact tree — block name/type/status/ timing/cost, no input or output — without touching large-value refs at all. The summary now includes that tree, so the model can see which block failed on the first turn, and the note narrows to what still requires a tool call: a block's actual input/output/error, or a grep. materializeExecutionData is still called, but it's a no-op for the common inline case (it only unwraps a top-level object-storage pointer for runs whose whole trace was offloaded as one blob) and was needed to reach traceSpans at all for those heavier runs — exactly the runs most worth an overview. A serialized-size cap (mirroring query-logs.ts's own truncation fallback, scaled down since this lands in the prompt unconditionally) drops the overview if a pathological span count pushes it over budget, falling back to the note alone. Extends the tests: the happy path now asserts the overview tree is present and that no raw input/output payload leaks into the serialized summary, plus a new test for the size-cap fallback. |
||
|
|
b34608856d |
fix(logs): right-size and reorganize log-detail action chips (#5352)
Two concrete regressions from the earlier Chip conversion (#5341): - Both chips used variant='primary' (the solid inverse-fill treatment), the heaviest chrome in the design system, reserved for a single standout action per context (Save, Upgrade, Add key) — never a peer among several row actions. Two solid pills stacked in a narrow side panel read as oversized. Switched both to the bare (default) chip, matching every analogous row action in Settings. - The Version badge was size='md' while its siblings (Level, Trigger) are size='sm' — an inconsistency. Aligned to 'sm'. Also folded the floating 'Troubleshoot in Chat' chip into the Details card as its own row (matching 'Snapshot' exactly) instead of leaving it orphaned below Workflow Output — every row in the card now shares one shape (label left, trailing content right), consistent top to bottom. |
||
|
|
e01123f715 |
feat(blog): add CTA band above footer (#5350)
- reuse the shared Cta component (same "Build your first agent today" band used on the homepage) at the end of the blog listing |
||
|
|
dcc7c0c7c4 |
ci(dev): auto-deploy Trigger.dev tasks + fail dev db:push on TTY prompt (#5343)
* ci(trigger): auto-deploy Trigger.dev tasks to dev-sim on dev pushes Add a deploy-trigger-dev job that runs `trigger.dev deploy --env preview --branch dev-sim` on pushes to the dev branch, replacing the manual step. Gated after migrate-dev for the same reason as build-dev: the new task code runs against the dev DB, so the schema must be pushed first. Uses Trigger.dev's remote build (no --local-build), so the runner needs no Docker/buildx. Requires a TRIGGER_ACCESS_TOKEN repo secret. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015orsjbLX34FPFGujSK3AQK * ci(trigger): source TRIGGER_PROJECT_ID from repo secret Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015orsjbLX34FPFGujSK3AQK * ci(trigger): fail fast when Trigger.dev secrets are unset Guard the deploy step so a missing TRIGGER_ACCESS_TOKEN or TRIGGER_PROJECT_ID exits with a clear message instead of a cryptic trigger.dev CLI error, matching the DATABASE_URL guard in migrations.yml. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015orsjbLX34FPFGujSK3AQK * ci(migrations): fail dev db:push on interactive prompt or error drizzle-kit push prompts interactively for ambiguous renames (--force only covers data-loss). In CI there's no TTY, so the prompt reads EOF and drizzle can exit 0 without applying — the job goes green while the schema change was silently skipped. Close stdin, reject prompt markers, and require a success marker so an unresolved rename or failed statement fails the job. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015orsjbLX34FPFGujSK3AQK * ci(migrations): fail dev db:push when drizzle-kit hits a TTY prompt drizzle-kit push needs a TTY to resolve ambiguous renames; in CI it throws "Interactive prompts require a TTY terminal" but still exits 0, so the job went green without applying the schema (e.g. run 28415609570). Fail on that explicit error. Keys on drizzle's own stable message rather than fuzzy prompt text, and a real non-zero exit still fails via set -e. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015orsjbLX34FPFGujSK3AQK * ci(trigger): scope the access token secret as DEV_TRIGGER_ACCESS_TOKEN The PAT is only used by the dev deploy job, so prefix it DEV_ to match the repo's dev-scoped secret convention. TRIGGER_PROJECT_ID stays unprefixed — it's the shared project (same one prod uses); dev-sim is a preview branch within it, not a separate project. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015orsjbLX34FPFGujSK3AQK * Adjust warning error * ci: align build-dev checkout to v6 to match the other jobs build-dev was the only job still pinning actions/checkout to the v4 hash; every other job uses v6. Non-functional consistency fix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015orsjbLX34FPFGujSK3AQK --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
69b81a679b |
feat(data-retention): granular PII redaction stages (input + block outputs) (#5272)
* feat(data-retention): granular PII redaction stages (input + block outputs) * fix(data-retention): propagate block-output redaction into child workflows * fix(data-retention): close block-output redaction gaps on streaming + resume * fix(data-retention): drain+mask streamed output, resolve PII policy unconditionally (no fail-open) * test(testing): support leftJoin().where().limit() in shared db mock * fix(data-retention): mask agent/Pi memory writes under block-output redaction * fix(data-retention): guard partial PII stages in GET normalize * fix(data-retention): mask seeded memory messages under block-output redaction * fix(guardrails): fail closed on misaligned Presidio batch responses * fix(data-retention): enabled stage with no entity types redacts all (no fail-open) * fix(data-retention): reject enabled stage with no entity types; empty = off everywhere * docs(data-retention): note resume remask covers inline values only * fix(data-retention): scrub offloaded large-value refs from logs when block-output redaction is off * fix(data-retention): hydrate, mask, and re-store large-value refs in logs (preserve redacted content) * fix(data-retention): always apply logs policy to large-value refs when logs stage is on * perf(data-retention): drop redaction byte ceiling, parallelize chunks (env-tunable), remove request timeouts, sync large-value walk * feat(data-retention): gate granular PII stages behind pii-granular-redaction flag - New pii-granular-redaction feature flag (fallback PII_GRANULAR_REDACTION), layered on pii-redaction, gating the execution-altering input + block-output stages - Route returns piiGranularRedactionEnabled and rejects enabling granular stages when off - UI shows only the Logs stage tab unless the flag is on; clamps active stage - Drop the per-search Select all toggle; add a Deselect all action to the PII section header * docs(pii): describe Presidio as a standalone service, not a sidecar Presidio now runs as its own ECS service (and, in Helm, its own Deployment + Service) reached over the network via PII_URL — not a sidecar in the app task. Update README, code comments, env docs, Dockerfiles, and the Helm chart docs to match, and note the deploy requirement that PII_URL must be reachable. * fix(data-retention): re-mask offloaded large-value refs on resume + don't lock out granular saves - Resume/run-from-block restore now hydrates → masks → re-stores large-value refs in restored blockStates (not just inline strings), so a value offloaded before the block-output stage was enabled can't warm raw PII into downstream blocks. Fails fast. - pii-large-values: add onFailure mode (throw on the execution path, scrub for logs) and redactLargeValueRefsInValue for arbitrary (non-RedactablePayload) values - Granular flag gate now rejects only NEW off→on granular enablement, so orgs that already configured granular stages can still save retention settings when the flag is off |
||
|
|
74571840cd | fix(knowledge): surface KB description validation errors and raise limit to 10k (#5347) | ||
|
|
8d6cec114a |
feat(blog): add five blogs (#5268)
* feat(blog): add five AI agent articles Add how-to-create-an-ai-agent, ai-agent-vs-chatbot, ai-agents-vs-rpa, ai-agent-ideas, and best-zapier-alternatives posts. * fix(blog): correct ai-agent-ideas pronoun and complete zapier TL;DR Fix 'everyone' -> 'every idea' in ai-agent-ideas intro; add the four missing tools (Power Automate, Pipedream, Relay.app, Integrately) to the best-zapier-alternatives TL;DR so it lists all 10. * fix(blog): remove HIPAA compliance claims We are not HIPAA compliant; drop the claim from ai-agents-vs-rpa and best-zapier-alternatives, keeping the SOC2 claim. * feat(blog): add cover images for new posts, refresh older post covers - Add cover.jpg for the 5 new AI agent blog posts - Replace existing cover art for enterprise, mothership, v0-5, multiplayer, executor, series-a, and openai-vs-n8n-vs-sim - Standardize openai-vs-n8n-vs-sim's og image to cover.jpg (was workflow.png) - Update ogImage frontmatter paths to match * fix(blog): move new post dates closer to today Shift the 5 new AI agent posts from June 23-27 to June 27 - July 1, keeping the same order and 1-day spacing, ending on today's date. * fix(blog): use current Sim terminology instead of legacy Mothership/Copilot names Per the constitution language rules, Sim's own natural-language agent surface is "Chat" and the agent you talk to is "Sim" — not "Mothership" or "Copilot" (those are prior internal names, still used correctly in the historical announcement posts but not for new content). Leaves references to Zapier's and Microsoft's own "Copilot" products as-is since those name real third-party features. |
||
|
|
26fb6875e0 |
fix(chat): fix secret-input chat widget reshaping after submit (#5346)
SecretReveal (the post-submit redacted state) used bespoke h-9/rounded-md/px-2.5 chrome with an absolutely-positioned copy button, instead of the canonical chip-field chrome (h-[30px]/rounded-lg/px-2) that SecretInput (the pre-submit state) uses. That mismatch made the credential-paste widget visibly resize right after saving. Rebuilt SecretReveal on the same chipFieldSurfaceClass tokens as ChipInput, with the copy button as an inline trailing adornment. |
||
|
|
577b402636 |
fix(chat): scope troubleshoot handoff to its workspace (#5344)
* fix(chat): scope troubleshoot handoff to its workspace MothershipHandoffStorage now records the target workspaceId and only the matching workspace consumes (and clears) it; a different workspace leaves it untouched for its owner. Prevents a workspace-A handoff from firing in workspace B, where A's executionId can't resolve and the run context is dropped. * test(chat): cover legacy no-workspaceId handoff tombstoning |
||
|
|
4df352fb72 |
fix(integrations): resolve Server Components crash on the integration detail page (#5345)
Root cause (confirmed via staging server logs, digest 783665031): the [block] page.tsx is a server component whose Suspense fallback rendered <ChipLink leftIcon={ArrowLeft}> — passing the lucide icon (a function) across the server->client boundary, which React rejects ("Functions cannot be passed directly to Client Components"). This surfaced as the integrations error boundary / "Failed to load integrations" on soft navigation to a detail page. Move the fallback into a client component so the icon never crosses the boundary.
|
||
|
|
bca7f2c9b3 |
feat(logs): add Troubleshoot in Chat button for errored runs (#5341)
* feat(logs): add Troubleshoot in Chat button for errored runs
Errored log runs now surface a "Troubleshoot in Chat" action in the log
details panel. It tags the failed run as a logs context (executionId) and
auto-sends a message to Chat asking Sim to investigate and fix the error,
porting the old copilot "Fix in Chat" behavior to mothership and adding
run-ID tagging.
Cross-route handoff rides a one-shot MothershipHandoffStorage consumed once
on the home surface mount, so the tagged run + prompt survive the navigation
from Logs to Chat and the agent receives the full run error via the resolved
logs context.
* fix(logs): deliver troubleshoot to a mounted chat + harden handoff
Review follow-ups:
- Same-route case (Cursor): LogDetailsContent is also embedded in the Chat
resource panel, where router.push('/home') doesn't remount Home, so the
mount-only handoff consume never fired. Generalize the existing
sendMothershipMessage event to carry contexts and be cancelable: deliver
straight to a mounted chat when one claims it, and only persist + navigate
when none is listening.
- Corrupted-entry tombstone (Greptile): consume now clears whenever any entry
exists, so a malformed/expired handoff can't linger across future mounts.
- Silent store failure (Greptile): only navigate when the handoff actually
stored, so a failed write never strands the user on an empty chat.
* docs(logs): convert inline comments to TSDoc on declarations
* style(logs): match Troubleshoot button icon gap to View Snapshot sibling
* improvement(logs): use Chip for log-detail action buttons
Aligns the log-details panel's labeled action buttons (View Snapshot,
Troubleshoot in Chat) with the settings design language by swapping the
emcn Button for the canonical Chip pill. variant='primary' preserves the
prior filled emphasis; leftIcon keeps the icons canonical.
* fix(chat): only consume troubleshoot handoff on the new-chat surface
Gate the mount-time handoff consume on `!chatId` so an existing
`/chat/[chatId]` mount can't claim a pending handoff if navigation races —
a handoff always targets a fresh chat.
* fix(logs): hover only the interactive Run ID row in log details
The detail-card rows all hovered to --surface-2, but the card itself is
--surface-2, so the hover was a no-op in light mode and only showed in dark.
It also implied clickability on static readout rows. Now only the clickable
Run ID row hovers, using the canonical --surface-active token; static rows
carry no hover.
* improvement(logs): use emcn Badge for the version pill
Replaces the hand-rolled version span with the canonical Badge
(variant='green' size='md', pixel-identical tokens), so all three detail
badges (Level, Trigger, Version) render through the same component.
|
||
|
|
507cee1187 |
fix(integrations): repair corrupt icons, backfill missing block metas, restore scroll on back-nav (#5342)
* fix(integrations): repair corrupt icons, backfill missing block metas, restore scroll on back-nav - Restore 7 brand icons (Google, Outlook, MongoDB, Postgres, OpenRouter, Groq, Cerebras) whose SVG path data was corrupted by a past bulk reformat, flooding the integrations page console with <path> parse errors; add a check:icon-paths CI gate that validates every icon d attribute (operand counts + arc flags). - Backfill BlockMeta (tags/url/templates/skills) for postgresql, mysql, ssh, sftp, smtp — previously catalog integrations with empty detail pages; add an integration meta-coverage CI check so every catalog block must have a meta. - Add scroll-position restoration for the integrations index/detail inner scroll containers so browser Back returns to where you were. - Remove the error digest pill from the shared workspace ErrorShell (kept in logs, dropped from UI). * fix(integrations): make scroll restoration robust — value-based echo detection + Back/Forward-only gate Addresses review: replace the racy programmatic-scroll flag with value comparison (a restore's echo equals lastApplied and is ignored, so a stuck flag can never drop the first user scroll or overwrite the saved target), and gate restoration on popstate history traversals so fresh push navigations open at the top instead of jumping mid-list. TSDoc-only comments. * fix(ci): attribute icon-path errors for export-const icons too Greptile review: iconNameAt only matched 'export function', so a malformed path inside an 'export const XxxIcon = (...)' arrow-function icon would be misattributed to the preceding function-declared icon. Match both forms (mirrors check-bare-icons indexIconBodies). |
||
|
|
4e8b88f0af |
fix(landing): avoid unpolyfilled ES2023 array methods in client code (#5340)
toSorted/toReversed require Safari 16+/iOS 16+ and Next.js/SWC does not polyfill prototype methods (vercel/next.js#58421 closed unmerged), so #5326 broke sorting on the models page and landing preview for Safari 15/iOS 15 with a runtime TypeError. Revert the 6 call sites to [...arr].sort()/[...arr].reverse() (immutable, universally supported, matches the existing codebase idiom) and drop the ES2023 tsconfig lib override that only existed to type-check them. |
||
|
|
62acc9c53f |
fix(interfaces): always-light public surfaces (chat, resume, file shares, unsubscribe, invite) with emcn components (#5336)
* fix(interfaces): pin deployed chat + resume to light mode, emcn-only components * fix(interfaces): review feedback — formErrors dep in field renderer, keep overlay tint on attachment remove * improvement(interfaces): chat header uses the platform SimWordmark instead of the svg asset * fix(interfaces): light mode for file-share gates, unsubscribe, and invite surfaces |
||
|
|
44215126f4 | improvement(tables): make max row size env-configurable and raise default to 400KB (#5338) | ||
|
|
eb367def31 |
fix(demo): unblock Cal.com booking embed and align work-email validation (#5335)
* fix(demo): unblock Cal.com booking embed and align work-email validation
- Exclude /demo from cross-origin isolation headers (COEP credentialless /
COOP same-origin) that degraded the third-party Cal.com booking iframe,
mirroring the existing Google Drive Picker exclusion; the booker no longer
loads under a Storage-Access handshake that often never finished
- Pin the Cal embed theme/layout in the inline config to fix a dark-on-light
theme race; keep cal('ui') to UI-only settings
- Gate the demo form's Continue on the same work-email rule the server
enforces via a shared isFreeEmailDomain helper, bundle-isolated in
lib/messaging/email/free-email.ts so it doesn't bloat other email bundles
- Trim redundant comments in the demo components
* fix(demo): match /demo subroutes in permissive COEP rule
Align the permissive-headers positive match with the strict-COEP negative
lookahead so any future /demo subroute still receives the permissive
COEP/COOP policy instead of falling through to no headers.
* fix(demo): use demo.* in permissive COEP rule (valid route source)
The demo(/.*)? form introduced a nested capturing group, which Next's
path-to-regexp route-source parser rejects ('Capturing groups are not
allowed'), failing the build. demo.* mirrors the strict-rule lookahead's
demo prefix without a nested group, matching the existing w/.* style.
|
||
|
|
2c5ee4a8db |
chore(rules): canonical useState prev-tracker for render-phase adjust + no-render-in-render caveat (#5333)
Two recurring pitfalls surfaced by the /w react-doctor pass, verified against react.dev: - sim-hooks.md: adjusting state on a prop transition uses the React-canonical useState prev-value tracker (NOT a useRef — React forbids reading/writing ref.current during render; the react-hooks 'refs' lint flags it, and useState is concurrent-safe). The tracker's initial value decides mount behavior (sentinel vs current value) — a mis-seed silently drops the mount action. The existing useRef variant is noted as discouraged for new code. - sim-components.md: no-render-in-render is a false positive for a helper called inline (reconciled by position, no remount); extract only when mechanical. Refs: react.dev useState 'Storing information from previous renders'; useRef 'Do not write or read ref.current during rendering'; react-hooks 'refs' lint. |
||
|
|
c923de6a19 |
feat(providers): add Claude Fable 5 model (#5334)
Re-add claude-fable-5 (Anthropic's most capable widely released model), not marked recommended. Verified against live Anthropic API + docs: - Pricing $10/$50 per MTok, $1 cached input (cache-read); 1M context; 128k max output; GA 2026-06-09 - Adaptive thinking only (always on, cannot be disabled) — routed via supportsAdaptiveThinking; manual budget_tokens/temperature are rejected with 400 - effort levels low/medium/high/xhigh/max (default high) - nativeStructuredOutputs confirmed supported (live output_format json_schema call returned 200), matching same-generation siblings (Sonnet 5, Opus 4.8) |
||
|
|
9204b4a248 |
improvement(knowledge): react-doctor perf pass across the knowledge base module (#5332)
* improvement(knowledge): react-doctor perf pass across the knowledge base module * improvement(knowledge): drop stable mutate fn from useCallback deps * docs(rules): tighten sim-react-performance mutation + toSorted wording |
||
|
|
76537c890c |
improvement(files): react-doctor performance pass on the files module (#5330)
* improvement(files): react-doctor performance pass on the files module * fix(files): use spread-sort not toSorted in client (Safari<16/iOS15 crash) SWC does not polyfill Array.prototype.toSorted and the repo sets no core-js/browserslist target, so it throws on Safari <16 / iOS 15. Revert the two client-side toSorted calls to [...arr].sort() and correct the harness guidance in sim-components.md accordingly. |
||
|
|
671535469d |
improvement(tables): react-doctor safe performance pass (#5329)
* improvement(tables): react-doctor safe performance pass Apply high-confidence, behavior-preserving perf fixes surfaced by react-doctor on the tables module: - Lazy-init the import-status ref so it stops allocating and discarding a fresh Map on every render (rerender-lazy-ref-init). - expandToDisplayColumns: build an outputs-by-column-name Map once per workflow group instead of Array.find() per column (js-index-maps). - Sort the tables list with toSorted() instead of [...list].sort() (js-tosorted-immutable; ES2023 lib is enabled for apps/sim). - Hoist the static TITLE_BY_MODE map and the pure editor wheel handler to module scope so they are not rebuilt each render. Left the effect/selection refactors (state-synced-to-prop, effect chains) untouched: those effects react to async-loaded rows and are not the copy-a-prop-into-state anti-pattern; refactoring them needs live grid verification. Barrel-import findings are false positives against the repo's mandated barrel-import convention. * improvement(tables): preserve find() first-match semantics + document perf idioms - expandToDisplayColumns: build the outputs-by-column-name index with an explicit first-write-wins loop so it is provably identical to the prior Array.find() on the (schema-precluded) duplicate-columnName case, not last-wins as new Map(entries) would be. - Add .claude/rules/sim-react-performance.md capturing the behavior- preserving render-perf idioms applied here (lazy object refs, module- scope hoisting, Map/Set pre-indexing, immutable array methods with the ES2022/ES2023 lib caveat, local-barrel false-positive note), and point to it from CLAUDE.md. * fix(tables): revert toSorted to spread-sort for universal browser support Array.prototype.toSorted is ES2023 runtime; SWC does not polyfill it and the default browserslist still includes browsers without it (iOS 15 Safari), so the tables page would crash there. [...result].sort() is non-mutating (sorts a copy, never touches the React Query cache array) and works everywhere; the perf delta is negligible. Correct the sim-react-performance rule doc to reflect that tsconfig lib only affects type-checking, not runtime availability. * refactor(tables): tidy lazy ref init and align perf-rule cross-reference - use-workspace-imports: lazy-init the status Map at its point of use in the effect ((ref.current ??= new Map())) instead of mutating the ref during render with a separate in-effect fallback. The ref is only read in the effect, so this removes the render-phase write and the dead '?? new Map()' branch while keeping the identical persistent Map. - CLAUDE.md: fix the render-performance pointer so it matches the rule doc — toSorted/toReversed are unsafe on client render paths (SWC does not polyfill prototype methods), not merely an ES2022/ES2023 lib note. |
||
|
|
8cebeb6774 |
improvement(chat): code-split resource preview panel out of initial /chat bundle (#5331)
* improvement(chat): code-split resource preview panel out of initial /chat bundle Lazy-load the MothershipView resource-preview panel (file-viewer, rich-markdown, CSV/PDF stack) via React.lazy + local Suspense so it is not in the initial /chat bundle; it only renders once a chat has messages. Remove its now-dead barrel re-export so the split takes effect (this app has no sideEffects:false, so a leftover barrel edge drags the heavy module back into the initial chunk). Also a small behavior-preserving perf pass on the input surface: - toSorted (non-mutating) instead of spread+sort in use-skill-auto-mention - Map first-match lookup instead of .find()-in-loop in prompt-editor Document the code-split/barrel gotcha in .claude/rules/sim-imports.md. * fix(chat): drop unsafe toSorted, keep code-split + Map lookup toSorted (ES2023) is not polyfilled by SWC and crashes iOS15/Safari<16 in client bundles, so revert use-skill-auto-mention to the non-mutating [...arr].sort() it had. The code-split of MothershipView and the first-match Map lookup in prompt-editor are unaffected. Tighten the sim-imports code-split note to state webpack *can* retain the barrel edge (removing the dead re-export is the guaranteed fix). |
||
|
|
42e3a038a0 |
improvement(landing): react-doctor health pass across the landing surface (#5326)
* improvement(landing): react-doctor health pass across the landing surface - shared JsonLd server component with HTML-safe serialization (replaces 32 inline dangerouslySetInnerHTML JSON-LD sites; structured-data output semantically identical, XSS hardened) - state/effect fixes: derive-instead-of-sync, phase state machines, useSyncExternalStore for media query, handler-only state to refs - structural splits for one-component-per-file and non-component export isolation - mechanical: combined iterations, hoisted Intl formatters/static values, immutable sorts, stable keys, a11y labels, focus rings, SVG precision - ES2023 lib for apps/sim to allow toSorted/toReversed * fix(landing): harden auth-modal async open (dismiss race + disabled-signup redirect) - guard the pending provider-status fetch with openRequestedRef so a late resolve can't reopen the modal or re-fire the opened event after dismiss - open synchronously (loader) when status is still loading so the click stays responsive - route to /login instead of /signup when registration is disabled and no modal providers are available * fix(landing): reset demo step index when the preview auto-cycle restarts - reactive isDesktop can re-run the demo effect on a 1024px resize; reset demoIndexRef to 0 so applyDemoStep(step 0) and scheduleNextStep read the same step, instead of replaying from a stale index and skipping beats - clarify why the chat reveal's previous-value ref is safe here (timer-driven, no concurrent-interruption boundary) * fix(landing): single-shot auth open, stable connector keys, exact prompt-row lookup - auth-modal: consume openRequestedRef on resolve so a queued double-click (or the shared mount prefetch) can't run openWithStatus twice (no duplicate auth_modal_opened / redundant setView) - landing-preview-knowledge: key connector icons by a stable slug instead of a component name that can be mangled/emptied under minification - workflow-data getEditorPrompt: single ordered pass preserves the original find() first-match-in-order semantics (Map lookup had preferred 'Prompt' over an earlier 'System Prompt') * style(landing): convert added inline comments to TSDoc-style |
||
|
|
c957aa2b94 |
improvement(settings): react-doctor perf & correctness pass (#5327)
* improvement(settings): react-doctor perf & correctness pass - combine multi-pass array iterations into single passes (api-keys, credential-sets, secrets-manager, team-management) - cache/hoist Intl formatters to module scope (billing); hoist pure functions and inline-default constants - stabilize react-query array fallbacks so memos stop recomputing while loading (api-keys, byok, workflow-mcp) - fix create-workflow-mcp modal reset via render-phase prevOpen compare instead of a state-adjusting effect - accessibility: aria-labels on real inputs, aria-hidden on autofill decoys, native <button> for clickable rows - immutable in-place sort where the array is already a fresh copy * fix(settings): render non-clickable inbox rows as div, not disabled button Addresses review: a native disabled <button> can inherit browser disabled styling (dimmed text / lower contrast) on non-navigable task rows. Render an interactive <button> only when the row is clickable; otherwise a plain <div> with identical layout — preserving the semantic-button a11y win without the disabled-state visual regression. |
||
|
|
78661d25ff |
fix(providers): drop deprecated temperature capability from claude-sonnet-5 (#5328)
Claude Sonnet 5 rejects the temperature parameter with a 400 ("`temperature` is deprecated for this model"), verified against the live Anthropic API. The model entry exposed temperature: { min: 0, max: 1 }, so supportsTemperature() returned true and the Anthropic request builder sent temperature whenever thinking was disabled, breaking those runs. Remove the capability (matching Opus 4.7/4.8, which omit it for the same reason) so temperature is never sent for Sonnet 5. Add a supportsTemperature regression assertion.
|
||
|
|
af87de09a7 |
fix(connectors): allow self-hosted private DB hosts via opt-in flag (#5322)
* fix(connectors): allow self-hosted private DB hosts via opt-in flag Database/connector tools rejected any host resolving to a private/reserved/ loopback IP, blocking the common self-hosted topology where the DB is reached by a Docker/K8s/Swarm service name. Add an opt-in ALLOW_PRIVATE_DATABASE_HOSTS flag that bypasses the private-host block in validateDatabaseHost while still resolving and pinning DNS. Blocked on the hosted platform regardless of the env var, mirroring DISABLE_AUTH. Fixes #4319 * fix(connectors): pin postgres IP in all ssl modes; strip IPv6 brackets Address review on #5322: - validateDatabaseHost now strips surrounding IPv6 brackets before the localhost/private-IP checks and DNS lookup, so a bracketed loopback like [::1] is classified correctly instead of failing as unresolvable. - PostgreSQL connector always connects to the validated, pinned IP (removed the ssl='preferred' carve-out that passed the original hostname and let the driver re-resolve during connection). Matches the MySQL/MongoDB pin pattern. - Add postgres connector pinning tests and bracketed-IPv6 host tests. * fix(connectors): rename flag to isPrivateDatabaseHostsAllowed; trim comment - Rename env-flag const to satisfy the env-flags 'is' prefix CI check (env var ALLOW_PRIVATE_DATABASE_HOSTS is unchanged). - Tighten the postgres pinning comment to a single line. |
||
|
|
b8e88b14b7 |
improvement(settings): react health pass across settings surface (#5324)
- workflow-mcp: move tool-edit state seeding from a derive effect into the Edit event handler - admin: drop 2 inert useMemo (page math) and 1 unused useCallback - inbox + teammates: migrate filter/search view-state from useState to nuqs URL params (shareable, debounced writes) - team roster: memoize O(workspaces x members) grouping so keystroke search stays cheap at scale - remove dead code (unused props/locals: currentUserEmail, setOrgName, isLoadingWorkflows, isTeam) |
||
|
|
0575875be1 |
fix(custom-tool): restore modal body scroll so Save stays reachable (#5321)
* fix(custom-tool): restore modal body scroll so Save stays reachable The Edit/Create Agent Tool modal clipped its footer (Save/Update) and could not scroll with long code or schema content. Root cause: #4354 migrated the modal to ChipModal and changed the body from a scroll region (flex-1 overflow-y-auto) to flex-none overflow-visible so the hand-positioned EnvVar/Tag autocompletes could spill past it. That removed the scroll region, so tall content grew the body past the modal's max-h-[84vh] cap and the overflow-hidden surface clipped the footer. Restore ChipModalBody as the scroll region (its documented behavior) and switch the EnvVar/Tag dropdowns to portaled inputRef caret-anchoring, matching the canonical Function-block editor, so they anchor to the caret in a portal and are never clipped by the scroll boundary. * fix(custom-tool): keep dropdown anchors content-relative on body scroll Review follow-up. The autocomplete popovers already portal their menus (never clipped by the body's scroll boundary), so the fix is only to restore the body as the scroll region. Reverting the dropdowns to their content-relative absolute anchors keeps them glued to the caret while the body scrolls; the caret-viewport inputRef anchoring used fixed viewport coordinates that only refreshed on edits, detaching the menu on scroll. |
||
|
|
33f9d645ba |
fix(careers): remove /careers redirect so the in-app page is reachable (#5320)
A pre-existing permanent redirect /careers -> jobs.ashbyhq.com/sim shadowed the new first-party careers page (#5316), sending visitors straight to the Ashby board. Drop it so /careers serves the in-app page (which itself pulls the Ashby roles). |
||
|
|
2393b72ee6 |
feat(careers): careers page backed by the Ashby job board (#5316)
* feat(careers): careers page backed by the Ashby job board * fix(careers): harden Ashby parsing and filter edge cases from review - validate jobUrl as http(s) only; drop postings with unsafe URLs - validate postings individually so one bad row can't empty the board - namespace the all-filter sentinel to avoid colliding with real values - dedupe the job metadata line (fixes duplicate React keys / Remote·Remote) - parse filters server-side so deep-linked views don't flash unfiltered * fix(careers): filter-aware empty state; drop inline comments - JobGroups owns its empty copy via a filtersActive flag, so the server fallback and client board render identical, correct empty messaging (no-open-roles vs no-matching-filters) - convert remaining inline comments to TSDoc |
||
|
|
af53eda5ac |
feat(landing): reintroduce /contact page styled like /demo (#5315)
* feat(landing): reintroduce /contact page styled like /demo - Restore the /contact page (removed in #5181) with a two-column layout mirroring /demo: value prop + trusted-by logos on the left, a message form card on the right, on the platform light tokens and chip components - Restore the contact contract, /api/contact route (rate-limit, honeypot, Turnstile, help-inbox notification + visitor confirmation), now fully contract-bound via parseRequest - Add a useSubmitContact React Query mutation hook - Link Contact from the footer Resources column and add it to the sitemap * fix(contact): server-authoritative captcha + review fixes - Make captcha server-authoritative: drop the client-trusted captchaUnavailable flag; a valid Turnstile token is the only way past the stricter fallback bucket, so callers can't opt out of the challenge - Re-execute the Turnstile widget on every submit (incl. after expiry) instead of falling into the no-captcha path once the token expires - Reset the pre-submit gate on mutation settle so rapid double-clicks can't fire a duplicate /api/contact request - Map only feature_request to its email type; every other topic resolves to a General Inquiry confirmation so support requests aren't labeled bug reports - Drop the confirmation-email promise from the success copy (it's best-effort) - Collapse the duplicated no-captcha rate-limit branch; hoist shared response constants; read the Turnstile site key as a module constant * fix(contact): drop redundant Turnstile hostname pin The Turnstile site key is already domain-bound in Cloudflare, so pinning expectedHostname to the marketing SITE_URL (www.sim.ai) only rejected valid tokens issued on self-hosted, preview, and apex-vs-www hosts. Remove the pin and rely on Cloudflare's own domain binding. * fix(contact): fail closed on the no-captcha rate-limit backstop checkRateLimitDirect fails open on limiter-storage errors so a limiter outage never takes down normal traffic. But the contact route's no-captcha bucket is the only throttle on token-less submits, so a fail-open there let uncaptcha'd requests reach the email path unthrottled during an outage. - Add an opt-in { failClosed } option to checkRateLimitDirect; default behavior (fail open) is unchanged - Use failClosed on the contact no-captcha backstop so an unenforceable limit rejects instead of admitting - Cover both fail-open and fail-closed paths with tests * refactor(contact): TSDoc over inline comments Move the captcha-design rationale into the route handler's TSDoc and drop the inline body/JSX comments, per the project's TSDoc-only comment convention. |
||
|
|
43ed80c7e3 |
improvement(broadcast): white canvas, LinkedIn footer, hi-res logo (#5317)
- Drop the #F8F8F8 canvas to a clean white background (body + outer wrapper). - Replace Discord with LinkedIn in the footer social row. - Swap the low-res header logo for the full-res sim logotype. |
||
|
|
ca34301d7f |
fix(mailer): permissions entitlements for enabling/disabling (#5312)
* v0.6.29: login improvements, posthog telemetry (#4026) * feat(posthog): Add tracking on mothership abort (#4023) Co-authored-by: Theodore Li <theo@sim.ai> * fix(login): fix captcha headers for manual login (#4025) * fix(signup): fix turnstile key loading * fix(login): fix captcha header passing * Catch user already exists, remove login form captcha * fix(mailer): permissions entitlements for enabling/disabling * fix lifecycle for agentmail infra --------- Co-authored-by: Waleed <walif6@gmail.com> Co-authored-by: Theodore Li <theodoreqili@gmail.com> Co-authored-by: Siddharth Ganesan <33737564+Sg312@users.noreply.github.com> Co-authored-by: Theodore Li <theo@sim.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
ff16b1b886 | fix(hitl): build the full enabled-block DAG so any persisted resume target exists (#5313) |