Skip to content

feat!: rename oc-chatgpt-multi-auth to oc-codex-multi-auth#104

Merged
ndycode merged 2 commits intomainfrom
git-plan/oc-codex-multi-auth-rebrand
Apr 6, 2026
Merged

feat!: rename oc-chatgpt-multi-auth to oc-codex-multi-auth#104
ndycode merged 2 commits intomainfrom
git-plan/oc-codex-multi-auth-rebrand

Conversation

@ndycode
Copy link
Copy Markdown
Owner

@ndycode ndycode commented Apr 6, 2026

Summary

  • rename the package, repo-facing plugin entry, installer surface, and runtime branding from oc-chatgpt-multi-auth to oc-codex-multi-auth
  • migrate active and flagged account storage to package-aligned filenames while preserving automatic migration from legacy project/global paths and older package-era names
  • refresh README/docs/config examples for the Codex-first package line and add the 6.0.0 cutover checklist

Testing

  • npm run lint
  • npm run build
  • npm test
  • Not applicable

Compliance Confirmation

  • This change stays within the repository scope and OpenAI Terms of Service expectations.
  • This change uses official authentication flows only and does not add bypass, scraping, or credential-sharing behavior.
  • I updated tests and documentation when the change affected users, maintainers, or repository behavior.

Notes

  • Linked issue: none
  • Follow-up work or rollout notes: npm run typecheck also passes. This is an intentional breaking rename for 6.0.0; post-merge cutover still needs the GitHub repo rename, npm publish for oc-codex-multi-auth, and npm deprecation for oc-chatgpt-multi-auth.

Summary by CodeRabbit

  • New Features

    • Automatic storage migration from previous package versions on first load.
  • Chores

    • Renamed package to oc-codex-multi-auth (v6.0.0 breaking change).
    • Updated OAuth authentication option labels from "ChatGPT Plus/Pro MULTI" to "Codex OAuth."
    • Cleared npm cache registry entries to prevent stale artifacts.
    • Updated all documentation and configuration examples for new package name.

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

this PR renames the package from oc-chatgpt-multi-auth to oc-codex-multi-auth (v6.0.0), centralises storage filename constants in lib/constants.ts, consolidates legacy migration into a generic migrateStorageFileIfNeeded helper, adds a new global-storage migration path, ships a rewritten installer with windows atomic-write retry logic, and updates all docs, config examples, and tests consistently.

  • critical data-loss gap (lib/storage.ts): the rename changes the active per-project storage filename from openai-codex-accounts.json to oc-codex-multi-auth-accounts.json in the same ~/.opencode/projects/<key>/ directory, but there is no migration from the old name in that directory. currentLegacyProjectStoragePath points at <projectRoot>/.opencode/openai-codex-accounts.json (the pre-v5.x local path), and getLegacyGlobalAccountsStoragePath() points at ~/.opencode/openai-codex-accounts.json — neither covers the v5.x primary path ~/.opencode/projects/<key>/openai-codex-accounts.json. any user upgrading from v5.x with project-scoped storage silently loses all accounts and oauth tokens.
  • windows locking concern: writeAccountsToPathUnlocked is called for the global path while holding only the project storage lock; concurrent processes migrating global storage simultaneously race on the atomic rename without a guard.
  • missing vitest coverage: the new migrateLegacyGlobalStorageIfNeeded() branch inside loadAccountsInternal (non-project-fallback ENOENT path, lines 842-848) has no test; no test exists for the v5.x per-project-global upgrade scenario either.
  • installer scripts/install-oc-codex-multi-auth-core.js is clean: atomic writes, exponential-backoff windows retry on EPERM/EBUSY, backup-before-overwrite, and legacy package removal from cache are all well-tested.
  • docs, config, and module-level renames are consistent and complete.

Confidence Score: 1/5

not safe to merge — v5.x users with per-project storage will silently lose all stored accounts and oauth tokens on upgrade to v6.0.0

one critical P0 data-loss bug (missing migration for the exact path v5.x wrote to) blocks merge; a P1 windows concurrency race in global migration and missing vitest coverage add further risk

lib/storage.ts (missing per-project-global migration path) and test/storage.test.ts (missing regression test for v5.x upgrade scenario)

Important Files Changed

