Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
434f413
feat(ui): add @workflowbuilder/ui and @workflowbuilder/ui-tokens pack…
librowski-synergy Jun 24, 2026
59adc22
fix(ui): correctness fixes from review
librowski-synergy Jun 25, 2026
7e8475c
refactor(ui): review polish pass
librowski-synergy Jun 25, 2026
a80d421
test(ui): add Vitest suites for ui + tokens pure logic
librowski-synergy Jun 25, 2026
135036c
chore(ui): release-prep for npm publish
librowski-synergy Jun 25, 2026
7959366
ci(release): scoped per-package release tags + ui publish workflow
librowski-synergy Jun 25, 2026
0b3cbcc
chore(ui): make @base-ui/react a regular dependency, not a peer
librowski-synergy Jun 26, 2026
ca743f9
fix(ui): ship react-day-picker styles so the calendar renders
librowski-synergy Jun 26, 2026
62f3a12
fix(ui): theme the date-picker calendar and add day hover
librowski-synergy Jun 26, 2026
a887eb1
fix(ui): theme the date-picker month-nav chevrons
librowski-synergy Jun 26, 2026
dd096cb
fix(ui): IconSwitch uncontrolled icon swap + Accordion double toggle
librowski-synergy Jun 30, 2026
11c56c5
docs(ui): correct and extend the CHANGELOG for the beta
librowski-synergy Jun 30, 2026
d431a14
chore(ui): release as 2.0.0 with a fresh changelog
librowski-synergy Jun 30, 2026
807657a
fix(ui): wrap remaining component CSS in cascade layers, guard agains…
Jul 30, 2026
0aed076
chore(ui): Apache-2.0 license, externalize @phosphor-icons/react, exp…
Jul 30, 2026
bcb22e8
chore(tokens): add lint/typecheck scripts, README, and CI coverage
Jul 30, 2026
c3fef52
docs: document packages/tokens in CLAUDE.md workspace tables
Jul 30, 2026
5292e5b
chore(docs): remove orphaned apps/docs/src/generated/ui-api.json
Jul 30, 2026
4f339a3
chore: sync pnpm-lock.yaml after rebase onto main
Jul 31, 2026
0fc78fe
fix(ui): require react 19 in peer range
Jul 31, 2026
802b87f
refactor(ui): rewrite built-css layer check on postcss
Jul 31, 2026
2f56fcb
fix(ui): export WithIcon from the barrel so TypeDoc resolves the icon…
Jul 31, 2026
10806da
fix(ui): pin the select caret to the trigger's far edge
Jul 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 51 additions & 4 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
name: PR Check

# Runs on every PR to give reviewers fast feedback on whether the change
# is safe to merge. Focus on @workflowbuilder/sdk (what we publish to
# npm) + global format consistency. Other workspaces (apps/docs, demo,
# ai-studio, …) are not checked here — they're internal and have their
# own broken-state tolerances (e.g. starlight virtual-module type errors).
# is safe to merge. Focus on the published packages @workflowbuilder/sdk and
# @workflowbuilder/ui (plus its private @workflowbuilder/ui-tokens build) +
# global format consistency. Other workspaces (apps/docs, demo, ai-studio, …)
# are not checked here — they're internal and have their own broken-state
# tolerances (e.g. starlight virtual-module type errors).

on:
pull_request:
Expand Down Expand Up @@ -75,3 +76,49 @@ jobs:

- name: Build
run: pnpm --filter @workflowbuilder/sdk build:lib

ui:
name: UI + UI tokens lint + typecheck + test + build
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
submodules: true

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22

- name: Enable Corepack
run: npm i -g corepack@latest

- name: Install pnpm
run: corepack prepare

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Lint tokens
run: pnpm --filter @workflowbuilder/ui-tokens lint

- name: Typecheck tokens
run: pnpm --filter @workflowbuilder/ui-tokens typecheck

- name: Test tokens
run: pnpm --filter @workflowbuilder/ui-tokens test

- name: Lint
run: pnpm --filter @workflowbuilder/ui lint

