mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-31 20:47:00 +00:00
17 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
082eef88b6
|
fix(node): keep the selected profile's service name for node install --profile (#180288)
node install --profile took the default node's service name, so a profiled node collided with the default service. The node-service identity owner now preserves the selected profile across installation, lifecycle commands and the stored environment; the default profile is unchanged. Supersedes #178342, thanks @MertBasar0. Co-authored-by: MertBasar0 <mertbasar0@hotmail.com> |
||
|
|
73ac5d64fd
|
chore: update stock Bun to 1.4.3 (#171627)
Select stock Bun 1.4.3 consistently across setup, cached archives, Docker, package smoke, supported-runtime documentation and runtime admission. Preserve the pinned OpenClaw fork and remove the upstream-fixed grapheme lookup workaround. Reject obsolete Bun in the standalone Team controller before activation. Proof: focused Node/stock Bun/pinned-fork behavior, admission and preinstall checks; setup/action syntax checks; verified multi-architecture Docker digest; 26 passing Linux controller tests and a before/after activation regression. Independent Codex P2 review and exact-head ClawSweeper found no remaining actionable issues. Exact-head CI: https://github.com/openclaw/openclaw/actions/runs/38617609269. The PR records inherited wrapper-inventory failures and Node-only load-wave timing pressure with baseline/source evidence; native admission retains the failed CI result and checks all remaining gates. |
||
|
|
2c87e33399
|
feat(sessions): run sessions in existing folders on paired devices (#169722)
Related: #136048 (non-Git directory semantics) and #142521 (non-Git worker workspace context; this PR does not implement ephemeral cloud workspaces). ## What Problem This Solves Device-hosted sessions required a Git repository or managed worktree, a constraint inherited from ephemeral cloud sessions, even when a paired personal machine should simply work in an existing non-Git folder. ## User Impact Users can choose **Existing folder on device** in New Session and run a session directly in an existing folder on a paired session-host device. OpenClaw does not create Git metadata, copy the folder to the Gateway, or sync, reconcile, reset, or delete it. - `nodeHost.workerRuns.folders` is node-local consent: unset allows existing directories, a non-empty list restricts selection to those roots and their descendants, and `[]` disables the feature and its capability advertisement. - The session stays pinned to that device: Auto/cloud dispatch, Move, and Continue on Gateway are refused. Attachment staging and the Gateway Files panel are unavailable for these sessions. - Worker HOME stays in private node storage. Files are not locked against external changes. ## Why This Change Was Made - `sessions.create` accepts `deviceFolder: { deviceId, path }` (requires `operator.write`); the binding is stored on the existing session entry and the `device-folder` workspace kind reuses the worker execution and lifecycle owners. - The node owns folder policy and re-validates on every use: absolute or `~` paths only, realpath resolution (symlinks cannot escape a root), no filesystem root, no overlap with private worker storage, and a dev/ino fence between acquisition and execution. One shared rule in `node-workspace-protocol.ts` forbids preparing, resetting, transferring, seeding, or quiescing a device folder, for both ingress parsing and direct node execution. - Gateway shutdown reads the teardown scope from the durable placement, so stopping an attachment with no in-memory tunnel no longer reaches closed worktree admission. - A restored existing-folder create retry is owned by its frozen request; current device capacity or runtime no longer blocks it. - Attachments are refused for device-folder sessions before anything is persisted: `chat.send` rejects them with a clear message, New Session blocks Send while attachments are attached, and worker media preparation never restages historical attachments into a device folder, so one refused file cannot make later turns fail. - Security tradeoff: a session-host node already runs operator-directed agents with exec, so the allow-all default does not widen that boundary. The folder list is a selection guardrail, not an exec sandbox or a boundary against a compromised Gateway. Deployments that contain `operator.write` with `tools.fs.workspaceOnly` should also set a root list; the docs say so. - Control UI selection/path input, plus docs for node configuration, session hosting, operator scopes, and workspace behavior. ## Screenshots Synthetic mocked-Gateway captures (no real paths or tokens). **Before — only the managed/new-workspace choice**  **After — desktop existing-folder input**  **After — mobile layout**  ## Evidence - **Cross-machine E2E on the final feature code:** a disposable Gateway on one Mac (tailnet TLS, token auth, QA mock model) and a session-host node on a second Mac, both on the same exact head, with `folders` unset and an existing non-Git target folder on the second Mac. Pairing and capability advertisement; create + explicit dispatch (`active`, workspace = the device folder); hosted exec wrote `pwd` and `hostname` into the folder, confirmed by independent readback on that Mac; node restart and an unclean Gateway restart, then a second turn appended to the same file; `~` and a Gateway-only path rejected; reclaim + delete left the folder, sentinel, and absence of `.git` unchanged with no copy in Gateway state. - **Isolated single-host E2E (25 checks, all pass):** missing/root/file/relative/private-storage rejections; auto-dispatch rejection; node restarts; clean Gateway shutdown with a live tunnel and with a durable attachment but no tunnel; Gateway restart and resume; symlink escape and outside-root rejection under a root list; `[]` disables the capability. - **Attachment refusal, live:** on the isolated Gateway, a `chat.send` with a text attachment to a device-folder session returns the refusal, the attachment never enters history, and the next text turn and later turns after node and Gateway restarts complete in the folder. - **Authority, live (real Gateway WebSocket, no mocks):** an operator client granted only `operator.read` + `operator.sessions.write` sends `sessions.create` with `deviceFolder` and gets `FORBIDDEN` / `missingScope: operator.write`; no session row exists afterwards and a debugger logpoint on the node records no workspace command for that request. The full `operator.write` client creates and dispatches the same folder (`active`). - **Device revocation during awaited admission, live:** with the node process tree stopped (`SIGSTOP`) while `sessions.create` and `sessions.dispatch` wait on it, `devices remove` succeeds, then `SIGCONT`. Create fails with `Selected device changed during folder validation; retry` and leaves no row; dispatch fails with `Device worker installation connection is no longer current`; the node is then disconnected and its old token is rejected. Known bounded behavior: the read-only folder validation request already delivered to the stopped node still runs once on resume (1 ms after removal) before the close frame arrives; its result is discarded, nothing is persisted, and no session command runs. Unit coverage also revokes the caller (real `captureGatewayDeviceRevocation` capture) and the device during validation. - **Requesting-operator revocation during awaited admission, live:** separate signed operator devices with `operator.write`, real paired node stopped with `SIGSTOP`. Removing the operator while `sessions.create` waits on folder validation: the client gets `gateway closed (4001): device removed`, `sessions.describe` returns `{"session":null}`, the key is absent from `sessions.list`, and the node trace has no worker execution command. Removing a different operator while `sessions.dispatch` waits: the session moves from `provisioning` to `{"state":"failed","terminalReason":"Gateway requester authority changed"}`, `hasActiveRun` is false, and no worker command runs. As with device revocation, one already-delivered read-only folder validation runs on resume and its result is discarded. - **Inline initial turns are refused:** `sessions.create` with `deviceFolder` plus `message`, `task` or `attachments` is rejected before node I/O; the UI already sends the first message through `sessions.send` after dispatch. The three new cases fail with the validator removed (`3 failed | 12 passed`) and pass with it (`25 passed`). - **Upgrade compatibility, live:** the `main` merge-base build created a plain session and an explicit-cwd session (turn `ok`); the PR build on the same state dir lists and describes both with their original IDs, a new turn on the old session completes `ok`, and Doctor exits 0 with no session-row load errors. - **Upgrade from stable `v2026.10.3`, live:** the stable build created a plain session with a completed turn, an explicit-cwd session, a custom model alias and a non-default `thinkingDefault`. Direct startup on the new build exits 78 with "uses schema version 24; … run openclaw doctor --fix" on both this PR and the plain `main` merge base (inherited). After `openclaw doctor --fix --non-interactive` (`v24 -> v26`), the PR Gateway starts, both old sessions list and describe with their original IDs, both settings read back unchanged, a new turn on the old session returns `ok`, and a new device-folder session created after the upgrade dispatches and runs a turn in the folder. One session-event publication warning about an unsettled worker-environment mutation appeared during that dispatch; the turn still succeeded. - **Focused tests:** device-folder node, tunnel, create, protocol, media, submit-gate and draft-state suites pass; the restored-retry and history-restage regressions fail before their fixes. - **Hosted CI:** on the exact head `364a000`, every job passes on the first attempt, and so does the Security Review, except `checks-ui-e2e (8/9)`. That job runs `plugins-lifecycle.e2e.test.ts`, which also fails the same way on plain `main` (see the maintainer override comment). Earlier heads hit flaky qa-lab E2E tests and `main`-side ratchet failures that plain `main` also reproduces. ## Merge Danger Additive optional protocol field and session-entry JSON field; no SQL schema change. Older Gateways reject the new `sessions.create` parameter; older nodes do not advertise the capability, so the option is not offered. Revert removes the feature; existing device-folder sessions would then be unrecognized but their folders are untouched. Co-authored-by: Ayaan Zaidi <hi@obviy.us> |
||
|
|
a881a23b3b
|
docs: simplify tool, node, and plugin guides (#168699) | ||
|
|
84e59beb3c
|
fix(node): keep npx-installed services outside the npm cache (#168644)
## What Problem This Solves
Fixes node services installed through `npx openclaw connect <join-url> --service` or `npx openclaw node install` pointing at npm's disposable `_npx` cache.
## User Impact
The one-paste command installs the selected OpenClaw release into a durable npm prefix under the node's state directory before writing the service. Removing npm's exec cache no longer removes the service's executable. Installation prints the package version, chosen runtime, service command, and a fresh-npx node update command.
## Why This Change Was Made
The service argument resolver previously used the running package's resolved path. #167905 fixes pnpm's replaceable store-generation paths by selecting its existing stable link; npm exec has no stable link to select. This preserves that pnpm behavior and adds node-install promotion through the existing npm update owners (`resolveGlobalInstallTarget`, `runGlobalPackageUpdateSteps`, and their staged publication/rollback/cleanup).
There is one `<state-dir>/npm` prefix, not a prefix per release. The normal state-directory/profile resolver chooses its location. Run `npx -y openclaw@latest node install --force` on the node to update it, retaining the same profile/state-directory settings. An exact version or `@beta` can replace `@latest`. Reinstalling an already-selected version repairs damaged package files. No new settings or package manager.
This does not change `openclaw update` or its existing co-located Gateway selection behavior. Node auto-update still follows the node's npm channel, not the connected Gateway's version/build. The rebase preserves #168653's paired-credential filtering and explicit `--auth-from-env` service argument.
No overlap with Pash/Sarah changes.
## Evidence
Final code: `27b447dc07b737126124ff8847f2059cb8a4f921`. Packaged live proof ran on `292bd19fe934ecf4ee4e3b20b00a03a1b08f7933`; production feature code and docs are unchanged since that proof. The final revision only corrects regression-test platform handling and rebases onto green main.
- **Before:** the regression on baseline `
|
||
|
|
1bc9624c8a
|
fix(node): keep paired credentials after service enrollment (#168653)
## What Problem This Solves
Fixes paired nodes failing to authenticate after `openclaw connect <join-url> --service` when the machine already has credentials for another Gateway.
## User Impact
A node reconnecting to its saved Gateway uses its paired device token instead of an unrelated Gateway token or password from the machine's environment, configuration, or state-directory `.env`. Paired service installations no longer persist those ambient credentials.
Intentional shared-token/password connections remain supported through `openclaw node run --auth-from-env` and `openclaw node install --auth-from-env --force`. This exposes the existing foreground override and records that explicit choice for installed services. If it displaces an available paired credential, the warning names the selected environment variable, never its value. No new configuration keys or token migration are introduced.
## Why This Change Was Made
The node credential owner already recognized a saved pairing but still treated every populated `OPENCLAW_GATEWAY_TOKEN` / `OPENCLAW_GATEWAY_PASSWORD` as an explicit override. The service planner also persisted those ambient values. Environment variables loaded from `env.vars` or the state-directory `.env` therefore had the same effect as an intentional override.
The runtime and service planner now share the same saved-endpoint eligibility check. Default reconnects leave device-token selection and refresh with `GatewayClient`; explicit shared auth uses the existing environment-only path. GatewayClient's trusted-endpoint retry policy is unchanged.
This retains the intent of [#31122](https://github.com/openclaw/openclaw/pull/31122) (intentional service environment credentials survive restarts), [#136253](https://github.com/openclaw/openclaw/pull/136253) (a co-located Gateway must not displace paired-node auth), and [#159360](https://github.com/openclaw/openclaw/pull/159360) (expired fallback setup codes may only resume the saved pairing; no expired bootstrap or shared-auth fallback).
## Evidence
- On baseline `
|
||
|
|
8f91e4bb65
|
improve: default device joins to session-host services (#168623)
## What Problem This Solves Newly joined machines default to a foreground, command-only node, while New Session gives already-paired devices an invalid reconnect command and misleadingly says no session hosts are paired. ## User Impact The CLI and Control UI now offer `npx -y openclaw connect <join-url> --service --session-host` by default. It installs a background node service that can run agent sessions, with a command-only service alternative. The UI shows the full command instead of clipping its consent flags. Session hosting remains an explicit device-local choice in the pasted command; the node runtime's default is unchanged. Use hosting only on trusted shared Gateway infrastructure. Already-paired devices get the supported `openclaw config set nodeHost.workerRuns.enabled true`, then `openclaw node install --force` instructions. The empty-host hint distinguishes pairing from enabling hosting. ## Why This Change Was Made Preserves the one-paste, single-use onboarding contract from [#122499](https://github.com/openclaw/openclaw/pull/122499) and [#122635](https://github.com/openclaw/openclaw/pull/122635). Corrects the remediation introduced in [#145183](https://github.com/openclaw/openclaw/pull/145183) using the saved-pairing service path documented by [#159810](https://github.com/openclaw/openclaw/pull/159810). The join handler is its own lazy CLI module rather than adding more responsibilities to the device-management runtime. `-y` only skips [npm's package-install confirmation](https://docs.npmjs.com/cli/v11/commands/npx/); it does not replace OpenClaw consent. No package version is pinned. No overlap with Pash/Sarah changes. ## Evidence - Regressions fail on baseline ` |
||
|
|
9148fbb46a
|
fix(nodes): explain and recover session-host setup problems (#160188)
* fix(nodes): explain and recover session-host setup problems Report unsafe workspace ancestry before dispatch, resume pending node pairing after approval, explain runtime command availability at its authority owner, and log inventory publication failures only when they change. Share inventory validation and remove superseded policy and projection helpers. * test(nodes): assert specific dispatch remediation messages * test(nodes): align pairing retry coverage with node recovery * fix(nodes): preserve desktop access after hosting failures Keep connected-node environment availability separate from session hosting readiness and retain diagnostic placement refusal. Include Codex plugin installation in missing-command remediation. Cover the inventory-to-environment boundary with real connected-node enumeration. * refactor(nodes): share runner declaration validation Keep the status-wait capability added on main while extending the existing strict record schema with bounded hosting diagnostics. Remove the superseded declaration parser and clone closed worker-host snapshots through one path. Production code remains net zero against the refreshed base. * fix(nodes): retain exhaustive command diagnostic states * refactor(nodes): preserve explicit diagnostic return flow |
||
|
|
968a08c6d0
|
perf(nodes): reuse warm workers so node session turns start as fast as local ones (#160265)
* perf(nodes): reuse warm workers so node turns start as fast as local ones Retain settled workers for two minutes with at most two idle children per node. Negotiate node-worker-idle-retention-v1 across Gateway, node, and bundle; fresh turn admission and credentials remain mandatory. Protect background work and preserve durable process cleanup and reconciliation. Expose reclaimable idle capacity to placement admission and the session picker. Consolidate lifecycle helpers under the supervisor and use the shared capacity parser. Document the bounded process-count and memory tradeoff; include lifecycle, negotiation, and picker regression coverage. fix(nodes): retry failed idle worker cleanup Rearm the supervisor idle timer after a transient physical cleanup failure while retaining the durable slot and retirement fence. Cover automatic expiry and idle-limit eviction alongside explicit cleanup with a fake clock. Fold the cancellation forwarding wrapper into its owner and remove the immediately repeated admission abort check. Preserve the existing authority, settlement, and shutdown guards. fix(nodes): synchronize idle capacity protocol models Regenerate the Swift worker-slot model for the optional reclaimableIdle field. The schema and named capability contract remain unchanged. Inline the single-caller prepared workspace custody wrapper in the supervisor and move its four cases to the public launch entry point. Preserve exact acquisition, abort, shutdown, and release ordering while keeping the complete branch production delta negative. chore(nodes): prune stale worker assertion allowance Remove the exact one-entry assertion baseline for worker-command.runtime.ts after the unsafe assertion was eliminated. Keep the scanner and all unrelated allowances unchanged. fix(nodes): keep supervisor dependencies on protocol owners Import protocol parsers and types directly from their canonical leaf, including the QA fixture, and remove the redundant supervisor-control re-exports. This breaks the dependency cycle without duplicating the wire contract. Keep the runner cancellation mock and shutdown callback asynchronous with the real Promise<void> contract, including teardown restoration. fix(nodes): complete asynchronous cleanup contracts Join cancellation cleanup in callers and tests while preserving parallel shutdown settlement and expected failure identity. Exclude absent cleanup owners before aggregation and keep stale-connection rejection unchanged. Use immutable worker input, type-only journal imports, stable sorted idle projections, and receiver-bound fault injection. Remove redundant descriptor bookkeeping and finish the test lint cleanup without changing limits or suppressions. * test(nodes): disambiguate inventory fixtures |
||
|
|
1b5ac171f6
|
fix(pairing): device join codes ignore gateway.publicOrigin behind public ingress (#159465)
* fix(pairing): honor gateway.publicOrigin for device join codes A loopback Gateway behind public HTTPS ingress sets gateway.publicOrigin, and cloud node enrollment already used it, but device join codes, the device-pair plugin, and Doctor's node-hosting check each resolved the pairing endpoint on their own and ignored it, failing with advice that omitted publicOrigin. Make src/pairing/setup-code.ts the single owner (device-pair publicUrl override, then gateway.publicOrigin, then existing discovery), expose it to the device-pair plugin through plugin-sdk/device-bootstrap, remove the plugin's duplicate resolver and enrollment's private fallback, and share one loopback error that names gateway.publicOrigin. * fix(pairing): preserve explicit remote endpoint selection Honor preferRemoteUrl before gateway.publicOrigin so qr --remote keeps its selected endpoint aligned with remote credentials. Retain publicOrigin as this Gateway's ingress ahead of automatic Tailscale, remote, and bind discovery, with the pairing-specific override taking precedence. Cover configurations with both URLs at the resolver and QR CLI boundaries, and correct the CLI, cloud-worker, and SDK precedence documentation. Validation: 221 focused tests passed; scoped core, extension, script, and test typechecks passed; independent review found no actionable P0-P2 issues. * fix(pairing): preserve device routes with explicit cloud ingress preference Keep existing device join-code, QR, and /pair discovery order. Use publicOrigin only at the loopback fallback, while cloud enrollment asks the same resolver to prefer public ingress at both preparation and issuance. Use the canonical lazy runtime binder for the SDK export so the collision guard recognizes one implementation without loading setup code at startup. Document the two call-site intents and cover Tailscale, LAN, loopback, and cloud enrollment behavior. Validation: export-name collision and SDK surface guards passed; 222 focused tests and scoped typechecks passed; independent review was clean. * chore(device-pair): drop the max-lines suppression the smaller plugin no longer needs * fix(device-pair): preserve origin-only setup URLs Retain the plugin command URL mapping through the shared pairing resolver while preserving context paths for join codes and cloud enrollment. Clarify public-origin fallback and remote QR prerequisites. |
||
|
|
2a1402cd3e
|
fix(startup): keep legacy state repair in Doctor (#151025)
* fix(startup): keep legacy state repair in doctor
Separate current-state startup readiness from explicit Doctor migrations.
Preserve current config recovery, quarantine, device identity checks,
lease fencing and updater completion ownership.
Remove automatic startup migration/checkpoint and node-host import paths.
Keep shipped read-only context and roster projections unchanged.
* test(doctor): align proof callers with repair ownership
Keep survivor fixture setup in caller order and select the shared Doctor
flow separately from the channel-specific proof. Include the complete
isolated diagnostics dependency closure.
Prove ordinary startup preserves legacy directories before explicit
Doctor repair, and await SQLite worker closure before test cleanup.
* test(startup): verify index repair through gateway maintenance
* test(doctor): align cutover fixtures with state owners
Reacquire the database after Doctor retires its generation, retain real session history for startup refusal, and keep pending reads at their actual owners. Distinguish the reused readonly reader from independent snapshot-token children and verify every child settles.
* fix(doctor): preserve image activation and published migration receipts
Run the shared noninteractive Doctor owner before default and Compose Gateway
activation so retained Docker volumes keep their published upgrade path while
ordinary Gateway startup stays readiness-only. Preserve root selectors and
settle interrupted repair before executing the original command.
Retain the path-wide tombstones emitted by the published restart-sentinel
importer, including consumed notices, and validate completed source decisions
before retiring recreated inputs. Add the root-image activation lane and causal
receipt coverage without introducing a schema, option, or second importer.
* test(docker): preserve release state pairs in upgrade proof
Use the existing synthetic v2026.9.2 corpus instead of combining a July shared database with a later agent schema. Preserve its deletion journal, registry, both transcript payloads, paired backups, and unsafe-state controls. Register the two shell-launched helpers with Knip.
* test(docker): normalize persisted schema snapshot rows
Compare node:sqlite schema rows using the same plain-object representation as the saved JSON preimage. Keep strict schema, row, and value-type assertions intact.
* fix(models): retain discovered models after refresh failures
Record successful legacy catalog results at the producer boundary so unavailable refreshes retain the accepted inventory. Preserve explicit outcomes, advisory SDK fallback behavior, and first-discovery starter policy.
* fix(models): preserve skipped catalog outcome semantics
Mark bundled static, configured, and advisory catalog projections with
explicit empty outcomes so legacy success inference cannot promote them
to observed account inventory. Preserve live outcomes and helper types.
Keep exact auth provenance histories and move existing fixture/policy
code into focused owners where required by the line-cap ratchet.
Validation: 447 producer and sibling cases, 56 shared self-hosted cases,
95 auth/policy cases, causal missing-outcome failures, maintained checks,
and independent review.
* test(plugin-sdk): keep discovery loader types acyclic
Move the shared loader type into a leaf consumed by both discovery
contract helpers. Preserve its public provider-test-contracts export
without a child-to-parent type import cycle.
Validation: maintained Madge check reports zero cycles; core, all core
test graphs, extension test types, lint, formatting and independent
review pass. Runtime behavior and previous catalog proof are unchanged.
* fix(plugin-sdk): mark generated static catalogs explicitly
Keep the generated non-live, non-strict catalog adapter from claiming
successful acquisition for manifest or configured rows. Preserve null,
errors, strict and custom callbacks, static catalogs, and public types.
Validation: three existing controls fail before the correction; all49
owner and sibling cases pass afterward, with types, lint, line caps and
fresh independent review clean.
* test(gateway): cover restart import during state retirement
Exercise canonical database close while a legacy notice read is paused. Verify admission rejection, retained canonical and source bytes, no migration receipt, and joined maintenance custody without changing the accepted sidecar-stop drain contract.
* fix(test): drain sharing fixtures before removing state
* test: bind retirement regression to its own worker
* docs(docker): clarify automatic Doctor activation
* test(doctor): keep readiness fixture runtime private
* test: stabilize shared skill watcher fixture roots
(cherry picked from commit 15606be10ed61be99931fcf3bb300ebdb475ad89)
* perf(tooling): share indexed scope parsing for artifact scans
(cherry picked from commit 6e6eef9f5b556e0005b16363169e6a85cd310ad0)
* fix(team-reports): use source owners in scheduler tests
The source barrel retired in #157819, but the scheduler tests still imported
it, breaking the extension test typecheck on main. Import the Discord and
GitHub owners directly, matching the production caller.
Validated the original TS2307/TS7006 failure, the corrected extension type
graph, all 36 scheduler tests, changed checks, and independent P2 review.
(cherry picked from commit
|
||
|
|
341f73b48b
|
fix(node): wait for resource cleanup before shutdown completes (#156995)
* fix(node): wait for resource cleanup before shutdown completes Join asynchronous provider disposal, disconnect cleanup, and client drainage. Fence late callbacks and starts, retain terminal failures, and retry only owners that keep unfinished retirement work. Preserve synchronous watcher callbacks and the existing public SDK exports. * fix(plugins): drain desktop cleanup and remove contract import cycle Wait for asynchronous provider watchers before the private computer worker exits, and propagate cleanup failures through its terminal completion. Route the existing SDK registration exports directly to their owner so the shared wire schemas no longer import the registration runtime. |
||
|
|
3c4c111b0f
|
feat: automatically update idle headless nodes (#151545)
* 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 |
||
|
|
5278a8f2ed
|
feat: share selected sessions read-only with a paired team Gateway (#136253)
* feat(node-host): advertise an explicit node command allowlist Persist exact node command selection and restrict ancillary publication and hosting. Preserve the unchanged assertion baseline under the work-order stop rule; check:changed requests removing the obsolete runtime.ts count (2 to 0). * feat(plugin-sdk): session transcript catalog reader Expose bounded read-only native display pages and portable attribution through the existing runtime subpath. Keep pagination scoped to the original active transcript branch and allow an explicit bounded native cursor length. * feat(session-share): read-only OpenClaw session catalog across paired gateways Publish explicitly selected native session groups through two paired node commands. Validate the closed wire contract, reject remote profile claims, and keep receiver identity binding opt-in and display-only. * fix(gateway): show published session catalogs to view-scoped roles Let publication consent satisfy catalog read visibility for roles allowed to view others, while owner-only and unprofiled callers stay hidden. Preserve published attribution without accepting a remote local-session adoption claim. Regression tests reproduce four pre-fix failures; final validation stopped at the work-order baseline gate. * docs: session sharing across gateways Document sessions-only node setup, explicit publication groups, receiver attribution, view-scoped catalog access, and read-only limits. Add the bundled plugin inventory and generated reference entry. Live proof runbook remains outside the repository; build and rig execution are blocked by the work-order baseline restriction. * fix(session-share): preserve source storage and paired reconnects Respect configured stores through listing, paging, and revocation. Keep cold listings available and bound raw transcript reads. Prefer the established paired node credential on service restart, suppress unrelated host metrics, and refresh the approved plugin configuration docs. * refactor(gateway): separate authorized catalog reads Keep the catalog dispatcher within its owned scope and preserve post-read role checks and sender projection. Align the rebased tests with their shared setup and imports. |
||
|
|
0d66d24fb1
|
docs: fix verified accuracy findings in channels, cli, nodes, and reference (#143950)
* docs: fix verified accuracy findings in channels, cli, nodes, and reference
Close the open `accuracy` ledger rows for docs/channels/, docs/cli/,
docs/nodes/ and docs/reference/ that survived verification against source.
Each edit is backed by code or by a dated commit/release:
- Name the release for previously unscoped time-relative claims
(Slack `progress` default 2026.8.1, Telegram preview default 2026.8.1,
Discord DAVE receive recovery 2026.2.24, gateway ownership contract
2026.8.1, cron `--deliver`/`cron.failureDestination`/file store,
nodes `nodes.run` removal 2026.3.31, media `{{Attachment*}}` rename,
presence clear action, memory-config embedding identity, schema-19
`consumed_event_id`, `[view ...]` -> `[embed ...]`).
- Delete time-relative wording where no release record exists and state
present behaviour instead (mattermost, msteams, groups, audio, camera,
computer-use, secretref store scope, full-release-validation alias).
- Correct concrete defects: matrix `threadReplies` default, audio
`gpt-transcribe` -> `gpt-4o-transcribe`, camera `--duration-ms`
(no such flag), signal quickstart probe command, googlechat macOS
bind-address check, discord `bash` fences holding slash commands,
usage-window provider lists, RELEASING script naming, zalo disclaimer
placement, talk.md placeholders, images.md duplicated vision rule.
`pnpm check:docs` passes. `docs-link-audit --anchors` reports the same 3
pre-existing `#windows-app-node` errors as the merge base.
* docs(nodes): restore the approved media-template deprecation window
ClawSweeper is right: `src/plugins/compat/media-legacy-projection.ts` marks
`{{MediaPath}}`, `{{MediaUrl}}`, `{{MediaType}}` and `{{MediaDir}}` deprecated
with `removeAfter: "2026-10-01"`, gated on a clean published-plugin artifact
sweep. "No removal is scheduled" was wrong.
Both pages now keep the deprecated status, state the approved date and its
gate, and link the record's own docs target
(/plugins/sdk-migration/compatibility-policy#media-legacy-projection).
|
||
|
|
69758a9ff6
|
docs(nodes): complete the two-stage approval flow (#136268)
Related: #128446, #98045 (both remain closed)
## What Problem This Solves
Several manual node setup paths stopped after device approval. A node paused for pairing could remain disconnected; after reconnecting, its initial command surface could still be unapproved. Troubleshooting omitted that separate gate, while bootstrap instructions incorrectly said enrollment never approved the first declared surface.
## Why This Change Was Made
The current CLI, node-host, pairing/status, Windows, and troubleshooting pages now lead through device approval, restarting or rerunning a paused node, inspecting the separate surface request, and approving its distinct request ID. Initial empty surfaces are distinguished from pending expansions that retain approved, still-declared commands. SSH-verified and administrator bootstrap enrollment are distinguished from trusted-network device-only approval.
The join-code reference shows the exact `npx openclaw connect <url>` output and current core ownership. It distinguishes reachable TLS endpoints, explicitly configured loopback URLs, default-loopback URL-discovery refusal, and direct plaintext-LAN setup codes. The invoke reference retains the existing 30,000 ms transport default and explains its invoke-plus-10,000 grace. The current configuration example uses `tools.exec.mode`.
The old nodes index remains a routing page with its stable anchors. Already-landed identity, revocation and re-pair guidance is preserved in the current owning pages.
## User Impact
Operators can complete manual enrollment and identify the correct missing approval before changing shell policy. Bootstrap consent, later expansion approval, Gateway command policy, node-local exec approvals and platform permissions remain distinct. This changes documentation only; runtime, configuration schema, storage, protocol and security policy are unchanged.
## Evidence
- Complete source-to-document audit against pinned main `
|
||
|
|
e427f280d9
|
docs(nodes): split the nodes overview by reader job (#142779)
* docs(nodes): split the nodes overview by reader job
docs/nodes/index.md was 68,029 bytes, 8,871 words and 35 headings mixing
pairing how-tos, node-host setup, session hosting, command-policy reference and
per-platform allowlists in one page. One H2, "Remote node host (system.run)",
parented 17 H3 sections that were not about system.run, and the page ended with
no next-steps list.
The page already lived in a directory with eleven siblings (audio, camera,
computer-use, images, location-command, media-playback, media-understanding,
presence, talk, troubleshooting, voicewake), so this extends that directory
rather than creating a parallel one. index.md becomes a real index at the same
/nodes route: intro, a "Node pages" list that also names the eleven existing
siblings, and the anchor table below.
Children, one per reader job:
- pairing-and-status.md - approve a node, read status and host stats, upgrade
a fleet across the N-1 protocol window.
- node-host.md - foreground, service, SSH-tunnel and headless node hosts,
gateway preconditions, identity state, and the system.* command surface.
- node-exec.md - allowlist commands, point exec at a node, raw node.invoke,
and exec node binding.
- mcp-and-skills.md - node-hosted MCP servers, node-hosted skills, and local
Ollama inference.
- session-hosting.md - nodeHost.workerRuns, device placement and capacity,
and container isolation.
- session-catalogs.md - Codex, Claude, OpenCode and Pi session discovery and
continuation on paired nodes.
- file-transfers.md - terminal uploads and the File Transfer plugin tools.
- command-policy.md - the platform default allowlists, dangerous-command
opt-ins, gateway.nodes/tools.exec config, and the permissions map.
- device-commands.md - widget panel, camera, screen recording, location, SMS
and device data CLI helpers.
Anchor strategy
Per-anchor redirects are not possible: redirectSource() in
scripts/lib/docs-redirects.mjs rejects any source containing [?#]. Every anchor
the old page published is therefore kept alive on the index itself as authored
<a id="..." /> stubs inside a "Where each section moved" list, each pointing at
its new home. Ids were computed with parseDocsDocument, not a slug
approximation, so the thirteen punctuated headings keep both their encoded and
their cleaned id (for example pairing-%2B-status and pairing-+-status). All 48
ids the pre-split page published resolve on the new index; the index publishes
only two ids of its own, node-pages and where-each-section-moved, so no stub
collides with a heading the index still owns. parseDocsDocument reports zero
collisions on the index and on every child.
Losslessness
Reassembling the 35 section bodies reproduces the original body byte for byte,
apart from the two declared link retargets below. Counts, original body vs
children:
- words 8,634 -> 8,634
- characters 66,320 -> 66,358 (+38, the two retargets)
- code fences 29 -> 29, identical fence for fence as a multiset
- markdown links 30 -> 30
- table rows 16 -> 16, all three tables byte-identical
- the per-platform default-allowlist table is byte-identical: 8 rows, with
iOS 11, watchOS 3, Android 19, macOS 14, Windows 6 and Linux 2 commands
No prose was rewritten. Two intra-page fragment links whose target moved to a
different child, both `](#command-policy)` in device-commands.md, became links
to /nodes/command-policy#command-policy; that is the whole +38 characters.
Sections keep their original relative order within each child, so the five
directional cross-references the page carried ("the environment fallback
above", "see above", "see below", "the static platform-default table above")
all still resolve on their own page.
Also updated: the "Nodes and media" nav group in docs/docs.json, eight in-repo
deep links repointed at the new pages (docs/releases/2026.9.2.md left
untouched, its anchor still resolves through the stubs), fourteen zh-CN
glossary entries for the new titles and index link labels, and
src/docs/config-path-docs.test.ts, which asserts on the `openclaw config`
bracket-path examples that now live in node-exec.md.
Closes audit findings: r3-0443, r3-0445, r3-0447
* docs(nodes): link the relocated device command examples from the exec page
The exec page's "(camera, screen, location, below)" pointed at helpers the
split moved to /nodes/device-commands. Replace the directional word with a
link. Found by ClawSweeper; the orphan-reference scanner's patterns do not
match a bare trailing "below" with no noun phrase in front of it.
|