fix(ai): clarified oauth completion close copy
Updated the OAuth success page so Firefox users are told they can close the tab manually while the existing close button and timeout remain best-effort. Added callback-server coverage for the served success page copy. Fixes #4855
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
- Fixed OpenAI Codex WebSocket continuations to treat proxy stale-anchor codes such as `codex_previous_response_stale` as an expired `previous_response_id` chain — same recovery class as the OpenAI-standard `previous_response_not_found` — so the turn is retried with full context instead of surfacing the error to the user ([#4624](https://github.com/can1357/oh-my-pi/issues/4624)).
|
||||
- Fixed Azure Foundry Anthropic utility requests to omit the structured-output beta whenever strict tools are disabled, preventing `structured_outputs not supported in your workspace` failures for Sonnet 5 compaction ([#4679](https://github.com/can1357/oh-my-pi/issues/4679)).
|
||||
- Fixed OAuth `launchUrl` advertisement for flows whose redirect never returns to the local callback server: custom-scheme redirects (e.g. GitLab Duo's `vscode://` URI, which `new URL` parses without complaint) and fixed non-loopback hosts no longer receive a `http://localhost:<port>/launch` copy target that misrepresents the callback endpoint and resolves nowhere for remote users.
|
||||
- Fixed the OAuth completion page copy to tell users they can close the tab manually when browsers such as Firefox ignore best-effort `window.close()` calls. ([#4855](https://github.com/can1357/oh-my-pi/issues/4855))
|
||||
### Fixed
|
||||
|
||||
- Codex load balancing: clear stale persisted and in-memory usage-limit blocks for an `openai-codex` account when a fresh live usage report shows it is allowed and below all limits, including broker-backed gateway snapshots, so traffic returns to recovered accounts instead of funneling to one sibling.
|
||||
|
||||
@@ -305,7 +305,7 @@
|
||||
if (serverState.ok) {
|
||||
app.classList.add("success", "countdown");
|
||||
title.textContent = "Authentication Successful";
|
||||
message.innerHTML = "You have successfully logged in.<br>This window will close automatically.";
|
||||
message.innerHTML = "You have successfully logged in.<br>You can now close this tab.";
|
||||
setTimeout(() => window.close(), 3000);
|
||||
} else {
|
||||
app.classList.add("error");
|
||||
|
||||
@@ -114,6 +114,24 @@ describe("OAuthCallbackFlow /launch route", () => {
|
||||
await login;
|
||||
});
|
||||
|
||||
it("serves success copy that permits manual tab close", async () => {
|
||||
const { info, login } = await startFlowAndWaitForAuth();
|
||||
const authUrl = new URL(info.url);
|
||||
const redirectUri = authUrl.searchParams.get("redirect_uri");
|
||||
expect(redirectUri).toMatch(/^http:\/\/localhost:\d+\/callback$/);
|
||||
const state = authUrl.searchParams.get("state") ?? "";
|
||||
|
||||
const callbackResponse = await fetch(`${redirectUri}?code=test-code&state=${encodeURIComponent(state)}`);
|
||||
expect(callbackResponse.status).toBe(200);
|
||||
const html = await callbackResponse.text();
|
||||
|
||||
expect(html).toContain("Authentication Successful");
|
||||
expect(html).toContain("You have successfully logged in.<br>You can now close this tab.");
|
||||
expect(html).toContain("Close Window");
|
||||
expect(html).not.toContain("This window will close automatically.");
|
||||
await login;
|
||||
});
|
||||
|
||||
it("suppresses launchUrl and routes /launch to the callback handler when callbackPath is /launch", async () => {
|
||||
const abort = new AbortController();
|
||||
const authFired = Promise.withResolvers<OAuthAuthInfo>();
|
||||
|
||||
@@ -51,20 +51,20 @@ Decompose first, then {{#if taskBatch}}batch the independent leaves{{else}}issue
|
||||
|
||||
{{#if taskBatch}}
|
||||
task(
|
||||
context: "# Goal\nReview the auth diff...\n# Constraints\nRead-only...\n# Contract\nReturn findings as severity/file/line/fix...",
|
||||
context: "# Goal\nReview the auth diff…\n# Constraints\nRead-only…\n# Contract\nReturn findings as severity/file/line/fix…",
|
||||
tasks: [
|
||||
{ id: "AuthOwner", role: "Auth Storage Reviewer", assignment: "# Target\npackages/ai/src/auth-storage.ts\n# Change\nTrace credential selection...\n# Acceptance\nReturn confirmed findings only..." },
|
||||
{ id: "PromptOwner", role: "Prompt Contract Reviewer", assignment: "# Target\npackages/coding-agent/src/prompts/**\n# Change\nCheck active-tool guidance...\n# Acceptance\nReturn mismatches and exact prompt lines..." },
|
||||
{ id: "AuthOwner", role: "Auth Storage Reviewer", assignment: "# Target\npackages/ai/src/auth-storage.ts\n# Change\nTrace credential selection…\n# Acceptance\nReturn confirmed findings only…" },
|
||||
{ id: "PromptOwner", role: "Prompt Contract Reviewer", assignment: "# Target\npackages/coding-agent/src/prompts/**\n# Change\nCheck active-tool guidance…\n# Acceptance\nReturn mismatches and exact prompt lines…" },
|
||||
]
|
||||
)
|
||||
{{else}}
|
||||
task(
|
||||
role: "Auth Storage Reviewer",
|
||||
assignment: "# Target\npackages/ai/src/auth-storage.ts\n# Change\nReview the auth diff. Shared contract: read-only; return findings as severity/file/line/fix.\n# Acceptance\nReturn confirmed findings only..."
|
||||
assignment: "# Target\npackages/ai/src/auth-storage.ts\n# Change\nReview the auth diff. Shared contract: read-only; return findings as severity/file/line/fix.\n# Acceptance\nReturn confirmed findings only…"
|
||||
)
|
||||
task(
|
||||
role: "Prompt Contract Reviewer",
|
||||
assignment: "# Target\npackages/coding-agent/src/prompts/**\n# Change\nCheck active-tool guidance. Shared contract: read-only; return mismatches and exact prompt lines.\n# Acceptance\nReturn confirmed findings only..."
|
||||
assignment: "# Target\npackages/coding-agent/src/prompts/**\n# Change\nCheck active-tool guidance. Shared contract: read-only; return mismatches and exact prompt lines.\n# Acceptance\nReturn confirmed findings only…"
|
||||
)
|
||||
{{/if}}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user