diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 390725885..6698e81f6 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -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:/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. diff --git a/packages/ai/src/registry/oauth/oauth.html b/packages/ai/src/registry/oauth/oauth.html index 0730c4514..08f54bfd2 100644 --- a/packages/ai/src/registry/oauth/oauth.html +++ b/packages/ai/src/registry/oauth/oauth.html @@ -305,7 +305,7 @@ if (serverState.ok) { app.classList.add("success", "countdown"); title.textContent = "Authentication Successful"; - message.innerHTML = "You have successfully logged in.
This window will close automatically."; + message.innerHTML = "You have successfully logged in.
You can now close this tab."; setTimeout(() => window.close(), 3000); } else { app.classList.add("error"); diff --git a/packages/ai/test/callback-server-launch-route.test.ts b/packages/ai/test/callback-server-launch-route.test.ts index 3d22b4205..9272a5f73 100644 --- a/packages/ai/test/callback-server-launch-route.test.ts +++ b/packages/ai/test/callback-server-launch-route.test.ts @@ -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.
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(); diff --git a/packages/coding-agent/src/prompts/system/workflow-notice.md b/packages/coding-agent/src/prompts/system/workflow-notice.md index 74eddee21..3e62ca5b0 100644 --- a/packages/coding-agent/src/prompts/system/workflow-notice.md +++ b/packages/coding-agent/src/prompts/system/workflow-notice.md @@ -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}}