From cccb77b552af59be55df2475115ac4ea2e6a963b Mon Sep 17 00:00:00 2001 From: hkfires <10558748+hkfires@users.noreply.github.com> Date: Fri, 20 Mar 2026 03:48:30 +0000 Subject: [PATCH] fix(auth): avoid blocking oauth callback wait on prompt --- sdk/auth/antigravity.go | 25 +++++++++++++++++++++---- sdk/auth/claude.go | 25 +++++++++++++++++++++---- sdk/auth/codex.go | 25 +++++++++++++++++++++---- sdk/auth/iflow.go | 25 +++++++++++++++++++++---- internal/auth/gemini/gemini_auth.go | 31 ++++++++++++++++++++++++------- 5 file(s) changed, 108 insertion(s)(+), 23 deletion(s)(-) diff --git a/sdk/auth/antigravity.go b/sdk/auth/antigravity.go --- a/sdk/auth/antigravity.go +++ b/sdk/auth/antigravity.go @@ -98,6 +98,9 @@ defer manualPromptTimer.Stop() } + var manualInputCh <-chan string + var manualInputErrCh <-chan error + waitForCallback: for { select { @@ -115,10 +118,22 @@ break waitForCallback default: } - input, errPrompt := opts.Prompt("Paste the antigravity callback URL (or press Enter to keep waiting): ") - if errPrompt != nil { - return nil, errPrompt - } + inputCh := make(chan string, 1) + inputErrCh := make(chan error, 1) + go func() { + input, errPrompt := opts.Prompt("Paste the antigravity callback URL (or press Enter to keep waiting): ") + if errPrompt != nil { + inputErrCh <- errPrompt + return + } + inputCh <- input + }() + manualInputCh = inputCh + manualInputErrCh = inputErrCh + continue + case input := <-manualInputCh: + manualInputCh = nil + manualInputErrCh = nil parsed, errParse := misc.ParseOAuthCallback(input) if errParse != nil { return nil, errParse @@ -132,6 +147,8 @@ Error: parsed.Error, } break waitForCallback + case errManual := <-manualInputErrCh: + return nil, errManual case <-timeoutTimer.C: return nil, fmt.Errorf("antigravity: authentication timed out") } diff --git a/sdk/auth/claude.go b/sdk/auth/claude.go --- a/sdk/auth/claude.go +++ b/sdk/auth/claude.go @@ -124,6 +124,9 @@ defer manualPromptTimer.Stop() } + var manualInputCh <-chan string + var manualInputErrCh <-chan error + waitForCallback: for { select { @@ -149,10 +152,22 @@ return nil, err default: } - input, errPrompt := opts.Prompt("Paste the Claude callback URL (or press Enter to keep waiting): ") - if errPrompt != nil { - return nil, errPrompt - } + inputCh := make(chan string, 1) + inputErrCh := make(chan error, 1) + go func() { + input, errPrompt := opts.Prompt("Paste the Claude callback URL (or press Enter to keep waiting): ") + if errPrompt != nil { + inputErrCh <- errPrompt + return + } + inputCh <- input + }() + manualInputCh = inputCh + manualInputErrCh = inputErrCh + continue + case input := <-manualInputCh: + manualInputCh = nil + manualInputErrCh = nil parsed, errParse := misc.ParseOAuthCallback(input) if errParse != nil { return nil, errParse @@ -167,6 +182,8 @@ Error: parsed.Error, } break waitForCallback + case errManual := <-manualInputErrCh: + return nil, errManual } } diff --git a/sdk/auth/codex.go b/sdk/auth/codex.go --- a/sdk/auth/codex.go +++ b/sdk/auth/codex.go @@ -127,6 +127,9 @@ defer manualPromptTimer.Stop() } + var manualInputCh <-chan string + var manualInputErrCh <-chan error + waitForCallback: for { select { @@ -152,10 +155,22 @@ return nil, err default: } - input, errPrompt := opts.Prompt("Paste the Codex callback URL (or press Enter to keep waiting): ") - if errPrompt != nil { - return nil, errPrompt - } + inputCh := make(chan string, 1) + inputErrCh := make(chan error, 1) + go func() { + input, errPrompt := opts.Prompt("Paste the Codex callback URL (or press Enter to keep waiting): ") + if errPrompt != nil { + inputErrCh <- errPrompt + return + } + inputCh <- input + }() + manualInputCh = inputCh + manualInputErrCh = inputErrCh + continue + case input := <-manualInputCh: + manualInputCh = nil + manualInputErrCh = nil parsed, errParse := misc.ParseOAuthCallback(input) if errParse != nil { return nil, errParse @@ -170,6 +185,8 @@ Error: parsed.Error, } break waitForCallback + case errManual := <-manualInputErrCh: + return nil, errManual } } diff --git a/sdk/auth/iflow.go b/sdk/auth/iflow.go --- a/sdk/auth/iflow.go +++ b/sdk/auth/iflow.go @@ -109,6 +109,9 @@ defer manualPromptTimer.Stop() } + var manualInputCh <-chan string + var manualInputErrCh <-chan error + waitForCallback: for { select { @@ -128,10 +131,22 @@ return nil, fmt.Errorf("iflow auth: callback wait failed: %w", err) default: } - input, errPrompt := opts.Prompt("Paste the iFlow callback URL (or press Enter to keep waiting): ") - if errPrompt != nil { - return nil, errPrompt - } + inputCh := make(chan string, 1) + inputErrCh := make(chan error, 1) + go func() { + input, errPrompt := opts.Prompt("Paste the iFlow callback URL (or press Enter to keep waiting): ") + if errPrompt != nil { + inputErrCh <- errPrompt + return + } + inputCh <- input + }() + manualInputCh = inputCh + manualInputErrCh = inputErrCh + continue + case input := <-manualInputCh: + manualInputCh = nil + manualInputErrCh = nil parsed, errParse := misc.ParseOAuthCallback(input) if errParse != nil { return nil, errParse @@ -145,6 +160,8 @@ Error: parsed.Error, } break waitForCallback + case errManual := <-manualInputErrCh: + return nil, errManual } } if result.Error != "" { diff --git a/internal/auth/gemini/gemini_auth.go b/internal/auth/gemini/gemini_auth.go --- a/internal/auth/gemini/gemini_auth.go +++ b/internal/auth/gemini/gemini_auth.go @@ -305,6 +305,9 @@ defer manualPromptTimer.Stop() } + var manualInputCh <-chan string + var manualInputErrCh <-chan error + waitForCallback: for { select { @@ -326,13 +329,25 @@ return nil, err default: } - input, err := opts.Prompt("Paste the Gemini callback URL (or press Enter to keep waiting): ") - if err != nil { - return nil, err - } - parsed, err := misc.ParseOAuthCallback(input) - if err != nil { - return nil, err + inputCh := make(chan string, 1) + inputErrCh := make(chan error, 1) + go func() { + input, err := opts.Prompt("Paste the Gemini callback URL (or press Enter to keep waiting): ") + if err != nil { + inputErrCh <- err + return + } + inputCh <- input + }() + manualInputCh = inputCh + manualInputErrCh = inputErrCh + continue + case input := <-manualInputCh: + manualInputCh = nil + manualInputErrCh = nil + parsed, errParse := misc.ParseOAuthCallback(input) + if errParse != nil { + return nil, errParse } if parsed == nil { continue @@ -345,6 +360,8 @@ } authCode = parsed.Code break waitForCallback + case errManual := <-manualInputErrCh: + return nil, errManual case <-timeoutTimer.C: return nil, fmt.Errorf("oauth flow timed out") } -- tangled.sh