mirror of
https://github.com/Hmbown/DeepSeek-TUI.git
synced 2026-09-03 06:50:13 +08:00
* feat(tui): native ChatGPT PKCE sign-in for openai-codex (#5778) Add a Codewhale-owned Sign in with ChatGPT adapter so the openai-codex route no longer requires Codex CLI. Browser PKCE uses the published auth.openai.com issuer, stores rotating refresh tokens in the existing credentials directory, and keeps external CLI import as an explicit alternative. Device-code is omitted because the issuer does not advertise device_authorization_endpoint. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * docs(changelog): record ChatGPT PKCE and Pod receipts (#5778, #5776) Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): accept the ChatGPT callback on either loopback family The redirect URI has to keep saying `localhost` -- that exact string is what the public Codex client is registered against and redirect matching is exact -- but `localhost` resolves to `::1` as readily as to `127.0.0.1`, and an IPv6-first browser is free to prefer it. Binding only `127.0.0.1` sent that browser to a closed port: Happy Eyeballs turns a working sign-in into a slow one, and where that fallback is off, into a hang until the callback timeout. So bind both families on the chosen port and poll both; a host with only one stack binds that one and still signs in. The redirect URI is untouched. The module doc also claimed revoke used the discovery `revocation_endpoint` while revoke_endpoint() hardcodes `/api/accounts/oauth/revoke`. The hardcoded path is deliberate -- revoke has to clear local credentials even when the issuer is unreachable, and a discovery fetch would only add a failure mode to a cleanup path -- so the doc now says that instead of describing code that was never written. New test drives a real callback into the IPv6 listener with an idle IPv4 listener ahead of it in the poll order, so it fails if either the bind or the polling loop regresses to one family: cargo test -p codewhale-tui --lib chatgpt_oauth test result: ok. 11 passed; 0 failed; 0 ignored; 0 measured; 11659 filtered out Signed-off-by: CodeWhale Bot <bot@codewhale.net> * docs(changelog): drop the branch-time entry; entries move to merge-time receipts on main * fix(test): pin the consent boundary to the ChatGPT auth choice stage The #5778 auth choice for openai-codex routes plain Enter to Stage::ChatgptAuthChoice before any key entry. The #5772 regression test pinned the old Stage::KeyEntry landing and failed on the branch. Walk the new path (Enter -> choice, 2 -> Import from Codex CLI, Enter -> ExternalConsentChoice) and keep every no-I/O trap assertion. * fix(tui): read the ChatGPT OAuth callback until the header terminator One read() is not one request: a fragmented delivery truncates the query and parses as a missing state parameter, failing the login. Read until the blank line ending the HTTP headers (bounded by the 4096-byte buffer and the 5s timeout). Proven failing first: callback_server_handles_success_and_error_requests panicked 'OAuth callback missing state' on this branch head (ubuntu CI run 33490133817 and locally); chatgpt_oauth suite now 11 passed; 0 failed. * fix(tui): /auth chatgpt-revoke runs off the event loop and clears the live route Review findings on #5784 that reviewers agreed should block merge: - The slash command called `revoke_owned_login(None, None)` inline from the async command dispatcher: one blocking reqwest POST per stored token under the OAuth lifecycle lock froze the TUI, `None` missed the session's own `app.config_path`, and `None` left `App.config`'s `oauth_credential_generation` and `auth_mode` stale. It now returns `AppAction::StartChatgptRevoke`; the loop runs the revoke on `spawn_blocking` against the session config path and clears the live route on success, mirroring the PKCE login path. - `auth_mode = "oauth"` is now reset with the generation pointer on revoke (persisted document and live config) and on CLI logout, so a revoked route does not keep claiming OAuth. Evidence: `cargo test -p codewhale-tui --lib chatgpt` test result: ok. 14 passed; 0 failed; 0 ignored (includes the new chatgpt_revoke_slash_command_defers_to_the_event_loop) `cargo check -p codewhale-cli` clean; `cargo fmt --all -- --check` clean. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdbuqwHAXSDcikPiS6L6Qw * ci: re-run — Buildkite build 1502 hung at started for 55 minutes Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AdbuqwHAXSDcikPiS6L6Qw * fix(cli): logout deadlocks re-entering the OAuth lifecycle lock run_logout_command_with_secrets wraps everything in with_xai_oauth_revocation_transaction, which holds the non-reentrant lifecycle mutex; the new chatgpt clear inside it called clear_all_chatgpt_oauth_credentials, which takes the same mutex again. Every logout hung forever — the three logout_* tests spun >47m on buildkite and both Actions test jobs stuck in_progress for 75+ minutes, and a real 'codewhale auth logout' would hang the same way. Add clear_all_chatgpt_oauth_credentials_locked() for callers already inside the transaction (store open is lock-free; the fd lock is not re-taken) and use it from logout. Evidence: cargo test -p codewhale-cli --lib logout_ 'test result: ok. 5 passed; 0 failed' in 0.05s (was: infinite hang). Signed-off-by: CodeWhale Bot <bot@codewhale.net> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>