Skip to content

Commit a88a4ee

Browse files
chore(slack): sync with staging
2 parents 3094f01 + fd061f5 commit a88a4ee

271 files changed

Lines changed: 11467 additions & 5917 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/rules/sim-architecture.md‎

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,25 @@ Every export of a `'use client'` module becomes a *client reference* on the serv
6262
Server code runs in two runtimes with **different environments**. The app container loads the
6363
full env from `SIM_ENV_SECRET_ID` (Secrets Manager). Trigger.dev workers — which execute
6464
workflows, so every block handler and every tool call — get their env from the Trigger.dev
65-
dashboard, and `trigger.config.ts` syncs only `DB_APP_NAME`. The repo cannot see what the
66-
dashboard holds.
65+
dashboard; `trigger.config.ts` additionally syncs `DB_APP_NAME`, `TRIGGER_DEV_ENABLED`, and the
66+
`FUNCTION_EXECUTION_ENV` vars. The repo cannot see what the dashboard holds.
6767

6868
So before replacing a worker's HTTP call to our own API with an in-process call, ask what env
6969
that work reads *on the app side*. Anything gated by a `require*Capability` helper is the sharp
7070
case: those **throw** when the variable is absent (`requireOAuthClientCapability` →
7171
`EnvCapabilityConfigurationError`), and the throw may be caught and reported as something
72-
unrelated. OAuth token refresh is the known example — moving it into the worker turns every
73-
expired credential into `Failed to refresh access token`, while a still-valid token hides the
74-
bug entirely, so it surfaces hours later and only for whoever's token lapsed first.
72+
unrelated — an in-worker OAuth refresh missing a provider's client pair reports every expired
73+
credential as `Failed to refresh access token`, while a still-valid token hides the bug until it
74+
lapses. The required step before such a conversion is verifying the dashboard env holds every
75+
variable the moved code reads (for OAuth refresh: the `OAUTH_CLIENT_CAPABILITIES` key pairs in
76+
`packages/deployment-config/src/env-capabilities.ts`).
7577

7678
An in-process conversion is safe when the same work already runs in that runtime (the agent
7779
block has always called `executeProviderRequest` in-process, so router and evaluator joining it
78-
is proven), or when the caller and the callee are both the app (a route calling a lib module, an
79-
RSC prefetch reading the data layer). It is not safe on reasoning alone.
80+
is proven; connector sync refreshing OAuth tokens in-worker is what proved credential-token
81+
resolution could move in-process), or when the caller and the callee are both the app (a route
82+
calling a lib module, an RSC prefetch reading the data layer). It is not safe on reasoning
83+
alone — verify the env, then convert.
8084

8185
## Feature Organization
8286

‎NOTICE‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
Sim Studio
22
Copyright 2026 Sim Studio
33

4-
This product includes software developed for the Sim project.
4+
This product includes software developed for the Sim project.

‎apps/desktop/package.json‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,10 @@
5050
"@sim/tsconfig": "workspace:*",
5151
"@types/micromatch": "4.0.10",
5252
"@types/node": "24.2.1",
53-
"electron": "43.5.0",
53+
"electron": "43.4.1",
5454
"electron-builder": "26.15.3",
5555
"esbuild": "0.28.1",
56+
"jsdom": "^26.0.0",
5657
"typescript": "^7.0.2",
5758
"vitest": "^4.1.0"
5859
}

‎apps/docs/app/global.css‎

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,9 @@ body {
5454
nominally references; loading a webfont here would make docs the odd one out, not the
5555
aligned one. If the app ever wires that font up for real, add the var back in both
5656
places at once. */
57-
--font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
58-
"Courier New", monospace;
57+
--font-mono:
58+
ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New",
59+
monospace;
5960
}
6061

