feat(gateway): surface negotiated handshake protocol version in UI

Users have reported confusion about "when will ClawPanel update its
gateway protocol to v4". This is actually a misreading: ClawPanel v0.15+
already advertises `minProtocol=3, maxProtocol=4` in its connect frame,
and negotiates v4 transparently when the kernel is >= 2026.5.12. The
`v3|` prefix users were seeing in dev-api.js is the device signature
payload string schema version, which is a completely separate concept
from the handshake protocol version.

Make this visible and unambiguous:

UI
- Add a "Proto v4" badge next to the Gateway service name in
  /services once the WS handshake succeeds, with a tooltip explaining
  that this is the WS handshake protocol version (not the device
  signature payload v3 format).
- Add the same protocol info to the WebSocket row in /chat-debug.

API
- WsClient now exposes `negotiatedProtocol` which prefers the explicit
  field from the hello payload (`protocol` / `protocolVersion` /
  `negotiatedProtocol`) and falls back to inferring from serverVersion:
  kernels >= 2026.5.12 are reported as v4, older as v3. This matches
  the panel's advertised range of [3, 4].
- KernelSnapshot grows a `protocol` field so feature gates and UIs that
  already consume the snapshot can read it without touching wsClient.

Comments
- Expand the KERNEL_TARGET comment in feature-catalog.js to spell out
  the two-distinct-version-numbers rule explicitly.
- Add matching clarifying comments next to the `v3|...` payload string
  in both scripts/dev-api.js and src-tauri/src/commands/device.rs, so
  the next reader does not confuse payload schema with handshake.

## Verification
- node --check on all touched JS files
- npm run build
- cargo fmt --check && cargo check (clippy errors that surface are
  pre-existing debt in config.rs, untouched here)
- Playwright /services: mock wsClient state, observe `协议 v4` badge
  rendered with `rgba(99, 102, 241, 0.1)` background and accent color,
  for both the explicit-protocol path and the version-inferred path.
This commit is contained in:
晴天
2026-05-16 13:02:08 +08:00
parent cb4c9bcdfc
commit 7d75486a53
9 changed files with 76 additions and 4 deletions

View File

@@ -115,7 +115,12 @@ pub fn create_connect_frame(
let scopes_str = SCOPES.join(",");
// v3 格式v3|deviceId|clientId|clientMode|role|scopes|signedAt|token|nonce|platform|deviceFamily
// 使用 openclaw-control-ui + ui 模式,使 Gateway 识别为 Control UI 客户端,
// 本地连接时触发静默自动配对shouldAllowSilentLocalPairing = true
// 本地连接时触发静默自动配对shouldAllowSilentLocalPairing = true
//
// ⚠️ 注意:这里的 `v3|` 前缀是 **device signature payload 字符串的 schema 版本**
// 与下面 `params.minProtocol/maxProtocol` 协商的 **Gateway WebSocket 握手帧协议版本**
// v3 / v4是两套独立的版本号。即使在 v4 握手协议下,签名 payload 仍以 `v3|` 开头。
// 详见 src/lib/feature-catalog.js KERNEL_TARGET 注释。
let payload_str = format!(
"v3|{device_id}|openclaw-control-ui|ui|operator|{scopes_str}|{signed_at}|{auth_secret}|{nonce}|{platform}|{device_family}"
);