Faster Cloudflare share QR + tighter QR + keybar keyboard toggle#293
Conversation
…instant The public Cloudflare QR appeared ~5-15s after clicking Share: the tunnel was established + verified-routable only on the click path. Move that cost off the critical path. - Pre-warm: when session sharing is enabled with a remote provider, bind the engine and establish the tunnel at app start (settings observer), so the verified public URL is already published when the user clicks Share. - Keep-warm: don't tear the engine/tunnel down on the last unshare while sharing stays enabled, so re-shares are instant. Disable-sharing / mode→off / quit still tear down. - Auto-respawn: if a kept-warm Cloudflare tunnel exits on its own, re-establish it after a 2s backoff. The remoteOp token is the authority — every cooperative teardown bumps the op before killing, so our own kills never respawn, and a persistent failure (FellBack, no adopted process) can't hot-loop. - Fix a port collision pre-warm exposed: the BossTerm MCP server (loopback, 7676-7685) and the share server (7677+) overlap. Started concurrently at launch under port pressure, both could land on the same port — MCP on 127.0.0.1, share on the 0.0.0.0 wildcard — and cloudflared (dials 127.0.0.1) then hit the MCP server's DNS-rebinding guard (403) instead of the viewer. Pre-warm now waits for the MCP server to claim its port first (bounded, only when MCP is enabled), and the port loop skips the MCP server's running port. Generated with [Claude Code](https://claude.com/claude-code)
Asking ZXing for a fixed 256px image made it scale the code by an integer module multiple and center it, baking the leftover slack in as a fat white border (on top of the quiet zone, then the 10dp modifier padding) — the QR looked small in a large white box. Encode at size 1 instead, which yields a tight 1px-per-module matrix (just the MARGIN=1 single-module quiet zone, no slack), then upscale by an integer factor so module edges stay crisp. The QR now fills the box; the 10dp white frame remains as the scan-friendly quiet zone. Generated with [Claude Code](https://claude.com/claude-code)
The on-screen keyboard button only summoned the soft keyboard (focused the hidden textarea). Make it a toggle: when the keyboard is up it blurs the textarea to dismiss it, when down it focuses to summon it — running inside the button's tap gesture so iOS honours the focus. "Up" is detected as a keyboard inset OR the textarea already being the focused element, so it's reliable across iOS/Android. wireKeyButton now takes an optional tap action; the key-row buttons keep their "always refocus to stay up" behavior unchanged — only the ⌨ button toggles. Generated with [Claude Code](https://claude.com/claude-code)
Review — Faster Cloudflare share QR + tighter QR + keybar toggleRead through all three changes against the surrounding ✅ What's solid
Minor concerns
TestsNo automated coverage for this module (consistent with the repo). The op-token state machine — especially the new respawn path interacting with teardown — is exactly the kind of concurrency logic that's easy to regress silently. A few unit tests around Nice work overall — the diff is small, the comments carry the reasoning, and the risky parts (op token, leak-free tunnel adoption) are handled correctly. 🤖 Generated with Claude Code |
…the fold After the keyboard is raised, entering a TUI (e.g. Claude Code) drops the prompt to the bottom of the screen — but the keyboard push was only computed at open/close, so the input hid behind the keyboard until you toggled it. Re-add a narrow cursor-follow: followCursor only ever INCREASES the upward push, and only when the cursor sits below the visible fold. A thinking TUI with a visible cursor writes nothing to the transform (no churn), so it doesn't reintroduce the dismiss bug — which came from the renderStage innerHTML="" detach and the autofit re-render (both fixed separately), not the transform write. Coalesced to one check per frame. Generated with [Claude Code](https://claude.com/claude-code)
|
Review — Faster Cloudflare share QR + tighter QR + keybar keyboard toggle Read through all four commits against 1. Pre-warm / keep-warm / auto-respawn ( The op-token discipline holds up. I traced every cooperative teardown — The MCP port-collision fix is the right shape. Minor — dead parameter: Worth flagging (you already acknowledge it) — always-on tunnel at launch: with the default Minor — no single-flight on pre-warm: the settings observer launches 2. Tighter QR ( Correct approach — encoding at 1x1 makes 3 & 4. Keybar toggle + cursor-follow ( The
Tests No tests added, and there are none for these files today. The logic is hard to unit-test (process lifecycle, soft-keyboard insets, ZXing rendering), so I would not block on it — but the QR matrix-to-bitmap mapping and the port-skip predicate are pure enough to cover cheaply if you want a regression net (e.g. assert Overall: ship it after trimming the unused 🤖 Reviewed with Claude Code |
Three session-sharing / mobile-viewer improvements (one commit each).
1. Pre-warm + keep the Cloudflare tunnel warm — instant QR (
SessionShareManager.kt)The public Cloudflare QR appeared ~5-15s after clicking Share, because the tunnel was established and verified-routable on the click path (
awaitUrl+awaitReady). This keeps that safety but moves the cost off the critical path:remoteOptoken is the authority — every cooperative teardown bumps the op before killing, so our own kills never respawn, and a persistent failure (FellBack, no adopted process) can't hot-loop.127.0.0.1, share on the0.0.0.0wildcard — and cloudflared (dials127.0.0.1) then hit the MCP server's DNS-rebinding guard (403 "not a loopback target") instead of the viewer. Pre-warm now waits for the MCP server to claim its port first (bounded, only when MCP enabled), and the port loop skips the MCP server's running port.Accepted trade-off: once sharing has been enabled (default mode
cloudflare), each launch spawns a quick tunnel at startup and keeps it for the session. It points at a token-gated server (serves nothing without a?t=token), and Disable session sharing turns it off.2. Tighter QR rendering (
ShareWindow.kt)Asking ZXing for a fixed 256px image made it integer-scale + center the code, baking the slack in as a fat white border. Encode at size 1 (tight 1px-per-module matrix, single-module quiet zone) then upscale by an integer factor → the QR fills the box and stays crisp; the 10dp white frame stays as the scan quiet zone.
3. Keybar
⌨toggles the soft keyboard (viewer.js)The on-screen keyboard button only summoned the keyboard. Now it toggles — blurs the focused textarea to dismiss when up, focuses to summon when down (inside the tap gesture so iOS honours it). "Up" = keyboard inset OR textarea focused, reliable across iOS/Android.
wireKeyButtongained an optional tap action; the key-row buttons are unchanged.Testing
Verified on the dev build + iPhone over a Cloudflare relay: tunnel pre-warms at launch (
reachable via cloudflare: …before any share); the port-collision guard fires (Session-sharing port 7679 is the BossTerm MCP port, trying next → bound 7680); the QR loads the viewer (no 403); stop→re-share is instant; the⌨button shows and hides the keyboard.Generated with Claude Code