Skip to content

feat(ui): make mobile pairing easy to find#100157

Merged
steipete merged 1 commit into
mainfrom
codex/easier-mobile-pairing
Jul 5, 2026
Merged

feat(ui): make mobile pairing easy to find#100157
steipete merged 1 commit into
mainfrom
codex/easier-mobile-pairing

Conversation

@steipete

@steipete steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Closes #100154

What Problem This Solves

Users pairing the iOS app could miss the supported web flow because its only trigger was inside the Devices card near the bottom of Nodes. Searching the main UI or Settings gave no obvious route to the QR setup dialog.

Why This Change Was Made

Adds a subtle phone action to the persistent sidebar footer and a Mobile app action to Quick Settings. All three entry points, including the existing Nodes button, now share one app-level dialog state; setup-code cancellation and pending-request refreshes remain synchronized across Gateway reconnects and pairing events.

User Impact

Operators with administrator access can open mobile pairing directly from any Control UI page or from Quick Settings, scan the QR code, and jump to Nodes to manage requests. Non-admin operators see the actions disabled with the existing access explanation.

Evidence

  • node scripts/run-vitest.mjs run ui/src/pages/config/quick.test.ts ui/src/pages/nodes/view.devices.test.ts ui/src/lib/device-pair-setup.test.ts — 23 tests passed.
  • node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner ui/src/e2e/mobile-pairing.e2e.test.ts — browser E2E passed for sidebar open, Quick Settings open, QR rendering, live pending-request refresh, code regeneration, and Manage devices routing.
  • pnpm ui:build — production Control UI build passed.
  • check:changed — Blacksmith Testbox tbx_01kwr1yvdny7vpvg21qtcvqvjq, exit 0; typechecks, lint, import-cycle, and pairing guards passed: https://github.com/openclaw/openclaw/actions/runs/28727067161
  • Structured Codex autoreview — accepted one pending-count synchronization finding, fixed it, reran focused proof, then clean with no actionable findings.
  • Visual proof captured in the attached-Chrome mocked Control UI; screenshots are attached to this PR.

AI-assisted: implemented and reviewed with Codex; maintainer understands the code and proof above.

@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui size: L maintainer Maintainer-authored PR labels Jul 5, 2026
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Visual proof with the mocked Gateway (no credentials or production data):

  1. Persistent sidebar shortcut
  2. Shared QR pairing dialog
  3. Quick Settings entry
sidebar-entry sidebar-dialog quick-settings-entry

@clawsweeper

clawsweeper Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed July 5, 2026, 12:41 AM ET / 04:41 UTC.

Summary
The PR adds Control UI mobile-pairing entry points in the sidebar and Quick Settings, moving the QR pairing dialog state from the Nodes page into app-level overlays.

PR surface: Source +229, Tests +39. Total +268 across 17 files.

Reproducibility: yes. Source inspection shows device.pair.setupCode can resolve and mutate setup state while openDevicePairSetup still waits for device.pair.list before publishing the non-loading snapshot.

Review metrics: 1 noteworthy metric.

  • Mobile pairing entry points: 2 added, 1 existing re-wired. All three entry points now share the app overlay, so one publish-order defect affects the sidebar, Quick Settings, and Nodes paths.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #100154
Summary: This PR is the direct implementation candidate for the linked Control UI mobile-pairing discoverability issue; the older merged PR introduced the underlying Nodes pairing flow.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦞 diamond lobster ✨ media proof bonus
Patch quality: 🦐 gold shrimp
Result: needs maintainer review before merge.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Publish setup-code completion independently from pending-count refresh.
  • [P2] Add a regression with a deferred or hanging device.pair.list, then rerun the focused mobile-pairing UI proof.

Risk before merge

  • [P1] Merging as-is can make all three mobile-pairing entry points appear hung on the generating spinner whenever device.pair.setupCode succeeds but device.pair.list is slow or never replies.

Maintainer options:

  1. Decouple QR publish from pending count (recommended)
    Publish the setup-code result when it resolves, let the pending-count refresh publish separately or run fire-and-forget, and add a regression where device.pair.list is deferred.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
In `ui/src/app/overlays.ts`, make `openDevicePairSetup` publish the setup-code result independently from `refreshDevicePairPendingCount`; do not let a slow or stuck `device.pair.list` keep the QR dialog on the generating spinner. Add a focused regression in `ui/src/e2e/mobile-pairing.e2e.test.ts` or an overlay-level test that defers `device.pair.list` while `device.pair.setupCode` resolves, then run the focused mobile-pairing UI tests.

