Skip to content

fix(tui): encode reachable pairing addresses in the /pair QR code - #54051

Open
opencode-agent[bot] wants to merge 1 commit into
devfrom
tui-pair-qr
Open

opencode-agent[bot] wants to merge 1 commit into
devfrom
tui-pair-qr

Conversation

@opencode-agent

@opencode-agent opencode-agent Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Issue for this PR

No issue; requested in Slack. Follow-up to #53588.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

#53588 changed pairing QR codes to {"code","urls"} JSON and made ServerInfo.connectionURLs list the loopback address first on 0.0.0.0 / ::. The TUI /pair dialog was not updated, so on 0.0.0.0:

  • the QR code encoded links[0], now the 127.0.0.1 link, which a phone cannot reach;
  • the "Run opencode service set hostname 0.0.0.0" hint always showed, because a loopback URL is now always present.

The dialog now matches opencode pair:

  • remote is server.urls without loopback hosts (localhost, *.localhost, 127.*, [::1], the same rule as the CLI's isLoopback, as a local predicate).
  • The QR code encodes JSON.stringify({ code, urls: remote }) and is omitted when remote is empty.
  • The hostname hint shows only when remote is empty.
  • "This device" and the full link list (loopback included) are unchanged.

The JSON payload is denser and grows with each address. A QR row that wraps is unscannable, so the dialog now measures the rendered width:

  • Wide layout (width >= 96): the code stays beside the links when it fits the space there (53 columns). Otherwise it moves below them.
  • Narrow layout: when the code is wider than the dialog body, the dialog shows "Widen the terminal to show the QR code." in its place. Before, the rows wrapped into an unscannable block.

How did you verify your code works?

  • bun typecheck in packages/tui; prettier clean.
  • Dev server on all interfaces (bun dev serve --hostname 0.0.0.0 --port 4097, isolated XDG dirs). The live service was not touched. Dev TUI connected with --server.
  • End-to-end scan: the dev web app's Settings → Add server → Scan QR code (Chromium with a fake camera fed the TUI's QR) decoded the payload, redeemed the code at http://10.42.0.42:4097/auth/connect/… (200), and added the server. Its following authenticated API calls returned 200.
  • Decoded every screenshot with jsQR. Before: http://127.0.0.1:4097/auth/connect/<code>. After: {"code":"<code>","urls":["http://10.42.0.42:4097"]}.
  • Loopback server (bun dev serve --port 4098, urls ["http://127.0.0.1:4098"]): no QR code; the hint shows (wide and narrow).
  • Sizes with the real payload (1 remote URL: 35×18 cells, the same size as the old single-URL code): 120×44, 96×40 (wide), 95×40, 70×50, 46×50 (narrow), 120×35 (wide scrollbox). The QR decodes in each.
  • Denser payloads, tested by appending fake URLs locally (not committed): 5 remote IPv4 URLs (51 columns) still fit beside the links; 8 (59 columns) move below them at width 120; 5 at width 52 show the widen message.
  • Unchanged limitation: in the short-terminal scrollbox (height < 36), a code taller than the viewport needs scrolling, and it cannot be scanned until the terminal is tall enough. The old single-URL code had the same problem below about 32 rows, and denser payloads need more height.

Screenshots / recordings

Server on 0.0.0.0:4097, one non-loopback interface.

Before (wide, 120×44): the QR code encodes http://127.0.0.1:4097/auth/connect/…, and the hostname hint shows even though the server is already on 0.0.0.0.

Before, wide: QR encodes the loopback link and the hostname hint shows

After (wide, 120×44): the QR code encodes {"code":"…","urls":["http://10.42.0.42:4097"]}, and there is no hint.

After, wide: QR encodes the reachable address as JSON, no hint

Before (narrow, 70×50):

Before, narrow

After (narrow, 70×50):

After, narrow

After, loopback-only server (127.0.0.1:4098): no QR code; the hint shows.

After, loopback server, wide: no QR, hint shown

After, loopback server, narrow: no QR, hint shown

After, dense payloads (fake URLs, local test only): 8 remote URLs at width 120 move the code below the links; at width 52 a code that would wrap is replaced by the widen message.

After, 8 remote URLs at width 120: QR below the links

After, too narrow for the QR: widen message

Screenshots are hosted on the tui-pair-qr-assets branch. Nothing is committed to this PR's branch. Delete the assets branch after review.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Requested by: @Hona (Hona via Slack)

@thdxr
thdxr changed the base branch from v2 to dev October 10, 2026 19:38

This branch has not been deployed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant