* fix(ui): restore visible gateway offline status and announce restarts in the sidebar footer
The sidebar footer has been the canonical offline indicator since #112600
(which deleted the top connection banner in its favor), but #125070's footer
compaction made it sr-only + aria-hidden - invisible to everyone. Restore the
visible red offline pill (click-to-retry, queued count, redacted error
tooltip) and add a restart-aware amber state: the gateway already broadcasts
shutdown { restartExpectedMs } before restarting and refuses drain-phase work
with reason "gateway-restarting", so the Control UI now shows "Restarting..."
immediately - before the socket drops - and degrades to the offline pill when
a restart overruns max(3x restartExpectedMs, 15s).
One shared renderSidebarConnectionStatus serves the main and settings
sidebars; the dead sr-only spans and clipped live region are deleted. The
drain reason strings become shared gateway-protocol constants. The e2e mock
now passes Vite's vite-hmr client socket through to the native WebSocket so
going offline in source-served suites no longer triggers a dev-client page
reload mid-test.
* refactor(ui): delete dead sr-only footer subtitle spans and fit the startup budget
The connected-state identity subtitle spans (gateway health dot, name,
build subtitle) were the same sr-only + aria-hidden dead-markup class the
previous commit fixed for offline: invisible to sighted users and screen
readers, with the identity button's aria-label already carrying the same
information. Delete them plus their orphaned CSS; tests now assert the
aria-label contract.
The e2e mock's Vite dev-client socket passthrough keys on the vite-hmr
subprotocol. The gateway store drops validation the shared timer clamp
already owns and re-arms the restart deadline on every fresh drain
rejection (server still says restarting, so amber stays honest). The
startup-budget baseline refresh (340901 -> 341446, jitter-safe max of
three builds) records the ~530 B this feature legitimately adds over the
512 B per-change tolerance; reason stored in the baseline file.
* fix(ui): keep ordinary gateway stops on the offline pill path
ClawSweeper finding: every shutdown broadcast armed the amber Restarting
state, so a deliberate stop hid the Offline/Retry action for the 15s
deadline floor. The amber state now arms only when the broadcast carries a
numeric restartExpectedMs; ordinary stops flow through the normal offline
pill. The server omits restartExpectedMs on non-restart shutdowns instead
of broadcasting null, aligning the wire with ShutdownEventSchema's
optional integer.
Also rewires build-info-unicode.e2e to the identity aria-label (the
visible subtitle span it asserted was deleted as dead markup) and splits
the restart-state store tests into gateway-store.restart.test.ts with a
shared test-support harness to respect the max-lines cap.
* chore(ui): tighten startup gzip baseline after composer-queue rebase
The combined tree measures 340754-340770 B across builds, below the
341489 B baseline main recorded for the composer stack; pin 340810 B
(max observed + jitter headroom) so the ratchet reflects reality.
* fix(ui): unexport the test-support fake gateway client (knip dead export)
* build(deps): remove npm shrinkwrap; mirror pnpm lock into transient package locks
npm 12 removed shrinkwrap (command + tarball/root loading). Delete all 82
committed npm-shrinkwrap.json files and stop publishing lockfiles; keep
pnpm-lock.yaml as the single reviewed dependency boundary. The generator
becomes scripts/generate-npm-package-lock.mjs and feeds plugin bundling via
a transient package-lock.json + npm ci (works on npm 11 and 12). Tarball
validation treats the published 2026.7.2 beta train as a shrinkwrap
transition; self-update npm detection now uses install topology instead of
the shipped shrinkwrap.
* fix(deps): repair lint, deadcode, and test-type lanes for the npm 12 migration
- sort integrity comparisons with an explicit comparator (oxlint)
- keep resolveBunGlobalNodeModules module-local (knip unused-export gate)
- model npm pack --json as npm<=11 array / npm 12 name-keyed object
- default calver destructuring in the tarball test fixture
The root package.json shipped "author": "", so npm showed no author for the
published openclaw package, and the three published workspace packages had no
author field at all. Set all four to the Foundation, matching the LICENSE
copyright holder and the openclaw.ai footer.
Also name the Foundation on the docs homepage, which never said who develops
OpenClaw even though the README and website footer now do.
Personal credits in docs/reference/credits.md, docs/start/lore.md, and the site
footer stay as authorship history; they are not org attribution.
* build(protocol): make @openclaw/gateway-protocol publishable to npm
* chore(mxc): align package version with release train
* fix(release): support gateway-only core packages