Skip to content

Commit fb63443

Browse files
committed
fix: patch post-merge review regressions for v1.2.4
1 parent ab096bf commit fb63443

18 files changed

Lines changed: 270 additions & 40 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ codex auth doctor --json
308308

309309
## Release Notes
310310

311-
- Current stable: [docs/releases/v1.2.3.md](docs/releases/v1.2.3.md)
311+
- Current stable: [docs/releases/v1.2.4.md](docs/releases/v1.2.4.md)
312312
- Previous stable: [docs/releases/v1.2.2.md](docs/releases/v1.2.2.md)
313313
- Earlier stable: [docs/releases/v1.2.1.md](docs/releases/v1.2.1.md)
314314
- Archived prerelease: [docs/releases/v0.1.0-beta.0.md](docs/releases/v0.1.0-beta.0.md)

docs/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ Public documentation for `codex-multi-auth`.
2323
| [configuration.md](configuration.md) | Stable defaults, precedence, and environment overrides |
2424
| [architecture.md](architecture.md) | Public system overview of the wrapper, storage, and optional plugin runtime |
2525
| [privacy.md](privacy.md) | Data handling and local storage behavior |
26-
| [releases/v1.2.3.md](releases/v1.2.3.md) | Stable release notes |
26+
| [releases/v1.2.4.md](releases/v1.2.4.md) | Stable release notes |
2727
| [releases/v1.2.2.md](releases/v1.2.2.md) | Previous stable release notes |
2828
| [releases/v1.2.1.md](releases/v1.2.1.md) | Earlier stable release notes |
2929
| [releases/v1.2.0.md](releases/v1.2.0.md) | Archived stable release notes |
@@ -52,7 +52,7 @@ Public documentation for `codex-multi-auth`.
5252
| [reference/storage-paths.md](reference/storage-paths.md) | Canonical and compatibility storage paths |
5353
| [reference/public-api.md](reference/public-api.md) | Public API stability and semver contract |
5454
| [reference/error-contracts.md](reference/error-contracts.md) | CLI, JSON, and helper error semantics |
55-
| [releases/v1.2.3.md](releases/v1.2.3.md) | Current stable release notes |
55+
| [releases/v1.2.4.md](releases/v1.2.4.md) | Current stable release notes |
5656
| [releases/v0.1.0-beta.0.md](releases/v0.1.0-beta.0.md) | Archived prerelease reference |
5757
| [Daily Use release notes](#daily-use) | Stable, previous, and archived release notes |
5858
| [releases/legacy-pre-0.1-history.md](releases/legacy-pre-0.1-history.md) | Archived pre-0.1 changelog history |

docs/releases/v1.2.4.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Release v1.2.4
2+
3+
Release line: `stable`
4+
5+
This patch release follows the already-published `v1.2.3` rebuild and lands the post-merge review fixes that were raised afterward.
6+
7+
## Scope
8+
9+
- Current package version in `package.json` is `1.2.4`.
10+
- Canonical command family remains `codex auth ...`.
11+
- Canonical package name remains `codex-multi-auth`.
12+
- This patch is prepared from `main` after merge commit `c1da059852d698fd53014b9b529eeeeb2db1d39d`.
13+
14+
## What Changed
15+
16+
- preserved standalone `config.json` values when unified settings are malformed, and hardened unified-settings writes so invalid primaries can be rebuilt safely without masking real unreadable-file errors
17+
- retried flagged-account primary, backup, and legacy reads before fallback so transient Windows file locks do not trigger unnecessary recovery paths
18+
- avoided capability-policy failure penalties on fallback stream-failover `429` responses
19+
- retried shadow-home sync-back renames in the Codex wrapper so transient `EBUSY` and `EPERM` locks do not drop auth-state sync
20+
- removed scheduler-fragile midpoint assertions from quota-refresh CLI tests and tightened dashboard/unified-settings regressions around the real legacy/unified read paths
21+
22+
## Validation
23+
24+
- `npm run lint`
25+
- `npm run typecheck`
26+
- `npm run build`
27+
- `npm test`
28+
- Full suite passed: `222/222` files, `3303/3303` tests
29+
30+
## Related
31+
32+
- [v1.2.3.md](v1.2.3.md)
33+
- [../getting-started.md](../getting-started.md)
34+
- [../upgrade.md](../upgrade.md)
35+
- [../reference/commands.md](../reference/commands.md)

index.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,11 +2192,11 @@ export const OpenAIOAuthPlugin: Plugin = async ({ client }: PluginInput) => {
21922192
modelFamily,
21932193
model,
21942194
);
2195+
capabilityPolicyStore.recordFailure(
2196+
fallbackEntitlementAccountKey,
2197+
capabilityModelKey,
2198+
);
21952199
}
2196-
capabilityPolicyStore.recordFailure(
2197-
fallbackEntitlementAccountKey,
2198-
capabilityModelKey,
2199-
);
22002200
continue;
22012201
}
22022202

