Skip to content

Commit 0a3cdcf

Browse files
committed
improvement(deps): harden dependency graph
1 parent 48f72a2 commit 0a3cdcf

184 files changed

Lines changed: 4379 additions & 1802 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.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: Dependency Governance
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- '**/package.json'
7+
- 'bun.lock'
8+
- 'bunfig.toml'
9+
- 'dependency-policy.json'
10+
- 'renovate.json'
11+
- 'scripts/check-dependency-advisories.ts'
12+
- 'scripts/check-dependency-governance.ts'
13+
- '.github/workflows/dependency-governance.yml'
14+
schedule:
15+
- cron: '23 13 * * 1'
16+
workflow_dispatch:
17+
18+
permissions:
19+
contents: read
20+
21+
jobs:
22+
dependency-governance:
23+
name: Ownership, licenses, and advisories
24+
runs-on: ubuntu-latest
25+
timeout-minutes: 10
26+
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
30+
31+
- name: Setup Bun
32+
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
33+
with:
34+
bun-version: 1.3.14
35+
36+
- name: Install dependencies
37+
run: bun install --frozen-lockfile --ignore-scripts --os='*' --cpu='*'
38+
39+
- name: Check direct ownership, dependency growth, and licenses
40+
run: bun run check:dependency-governance
41+
42+
- name: Reject unreviewed dependency advisories
43+
run: bun run check:dependency-security

NOTICE

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
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.
5+
6+
Third-party notices for distributed runtime components are in
7+
THIRD-PARTY-NOTICES.md.

THIRD-PARTY-NOTICES.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# Third-Party Notices
2+
3+
Sim Studio is licensed under the Apache License 2.0. The distributed application
4+
and container images also include third-party software under separate terms.
5+
Those terms apply to the relevant third-party components and do not replace the
6+
Sim Studio license.
7+
8+
## libheif-js and libheif
9+
10+
The HEIC decode and conversion path uses `libheif-js` 1.19.8 through
11+
`heic-decode` and `heic-convert`. `libheif-js` is an Emscripten distribution of
12+
libheif and declares the `LGPL-3.0` license.
13+
14+
- Packaged project and corresponding source:
15+
<https://github.com/catdad-experiments/libheif-js/tree/1.19.8>
16+
- Upstream libheif project and source: <https://github.com/strukturag/libheif>
17+
- License text shipped by the package: `node_modules/libheif-js/LICENSE` and
18+
`node_modules/libheif-js/libheif/LICENSE`
19+
20+
The application container copies the package's combined libheif license text to
21+
`/app/third-party-licenses/libheif-LICENSE` so it remains available alongside
22+
the distributed runtime.
23+
24+
## sharp-libvips and libvips
25+
26+
Image processing uses `sharp` with the platform-specific
27+
`@img/sharp-libvips-*` 1.3.2 runtime package. That package declares
28+
`LGPL-3.0-or-later` and bundles libvips 8.18.3 as a dynamically loaded shared
29+
library. Its `versions.json` records the exact versions of libvips and the codec
30+
libraries in each platform artifact; its `README.md` records their individual
31+
license families. Both files are included in the application container with the
32+
platform package.
33+
34+
- sharp-libvips build source:
35+
<https://github.com/lovell/sharp-libvips/tree/v1.3.2>
36+
- libvips 8.18.3 corresponding source:
37+
<https://github.com/libvips/libvips/tree/v8.18.3>
38+
- GNU Lesser General Public License 3.0:
39+
<https://www.gnu.org/licenses/lgpl-3.0.html>
40+
- GNU General Public License 3.0, incorporated by LGPL 3.0:
41+
<https://www.gnu.org/licenses/gpl-3.0.html>
42+
43+
The complete platform-specific dependency and license table remains available
44+
at `/app/node_modules/@img/sharp-libvips-*/README.md` in the application
45+
container.

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/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)