openclaw - 💡(How to fix) Fix Source/runtime builds can leave `dist/control-ui` missing because the UI build is only documented, not enforced

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

A source/runtime checkout can be rebuilt into an internally inconsistent dist/ tree: the backend runtime is rebuilt under dist/, but the Control UI assets under dist/control-ui/ are not regenerated by pnpm build / scripts/build-all.mjs.

The current documented workaround is to remember a second command:

pnpm build
pnpm ui:build

That documentation is correct about the order, but it is not a reliable contract for source/live runtimes, service restarts, automation, or hotfix workflows. A backend build can clean dist/, remove a previously working dist/control-ui/, and produce a runtime that later serves:

Control UI assets not found. Build them with `pnpm ui:build` (auto-installs UI deps), or run `pnpm ui:dev` during development.

Root Cause

A source/runtime checkout can be rebuilt into an internally inconsistent dist/ tree: the backend runtime is rebuilt under dist/, but the Control UI assets under dist/control-ui/ are not regenerated by pnpm build / scripts/build-all.mjs.

The current documented workaround is to remember a second command:

pnpm build
pnpm ui:build

That documentation is correct about the order, but it is not a reliable contract for source/live runtimes, service restarts, automation, or hotfix workflows. A backend build can clean dist/, remove a previously working dist/control-ui/, and produce a runtime that later serves:

Control UI assets not found. Build them with `pnpm ui:build` (auto-installs UI deps), or run `pnpm ui:dev` during development.

Fix Action

Fix / Workaround

The current documented workaround is to remember a second command:

That documentation is correct about the order, but it is not a reliable contract for source/live runtimes, service restarts, automation, or hotfix workflows. A backend build can clean dist/, remove a previously working dist/control-ui/, and produce a runtime that later serves:

Code Example

pnpm build
pnpm ui:build

---

Control UI assets not found. Build them with `pnpm ui:build` (auto-installs UI deps), or run `pnpm ui:dev` during development.

---

rm -rf dist dist-runtime
pnpm build

test -f dist/index.js
test -f dist/control-ui/index.html

---

# In a source/live runtime that serves Control UI from dist/control-ui
pnpm build
# restart the gateway / LaunchAgent that loads dist/index.js
# open the Control UI route

---

pnpm build
test -f dist/control-ui/index.html
RAW_BUFFERClick to expand / collapse

Summary

A source/runtime checkout can be rebuilt into an internally inconsistent dist/ tree: the backend runtime is rebuilt under dist/, but the Control UI assets under dist/control-ui/ are not regenerated by pnpm build / scripts/build-all.mjs.

The current documented workaround is to remember a second command:

pnpm build
pnpm ui:build

That documentation is correct about the order, but it is not a reliable contract for source/live runtimes, service restarts, automation, or hotfix workflows. A backend build can clean dist/, remove a previously working dist/control-ui/, and produce a runtime that later serves:

Control UI assets not found. Build them with `pnpm ui:build` (auto-installs UI deps), or run `pnpm ui:dev` during development.

Why the current documentation-only approach is not sufficient

The current design relies on humans and automation remembering that a “full local dist” requires two independent commands. That is brittle for several reasons:

  1. dist/ is the runtime boundary, but pnpm build does not make it complete. The gateway backend runs from dist/index.js, while the same runtime serves Control UI from dist/control-ui/index.html. After pnpm build, dist/ should not be half-valid.

  2. The build is destructive to old UI assets. tsdown cleans dist. Since Vite writes Control UI to dist/control-ui, any UI bundle produced earlier can be deleted by a later backend build. This makes pnpm build able to turn a previously working checkout into one with missing dashboard assets.

  3. The failure appears during service operations, not just during source install. A realistic sequence is:

    • make a backend-only code change;
    • run a backend build command such as pnpm build, pnpm build:docker, or a build-all profile while verifying the change;
    • restart a source/live gateway process that points at dist/index.js;
    • dashboard route resolves the rebuilt backend, but dist/control-ui/index.html is missing or stale.
  4. Startup auto-repair is not a substitute for a correct build artifact. Startup repair may mask the bug, but it happens at the worst possible time: during gateway startup / LaunchAgent readiness / remote access recovery. It can be slow, can fail due to missing UI dependencies or platform-specific script execution issues, and it still allows users to observe readiness failures or a 503 before repair completes.

  5. Existing related issues show that documentation has not eliminated the class of failures. The issue has appeared in several forms: missing npm assets, source builds that do not emit control-ui/, incorrect command ordering, and startup repair edge cases.

Concrete reproduction of the build artifact gap

On current main, scripts/build-all.mjs has no ui:build step in the full or ciArtifacts build profiles.

A minimal artifact-level check is:

rm -rf dist dist-runtime
pnpm build

test -f dist/index.js
test -f dist/control-ui/index.html

Expected: both runtime backend and Control UI index exist.

Actual: the backend runtime exists, but dist/control-ui/index.html is not guaranteed by pnpm build; users must remember an extra pnpm ui:build step.

A service-level manifestation is:

# In a source/live runtime that serves Control UI from dist/control-ui
pnpm build
# restart the gateway / LaunchAgent that loads dist/index.js
# open the Control UI route

The backend can be live while the dashboard returns the missing-assets message above.

Related prior work

  • #65594 — packaging: runtime dist build does not emit control-ui/ when only pnpm build is run
  • #69050 — scripts: include ui:build in build-all pipeline
  • #45063 — docs fix confirming that tsdown cleans dist and therefore ui:build must run after pnpm build
  • #53050 / #52977 / #52932 — historical published/global install failures with the same missing Control UI asset symptom
  • #73059 — startup Control UI auto-build can be skipped in a Windows linked-source scenario

Proposed fix

Make the build pipeline enforce the invariant instead of relying on documentation:

  • Add ui:build to scripts/build-all.mjs after the tsdown / runtime postbuild cleanup steps.
  • Include it in the full and ciArtifacts profiles so pnpm build produces a complete source/runtime dist/.
  • Keep gatewayWatch / CLI-startup minimal profiles unchanged so backend-only dev loops stay fast.
  • Add a regression test asserting that ui:build is present and runs after tsdown.
  • Update docs and release/prepack hints so the full local dist contract is pnpm build.

Expected behavior

After this change:

pnpm build
test -f dist/control-ui/index.html

should pass without requiring a second remembered command.

Scope boundary

This is not proposing that every dev-loop rebuild should run Vite. pnpm gateway:watch and other explicitly minimal backend profiles can stay backend-only. The fix is specifically for the full source/runtime build contract exposed by pnpm build and CI artifact builds.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

After this change:

pnpm build
test -f dist/control-ui/index.html

should pass without requiring a second remembered command.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix Source/runtime builds can leave `dist/control-ui` missing because the UI build is only documented, not enforced