Release 5.8.0 — Remote Control - #67
Merged
Merged
Conversation
The release workflow reads the version from build.gradle.kts, and the README states it twice as user-facing text: the badge and the name of the artifact buildPlugin writes. All three move together or the README describes a zip that no build produces.
The bump missed a fourth place the version is written. PluginIdentity is the one the plugin announces on every outbound request, and the descriptor cannot be read at runtime without an internal API this build refuses to ship, so the constant is hand-kept and PluginIdentityTest is what keeps it honest. It went red on 5.7.0 against a 5.7.1 build, which is the test doing its job.
The slash command is closed in the mode this plugin launches, and answers "isn't available in this environment". The control request behind it is not: the binary takes a remote_control subtype carrying an enabled flag, and runs the bridge itself with the session credential. That is the same shape as the btw command, which is a side_question request rather than the command it looks like. The reply rides SessionControlClient.send instead of SessionQueries.ask, because a success comes back with no payload at all. Ask decodes the payload whether the request succeeded or failed, so a toggle built on it would paint itself on after a refusal and never say so. Two ways in, one path: the composer's phone button and the settings menu row both emit the same settingsToggle key, so there is one destination to keep honest rather than two that can disagree.
The binary answers the enable request with an error when the account or the organisation has Remote Control switched off, so the host state was already right. What lied was the page. The settings row flipped itself on the click, before the host had answered. That is correct for every other row in this menu, because they write to the settings document and cannot be refused; this is the first one whose destination can say no. Rows may now declare themselves host-owned, and the page leaves those alone until the state it is sent says otherwise. The composer button had no way to fail. It stayed off after a refusal with the reason reachable only by reading the transcript, which is the same as failing silently for anyone who was watching the button they just pressed. The refusal now travels to the page and the button wears it.
Remote Control is a new capability, not a repair, so the release is a minor. The number is written in four places and the release workflow greps only the first of them, which is why the other three are moved in the same commit. The changelog section is the one the release job extracts for the GitHub Release, and the release notes are what the Marketplace shows as What's New. Both name what the feature needs to work, because the refusal a user is most likely to meet is an account or organisation that has Remote Control off.
Approving a call from the phone left the card sitting in the chat forever. With Remote Control on, the binary forwards the prompt to claude.ai as well, and when the remote answers it withdraws the one it left here — over a top-level control_cancel_request frame carrying the request_id it echoes. The parser had no entry for that type, so it fell through to Other and was dropped, and nothing ever took the card down. The withdrawal writes no reply. The binary already has its answer and is no longer waiting, so answering a request that was retracted would be inventing a second verdict. It closes the review diff the same way a rejection does, because a card that leaves without closing it strands the pane. This is the connected surface the feature commit missed: enabling Remote Control adds an inbound frame the plugin never had to understand before.
checkDrift had not been run since the tools moved: it recorded SDK 0.3.233 and binary 2.1.233 against a machine running 0.3.250 and 2.1.250. A drift gate whose baseline is stale reports on a protocol nobody is speaking. The detector updates the tools itself before reporting, which is what moved the lockfile here. The vendored SDK is protocol reference and ships to nobody, and package.json already allowed the newer one, so the range is unchanged. The surface came back fully covered once the withdrawal frame was modelled.
Its own section in the user guide and an entry at the top of What's new. Says what the feature needs before it will work, because the account and organisation gates are the refusal a reader is most likely to meet, and says plainly that the guard still decides first on this machine — connecting a phone changes who can answer a permission, never what the chat may do.
…ontrol feat: drive a chat from claude.ai with Remote Control (5.8.0)
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.
Publishes 5.8.0. Merging this cuts the tag and ships to the Marketplace, unattended.
What ships
Remote Control. A chat running in the IDE can be driven from claude.ai or the Claude mobile
app, and Claude keeps executing locally the whole time. A phone button in the chat's button row,
left of the guard's shield, and a Remote control row in the settings menu. Neither lights up until
the CLI has accepted, and a refusal names its reason on the button and in the chat.
The slash command is closed in the mode this plugin launches the binary in. The control request
behind it is not, and that is what the plugin sends. Neither that subtype nor the withdrawal frame
below is declared in the vendored SDK types, so both were verified against the binary.
A permission answered from the phone now closes its card here. The binary withdraws the prompt
it left with the host over a top-level control_cancel_request frame; the parser had no entry for
that type and dropped it, so the card stayed forever. Found by using the feature, fixed and
validated by hand.
The drift baseline is reconciled. checkDrift still recorded SDK 0.3.233 and binary 2.1.233
against tools at 0.3.250 and 2.1.250. Surface reports fully covered once the withdrawal frame was
modelled. The vendored SDK is protocol reference and ships to nobody.
Gates, run locally on this tree
JVM tests and koverVerify, detekt, spotlessCheck, ESLint, Prettier, 616 frontend tests, npm audit
on the distributed scope at 0 vulnerabilities, verifyPlugin, checkDrift, and the packaging
assertions: 0 node_modules entries in the zip, and LICENSE, THIRD-PARTY-NOTICES.md and the
licences directory present in the jar.
CI on the develop PR was green on the three jobs it runs plus CodeQL.
Validated by hand
Installed in PyCharm and exercised end to end, including approving a call from the phone and
watching the card close, and the refusal path against an account without Remote Control.