[ENG-3568] Stop login hanging when an assistant runs it - #155
Merged
Conversation
Reported from Lovable: the command appears to hang. It does, from the caller's side. An assistant runs a command, waits for it to exit, and only then reads stdout — so a command that prints a link at second zero and then blocks for ten minutes shows nothing until the code has already expired. Splits the flow. `startLogin` returns as soon as the link exists; `waitForApproval` polls. The CLI picks by whether anyone is watching: - interactive terminal — unchanged: print the link, then wait - output captured — print the link and exit, then `login --wait` resumes The pending request is handed between the two invocations through a file in the temp directory, keyed by site. Not the project directory: the device code is a secret with a ten-minute life, and nothing that short-lived belongs somewhere it could be committed. It is never printed either, so it cannot leak through an assistant's captured output. Verified against production: piped, the command now exits in about a second instead of blocking. AGENT-INSTALL states the two-step sequence and the three ways an assistant would otherwise get it wrong — wrapping step one in a timeout, re-running it to retry (which invalidates the link the user is looking at), and running --wait before the user has approved. Co-Authored-By: Claude <noreply@anthropic.com>
|
Clear splitting of interactive and automated login flows solves hanging issue. 🎯 Quality: 100% Elite · 📦 Size: Large — consider splitting if possible 📈 This month: Your 59th PR — above team average · Averaging Excellent |
Splitting start from wait left a gap: nothing writes the credential unless someone comes back and runs the second command. An assistant that forgets leaves the user having approved for nothing. Re-running `login` now resumes the pending request rather than issuing a new one. If the owner has approved, it redeems and finishes; if not, it reports the code and the time remaining and exits. So the second step is the same command as the first, which is one less thing for an assistant to get right, and re-running can no longer invalidate the link the user is looking at — which the previous docs had to warn against. An abandoned flow stays harmless. Approving only marks the request server side; the rotation happens on redeem. Nothing changes until the CLI comes back, so a forgotten flow expires quietly and the site keeps working. Verified against production: a second run reports the same code with the countdown decremented, rather than starting a fresh one. --wait remains as the blocking variant for anyone who wants it. Co-Authored-By: Claude <noreply@anthropic.com>
Contributor
Author
|
/review |
daniloradovic
approved these changes
Aug 20, 2026
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.
Reported from Lovable:
loginappears to hang. It does — and the cause is structural, not a quirk of that tool.🥞 Merge after #153 and #154 (both merged).
Why
An assistant runs a command, waits for it to exit, then reads stdout.
loginprinted the link at second zero and blocked for ten minutes. So the agent saw nothing until the process exited, by which point the code had already expired. Every assistant hits this; Lovable just reported it.The fix — the second step is the same command
Re-running resumes the pending request rather than issuing a new one:
The CLI picks the shape by whether anyone is watching:
A person at a shell still gets the one-command flow they had.
--waitremains as the explicit blocking variant.Why not leave step 3 as
--waitSplitting start from wait fixed the hang but opened a gap: nothing writes the credential unless someone comes back and runs the second command. An assistant that forgets leaves the user having approved for nothing.
Making step 3 the same command as step 1 removes the flag an assistant has to remember, and re-running can no longer invalidate the link the user is looking at — which the previous docs had to warn against. The obvious action is now the correct one.
Verified against production
Same code, countdown decrementing — resuming, not restarting.
An abandoned flow is harmless
RunPulseDeviceFlow::approve()only marks the request server-side; the rotation happens on redeem. So if step 3 never runs, nothing changed, the request expires in ten minutes, and the site keeps working on its existing credential. No orphaned state to clean up.The pending request
Held in
os.tmpdir(), keyed by a hash of the site UUID, mode0600. Not the project directory — the device code is a ten-minute secret and nothing that short-lived belongs somewhere it could be committed. The device code is never printed; only the user code and link are.Closes ENG-3568
🤖 Generated with Claude Code