Skip to content
Merged
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
92 changes: 85 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ on:
required: true
type: choice
options:
- capture-protocol
- capture-viewer
- core
- viewer
- editor
Expand Down Expand Up @@ -128,7 +130,7 @@ jobs:
# peerDeps sync below must use shell vars, not env indirection.
declare -A NEW_VERSIONS

for pkg in core viewer editor nodes mcp ifc-converter cli; do
for pkg in capture-protocol core viewer capture-viewer editor nodes mcp ifc-converter cli; do
if [ "$TARGET" = "$pkg" ] || [ "$TARGET" = "all" ]; then
CUR=$(jq -r '.version' packages/$pkg/package.json)
NEW=$(bump_version "$CUR")
Expand All @@ -141,26 +143,77 @@ jobs:
fi
done

# Sync inter-package references in peerDependencies and devDependencies.
# Sync inter-package references in dependencies, peerDependencies, and devDependencies.
# Anything that references a bumped @pascal-app/* package is updated to ^NEW.
for pkg in core viewer editor nodes mcp ifc-converter cli; do
for pkg in capture-protocol core viewer capture-viewer editor nodes mcp ifc-converter cli; do
FILE=packages/$pkg/package.json
for dep in core viewer editor nodes mcp ifc-converter cli; do
for dep in capture-protocol core viewer capture-viewer editor nodes mcp ifc-converter cli; do
VAL="${NEW_VERSIONS[$dep]}"
[ -z "$VAL" ] && continue
jq --arg name "@pascal-app/$dep" --arg v "^$VAL" '
if .peerDependencies[$name] then .peerDependencies[$name] = $v else . end
if .dependencies[$name] then .dependencies[$name] = $v else . end
| if .peerDependencies[$name] then .peerDependencies[$name] = $v else . end
| if .devDependencies[$name] then .devDependencies[$name] = $v else . end
' "$FILE" > tmp.json && mv tmp.json "$FILE"
done
done

echo "=== @pascal-app/* refs after sync ==="
for pkg in core viewer editor nodes mcp ifc-converter cli; do
for pkg in capture-protocol core viewer capture-viewer editor nodes mcp ifc-converter cli; do
echo "--- packages/$pkg/package.json ---"
jq '{ peerDependencies: (.peerDependencies // {} | with_entries(select(.key | startswith("@pascal-app/")))), devDependencies: (.devDependencies // {} | with_entries(select(.key | startswith("@pascal-app/")))) }' packages/$pkg/package.json
jq '{ dependencies: (.dependencies // {} | with_entries(select(.key | startswith("@pascal-app/")))), peerDependencies: (.peerDependencies // {} | with_entries(select(.key | startswith("@pascal-app/")))), devDependencies: (.devDependencies // {} | with_entries(select(.key | startswith("@pascal-app/")))) }' packages/$pkg/package.json
done

# Version and dependency ranges changed after the frozen install.
# Refresh the lockfile so the release commit remains reproducible.
bun install