- name: Typecheck
run: pnpm --filter @workflowbuilder/ui typecheck

- name: Test
run: pnpm --filter @workflowbuilder/ui test

- name: Build
# build:ui builds @workflowbuilder/ui-tokens first, then ui, then runs
# the check:built-css guard.
run: pnpm build:ui
18 changes: 11 additions & 7 deletions .github/workflows/release-sdk.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
name: Release SDK

# Triggers on tags `vX.Y.Z` matching the version in packages/sdk/package.json.
# Maintainer pushes the tag after merging the version-bump PR (which ran
# `pnpm changeset version`). See packages/sdk/RELEASE.md.
# Triggers on scoped tags `@workflowbuilder/sdk@X.Y.Z` matching the version in
# packages/sdk/package.json. Scoped tags let this repo publish more than one
# package (see release-ui.yml for @workflowbuilder/ui). Maintainer pushes the
# tag after merging the version-bump PR (which ran `pnpm changeset version`).
# See packages/sdk/RELEASE.md.

on:
push:
tags:
- "v*"
- "@workflowbuilder/sdk@*"
workflow_dispatch: # manual fire from GitHub UI — for testing or rerunning a failed publish

permissions:
Expand Down Expand Up @@ -60,10 +62,12 @@ jobs:
run: pnpm --filter @workflowbuilder/sdk build:lib

- name: Verify version matches tag
# Tag refs/tags/vX.Y.Z must match packages/sdk/package.json version.
# Catches push of wrong tag (typo, pushed before version-bump PR merged).
# Tag `@workflowbuilder/sdk@X.Y.Z` must match packages/sdk/package.json
# version. ${GITHUB_REF_NAME##*@} strips everything up to the last `@`,
# leaving X.Y.Z. Catches push of wrong tag (typo, pushed before the
# version-bump PR merged).
run: |
TAG_VERSION="${GITHUB_REF_NAME#v}"
TAG_VERSION="${GITHUB_REF_NAME##*@}"
PKG_VERSION=$(node -p "require('./packages/sdk/package.json').version")
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
echo "::error::Tag version ($TAG_VERSION) does not match package.json version ($PKG_VERSION)."
Expand Down
114 changes: 114 additions & 0 deletions .github/workflows/release-ui.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Release UI

# Triggers on scoped tags `@workflowbuilder/ui@X.Y.Z` matching the version in
# packages/ui/package.json. Mirrors release-sdk.yml. Maintainer pushes the tag
# after merging the version-bump PR (which ran `pnpm changeset version`). See
# packages/sdk/RELEASE.md (the release flow is shared between both packages).
#
# One-time npm setup: @workflowbuilder/ui needs its own GitHub Actions trusted
# publisher registered on npmjs.com pointing at THIS workflow file
# (.github/workflows/release-ui.yml). It is separate from the sdk one.

on:
push:
tags:
- "@workflowbuilder/ui@*"
workflow_dispatch: # manual fire from GitHub UI — for testing or rerunning a failed publish

permissions:
contents: write # create GitHub Release
id-token: write # OIDC for npm Trusted Publisher (and provenance attestation)

jobs:
publish:
name: Build and publish to npm
runs-on: ubuntu-latest
steps:
- name: Checkout code (at tag)
uses: actions/checkout@v4
with:
submodules: true
fetch-depth: 0 # full history so changesets can read CHANGELOG context

- name: Set up Node.js
# No `registry-url:` here on purpose — see the note in release-sdk.yml.
# setup-node's registry-url breaks OIDC by injecting a sentinel token.
uses: actions/setup-node@v4
with:
node-version: 22

- name: Enable Corepack
run: npm i -g corepack@latest

- name: Install pnpm
run: corepack prepare

- name: Install dependencies
run: pnpm install --frozen-lockfile

# Defensive layer — fail before npm, not on consumers.
- name: Lint
run: pnpm --filter @workflowbuilder/ui lint

- name: Typecheck
run: pnpm --filter @workflowbuilder/ui typecheck

- name: Test
run: pnpm --filter @workflowbuilder/ui test

