fix(github): wait for browser callback before polling install status#37810
Open
Harshit16g wants to merge 4 commits into
Open
fix(github): wait for browser callback before polling install status#37810Harshit16g wants to merge 4 commits into
Harshit16g wants to merge 4 commits into
Conversation
Closes anomalyco#37786 Root cause: exec(url) opens the GitHub App install page and returns immediately, but the polling loop starts BEFORE the user switches to the browser window. Since xdg-open is non-blocking on Linux, the CLI polls for up to 120 seconds while the user is still reading the GitHub page — by the time they install and the redirect fires, the timeout may already have expired. Fix: start a short-lived HTTP server on the local machine before opening the browser. The server listens on /github-install-callback and returns a friendly 'Authorized!' page. After opening the browser, the CLI waits on the callback promise (up to 5 minutes) instead of polling. The browser redirect fires when the user completes installation, resolving the promise and unblocking the verification poll. The 5-minute timeout ensures the CLI never hangs forever. Changes: - packages/opencode/src/cli/cmd/github.handler.ts: replace do-while polling with startCallbackServer() + waitForCallback() before polling - packages/opencode/src/util/callback-server.ts: new utility providing startCallbackServer() and waitForCallback() for browser-based OAuth flows
Contributor
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
Harshit16g
marked this pull request as ready for review
July 19, 2026 20:58
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.
Issue for this PR
Closes #37786
Type of change
What does this PR do?
opencode github installhangs indefinitely on Linux and silently times out on macOS/Windows. The root cause is thatxdg-open/open/startare non-blocking — they return instantly. The old code immediately entered a 120-iteration polling loop (2 minutes) before the user had even switched to the browser window. On any normal install, the loop exhausted before GitHub's post-install redirect fired.Root cause:
Fix — 4 files changed across 2 commits:
packages/opencode/src/util/callback-server.ts(new file)A minimal, event-driven HTTP server utility. Key design decisions:
127.0.0.1:0so the OS assigns a free port — no hardcoded port collision risk.promiseon the returnedCallbackServerobject that resolves only when the real browser hits the configured path. No internal polling anywhere.waitForCallback()doesPromise.race([server.promise, timeout])— purely reactive, nosetInterval.server.close()is idempotent and rejects the internal promise cleanly if called before the callback fires (e.g. on SIGINT).packages/opencode/src/cli/cmd/github.handler.ts(modified)redirect_uri=http://127.0.0.1:{port}/github-install-callback— this is what causes GitHub to redirect the browser back to the local server after the user clicks Install.do { poll } while (true)loop withawait waitForCallback(server, { timeoutMs: 300_000 }).getInstallation()) to confirm the install is visible server-side.server.close()calls — the server closes itself 500ms after serving the success page.packages/opencode/test/util/callback-server.test.ts(new file, 6 unit tests)Covers: port binding, HTML 200 response on correct path, 404 on wrong path without false-resolving the promise,
waitForCallbackresolving on real browser hit,waitForCallbackrejecting after timeout,close()idempotency.packages/opencode/test/util/callback-server-integration.test.ts(new file, 4 integration tests)Exercises the full
installGitHubApp()flow end-to-end: happy path (server binds → simulated browser redirect →waitForCallbackresolves), timeout path (rejects within 1s with no browser hit), wrong-path 404 guard (does not accidentally resolve the promise), and the already-installed bypass (API returns truthy on first check, callback server never started).How did you verify your code works?
Unit + integration tests — 10/10 pass locally (
bun test):Live CLI run on a repo where the app is already installed:
Confirmed
installGitHubApp()short-circuits before the callback server is even created when the app is already installed.Live CLI run on a fresh repo (new-install path):
The spinner displayed
Waiting for GitHub app to be installed — complete it in your browserand held open correctly until the 5-minute timeout — proving the CLI no longer races the user.Screenshots / recordings
No UI change — terminal-only flow.
Checklist