fix: route sign-in links by what can actually catch the callback
`isAnthropicSignInUrl` made the container the default action for every Anthropic sign-in link, justified by "the host has nothing to catch it with". That was wrong in both directions. The host does have something -- the auth bridge -- and the container side is not a general browser at all but Playwright's dashboard, whose packages and chromium are deliberately not baked into the image. So the default pointed at the one path that is uninstalled on a fresh project, on every platform, while the path that works sat behind a switch. The decision now lives in `useSignInOpenTarget`: a live auth bridge picks the host, otherwise a container that can actually launch a browser picks the container, otherwise the host. It resolves at mount rather than when a URL arrives, so the buttons do not swap under a moving mouse, and it re-decides on `auth-bridge-changed` so flipping the switch during a hanging login takes effect. A bridge with port conflicts reads as not live; an empty `active_ports` does not, since there is nothing to bridge until the CLI binds its listener and that races the URL. Both buttons still render either way -- this changes which one leads. `sanitizeRelayUrl` is byte-for-byte unchanged, so the embedded copy in web_terminal/terminal.html needs no matching edit. The host "Open" path also failed silently: `dismissUrlPrompt()` ran before `openUrl`, so the toast vanished and a rejected promise reached only the devtools console. Dismissal now happens on success only, leaving "In container" one click away after a failure, and the error surfaces through the same toast the container path already used. On Linux this catch will not fire for the common case -- `xdg-open` routinely exits 0 having done nothing -- so it complements the AppImage environment fix rather than replacing it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+16
-5
@@ -182,11 +182,22 @@ export function extendsUrl(next: string, current: string): boolean {
|
||||
/**
|
||||
* Whether this is a URL that signs the user in to Anthropic.
|
||||
*
|
||||
* Used to decide *presentation*, not permission — the toast makes the
|
||||
* container-side browser the default action for these, because the OAuth
|
||||
* callback listener is inside the container and the host has nothing to catch
|
||||
* it with. It is deliberately the same host allowlist the sign-in flow itself
|
||||
* uses, so the two cannot disagree about what a sign-in link is.
|
||||
* Classification only. It answers "is this a sign-in link", never "where should
|
||||
* it be opened" — that decision moved out to `hooks/useSignInOpenTarget.ts`,
|
||||
* because it depends on things this module has no business knowing: whether the
|
||||
* project's auth bridge is live, and whether a browser is actually installed in
|
||||
* the container. This function stays here because the *rule* it encodes is a
|
||||
* URL rule, and it is deliberately the same host allowlist the sign-in flow
|
||||
* itself uses, so the two cannot disagree about what a sign-in link is.
|
||||
*
|
||||
* It used to carry the default with it — container-side always, on the grounds
|
||||
* that "the OAuth callback listener is inside the container and the host has
|
||||
* nothing to catch it with". Both halves of that are now wrong. The host does
|
||||
* have something to catch it with (the auth bridge mirrors the container's
|
||||
* loopback listener onto the same host port), and the container-side target is
|
||||
* not a general browser but Playwright's dashboard pane, whose browsers are
|
||||
* deliberately not baked into the image — so on a fresh project the default
|
||||
* pointed at something that was not installed, on every platform.
|
||||
*/
|
||||
export function isAnthropicSignInUrl(url: string): boolean {
|
||||
const safe = sanitizeRelayUrl(url, { allowHosts: ANTHROPIC_SIGN_IN_HOSTS });
|
||||
|
||||
Reference in New Issue
Block a user