- name: Build UI
# build:ui builds @workflowbuilder/ui-tokens first (ui consumes its
# built tokens.css) and runs the check:built-css guard afterwards.
run: pnpm build:ui

- name: Verify version matches tag
# Tag `@workflowbuilder/ui@X.Y.Z` must match packages/ui/package.json
# version. ${GITHUB_REF_NAME##*@} strips everything up to the last `@`.
run: |
TAG_VERSION="${GITHUB_REF_NAME##*@}"
PKG_VERSION=$(node -p "require('./packages/ui/package.json').version")
if [ "$TAG_VERSION" != "$PKG_VERSION" ]; then
echo "::error::Tag version ($TAG_VERSION) does not match package.json version ($PKG_VERSION)."
echo "Did you forget to merge the version-bump PR before pushing the tag?"
exit 1
fi
echo "Publishing @workflowbuilder/ui@$PKG_VERSION"

- name: Check if version already published
# Idempotency — re-pushing a tag should not re-publish.
id: check-version
run: |
PKG_VERSION=$(node -p "require('./packages/ui/package.json').version")
if npm view "@workflowbuilder/ui@$PKG_VERSION" version 2>/dev/null; then
echo "already_published=true" >> "$GITHUB_OUTPUT"
echo "::notice::@workflowbuilder/ui@$PKG_VERSION already on npm — skipping publish step."
else
echo "already_published=false" >> "$GITHUB_OUTPUT"
fi

- name: Publish to npm
# Authenticates via npm Trusted Publisher (OIDC). No NPM_TOKEN.
# Requires @workflowbuilder/ui to have trusted publishing configured on
# npmjs.com pointing at this workflow file.
if: steps.check-version.outputs.already_published == 'false'
run: pnpm --filter @workflowbuilder/ui publish --no-git-checks --access public --provenance

- name: Extract release notes from CHANGELOG
id: notes
run: |
VERSION=$(node -p "require('./packages/ui/package.json').version")
NOTES=$(awk -v v="$VERSION" '$0 ~ ("^## \\[?" v "\\]?([ -]|$)"){flag=1;next}/^## /{flag=0}flag' packages/ui/CHANGELOG.md)
{
echo "notes<<EOF"
echo "$NOTES"
echo "EOF"
} >> "$GITHUB_OUTPUT"

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: ${{ github.ref_name }}
body: ${{ steps.notes.outputs.notes }}
draft: false
prerelease: false
71 changes: 38 additions & 33 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ Visual workflow editor SDK (React) with a reference backend and Temporal-based e

