* fix(runtime): require Node releases that reject compromised CA keys
Require Node 24.22.1 or 26.12.1 even when SQLite capability checks pass.
Align active managed runtime selectors, archive checksums, image digests, native macOS selection, diagnostics, and coupled fixtures while preserving update recovery.
* fix(tooling): use pnpm that rejects compromised CA keys
* test(runtime): align pinned Node fixtures and generated guidance
* test(runtime): qualify service and update fixtures at patched Node floor
* fix(security): update Alpine test trust and aligned workflow contracts
* test: align guest runtime fixture and preserve mock exports
* fix: preserve standalone CLI commands across startup respawns
Resolve launcher-bound runtime arguments at the CLI invocation owner. Consume a one-child parent PID signal in compiled runtimes while preserving the loose preload and detached worker lifetimes.
* test: keep respawn transport guard independent of local names
* test: include respawn owner dependencies in CLI fixtures
Killing a hung openclaw doctor --fix left its respawned child alive (reparented to PID 1) and renewing sqlite-maintenance ownership, so every later Gateway start failed with 'undergoing offline maintenance' and stale-owner recovery never fired because the recorded owner was still alive. CLI respawns now carry an explicit launcher-bound lifetime marker; when the launcher disappears the owner is asked to cancel, rolls back and releases its lease while keeping custody during cleanup, and is escalated only after ten seconds. Detached update and handoff drivers stay independent by default and are never terminated because their launcher exited. Live on macOS: launcher killed → owner exits in 0.22 s, lock released, zero orphans, next Gateway HTTP 200, SQLite integrity ok. The separate zero-output Doctor hang is addressed by the bounded SQLite admission wait (#174060).
Fixes#174219
Preserve explicit profiles across standalone CLI respawns through one bootstrap-safe invocation owner. Select loose runtime/script arguments or direct compiled arguments from the embedded builder fact or adjacent manifest. Include the owner and compile-cache workers in packaged launchers and standalone builds.
Settle worker execution and native resource closure independently after snapshot failure. Release startup-refused broker claims only after native process and pipe closure, retain cleanup transport on operation failure, propagate Doctor snapshot errors, and cancel further inspections without losing maintenance restoration.
Document the private Unix-domain bind/connect allowance required by both loose and standalone snapshot workers. Keep network, home, Keychain, launchctl, and host-SQLite denials in the relocated verifier.
Validation: signed production-pinned JIT and bytecode artifacts at 4aa64f9ddc passed explicit-profile Doctor, Gateway/agent/restart campaigns, denied-IPC failure, and SIGTERM settlement in 364/375 ms with unchanged deadlines. Later source repairs passed owning-boundary regressions, scoped checks, and independent review. Signed artifact identity is preserved separately from the final CI head.
Exact-head CI for 9617855492: 172 successful jobs, 19 skipped, zero failures (run 38833042547). Tested merge 58c3b87a8594 has the same tree as the prepared PR head. No CI exception, rerun, or timeout increase.
Leave Node compile caching disabled on the Gateway main thread while preserving the shared build-scoped worker cache and existing worker flush boundaries. Remove the two synchronous Gateway flush calls that can stall cold startup.
Reuse the existing inherited-cache respawn handoff, preserving the supervised PID on supported platforms and the child bridge on Windows. Ordinary CLI caching and caller-authored disable settings remain unchanged. Permission-mode callers retain an already-active cache when process replacement may be forbidden.
Four alternating cold/warm runs retained worker caching, eliminated main-thread cache flushes, and passed the warm CPU regression gate. Focused regression proof covers main/worker cache state, Windows handoff, and POSIX signal propagation.
One-shot Node and Bun CLI commands no longer enable the automatic module compile cache, avoiding seconds of bytecode persistence after output. The shared cache-directory owner admits automatic caching for foreground Gateway runs and explicit prewarming; NODE_COMPILE_CACHE still opts one-shots in, and NODE_DISABLE_COMPILE_CACHE retains precedence. Windows Gateway supervision keeps caching and full CLI parsing.
Fixes the exit-tail regression introduced by #170514 (e517de8ca2). No disposer timeout, persisted configuration, schema, or update migration changes.
Lead warm-cache A/B, four interleaved samples with reused state: config get took 2.00s cache-off vs 6.54s cache-on on Bun, and 3.63s vs 5.55s on Node. The reviewed patch remains unchanged after integrating main's session-recovery type-fixture repair and offscreen message-reveal repair.
Validation: full build and focused owner/entrypoint/prewarm/wrapper checks passed. Exact-head CI run 38366283226 at 606b674016 completed successfully: 53 passed, 24 skipped, zero failures. Earlier inherited reds are documented in the PR; their admin attempt stopped before dispatch, and this refreshed head uses normal green-CI admission.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Enable a build-scoped Node compile cache for the direct Gateway entry and share its prepared directory with the packaged launcher. Retain recent release caches within the existing limits, preserve the Gateway PID, and keep cache scoping optional under Node permissions.
Verified cold/warm startup improvements and launcher/worker regression coverage. Inherited UI CI failures are documented with matching main-run evidence in PR #169365.
Related: #163788
## What Problem This Solves
Fixes commands hanging after output during forced Node shutdown without retaining the blanket Maglev and concurrent-Sparkplug workaround.
## User Impact
CLI commands and the Gateway finish owned work and cleanup before exiting naturally, with Node's default compiler settings restored. Exit status, Unix signal termination, output, explicit compiler overrides, and system-CA trust are preserved.
The Gateway still joins native skills-watcher retirement. This can retain synchronous FSEvents shutdown latency on macOS; the separate upstream certificate-loader stall is not fixed. Native macOS/Windows qualification is not claimed.
## Why This Change Was Made
Existing lifecycle owners retain admitted work, native workers, child transports, updater recovery, and watchdogs through actual completion. The boundary guard prevents new forced normal exits. Cleanup dependencies are retained before a command can replace its package, without eagerly importing them into CLI bootstrap. No new configuration, dependency, or schema is introduced.
## Evidence
- Earlier full pnpm build passed on composed tree faaafbe6b1f47e707f8392243898525990f3a452 (the terminal repair plus pinned CI base 97e81ce), including the canonical CLI-bootstrap import gate, in 4m35.7s. Explicit/requested exits restore terminal state after cleanup; ordinary completion stays reset-free. The build retains a Control UI startup-JS size warning; no budget was raised or waived.
- The built packaged CLI completed a real-PTY model round trip and exited naturally with status 0. Eight dual-TTY failure probes and twelve piped/dual-TTY telemetry probes passed. These used the built executable and existing helpers, not a claimed canonical Vitest smoke run.
- The composed memory helper parses with one run/execute binding and passes 20 publication tests. The final runtime, one-shot, and cleanup suites passed 40 tests, including red proof of premature watcher loading. Broker regressions: 84 passed; real-process negative controls cover IPC disconnect and Unix signal propagation after output settlement.
- The SIGTERM capture fixture retains its 20-second parent deadline and persistence assertions: red was 99 instead of 143; repaired case passed in 708ms (11.19s wrapper). The latest message/update fixture matrix passed 25/25 (179.52s): synthetic pending resources release only after observed stall diagnostics and join completion; ordered exit listeners remain checked. These later repairs change test/support files only, not production code.
- Latest pinned-main integration preserved QA error reporting without forced exit: 204 QA tests, 10 reconciliation tests, and 6 real service-child relay tests passed. The reconciliation case failed before removing an obsolete admission close. Scoped types, lint, and three-pass review are complete; this integration did not repeat the full application build.
- CI repair qualification: 96 tests across seven files passed (196.15s); final QA integration: 34 tests across three files passed (43.28s). Scoped types, type-aware lint, formatting, and mock-export checking passed. Fresh independent P0–P2 reviews found no actionable issues.
- Browser startup recovery: all three saved/chat/toast cases passed (35.743s). Output and local-chat shutdown regressions were exercised with the rebuilt CLI. Fixture repairs preserve native completion, privacy, output, and fallback-model assertions.
- Historical pre-integration proof: 115 affected test files; 137 built-executable cases with two platform skips; package-integrity checks; Linux Node 24.19.0 compiler activity and real Gateway SIGTERM-to-natural-exit in 175ms; published 2026.9.9 driver update with readiness and durable/incognito state checks. [Historical verification](https://github.com/openclaw/openclaw/actions/runs/38073218249). Compiler traces are functional witnesses, not throughput benchmarks or universal deadlock proof.
Current-head CI run 38106144930 is red: 12 failing test jobs are attributed to the tested baseline (294b2e3a), with complete job and source-bound evidence for native admission. They cover browser catalog/focus and a stale Details selector, channel mocks, Codex import/steering, and Claude discovery fixtures. None is claimed fixed or green by this PR. The original Gateway read-admission and node-wire timeout observations remain unreproduced, not declared fixed. Earlier local smoke preparation was refused by managed-artifact separation; no guard was bypassed.
Requested and directed by @steipete.
## Work sessions
- [Original discussion with @steipete](https://team.openclaw.ai/chat/roboclaw/dashboard/fcef23f8-a69b-4b60-9869-3bd40ac48588)
- [Implementation and verification](https://team.openclaw.ai/chat/roboclaw/subagent/c0adc270-c23a-4139-b3b7-00852b7db66f)
## Worked on by
- @steipete
<!-- openclaw-publication:09df66dc-cd63-4093-b782-154eeacdaa8f -->
---
[View the OpenClaw team session](https://team.openclaw.ai/chat/roboclaw/subagent/c0adc270-c23a-4139-b3b7-00852b7db66f)
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
2026.9.7 lengthened the compile-cache marker from <mtime>-<size> to build-<buildId>, which pushed cache paths on Windows into the directory-length window where Node 24's module.enableCompileCache() never returns (nodejs/node#66438); every OpenClaw process start could then spin at full CPU. The shared cache owner now uses a 16-character hash of the full build id as the marker, refuses Windows cache paths over 200 characters with a recorded warning (cache off for that process), and no longer propagates an unsafe inherited cache path to children. Legacy namespace handling and POSIX behavior are unchanged; native Windows/Node 24.18 completes the packaged CLI with a 220-character TEMP in 2.4 s.
Closes#162821
Remove Tasks and TaskFlow runtime, APIs, CLI, SDK surfaces and panels after the Cron, session, native execution and media completion ownership cutovers. Preserve stored rows and import provable legacy native assignments through Doctor; ambiguous ownership stays untouched with a warning.
Follows #158221, #158217, #158225, #158222, #158702 and #158776. Related: #156532. Task-specific public APIs retire immediately; retained responsibilities use their existing owners.
Maintainer-authorized administrative landing after full CI run 36312986498 attempt 2 passed on 274595e2, with subsequent actual conflicts reviewed and focused checks passing. Current PR CI preflight hits the 64 KiB changed-path metadata limit before tests (run 36335042695); its duplicate security-review status mirrors that planning failure. Review and scoped proof are recorded in the PR. Published 9.4 native import is proven; remaining native completion and 9.4 rollback witnesses are explicitly unproven.
Share build-scoped compile-cache ownership between the launcher and runtime. Reuse inherited namespaces, avoid redundant respawns, and retire superseded builds with best-effort seven-day and 512 MiB maintenance.
Testbox: 304 focused tests passed with one Bun-only skip; pinned changed-file checks passed. Thirty child launches used 41,544 bytes instead of 1,185,000 bytes, and same-build launch time fell from 2.46 s to 1.22 s. Persistent external-plugin source capture reuse remains outside this scoped change.
* feat(browser): unify local Chrome setup across desktop and terminal
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
* feat(browser): unify local Chrome setup across desktop and terminal
OpenClaw-Publication: d19e865e-b5a0-4c70-8876-c1662f6e7ef2
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
* chore(linux): format Chrome setup fixture
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
* feat(browser): keep desktop Chrome setup local and preserve pairing
Delegate Windows registration to the shared native management owner, preserve
released native bridge compatibility and saved launcher profiles, and integrate
serialized desktop setup through isolated local runtimes.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(browser): repair native setup CI contracts
Keep Windows installer dependencies acyclic, validate Unicode within the
package library target, and remove unused private exports. Require all
eight packaged native-host proof cases and update lazy CLI inventory.
Apply native Swift formatter diagnostics without changing behavior.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test(cli): account for plugin-owned browser extension catalog
Keep the core-only registration invariant aligned with the Browser plugin
owner already exercised by its lazy registration tests.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test(macos): retain released Chrome bridge request expectation
Align the native bridge test with the shipped contract1 request retained
by the canonical setup owner, and reject extra legacy payload fields.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test(tui): give command handler harness a unique export
Rename the shared TUI test helper and both consumers to avoid the
Gateway placement harness export collision. No alias or guard waiver.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* chore(sdk): allow canonical browser config path resolver
Apply the approved single public-export and callable allowance for
resolveConfigPath. Preserve canonical pre-config path ownership and
all other SDK surface checks.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(browser): preserve desktop setup selection and supported actions
Keep native automatic setup selector-free and resolve saved local browser
selection through the canonical setup owner before installation. Respect
Mac action advertisements and the released legacy install projection in
the Apps card, and document the public config-path resolver contract.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(auth): retry model selection after concurrent credential refresh
Adopt upstream PR #152426, commit 32298b10f6, without changing its five source files.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test: preserve native setup selection and await dashboard document
Match the selector-free native CLI arguments exactly and preserve a saved work-profile result. Wait through the existing document-readiness owner only at the quota test browser-proof boundary, after auth assertions.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(ui): avoid preloading already imported modules
Remove exact direct static JavaScript imports from lazy preload tables using the emitted build graph. Preserve HTML, lazy-only JavaScript, CSS, and locale hints. Source-exact CI merge reproduction drops startup gzip from 363283 to 362968 bytes without changing budgets. Add a real emitted-bundle regression.
Apply rustfmt layout to the native Chrome selector-free expected arguments.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix: preserve Chrome profiles and attachment follow-up branch binding
Let the TUI canonical setup controller retain its saved browser profile and project only a bounded returned name. Align both native first-run fixture expectations with selector-free setup.
Join pending chat history before the composer task handoff can expose an admitted attachment to restored-outbox delivery. Preserve idempotency, attachment custody, restored delivery semantics, and all existing assertions and timeouts. Add a deterministic regression reproduced on the exact failed CI merge and its main parent.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test(state): adopt canonical worker-custody fixture repair
Adopt src/plugin-state/plugin-state-worker.test.ts byte-for-byte from upstream bfec65a2a0 (#152456).
The former fixture held its late competing owner until after awaiting off-thread acquisition. Preserve that overlap, assert continued host authority checks and noncompletion, release custody, then assert the original result and persisted state. No production locking, guard, deadline or outcome assertion is relaxed.
Both prior failures reproduced on the exact CI main parent with independently installed frozen dependencies and Node 24.19.0. All 12 repaired file tests, selected state-logging types, scoped typed lint and fresh P0-P2 review passed.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(browser): retain saved Windows setup profiles
Recover configured extension profiles through bounded serial read-only C# inspection. Select only independently validated current matching descriptors, confirm the selected generation before effects, and leave the single mutation under the existing C# owner. Preserve POSIX behavior, existing manual relay verification and explicit same-profile repair.
Missing descriptors, runtime/origin drift and unknown or changing observations fail closed without automatic mutation. Keep raw management facts private and populate the existing browserProfile field only from validated binding metadata. No ABI, schema, SDK, configuration flag or registry/activation owner change.
29 actual CLI/controller/Windows-adapter boundary cases plus sibling coverage: 94 tests pass. Canonical changed checks, full production build and fresh independent P0-P2 review passed. Actual C# native proof remains separately coordinated.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(browser): preserve saved profiles after POSIX bundle relocation
Separate validated native registration ownership from supported origin-migration readiness. Recover the profile only after full private manifest and exact launcher validation; preserve the existing one-slot migration rule and all unsupported-origin, ACL and foreign-host refusals. Fail closed before selector-free installation when the saved selection cannot be proved.
Extract the unchanged shared origin helpers into a cohesive sibling to satisfy the existing line-cap guard without waivers. Windows admission, ABI and selector behavior remain unchanged.
Actual Linux/Darwin CLI-to-filesystem relocation regressions: 18 failures on original production, all 22 cases repaired. Preserve the private relay key and inode, config, Chrome preferences, work relay19444 and explicit-profile intent. 137 focused tests, eight real POSIX native-host E2E cases, canonical changed checks, full production build and fresh P0-P2 review passed.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(ui): retain input handoff through the shared outbox owner
Remove the superseded pending-history no-yield workaround after main introduced foreground submission custody in the shared outbox owner. Restore chat-submit-guard.ts exactly to pinned main cc7 rather than retaining competing timing policies. Keep passive drains fenced while the input task yields.
Preserve the retained history regression with explicit MessageChannel admission, no passive send before resume, and the same terminal leaf, idempotency key, attachment bytes and exactly-once assertions after completion. Original composed source fails all five focused cases; the repair passes 67 handoff/attachment cases and 20 real Chromium cases in the canonical secretless network-none runner. Canonical checks, UI build/performance and fresh P0-P2 review pass. No assertion, timeout, origin or proxy-policy weakening.
Browser POSIX/Windows repairs remain byte-identical to accepted255f. The failed e40e CI receipts remain preserved; fresh exact-head CI and parent handoff are still required.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(tasks): preserve reads across native event finalization
Hand joined event publication to its exact native successor after the native
flow and observer publication frame completes. Keep worker settlement and
cleanup, reversible claim transfer, current-authority and ABA checks, and
post-commit delivery in their existing owners without replaying writes.
Cover pre-result and readback finalization, native and reentrant successor
chains, rollback, failed publication, delivery, and terminal activity cleanup.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test(ui): retain rail baseline geometry on readiness failure
Keep the exact existing readiness predicate, fixtures, case inventory, assertion and timeout. When the predicate is false, retain synthetic marker identity and numeric geometry so hosted CI can distinguish scroll, visibility and viewport failures.
This is diagnostic evidence, not a repair or waiver of the unresolved rail failure. Local rootless browser infrastructure is unavailable; the existing hosted CI lane will verify the reviewed task-publication repair and collect meaningful rail evidence. Canonical changed checks and P0-P2 diagnostic review pass.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* docs(linux): describe saved-profile Chrome setup selection
Match the selector-free adapter argument vector and its regression test. Address the fresh P3 review finding without changing runtime behavior. Markdown syntax and diff checks pass; the generic formatter excludes this subtree.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* test(transcripts): join configured startup before cleanup faults
Observe and await the real startTranscripts promise through a narrow call-through spy while retaining the configured service entry point and real SQLite/provider work. Bind the await to the existing test lifetime instead of charging startup to the subsequent short active-map poll.
Gate provider return after persisted utterance to prove readiness does not settle early; retain both missing/unreadable row injections and all cleanup, private-source, lifecycle-token and summary assertions. Cover real startup rejection explicitly. No production change, timeout increase, retries or broad module/storage mocks.
The deterministic ordering boundary fails with the old fire-and-forget readiness and passes with the real promise join. Final 39 tests across 3 files, canonical changed checks and full-owner P0-P2 review pass. This does not recover whether the historical CI startup was late or rejected.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
* fix(browser): preserve automatic desktop status inspection
Restore read-only Device-page inspection for current and released Mac bridges while keeping installation and verification explicit. Preserve the native filesystem prerequisite proof, split installer repair tests within the existing line cap, and remove the superseded constant export.
* fix(browser): preserve registered setup configuration
Require canonical setup to match an owned launcher's effective state and
config selection before installation or relay access. Preserve equivalent
implicit/explicit default selections and the saved launch context. Recheck
automatic profile selection before effects and the current manifest before
publication through the existing registration owner. Keep manual install
and relocation repair contracts unchanged.
Cover mismatched configs, legacy selectors, equivalent defaults, selection
drift, and actual bootstrap after refused setup. Restore the missing Command
import in the existing Unix-only companion CLI test.
Focused tests, types, lint, fresh review, clean package build and sealed Mac
ARM64 runtime proof pass. The separate historical clock-jump CI failure has
bounded replay evidence and remains documented without a speculative fix.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
* fix(browser): keep setup registration types acyclic
Move the private registration status contract beside its context policy and
point both consumers at that owner. Remove the publication-module back-edge
without keeping an unused compatibility export.
The full architecture gate, extension production/test types, typed lint and
fresh independent review pass. Node's transformed JavaScript is byte-identical
for all three affected modules, so the existing runtime proof remains valid.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
* test(linux): handle Chrome setup in desktop sharing fixture
Recognize the exact automatic Chrome setup invocation and require its native
no-respawn flag. Keep unknown-command rejection, selected-auth validation,
process-group ownership and joined teardown assertions unchanged.
The original fixture reproduces the CI rejection against the real Linux app.
The repaired fixture passes all nine checks against that same binary, with
five Chrome setup calls and five node starts and joined stops. Fresh review
is clean; production app behavior is unchanged.
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
---------
Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
Co-authored-by: steipete <58493+steipete@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(node): update headless runtimes automatically when idle
Stage private packaged node runtimes and activate only after all owned work
and cleanup settle. Preserve pairing and launch options, keep automatic
activations at least 12 hours apart, and leave shared-state migration and
Gateway installation ownership with the normal updater.
Document defaults, opt-outs, runtime version discovery, and recovery.
Support recoverable Windows selector replacement across service restarts.
Refs #151462
* fix(node): complete auto-update integration and settings defaults
Capture the launcher in compiled test runtimes and trusted wrapper inventories, register the package update proof, and use the canonical Kysely read path. Preserve the inherited enabled state in the config UI and align caller tests with the node shutdown lifecycle.
* fix(node): preserve retained plugin work during automatic updates
Require an explicit idle result from plugin commands, preserve older-plugin work, and connect bundled lifetime owners to automatic node updates. Join canceled inference and failed terminal cleanup before command settlement; keep historical state repair with Doctor. Document compatibility and extend installed-package proof for retained legacy plugin work.
* test(browser): align idle-work fixtures with runtime exports
* test(browser): extract proxy request fixtures
* test(node): retain idle assertions across native cleanup
* refactor(runtime): probe SQLite startup capabilities in a worker
Move current-runtime capability SQL off the main thread and share one pending result across launcher and runtime callers. Await worker exit before admission, preserve failure caching and Bun library selection, and retain the native SQLite SDK and foreign-runtime probe contracts.
* test(config): expose include provenance in writer failures
Carry the bounded consumed-snapshot, provenance, and include-boundary assertions from 3de18f60bd (#143587). Preserve the observed snapshot and all existing writer/exclusion assertions. The hosted failure cause remains unresolved.
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
* fix(update): report the built runtime instead of the unbuilt source version
A git checkout that pulls without rebuilding keeps executing the previous dist,
and every surface an operator would check hid that. `openclaw --version` read
the source package.json while the commit came from the build, so a machine
running a 2026.8.1 build reported "2026.9.2 (1623683)" — a version that was
never compiled. `openclaw status` reported HEAD with no hint that dist lagged.
Prefer build-info.json for the version (source runs have none and still fall
back to package.json), and report the built commit in the update row when it
differs from HEAD.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rTGeD4bUUEvA6vupgJt4d
* test(update): cover built-commit provenance reads
Pins the null results that keep source-only checkouts from being reported
as running a stale build.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rTGeD4bUUEvA6vupgJt4d
* fix(update): apply built-version precedence to the launcher fast path
`openclaw.mjs` answers bare --version/-V/-v and exits before the runtime
entry loads, so the resolver change alone left the packaged CLI reporting the
source version. Its commit half already preferred dist provenance, which is
how a stale build printed a source version paired with a built commit.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014rTGeD4bUUEvA6vupgJt4d
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix(runtime): reuse an available compatible Node at startup
Share startup recovery between the launcher and legacy CLI runtime admission
so older updaters can run target Doctor through dist/index.js under an
already installed compatible Node. Preserve process-contract exclusions,
arguments, environment, standard streams, and exit status.
Refs #140465
* test(runtime): include recovery proof in E2E routing
* fix(runtime): secure Node discovery and decode service scripts
Reject relative candidates and cwd-resolved runtimes before probing, except
for explicit absolute PATH directories. Parse generated Windows command
quoting and recorded code pages without loading application dependencies.
Skip CP850 and CP949 with a diagnostic instead of guessing executable paths.
Use real task-writer fixtures for encoding, quoting, and fallback coverage.
Refs #140465
* fix(runtime): reject cwd-local manager symlinks
* test(runtime): keep recovery home outside launcher cwd
* fix(runtime): isolate recovery from dotenv environment
* fix(runtime): canonicalize discovery paths before use
* fix(runtime): preserve private Node recovery from home
* refactor(runtime): trim Node recovery comments and aliases
Behavior-neutral cleanup of the recovery launcher module: fold the serviceHome and managerHome aliases into homeDir and shorten five comment blocks to the invariant they protect.
* fix(runtime): keep diagnostics and update usable on an unsupported Node
Share CLI admission between the launcher and source guard, retain private-copy
SQLite recovery, and keep live database writers and repair agents refused.
Route plain Doctor to lint and refuse update before its run-ledger admission
when the CLI Node is unsupported. Report CLI/service runtime findings and the
reporting Node version in update-failure reports.
Refs #140672#142742
* docs(install): explain private Node recovery and diagnostic access
* test(runtime): preserve Node recovery coverage with diagnostic admission
* fix(runtime): offer Node recovery once per update invocation
* fix(build): emit Node 22 syntax for recovery diagnostics
* fix(update): check runtime at the state preparation boundary
* fix(doctor): preserve migration order before runtime diagnostics
* fix(runtime): recover before admitting unsupported Node diagnostics
* fix(runtime): preserve capability admission in diagnostic recovery
* test(cli): retain capability checks in startup fixtures
* refactor(runtime): share Node findings across diagnostic commands
* fix(doctor): omit absent repair hints in lint errors
* fix(runtime): gate node:sqlite on a NUL round-trip capability probe
Validate the loaded SQLite library and TEXT, BLOB, and JSON round trips across startup, doctor, Gateway install, update preflight, and installers. Admit capable Node 24+ vendor builds with a support-policy note while retaining the package engines and Node 22 exclusion. Refs #140465#140672.
* fix(runtime): expose capability diagnostics through doctor
Register the runtime check in the ordered Doctor contribution catalog. Keep shared audit types in a leaf module, include the bootstrap probe in duplicate scanning, and update native runtime and compiled-worker fixtures for the capability protocol.
* fix(update): preserve target Node version requirements
* fix(install): remove unused Node major probe state
* feat: offer Node.js updates when the CLI runtime is incompatible
* fix: include Node runtime recovery in duplicate scans
---------
Co-authored-by: Morrow <morrow@bluedot.it.com>
* fix(runtime): require Node builds with lossless SQLite reads
* fix(runtime): preserve upgrades and guard sealed workers
Validate downloaded Node before switching the active runtime alias, reject unsupported sealed-worker runtimes, and keep the Gateway error fixture on a supported Node release. Document the approved ARMv7 and older macOS compatibility losses and decoder fix boundaries.
* test(runtime): use typed process exports in worker fixture
* test(runtime): align installer fixtures without growing test shards
* test(runtime): align release and guest runtime fixtures
* fix(test): canonicalize Windows temp roots for Node 24
Expand Windows short paths before creating test directories and owned child environments. Node 24 filesystem watchers otherwise abort when native long event paths differ from inherited short temporary paths. Preserve explicit custom-root spelling and existing cleanup ownership.
* test(ci): run Windows temp-root regressions in the native lane
## Summary
- Preserve the lexical package entry through the packaged compile-cache respawn.
- Refuse package updates when no package manager owns the active package root.
- Keep pnpm ownership tied to one active global project, never its shared-store realpath.
## Problem
`openclaw update --dry-run` could classify a pnpm 11 global install as npm after the launcher respawned through the shared-store package path. A real update could then create a second npm install while the pnpm-owned Gateway stayed on the old package.
## Root cause
The packaged compile-cache respawn replaced the pnpm-generated hash-link entry in `process.argv[1]` with `import.meta.url`. The latter resolves to shared package content and has no global-project ownership identity. Manager detection then fell through to npm.
## Fix
The launcher passes the lexical entry to its child. Existing pnpm owner discovery then resolves the exact active project, carries its prepared install target through dry-run and mutation, and rejects grouped, multiple, orphaned, or mismatched owners. Package roots with no proven owner now stop before stale-handoff cleanup, with recovery guidance, instead of falling back to npm.
## Proof
- Red: a real isolated pnpm 11.25.0 global install of `openclaw@2026.8.1` reported `mode: npm` when compile-cache respawn was active.
- Green: the same non-mutating dry-run on the repaired launcher reported `mode: pnpm` and the active hash-linked project root.
- The green trace contains only pnpm probes and no npm command.
- The complete pnpm global-project tree was unchanged after dry-run.
- Focused launcher, owner-discovery, target-carry, ambiguity-refusal, and no-cleanup tests pass: 87 passed, one platform skip.
## Size
- Production: +10/-6, net +4 lines for lexical ownership preservation, fail-closed package detection, and pre-mutation cleanup ordering.
- Tests: +69 lines at the launcher, command, and package-owner boundaries.
Fixes#134037
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
## Problem
A pnpm 11 global update from OpenClaw 2026.7.1-2 to 2026.8.1 fails verification and rolls back. The 2026.8.1 package puts `openclaw-install-guard` inside `dist/`, but the old updater treats every uninventoried `dist/` file as invalid.
## Root cause
Package lifecycle state was stored inside the closed `dist/` inventory. That made a valid pending lifecycle marker look like package corruption to an older updater.
## Fix
- Store pending lifecycle state at package root as `.openclaw-lifecycle-pending`.
- Let postinstall remove the marker only after all lifecycle work succeeds.
- Use one lifecycle completion owner from the updater, `dist/index.js`, and `openclaw.mjs`.
- Keep the lifecycle lock valid beyond the full preinstall and postinstall timeout budget.
- Keep temporary recovery support for the 2026.8.1 `dist/openclaw-install-guard` path.
- Keep source package preparation and worker package generation aligned with the new marker contract.
## Product proof
- Red: a published 2026.7.1-2 pnpm 11 install rejected the published 2026.8.1 package with `unexpected packaged dist file dist/openclaw-install-guard`, exited nonzero, and remained on 2026.7.1-2.
- Green: the built candidate passes the old-updater upgrade path, the pnpm 11 lifecycle-repair path, a forced postinstall failure and retry, and native npm controls.
- Anti-cheat: the proof checks the installed CLI version before and after the update.
## Validation
- `node scripts/run-vitest.mjs src/infra/package-lifecycle.test.ts src/infra/package-update-steps.pnpm11-guard.test.ts src/index.entrypoint.test.ts`
- Focused lifecycle, updater, tarball, postinstall, inventory, and entrypoint suites: 176 tests passed.
- Exact-head lifecycle lock suite: 4 tests passed, including the old 20-minute expiry boundary.
- Remote core and scripts checks passed.
- `git diff --check`
- GitHub CI is the full release and platform gate.
## Scope
- Production and release-tooling delta: +370/-162, net +208.
- Test and CI support delta: +370/-84, net +286.
- The production growth adds the shared lifecycle owner, crash-safe retry marker, and concurrent-launch lock. It removes the updater-only lifecycle sequence and keeps the closed `dist/` verifier unchanged.
- Sibling coverage: updater, package launcher, legacy package entrypoint, installers, tarball validator, worker bootstrap package, and Docker package preparation.
## ClawSweeper
- No actionable code findings.
- Rank-up skip: the package-upgrade trace came from an internal isolated runner and is not suitable for a public log attachment. Exact-head GitHub CI and the focused regression commands above remain the public proof.
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(infra): prevent dollar-pattern injection in home dir tilde expansion
String.replace interprets dollar-amp/dollar-1/dollar-backtick in the
replacement string. When the home directory contains these sequences
(e.g. a username with a dollar sign), tilde expansion via
.replace(/^~/, fallbackHome) corrupts the path silently.
Use a function replacement so the home path is treated literally,
matching the pattern already fixed in terminal-core/display-string (#111398).
Two call sites: resolveRawHomeDir and expandHomePrefix.
* fix(daemon): prevent dollar-pattern injection in state dir tilde expansion
Address review rank-up: the daemon state-path expansion deliberately does
not use the core helper and still passed home as a string replacement.
Apply the callback form here too and add a literal-dollar regression to
the existing service-env suite (fails on the string form, passes with
the callback).
* fix(launcher): keep literal $ patterns when expanding tilde OPENCLAW_HOME
* fix(ui): keep literal $ patterns in local media tilde expansion
* test(ui): prove literal-$ tilde local media preview through Control UI e2e
* test(ui): align literal-dollar media proof with compact attachment contract
Preserve the current authenticated metadata and ticket-scoped download behavior while exercising the real Chromium Control UI under a literal-dollar home.
Co-authored-by: liyuanbin <li.yuanbin1@xydigit.com>
---------
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(runtime): allow Bun runtimes that provide node:sqlite
* fix(process): drop execa buffer encoding under Bun spawn (Bun rejects non-spawn options)
* chore(process): cite oven-sh/bun#36049 in bun spawn workaround
* docs(install): bun with node:sqlite can run openclaw; bun install workspace caveat
* fix(process): clear execa buffer encoding under Bun without mutating read-only options
* perf: speed up precomputed command help
* perf: precompute sessions and tasks help
* Speed up precomputed command help startup
* Speed up precomputed command help startup
---------
Co-authored-by: Zeheng Huang <153708448+hunjaiboy@users.noreply.github.com>
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>