6162
/* Pure white light mode background */
@@ -243,14 +244,16 @@ body {
243244

244245
/* Font family utilities */
245246
.font-sans {
246-
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
247-
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
247+
font-family:
248+
var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
249+
Roboto, "Helvetica Neue", Arial, sans-serif;
248250
}
249251

250252
/* Platform UI font — Season Sans, used by the chip chrome to match the main app */
251253
.font-season {
252-
font-family: var(--font-season), system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial,
253-
"Noto Sans", sans-serif;
254+
font-family:
255+
var(--font-season), system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans",
256+
sans-serif;
254257
}
255258

256259
:root {
@@ -445,8 +448,9 @@ html #nd-sidebar button:not([aria-label*="ollapse"]):not([aria-label*="xpand"])
445448
padding: 5px 0.5rem !important; /* 30px tall overall — the app's chip pill, at its px-2 */
446449
font-weight: 400 !important;
447450
border-radius: 0.5rem !important; /* platform rounded-lg */
448-
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
449-
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif !important;
451+
font-family:
452+
var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
453+
Roboto, "Helvetica Neue", Arial, sans-serif !important;
450454
}
451455

452456
/* Sidebar text — platform --text-body */
@@ -904,8 +908,9 @@ video {
904908
#nd-page:has(.api-page-header) div:not(.font-mono),
905909
#nd-page:has(.api-page-header) label:not(.font-mono),
906910
#nd-page:has(.api-page-header) button:not(.font-mono) {
907-
font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
908-
"Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
911+
font-family:
912+
var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
913+
Roboto, "Helvetica Neue", Arial, sans-serif;
909914
}
910915

911916
/* Method badge pills — shared background colors (page + sidebar) */

‎apps/docs/components/icons.tsx‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5895,12 +5895,11 @@ export function PipedriveIcon(props: SVGProps<SVGSVGElement>) {
58955895

58965896
export function SailPointIcon(props: SVGProps<SVGSVGElement>) {
58975897
return (
5898-
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none'>
5899-
<path
5900-
fill='currentColor'
5901-
d='M7.25 2.4c5.66 1.7 9.2 6.86 9.9 15.35a.75.75 0 0 1-.75.81H7.25a.75.75 0 0 1-.75-.75V3.12a.75.75 0 0 1 .95-.72Z'
5902-
/>
5903-
<rect fill='currentColor' x='3' y='19.9' width='18' height='1.8' rx='.9' />
5898+
<svg {...props} xmlns='http://www.w3.org/2000/svg' viewBox='0 0 109.5 107'>
5899+
<path fill='#0033A1' d='M63,0l13.2,78.6H0L63,0z' />
5900+
<path fill='#CC27B0' d='M62.9,0l46.7,78.6H76L62.9,0z' />
5901+
<path fill='#0071CE' d='M0,78.6h76.2l4.8,28.4L0,78.6z' />
5902+
<path fill='#E17FD2' d='M76,78.6h33.5L80.8,107L76,78.6z' />
59045903
</svg>
59055904
)
59065905
}

‎apps/docs/components/workflow-preview/block-preview.tsx‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
'use client'
22

33
import { useMemo } from 'react'
4+
import { type NodeTypes, ReactFlow, ReactFlowProvider } from '@xyflow/react'
45
import { domAnimation, LazyMotion } from 'framer-motion'
5-
import ReactFlow, { type NodeTypes, ReactFlowProvider } from 'reactflow'
6-
import 'reactflow/dist/style.css'
6+
import '@xyflow/react/dist/style.css'
77
import { BLOCK_DISPLAY_WORKFLOWS } from '@/components/workflow-preview/block-display-workflows'
88
import { DocsBlockNode } from '@/components/workflow-preview/docs-block-node'
99
import { toReactFlowElements } from '@/components/workflow-preview/workflow-data'
1010

1111
/** The hero mounts the same node type the canvas uses, so it can never drift. */
12-
const NODE_TYPES: NodeTypes = { previewBlock: DocsBlockNode }
12+
const NODE_TYPES = { previewBlock: DocsBlockNode } satisfies NodeTypes
1313
const PRO_OPTIONS = { hideAttribution: true }
1414
/** `maxZoom` mirrors the previous hand-rolled hero's 1.3 scale. */
1515
const FIT_VIEW_OPTIONS = { padding: 0.2, maxZoom: 1.3 } as const

‎apps/docs/components/workflow-preview/docs-block-node.tsx‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
import { type ComponentType, memo } from 'react'
44
import { SubBlockRowView, WorkflowBlockView } from '@sim/workflow-renderer'
5+
import type { Node, NodeProps } from '@xyflow/react'
56
import { m } from 'framer-motion'
6-
import type { NodeProps } from 'reactflow'
77
import { resolveIcon } from '@/components/workflow-preview/block-icons'
88
import {
99
BLOCK_STAGGER,
@@ -16,7 +16,7 @@ const EMPTY_ICON: ComponentType<{ className?: string }> = () => null
1616

1717
const RING_STYLES = 'ring-[1.75px] ring-[var(--brand-secondary)]'
1818

19-
interface DocsBlockData {
19+
export interface DocsBlockData extends Record<string, unknown> {
2020
name: string
2121
blockType: string
2222
bgColor: string
@@ -30,6 +30,8 @@ interface DocsBlockData {
3030
isDimmed?: boolean
3131
}
3232

33+
export type DocsBlockNodeType = Node<DocsBlockData, 'previewBlock'>
34+
3335
/**
3436
* Docs adapter for workflow block nodes: maps the static preview data to the
3537
* shared {@link WorkflowBlockView}'s props. Carries no stores, hooks, or
@@ -38,7 +40,10 @@ interface DocsBlockData {
3840
* `WorkflowPreview` provides the `LazyMotion` feature set). The block's ring is
3941
* driven by `hasRing`/`ringStyles` inside the View.
4042
*/
41-
export const DocsBlockNode = memo(function DocsBlockNode({ id, data }: NodeProps<DocsBlockData>) {
43+
export const DocsBlockNode = memo(function DocsBlockNode({
44+
id,
45+
data,
46+
}: NodeProps<DocsBlockNodeType>) {
4247
const {
4348
name,
4449
blockType,

‎apps/docs/components/workflow-preview/docs-container-node.tsx‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22

33
import { memo } from 'react'
44
import { type SubflowNodeData, SubflowNodeView } from '@sim/workflow-renderer'
5-
import type { NodeProps } from 'reactflow'
5+
import type { Node, NodeProps } from '@xyflow/react'
66

7-
interface DocsContainerData {
7+
export interface DocsContainerData extends Record<string, unknown> {
88
name: string
99
blockType: string
1010
size?: { width: number; height: number }
1111
parentId?: string
1212
}
1313

14+
export type DocsContainerNodeType = Node<DocsContainerData, 'previewContainer'>
15+
1416
/**
1517
* Docs adapter for loop/parallel container blocks: maps the static preview data
1618
* to {@link SubflowNodeView}'s read-only `isPreview` shape. Carries no stores,
@@ -19,7 +21,7 @@ interface DocsContainerData {
1921
export const DocsContainerNode = memo(function DocsContainerNode({
2022
id,
2123
data,
22-
}: NodeProps<DocsContainerData>) {
24+
}: NodeProps<DocsContainerNodeType>) {
2325
const subflowData: SubflowNodeData = {
2426
kind: data.blockType === 'parallel' ? 'parallel' : 'loop',
2527
name: data.name,

‎apps/docs/components/workflow-preview/workflow-data.ts‎

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,15 @@ import {
44
getEdgeZIndex,
55
getEdgeZIndexForTarget,
66
} from '@sim/workflow-renderer'
7-
import { type Edge, type Node, Position } from 'reactflow'
7+
import { type Edge, Position } from '@xyflow/react'
8+
import type {
9+
DocsBlockData,
10+
DocsBlockNodeType,
11+
} from '@/components/workflow-preview/docs-block-node'
12+
import type {
13+
DocsContainerData,
14+
DocsContainerNodeType,
15+
} from '@/components/workflow-preview/docs-container-node'
816

917
/**
1018
* Tool entry displayed as a chip on a block (e.g. an Agent's attached tools).
@@ -51,6 +59,15 @@ export interface PreviewWorkflow {
5159
edges: Array<{ id: string; source: string; target: string; sourceHandle?: string }>
5260
}
5361

62+
export type PreviewNode = DocsBlockNodeType | DocsContainerNodeType
63+
64+
export interface PreviewEdgeData extends Record<string, unknown> {
65+
animate: boolean
66+
delay: number
67+
}
68+
69+
export type PreviewFlowEdge = Edge<PreviewEdgeData, 'previewEdge'>
70+
5471
export const BLOCK_STAGGER = 0.12
5572
export const EASE_OUT: [number, number, number, number] = [0.16, 1, 0.3, 1]
5673

@@ -96,14 +113,14 @@ export function toReactFlowElements(
96113
workflow: PreviewWorkflow,
97114
animate = false,
98115
highlight: HighlightOptions = {}
99-
): { nodes: Node[]; edges: Edge[] } {
116+
): { nodes: PreviewNode[]; edges: PreviewFlowEdge[] } {
100117
const { highlightBlock, highlightEdge, selectedBlock } = highlight
101118
const hasHighlight = Boolean(highlightBlock || highlightEdge)
102119
const blockIndexMap = new Map(workflow.blocks.map((b, i) => [b.id, i]))
103120

104121
const blocksById = new Map(workflow.blocks.map((b) => [b.id, b]))
105122

106-
const nodes: Node[] = workflow.blocks.map((block, index) => {
123+
const nodes: PreviewNode[] = workflow.blocks.map((block, index) => {
107124
const isContainer = Boolean(block.size)
108125
const nestingDepth = getNestingDepth(block, blocksById)
109126
// Nested blocks are authored relative to their container; render them at
@@ -113,13 +130,20 @@ export function toReactFlowElements(
113130
const position = parent
114131
? { x: parent.position.x + block.position.x, y: parent.position.y + block.position.y }
115132
: block.position
116-
return {
133+
const commonNode = {
117134
id: block.id,
118-
type: isContainer ? 'previewContainer' : 'previewBlock',
119135
position,
120136
zIndex: isContainer ? nestingDepth : block.parentId ? CONTAINER_CHILD_Z_BASE : BLOCK_Z_BASE,
121137
...(block.size ? { style: { width: block.size.width, height: block.size.height } } : {}),
122-
data: {
138+
draggable: true,
139+
selectable: false,
140+
connectable: false,
141+
sourcePosition: Position.Right,
142+
targetPosition: Position.Left,
143+
}
144+
145+
if (isContainer) {
146+
const data: DocsContainerData = {
123147
name: block.name,
124148
blockType: block.type,
125149
bgColor: block.bgColor,
@@ -133,16 +157,37 @@ export function toReactFlowElements(
133157
animate,
134158
isHighlighted: highlightBlock === block.id || selectedBlock === block.id,
135159
isDimmed: hasHighlight && highlightBlock !== block.id,
136-
},
137-
draggable: true,
138-
selectable: false,
139-
connectable: false,
140-
sourcePosition: Position.Right,
141-
targetPosition: Position.Left,
160+
}
161+
return {
162+
...commonNode,
163+
type: 'previewContainer',
164+
data,
165+
}
166+
}
167+
168+
const data: DocsBlockData = {
169+
name: block.name,
170+
blockType: block.type,
171+
bgColor: block.bgColor,
172+
rows: block.rows,
173+
branches: block.branches,
174+
tools: block.tools,
175+
hideTargetHandle: block.hideTargetHandle,
176+
size: block.size,
177+
parentId: block.parentId,
178+
index,
179+
animate,
180+
isHighlighted: highlightBlock === block.id || selectedBlock === block.id,
181+
isDimmed: hasHighlight && highlightBlock !== block.id,
182+
}
183+
return {
184+
...commonNode,
185+
type: 'previewBlock',
186+
data,
142187
}
143188
})
144189

145-
const edges: Edge[] = workflow.edges.map((e) => {
190+
const edges: PreviewFlowEdge[] = workflow.edges.map((e) => {
146191
const sourceIndex = blockIndexMap.get(e.source) ?? 0
147192
const isEdgeHighlight = highlightEdge === e.id
148193
const dimmed = hasHighlight && !isEdgeHighlight

0 commit comments

Comments
 (0)