Three onboarding paths (A installs from npm; B, C run the repo locally). README "Get started" covers all three. Path A ("Embed the SDK") installs `@workflowbuilder/sdk` from npm; the README has install + a minimal snippet, and the full guide lives in the [docs site](https://www.workflowbuilder.io/docs/get-started/quick-start/wb-as-react-component/).

| Command | Path | What it does |
| ---------------------------- | ---- | --------------------------------------------------------------------------- |
| `pnpm preflight` | B/C | Verify Node / pnpm / Docker / ports / `.env` files. Add `--json` for agents |
| `pnpm dev` / `pnpm dev:demo` | B | Demo (UI only, port 4200). No backend, no Docker |
| `pnpm infra:up` | C | Start Postgres + Temporal in Docker. Required before backend/worker |
| `pnpm -F backend db:migrate` | C | Apply Drizzle migrations out-of-band (backend also auto-migrates on boot) |
| `pnpm dev:ai-studio` | C | Full stack: infra + backend (3001) + worker + AI Studio frontend (4201) |
| `pnpm dev:backend` | C | Backend only (debug). Needs infra up |
| `pnpm dev:worker` | C | Execution worker only (debug). Needs infra up |
| `pnpm infra:down` | C | Stop the Docker stack |
| `pnpm dev:docs` | - | Docs site (Astro + Starlight) |
| `pnpm build:lib` | - | Build the SDK package (`packages/sdk`) |
| `pnpm build` | - | Build the demo app |
| `pnpm test` | - | Run tests in `packages/sdk` and `packages/execution-core` |
| `pnpm check` | - | Lint + typecheck + format + knip |
| Command | Path | What it does |
| ---------------------------- | ---- | --------------------------------------------------------------------------------------- |
| `pnpm preflight` | B/C | Verify Node / pnpm / Docker / ports / `.env` files. Add `--json` for agents |
| `pnpm dev` / `pnpm dev:demo` | B | Demo (UI only, port 4200). No backend, no Docker |
| `pnpm infra:up` | C | Start Postgres + Temporal in Docker. Required before backend/worker |
| `pnpm -F backend db:migrate` | C | Apply Drizzle migrations out-of-band (backend also auto-migrates on boot) |
| `pnpm dev:ai-studio` | C | Full stack: infra + backend (3001) + worker + AI Studio frontend (4201) |
| `pnpm dev:backend` | C | Backend only (debug). Needs infra up |
| `pnpm dev:worker` | C | Execution worker only (debug). Needs infra up |
| `pnpm infra:down` | C | Stop the Docker stack |
| `pnpm dev:docs` | - | Docs site (Astro + Starlight) |
| `pnpm build:lib` | - | Build the publishable chain: `ui-tokens` -> `ui` -> SDK (`build:ui` does the first two) |
| `pnpm build` | - | Build the demo app |
| `pnpm test` | - | Run tests in `packages/sdk` and `packages/execution-core` |
| `pnpm check` | - | Lint + typecheck + format + knip |

Path B is UI-only and does not need Docker. Path C requires `pnpm infra:up` before backend/worker can start; the backend applies pending migrations automatically at boot.

Expand Down Expand Up @@ -55,6 +55,8 @@ apps/
tools/ - @workflow-builder/tools workspace (decision-log collector, lint-staged config)
packages/
sdk/ - @workflowbuilder/sdk public package (WorkflowBuilder compound component, plugin API, components)
ui/ - @workflowbuilder/ui published component library (Base UI), consumed by sdk/demo/ai-studio
tokens/ - @workflowbuilder/ui-tokens private design-token build (style-dictionary), feeds packages/ui
execution-core/ - Pure topological graph runner + node executor registry
types/ - Shared TypeScript types
```
Expand All @@ -65,20 +67,23 @@ Where to put a new script: root `tools/` for pure-Node bootstrap (runs before an

Each workspace has its own context. Read the relevant file before extending a workspace.

| Workspace | Authoritative docs |
| ------------------------- | ----------------------------------- |
| `packages/sdk` | `packages/sdk/README.md` |
| `packages/execution-core` | `packages/execution-core/README.md` |
| `apps/demo` | `apps/demo/CLAUDE.md` |
| `apps/ai-studio` | `apps/ai-studio/README.md` |
| `apps/backend` | `apps/backend/README.md` |
| `apps/execution-worker` | `apps/execution-worker/README.md` |
| Workspace | Authoritative docs |
| ------------------------- | ------------------------------------------------------- |
| `packages/sdk` | `packages/sdk/README.md` |
| `packages/ui` | `packages/ui/README.md` (+ `packages/ui/css-layers.md`) |
| `packages/tokens` | `packages/tokens/README.md` |
| `packages/execution-core` | `packages/execution-core/README.md` |
| `apps/demo` | `apps/demo/CLAUDE.md` |
| `apps/ai-studio` | `apps/ai-studio/README.md` |
| `apps/backend` | `apps/backend/README.md` |
| `apps/execution-worker` | `apps/execution-worker/README.md` |

## Types & Aliases

Shared types: `packages/types/` (imported as `@workflow-builder/types/*`).
Icons: `apps/icons/` (imported as `@workflow-builder/icons`).
SDK: `packages/sdk/` (imported as `@workflowbuilder/sdk`).
UI: `packages/ui/` (imported as `@workflowbuilder/ui`; styles via `@workflowbuilder/ui/styles.css`, `/index.css`, `/tokens.css`).

## Local Infrastructure

Expand All @@ -93,14 +98,14 @@ Backend reads `DATABASE_URL` and `TEMPORAL_ADDRESS`; defaults work out of the bo

## Code Quality

| Tool | Command | Notes |
| ---------- | ----------------------------- | --------------------------------------------------------- |
| ESLint | `pnpm lint` / `pnpm lint:fix` | Per-workspace configs |
| Prettier | `pnpm format` | Sorts imports via `@trivago/prettier-plugin-sort-imports` |
| TypeScript | `pnpm typecheck` | Per-workspace `tsconfig.json` |
| Knip | Part of `pnpm check` | Detects unused exports/dependencies |
| Vitest | `pnpm test` | Runs in `packages/sdk` and `packages/execution-core` |
| Full check | `pnpm check` | Run before PR |
| Tool | Command | Notes |
| ---------- | ----------------------------- | --------------------------------------------------------------------------------------- |
| ESLint | `pnpm lint` / `pnpm lint:fix` | Per-workspace configs |
| Prettier | `pnpm format` | Sorts imports via `@trivago/prettier-plugin-sort-imports` |
| TypeScript | `pnpm typecheck` | Per-workspace `tsconfig.json` |
| Knip | Part of `pnpm check` | Detects unused exports/dependencies |
| Vitest | `pnpm test` | Runs in `packages/sdk`, `packages/execution-core`, `packages/ui`, and `packages/tokens` |
| Full check | `pnpm check` | Run before PR |

## Getting Started

Expand Down Expand Up @@ -133,7 +138,7 @@ If you're new to this repo and want to build your own consumer app or POC, follo

### Releasing `@workflowbuilder/sdk`

The SDK is the only npm-published workspace; everything else under `apps/` and `packages/` is private (and listed under `ignore` in `.changeset/config.json`).
Two workspaces are npm-published: `@workflowbuilder/sdk` and `@workflowbuilder/ui` (the component library, built on Base UI). Everything else under `apps/` and `packages/` is private - including `@workflowbuilder/ui-tokens` - so Changesets skips it automatically; the internal `@workflow-builder/*` packages are additionally listed under `ignore` in `.changeset/config.json` (note `@workflowbuilder/ui-tokens` is not in that list - it relies on `private: true`). Both publish via scoped release tags (`@workflowbuilder/sdk@X.Y.Z`, `@workflowbuilder/ui@X.Y.Z`), each with its own workflow (`release-sdk.yml`, `release-ui.yml`) - see `packages/sdk/RELEASE.md`.

**Commit format is enforced.** Every commit goes through `commitlint` via the `commit-msg` husky hook — Conventional Commits format only (`<type>(<scope>): <subject>`, types from `feat / fix / perf / refactor / docs / test / chore / build / ci / style / revert`). Bad messages are rejected before they land in git history.

Expand All @@ -158,7 +163,7 @@ The SDK is the only npm-published workspace; everything else under `apps/` and `
4. GitHub Action triggered by the tag runs lint + typecheck + test + `pnpm publish --provenance` (authenticated via npm Trusted Publisher / OIDC, no `NPM_TOKEN` stored anywhere) + creates a GitHub Release.
5. Sync back: `git checkout main && git merge release && git push` so main picks up the bumped version + clean `.changeset/`.

Tag format follows the ng-diagram convention (single-package monorepo, `v*` regex). If we ever publish a second package we'll migrate to scoped (`@workflowbuilder/sdk@X.Y.Z`) — ~1h of work, see `packages/sdk/RELEASE.md` § "Why these decisions".
Tags are scoped per package (`@workflowbuilder/sdk@X.Y.Z`, `@workflowbuilder/ui@X.Y.Z`); each package has its own tag-triggered workflow (`release-sdk.yml`, `release-ui.yml`). The earlier single-package `v*` scheme was retired when `@workflowbuilder/ui` became publishable. See `packages/sdk/RELEASE.md` § "Why these decisions".

Canonical procedure with edge cases and rollback: [`packages/sdk/RELEASE.md`](packages/sdk/RELEASE.md).

Expand Down
Loading
Loading