Next step before merge

  • [P2] One narrow overlay publish-order defect remains; an automated repair can decouple setup-code rendering from pending-count refresh and add focused regression coverage.

Security
Cleared: The diff is limited to Control UI TypeScript, CSS, and tests; it does not add dependencies, workflows, secret handling, or a new setup-code persistence path.

Review findings

  • [P2] Publish the setup code before pending count returns — ui/src/app/overlays.ts:625
Review details

Best possible solution:

Keep the shared app-level pairing dialog, but publish setup-code state as soon as device.pair.setupCode resolves and refresh the pending count independently with regression coverage for a deferred device.pair.list.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows device.pair.setupCode can resolve and mutate setup state while openDevicePairSetup still waits for device.pair.list before publishing the non-loading snapshot.

Is this the best way to solve the issue?

No, not as written. The shared overlay is the right layer, but pending-count refresh must not gate QR/setup-code rendering before merge.

Full review comments:

  • [P2] Publish the setup code before pending count returns — ui/src/app/overlays.ts:625
    This is the same publish-order blocker from the previous ClawSweeper cycle: openDevicePairSetup still waits for both the setup-code request and refreshDevicePairPendingCount() before publishing the completed overlay snapshot. If device.pair.setupCode succeeds but device.pair.list is slow or never replies, devicePairSetup is populated internally but listeners are not notified, so the dialog stays on the generating spinner instead of showing the QR code.
    Confidence: 0.91

Overall correctness: patch is incorrect
Overall confidence: 0.9

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against f7d7148cf047.

Label changes

Label changes:

  • add merge-risk: 🚨 availability: The changed overlay flow can stall the shared pairing dialog when the pending-count RPC is slow even after the setup-code RPC succeeds.
  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR includes inspected browser screenshots of the sidebar entry, shared QR dialog, and Quick Settings entry, plus focused E2E and build evidence in the PR body.
  • add proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The PR includes inspected browser screenshots of the sidebar entry, shared QR dialog, and Quick Settings entry, plus focused E2E and build evidence in the PR body.
  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp.
  • add status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (screenshot): The PR includes inspected browser screenshots of the sidebar entry, shared QR dialog, and Quick Settings entry, plus focused E2E and build evidence in the PR body.

Label justifications:

  • P2: The PR addresses normal-priority mobile setup discoverability, but the remaining spinner bug has limited blast radius to the pairing dialog.
  • merge-risk: 🚨 availability: The changed overlay flow can stall the shared pairing dialog when the pending-count RPC is slow even after the setup-code RPC succeeds.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (screenshot): The PR includes inspected browser screenshots of the sidebar entry, shared QR dialog, and Quick Settings entry, plus focused E2E and build evidence in the PR body.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR includes inspected browser screenshots of the sidebar entry, shared QR dialog, and Quick Settings entry, plus focused E2E and build evidence in the PR body.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The PR includes inspected browser screenshots of the sidebar entry, shared QR dialog, and Quick Settings entry, plus focused E2E and build evidence in the PR body.
Evidence reviewed

PR surface:

Source +229, Tests +39. Total +268 across 17 files.

View PR surface stats
Area Files Added Removed Net
Source 13 362 133 +229
Tests 4 53 14 +39
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 17 415 147 +268

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs run --config test/vitest/vitest.ui-e2e.config.ts --configLoader runner ui/src/e2e/mobile-pairing.e2e.test.ts.
  • [P1] node scripts/run-vitest.mjs run ui/src/pages/config/quick.test.ts ui/src/pages/nodes/view.devices.test.ts ui/src/lib/device-pair-setup.test.ts.
  • [P1] pnpm ui:build.