Filename Overview
lib/storage.ts generic migration helper is clean, but missing the v5.x per-project-global path (~/.opencode/projects/<key>/openai-codex-accounts.json) — existing users lose accounts on upgrade
lib/constants.ts exports all filename constants clearly; LEGACY_ACCOUNTS_FILE_NAME covers global and local-project dirs but no per-project-global constant is defined
scripts/install-oc-codex-multi-auth-core.js new installer with atomic writes, exponential windows retry, backup-before-overwrite, and legacy package removal — well structured and fully exported for testing
test/install-oc-codex-multi-auth.test.ts good installer test coverage: windows lock retry, merged catalog, plugin normalisation, --no-cache-clear, and template collision detection
test/storage.test.ts filename assertions updated correctly; no new tests for the v5.x per-project upgrade path or the new non-project-fallback global migration branch
test/storage-async.test.ts filename path assertions updated to oc-codex-multi-auth-accounts.json — straightforward and correct
package.json clean rename to oc-codex-multi-auth 6.0.0 with updated bin entry, repository, homepage, and bugs URLs

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["loadAccountsInternal ENOENT"] --> B["migrateProjectLocal?\ngetProjectConfigDir / LEGACY_FILE\n&lt;projectRoot&gt;/.opencode/openai-codex-accounts.json"]
    B -- found --> C["Return migrated project-local data ✅"]
    B -- not found --> D{"shouldUseProjectGlobalFallback?"}
    D -- false --> E["migrateLegacyGlobal?\ngetConfigDir / LEGACY_FILE\n~/.opencode/openai-codex-accounts.json"]
    E -- found --> F["Return migrated global data ✅"]
    E -- not found --> G["Return null"]
    D -- true --> H["loadGlobalAccountsFallback"]
    H --> I["migrateLegacyGlobal?\ngetConfigDir / LEGACY_FILE"]
    I -- found --> J["Return migrated global data ✅"]
    I -- not found --> K["Read getConfigDir / ACCOUNTS_FILE"]
    K -- found --> L["Return global data seeded to project ✅"]
    K -- not found --> G
    M["❌ MISSING PATH\ngetProjectGlobalConfigDir / LEGACY_FILE\n~/.opencode/projects/key/openai-codex-accounts.json\nwhere v5.x actually wrote per-project storage"] -. never checked .-> A
Loading

