From d18312d6de2d79c9f0e8dc2e964fc94e85affd0b Mon Sep 17 00:00:00 2001 From: Dotta Date: Tue, 3 Mar 2026 15:45:45 -0600 Subject: [PATCH] fix: bundle UI dist into server package for npm publishing The server's static-ui mode resolves the UI dist path relative to its own directory. In the monorepo it finds ../../ui/dist, but when published to npm the UI package isn't available. - server/src/app.ts: try ../ui-dist (published) then ../../ui/dist (dev), gracefully degrade to API-only if neither exists - server/package.json: include ui-dist/ in published files - scripts/release.sh: build UI and copy dist to server/ui-dist before publishing, clean up in restore step Co-Authored-By: Claude Opus 4.6 --- scripts/release.sh | 12 ++++++++++-- server/package.json | 3 ++- server/src/app.ts | 20 ++++++++++++++------ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/scripts/release.sh b/scripts/release.sh index 169a84b4..4ffa70c5 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -125,7 +125,7 @@ echo "" echo "==> Step 4/7: Building all packages..." cd "$REPO_ROOT" -# Build packages in dependency order (excluding UI and CLI) +# Build packages in dependency order (excluding CLI) pnpm --filter @paperclipai/shared build pnpm --filter @paperclipai/adapter-utils build pnpm --filter @paperclipai/db build @@ -133,7 +133,12 @@ pnpm --filter @paperclipai/adapter-claude-local build pnpm --filter @paperclipai/adapter-codex-local build pnpm --filter @paperclipai/adapter-openclaw build pnpm --filter @paperclipai/server build -echo " ✓ All packages built" + +# Build UI and bundle into server package for static serving +pnpm --filter @paperclipai/ui build +rm -rf "$REPO_ROOT/server/ui-dist" +cp -r "$REPO_ROOT/ui/dist" "$REPO_ROOT/server/ui-dist" +echo " ✓ All packages built (including UI)" # ── Step 5: Build CLI bundle ───────────────────────────────────────────────── @@ -183,6 +188,9 @@ if [ -f "$CLI_DIR/README.md" ]; then rm "$CLI_DIR/README.md" fi +# Remove UI dist bundled into server for publishing +rm -rf "$REPO_ROOT/server/ui-dist" + # Commit all changes git add -A git commit -m "chore: release v$NEW_VERSION" diff --git a/server/package.json b/server/package.json index ffd0c2e5..db67e938 100644 --- a/server/package.json +++ b/server/package.json @@ -17,7 +17,8 @@ "types": "./dist/index.d.ts" }, "files": [ - "dist" + "dist", + "ui-dist" ], "scripts": { "dev": "tsx src/index.ts", diff --git a/server/src/app.ts b/server/src/app.ts index e14e7de2..1faab285 100644 --- a/server/src/app.ts +++ b/server/src/app.ts @@ -124,12 +124,20 @@ export async function createApp( const __dirname = path.dirname(fileURLToPath(import.meta.url)); if (opts.uiMode === "static") { - // Serve built UI from ui/dist in production. - const uiDist = path.resolve(__dirname, "../../ui/dist"); - app.use(express.static(uiDist)); - app.get(/.*/, (_req, res) => { - res.sendFile(path.join(uiDist, "index.html")); - }); + // Try published location first (server/ui-dist/), then monorepo dev location (../../ui/dist) + const candidates = [ + path.resolve(__dirname, "../ui-dist"), + path.resolve(__dirname, "../../ui/dist"), + ]; + const uiDist = candidates.find((p) => fs.existsSync(path.join(p, "index.html"))); + if (uiDist) { + app.use(express.static(uiDist)); + app.get(/.*/, (_req, res) => { + res.sendFile(path.join(uiDist, "index.html")); + }); + } else { + console.warn("[paperclip] UI dist not found; running in API-only mode"); + } } if (opts.uiMode === "vite-dev") {