SIGN IN SIGN UP

feat: support multiple workspaces for the same email (#491) (#493)

* feat(accounts): persist and surface per-account workspaces (#491)

Support a single OpenAI/Google account that belongs to multiple ChatGPT
workspaces (personal Plus vs business/team), each a distinct quota pool
keyed by its org_id. The composite accountId+email matching already keeps
such entries separate, but the workspace metadata captured at login did
not survive a reload and was invisible in list/status output.

- schemas: add WorkspaceSchema and declare workspaces and
  currentWorkspaceIndex on AccountMetadataV3Schema. The strict z.object
  stripped these fields on every load, so login-captured workspaces
  vanished after one read/write round-trip. This is the root cause of the
  reported "workspaceName always empty even after login".
- accounts: surface the active workspace name in formatAccountLabel so two
  same-email accounts in different workspaces stay distinguishable, while
  preserving every existing label format.
- tests: schema round-trip preservation plus label disambiguation coverage.

* feat(workspace): show and switch per-account workspaces (#491)

Build on the workspace-persistence fix by making an email's multiple
workspaces visible and selectable, so personal Plus and business/team under
one Google account can be tracked and rotated between independently.

- accounts: add formatWorkspaceLines, one display line per workspace with the
  active one marked and disabled ones flagged.
- status/list: list every workspace beneath an account when it tracks more
  than one, so both stay visible at once.
- new "workspace <account> [workspace]" command: with an account index it
  lists that account's workspaces; with a workspace index it sets the active
  workspace and persists it. Wired into the command registry, dispatch, and
  help.
- tests: formatWorkspaceLines coverage and nine workspace-command cases.

* feat(login): add --org flag to bind a workspace at login (#491)

Let a user register a specific workspace for an email that belongs to more
than one (personal Plus vs business/team). `--org <org_id>` reuses the
CODEX_AUTH_ACCOUNT_ID override that every login resolver already honors, so the
chosen org is bound for that login and a second workspace can be added on
demand instead of always resolving to the default one.

- help: parse --org <id> and --org=<id> (rejects a missing value), document it
  in the login usage line.
- codex-manager: runAuthLogin sets the override env var from --org for the
  invocation, taking precedence over any inherited value.
- tests: --org parsing and missing-value cases.

* fix(workspace): guard undefined workspace id and cover non-numeric indices (#491)

Address review feedback on the workspace command.

- guard `target.id` with optional chaining when building the id suffix, matching
  formatWorkspaceLines, so non-conforming on-disk data cannot throw.
- add tests for non-numeric account and workspace indices.

* fix(login): scope --org override and restore it after login (#491)

The --org flag set process.env.CODEX_AUTH_ACCOUNT_ID without restoring it, so it
leaked for the whole process: a later login in the same invocation (menu
re-entry) or a reused test worker would silently bind to the stale org.

Split runAuthLogin into a thin wrapper that saves the prior override, sets it
for the org-bound login, and restores (or deletes) it in a finally, delegating
the unchanged flow to runAuthLoginFlow.
N
Neil Daquioag committed
7ecb4adcf731e57591acb0ccea6c4bf50e24679b
Parent: 9807f12
Committed by GitHub <noreply@github.com> on 5/31/2026, 2:22:38 AM