fix(tui): correct disconnect copy for device scope upgrades (#98144)

* fix(tui): correct disconnect copy for device scope upgrades

On disconnect, the TUI told users "Pairing required. Run `openclaw devices
list`, approve your request ID, then reconnect." This is misleading: the
gateway is asking for a device *scope upgrade* (the device is already
paired), and "pairing" points users at `openclaw pairing`, which only
handles chat DM pairing — a different subsystem.

- Reword the hint to name the scope upgrade and the actual recovery command
  (`openclaw devices approve --latest`), including the `--token`/`--password`
  escape hatch for when the device can't approve its own upgrade.
- Also match the gateway's "scope upgrade" disconnect reason, not just
  "pairing required".

AI-assisted (Claude Code).

* fix(tui): clarify device approval preview hint
This commit is contained in:
Dallin Romney
2026-06-30 18:10:04 -07:00
committed by GitHub
parent 21e6fc948b
commit 3eaaa2ca3c
2 changed files with 22 additions and 6 deletions
+16 -3
View File
@@ -346,11 +346,24 @@ describe("resolveInitialTuiAgentId", () => {
});
describe("resolveGatewayDisconnectState", () => {
it("returns pairing recovery guidance when disconnect reason requires pairing", () => {
it("returns scope-upgrade recovery guidance when disconnect reason requires pairing", () => {
const state = resolveGatewayDisconnectState("gateway closed (1008): pairing required");
expect(state.connectionStatus).toContain("pairing required");
expect(state.activityStatus).toBe("pairing required: run openclaw devices list");
expect(state.pairingHint).toContain("openclaw devices list");
expect(state.activityStatus).toBe("device approval needed: preview latest request");
expect(state.pairingHint).toContain("openclaw devices approve --latest");
expect(state.pairingHint).toContain("openclaw devices approve <requestId>");
expect(state.pairingHint).toContain("--token");
// Must steer users to `devices`, not the unrelated chat-DM `pairing` command.
expect(state.pairingHint).not.toContain("openclaw pairing");
});
it("returns the same guidance when the gateway reports a pending scope upgrade", () => {
const state = resolveGatewayDisconnectState(
"gateway closed (1008): scope upgrade pending approval",
);
expect(state.activityStatus).toBe("device approval needed: preview latest request");
expect(state.pairingHint).toContain("openclaw devices approve --latest");
expect(state.pairingHint).toContain("openclaw devices approve <requestId>");
});
it("falls back to idle for generic disconnect reasons", () => {
+6 -3
View File
@@ -230,12 +230,15 @@ export function resolveGatewayDisconnectState(reason?: string): {
pairingHint?: string;
} {
const reasonLabel = reason?.trim() ? reason.trim() : "closed";
if (/pairing required/i.test(reasonLabel)) {
// Covers both "pairing required" and a pending "scope upgrade" for a paired device.
if (/pairing required|scope upgrade/i.test(reasonLabel)) {
return {
connectionStatus: `gateway disconnected: ${reasonLabel}`,
activityStatus: "pairing required: run openclaw devices list",
activityStatus: "device approval needed: preview latest request",
pairingHint:
"Pairing required. Run `openclaw devices list`, approve your request ID, then reconnect.",
"Device approval needed. Run `openclaw devices approve --latest` to preview the pending request, " +
"then rerun the printed `openclaw devices approve <requestId>` command " +
"(reuse `--token` or other auth flags if needed), then reconnect.",
};
}
return {