feat(cli): enable auth by default and auto-authorize --open via OTP#124
Merged
Conversation
Every built-in plugin's standalone CLI now gates the dev server behind devframe's interactive OTP handshake by default (code-server, git, inspect, messages, terminals, data-inspector previously opted out; og/a11y already defaulted on). Each plugin keeps an `auth` option to opt back out for single-user/CI use. To keep that gate from adding friction, `--open` now asks the resolved auth handler to rewrite the launched URL — the interactive handler embeds the current OTP (via buildOtpAuthUrl), so the opened tab authenticates automatically instead of prompting for a code. Adds DevframeAuthHandler.buildOpenUrl (optional) as the seam, wires it through maybeOpenBrowser in the dev adapter, and updates docs/skill guidance + tsnapi snapshots accordingly. Co-authored-by: opencode <noreply@opencode.ai>
✅ Deploy Preview for devfra ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
connectDevframe()/getDevframeRpcClient() kicks off the auth bootstrap (stored token, then the URL's magic-link OTP, then a native-prompt fallback) without waiting for it, so it can return the client right away. A caller's very first RPC calls — e.g. a component's onMount, fired the instant connectDevframe() resolves — raced that still in-flight sequence: the socket was already open, so the transport sent them straight through, and the server rejected them with DF0036 because trust hadn't landed yet, even though the exact same call would succeed a moment later once the handshake completed. rpc.call/callOptional/callEvent now hold anything issued before the first bootstrap attempt settles and release it (or fail fast, if the handshake ultimately failed) once it does. This lives once in devframe's client RPC core, so every plugin's standalone/hosted SPA gets it automatically — no plugin-level changes needed. Co-authored-by: opencode <noreply@opencode.ai>
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.
Summary
code-server,git,inspect,messages,terminals, anddata-inspectorpreviously opted out withauth: false/auth: options.auth ?? false;oganda11yalready defaulted on. Each plugin keeps anauthoption (anddata-inspector's CLI a--no-authflag) to opt back out for single-user/CI use.--opennow asks the resolved auth handler to rewrite the launched URL before opening it.createInteractiveAuthimplements this by embedding the current OTP (viabuildOtpAuthUrl), so the tab the CLI opens lands already authenticated instead of prompting for a code.DevframeAuthHandler.buildOpenUrl(optional) as the seam and wires it throughmaybeOpenBrowserin thedevadapter; a handler that omits it (e.g. a pre-shared-token scheme) leaves the opened URL unchanged.connectDevframe()/getDevframeRpcClient()kicks off the handshake (stored token → URL OTP → native-prompt fallback) without waiting for it, so a caller's very first RPC calls (e.g. a component'sonMount, fired the instant the client is available) could race that still-in-flight sequence — the socket was already open, so the transport sent them straight through, and the server rejected them withDF0036even though the exact same call succeeds moments later.rpc.call/callOptional/callEventnow hold anything issued before the first bootstrap attempt settles and release it (or fail fast, if the handshake ultimately failed) once it does. This lives once in devframe's client RPC core, so every plugin's standalone/hosted SPA gets it automatically — no plugin-level changes needed.Optionstype gainedauth?: boolean.Verification
pnpm build && pnpm lint && pnpm typecheckall pass.pnpm exec vitest run— 834/834 tests pass across every package/plugin, including:dev.test.tscases asserting the OTP is embedded in the opened URL when auth is on, and that the plain origin opens whenauth: false.rpc-auth-gate.test.tscases provingcall/callOptional/callEventhold until the auth bootstrap settles, then release (verified the tests fail without the fix and pass with it).This PR was created with the help of an agent.