lib/config.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -647,10 +647,7 @@ export async function savePluginConfig(
647647
: loadUnifiedPluginConfigSync();
648648
const unifiedConfig = sanitizeStoredPluginConfigRecord(unifiedConfigRecord);
649649
const legacyPath =
650-
unifiedConfigState.status === "missing" ||
651-
(unifiedConfigState.status === "ok" && !unifiedConfig)
652-
? resolvePluginConfigPath()
653-
: null;
650+
unifiedConfig === null ? resolvePluginConfigPath() : null;
654651
const legacyConfigState = legacyPath
655652
? await readConfigRecordForSave(legacyPath)
656653
: null;

lib/storage/flagged-storage-file.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function isRetryableReadError(error: unknown): boolean {
88
return typeof code === "string" && RETRYABLE_READ_CODES.has(code);
99
}
1010

11-
async function readFileWithRetry(
11+
export async function readFileWithRetry(
1212
path: string,
1313
deps: {
1414
readFile: typeof import("node:fs").promises.readFile;

lib/storage/flagged-storage-io.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { existsSync, promises as fs } from "node:fs";
22
import { dirname } from "node:path";
33
import type { FlaggedAccountStorageV1 } from "../storage.js";
4+
import { readFileWithRetry } from "./flagged-storage-file.js";
45

56
const RETRYABLE_UNLINK_CODES = new Set(["EBUSY", "EAGAIN", "EPERM"]);
67

@@ -75,7 +76,9 @@ export async function loadFlaggedAccountsState(params: {
7576
continue;
7677
}
7778
try {
78-
const backupContent = await fs.readFile(backupPath, "utf-8");
79+
const backupContent = await readFileWithRetry(backupPath, {
80+
readFile: fs.readFile,
81+
});
7982
const backupData = JSON.parse(backupContent) as unknown;
8083
const recovered = params.normalizeFlaggedStorage(backupData);
8184
if (!isValidFlaggedStorageCandidate(backupData, recovered)) {
@@ -123,7 +126,9 @@ export async function loadFlaggedAccountsState(params: {
123126
};
124127

125128
try {
126-
const content = await fs.readFile(params.path, "utf-8");
129+
const content = await readFileWithRetry(params.path, {
130+
readFile: fs.readFile,
131+
});
127132
const data = JSON.parse(content) as unknown;
128133
const loaded = params.normalizeFlaggedStorage(data);
129134
if (!isValidFlaggedStorageCandidate(data, loaded)) {
@@ -154,7 +159,9 @@ export async function loadFlaggedAccountsState(params: {
154159
}
155160

156161
try {
157-
const legacyContent = await fs.readFile(params.legacyPath, "utf-8");
162+
const legacyContent = await readFileWithRetry(params.legacyPath, {
163+
readFile: fs.readFile,
164+
});
158165
const legacyData = JSON.parse(legacyContent) as unknown;
159166
const migrated = params.normalizeFlaggedStorage(legacyData);
160167
if (migrated.accounts.length > 0) {

lib/unified-settings.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,16 @@ function shouldFallbackToSettingsBackup(
143143
return true;
144144
}
145145

146+
function isInvalidSettingsRecordError(error: unknown): boolean {
147+
if (error instanceof SyntaxError) {
148+
return true;
149+
}
150+
return (
151+
error instanceof Error &&
152+
error.message === "Unified settings must contain a JSON object at the root."
153+
);
154+
}
155+
146156
/**
147157
* Snapshot the primary settings file into `settings.json.bak` for sync writes.
148158
*
@@ -221,6 +231,9 @@ function readSettingsRecordSyncInternal(): SettingsReadResult {
221231
if (backupRecord) {
222232
return { record: backupRecord, usedBackup: true };
223233
}
234+
if (isInvalidSettingsRecordError(error)) {
235+
return { record: null, usedBackup: false };
236+
}
224237
throw error;
225238
}
226239

@@ -255,6 +268,9 @@ async function readSettingsRecordAsyncInternal(): Promise<SettingsReadResult> {
255268
if (backupRecord) {
256269
return { record: backupRecord, usedBackup: true };
257270
}
271+
if (isInvalidSettingsRecordError(error)) {
272+
return { record: null, usedBackup: false };
273+
}
258274
throw error;
259275
}
260276

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codex-multi-auth",
3-
"version": "1.2.3",
3+
"version": "1.2.4",
44
"description": "Multi-account OAuth manager and codex auth wrapper for the official @openai/codex CLI, with switching, health checks, and recovery tools",
55
"main": "./dist/index.js",
66
"types": "./dist/index.d.ts",

0 commit comments

Comments
 (0)