diff --git a/package.json b/package.json index 5de3ddd8b7..1bb11a2ebb 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ "docs:start": "pnpm --filter @objectstack/docs start", "os": "node packages/cli/bin/run.js", "objectui:build": "bash scripts/build-console.sh", + "sdui:manifest": "bash scripts/gen-sdui-manifest.sh", "objectui:bump": "bash scripts/bump-objectui.sh", "objectui:refresh": "bash scripts/bump-objectui.sh && bash scripts/build-console.sh", "objectui:clean": "rm -rf packages/console/dist .cache/objectui-*", diff --git a/scripts/build-console.sh b/scripts/build-console.sh index a11ba1ea2e..c05da32b7d 100755 --- a/scripts/build-console.sh +++ b/scripts/build-console.sh @@ -129,38 +129,10 @@ cp -R "$CONSOLE_DIST" "$TARGET" BYTES="$(du -sk "$TARGET" 2>/dev/null | awk '{print $1}')" echo "✓ @objectstack/console dist ready (${BYTES} KB) from objectui@${PINNED_SHA:0:12}" -# ADR-0080: generate the public-tier SDUI manifest from the just-built console's -# registry so the framework os-build JSX gate can do full component/prop -# validation. Best-effort and GUARDED: skips on a sha without the dump tooling, -# and never fails the console build (the gate falls back to parse-level). -DUMP_PAGE="${BUILD_ROOT}/apps/console/dev/manifest-dump.html" -DUMP_SCRIPT="${BUILD_ROOT}/scripts/dump-public-manifest.mjs" -if [[ -f "$DUMP_PAGE" && -f "$DUMP_SCRIPT" ]]; then - echo "→ Generating SDUI public-tier manifest (ADR-0080)..." - pushd "$BUILD_ROOT" > /dev/null - pnpm --filter @object-ui/console exec vite dev --port 5180 > /tmp/sdui-dump-dev.log 2>&1 & - DUMP_DEV_PID=$! - for _ in $(seq 1 90); do curl -sf "http://localhost:5180/" > /dev/null 2>&1 && break; sleep 1; done - if BASE_URL="http://localhost:5180" OUT="${TARGET}/sdui.manifest.json" node scripts/dump-public-manifest.mjs; then - echo "✓ wrote ${TARGET}/sdui.manifest.json" - # ADR-0081: ratchet the spec↔frontend react-block conformance against the - # committed baseline while the freshly-dumped manifest is here for free. This - # is the ONLY place the manifest exists, so it is the cheapest place to catch - # NEW divergence (a component exposing an undocumented prop, or a block - # vanishing). Warn-only — never fails the console build; run check:react-conformance - # --strict locally to gate intentionally. - if [[ -f "${FRAMEWORK_ROOT}/packages/spec/react-conformance.baseline.json" ]]; then - echo "→ Ratcheting spec↔frontend react-block conformance (ADR-0081)..." - ( cd "${FRAMEWORK_ROOT}" && MANIFEST="${TARGET}/sdui.manifest.json" \ - pnpm --filter @objectstack/spec check:react-conformance \ - --baseline react-conformance.baseline.json ) || \ - echo "⚠ conformance ratchet reported new divergence (non-fatal) — see output above" - fi - else - echo "⚠ manifest generation failed — os-build JSX gate falls back to parse-level (non-fatal)" - fi - kill "$DUMP_DEV_PID" 2>/dev/null || true - popd > /dev/null -else - echo "ℹ manifest dump tooling not present at objectui@${PINNED_SHA:0:12} — skipping (bump .objectui-sha to >=96b1293 to enable full JSX validation)" -fi +# ADR-0080/0081: the public-tier SDUI manifest and the spec↔frontend react-block +# conformance ratchet are intentionally NOT generated here — they require a real +# browser (Playwright) to enumerate the console registry, and the console build +# must not drag in a browser dependency. Regenerate them on demand instead: +# pnpm sdui:manifest (see scripts/gen-sdui-manifest.sh) +echo "ℹ SDUI manifest + conformance ratchet are decoupled from the console build." +echo " Run 'pnpm sdui:manifest' on demand to regenerate (requires Playwright)." diff --git a/scripts/gen-sdui-manifest.sh b/scripts/gen-sdui-manifest.sh new file mode 100755 index 0000000000..f9661f31d9 --- /dev/null +++ b/scripts/gen-sdui-manifest.sh @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +# ADR-0080/0081: generate the public-tier SDUI component manifest and ratchet the +# spec↔frontend react-block conformance. +# +# This is deliberately SEPARATE from build-console.sh and is NOT part of the +# default build. The console component registry is a browser app (plugin-map / +# charts pull browser-only deps), so the only reliable way to enumerate it is to +# load the built `manifest-dump.html` in a real browser and read +# `window.__MANIFEST`. We do not want every console rebuild to drag in a +# Playwright browser dependency, so this step is opt-in / on-demand: +# +# pnpm objectui:build # (re)build + vendor the console dist at .objectui-sha +# pnpm sdui:manifest # then dump the manifest + ratchet conformance +# +# Requires a matching Playwright browser. If it complains the executable is +# missing, install it: +# +# pnpm exec playwright install chromium-headless-shell +# +# Output: packages/console/dist/sdui.manifest.json (consumed by the os-build +# JSX gate for full component/prop validation; absent -> gate falls back to +# parse-level). + +set -euo pipefail + +FRAMEWORK_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +SHA_FILE="${FRAMEWORK_ROOT}/.objectui-sha" + +if [[ ! -f "$SHA_FILE" ]]; then + echo "✗ ${SHA_FILE} is missing — cannot determine which objectui commit to use." + exit 1 +fi +PINNED_SHA="$(tr -d '[:space:]' < "$SHA_FILE")" + +BUILD_ROOT="${FRAMEWORK_ROOT}/.cache/objectui-${PINNED_SHA:0:12}" +TARGET="${FRAMEWORK_ROOT}/packages/console/dist" +DUMP_PAGE="${BUILD_ROOT}/apps/console/dev/manifest-dump.html" +DUMP_SCRIPT="${BUILD_ROOT}/scripts/dump-public-manifest.mjs" + +if [[ ! -d "$BUILD_ROOT" ]]; then + echo "✗ objectui build tree not found at ${BUILD_ROOT}" + echo " Run 'pnpm objectui:build' first to vendor the console at the pinned SHA." + exit 1 +fi +if [[ ! -f "$DUMP_PAGE" || ! -f "$DUMP_SCRIPT" ]]; then + echo "ℹ manifest dump tooling not present at objectui@${PINNED_SHA:0:12} — nothing to do." + echo " (bump .objectui-sha to >=96b1293 to enable full JSX validation)" + exit 0 +fi + +echo "→ Generating SDUI public-tier manifest (ADR-0080) from objectui@${PINNED_SHA:0:12}..." +pushd "$BUILD_ROOT" > /dev/null +pnpm --filter @object-ui/console exec vite dev --port 5180 > /tmp/sdui-dump-dev.log 2>&1 & +DUMP_DEV_PID=$! +trap 'kill "$DUMP_DEV_PID" 2>/dev/null || true' EXIT +for _ in $(seq 1 90); do curl -sf "http://localhost:5180/" > /dev/null 2>&1 && break; sleep 1; done + +if BASE_URL="http://localhost:5180" OUT="${TARGET}/sdui.manifest.json" node scripts/dump-public-manifest.mjs; then + echo "✓ wrote ${TARGET}/sdui.manifest.json" +else + status=$? + echo "✗ manifest generation failed (exit ${status})." + echo " If Playwright reported a missing browser, install it and retry:" + echo " pnpm exec playwright install chromium-headless-shell" + popd > /dev/null + exit "$status" +fi +popd > /dev/null + +# ADR-0081: ratchet the spec↔frontend react-block conformance against the +# committed baseline. Warn-only here — run check:react-conformance --strict to +# gate intentionally. +if [[ -f "${FRAMEWORK_ROOT}/packages/spec/react-conformance.baseline.json" ]]; then + echo "→ Ratcheting spec↔frontend react-block conformance (ADR-0081)..." + ( cd "${FRAMEWORK_ROOT}" && MANIFEST="${TARGET}/sdui.manifest.json" \ + pnpm --filter @objectstack/spec check:react-conformance \ + --baseline react-conformance.baseline.json ) || \ + echo "⚠ conformance ratchet reported new divergence — run check:react-conformance --strict to gate." +fi