Keep one host record per remote device and show its platform - #451
Merged
Merged
Conversation
Claude Code echoes the launch id (`claude-opus-5[1m]`) in its `init` message while the API reports the bare id, so every Opus 5 / Fable 5 session opened with a spurious "model changed" divider. - Only append the manifest's context suffix when the selected window exceeds the model's default; 1M-default slugs launch bare. Smaller selections keep compacting early via `autoCompactWindow`. - Resolve manifest aliases (`opus`, `claude-opus-5.0`) to the canonical slug before launch, matching upstream t3code. - Treat a `[1m]` launch id and its bare form as the same served model when deciding whether to draw the divider. Only the fixed `[1m]` suffix is ignored.
Claude Code strips model suffixes with /\[1m\]$/i and its canonical-name normalizer already accepts [2m], so the served-model comparison now ignores that explicit, case-insensitive list. Arbitrary [...] suffixes are still treated as a real model change.
Clients now send a persistent, self-generated device id with /pair, /auth/login and the websocket hello. A host that already holds a record for that id rotates its token and refreshes the name instead of adding a second device, so repeated pairings no longer pile up credentials. Clients also report their operating system: Android sends the Settings device name (or marketing name) plus "Android <release>", iOS the device name plus "iOS <version>", desktop the computer name plus the OS version, and the browser its family plus the OS from the user agent. Connected device rows read "Xiaomi 15 · Android 15" instead of a bare model code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Behaviour
One device per peer on the host. Every client now owns a persistent, self-generated device id (native apps keep it in
mobile.json, the browser inlocalStorageundertcode.device_id) and sends it asdevice_idwith/pair,/auth/loginand the websocket hello. When the host already holds a record for that id,issue_tokenrotates that record's token and refreshes its details, keeping the record id and first-connection time; the previous token stops validating. Clients without an id (older builds) keep today's behaviour. On a valid hello the host also refreshes the stored name/platform, persisting only on change, so a rename or OS upgrade shows without re-pairing.Device name · platform. Clients report a
platformstring next todevice_name, and the Connected devices rows (desktop hosting panel and the remote hosting view) render‹name› · ‹platform›:ro.product.marketname→ manufacturer + model, plusAndroid <release>(e.g.Xiaomi 15 · Android 15instead of24129PN74C).UIDevice.nameplusiOS <version>.macOS <version>(sysctlkern.osproductversion),Windows <major.minor.build>(RtlGetVersion) or the/etc/os-releasepretty name.Chrome · macOS).Client-side saved hosts were already replaced by
host_id; that policy now lives in oneremember_hosthelper used by the shell, the--paircommand and the web client.Wire
POST /pair:{"code","device_name","device_id"?,"platform"?}POST /auth/login:{"password","device_name","device_id"?,"platform"?}device_idandplatformdevices[]andDeviceInfo: optionalplatform;remote.jsonrecords gain optionalclient_id/platform. No protocol version bump; all new fields are optional.Abstractions
DeviceIdentityintcode_client::hostis the single owner of the pair body and hello line shared by native and web transports.DeviceClaimon the server owns validation of the three device fields for all three entry points. The only manifest change is thewindowscrate (already in the lock file) forcfg(windows)intcode-remote.Tests
auth.rs: re-pairing with the same client id yields one record with a rotated token, id andcreated_unixkept; a hello refresh writes only on change; an olderremote.jsonwithout the new fields loads.tests/remote.rs: a second/pairwith the samedevice_iddoes not add a device, the old token is rejected, the hosting-state row is asserted literally withplatform, and a hello with a new platform shows in hosting state.client_host.rs: device id minted once and shared by later instances; os-release parsing.client/host.rs: literal pair/hello JSON; id reuse vs. minting.auth.test.mjslogin body and id persistence.Checks run
cargo fmt --all --check,cargo clippy --workspace --all-targets --locked -- -D warnings,cargo test --workspace --locked: pass.cargo machete: clean.RUSTFLAGS='-D warnings'checks:tcode-web(wasm32),tcode-ios(aarch64-apple-ios-sim),tcode-android(arm64-v8a via cargo ndk): pass.tcode-remotechecked forx86_64-pc-windows-gnuandx86_64-unknown-linux-gnu.node --test crates/web/static/auth.test.mjs: pass.Not verified: no on-device Android/iOS run (Java compiled against android.jar only, Swift not built); Windows and Linux version strings are compile-checked only. The Android name depends on the phone's Settings device name or
ro.product.marketname.