Skip to content

v0.7.17: emcn and workflow renderer isolated package, popular blocks extension, workspace forking, slack trigger extension, new README#5281

Merged
waleedlatif1 merged 22 commits into
mainfrom
staging
Jun 30, 2026
Merged

v0.7.17: emcn and workflow renderer isolated package, popular blocks extension, workspace forking, slack trigger extension, new README#5281
waleedlatif1 merged 22 commits into
mainfrom
staging

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

icecrasher321 and others added 22 commits June 28, 2026 13:13
* feat(workspaces): fork + push/pull

* type fix

* fix tests

* progress on ux

* remove modal section

* improve UI of modal

* update more ui

* make rollback part of the footer

* track skipped count correctly

* address comments

* make it workspace admin level

* update skipped count

* address more comments

* deal with unbounded memory possibility

* fix deleted kb article bug

* no deployed workflow case

* UI/UX cleanup

* fix oauth dropdown case

* fix oauth selector issue

* infra work + activity log

* consolidate migration

* update modal state

* more UI simplification

* grammar

* update audit report ui

* perf improvements

* fix tool input scenarios and add dependsOn UI handling

* minor comments

* fix webhook stability issues + drift detection removal

* make dependsOn subblock mapping cleanly stored

* fix: harden fork dependent-value mapping (clear stale rows, identity-guard first-sync fallback, perf + cleanup)

* address comments

* update comment

* enforce admin perms for activity api

* fix required + dependsOn combo
* improvement(docs): flatten the academy learn/chapters panels

The "What you will learn" and "Chapters" panels were filled, bordered
cards — the only boxed elements on the page. The docs design system is
explicitly flat: global.css strips fumadocs cards/callouts/card-grids to
transparent/divider-based, and the right-rail "On this page" TOC is small,
muted, and borderless.

- WhatYouWillLearn (inline): flat divider list like the FAQ, with a small
  panel label at the app's text scale instead of a page-h2-scale title
- VideoChapters (right rail): borderless, matching the TOC — small muted
  label + flat hover rows, no card chrome

* improvement(docs): drop the repeated per-row play icon from the chapters list

The CirclePlay glyph repeated on every chapter row read as noise — a column
of identical icons down the rail. The "On this page" TOC this list mirrors
has no per-row icons; the timestamps already signal video chapters and the
hover highlight signals they're seekable. Rows are now text + time only.

* improvement(docs): drop the under-label rule on the learn callout

A full-width rule under the small "What you will learn" label read as an
awkward heading underline and blurred into the inter-item dividers. The label
is now a quiet muted marker (matching the Chapters label and the TOC heading),
with dividers only between items — so it never competes with the bold item
titles or looks like an underlined heading.
* chore(deploy): remove a2a

