feat(gateway): make suspend/resume operator-usable end to end (#122100)

* 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.
This commit is contained in:
Peter Steinberger
2026-08-11 22:12:53 -07:00
committed by GitHub
parent 00fc1bd123
commit 61ab6a8f9d
20 changed files with 1034 additions and 184 deletions
+30
View File
@@ -516,6 +516,36 @@ openclaw gateway call logs.tail --params '{"limit": 200}'
`--params` must be valid JSON, and each method validates its own param shape (extra/misnamed fields are rejected). Use `--port` for a custom-port local Gateway; explicit `--url` targets still require explicit credentials.
</Note>
### `gateway suspend`
Prepare an idle Gateway for a cooperative host freeze or snapshot. Without
`--wait`, active work returns a nonzero exit with blocker details. With
`--wait`, the CLI retries until the bounded deadline using one stable request
ID.
```bash
openclaw gateway suspend
openclaw gateway suspend --request-id snapshot-2026-08-11 --wait 30
openclaw gateway suspend --port 18999 --json
```
The ready output includes the suspension ID, lease expiry, and the matching
resume command. Common RPC options such as `--url`, `--token`, `--password`,
`--timeout`, `--json`, and `--port` are supported.
### `gateway resume <suspensionId>`
Release a prepared suspension after thaw or when the host operation is
abandoned.
```bash
openclaw gateway resume <suspensionId>
openclaw gateway resume <suspensionId> --port 18999 --json
```
An already expired or resumed lease is a successful no-op. A different active
suspension ID is rejected.
## Manage the Gateway service
```bash