* fix(onboard): honor secret-input-mode ref for the generated gateway token
`openclaw onboard --secret-input-mode ref` was silently ignored for
`gateway.auth.token`: onboarding generated the token and wrote it into
`openclaw.json` as a plaintext string, so `openclaw doctor` warned about
`gateway.auth.token` on the install it had just created. The flag was
honored for provider credentials, so an operator who explicitly opted into
references still ended up with a plaintext secret and a remediation
(`openclaw secrets configure`) that cannot migrate a self-generated value,
because it validates a ref by resolving one that already exists.
Setup mints this token itself, so reference mode now provisions it:
- an ambient OPENCLAW_GATEWAY_TOKEN keeps an `env` ref to that variable, so a
later rotation stays authoritative instead of being pinned by a stale copy
- anything else (freshly generated, or an existing plaintext token being
migrated) goes into the shared SQLite secret store as a write-only `secret`
entry, with config holding only `{source:"store",...}`
An existing store entry wins over a freshly generated one, so reruns never
rotate a token already paired with clients. The store write precedes the
config write: a ref persisted without its value would leave the gateway
unauthenticatable, while an orphaned entry is reused by the next run.
The interactive wizard had the same dead end and is fixed the same way.
Default (plaintext) onboarding is unchanged.
User impact: `--secret-input-mode ref` now keeps the gateway token out of
openclaw.json, and a fresh install no longer self-reports a plaintext-secret
warning.
* test(onboard): split gateway onboarding suite under the max-lines gate
The added gateway auth-token tests pushed
onboard-non-interactive.gateway.test.ts to 1014 lines, over the max-lines
limit (check-lint-core-3). Repo policy is to split, never suppress.
Extract the shared vi.mock/harness preamble into
onboard-non-interactive.gateway.test-mocks.ts, following the existing
agent-command.test-mocks.ts pattern, and move the four gateway auth-token
storage tests into their own suite. The reachability mock becomes a holder
object so both suites can swap it across the module boundary, and hoisted
mocks are re-exported in a separate export clause because Vitest rejects
exporting a vi.hoisted binding at its declaration.
Test set is unchanged: the it-declaration multiset matches the pre-split
file exactly, with no duplication across the two suites.
* test(onboard): give the shared gateway onboarding mocks unique export names
check-export-name-collisions flagged `runtime` and `readConfigFileSnapshotMock`
as colliding with program.test-mocks.ts and plugins-cli-test-helpers.ts once the
gateway onboarding preamble became a shared module. Rename the exports to
gatewayOnboardRuntime / gatewayOnboardConfigSnapshotMock per the repo's
unique-export-name rule; suites alias them locally so the assertions read the
same as before.
* test(tooling): route the new gateway auth-token suite from its test helper
test-projects asserts which suites a change to
onboard-non-interactive.test-helpers.ts should run. The new
onboard-non-interactive.gateway-auth-token.test.ts imports that helper, so it
belongs in the expected routing plan.
Host zlib versions compress identical startup assets into different bytes, causing false Linux budget failures. Emit canonical shipped pako gzip sidecars, restore the 512 B ratchet tolerance, and lower the startup baseline from 348351 B to 344531 B.
* fix(config): validate config writes against the config being written
writeConfigFileFromContext passed the pre-write snapshot's plugin
metadata into strict validation. During onboarding that snapshot belongs
to an intermediate config written by agent creation, which has no plugin
entries, so its scoped manifest registry is empty. Validating the final
candidate against it made every plugin entry added by the same write look
unknown, and non-interactive onboarding warned that the openai and codex
entries it had just written were stale or uninstalled.
Drop the stale snapshot so validation resolves the manifest registry from
the candidate it is actually validating. Strict semantic validation is
unchanged, and the registry load stays lazy.
* fix(ci): raise the Control UI startup JS baseline to unblock main
main is red on the Control UI startup-JS ratchet: unrelated PR #126725 measures 348289 B and this branch measures 348351 B against a 347023 B baseline + 1056 B tolerance. Twenty-six UI commits have landed since the last bump (#126474), none individually large. Baseline moves to the CI-measured 348351 B, well under the 358400 B maintainer-approved ceiling that still guards cumulative creep.
Give maintainers immediate visibility when Mantis is requested. Bare mentions now react, link the active run, and keep one run-owned status comment through proof, short-circuit, or failure.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(gateway): admit recovering workers during startup
* fix(gateway): admit recovering nodes during startup
* fix(crabbox): bind worker desktop to XFCE session
* fix(workers): reuse Git base during workspace transfer
large clean/stale worktrees were downloading every tracked file after the verified base pack, crossing transfer authority; selectively checkout desired base-index paths, preserving deletions and symlink confinement.
* fix(workers): clone reachable stale workspace commits
tip-only origin detection forced published ancestor commits through heavyweight Gateway transfer; the existing exact checkout and manifest verification safely own reachability/fallback.
* perf(workers): use blobless origin clones
* fix(workers): bundle undici in worker deploy artifact
Add trusted ClawSweeper-label and maintainer-comment dispatch for Mantis Telegram proof. Short-circuit non-visible PRs before desktop setup while preserving exact-head, fork, credential, and comment-ownership boundaries.
Move Mantis Telegram Desktop proof from the remote AWS/Crabbox lane to a recorder-driven local Docker desktop. Keep proof scenarios agent-authored, cache trusted build outputs, and publish exact visible Telegram evidence without writing the QA bot token to artifacts.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
The "includes weekday and relative time" test computed the expected
weekday with the ambient host locale (`toLocaleDateString(undefined, ...)`)
while `formatNextRun` formats the weekday through `i18n.getLocale()`
(default "en"). On hosts whose default locale is not English (e.g.
`LANG=zh_CN.UTF-8` -> "周一"), the two diverge and the slice assertion
fails: `expected 'Mon,' to be '周一, '`.
Mirror `i18n.getLocale()` in the test so the expected weekday always
matches the locale the presenter uses. No production behavior change.
Verified: passes under `LANG=zh_CN.UTF-8` and `LANG=C` via
`pnpm test:unit:fast -- test/ui.presenter-next-run.test.ts`.
AI-assisted.