What I checked:

  • PR head gates setup publication on pending count: openDevicePairSetup starts setup-code and pending-count requests, publishes the loading state, then waits for Promise.all([setupOperation, pendingCountOperation]) before publishing the completed snapshot. (ui/src/app/overlays.ts:625, 2c16a0ad1f23)
  • Setup helper does not notify overlays by itself: refreshDevicePairSetup mutates devicePairSetup and clears loading, but it has no listener or publish hook; callers must publish after the setup operation completes. (ui/src/lib/device-pair-setup.ts:45, 2c16a0ad1f23)
  • Gateway contract keeps list and setup-code independent: The protocol documents device.pair.list and device.pair.setupCode as separate device-pairing methods; rendering the QR/setup code does not depend on a successful list response. Public docs: docs/gateway/protocol.md. (docs/gateway/protocol.md:458, f7d7148cf047)
  • Focused E2E covers the normal immediate-list path only: The PR E2E uses an immediate device.pair.list mock and verifies the happy path, so it does not catch a slow or deferred pending-count request blocking QR publication. (ui/src/e2e/mobile-pairing.e2e.test.ts:56, 2c16a0ad1f23)
  • Current main still has only the original Nodes entry point: Current main renders the pairing setup button from the Nodes Devices card, so the discoverability feature remains unmerged and this PR is still relevant. (ui/src/pages/nodes/view.ts:61, f7d7148cf047)
  • Visual proof inspected: The attached screenshots show the sidebar shortcut, the shared QR dialog, and the Quick Settings entry in a browser Control UI session.

Likely related people:

  • bkudiess: Authored the merged PR that added the device.pair.setupCode Gateway method and original Control UI mobile-pairing flow this PR extends. (role: introduced behavior; confidence: high; commits: cf313b154848; files: src/gateway/server-methods/device-pair-setup.ts, packages/gateway-protocol/src/index.ts)
  • steipete: Merged the original pairing PR, authored the current discovery PR, and recent blame/log history points to the current Nodes pairing UI files. (role: recent follow-up owner; confidence: high; commits: 089f8c1f6fce, aaaa8030bf4f, 2c16a0ad1f23; files: ui/src/app/overlays.ts, ui/src/pages/nodes/view-pairing.ts, ui/src/components/app-sidebar.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (4 earlier review cycles)
  • reviewed 2026-07-05T03:12:09.275Z sha d5fc815 :: needs maintainer review before merge. :: none
  • reviewed 2026-07-05T03:48:03.595Z sha 2c19fdd :: needs maintainer review before merge. :: none
  • reviewed 2026-07-05T03:54:59.631Z sha 5b5d9ce :: needs maintainer review before merge. :: none
  • reviewed 2026-07-05T04:01:56.695Z sha 5b5d9ce :: found issues before merge. :: [P2] Publish the setup code before refreshing pending count

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf0ed5031b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/e2e/mobile-pairing.e2e.test.ts Outdated
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels Jul 5, 2026
@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation channel: slack Channel integration: slack channel: telegram Channel integration: telegram app: android App: android app: ios App: ios agents Agent runtime and tooling extensions: codex size: XL and removed size: L labels Jul 5, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 5, 2026
@openclaw-barnacle openclaw-barnacle Bot added the channel: whatsapp-web Channel integration: whatsapp-web label Jul 5, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5b5d9cec52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread ui/src/app/overlays.ts
@clawsweeper clawsweeper Bot added status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. and removed status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jul 5, 2026
@steipete
steipete marked this pull request as draft July 5, 2026 04:21
@clawsweeper clawsweeper Bot removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. labels Jul 5, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d5ac873b2f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/ios/Sources/Terminal/TerminalHubScreen.swift
@steipete
steipete force-pushed the codex/easier-mobile-pairing branch from d5ac873 to 2c16a0a Compare July 5, 2026 04:31
@openclaw-barnacle openclaw-barnacle Bot added size: L and removed docs Improvements or additions to documentation channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: whatsapp-web Channel integration: whatsapp-web app: android App: android app: ios App: ios agents Agent runtime and tooling extensions: codex size: XL labels Jul 5, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels Jul 5, 2026
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Land-ready verification for head 2c16a0ad1f23a017fbe193996ecac6d1a131cdda:

Known proof gap: the local aggregate pnpm test reached 4,613 passing tests but its unrelated Mattermost shard stalled on an open handle under both Node 24 and Node 26. The exact-head hosted CI completed successfully, including the scoped test matrix.

@steipete
steipete merged commit 1d9fb27 into main Jul 5, 2026
119 of 129 checks passed
@steipete
steipete deleted the codex/easier-mobile-pairing branch July 5, 2026 04:47
@steipete

steipete commented Jul 5, 2026

Copy link
Copy Markdown
Contributor Author

Merged via squash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui maintainer Maintainer-authored PR merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. P2 Normal backlog priority with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: L status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: Make mobile pairing easy to find in Control UI

1 participant