# A single-package release may depend on another package introduced
# by this monorepo. Refuse to publish an uninstallable package when
# that dependency is not part of this run and is absent from npm.
RELEASE_PACKAGES="capture-protocol core viewer capture-viewer editor nodes mcp ifc-converter cli"
if [ "$TARGET" != "all" ]; then
FILE="packages/$TARGET/package.json"
while IFS=$'\t' read -r DEP RANGE; do
SLUG="${DEP#@pascal-app/}"
case " $RELEASE_PACKAGES " in
*" $SLUG "*)
if ! npm view "$DEP@$RANGE" version >/dev/null 2>&1; then
echo "Missing required published dependency: $DEP@$RANGE"
echo "Release $SLUG first or use the all-package release."
exit 1
fi
;;
esac
done < <(
jq -r '
[(.dependencies // {}), (.peerDependencies // {})]
| add
| to_entries[]
| select(.key | startswith("@pascal-app/"))
| [.key, .value]
| @tsv
' "$FILE"
)
fi

- name: Build & publish capture protocol
if: inputs.package == 'capture-protocol' || inputs.package == 'all'
working-directory: packages/capture-protocol
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
bun run build
if [ "${{ inputs.dry-run }}" = "true" ]; then
echo "🏜️ Dry run — would publish @pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION"
npm publish --dry-run --access public --tag "$NPM_TAG"
elif npm view "@pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION" version >/dev/null 2>&1; then
echo "📦 @pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION is already published; continuing release recovery"
else
npm publish --access public --tag "$NPM_TAG"
echo "📦 Published @pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION"
fi

- name: Validate portable editor runtime
if: inputs.package == 'cli' || inputs.package == 'all'
env:
Expand Down Expand Up @@ -206,6 +259,23 @@ jobs:
echo "📦 Published @pascal-app/viewer@$VIEWER_VERSION"
fi

- name: Build & publish capture viewer
if: inputs.package == 'capture-viewer' || inputs.package == 'all'
working-directory: packages/capture-viewer
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
bun run build
if [ "${{ inputs.dry-run }}" = "true" ]; then
echo "🏜️ Dry run — would publish @pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION"
npm publish --dry-run --access public --tag "$NPM_TAG"
elif npm view "@pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION" version >/dev/null 2>&1; then
echo "📦 @pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION is already published; continuing release recovery"
else
npm publish --access public --tag "$NPM_TAG"
echo "📦 Published @pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION"
fi

- name: Publish editor
if: inputs.package == 'editor' || inputs.package == 'all'
working-directory: packages/editor
Expand Down Expand Up @@ -298,6 +368,10 @@ jobs:
PKGS=""
TAGS=""

if [ -n "$CAPTURE_PROTOCOL_VERSION" ]; then
PKGS="$PKGS @pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION"
TAGS="$TAGS @pascal-app/capture-protocol@$CAPTURE_PROTOCOL_VERSION"
fi
if [ -n "$CORE_VERSION" ]; then
PKGS="$PKGS @pascal-app/core@$CORE_VERSION"
TAGS="$TAGS @pascal-app/core@$CORE_VERSION"
Expand All @@ -306,6 +380,10 @@ jobs:
PKGS="$PKGS @pascal-app/viewer@$VIEWER_VERSION"
TAGS="$TAGS @pascal-app/viewer@$VIEWER_VERSION"
fi
if [ -n "$CAPTURE_VIEWER_VERSION" ]; then
PKGS="$PKGS @pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION"
TAGS="$TAGS @pascal-app/capture-viewer@$CAPTURE_VIEWER_VERSION"
fi
if [ -n "$EDITOR_VERSION" ]; then
PKGS="$PKGS @pascal-app/editor@$EDITOR_VERSION"
TAGS="$TAGS @pascal-app/editor@$EDITOR_VERSION"
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,12 @@ troubleshooting.
## Using Published Packages

The viewer runtime and built-in node definitions are separate packages. Install the full built-in
viewer set, then load the built-in plugin once before mounting `<Viewer>`:
viewer set, then load the built-in plugin once before mounting `<Viewer>`. Capture sessions are an
optional transport-neutral extension:

```bash
npm install @pascal-app/core @pascal-app/viewer @pascal-app/editor @pascal-app/nodes
npm install @pascal-app/capture-protocol @pascal-app/capture-viewer
```

```typescript
Expand All @@ -57,6 +59,8 @@ editor/
├── packages/
│ ├── core/ # Schemas, scene state, and registry contracts
│ ├── viewer/ # 3D rendering runtime and shared systems
│ ├── capture-protocol/ # Static/live capture-session contracts
│ ├── capture-viewer/ # Capture source runtime and reference renderers
│ ├── editor/ # Editing tools and UI components
│ ├── nodes/ # Built-in node definitions, renderers, and systems
│ ├── cli/ # Persistent local editor installer and process manager
Expand All @@ -70,6 +74,8 @@ editor/
|---------|---------------|
| **@pascal-app/core** | Node schemas, scene state (Zustand), registry contracts, spatial queries, and event bus |
| **@pascal-app/viewer** | 3D rendering via React Three Fiber, shared render systems, default camera/controls, and post-processing |
| **@pascal-app/capture-protocol** | Versioned capture manifests, normalized streams, and transport-neutral static/live sources |
| **@pascal-app/capture-viewer** | Viewer child runtime and reference model, device-motion, and point-cloud layers |
| **@pascal-app/editor** | Editing tools, panels, selection, and direct-manipulation UI |
| **@pascal-app/nodes** | Built-in registry plugin with node definitions, renderers, geometry, and systems |
| **@pascal-app/cli** | Installs and manages a versioned standalone editor runtime and persistent local data |
Expand Down
58 changes: 51 additions & 7 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading