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: main
Choose a base ref
...
head repository: simstudioai/sim
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: improvement/forking-settings-refresh
Choose a head ref
Checking mergeability… Don’t worry, you can still create the pull request.
  • 20 commits
  • 447 files changed
  • 7 contributors

Commits on Jul 8, 2026

  1. feat(pii): add opt-in GLiNER NER engine (PII_ENGINE), device-agnostic (

    …#5495)
    
    * feat(pii): add opt-in GLiNER NER engine (PII_ENGINE), device-agnostic
    
    Swap the 4 NER entity types (PERSON/LOCATION/NRP/DATE_TIME) to a single
    multilingual GLiNER zero-shot model when PII_ENGINE=gliner; spaCy stays the
    default and all ~36 regex/checksum recognizers are identical on both engines.
    Device-agnostic via PII_DEVICE / cuda auto-detect — same code on Fargate CPU
    now and EC2-GPU later.
    
    - engines.py: side-effect-free builders; SharedModelGLiNERRecognizer loads
      ONE model shared across the 5 per-language instances and restricts labels
      to the entities it owns; small spaCy models keep tokenization/lemmas for
      the regex recognizers; fail-fast on the lean image
    - pii.Dockerfile: multi-stage — default target unchanged (lean spaCy);
      --target gliner is a superset (torch CPU + gliner + baked model) where
      both engines work; gliner-gpu scaffold for the GPU fleet
    - CI publishes the gliner variant (:staging-gliner/:latest-gliner, amd64)
    - Helm: pii.engine / pii.device values wired to PII_ENGINE/PII_DEVICE
    - scripts/bench_engines.py: throughput + NER-parity diff harness
    - tests: unit (mocked GLiNER) + in-image integration for both engines
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Up3F97mjCH9HCj1pX4J8VJ
    
    * refactor(pii): ship both engines in one image — engine is a pure env flip
    
    Collapse the gliner build target into the single pii image: spaCy lg models,
    torch (CPU), gliner, and the baked GLiNER weights all ship in it, so
    PII_ENGINE switches engines with no image swap and no tag matrix. CI reverts
    to the single pii build (no -gliner tags). The GPU variant becomes the same
    Dockerfile built with --build-arg TORCH_INDEX_URL=.../cu128. Image grows
    ~6.1GB -> ~9.6GB.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01Up3F97mjCH9HCj1pX4J8VJ
    
    ---------
    
    Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
    TheodoreSpeaks and claude authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    4e6594d View commit details
    Browse the repository at this point in the history
  2. chore(tables): remove tables-fractional-ordering feature flag (#5503)

    * chore(tables): remove tables-fractional-ordering feature flag
    
    * improvement(tables): drop dead position tracking from paste undo path
    
    * improvement(tables): drop dead position from create-row undo records
    TheodoreSpeaks authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    8c61720 View commit details
    Browse the repository at this point in the history
  3. fix(deps): upgrade better-auth 1.6.11 -> 1.6.13 (GHSA fix, Dependabot #…

    …166/#167) (#5508)
    
    Patches a high-severity stored XSS in the oidc-provider and mcp plugins
    via javascript:/data: redirect_uri schemes. Also bumps @better-auth/sso
    and @better-auth/stripe to matching 1.6.13 peers. Patch-only release
    (1.6.11 -> 1.6.12 -> 1.6.13), no breaking changes in either changelog.
    waleedlatif1 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    cb6f99d View commit details
    Browse the repository at this point in the history
  4. improvement(knowledge): open document tags from row context menu (#5510)

    * improvement(knowledge): open document tags from row context menu
    
    The document row context menu had a Tags entry that only navigated to the document detail page, requiring another click through the breadcrumb dropdown to actually edit tags. It now opens the tag editor directly, and shows even when the document has no tags yet so a first tag can be added.
    
    * fix(knowledge): gate document tags menu item on edit permission
    
    Matches the existing disableRename/disableDelete/disableToggleEnabled pattern; the document detail breadcrumb already hides its Tags entry for non-editors the same way.
    
    * fix(knowledge): derive tags modal document data from live list cache
    
    The modal was fed a frozen document snapshot taken at right-click time. After a save, the mutation only invalidates the single-document and KB-detail queries (not the documents list query), so the modal's own sync effect rebuilt tags from the stale snapshot and could revert or drop the just-saved value. Track only the document id and look it up from the same documents array updateDocument() patches, so the modal always sees current data.
    waleedlatif1 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    099f525 View commit details
    Browse the repository at this point in the history
  5. refactor(utils): consolidate duplicated helpers onto @sim/utils (#5509)

    * refactor(utils): consolidate duplicated helpers onto @sim/utils
    
    Replaces ~90 hand-rolled reimplementations of error-message extraction,
    postgres error-code checks, sleep, Math.random, retry/backoff, object
    filtering/omission, noop, string truncation, date/time formatting, email
    normalization, and plain-object type guards with the shared @sim/utils
    exports. Wires check:utils into CI (test-build.yml) so these patterns
    don't regress.
    
    * fix(test): mock @sim/utils/random instead of Math.random in schedule-execute tests
    
    The schedules/execute route previously used Math.random() for jitter delay;
    this consolidation PR switched it to randomInt() from @sim/utils/random,
    which is backed by crypto.getRandomValues() rather than Math.random(). The
    route.test.ts spies on Math.random() no longer had any effect, so jitter
    became real random delay instead of the deterministic 0ms the tests expect,
    causing intermittent 10s timeouts in CI.
    
    * fix(retry): preserve uncapped Retry-After comparison in tools/index.ts
    
    parseRetryAfter() caps its return value at 30s by default. tools/index.ts
    compares the parsed Retry-After against a caller-configured maxDelayMs to
    decide whether to skip a retry entirely -- capping before that comparison
    silently defeats the skip check whenever maxDelayMs is configured above
    30s, since a Retry-After between 30s and maxDelayMs would incorrectly look
    "within limits" and get retried instead of skipped (caught by Cursor
    Bugbot). Added an optional maxMs param (default unchanged) so tools/index.ts
    can request the raw, uncapped value for its own comparison while
    backoffWithJitter still clamps the actual sleep duration to maxDelayMs.
    Added a regression test covering maxDelayMs > 30s.
    
    * fix(utils): fall back to Intl-resolved abbreviation for unmapped timezones
    
    getTimezoneAbbreviation only covered 9 hardcoded IANA zones and returned
    the raw IANA string for everything else, degrading schedule descriptions
    for zones like Europe/Berlin or America/Toronto (caught by Greptile). The
    deleted local implementation in schedules/utils.ts resolved any valid IANA
    timezone generically via Intl.DateTimeFormat's short timeZoneName. Restore
    that as a fallback so only genuinely invalid timezone strings return
    themselves unchanged.
    waleedlatif1 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    9d34fbe View commit details
    Browse the repository at this point in the history
  6. feat(providers): add xAI grok-4.5 model (#5511)

    * feat(providers): add xAI grok-4.5 model
    
    * fix(providers): correct grok-4.5 release date to API-availability date
    waleedlatif1 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    93481e4 View commit details
    Browse the repository at this point in the history
  7. Configuration menu
    Copy the full SHA
    117fa66 View commit details
    Browse the repository at this point in the history
  8. fix(comparison): correct stale and unsourced claims on comparison pag…

    …es (#5513)
    
    * fix(comparison): correct stale and unsourced claims on comparison pages
    
    - Remove stale "Templates" references from the LangChain page and
      related blog posts (feature was removed platform-wide)
    - Re-verify every sourced claim across all comparison-page profiles
      (Sim's own facts and all 20 competitor profiles) against live
      sources; fix dead links, renamed products, outdated figures, and
      claims no longer supported by their citation
    - Fix a stale sidebar permissions reference in the enterprise
      access-control docs
    
    * fix(comparison): use consistent URL format for n8n AI Workflow Builder citation
    waleedlatif1 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    7673071 View commit details
    Browse the repository at this point in the history
  9. improvement(forking): unlink, settings page migration, deployed chats…

    …, public apis, external mcp servers/tools, special subblocks (#5505)
    
    * bad checkpoint
    
    * stash
    
    * add unlink, move UI to settings pages
    
    * fix edge cases
    
    * remove dead code
    
    * remove migration 0255 ahead of staging merge (regenerated after)
    
    * regenerate workflow_mcp_server enum migration on top of staging (0257)
    
    * fix tests
    
    * more tests
    
    * address comments
    
    * consolidate fork migrations into 0257 (enum value + activity metadata indexes)
    
    * acquire MCP server locks before reads in attachment reconcile (TOCTOU)
    
    * move into ee folder + ui perm gates
    
    * use randomInt from @sim/utils/random for chat identifier suffix
    
    ---------
    
    Co-authored-by: Siddharth Ganesan <siddharthganesan@gmail.com>
    icecrasher321 and Sg312 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    4a80374 View commit details
    Browse the repository at this point in the history
  10. feat(custom-blocks): org-member visibility, workspace-admin-gated man…

    …agement (#5507)
    
    * fix(settings): let workspace admins reach the Custom blocks settings page
    
    The Custom blocks page lives in the Enterprise nav section, which the
    sidebar filter hides unless the user is an org admin/owner. But the
    server authz for managing custom blocks is source-workspace admin
    (hasWorkspaceAdminAccess), not org admin — so a workspace admin who
    could manage a block via the API couldn't even reach the page.
    
    Add an `allowNonOrgAdmin` nav flag that exempts an item from the org
    admin/owner requirement (the plan/hosted entitlement still applies; the
    page enforces its own per-resource authz), and set it on custom-blocks.
    Other Enterprise items (access control, audit logs, SSO, data
    retention/drains, whitelabeling) stay org-admin-only.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_017ddpeoz81CSqYQ73Dzf7yo
    
    * feat(custom-blocks): any org member views; create gated on workspace admin
    
    Split visibility from management to match the org-wide nature of custom
    blocks:
    - View: any org member (the nav item is now plan-gated, not org-admin).
    - Create: the "Create block" action shows only when the user is admin of
      a workspace in the current org, matching the publish route's
      source-workspace admin authz.
    - Source picker: lists only workspaces the user administers (in the
      current org); the default selection snaps to an eligible workspace when
      the current one isn't one they can publish from.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_017ddpeoz81CSqYQ73Dzf7yo
    
    * feat(custom-blocks): read-only detail for non-managers + fill image icon
    
    - Add the source workspaceId to the block wire type and gate the detail
      view on it: a viewer who isn't an admin of the block's source workspace
      gets a read-only view — no Save/Discard, no Delete, all fields disabled.
      Matches the server authz (edit/delete require source-workspace admin),
      so the UI no longer dangles buttons that 403.
    - SettingsResourceRow: add an opt-in `iconFill` so uploaded image icons
      fill the tile edge-to-edge instead of clamping to 20px; glyph svgs still
      normalize to 20px. Custom blocks list opts in.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_017ddpeoz81CSqYQ73Dzf7yo
    
    * fix(custom-blocks): include workspaceId in publishCustomBlock return
    
    The publish path builds a CustomBlockWithInputs literal; it was missing
    the workspaceId field added to the interface, breaking the type check.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_017ddpeoz81CSqYQ73Dzf7yo
    
    * fix(custom-blocks): don't flag create as dirty when source auto-snaps
    
    The create dirty-check compared selectedWorkspaceId against the URL
    workspace, but the source picker now auto-snaps to the first workspace
    the user can publish from — which may differ. Compare against that
    eligible default so opening/discarding the create flow doesn't show a
    false unsaved-changes state. (Bugbot)
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_017ddpeoz81CSqYQ73Dzf7yo
    
    ---------
    
    Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    TheodoreSpeaks and claude authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    4cd1461 View commit details
    Browse the repository at this point in the history
  11. refactor(blog): split AEO/GEO content into a new /library section (#5516

    )
    
    * refactor(blog): split AEO/GEO content into a new /library section
    
    Blog was mixing hand-written editorial posts with listicle/comparison/how-to
    posts optimized for answer engines. Extract a generic content engine
    (lib/content) shared by both sections, move the 6 AEO/GEO posts into a new
    /library route tree, and keep /blog editorial-only.
    
    - lib/content: generic registry factory, MDX components, SEO builders
    - lib/blog + lib/library: thin per-section instantiations over the shared engine
    - app/(landing)/library: mirrors the blog route tree via shared Content*Page components
    - app/sitemap.ts, app/robots.ts, navbar: updated for the new section
    - next.config.ts: permanent redirects from moved /blog/<slug> URLs to /library/<slug>
    
    * fix(blog): thread route id through buildAuthorMetadata for canonical URL
    
    Author pages for unknown/unmatched ids fell back to author?.id, which is
    undefined when no post matches — collapsing canonical/OG URLs to
    {basePath}/authors/ instead of {basePath}/authors/{id}. Pass the route id
    explicitly so canonical always resolves correctly.
    
    * fix(blog): address Greptile review — RSS lastBuildDate, shared author cache, dead-export docs
    
    - RSS lastBuildDate now uses updated ?? date so edits after publication are
      reflected, matching the per-item pubDate semantics (blog + library)
    - Author JSON is now cached once per authorsDir at module scope instead of
      once per registry instantiation, since blog and library point at the same
      directory
    - Documented getNavPosts as reserved-but-unwired, matching the existing
      PLATFORM_MENU/SOLUTIONS_MENU convention in the navbar
    
    * fix(blog): dedupe featured posts from ContentIndexPage pagination pool
    
    A featured post older than POSTS_PER_PAGE would appear both on page 1's
    featured row (sorted to the front) and again on its natural date-sorted
    page, since only page 1 excluded featured posts from the remaining list.
    Carve featured posts out of the paginated pool up front so pagination stays
    consistent and duplicate-free across all pages.
    
    * fix(blog): RSS lastBuildDate reflects the whole feed, not just the newest item
    
    lastBuildDate only looked at items[0]'s updated/date, so revising an older
    post already in the feed wouldn't advance it. Extract the max-across-posts
    logic sitemap.ts already had into a shared lib/content/utils helper
    (latestModified) and use it in both RSS routes and the sitemap, so a
    revision to any feed item is reflected.
    waleedlatif1 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    004955d View commit details
    Browse the repository at this point in the history
  12. fix(workflow): render agent tool chip names from static sources, not …

    …stored title (#5501)
    
    * fix(workflow): render agent tool chip names from static sources, not stored title
    
    Tool entries in an agent block's inputs carry a mutable `title` in workflow
    state, which copilot edits (edit_workflow) could rewrite to change what the
    UI displays. Derive chip names from static/canonical sources instead: the
    block registry name for integration tools (raw type id if unregistered),
    the custom-tool record over the stored snapshot, the live MCP tool name,
    and a static literal for workflow-as-tool. The stored `title` still persists
    in state; the UI just no longer reads it for registry-backed tools.
    
    Covers both render paths: the expanded tool-input chips and the collapsed
    canvas summary (resolveToolsLabel, also used by workflow preview).
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    * fix(workflow): cover workflow-as-tool and custom-tool fallbacks in static naming
    
    Address review findings: resolveToolsLabel now returns the static
    'Workflow' label for workflow/workflow_input entries instead of falling
    through to the stored title, matching the panel chip; the panel's
    custom-tool name priority now matches resolveToolsLabel (record title,
    record schema function name, then stored title); and the display-name
    comment no longer overstates the guarantee.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    * fix(workflow): resolve panel chip names via unfiltered block registry
    
    The panel resolved integration tool names through toolBlocks, which is
    permission- and toolbar-filtered, so a stored tool whose type was
    filtered out of the picker fell back to the raw type id while the
    canvas summary (getBlock) still showed the registry name. Use getBlock
    directly for the display name so both paths agree; toolBlocks still
    drives the chip icon, params, and picker.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    * fix(workflow): resolve MCP tool names from live server data in canvas summaries
    
    resolveToolsLabel preferred the stored title for mcp entries, so canvas
    and preview summaries could show a state-edited name while the config
    panel showed the live MCP tool name. Accept an optional mcpTools list
    (matched by toolId, same as the panel) and pass the already-fetched MCP
    tool data from workflow-block; the stored title remains the fallback
    while server data is unavailable.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    * refactor(workflow): single shared tool-name resolver; fix overlay, fallback, and search regressions
    
    Consolidate the per-surface name logic into one resolveStoredToolName in
    display.ts (canonical source -> stored title -> raw type id) used by the
    panel chips, the canvas summary, and the search indexer, fixing the
    regressions the per-renderer patches introduced:
    
    - custom-block tools (async registry overlay) no longer render raw
      custom_block_<uuid> ids pre-hydration or after deletion; the canvas
      memo and panel picker now subscribe to the overlay version so labels
      recompute when custom blocks hydrate
    - unresolvable block types fall back to the stored title before the raw
      type id, instead of always showing the id
    - the search indexer now indexes the resolved display name (the title
      entry was already read-only), so search text and highlights match what
      the chips render instead of the mutable stored title
    - redundant hardcoded 'Workflow' labels removed (registry names cover
      workflow/workflow_input); MCP lookups use a shared Map keyed by
      composite tool id instead of per-entry array scans; panel chip chrome
      falls back to the unfiltered registry for picker-hidden types
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    * fix(workflow): thread custom-tool and MCP data into the search indexer; fix blockConfigs type
    
    The search index now resolves tool names with the same data as the chip
    renderers: the single caller passes customTools and a live MCP name map
    into indexWorkflowSearchMatches, so indexed names match the panel for
    custom-tool references and MCP entries, not just registry-backed types.
    Also declare the optional name on WorkflowSearchIndexerOptions
    blockConfigs entries, fixing the next build type error.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    * fix(workflow): recompute search index when the custom-block overlay hydrates
    
    The matches memo resolves tool names through getBlock, so it must carry
    the overlay version dep like the other getBlock-derived memos; without
    it, find-in-workflow could index stale custom-block names until an
    unrelated dep changed.
    
    Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
    j15z and claude authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    fa82acd View commit details
    Browse the repository at this point in the history
  13. docs(enterprise): add Custom Blocks page (#5515)

    * docs(enterprise): add Custom Blocks page
    
    Document publishing a deployed workflow as a reusable org-wide block:
    publishing flow, common uses, using a block, managing, and self-hosted
    setup, with UI screenshots. Register in the enterprise sidebar and wire
    the settings docsLink.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01NvLuS5o1eFjBBhEC4PytcA
    
    * docs(enterprise): drop explicit Enterprise framing, note access control
    
    The page's Enterprise placement is implicit, so remove the "Enterprise
    feature" callout and plan mentions. Add that custom blocks can be
    allowlisted per permission group via Access Control.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01NvLuS5o1eFjBBhEC4PytcA
    
    * docs(enterprise): remove Self-hosted setup section from Custom Blocks
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01NvLuS5o1eFjBBhEC4PytcA
    
    ---------
    
    Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
    TheodoreSpeaks and claude authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    d30eb36 View commit details
    Browse the repository at this point in the history
  14. fix(rich-markdown-editor): eliminate empty-block / boundary-key struc…

    …tural bugs (#5517)
    
    * fix(rich-markdown-editor): don't split a list when deleting an empty item
    
    Backspacing an emptied list item in the middle of a list used ProseMirror's default lift, which pulls
    the item out into a top-level paragraph — splitting one list into two and stranding an empty paragraph
    (a visible gap). Backspace at the start of an empty list item now joins into the previous block instead,
    removing the item and keeping a single list. Covers bullet, ordered, and task lists.
    
    * fix(rich-markdown-editor): generalize empty-wrapped-block boundary keys
    
    Replace the joinBackward empty-list-item Backspace branch with a walk-up-and-delete
    that removes the whole emptied wrapper, and extend it to task items and blockquotes.
    joinBackward left a stray empty paragraph inside the previous item (flat lists) or
    no-op'd entirely on nested items (leaving them stuck); blockquotes were never handled
    and split in two. Add an Enter handler so an empty non-trailing list/task item is
    removed rather than split into two lists around a stranded, non-round-trippable empty
    paragraph; a trailing empty item still exits the list via the default.
    
    Covers bullet/ordered/task/blockquote at every position; non-empty items and the
    double-Enter list-exit are unaffected.
    
    * fix(rich-markdown-editor): isolate verbatim block nodes from boundary joins
    
    footnoteDef and rawHtmlBlock hold exact source text but were neither isolating nor
    atom, so a single Backspace/Delete at their boundary let ProseMirror's default join
    merge their raw markdown into an adjacent paragraph as HTML-escaped prose — silently
    destroying the node and corrupting saved markdown. Mark the block variants isolating
    so boundary keys can't cross their edge. Round-trip and in-place editing are unchanged.
    
    * fix(rich-markdown-editor): escape leading block markers in paragraph serialization
    
    A paragraph beginning with #, -, +, 1., 1), or a bare --- serialized unescaped, so it
    silently re-parsed into a heading / list / thematic break on the next load (reachable
    via type-a-marker then undo). The upstream serializer escapes inline delimiters (* _ `
    [ ] ~, so * bullets and > quotes already round-trip) but not these block-starting
    markers. BlockSafeParagraph wraps the paragraph renderer with a leading-marker guard;
    escaping is idempotent (parsing consumes the backslash) and never over-escapes non-markers
    like #hashtag or -5.
    
    * fix(rich-markdown-editor): strip leading paragraph indent; keep empty paragraphs &nbsp;-free
    
    A paragraph beginning with a 4-space/tab indent re-parsed as an indented code block on the
    next load. Leading whitespace never renders in a paragraph (CommonMark strips up to three
    leading spaces; four or more become code), so BlockSafeParagraph now strips it — lossless
    and idempotent. Composes with the existing leading-marker escaping (e.g. '   # x' → '\# x').
    
    Also locks in that consecutive empty paragraphs serialize via blank lines rather than the
    upstream '&nbsp;' marker: replacing StarterKit's Paragraph already dropped the &nbsp; path,
    and the round-trip preserves the empty-paragraph count without tripping the read-only
    safety gate (which flags &nbsp; as a stable-loss pattern). Added tests for both.
    waleedlatif1 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    1236474 View commit details
    Browse the repository at this point in the history
  15. fix(ashby): repair broken idempotency dedup and clarify duplicate-web…

    …hook errors (#5518)
    
    * fix(ashby): repair broken idempotency dedup and clarify duplicate-webhook errors
    
    extractIdempotencyId looked for a webhookActionId field that does not
    exist anywhere in Ashby's webhook payload schema (confirmed against the
    live OpenAPI spec), so every delivery — including Ashby's own retries —
    got a fresh random dedup key and could re-execute workflows. Derive the
    key from the affected resource's id plus its updatedAt/decidedAt instead.
    
    Also surface a clear, actionable message when Ashby's webhook.create
    rejects a request as a duplicate (seen repeatedly in production logs,
    where the outbox retried the same failing subscription for ~23 minutes
    before dead-lettering) instead of the generic API error passthrough.
    
    Also add the interview stage `type` field to trigger outputs (present
    in Ashby's schema, useful for a stage-change trigger) and fix the
    employmentType description to match Ashby's actual enum values.
    
    * fix(ashby): correct offer status enum values in trigger output descriptions
    
    acceptanceStatus listed a non-existent "WaitingOnResponse" value and
    offerStatus was missing "WaitingOnApprovalDefinition" — both caught on
    a second pass re-checking every enum against Ashby's live OpenAPI spec.
    
    * fix(ashby): harden idempotency key against Greptile-flagged collision risks
    
    - Return null (skip dedup) when application.updatedAt is absent instead
      of collapsing to an empty string, which could collide two distinct
      events sharing an application id onto the same key.
    - Drop decidedAt from the offerCreate key. It's populated only after
      the fact, so including it gave a retry of the same delivery a
      different key than the original attempt once the candidate
      responded, defeating dedup. offer.id alone is already stable and
      unique per created offer.
    
    * fix(ashby): fall back to a content fingerprint instead of skipping dedup
    
    Returning null when application.updatedAt was missing avoided false
    collisions between distinct events, but also disabled retry dedup
    entirely for that payload shape — an Ashby retry would get a random
    key from the idempotency service's own fallback and re-run the
    workflow.
    
    Extract the fallback-fingerprint helper (sha256 of a stably-serialized
    payload) out of salesforce.ts into the shared providers/utils.ts, and
    use it in ashby.ts: identical retried bytes hash identically (dedup
    still works), while two genuinely different events hash differently
    (no false collision).
    
    * chore(ashby): remove inline comments, let names carry the intent
    
    * fix(ashby): fingerprint the full data payload, not just application
    
    Hashing only data.application missed other fields (e.g. offer on
    candidateHire) when updatedAt is absent, so two deliveries sharing an
    application snapshot but differing elsewhere in data could collide
    onto the same idempotency key.
    
    * fix(ashby): rename output field 'type' to 'stageType' to fix build
    
    TriggerOutput reserves the 'type' key for the output's own JSON type
    (e.g. 'string'), so a nested field literally named 'type' inside
    currentInterviewStage collided with that meta-field and broke the
    Record<string, TriggerOutput> cast — passing local type-check (which
    turbo was silently serving a stale cached pass for) but failing
    Next.js's build-time type check in CI. Renamed to stageType, matching
    the existing eventType-style convention used elsewhere for API fields
    literally called 'type'.
    
    * fix(ashby): rename currentInterviewStage.type to stageType in delivered data too
    
    Renaming the field in the output schema alone (to fix the TriggerOutput
    build collision) left a mismatch: Ashby's real payload still has
    currentInterviewStage.type, so a picker/expression using the schema's
    declared stageType would resolve to undefined at runtime. formatInput
    now renames the field in the actual delivered payload so it matches
    what the schema declares.
    
    * fix(ashby): fold offer id into the idempotency key when present
    
    When application.updatedAt is present, the key ignored sibling data
    fields — a candidateHire delivery carries both application and offer,
    so two deliveries sharing an application snapshot could collide even
    though they concern different offers. Append offer.id to the
    discriminator when present; it's the only sibling object Ashby's
    schema ever pairs with application.
    waleedlatif1 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    07c026a View commit details
    Browse the repository at this point in the history
  16. feat(comparison): add Custom Blocks as a comparison-page fact (#5519)

    - New "customBlocks" row in the platform section: whether a platform
      lets a builder publish a deployed workflow as a reusable, encapsulated
      block for org-wide reuse (Sim's new Custom Blocks feature)
    - Researched and sourced an accurate answer for all 20 competitors,
      distinguishing real equivalents from look-alikes (sub-workflow
      composition, custom code nodes, connector wrappers, templates)
    waleedlatif1 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    57ff500 View commit details
    Browse the repository at this point in the history
  17. docs(forking): workspace forking for enterprises (#5520)

    * docs(forking): workspace forking
    
    * update comparison links
    icecrasher321 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    9404bda View commit details
    Browse the repository at this point in the history
  18. chore(typescript): upgrade to TypeScript 7 (native Go compiler) (#5521)

    * chore(typescript): upgrade to TypeScript 7 (native Go compiler)
    
    Bumps typescript to ^7.0.2 across every workspace package. Full
    bun run type-check/lint/build/test all pass; apps/sim's type-check
    (the one needing an 8GB heap bump) drops from ~55s to ~7s wall time.
    
    Migration fixes required by TS7's stricter defaults:
    - baseUrl removed: drop it from 5 tsconfigs (paths already resolved
      relative to tsconfig dir, so behavior is unchanged) and prefix the
      one bare (non-relative) paths entry each in apps/sim and
      apps/realtime with './'
    - moduleResolution=node10 removed: switch packages/cli and
      packages/ts-sdk to "bundler", matching the rest of the monorepo
    - types now defaults to [] instead of auto-including every @types/*
      package: add "types": ["node"] to the shared base tsconfig (this
      is fundamentally a Node monorepo, so this restores prior behavior
      in one place instead of duplicating it per-package), add explicit
      @types/node deps to packages that now rely on it transitively via
      @sim/db/@sim/logger, and add "declare module '*.css'" to the two
      packages with plain (non-module) CSS side-effect imports that
      TS7's stricter checker now flags
    - packages/logger's isomorphic `typeof window` check no longer needs
      DOM lib in every consumer: replaced with `'window' in globalThis`
    - packages/testing and apps/realtime's fetch/DOM mocks need DOM lib
      where they're compiled, since they model the browser Fetch API
    - the `typescript` npm package no longer exports the classic
      Compiler API from its main entry (moved to unstable/ast subpaths);
      apps/sim's Function-block route used it at runtime to strip
      import statements from user code, so that one call site now uses
      Microsoft's official transition package, @typescript/typescript6
    - Next.js 16.2.6's own TypeScript-detection heuristic hardcodes a
      path TS7 no longer ships, and its auto-install fallback assumes
      npm/pnpm; added @typescript/native-preview as a devDependency to
      apps/sim and apps/docs so Next detects a valid native compiler
      instead of trying (and failing) to auto-install one
    
    Not merging yet: TS 7.0.2 published today and is still inside this
    repo's bunfig.toml minimumReleaseAge (7-day) supply-chain gate, so
    `bun install` will fail for everyone until 2026-07-15. Opening this
    now to get it through review; hold the actual merge until then.
    
    * fix(typescript): address Greptile review findings on TS7 upgrade
    
    - packages/logger: 'window' in globalThis treats a shim that leaves
      globalThis.window explicitly undefined as browser-only, silently
      dropping production server logs. Restore the original
      typeof !== 'undefined' semantics via an inline cast instead, so it
      stays correct without requiring DOM lib in every consumer.
    - packages/ts-sdk, packages/cli: both are tsc-built, published as
      Node ESM (package.json "type": "module" with an "exports" map).
      "moduleResolution": "bundler" is too permissive for that target -
      it accepts import patterns (e.g. extensionless relative imports)
      that Node's actual ESM resolver rejects at runtime. Switch both to
      "module"/"moduleResolution": "nodenext", the correct pairing for a
      published Node ESM package. Verified real tsc builds (not just
      --noEmit) still succeed for both.
    
    * chore(bunfig): temporarily disable minimumReleaseAge gate for TS7 install
    
    TS 7.0.2 published today, still inside the 7-day gate. Lowering to 0
    to unblock this merge; will restore to 604800 in an immediate follow-up
    commit right after merging.
    waleedlatif1 authored Jul 8, 2026
    Configuration menu
    Copy the full SHA
    d078c84 View commit details
    Browse the repository at this point in the history

Commits on Jul 9, 2026

  1. Configuration menu
    Copy the full SHA
    bacfe43 View commit details
    Browse the repository at this point in the history
  2. fix warning

    icecrasher321 committed Jul 9, 2026
    Configuration menu
    Copy the full SHA
    388213b View commit details
    Browse the repository at this point in the history
Loading