Comments Outside Diff (1)

  1. lib/storage.ts, line 284-294 (link)

    P0 missing v5.x → v6.0.0 per-project global storage migration

    v5.x stored project-scoped accounts at ~/.opencode/projects/<key>/openai-codex-accounts.json — that was the value of currentStoragePath in v5.x (line 288 used getProjectGlobalConfigDir(projectRoot) + the old ACCOUNTS_FILE_NAME). v6.0.0 changes the filename but keeps the same dir. the two migration paths added by this PR cover:

    • <projectRoot>/.opencode/openai-codex-accounts.jsoncurrentLegacyProjectStoragePath
    • ~/.opencode/openai-codex-accounts.jsongetLegacyGlobalAccountsStoragePath()

    but neither covers ~/.opencode/projects/<key>/openai-codex-accounts.json. any user who ran v5.x in project mode hits ENOENT on the new filename, both migration checks fail, loadGlobalAccountsFallback() also won't find their data, and loadAccountsInternal returns null — silently discarding all stored accounts and OAuth tokens.

    a third migration path is needed:

    // add to lib/storage.ts
    function getLegacyProjectGlobalStoragePath(): string {
      if (!currentProjectRoot) return "";
      return join(getProjectGlobalConfigDir(currentProjectRoot), LEGACY_ACCOUNTS_FILE_NAME);
    }
    
    async function migrateLegacyProjectGlobalStorageIfNeeded(
      persist: (storage: AccountStorageV3) => Promise<void> = saveAccounts,
    ): Promise<AccountStorageV3 | null> {
      return migrateStorageFileIfNeeded(
        getLegacyProjectGlobalStoragePath(),
        getStoragePath(),
        persist,
        "per-project global account storage",
      );
    }

    this should be called in the ENOENT handler before migrateLegacyProjectStorageIfNeeded. a regression test covering the v5.x → v6.0.0 upgrade path is also missing from test/storage.test.ts.

    windows risk: if the legacy file is locked by antivirus during fs.unlink, the stale token file persists on disk — the warn log should redact the refreshToken field.

    Rule Used: What: Every code change must explain how it defend... (source)

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: lib/storage.ts
    Line: 284-294
    
    Comment:
    **missing v5.x → v6.0.0 per-project global storage migration**
    
    v5.x stored project-scoped accounts at `~/.opencode/projects/<key>/openai-codex-accounts.json` — that was the value of `currentStoragePath` in v5.x (line 288 used `getProjectGlobalConfigDir(projectRoot)` + the old `ACCOUNTS_FILE_NAME`). v6.0.0 changes the filename but keeps the same dir. the two migration paths added by this PR cover:
    - `<projectRoot>/.opencode/openai-codex-accounts.json``currentLegacyProjectStoragePath`
    - `~/.opencode/openai-codex-accounts.json``getLegacyGlobalAccountsStoragePath()`
    
    but neither covers `~/.opencode/projects/<key>/openai-codex-accounts.json`. any user who ran v5.x in project mode hits ENOENT on the new filename, both migration checks fail, `loadGlobalAccountsFallback()` also won't find their data, and `loadAccountsInternal` returns `null` — silently discarding all stored accounts and OAuth tokens.
    
    a third migration path is needed:
    ```typescript
    // add to lib/storage.ts
    function getLegacyProjectGlobalStoragePath(): string {
      if (!currentProjectRoot) return "";
      return join(getProjectGlobalConfigDir(currentProjectRoot), LEGACY_ACCOUNTS_FILE_NAME);
    }
    
    async function migrateLegacyProjectGlobalStorageIfNeeded(
      persist: (storage: AccountStorageV3) => Promise<void> = saveAccounts,
    ): Promise<AccountStorageV3 | null> {
      return migrateStorageFileIfNeeded(
        getLegacyProjectGlobalStoragePath(),
        getStoragePath(),
        persist,
        "per-project global account storage",
      );
    }
    ```
    this should be called in the ENOENT handler before `migrateLegacyProjectStorageIfNeeded`. a regression test covering the v5.x → v6.0.0 upgrade path is also missing from `test/storage.test.ts`.
    
    windows risk: if the legacy file is locked by antivirus during `fs.unlink`, the stale token file persists on disk — the warn log should redact the `refreshToken` field.
    
    **Rule Used:** What: Every code change must explain how it defend... ([source](https://app.greptile.com/review/custom-context?memory=637a42e6-7a78-40d6-9ef8-6a45e02e73b6))
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Codex

Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: lib/storage.ts
Line: 284-294

Comment:
**missing v5.x → v6.0.0 per-project global storage migration**

v5.x stored project-scoped accounts at `~/.opencode/projects/<key>/openai-codex-accounts.json` — that was the value of `currentStoragePath` in v5.x (line 288 used `getProjectGlobalConfigDir(projectRoot)` + the old `ACCOUNTS_FILE_NAME`). v6.0.0 changes the filename but keeps the same dir. the two migration paths added by this PR cover:
- `<projectRoot>/.opencode/openai-codex-accounts.json``currentLegacyProjectStoragePath`
- `~/.opencode/openai-codex-accounts.json``getLegacyGlobalAccountsStoragePath()`

but neither covers `~/.opencode/projects/<key>/openai-codex-accounts.json`. any user who ran v5.x in project mode hits ENOENT on the new filename, both migration checks fail, `loadGlobalAccountsFallback()` also won't find their data, and `loadAccountsInternal` returns `null` — silently discarding all stored accounts and OAuth tokens.

a third migration path is needed:
```typescript
// add to lib/storage.ts
function getLegacyProjectGlobalStoragePath(): string {
  if (!currentProjectRoot) return "";
  return join(getProjectGlobalConfigDir(currentProjectRoot), LEGACY_ACCOUNTS_FILE_NAME);
}

async function migrateLegacyProjectGlobalStorageIfNeeded(
  persist: (storage: AccountStorageV3) => Promise<void> = saveAccounts,
): Promise<AccountStorageV3 | null> {
  return migrateStorageFileIfNeeded(
    getLegacyProjectGlobalStoragePath(),
    getStoragePath(),
    persist,
    "per-project global account storage",
  );
}
```
this should be called in the ENOENT handler before `migrateLegacyProjectStorageIfNeeded`. a regression test covering the v5.x → v6.0.0 upgrade path is also missing from `test/storage.test.ts`.

windows risk: if the legacy file is locked by antivirus during `fs.unlink`, the stale token file persists on disk — the warn log should redact the `refreshToken` field.

**Rule Used:** What: Every code change must explain how it defend... ([source](https://app.greptile.com/review/custom-context?memory=637a42e6-7a78-40d6-9ef8-6a45e02e73b6))

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: lib/storage.ts
Line: 729-741

Comment:
**global path written outside its intended lock scope**

`writeAccountsToPathUnlocked` documents "callers must already be inside withStorageLock" (see its JSDoc at line ~891), but `migrateLegacyGlobalStorageIfNeeded()` calls it for the global path while holding only the PROJECT storage lock (when invoked via `loadGlobalAccountsFallback()`). on windows, two concurrent plugin processes — e.g. one running opencode while a terminal relaunch fires another — can both pass the `existsSync(legacyPath)` check, both read the old file, and race to rename their temp files over the new path. the atomic write prevents a torn file, but the second rename silently wins and there is no guard against double-migration. consider checking whether `nextPath` already exists immediately before calling `persist`, or guard the global path with the same mutex that protects it elsewhere.

**Rule Used:** What: Every code change must explain how it defend... ([source](https://app.greptile.com/review/custom-context?memory=637a42e6-7a78-40d6-9ef8-6a45e02e73b6))

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: lib/storage.ts
Line: 842-848

Comment:
**no vitest coverage for this new migration branch**

lines 842-848 add `migrateLegacyGlobalStorageIfNeeded()` for the non-project-fallback ENOENT path (global storage is primary, old filename exists). the existing migration tests in `test/storage.test.ts` go through `loadGlobalAccountsFallback()` which is a different branch. this path needs a dedicated vitest case:
- call `setStoragePathDirect(null)` so no project root is active
- write `openai-codex-accounts.json` into a fake `~/.opencode/`
- call `loadAccounts()`
- assert new-name file is created, old file is removed

windows filesystem risk: the `unlink` of the old file can throw `EPERM` when antivirus holds a handle; that code path is also unexercised by current tests.

**Rule Used:** What: Every code change must explain how it defend... ([source](https://app.greptile.com/review/custom-context?memory=637a42e6-7a78-40d6-9ef8-6a45e02e73b6))

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "docs: refresh codex-first rebrand and cu..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

Context used:

  • Rule used - What: Every code change must explain how it defend... (source)

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 6, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

The pull request rebands the package from oc-chatgpt-multi-auth to oc-codex-multi-auth with a version bump to 6.0.0. Changes include plugin manifest updates, storage filename migrations with legacy fallback logic, UI label rebranding from "ChatGPT Plus/Pro MULTI" to "Codex OAuth", installer script restructuring, and comprehensive documentation updates across configuration, testing, and user-facing guides.

Changes

Cohort / File(s) Summary
Plugin & Package Identity
.codex-plugin/plugin.json, package.json
Updated name from oc-chatgpt-multi-auth to oc-codex-multi-auth, version to 6.0.0, descriptions to reflect Codex-first branding, and CLI entrypoint to new script path.
Core Constants & Labels
lib/constants.ts
Added PACKAGE_NAME, LEGACY_PACKAGE_NAME, and storage filename constants for current and legacy files. Updated AUTH_LABELS to use "Codex OAuth" terminology and reworded API_KEY label.
Storage & Migration Logic
lib/storage.ts
Refactored legacy storage migration with shared helper migrateStorageFileIfNeeded(), added global legacy migration on fallback, and introduced iteration over multiple legacy flagged/blocked account paths.
Installer Scripts
scripts/install-oc-codex-multi-auth.js, scripts/install-oc-codex-multi-auth-core.js, scripts/test-all-models.sh
Created new entrypoint script with error handling; refactored core script to manage package sets with cache cleanup for all managed names; updated test script sed replacement pattern.
Auto-update & Supporting Libraries
lib/auto-update-checker.ts, lib/oauth-success.html, lib/recovery/index.ts
Updated package name references in update checker, OAuth success page header, and recovery module comment.
Configuration Examples
config/README.md, config/minimal-opencode.json, config/opencode-legacy.json, config/opencode-modern.json
Updated plugin identifiers in templates and config file descriptions from oc-chatgpt-multi-auth to oc-codex-multi-auth.
General Documentation
README.md, AGENTS.md, CONTRIBUTING.md, CHANGELOG.md, index.ts
Rebranded package references, account storage filenames, and installation instructions. Added 6.0.0 cutover section in README documenting intentional breakage and deprecation strategy.
Site & Configuration Docs
docs/_config.yml, docs/index.md, docs/configuration.md, docs/development/CONFIG_FIELDS.md, docs/development/CONFIG_FLOW.md
Updated documentation titles, npm links, plugin examples, storage paths, and installer script references.
Development & Testing Docs
docs/development/TESTING.md, docs/development/TUI_PARITY_CHECKLIST.md, docs/faq.md, docs/getting-started.md, docs/privacy.md, docs/troubleshooting.md
Updated validation surface, package references, OAuth flow labels, storage paths, and repository links; expanded migration guidance in FAQ.
Skill Documentation
skills/oc-codex-setup/SKILL.md, test/README.md
Updated package name references in skill frontmatter, descriptions, and install commands.
Unit & Integration Tests
test/index.test.ts, test/audit.race.test.ts, test/install-oc-codex-multi-auth.test.ts, test/login-runner.test.ts, test/rotation-integration.test.ts, test/storage-async.test.ts, test/storage.test.ts
Updated expected label strings to "Codex OAuth" terminology, storage filenames, test directory names, and imports to new installer module; expanded cache tests to cover both legacy and new package paths.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 A new era hops into place,
From ChatGPT's old ways we embrace,
Codex OAuth takes the stage,
Storage files turn a fresh page,
Six-point-oh marks our grand advance! 🚀

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 19.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main breaking change: renaming the package from oc-chatgpt-multi-auth to oc-codex-multi-auth, which is the primary objective of this PR.
Description check ✅ Passed The PR description covers all required template sections: Summary details the key changes, Testing confirms all checks passed, Compliance Confirmation checkboxes are marked appropriately, and Notes provide context for post-merge work.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ndycode ndycode merged commit 409c564 into main Apr 6, 2026
1 of 2 checks passed
@ndycode ndycode deleted the git-plan/oc-codex-multi-auth-rebrand branch April 6, 2026 11:38
Comment thread lib/storage.ts
Comment on lines +729 to +741
async function migrateLegacyGlobalStorageIfNeeded(): Promise<AccountStorageV3 | null> {
const nextPath = getGlobalAccountsStoragePath();
const persistGlobalStorage = async (storage: AccountStorageV3): Promise<void> => {
await writeAccountsToPathUnlocked(nextPath, storage);
};

return migrateStorageFileIfNeeded(
getLegacyGlobalAccountsStoragePath(),
nextPath,
persistGlobalStorage,
"global account storage",
);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 global path written outside its intended lock scope

writeAccountsToPathUnlocked documents "callers must already be inside withStorageLock" (see its JSDoc at line ~891), but migrateLegacyGlobalStorageIfNeeded() calls it for the global path while holding only the PROJECT storage lock (when invoked via loadGlobalAccountsFallback()). on windows, two concurrent plugin processes — e.g. one running opencode while a terminal relaunch fires another — can both pass the existsSync(legacyPath) check, both read the old file, and race to rename their temp files over the new path. the atomic write prevents a torn file, but the second rename silently wins and there is no guard against double-migration. consider checking whether nextPath already exists immediately before calling persist, or guard the global path with the same mutex that protects it elsewhere.

Rule Used: What: Every code change must explain how it defend... (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: lib/storage.ts
Line: 729-741

Comment:
**global path written outside its intended lock scope**

`writeAccountsToPathUnlocked` documents "callers must already be inside withStorageLock" (see its JSDoc at line ~891), but `migrateLegacyGlobalStorageIfNeeded()` calls it for the global path while holding only the PROJECT storage lock (when invoked via `loadGlobalAccountsFallback()`). on windows, two concurrent plugin processes — e.g. one running opencode while a terminal relaunch fires another — can both pass the `existsSync(legacyPath)` check, both read the old file, and race to rename their temp files over the new path. the atomic write prevents a torn file, but the second rename silently wins and there is no guard against double-migration. consider checking whether `nextPath` already exists immediately before calling `persist`, or guard the global path with the same mutex that protects it elsewhere.

**Rule Used:** What: Every code change must explain how it defend... ([source](https://app.greptile.com/review/custom-context?memory=637a42e6-7a78-40d6-9ef8-6a45e02e73b6))

How can I resolve this? If you propose a fix, please make it concise.

Fix in Codex

ndycode added a commit that referenced this pull request Apr 6, 2026
…rand

feat!: rename oc-chatgpt-multi-auth to oc-codex-multi-auth
ndycode added a commit that referenced this pull request Apr 6, 2026
…rand

feat!: rename oc-chatgpt-multi-auth to oc-codex-multi-auth
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