* add block
… tool depth (#5256)

* feat(airtable): add delete and upsert record tools

* feat(google-docs): add batchUpdate text, table, image, and style tools

* feat(whatsapp): add template, media, interactive, reaction, and mark-read tools

* feat(microsoft-excel): add clear, format, create-table, sort, and delete-worksheet tools

* fix(integrations): address review feedback

- google-docs: use camelCase fontSize field mask; normalize string booleans for bold/italic/underline and matchCase
- microsoft-excel: escape OData single quotes in worksheet/table keys; validate range for clear/format
- airtable: enforce batch limits (delete <=10 ids, upsert <=10 records and 1-3 merge fields) with clear errors

* fix(integrations): address round-2 review

- airtable: coerce upsert typecast as string-aware boolean (string "false" no longer truthy)
- microsoft-excel: format_range surfaces precise partial-state error when fill PATCH fails after font (no atomic font+fill endpoint in Graph)

* fix(whatsapp): treat 2xx mark-as-read as success unless body says success:false

* fix(integrations): build fix, doc accuracy, and comment cleanup

- google-docs: align manualDocumentId condition with the document selector so the documentId canonical group has matching conditions (fixes canonical-pair block test / build)
- microsoft-excel: describe fill/font color as hex code only (Graph does not reliably accept named colors)
- remove verbose explanatory inline comments from new tools (keep idiomatic section dividers)
- regenerate integration docs + integrations.json catalog from the block registry

* fix(integrations): harden delete-record id coercion and excel sort-column validation

- airtable: coerce recordIds entries via String() so numeric JSON values don't crash on .trim()
- microsoft-excel: drop the silent sortColumn default to 0 so invalid input surfaces the tool's clear validation error (both v1 and v2 blocks)

* fix(airtable): coerce upsert fieldsToMergeOn entries via String() to handle non-string values
#5257)

Moves apps/sim/components/emcn into a shared @sim/emcn package consumed directly by apps/sim and apps/docs. cn/keyboard/use-copy-to-clipboard move into the package; all imports become direct @sim/emcn (icons via @sim/emcn/icons, CSS via file path). ChipModal email validation is now prop-driven (quickValidateEmail stays in apps/sim, injected via validate). Docs drops its local chip/chip-dropdown/dropdown-menu mirrors and consumes @sim/emcn.
…tion (#5258)

Two regressions from moving emcn into @sim/emcn:

1. optimizePackageImports['@sim/emcn'] rewrote barrel imports to direct subpaths, duplicating the toast module so ToastProvider (layout) and useToast (workspace permissions provider) resolved different ToastContext objects — useToast threw 'must be used within <ToastProvider>' on every workspace route. Removed @sim/emcn from optimizePackageImports.

2. emcn's source left apps/sim's Tailwind content globs (and docs' v4 auto-content scope, which excludes node_modules), so utility classes used only inside emcn components stopped generating and components rendered unstyled. Added the package to apps/sim's Tailwind content and a @source to docs.
…ter works (#5259)

* fix(knowledge): send tag filters as a JSON string so the document filter works

The document-list tag filter never reached the database. The `tagFilters`
query field was a Zod `.transform()` that decoded the JSON string into an
array of objects; the client's `requestJson` parses the query before
serializing, so `appendQuery` received the array and emitted
`tagFilters=[object Object]` into the URL. The route then failed to
`JSON.parse` it and returned 400, so the list came back empty (or stale via
keepPreviousData) regardless of operator or value.

- Model `tagFilters` as the wire string it actually is; decode it server-side
  via a new `parseDocumentTagFiltersParam` helper (route maps a bad value to 400).
- Harden `appendQuery`: throw on an array-of-objects query param instead of
  silently serializing `[object Object]`, so this whole class fails loudly.
- Default the text tag-filter operator to `contains` so a partial value matches.
- Tests: requestJson serializes the JSON param verbatim + the guard throws; the
  query schema keeps tagFilters a string; the decode helper round-trips.

A full sweep of every GET/DELETE contract query field confirmed this was the
only field of this class — logs filters and table filter/sort are unaffected.

* fix(knowledge): reject tag-filter operators invalid for the field type

Greptile P2: documentTagFilterSchema accepted any non-empty operator string, so
an unsupported operator was silently dropped by the query builder instead of
returning 400. Validate the operator against the field type's allowed set
(single source of truth in filters/types) via superRefine.

* fix(knowledge): validate tag-filter type against the slot, not the client claim

Greptile P1: operator validation trusted the client-supplied fieldType, so a
numeric slot could be sent with fieldType 'text' + 'contains' and slip through
to build a text LIKE on a numeric column. Validate against the slot's inherent
type via getFieldTypeForSlot (the source of truth): reject unknown slots and
fieldType/slot mismatches at the boundary before checking the operator.

* fix(knowledge): validate tag-filter values against the field type

Greptile P1: value/valueTo were z.unknown(), so a number filter accepted 'abc',
a date filter 'not-a-date', etc. — unusable values the query builder then
silently dropped. Add a shared isValidFilterValue (single source of truth in
filters/types) and reject unusable value/valueTo at the boundary, including the
between upper bound.

* fix(knowledge): only send a between tag filter once both bounds are set

Cursor Bugbot: the strict valueTo validation made a partially-entered between
filter (lower bound only) 400 and break the whole document list mid-entry.
activeTagFilters now withholds a between row until both bounds are filled —
consistent with already requiring the lower bound before sending any filter — so
the list keeps loading while the range is being entered.

* fix(knowledge): reject impossible calendar dates in tag filters

Greptile P1: the date value check was format-only, so 2026-02-30 / 2026-99-99
passed the boundary and then made the document query's ::date cast throw a 500.
Validate real calendar dates by round-tripping the parsed parts.
…rve prism side effects (#5261)

Two post-extraction regressions:

1. The barrel resolves the Calendar name-collision to the date-picker COMPONENT (symmetric with Table). Scheduled-tasks imported Calendar from the barrel but used it as an ICON, so its header rendered a date picker. Route the icon consumers (scheduled-tasks + loading) to @sim/emcn/icons, matching the 'icons come from the /icons subpath' convention.

2. The package's new sideEffects: ['**/*.css'] marked code/prism.ts as side-effect-free, but it registers prismjs languages on the global Prism (a real JS side effect). The bundler could drop/reorder its core init, causing 'Prism is not defined'. Add code/prism.ts to sideEffects so the bundler preserves it.
prismjs language components (prismjs/components/prism-*) register on the global Prism that core installs; importing a component before core throws 'Prism is not defined' (in SSR and the client). The @sim/emcn extraction changed bundling so core no longer loaded eagerly first, exposing the latent bad order on the home (chat-content) and workflow-editor pages.

- chat-content.tsx: import prismjs core first (it needs ts/bash/css/markup, which emcn does not register).
- code-editor.tsx, input-format.tsx, code.tsx: drop the redundant prism-json/prism-python imports — these highlight via emcn's languages, which already registers js/json/python in the correct order.
…th (#5264)

- Log per-request duration in the Presidio sidecar (/analyze, /anonymize)
- Add durationMs to the mask-batch endpoint log line
- Emit per-execution PII redaction timing (stringCount, totalBytes, durationMs, scrubbed)
…sim/workflow-renderer (#5263)

Adds a @sim/workflow-renderer package with pure, props-driven WorkflowEdgeView, SubflowNodeView, and NoteBlockView shared by the editor and (future) docs preview. Moves block-dimensions constants into the package. Each editor node becomes a thin Container that wires stores/permissions and injects the editor-only ActionBar via a slot. No optimizePackageImports for the workspace component packages (avoids the toast-style module duplication); Tailwind scans the package source.
)

Rebuild the dev-only minimal block registry from the canonical, toolbar-visible
core (category blocks/triggers, not hideFromToolbar, latest version). Adds the
visible workflow_input and table blocks (previously only the hidden `workflow`
was present, so the Workflow block never rendered in dev:minimal), drops the
superseded/hidden entries (api_trigger, chat_trigger, input_trigger,
manual_trigger, router, starter, workflow), and hand-prunes the heaviest /
rarely-core-dev blocks (mothership, pi, tts, stt_v2, image_generator_v2,
video_generator_v3, circleback).

Dev-only, gated on SIM_DEV_MINIMAL_REGISTRY=1; never aliased in production.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#5266)

* fix(uploads): attach compiled binary for AI-generated docs, not source

AI-generated documents (pdf/docx/pptx/xlsx) created in Chat are stored as
their generation source, with the rendered binary in a separate
content-addressed artifact store. Read/preview paths swap in the binary, but
attachment/upload/provider paths downloaded the raw source — so a generated
PDF emailed via Gmail (and 30+ other tools) arrived as the generator script
renamed .pdf.

- Add shared resolveServableDocBytes resolver + downloadServableFileFromStorage
  wrapper; the file-serve route now delegates to the same resolver so the two
  paths resolve identically.
- Migrate ~34 attachment/upload/parse tool routes + the LLM provider attachment
  path to the servable download; media-only tools and source-editing paths keep
  the raw download intentionally.
- Surface a retryable 409 (shared docNotReadyResponse) when a doc artifact is
  still compiling instead of shipping source.

* fix(uploads): return retryable 409 for not-ready docs in slack/teams sends

The slack send-message and teams write_channel/write_chat routes call
download helpers that can throw DocCompileUserError while a generated doc is
still compiling. Map it to the shared docNotReadyResponse 409 (matching the
other migrated tool routes) instead of a generic 500. The provider attachment
path is internal LLM execution (no HTTP response), so it intentionally
propagates the typed error.

* fix(uploads): not-ready 409 for uptimerobot, real MIME for non-doc, xlsx tests

Address review findings:
- uptimerobot create-psp/update-psp now map DocCompileUserError to the shared
  409 (Greptile + Cursor flagged the gap alongside slack/teams).
- downloadServableFileFromStorage returns the extension-derived MIME
  (getMimeTypeFromExtension) for non-doc files instead of an empty string when
  userFile.type is unset.
- Add resolveServableDocBytes tests for the three xlsx branches (binary ZIP
  passthrough, not-ready throw under E2B+beta, no-workspaceId raw passthrough).

* fix(uploads): enforce attachment size limits on resolved bytes

Size limits were checked against userFile.size (source metadata) before
resolution, but a generated doc resolves to a larger compiled binary — so a
small-source doc could pass the pre-check yet exceed the service limit. Add a
post-resolution check on the actual resolved bytes (mirroring docusign/vanta)
across gmail send/draft/edit-draft, smtp, outlook send/draft, telegram, sftp,
and teams; the cheap source pre-check stays as an early reject.

* chore(uploads): drop extraneous inline comments from servable-file changes

* fix(sftp): enforce 100MB cap on cumulative resolved bytes, not per-file

The SFTP batch upload checked each resolved file against the 100MB cap
individually, so multiple resolved attachments could each pass while their
combined size exceeded the limit. Accumulate resolved bytes across the loop
and reject once the running total exceeds the cap.

* fix(sendgrid): reject attachments exceeding SendGrid's 30MB limit on resolved bytes

SendGrid had no attachment-size guard, so a generated doc resolving to a large
compiled binary could be sent and fail opaquely at the API. Add a post-resolution
total-size check (30MB, SendGrid's documented message limit) matching the
gmail/smtp/outlook routes.
…5265)

* feat(telegram): add edit, forward, copy, location, contact, poll, pin, reaction, chat-action, and chat-info tools

* feat(outlook): add reply, reply-all, folders, attachments, search, and message-update tools

* feat(notion): add block children CRUD, comments, and users tools (v1 + v2)

* docs(integrations): regenerate docs + catalog for telegram, outlook, notion tools

* fix(notion): guard pageSize coercion with Number.isFinite so non-numeric input isn't forwarded as NaN

* fix(telegram): normalize send_poll options (array, JSON string, or newlines) so json-typed input can't crash on .map

* fix(integrations): harden outlook search quoting, notion archive default, and telegram poll options

- outlook: strip embedded double quotes from the $search term so they can't break the quoted KQL query
- notion: default the update_block Archive dropdown to 'Leave unchanged' so updates don't send an unintended archived:false restore flag
- telegram: pass raw poll options through to the tool's normalizePollOptions (handles array/JSON-string/newlines) so the block layer no longer mishandles JSON-string input

* fix(integrations): normalize outlook categories input and clamp notion pageSize

- outlook: normalize update_message categories (array, JSON string, or comma/newline) so a JSON-string value isn't silently dropped
- notion: clamp pageSize to Notion's 1-100 range (truncated) so out-of-range values don't hit an API error

* fix(outlook): pass raw categories to the tool's normalizeCategories so the block handles JSON-string input too

* fix(outlook): allow clearing message categories by passing an empty array

An explicit empty array now sends categories:[] to clear all labels, a non-empty value replaces, and an absent/empty value leaves them untouched — matching the documented replace semantics.

* fix(outlook): only clear categories on an explicit empty array, not a delimiter-only string

A string that normalizes to no categories (e.g. just commas) is now a no-op rather than clearing all labels; clearing requires an explicit empty array.

* fix(notion): clamp page_size to 1-100 at the tool layer for list comments/users and block children

Adds a shared clampNotionPageSize helper so the agent-direct path is bounded to Notion's range, not just the block path.

* fix(outlook): use consistent set/replace semantics for message categories

Categories are replaced with the provided non-empty list and left unchanged when empty, consistent across the block and agent paths. Drops the ambiguous empty-array clear (clearing all categories isn't expressible unambiguously from the comma-separated field) and updates the description to match.
…View (#5267)

* feat(workflow-renderer): extract pure SubBlockRowView from the block's summary row

Splits the canvas block's collapsed subblock summary row into a pure SubBlockRowView (title + resolved displayValue + monospace flag) in @sim/workflow-renderer. The ~9 selector-name hydration hooks stay in the SubBlockRow container behind its memo comparator; the view receives only resolved strings. Byte-identical row JSX. First step toward the full WorkflowBlockView.

* feat(workflow-renderer): extract pure WorkflowBlockView shell

Moves the canvas block's render (header, badges, dynamic handles, ring) into a pure WorkflowBlockView in @sim/workflow-renderer. WorkflowBlock becomes a thin container that resolves all stores/hooks/permissions, builds the subblock rows + actionBar slots, and binds wouldCreateConnectionCycle (reads the edge store fresh per call to preserve cycle prevention). getHandleClasses/getHandleStyle move into the view; config.icon/bgColor, the webhook provider name, and every visual flag cross as props. Byte-identical JSX — every handle id/class/style/offset and badge guard preserved (verified by an independent adversarial audit). Container drops from 1137 to 829 lines.
…one, Resend, and S3 tool depth (#5270)

* feat(firecrawl): add crawl status/cancel, batch scrape + status, extract status, credit usage tools

* feat(resend): add audiences, broadcasts, and cancel-email tools

* feat(pinecone): add delete/update vectors, index, and stats tools

* feat(google-drive): add revisions, comments, and export tools

* feat(elevenlabs): add voices, settings, models, user, sound-effects, speech-to-speech, audio-isolation tools

* feat(s3): add bucket CRUD, head-object, presigned-url, and batch-delete tools

* chore(api-validation): bump route baseline to 873 for wave-3 internal tool routes (s3, elevenlabs, google_drive export)

* docs(integrations): regenerate docs + catalog for wave-3 tools

* fix(integrations): audit fixes for wave-3

- pinecone: read camelCase vectorType/deletionProtection (with snake_case fallback) so list_indexes/describe_index populate them; make describe_index_stats casing defensive
- google-drive: URL-encode fileId in the export route
- remove extraneous inline/section-divider comments across new blocks/tools; convert type docs to TSDoc

* fix(integrations): address review — elevenlabs settings bleed, batch-scrape job-id guard, s3 head-object existence

- elevenlabs: select stability/similarityBoost by operation so a stale edit-settings value can't bleed into a TTS call
- firecrawl: fail fast with a clear error when batch scrape returns no job id (avoids a misleading polling timeout)
- s3: head_object on a missing key now returns exists:false instead of a generic failure

* fix(s3): allow exists:false in head-object response contract (schema must match the missing-object output)

* fix(pinecone): guard JSON.parse of ids/filter/values/sparseValues/setMetadata

Malformed JSON-string input now throws a clear '<field> must be valid JSON' error via a shared parseJsonParam helper instead of crashing the request body builder.

* fix(pinecone): enforce mutual exclusivity of ids/deleteAll/filter in delete_vectors

Pinecone treats these delete selectors as mutually exclusive; the tool now requires exactly one and throws a clear error otherwise, instead of sending a conflicting body.

* fix(integrations): I/O fidelity vs API docs (wave-3 audit)

- pinecone: normalize describe_index_stats per-namespace vector_count -> vectorCount
- firecrawl: remove phantom 'sources' from extract_status, add real creditsUsed/tokensUsed; expose batch_scrape maxConcurrency/ignoreInvalidURLs
- google-drive: drop undocumented supportsAllDrives from the files.export URL
- elevenlabs: add next_page_token input to list_voices (fixes pagination dead-end)
- resend: surface segment_id on get_broadcast; declare replyTo + segment_id in block outputs
* feat(mship): secrets prompting

t# with '#' will be ignored, and an empty message aborts the commit.

* improvement(secrets): special tags improvement

* fix(comments): fix pr comments
)

* docs(readme): redesign README — animated hero + product demo

A visual redesign of the top-level README:
- Self-contained animated hero (logo, headline with cycle-loader, chat composer,
  and workflow + integrations peeks) baked into one looping image.
- One combined demo GIF: Integrate / Ingest / Build / Monitor header over an
  animated product tour (chat → integrate → ingest → build → deploy → monitor).
- Graphics rendered from the real product UI, full content width.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(readme): rebuild demo without dither to remove flat-area speckle artifacts

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* docs(readme): rename feature label Ingest -> Context

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: andresdjasso <andresdjasso@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…5277)

* chore(workflow-renderer): declare @sim/emcn dep + wire the package into docs

Adds the missing @sim/emcn peer/dev dependency to @sim/workflow-renderer (it imports @sim/emcn in every View but resolved only via workspace hoisting). Wires apps/docs to consume @sim/workflow-renderer (dependency, transpilePackages, Tailwind @source) and adds remark-breaks (pulled transitively via the barrel's NoteBlockView export) — mirroring the @sim/emcn integration. Foundation for migrating the docs workflow-preview fork onto the shared Views. Build resolves the package/@source/remark-breaks cleanly.

* feat(docs): render loop/parallel containers with the shared SubflowNodeView

Replaces the forked PreviewContainerNode with a thin DocsContainerNode that maps the static preview data to SubflowNodeView's read-only (isPreview) props — no stores or hooks. Adds the block size to the preview node data so the view can size itself, and corrects the parallel example's start-edge handle id to 'parallel-start-source' (the view derives the handle id from kind). Deletes preview-container-node.tsx. Container colors/icons are now owned by the shared view (loop=blue, parallel=yellow).

* feat(docs): render block nodes with the shared WorkflowBlockView

Replaces the forked PreviewBlockNode with a thin DocsBlockNode that maps the static preview data to WorkflowBlockView's props — store-free, builds the subblock rows (condition/router Context+routes/default + tools + error) via SubBlockRowView, strips branch-id prefixes so the view's regenerated handle ids match, remaps router->router_v2, and keeps the framer-motion dim/stagger wrapper. Promotes resolveIcon into block-icons.tsx, adds the --workflow-edge token to docs global.css, deletes preview-block-node.tsx. The canvas diagrams now render with the real editor's view.

* refactor(workflow-renderer): make editor-only WorkflowBlockView props optional

The child-deploy, schedule, and webhook badge props (and their callbacks) only matter in the editor. Mark them optional and optional-chain the three callbacks so read-only consumers (docs, academy) can omit the whole group instead of passing ~18 explicit off-values. The editor still passes them, so its behavior is byte-identical (verified: apps/sim type-check clean). DocsBlockNode drops the off-props.

* feat(docs): replace how-it-runs static diagrams with live WorkflowPreview

Swaps the four static PNGs on the how-it-runs page for live, app-styled WorkflowPreview diagrams (concurrency, combination, condition+router branching, error path). Adds the four example workflows and renders error-port edges red to match the editor. The English page only; the translated execution/basics pages keep the PNGs.

* refactor(workflow-renderer): the view owns condition/router/error rows

Both the editor container and the docs adapter hand-built the condition/router/error summary rows in an order that had to stay in lockstep with the view's absolute handle-offset math — a three-way coupling with nothing enforcing it. The view now renders those rows itself from the conditionRows/routerRows it already receives (plus a routerContextValue prop for the router's Context row), so row order and handle geometry live together in one place. Both containers pass only data and their non-branch rows.

Editor is byte-identical: getDisplayValue moves to where conditionRows/routerRows are built; the no-subBlock SubBlockRow path is already an exact SubBlockRowView(title, value) passthrough; the error row stays gated on shouldShowDefaultHandles. Verified apps/sim type-check clean. Docs now also renders the error row on condition/router blocks, which the real editor already did (shouldShowDefaultHandles is true for them) — an alignment fix.

* refactor(docs): drop the parallel --wp-* token layer for the app/emcn tokens

The workflow-preview ran a 25-token --wp-* mirror (22 were pure aliases of app tokens docs already defines) plus a .wp-scope wrapper class. Replaces every var(--wp-X) with its canonical app/emcn token (--wp-edge->--workflow-edge, --wp-highlight->--brand-secondary, badges->--badge-*, etc.), adds the one missing token (--divider), and deletes the .wp-scope blocks + class. Visually identical (aliases resolve to the same values); the preview now inherits the same design tokens as the shared views and the rest of the app instead of a hand-rolled parallel set.

* refactor(docs): adopt emcn Badge + dedup resolveIcon in workflow-preview

output-bundle's hand-rolled type badge (BADGE_COLORS + a styled span) becomes the emcn Badge (its green/blue/orange/purple/gray variants use the identical --badge-* tokens). resolveIcon, which had three copies, is now imported once from block-icons by output-bundle and block-inspector.

* refactor(docs): rebuild the preview inspector on emcn chip primitives

The lightbox inspector was a hand-rolled facsimile (raw divs + a CONTROL class string + inline dashed borders). It now composes from the same @sim/emcn primitives the live editor's sub-block controls wrap — ChipSelect/ChipInput/ChipTextarea(viewOnly)/ChipSwitch/ChipTag/FieldDivider/Label — so it reads as the real editor panel, fed example data (read-only, full opacity via readOnly/viewOnly, not greyed). Slider stays minimal (no emcn equivalent) but on app tokens. Props API and embedded/standalone modes unchanged.

* refactor(docs): render the block-reference hero through the shared View

Retires the hand-rolled BlockCard (a parallel reimplementation of WorkflowBlockView) and the BlockDisplaySpec data model. Each block hero is now a single-block PreviewWorkflow (block-display-workflows.ts) rendered through the same toReactFlowElements -> DocsBlockNode -> WorkflowBlockView pipeline as the diagrams, mounted in a minimal fitView ReactFlow (maxZoom 1.3, no canvas chrome). A single block can no longer drift from the canvas.

* fix(docs): define sim's type scale + align the preview inspector to the editor

Docs Tailwind v4 never defined sim's custom font sizes (text-small/caption/md/micro), so emcn components (Label, Badge, the shared views) fell back to inherited sizes — the inspector labels rendered huge. Adds the type scale to the docs @theme. Also aligns the inspector header to the real editor panel (surface-4 bar, size-[18px] rounded-sm icon, text-sm name) and removes the Connections section (and its now-dead prop/wiring).

* fix(docs): inspector shows the full field list + dragged positions persist

Inspector: shows the block type's full field list (from the reference data) with the example's values overlaid, so it reads like the editor panel instead of only the canvas summary rows. Drag: selecting another block no longer relayouts the canvas — node positions the viewer dragged are preserved across highlight/selection changes (only a different workflow relayouts).

* feat(docs): highlight <> references + env vars; hide Ask AI over the lightbox; respace blocks

Inspector text fields render the value with <...> block references and {{...}} environment variables highlighted in brand-secondary (a lean read-only port of the editor's formatDisplayText), in the canonical chip field chrome. The floating Ask AI widget is hidden while a preview lightbox is open. Plus the example-data respacing so the editor-faithful Error row no longer makes stacked blocks overlap.

* fix(docs): make per-type field templates match the real block registry

Audited every block type's field list (the source the inspector + block-reference heroes render) against apps/sim/blocks/blocks/*. Corrected drift to the registry's default-visible fields, titles, and order: agent gains Temperature; router gains Model; wait gains Async; schedule rewritten (default is Daily, not minutes); webhook_trigger expanded to its real default-visible set; human_in_the_loop notification title fixed. Provider-credential and advanced-mode fields stay hidden, matching the editor. Canvas diagrams keep their clean curated rows; the inspector now shows the full, real field list per the chosen clean-canvas/full-inspector split.

* improvement(docs): taller default preview height so respaced diagrams aren't shrunk

Bumps the default WorkflowPreview height 260->300 (the respaced, editor-faithful blocks are taller, so fitView was shrinking diagrams that relied on the default). The tall how-it-runs routing diagram gets 400.

* improvement(docs): zoomable inline preview + taller default + themed controls

The inline preview is now zoomable outside the lightbox: adds react-flow zoom/fit Controls (themed to the dark canvas chrome) and enables pinch-zoom, while keeping scroll-zoom off so the page still scrolls over the diagram. Pan-drag and click-block-to-inspect already worked. Default height 300->340.

* improvement(docs): click canvas to expand; click empty lightbox to deselect

Clicking the inline preview canvas opens the full lightbox; clicking empty space in the lightbox clears the selection, matching the real editor.

* improvement(docs): reveal inline zoom controls on hover only

The always-visible zoom controls felt heavy on the inline preview; they now fade in on hover (matching the expand button) and stay visible in the lightbox.

* improvement(docs): drop zoom controls on the inline preview

Inline preview keeps pinch-zoom, pan, drag, and click-to-expand; zoom buttons stay in the lightbox only.

* improvement(docs): remove zoom controls from the lightbox too

Both previews zoom via scroll/pinch and pan via drag; no on-canvas zoom buttons. Drops the Controls import and its theming CSS.

* improvement(docs): match the real canvas — flat background + editor edge geometry

Closes the last faithfulness gaps the audit found: removes the dot grid (the real editor hides its background — flat bg), aligns PreviewEdge to the editor's smoothstep math (borderRadius 8, offset 30) and 2px stroke (default + error edges), the selection ring to 1.75px, and minZoom to 0.1. Structural parity (blocks/handles/containers/colors/tokens) was already shared. Kept PreviewEdge rather than swapping to WorkflowEdgeView, which would clobber the docs-only highlight/dim/animate for no visual gain.

* improvement(docs): rebrand the docs assistant as 'Ask Sim', styled like the real chat input

Renames the floating assistant from 'Ask AI' to 'Ask Sim' (matching the platform's voice — you talk to Sim) and restyles the composer to mirror the home chat input: a rounded-2xl bordered field with the toolbar inside, and the same 28px circular send/stop button (the home's exact active/disabled colors + white/black arrow). Updates the lightbox hide-selector to the new label.

* improvement(docs): match Ask Sim message styling to the mothership chat

Aligns the user bubble (rounded-[16px] surface-5, text-base/primary, leading-23, max-w-85%) and the assistant markdown (text-base, 600 headings/strong, text-primary dashed-underline links, surface-5 code blocks) to the real mothership chat's user-message + chat-content treatment, instead of the prior generic text-sm rendering. The composer already mirrors the home user-input (rounded-2xl field + 28px circular send button).

* improvement(docs): compact single-row Ask Sim composer

The two-row layout left a tall dead gap (the docs widget has no toolbar buttons to fill the second row). The composer is now a single row — textarea with the circular send button inline — so it sits at the natural input height.

* fix(docs): pass the router Context value to the shared view

DocsBlockNode never set routerContextValue, so the view (which renders the router's Context row from that prop, not from rows) showed a blank Context even when the preview data authored a value like <start.input>. Extract it from the block's Context row and pass it through.

* fix(docs): don't apply a block-type field template that doesn't match the block

inspectorFieldsFor keyed the full field template purely off block.type, but some types are reused across roles (a table action block vs the table trigger, a webhook trigger vs the webhook action), so the wrong template was applied. Only use the template when the block's authored rows are actually a subset of it; otherwise fall back to the block's own rows.

* fix(docs): connect preview edges to subflow container handles

toReactFlowElements hardcoded targetHandle to 'target' and defaulted source handles to 'source', but Loop/Parallel containers (SubflowNodeView) expose a 'loop-end-source'/'parallel-end-source' output handle and a left input handle with no id. Edges into and out of containers therefore failed to connect. Resolve each edge end to the block's real handle based on whether it's a container.

* fix(docs): don't expand the inspector template for blocks with no rows

block.rows.every(...) is vacuously true for an empty rows array, so a block defined only by branches (e.g. a router in ROUTING_WORKFLOW) inherited the type template's invented field defaults. Require non-empty authored rows before applying the template.

* fix(docs): render blank branch/router-context values as '-' like the editor

The editor maps condition/router branch values and the router Context through getDisplayValue, which renders '-' for a blank value. DocsBlockNode mapped them to an empty string, so else branches and unset routes looked blank instead of matching the editor. Mirror getDisplayValue's empty-value handling.

* fix(docs): show '-' for blank inspector branch values, matching the canvas

inspectorFieldsFor passed raw branch.value into the lightbox branch fields, so an unset else route read blank in the inspector while DocsBlockNode (and the editor's getDisplayValue) render '-' on the canvas. Normalize the same way; drop the now-redundant placeholder.
)

* improvement(settings): persistent layout + locked-down header API

Mirror the Resource compound component's locked invariant for settings.

- Move ALL page chrome (header bar, title/description, scroll region, centered
  max-w-[48rem] column, spacing) into the Next.js settings/[section]/layout.tsx
  via SettingsHeaderShell, so it persists across section navigation and never
  re-renders / re-lays-out. SettingsPanel becomes a thin registrar that feeds the
  shell its header data via a React context slot.
- Lock the header API: actions is now SettingsAction[] (data only:
  text/icon/variant/active/onSelect/disabled, rendered as Chips) — no JSX, no
  <div>, no className, so a padding change is structurally impossible. Add a left
  'back' slot for detail sub-views + an 'aside' escape hatch for the rare non-chip
  widget.
- SaveDiscardActions component -> saveDiscardActions() helper returning the
  dirty-gated SettingsAction[].
- Migrate every panel page + the 5 in-section detail views (access-control
  group-detail, data-retention PolicyDetail, mcp, credential-sets, workflow-mcp)
  onto the layout/back-slot; they no longer hand-roll their own shells.
- Chip labels are sentence case (Add override, Create server, ...); the action gap
  is owned once by the shell; no action <div>s.

Documents the new contract in the settings rule + add-settings-page skill.

* refactor(settings): cleanup pass — deref handlers, tooltip data field, parity fixes

Address /cleanup + /simplify + per-page parity audit findings:

- Foundation: shell dereferences action/back/search handlers from the config ref
  at call time, so a section re-render that changes a closure (e.g. a dirty-form
  onSave) can never leave the shell holding a stale handler.
- Add SettingsAction.tooltip (shell renders the hover tooltip, incl. for disabled
  actions). Migrate the secrets-manager + workflow-mcp 'aside' tooltips to data
  actions — eliminates the per-page <div>-wrapped tooltip chips (Emir's no-div).
- Parity: detail-view description no longer falls back to the section meta blurb
  (empty-description groups render blank again); secrets Save keeps no variant.
- Sentence-case: group-detail back 'Access control'; empty-state prose
  'Create API key' / 'Add tool' / 'Add server'.
- Drop redundant array-level 'satisfies SettingsAction[]'; make SettingsPanel
  children optional (loading detail states drop the {null}).

* docs(settings): document SettingsAction.tooltip in the settings rule

* fix(settings): add key to header action chip (biome useJsxKeyInIterable)

* fix(settings): address review — remove aside footgun, sticky tabs, restore tooltips

- Remove the SettingsHeaderConfig 'aside' escape hatch (the last stale-prone,
  div-admitting path). Add SettingsAction.onPrefetch so the teammates Invite chip
  (hover-prefetch) is pure data — nothing renders header JSX now, so the
  signature-vs-ref staleness cursor flagged is gone.
- useIsomorphicLayoutEffect for header registration: section switches flush the
  new header before paint (no stale/blank header frame).
- group-detail: pin the config tabs (sticky top-0) so they stay visible while the
  detail body scrolls.
- Restore the team-management Invite disabled-reason tooltip via the new
  SettingsAction.tooltip field.

* refactor(settings): final audit pass — parity, sentence-case, import consistency

From a line-by-line audit (+ React-docs validation of the click-time ref deref and
isomorphic layout-effect patterns):
- workflow-mcp detail: restore origin action order (Edit server, then the primary
  Add workflows) so the primary CTA stays rightmost.
- Sentence-case the detail back-chip labels to match nav ('MCP tools', 'MCP
  servers'); fix the workflow-mcp list empty-state copy ('Add server').
- data-retention: import ArrowLeft from '@sim/emcn/icons' (canonical back-chip icon
  source, matching the other detail views); group-detail: import SettingsPanel from
  the package index, not the deep file path.
- Document that scrollContainerRef is intentionally excluded from the header
  signature (refs are identity-stable).
…ctivity payloads (#5279)

The native Slack trigger flattened every interaction into scalar event.* fields
and dropped the structured objects, so view_submission and block-rewrite
workflows could not read view.state.values, view.private_metadata, or
message.blocks. Pass the full Slack view and message objects through, plus the
top-level block_actions state (state.values), and declare them in the trigger
outputs so they surface in the editor. Additive and backwards compatible:
existing flattened fields are unchanged and new fields default to null.
…king feature flag (#5280)

* feat(workspaces): gate workspace forking behind runtime workspace-forking feature flag

* fix(workspaces): scope workspace-forking flag to AppConfig deployments to preserve self-hosted gate
@waleedlatif1 waleedlatif1 requested a review from a team as a code owner June 30, 2026 05:47
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Jun 30, 2026 5:47am

Request Review

@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Too many files changed for review. (1128 files found, 100 file limit)

@cursor

cursor Bot commented Jun 30, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Docs and import-path migration touch shared UI packages and workflow rendering; regressions would be visual or docs-only, not core app auth/data paths.

Overview
This release moves the design system into @sim/emcn and updates contributor/docs rules so apps import components, cn, and tokens from that barrel (icons from @sim/emcn/icons) instead of @/components/emcn or @/lib/core/utils/cn.

Docs drops duplicated chip/dropdown UI and wires navbar, Ask Sim, inspectors, and badges through shared emcn chrome. global.css adds Tailwind sources for packages/emcn and packages/workflow-renderer, expands Sim tokens, and removes the old --wp-* preview scope.

Workflow documentation previews now render via @sim/workflow-renderer (DocsBlockNode / DocsContainerNode, ReactFlow) with block heroes driven by block-display-workflows.ts instead of hand-rolled cards; example workflows lose manual handle flags and gain how-it-runs diagrams. The block inspector uses real chip controls and app CSS variables.

README is redesigned (hero/tour GIFs, condensed quickstart). Settings authoring rules document layout-owned chrome, data-only SettingsAction[], and saveDiscardActions(). German A2A tool doc page is removed.

Reviewed by Cursor Bugbot for commit 7bf8dba. Configure here.

@waleedlatif1 waleedlatif1 merged commit 0371856 into main Jun 30, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants