Skip to content

feat(cli): build the pairing QR code while remote access is set up - #53949

Closed
R44VC0RP wants to merge 7 commits into
v2from
pair-qr-build
Closed

R44VC0RP wants to merge 7 commits into
v2from
pair-qr-build

Conversation

@R44VC0RP

@R44VC0RP R44VC0RP commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Rebased on #53962 (random remote-access route) with #53946 merged in. Base is random-route for now; retarget to v2 once #53962 and #53946 merge. Changes for #53962: the stand-in link uses a 16-character route, the first-time check uses a new RemoteTunnel.created() (whether this device has its tunnel yet), config.remote === undefined replaces !== true, and ensure(onProgress?) returns the bare hostname like #53962. Re-tested: tsgo -b passes; test/service.test.ts passes (24); a real first-time pair --remote from source on a fresh home built the code, finished on https://<16 hex>.<id>.opentunnel.xyz/auth/connect/… (the final QR decodes to it), and the finishing pass ran.

Stacked on #53946 (the remote QR code carries the pairing link). Retarget to v2 once that merges.

What

A device's first opencode pair --remote waits about 25 s for its tunnel certificate (measured: 23.5–26.8 s on fresh setups; later runs take 0.1 s). Until now the user saw one line: "Setting up remote access; this can take a minute...".

In a terminal, the QR code is now built where it will be printed, Minecraft-style:

  • Two builders lay the code block by block: the outer wall up from the bottom corners, then the corner squares and timing beams, then the rest from the bottom row up.
  • Each block pops in in its builder's color (warm from the left, cool from the right) and settles dim. Nothing unbuilt is shown.
  • One dim status line names the real step, from OpenTunnel's provisioning progress: "Reserving an address for this computer…", "Making a key for this computer…", "Getting a certificate for the tunnel…", "Connecting the tunnel…".
  • There's no seconds counter, which made the wait feel longer.
  • When the pairing code exists, a finishing pass lays the real code from both sides and flashes. The normal output then replaces the animation line for line, with the code in the same place.

The pairing code only exists after the service restarts with the tunnel (codes live in the service's memory). So the builders lay a stand-in of the same length, which has the same QR version: the same size, wall, corners, and beams. The finishing pass re-lays every data block from the real code. If the real code's size ever differed, it skips straight to the output.

Where

  • packages/cli/src/ui/qr-build.ts (new): the renderer. It uses the half-block glyphs renderUnicodeCompact uses, with SGR dim and bold plus two truecolor tints, so it follows the terminal's theme.
  • remote-tunnel.ts: ensure(onProgress?) creates a first tunnel with client.tunnel.create({ onProgress }). With a callback, the plain notice isn't printed.
  • pair.ts:
    • Starts the build only on a first-time --remote setup, with a TTY stdout and color (not NO_COLOR, TERM=dumb, or CI).
    • Builds the output text, then hands it to finish.
    • A failure or interrupt clears the animation before the error prints.

Everything else is unchanged. Piped output, existing tunnels, and opencode service set remote true all keep the plain line.

Verified

  • tsgo -b in packages/cli passes.
  • A real first-time setup, recorded with termctrl from source on a fresh home (fresh tunnel and certificate): the build ran through the real steps, finished, and left the normal output. The final QR decodes to the tunnel's pairing link.
  • A first-time setup with stdout piped to a file: the plain notice on stderr, and clean pairing output with no escape codes.

R44VC0RP and others added 7 commits October 8, 2026 07:47
opencode pair --remote pairs through one public https address, so its QR code now carries the link itself (https://<tunnel>/auth/connect/<code>) instead of {"code","urls"} JSON. A phone's camera can open it: in the OpenCode iOS app once it handles /auth/connect links on opentunnel.xyz (universal link), and otherwise in the browser, where the same link signs in and redirects to the web app. Other QR codes keep the JSON, since they can list several addresses.

The app scanners already read both forms (packages/app pairing.ts and the iOS app).
A device's first opencode pair --remote waits ~25 s for its tunnel certificate behind one plain line. In a terminal, the QR code is now built where it will be printed: two builders lay the outer wall, the corner squares and timing beams, then the rest from the bottom row up, each block popping in in its builder's color. Nothing unbuilt is shown. The step comes from OpenTunnel's provisioning progress. When the pairing code exists (after the service restarts with the tunnel), a finishing pass lays the real code and flashes, and the normal output replaces the animation line for line.

Only on a first-time remote setup with a TTY stdout and color (not NO_COLOR, TERM=dumb or CI); otherwise unchanged, including the plain notice.
@R44VC0RP
R44VC0RP changed the base branch from pair-remote-link to random-route October 8, 2026 13:50
Base automatically changed from random-route to v2 October 8, 2026 13:53
@R44VC0RP R44VC0RP closed this Oct 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants