Skip to content

Offer Refresh when Codex loses its sign-in - #137

Merged
cu1ch3n merged 3 commits into
mainfrom
fix/codex-sign-in-again
Nov 11, 2026
Merged

cu1ch3n merged 3 commits into
mainfrom
fix/codex-sign-in-again

Conversation

@cu1ch3n

@cu1ch3n cu1ch3n commented Nov 11, 2026

Copy link
Copy Markdown
Member

Problem

Papilot's Codex app-server reads its sign-in once, at startup. When another Codex on the host (CLI or desktop app) signs in again or rotates the shared refresh token, Papilot's in-memory token is revoked and every turn fails with:

Your access token could not be refreshed because you have since logged out or signed in to another account. Please sign in again.

Papilot still showed Codex as Ready (its account/read reads the cached account), and Reconnect leaves a running Codex alone, so the only way out was restarting Papilot.

Change

  • Detect a lost sign-in. A failed Codex turn (turn/completed, a non-retrying error, or a failed thread/start/turn/start) whose error is unauthorized, an HTTP 401, or says "could not be refreshed" / "sign in again" marks Codex signed out. Codex 0.164 reports the revoked-token case as codexErrorInfo: "other", so the message is matched too. An account/read refused with 401 at connect (seen with a revoked token: workspace routing discovery unauthorized (401)) now also shows Codex signed out instead of unavailable. Signed out holds queued tasks.
  • Refresh. In that state the composer's connection notice and Settings › Agents › Codex show Refresh instead of Reconnect. It goes through /api/reconnect, which now restarts a running Codex that is signed out, so it loads the host's current auth.json. Turns in progress are marked interrupted (resumable), as on a disconnect. It never restarts on its own: connect() runs only at startup and from this button.
  • If the host itself is signed out, the notice's details say to run papilot codex login there first.

Testing

  • tests/workspace.test.ts: two new tests (revoked-token turn → signed out → Refresh restarts and signs back in, without restarting a signed-in Codex; unrelated failures keep the sign-in; a 401 account read shows signed out). Both fail without the server change. Whole file: 190/190.
  • scripts/check-task-model.mjs: asserts Refresh (and no Reconnect) for a signed-out agent and the "Codex sign-in expired" notice.
  • npm run typecheck, npm run build, npm run i18n -- check, npm run i18n:check-app. New strings are translated for all locales (zh-CN curated, the rest via the i18n pipeline); the pipeline also re-sorted the error dictionaries' keys.

Papilot's Codex reads its sign-in once, when it starts. When another Codex
on the host signs in again or rotates the shared refresh token, its turns
fail with "Your access token could not be refreshed ... Please sign in
again.", yet Papilot still showed Codex as ready, and Reconnect left the
running process alone, so only restarting Papilot recovered.

A Codex turn or account read that fails for lack of a sign-in now shows
Codex signed out, which holds queued tasks. In that state the connection
notice and the agent's settings offer Refresh instead of Reconnect: it
starts Codex again, so it uses the host's current sign-in. Turns in
progress are interrupted and can be resumed.
@cu1ch3n

cu1ch3n commented Nov 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 11, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ✅ Completed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-11T15:49:19.470805Z eeec67e Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e8bc2cc313

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/server/workspace.ts Outdated
Comment on lines +220 to +221
agent.close();
this.disconnected(id, new Error('Codex restarted to load the current sign-in.'));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Notify helper turns when restarting Codex

If Refresh is selected while a Codex helper turn is in flight, agent.close() kills that turn without emitting the agent's disconnected event, and calling Workspace.disconnected() directly does not notify its listeners. In helperTurn(), helpers whose turn/start request already completed are waiting for either a notification or that event, so they remain pending until their timeout instead of failing promptly. This can leave commit-message generation stuck for two minutes or import repair stuck for ten minutes after Refresh has successfully reconnected. Notify the helper listeners as part of this restart so their promises and UI state settle immediately.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in eeec67e: the restart now emits the agent's own disconnected event, so waiting helper turns reject immediately (and tasks are interrupted as before). Covered in the sign-in test.

Codex's close() does not emit 'disconnected', so a commit message or
import repair waiting on a helper turn hung until its timeout after
Refresh. Announce the restart through the agent's own event, which also
interrupts the tasks as before.
@cu1ch3n

cu1ch3n commented Nov 11, 2026

Copy link
Copy Markdown
Member Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

Reviewed commit: eeec67eabd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cu1ch3n
cu1ch3n merged commit 6b07ab5 into main Nov 11, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant