Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: simstudioai/sim
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.6.87
Choose a base ref
...
head repository: simstudioai/sim
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.6.88
Choose a head ref
  • 9 commits
  • 159 files changed
  • 3 contributors

Commits on May 22, 2026

  1. Configuration menu
    Copy the full SHA
    9276463 View commit details
    Browse the repository at this point in the history
  2. improvement(hubspot): OAuth-native polling trigger replacing webhook …

    …flow (#4705)
    
    * improvement(hubspot): OAuth-native polling trigger replacing webhook flow
    
    * feat(hubspot): property autocomplete, multi-filter, property-changed, list-membership, pipeline/owner dropdowns
    
    * fix(hubspot): freeze cursor on failure + request full OAuth scopes
    
    * chore(api): bump API route baseline from 749 to 753 for HubSpot selector routes
    
    * fix(hubspot): make eventType required conditional on visibility
    
    * improvement(hubspot): align trigger name and longDescription with poll-trigger conventions
    
    * fix(hubspot): encodeURIComponent on search path segment for defense-in-depth
    
    * fix(hubspot): cursor-based seed for list_membership polling
    
    * fix(hubspot): Map-backed property snapshot + drop redundant filter parse
    waleedlatif1 authored May 22, 2026
    Configuration menu
    Copy the full SHA
    21c956c View commit details
    Browse the repository at this point in the history
  3. Configuration menu
    Copy the full SHA
    543d2fa View commit details
    Browse the repository at this point in the history
  4. improvement(search-replace): pass down to subblocks (#4712)

    * improvement(search-replace): pass down to subblocks:
    
    * fix local lowercasing bug
    icecrasher321 authored May 22, 2026
    Configuration menu
    Copy the full SHA
    1af6538 View commit details
    Browse the repository at this point in the history
  5. feat(mailer): add AWS SES and SMTP providers with auto-detect fallback (

    #4710)
    
    * feat(mailer): add AWS SES and SMTP providers with auto-detect fallback
    
    * fix(mailer): cast SES options to bridge duplicate @aws-sdk type identities
    
    * fix(mailer): dedupe aws-sdk-sesv2, address review feedback
    
    - Force a single @aws-sdk/client-sesv2 install via root package.json overrides; @types/nodemailer pulled in a nested copy whose nominal class brand made the two SDK type identities incompatible, breaking the CI build. With one install the cast disappears.
    - Batch result message now reports successCount instead of sendable.length when entries are skipped, so "5 emails sent" no longer overstates delivery on partial failures.
    - SMTP provider now warns when SMTP_HOST is set without SMTP_PORT, and when only one of SMTP_USER/SMTP_PASS is set — both previously silent misconfigurations.
    - SMTP_SECURE schema is z.boolean() to match every other boolean in env.ts; runtime parsing is still handled by envBoolean.
    - Strip the verbose TSDoc comments I had added.
    
    * fix(mailer): exact sent counts in batch results, restore SES type cast
    
    - mergeBatchResults: data.count and the message now report only emails that were actually delivered, not skipped-unsubscribed ones (they returned success: true and inflated the count). Empty-sendable branch distinguishes "all unsubscribed" from "mixed skip/failure" so the message stops lying when some entries fail validation.
    - ses.ts: revert the package.json override approach (bun honors it locally but CI still installs a nested @types/nodemailer copy). Reinstate the `as unknown as` cast with a single-line WHY comment.
    
    * fix(mailer): annotate double-cast in ses provider for strict api-validation
    
    * fix(mailer): batch degrades isUnsubscribed errors to per-entry failures
    
    A transient DB error in isUnsubscribed used to abort the whole batch
    because the call sat outside the per-email try/catch in prepareBatch.
    Wrap the unsubscribe check inside the same catch so a rejection becomes
    a per-recipient failure, matching sendEmail's behavior. Lock it in
    with a regression test.
    waleedlatif1 authored May 22, 2026
    Configuration menu
    Copy the full SHA
    952eb12 View commit details
    Browse the repository at this point in the history
  6. improvement(kb-connectors): multi-select fields + Slack bot/app messa…

    …ge extraction (#4711)
    
    * improvement(kb-connectors): multi-select fields + Slack bot/app message extraction
    
    Adds multi-value support to KB connector configuration fields and applies it
    across 8 connectors: Jira (projects), Confluence (spaces), Slack (channels),
    Microsoft Teams (channels), Google Calendar (calendars), Gmail (labels),
    Notion (databases), and Linear (teams + projects). Each connector emits
    byte-identical externalId for legacy single-value configs so existing rows
    reconcile in place via the sync engine's externalId-keyed matching.
    
    Framework changes:
    - ConnectorConfigField gains `multi?: boolean`
    - New `parseMultiValue` helper in @/connectors/utils
    - useConnectorConfigFields state model upgraded to string|string[]
    - ConnectorSelectorField renders Combobox in multi-select mode when `field.multi`
    - Add/edit connector modals handle array values end-to-end
    
    Per-connector specifics:
    - Jira: JQL `project in (...)` for 2+ keys, `project = X` for one
    - Confluence: routes through CQL `space in (...)` when multi; v2 fast path stays
      for single+no-label; also fixes selector returning space.id instead of space.key
    - Slack: loops per channel emitting one document each; extracts text from
      attachments and Block Kit blocks (incl. nested attachment.blocks where GitHub
      embeds PR bodies); contentHash bumped to slack-v2: to force one-time re-embed
    - Microsoft Teams: loops per channel within a single team
    - Google Calendar: compound cursor across calendars; single-calendar keeps
      legacy externalId/contentHash for zero-churn
    - Gmail: (label:A OR label:B) with quoted-form for labels with spaces
    - Notion: sequential walk via JSON compound cursor; single-DB keeps bare cursor
    - Linear: GraphQL IdComparator.in for multi, eq for single
    
    * fix(kb-connectors): valuesEqual treats legacy scalar as equal to multi-array
    
    Existing connectors created before multi-select store sourceConfig values as
    scalars (e.g. projectKey: "ENG"). With the field now declared multi: true,
    resolveSourceConfig returns an array (["ENG"]), and the original valuesEqual
    fell through to a strict reference comparison — falsely flagging unsaved
    changes on open and triggering an unnecessary string→array shape rewrite on
    save.
    
    valuesEqual now normalizes both sides to string[] via CSV-split when either
    is an array, so persisted scalar and in-memory array of the same content
    compare equal. Single-value (non-multi) fields keep strict string equality.
    
    * fix(kb-connectors): GCal externalId on config downgrade, Slack silent skip, valuesEqual order
    
    - google-calendar getDocument: derive isMultiCalendar from the externalId's
      `:` separator instead of the current config count. Prevents duplicates when
      a user downgrades from multi to single calendar — previously the returned
      doc lost its `calendarId:` prefix and was treated as a new row by the sync
      engine, orphaning the original.
    - slack listDocuments: throw on unresolvable channel instead of silently
      skipping. Matches MS Teams behaviour. Silent skip would let the sync
      engine orphan-delete the previously indexed channel content if a bot was
      removed or a channel was archived/renamed mid-life.
    - edit-connector-modal valuesEqual: order-insensitive comparison for multi-
      select arrays via Set membership. Multi-select UI doesn't guarantee
      insertion order matches the server-returned order, so `["A","B"]` vs
      `["B","A"]` would otherwise flag false unsaved changes.
    
    * chore(kb-connectors): use emptyValue() fallback in isFieldPopulated for consistency
    
    Behavior unchanged — isValuePopulated('') and isValuePopulated([]) both return
    false — but reading the field-typed fallback inline matches the convention
    used elsewhere in the hook (coerceForField, handleFieldChange, resolveSourceConfig).
    
    * fix(kb-connectors): Linear projects selector loads across all selected teams
    
    When the team selector is in multi-select mode, the basic-mode projects
    dropdown was passing only the first team ID into the linear.projects
    selector context (via readFirst in resolveDepValue), so projects from other
    selected teams were invisible.
    
    resolveDepValue now joins multi-value parents into a CSV string so dependent
    selectors receive every selected parent ID. The /api/tools/linear/projects
    route splits the CSV teamId, fetches projects from each team in parallel,
    and dedupes by project ID. Single-team configs pass through unchanged
    (`split(",")` on a bare ID yields a one-element array).
    
    The AND-of-filters semantics in buildIssuesQuery is intentional and matches
    standard GraphQL filter behavior — a user filtering on teams [A,B] and
    projects [X,Y] gets issues in (A or B) AND (X or Y). With this fix the
    project dropdown now shows every project under any selected team so the
    user can compose the right project set.
    
    * fix(gmail-connector): always wrap OR-containing custom query, not just unwrapped ones
    
    The previous check `!/^\(.*\)$/.test(trimmedCustom)` was supposed to avoid
    double-wrapping an already-parenthesized expression, but it false-positives
    on inputs like `(from:alice) OR (from:bob)` where the parens don't bracket
    the whole string. Those would skip wrapping and the top-level OR would bind
    across the preceding label / category / date filters instead of the custom
    clause.
    
    Always wrap when an OR is present — double-parens are a no-op in Gmail
    search syntax, so `((from:a OR from:b))` parses the same as `(from:a OR
    from:b)`. Simpler than walking parens depth and provably safe.
    waleedlatif1 authored May 22, 2026
    Configuration menu
    Copy the full SHA
    e0551b3 View commit details
    Browse the repository at this point in the history
  7. improvement(mcp): per-server tool queries + negative cache (#4715)

    * improvement(mcp): per-server tool queries + negative cache so one slow server can't block the workspace
    
    Move MCP tool discovery off the workspace-aggregated `Promise.all` fan-out and
    onto per-server React Query keys, matching how Cursor and Claude Code render
    remote MCP. `useMcpToolsQuery` is now a `useQueries` combiner: each server has
    its own cache entry, its own loading state, and a slow neighbor never gates the
    others. Public shape stays compatible with existing consumers.
    
    Add a short-TTL negative cache: when `listTools` fails (timeout, connection
    error, etc.) we mark the server unhealthy for 30s so subsequent discovery calls
    short-circuit instead of re-paying the timeout. OAuth-required errors are
    exempt so re-auth retries immediately. Drop `LIST_TOOLS_TIMEOUT_MS` from 30s
    to 10s to bound the worst-case first failure.
    
    Invalidations are per-server where the action is per-server (OAuth popup,
    per-server SSE event, refresh, update, delete). Bulk operations stay
    workspace-broad. Adds tests for the negative-cache behavior and the OAuth
    exemption.
    
    Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
    
    * improvement(mcp): in-flight dedup + 2min negative TTL + no refetch on window focus
    
    Three small follow-ups on top of per-server tool queries:
    
    - Coalesce concurrent `discoverServerTools(userId, serverId, workspaceId)`
      calls into a single upstream `tools/list`. Races between OAuth-callback
      cache priming, post-OAuth UI refetch, and multi-tab loads no longer
      double-fetch the same server.
    - Bump negative-cache TTL from 30s to 2 minutes. Cleared on listChanged,
      OAuth completion, manual refresh, and the next successful discovery, so
      this floor only matters for genuinely dead servers — drops their floor
      traffic by 4x.
    - Disable `refetchOnWindowFocus` on per-server tool queries. listChanged
      SSE + mutation invalidations already cover real schema changes; alt-tab
      no longer triggers N parallel `tools/list` calls.
    
    * fix(mcp): address bugbot/greptile review on per-server tool discovery
    
    - Workspace-scoped `mcpKeys.serverToolsWorkspace(workspaceId)` prefix for bulk
      invalidations (create-server, refresh-all, SSE workspace fallback, OAuth
      fallback). The previous `mcpKeys.serverTools()` prefix was global and
      invalidated every workspace's tools cache.
    - `useMcpToolsQuery` folds `useMcpServers().isLoading` into the aggregate
      `isLoading` so mounting no longer flashes an "empty tools" state during the
      servers-list fetch. Aggregate `error` is suppressed when any per-server
      query already returned data so one slow server can't blank out the others.
    - `useForceRefreshMcpTools` invalidates the per-server query keys of servers
      whose force refresh failed, so stale tools don't linger.
    - `DiscoveryOutcome` error variant carries the original error, restoring the
      OAuth-exemption check that `getErrorMessage(...)` previously erased.
    - `discoverServerTools(userId, serverId, workspaceId, forceRefresh = false)`
      now consults the positive + negative cache by default. Per-server React
      Query refetches hit the cache instead of re-paying the listTools timeout;
      callers that explicitly bypass cache (refresh route, OAuth callback, bulk
      POST refresh) pass `forceRefresh: true`. Negative-cache hits throw a typed
      `McpConnectionError` so the route layer can surface a fast 503.
    
    * update icons
    
    * chore(mcp): remove dead query keys and trim verbose comments
    
    - Drop unused `mcpKeys.tools()` / `mcpKeys.toolsList()` — replaced by
      per-server keys, no remaining callers.
    - Trim narrative comments to keep only the non-obvious "why" notes.
    
    * fix(mcp): map negative-cache cooldown error to HTTP 503
    
    `McpConnectionError` thrown when a server is in cooldown previously
    fell through `categorizeError` to a generic 500. Cooldown is a
    transient-unavailability condition, so route it to 503.
    
    * test(mcp): cover cooldown error → 503 categorization
    
    * fix(mcp): address second-round bugbot review
    
    - useMcpToolsQuery serverIds: filter on enabled + workspaceId match.
      Disabled rows no longer trigger discover calls that get negative-cached,
      and keepPreviousData on useMcpServers no longer races a workspace switch
      into cross-workspace discover requests.
    - Aggregate skips per-server data when that server's latest refetch errored,
      so a broken server's last-known tools no longer linger in the workspace
      view while its card shows an error.
    - discoverServerTools failure path drops the positive cache alongside writing
      the negative-cache marker. A cache-respecting follow-up now fails fast via
      cooldown instead of returning stale tools from a now-broken server.
    - useMcpTools.refreshTools drops the dead forceRefresh param — the per-server
      queryFn always sends refresh=false, so the flag was never effective. Callers
      wanting cache-bypass should use useForceRefreshMcpTools.
    
    * chore(mcp): trim verbose comments
    
    * fix(mcp): third-round bugbot review
    
    - discoverTools failure path now drops the per-server positive cache alongside
      writing the negative-cache marker, matching discoverServerTools' behavior so
      a workspace-aggregate failure doesn't leave stale tools cached.
    - useForceRefreshMcpTools filters disabled and out-of-workspace rows before
      fan-out so disabled servers don't 404 → negative-cache themselves.
    - Remove unused useMcpServerTools export — the aggregate goes through
      useQueries directly, no external consumer exists.
    
    ---------
    
    Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
    waleedlatif1 and claude authored May 22, 2026
    Configuration menu
    Copy the full SHA
    0c96964 View commit details
    Browse the repository at this point in the history
  8. fix(oauth): follower last-chance read after poll deadline (#4718)

    * fix(oauth): follower last-chance read after poll deadline
    
    * test(oauth): exercise last-chance read in follower timeout test
    waleedlatif1 authored May 22, 2026
    Configuration menu
    Copy the full SHA
    3d9a1c4 View commit details
    Browse the repository at this point in the history
  9. v0.6.88: mutex lock on oauth refresh, files export fix, hubspot trigg…

    …er, search & replace UX, kb connectors multi-select, mcp negative cache
    waleedlatif1 authored May 22, 2026
    Configuration menu
    Copy the full SHA
    e9ee351 View commit details
    Browse the repository at this point in the history
Loading