Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5a81341
feat(workspaces): fork + push/pull (#5210)
icecrasher321 Jun 28, 2026
66315f1
improvement(docs): flatten the academy learn/chapters panels (#5253)
waleedlatif1 Jun 28, 2026
c596316
chore(deploy): remove deploy as a2a (#5255)
icecrasher321 Jun 29, 2026
d878f15
feat(integrations): extend Airtable, Google Docs, WhatsApp, and Excel…
waleedlatif1 Jun 29, 2026
bcf6a80
improvement(emcn): extract design system into shared @sim/emcn packag…
waleedlatif1 Jun 29, 2026
f5f87de
fix(emcn): repair app-wide crash and unstyled UI after package extrac…
waleedlatif1 Jun 29, 2026
6dea1dc
fix(knowledge): send tag filters as a JSON string so the document fil…
waleedlatif1 Jun 29, 2026
f5116f4
fix(emcn): resolve Calendar icon/component barrel collision and prese…
waleedlatif1 Jun 29, 2026
56f9393
fix(prism): load prismjs core before language components (#5262)
waleedlatif1 Jun 29, 2026
23ec96b
feat(pii): add redaction timing metrics across sidecar and persist pa…
TheodoreSpeaks Jun 29, 2026
27b2a4f
feat(workflow-renderer): extract edge, subflow, and note Views into @…
waleedlatif1 Jun 29, 2026
a6196e0
perf(dev): curate SIM_DEV_MINIMAL_REGISTRY to core toolbar blocks (#5…
TheodoreSpeaks Jun 29, 2026
950c260
fix(uploads): attach compiled binary for AI-generated docs, not sourc…
waleedlatif1 Jun 29, 2026
69e3550
feat(integrations): extend Telegram, Outlook, and Notion tool depth (…
waleedlatif1 Jun 29, 2026
c7bb37d
feat(workflow-renderer): extract pure WorkflowBlockView + SubBlockRow…
waleedlatif1 Jun 29, 2026
48c1b45
feat(integrations): extend ElevenLabs, Google Drive, Firecrawl, Pinec…
waleedlatif1 Jun 29, 2026
8925334
feat(mothership): add secrets input in chat (#5274)
Sg312 Jun 30, 2026
f66d0c7
improvement(docs): redesign README (animated hero + product demo) (#5…
andresdjasso Jun 30, 2026
7545391
feat(docs): render workflow previews with the shared editor renderer …
waleedlatif1 Jun 30, 2026
948a5cb
improvement(settings): persistent layout + locked-down header API (#5…
waleedlatif1 Jun 30, 2026
98d84f2
improvement(slack-trigger): expose view, message, and state on intera…
waleedlatif1 Jun 30, 2026
7bf8dba
feat(workspaces): gate workspace forking behind runtime workspace-for…
waleedlatif1 Jun 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 2 additions & 2 deletions .claude/rules/emcn-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ paths:

# EMCN Components

Import from `@/components/emcn`, never from subpaths (except CSS files). The **chip family** is the platform's primary chrome — always reach for it over the legacy primitives it is progressively replacing (`Input`→`ChipInput`, `Textarea`→`ChipTextarea`, `Modal`→`ChipModal`, `Select`/`Combobox`→`ChipSelect`/`ChipCombobox`/`ChipDropdown`, `Switch`→`ChipSwitch`, date field→`ChipDatePicker`). For context/action menus the canonical control is `DropdownMenu` — the standard menu (not a chip, and never a hand-rolled popover).
Import components, `cn`, and tokens from the `@sim/emcn` barrel; icons come from the `@sim/emcn/icons` subpath, and CSS modules from their file path. Never deep-import other component subpaths. The **chip family** is the platform's primary chrome — always reach for it over the legacy primitives it is progressively replacing (`Input`→`ChipInput`, `Textarea`→`ChipTextarea`, `Modal`→`ChipModal`, `Select`/`Combobox`→`ChipSelect`/`ChipCombobox`/`ChipDropdown`, `Switch`→`ChipSwitch`, date field→`ChipDatePicker`). For context/action menus the canonical control is `DropdownMenu` — the standard menu (not a chip, and never a hand-rolled popover).

## Chip chrome — single source of truth

Never hand-roll the chip pill from raw class strings (they go stale). Compose from the canonical sources:

- **Surface, typography + content tokens:** `chip/chip-chrome.ts` — `chipFilledSurfaceTokens`, `chipFieldSurfaceClass`, `chipFieldTextClass` (text fields and the dropdown search box build on these), plus the chip-content chrome `chipContentGap`, `chipGeometryClass`, `chipContentIconClass`, `chipContentLabelClass`, and `cellIconNodeClass` (non-chip surfaces that must visually match chip content, e.g. resource table cells). All are re-exported from the `@/components/emcn` barrel — no subpath import needed.
- **Surface, typography + content tokens:** `chip/chip-chrome.ts` — `chipFilledSurfaceTokens`, `chipFieldSurfaceClass`, `chipFieldTextClass` (text fields and the dropdown search box build on these), plus the chip-content chrome `chipContentGap`, `chipGeometryClass`, `chipContentIconClass`, `chipContentLabelClass`, and `cellIconNodeClass` (non-chip surfaces that must visually match chip content, e.g. resource table cells). All are re-exported from the `@sim/emcn` barrel — no subpath import needed.
- **Pill geometry:** `chip/chip.tsx` — `chipVariants` (30px tall, `rounded-lg`, `px-2`, icon↔text `gap-1.5`). Every pill-shaped trigger (`ChipDropdown`, `ChipSelect`, `ChipSwitch`) reuses it for visual parity.

Canonical look: normal font-weight (never `font-medium`/`font-semibold`), value text `--text-body`, icons `--text-icon` at `size-[14px]`, placeholder `--text-muted`, `transition-colors`, **no focus ring** (the caret marks focus). Filled surface is `--surface-5` light / `--surface-4` dark with a `--border-1` border.
Expand Down
2 changes: 1 addition & 1 deletion .claude/rules/sim-imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import { CORE_TRIGGER_TYPES } from '@/app/workspace/.../utils'

1. React/core libraries
2. External libraries
3. UI components (`@/components/emcn`, `@/components/ui`)
3. UI components (`@sim/emcn`, `@/components/ui`)
4. Utilities (`@/lib/...`)
5. Stores (`@/stores/...`)
6. Feature imports
Expand Down
74 changes: 44 additions & 30 deletions .claude/rules/sim-settings-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,18 @@ paths:

# Settings Pages

Every settings page renders through the shared **`SettingsPanel`** primitive
(`@/app/workspace/[workspaceId]/settings/components/settings-panel`). It owns the
page chrome so pages never hand-roll it: a fixed header bar (right-aligned
actions), a scroll region, and a centered `max-w-[48rem]` content column led by a
**title + description that come from navigation metadata**. Pages render only
their body.

Do NOT hand-roll any of these in a settings page — they are the panel's job:
The Next.js `settings/[section]/layout.tsx` owns all settings page chrome via
`SettingsHeaderShell` — a fixed header bar (a left back chip + right-aligned
action chips), a scroll region, and a centered `max-w-[48rem]` content column led
by a **title + description from navigation metadata**. The chrome stays mounted
across section navigation (it never re-renders or re-lays-out). Each section
renders through the **`SettingsPanel`** registrar
(`@/app/workspace/[workspaceId]/settings/components/settings-panel`), which feeds
the shell its header data and renders only the section body. Sections supply
**data**, never chrome.

Do NOT hand-roll any of these in a settings page — they are owned by the layout
shell (fed through `SettingsPanel`):

- `<div className='flex h-full flex-col bg-[var(--bg)]'>` shell
- the header bar (`flex flex-shrink-0 … px-[16px] pt-[8.5px] pb-[8.5px]`)
Expand All @@ -29,11 +33,7 @@ import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components

return (
<SettingsPanel
actions={
<Chip leftIcon={Plus} variant='primary' onClick={onCreate}>
Create
</Chip>
}
actions={[{ text: 'Create', icon: Plus, variant: 'primary', onSelect: onCreate }]}
search={{ value: searchTerm, onChange: setSearchTerm, placeholder: 'Search …' }}
>
{/* body only — sections, lists, forms */}
Expand All @@ -54,9 +54,22 @@ return (

## `SettingsPanel` props

- `actions?: ReactNode` — right-aligned header chips. Wrap multiple in a fragment;
the slot reserves the 30px chip height even when empty, so vertical rhythm is
identical across pages. Conditional actions are fine: `actions={canManage && <Chip…/>}`.
- `actions?: SettingsAction[]` — right-aligned header chips, **data only**:
`{ text, icon?, variant?: 'primary'|'destructive', active?, onSelect, disabled?, tooltip? }`.
The shell renders each as a `Chip` — never pass JSX, a `<div>`, or `className`
(the locked contract: it's structurally impossible to vibe-code a padding
change). Multiple/conditional actions are a plain array
(`[...(canManage ? [{…}] : []), …]`). Labels are **sentence case** (`Add override`,
not `Add Override`). A disabled action that needs to explain itself sets
`tooltip` (the shell renders the hover tooltip, disabled chip included) — never
hand-roll a tooltip-wrapped chip in `aside`. Save/Discard pairs come from the
`saveDiscardActions()` helper (spread it into `actions`). Only a widget that
genuinely cannot be a chip (e.g. one needing hover-prefetch) goes in `aside`.
- `back?: SettingsBackAction` (`{ text, icon?, onSelect }`) — left-aligned back
chip for a **detail sub-view** (e.g. a selected MCP server, a permission group,
a retention policy). Detail sub-views render through `SettingsPanel` like list
pages — they do NOT hand-roll their own shell.
- `aside?: ReactNode` — escape hatch for the rare non-chip header widget. Keep it rare.
- `search?: { value; onChange: (value: string) => void; placeholder?; disabled? }` —
renders the canonical search field directly below the title. Pass `setSearchTerm`
straight to `onChange`. Use this for a standalone search; if search shares a row
Expand All @@ -66,8 +79,6 @@ return (
detail sub-view that needs a different heading; normal pages never pass these.
- `scrollContainerRef?: React.Ref<HTMLDivElement>` — forwards a ref to the scroll
region (e.g. programmatic scroll-to-bottom).
- `contentClassName?` — layout/spacing only; reach for it rarely. Prefer the
default `gap-7`.

## Title + description live in navigation metadata

Expand Down Expand Up @@ -107,12 +118,11 @@ Any settings surface with editable state uses **one** shared stack — never
hand-roll a Save button, a Discard button, a `beforeunload`, or an "Unsaved
changes" modal:

- **`SaveDiscardActions`** (`…/components/save-discard-actions/save-discard-actions`)
— the canonical dirty-gated **Discard + Save** chip pair. Renders nothing when
`!dirty`; otherwise a fragment so it composes beside sibling chips (a detail
view's Delete / Remove override, a Share chip). Props: `dirty`, `saving`,
`onSave`, `onDiscard`, `saveDisabled?`, `saveLabel?`, `savingLabel?`. Put it in
the `SettingsPanel actions` slot (top-level pages) or the detail header bar.
- **`saveDiscardActions(config)`** (`…/components/save-discard-actions/save-discard-actions`)
— returns the canonical dirty-gated **Discard + Save** `SettingsAction[]` (empty
when not dirty). Spread it into a `SettingsPanel` `actions` array, beside any
sibling actions (a detail view's Delete / Remove override). Config: `dirty`,
`saving`, `onSave`, `onDiscard`, `saveDisabled?`, `saveLabel?`, `savingLabel?`.
- **`useSettingsUnsavedGuard({ isDirty })`** (`…/settings/hooks/use-settings-unsaved-guard`)
— syncs the page's local `isDirty` into the shared `useSettingsDirtyStore` (so
the sidebar's **section-switch** confirm + the centralized `beforeunload` both
Expand Down Expand Up @@ -141,14 +151,18 @@ changes" modal:
guards real `router.push` navigation + browser Back via a history sentinel);
it already shares `UnsavedChangesModal`, so copy stays unified.

## Detail sub-views (the one exception)
## Detail sub-views

A drill-down view reached from a list row (selected MCP server, workflow MCP
server, credential set, permission group) keeps its **own** chrome because it
needs a left-aligned back button (`<Chip leftIcon={ArrowLeft}>`), which the panel
header (right-actions only) does not model. Leave those returns as hand-rolled
shells; only the list/main view uses `SettingsPanel`. Gate/early-return states
(not-entitled, loading, upgrade prompts) also stay as-is.
server, credential set, permission group, retention policy) renders through
`SettingsPanel` like a list page: pass `back={{ text, icon: ArrowLeft, onSelect }}`
for the left back chip, `title` (the entity name), and the header `actions`, then
render the body. Do NOT hand-roll a shell or header bar; a tab bar renders as the
first body child. Gate/early-return states (not-entitled, loading, upgrade
prompts) stay as-is.

The route-based credential detail (`settings/secrets/[credentialId]`) is the lone
exception — it lives outside `[section]` and keeps its own `CredentialDetailLayout`.

## Audit checklist

Expand Down
4 changes: 2 additions & 2 deletions .claude/rules/sim-styling.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ paths:
## Conditional Classes

```typescript
import { cn } from '@/lib/core/utils/cn'
import { cn } from '@sim/emcn'

<div className={cn(
'base-classes',
Expand Down Expand Up @@ -52,7 +52,7 @@ Value text `--text-body`; muted/placeholder/labels `--text-muted`; icons `--text

## Chip Components (consumer usage)

`ChipInput`, `ChipTextarea`, `ChipModal*` own their full chrome. Consumers describe intent through PROPS; they never re-style the chrome. The canonical chrome lives in `apps/sim/components/emcn/components/chip/chip-chrome.ts` (all tokens are re-exported from the `@/components/emcn` barrel — no subpath import needed) — never hand-roll `rounded-lg`/`border`/`bg-[var(--surface-5)]`/`h-[30px]`/`px-2`/`text-sm`/focus rings.
`ChipInput`, `ChipTextarea`, `ChipModal*` own their full chrome. Consumers describe intent through PROPS; they never re-style the chrome. The canonical chrome lives in `apps/sim/components/emcn/components/chip/chip-chrome.ts` (all tokens are re-exported from the `@sim/emcn` barrel — no subpath import needed) — never hand-roll `rounded-lg`/`border`/`bg-[var(--surface-5)]`/`h-[30px]`/`px-2`/`text-sm`/focus rings.

### Props over className

Expand Down
4 changes: 2 additions & 2 deletions .cursor/rules/emcn-components.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ globs: ["apps/sim/components/emcn/**"]
---
# EMCN Components

Import from `@/components/emcn`, never from subpaths (except CSS files). The **chip family** is the platform's primary chrome — always reach for it over the legacy primitives it is progressively replacing (`Input`→`ChipInput`, `Textarea`→`ChipTextarea`, `Modal`→`ChipModal`, `Select`/`Combobox`→`ChipSelect`/`ChipCombobox`/`ChipDropdown`, `Switch`→`ChipSwitch`, date field→`ChipDatePicker`). For context/action menus the canonical control is `DropdownMenu` — the standard menu (not a chip, and never a hand-rolled popover).
Import from `@sim/emcn`, never from subpaths (except CSS files). The **chip family** is the platform's primary chrome — always reach for it over the legacy primitives it is progressively replacing (`Input`→`ChipInput`, `Textarea`→`ChipTextarea`, `Modal`→`ChipModal`, `Select`/`Combobox`→`ChipSelect`/`ChipCombobox`/`ChipDropdown`, `Switch`→`ChipSwitch`, date field→`ChipDatePicker`). For context/action menus the canonical control is `DropdownMenu` — the standard menu (not a chip, and never a hand-rolled popover).

## Chip chrome — single source of truth

Never hand-roll the chip pill from raw class strings (they go stale). Compose from the canonical sources:

- **Surface, typography + content tokens:** `chip/chip-chrome.ts` — `chipFilledSurfaceTokens`, `chipFieldSurfaceClass`, `chipFieldTextClass` (text fields and the dropdown search box build on these), plus the chip-content chrome `chipContentGap`, `chipGeometryClass`, `chipContentIconClass`, `chipContentLabelClass`, and `cellIconNodeClass` (non-chip surfaces that must visually match chip content, e.g. resource table cells). All are re-exported from the `@/components/emcn` barrel — no subpath import needed.
- **Surface, typography + content tokens:** `chip/chip-chrome.ts` — `chipFilledSurfaceTokens`, `chipFieldSurfaceClass`, `chipFieldTextClass` (text fields and the dropdown search box build on these), plus the chip-content chrome `chipContentGap`, `chipGeometryClass`, `chipContentIconClass`, `chipContentLabelClass`, and `cellIconNodeClass` (non-chip surfaces that must visually match chip content, e.g. resource table cells). All are re-exported from the `@sim/emcn` barrel — no subpath import needed.
- **Pill geometry:** `chip/chip.tsx` — `chipVariants` (30px tall, `rounded-lg`, `px-2`, icon↔text `gap-1.5`). Every pill-shaped trigger (`ChipDropdown`, `ChipSelect`, `ChipSwitch`) reuses it for visual parity.

Canonical look: normal font-weight (never `font-medium`/`font-semibold`), value text `--text-body`, icons `--text-icon` at `size-[14px]`, placeholder `--text-muted`, `transition-colors`, **no focus ring** (the caret marks focus). Filled surface is `--surface-5` light / `--surface-4` dark with a `--border-1` border.
Expand Down
2 changes: 1 addition & 1 deletion .cursor/rules/sim-imports.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ import { CORE_TRIGGER_TYPES } from '@/app/workspace/.../utils'

1. React/core libraries
2. External libraries
3. UI components (`@/components/emcn`, `@/components/ui`)
3. UI components (`@sim/emcn`, `@/components/ui`)
4. Utilities (`@/lib/...`)
5. Stores (`@/stores/...`)
6. Feature imports
Expand Down
4 changes: 2 additions & 2 deletions .cursor/rules/sim-styling.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ globs: ["apps/sim/**/*.tsx", "apps/sim/**/*.css"]
## Conditional Classes

```typescript
import { cn } from '@/lib/core/utils/cn'
import { cn } from '@sim/emcn'

<div className={cn(
'base-classes',
Expand Down Expand Up @@ -50,7 +50,7 @@ Value text `--text-body`; muted/placeholder/labels `--text-muted`; icons `--text

## Chip Components (consumer usage)

`ChipInput`, `ChipTextarea`, `ChipModal*` own their full chrome. Consumers describe intent through PROPS; they never re-style the chrome. The canonical chrome lives in `apps/sim/components/emcn/components/chip/chip-chrome.ts` (all tokens are re-exported from the `@/components/emcn` barrel — no subpath import needed) — never hand-roll `rounded-lg`/`border`/`bg-[var(--surface-5)]`/`h-[30px]`/`px-2`/`text-sm`/focus rings.
`ChipInput`, `ChipTextarea`, `ChipModal*` own their full chrome. Consumers describe intent through PROPS; they never re-style the chrome. The canonical chrome lives in `apps/sim/components/emcn/components/chip/chip-chrome.ts` (all tokens are re-exported from the `@sim/emcn` barrel — no subpath import needed) — never hand-roll `rounded-lg`/`border`/`bg-[var(--surface-5)]`/`h-[30px]`/`px-2`/`text-sm`/focus rings.

### Props over className

Expand Down
6 changes: 3 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ Use barrel exports (`index.ts`) when a folder has 3+ exports. Do not re-export f

1. React/core libraries
2. External libraries
3. UI components (`@/components/emcn`, `@/components/ui`)
3. UI components (`@sim/emcn`, `@/components/ui`)
4. Utilities (`@/lib/...`)
5. Stores (`@/stores/...`)
6. Feature imports
Expand Down Expand Up @@ -375,7 +375,7 @@ Co-locate a `search-params.ts` per feature exporting the parser map (single sour

## Styling

Use Tailwind only, no inline styles. Use `cn()` from `@/lib/core/utils/cn` for conditional classes.
Use Tailwind only, no inline styles. Use `cn()` from `@sim/emcn` for conditional classes.

```typescript
<div className={cn('base-classes', isActive && 'active-classes')} />
Expand All @@ -391,7 +391,7 @@ On chip components (see "EMCN Components"), drive chrome through PROPS, not `cla

## EMCN Components

Import from `@/components/emcn`, never from subpaths (except CSS files). Use CVA only when 2+ genuine variants exist; otherwise plain `cn()`.
Import components, `cn`, and tokens from the `@sim/emcn` barrel; icons come from the `@sim/emcn/icons` subpath, and CSS modules from their file path. Never deep-import other component subpaths. Use CVA only when 2+ genuine variants exist; otherwise plain `cn()`.

The chip family is the canonical UI chrome and is progressively replacing the legacy EMCN primitives — always reach for the chip equivalent: `ChipInput` over `Input`, `ChipTextarea` over `Textarea`, `ChipModal`/`ChipModalField` over `Modal`, `ChipSelect`/`ChipCombobox` (searchable) or `ChipDropdown` (simple menu-select) over `Select`/`Combobox`, `ChipSwitch` over `Switch`, `ChipDatePicker` over a raw date field, `Chip`/`ChipLink` for pill buttons/links, `ChipTag` for inline tags/badges. For context/action menus the canonical control is `DropdownMenu` (not a chip, but the standard menu — not a hand-rolled popover). Components OWN their chrome (single source of truth) — consumers pass props, not class overrides. Authoring rules in `.claude/rules/emcn-components.md`; consumer rules in `.claude/rules/sim-styling.md`.

Expand Down
Loading
Loading