Skip to content

v6.20.0

Choose a tag to compare

@ndycode ndycode released this 14 Sep 00:02
· 39 commits to main since this release

https://www.npmjs.com/package/oc-codex-multi-auth/v/6.20.0

npx oc-codex-multi-auth@6.20.0 install

Added

The requested model now falls back to a cheaper one when every account is quota-blocked (#255, contributed by @WarGloom).

Before, a pool whose every enabled account carried an upstream block for the requested model waited out the block (or failed with 429) even though a cheaper model in the default fallback chain was fully available. Now, when the block is upstream (a spent subscription quota or a server rate limit on every enabled account), the request degrades down the configured unsupportedCodexFallbackChain like an entitlement miss: at most 3 model switches per request, no model tried twice, and the chain terminates at gpt-5.2. Local token depletion and cooldowns alone never trigger the downgrade, strict pools still refuse it (strict_pool_unavailable), and directly selected non-entry models stay strict. Opt out per family with the existing CODEX_AUTH_DISABLE_*_AUTO_FALLBACK=1 switches.

Spent subscription quota is now tracked account-wide, separate from transient rate limits (#255, contributed by @WarGloom).

A fully spent 5-hour or weekly window used to be recorded as a blanket per-family rate limit that blocked every model and was reported as "rate limited". It now lands on a dedicated quotaExhaustedUntil stamp written only by authoritative sources: the usage poller and quota-429 response headers, both horizon-guarded so a bad header cannot strand an account. Rotation, the TUI status line, codex-list/codex-status, and codex-limits all report it as quota exhaustion with its own reset countdown, never as a rate limit.

oc-codex-multi-auth doctor --fix repairs accounts outside OpenCode (#255, contributed by @WarGloom).

The standalone doctor can now refresh every enabled account's token, clear stale cooldown, rate-limit, and quota-exhaustion markers after successful verification, and persist rotated credentials — including keychain-backed pools. --config-path repairs only the selected JSON pool and bypasses keychain routing.

Fixed

Corrupt storage files no longer report success from the standalone CLI.

doctor --fix on a corrupt default storage file used to exit 0 with "No accounts configured." while doctor alone exited 1; warm and limits did the same for any unreadable file, and a JSON file of the wrong shape (an array, a scalar, a missing accounts array) was accepted as a healthy empty pool by every command. All standalone commands now validate shape, parse, and schema version, and exit nonzero with the exact error — including the "written by a newer version" upgrade hint — when the file cannot be read.

Non-finite numbers in a hand-edited accounts file no longer poison rotation.

JSON.parse turns 1e400 into Infinity, and an Infinity rate-limit stamp blocked an account forever while feeding NaN into retry math that could spin hot retries. Numeric timing fields are now sanitized at the storage boundary on every load and save; a poisoned file heals itself on the next persist.

An all-blocked pool now waits out the longest block, not the shortest.

With a legacy all-family weekly stamp and a newer 2-hour quota stamp on the same account, the wait loop was promised a 2-hour wait for an account that stayed blocked 6 days, waking to a still-blocked pool in a cycle. The pool wait is now the earliest moment any single account becomes selectable.

A doctor-cleared quota stamp stays cleared across processes.

A second OpenCode process still holding the stamp in memory used to write it back on its next save, undoing the repair; nothing in-tree ever corrected it, since the usage poller only writes stamps. Doctor now dates its clear and every authoritative stamp write dates itself, so a save can tell a stale snapshot from fresh evidence: a stamp older than the clear stays suppressed, a fresh 429 or poller stamp recorded after the clear wins.

codex-health no longer tells a user with a real week-long quota block that it is stale state.

Quota-exhaustion stamps are written only by authoritative sources, so codex-health now reports them under their own "Quota exhausted" finding with wording that says the stamp re-establishes after --fix clears it, instead of lumping them into the recoverable-stale-state hint.

Spent subscription quota is recorded once per account, not once per model family (#255, contributed by @WarGloom).

The usage poller used to forge a rate-limit block for every family on a spent shared window; it now records the single account-wide stamp.

The TUI status line no longer badges every account as rate-limited (#255, contributed by @WarGloom).

Internal

  • The hybrid selector's last-resort retry (send a blocked account rather than nothing) is now overridden on the request path: an all-blocked pool waits out or fails on the block instead of retrying it, which is also what allows the model fallback above to run.
  • Cross-process quota-stamp merges are monotonic in both save paths, including the disposed-manager path.
  • The doctor repair workflow moved out of codex-doctor into a shared lib/tools/doctor-repair.ts used by both the plugin tool and the standalone CLI.
  • Removed the unused ctx.getQuotaExhaustedUntil tool-context surface.

Thanks @WarGloom for the quota-separation and model-fallback work in #255.