* feat(gateway): make suspend/resume operator-usable end to end
A prepared Gateway now accepts authenticated WebSocket connects while
keeping every method except gateway.suspend.* fenced, so a fresh CLI or
controller process can resume a suspension instead of dead-ending on a
rejected upgrade until the two-minute lease expires. Restart drain,
worker ingress, and desktop-observe streams stay fully closed.
The gateway client surfaces non-101 upgrade responses (bounded body
read) as typed retryable errors instead of an opaque 1006 close, and
new openclaw gateway suspend / resume commands drive the whole
handshake, including bounded --wait polling with blocker output.
Live-verified on an isolated dev gateway: prepare, SIGSTOP/SIGCONT
freeze, resume, over-TTL expiry self-heal, conflict and mismatch paths.
* refactor(gateway-client): move wire-client contract types to protocol-client-contract
The connectError addition pushed protocol-client.ts over the 700-line
max-lines gate; split the adapter-facing contract types into their own
module instead of suppressing.
* refactor(gateway-client): keep contract-internal option types unexported
Knip deadcode gates reject exported types with no importer; the connect
and close decision shapes are only referenced inside the contract module.
* chore(plugin-sdk): refresh gateway-runtime API baseline after rebase
* fix(gateway-client): preserve hello type after rebase
* test(gateway): support websocket upgrade rejection events
* test(gateway): expect connection errors in close info
* fix(gateway): keep prepared-suspension connects control-only
Address ClawSweeper review: node and worker connects stay refused while
suspension is prepared (only operator control connects pass), and the
CLI never issues another suspend prepare after its --wait deadline.
* fix: gateway service commands refuse a named profile or relocated OPENCLAW_HOME
- Resolve the default install identity against the canonical state directory
for the active OpenClaw home and profile instead of the unprofiled OS
account default.
- `--profile <name>` / `--dev` project `.openclaw-<profile>` state and config
paths, so every named profile was classified as isolated state and refused
`install`, `start`, `stop`, `restart`, `uninstall`, Doctor service repair,
and self-update service handling.
- `OPENCLAW_HOME` relocates all OpenClaw path defaults and is documented for
running as a dedicated service user; a relocated home is now an install
identity. `HOME` alone still is not.
- An `OPENCLAW_STATE_DIR` or `OPENCLAW_CONFIG_PATH` pointing outside those
canonical paths is still treated as isolated state.
- Recovery guidance in the refusal message now names the paths that must match.
Verified: focused vitest shards for the changed suites plus the daemon, CLI,
and doctor suites that consume the identity check; tsgo core and core-test
lanes; oxlint; docs format, MDX, link, and map checks.
* fix(gateway): keep relocated homes isolated
* fix(config): validate service profile identity
* fix(daemon): enforce named-profile service ownership
* fix(update): reject drifted service selectors before probes
* test(windows): prove scheduled task lifecycle
* test(windows): harden scheduled task proof cleanup
* test(windows): bind lifecycle proof to checkout
* test(windows): normalize cleanup exit status
* test(windows): verify effective task privilege
* test(windows): protect scheduled task proof roots
* test(windows): prove listener-owned task lifecycle
* test(windows): fix scheduled task proof contracts
* test(windows): remove redundant mock coercions
* test(windows): measure fallback before task probes
* test(windows): prove scheduled task process origin
* fix(gateway): preserve unmanaged restart fallback
* test(gateway): cover denied restart ownership
* test(gateway): keep restart helper types private
* test(gateway): classify lifecycle helpers as test code
---------
Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
resolveSshConfig and startSshPortForward spawned a hard-coded /usr/bin/ssh,
so SSH config discovery and gateway tunneling failed wherever the system ssh
client lives elsewhere: Windows (built-in OpenSSH under System32\OpenSSH) and
NixOS (/run/current-system/sw/bin).
Route both helpers through the existing resolveSystemBin("ssh", { trust:
"strict" }) resolver, and add the Windows built-in OpenSSH directory to the
resolver's trusted Windows locations (it had System32 but not the
System32\OpenSSH subdirectory where ssh.exe actually ships). Fail closed with
a clear diagnostic when no system ssh client is present.
Closes#83289.
Co-authored-by: Peter Steinberger <steipete@gmail.com>
Channel plugins declare package env triggers in manifests, and ambient
environment variables count as "channel configured". A dev gateway
(gateway run --dev) inherits the operator's shell, so real channel
credentials silently configured channels and could connect development
instances to live services (observed with reef and a Telegram-range
connection during isolated stress testing).
Dev mode now drops presence signals whose only sources are env or
manifest-env across activation planning, auto-enable, autostart, health
recovery, readiness, reloads, and startup warnings. Explicit
channels.<id> config still works, --dev-ambient-channels restores the
old behavior, and startup logs the suppressed channel ids once. Non-dev
gateways are unchanged.
Phase 3 of #107237. Removes config.apply/config.patch/restart from the
regular-agent gateway tool (mirroring Phase 2's update.run removal); only
config.get and config.schema.lookup reads remain. Persistent config changes
and restarts now go exclusively through the human-approved openclaw
delegation path — closing the last unmediated agent config-write surface.
gateway stays owner-only/control-plane gated (config reads expose secrets and
host topology). Legacy setups can re-enable writes via the existing per-agent
tool allowlist; no new config key. Net -2271 LOC.
Refs #107237
* feat(gateway-cli): scope usage-cost by agent
The `gateway usage-cost` CLI only sent `{ days }` to the `usage.cost` RPC, so
callers could not break cost down per agent or aggregate across all agents the
way the Control UI can. Add `--agent <id>` (forwards `agentId`, scoping to one
agent) and `--all-agents` (forwards `agentScope: "all"`, aggregating every
agent). The two are mutually exclusive because the gateway honors `agentScope`
only when no `agentId` is set; passing both now errors instead of silently
dropping `--all-agents`. No flag keeps the existing default-agent behavior.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(gateway-cli): scope usage-cost by agent
---------
Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
* fix(gateway): accept port for health and probe
* fix(gateway): repair health port override
* fix(gateway): repair health port override
* fix(gateway): accept port for health and probe
---------
Co-authored-by: openclaw-clownfish[bot] <280122609+openclaw-clownfish[bot]@users.noreply.github.com>
Summary:
- The PR updates `docs/cli/gateway.md` and `docs/reference/test.md` to document Gateway startup/restart benchmark prerequisites, commands, case IDs, probes, output semantics, and platform limits.
- Reproducibility: not applicable. as a runtime bug; docs correctness is source-checkable against the benchmar ... ipts, and readiness source. The current PR head corrected the earlier startup-hook readiness wording issue.
Automerge notes:
- PR branch already contained follow-up commit before automerge: docs(gateway): correct benchmark readiness wording
Validation:
- ClawSweeper review passed for head 5bd0f6c463.
- Required merge gates passed before the squash merge.
Prepared head SHA: 5bd0f6c463
Review: https://github.com/openclaw/openclaw/pull/83866#issuecomment-4483820005
Co-authored-by: samzong <samzong.lu@gmail.com>
Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com>
Approved-by: takhoffman
Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
Expose the existing safe-restart skipDeferral escape hatch through gateway RPC and the daemon CLI, document the flag, and add restart/CLI regression coverage.
Also keep CLI failure output off the cold bootstrap graph and align CLI guidance expectations needed by current CI.
Co-authored-by: Solomon Neas <solomonneas@users.noreply.github.com>
The `gateway restart` Command-options accordion only listed `--force`,
`--wait`, and `--json` even though `--safe` is a fully-supported flag
(documented in the prose at line 112 and rejected by lifecycle.ts when
combined with --force/--wait). Add --safe to the option list and a
Lifecycle-behavior bullet that explains the preflight-defer behavior
plus its mutual exclusion with --force and --wait, matching
src/cli/daemon-cli/lifecycle.ts:153-156.
Simplify plugin installation and runtime loading around package-manager-owned dependencies, with Jiti reserved for local/TS fallback paths.
Also scans npm plugin install roots so hoisted transitive dependencies are covered by dependency denylist and node_modules symlink checks.