Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 40 additions & 3 deletions .github/workflows/pr-check.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
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
# is safe to merge. Focus on the published packages @workflowbuilder/sdk and
# @workflowbuilder/ui + 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:
Expand Down Expand Up @@ -75,3 +75,40 @@ jobs:

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

ui:
name: UI 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
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
54 changes: 29 additions & 25 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. First run, or after schema changes |
| `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. First run, or after schema changes |
| `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, and `db:migrate` on the first run.

Expand Down Expand Up @@ -52,6 +52,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 @@ -62,20 +64,22 @@ 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/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 Down Expand Up @@ -130,7 +134,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 @@ -155,7 +159,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