Skip to content

Commit 046993a

Browse files
committed
release: ship v1.2.0
1 parent b4dcaad commit 046993a

File tree

7 files changed

+133
-39
lines changed

7 files changed

+133
-39
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -291,9 +291,9 @@ codex auth doctor --json
291291

292292
## Release Notes
293293

294-
- Current stable: [docs/releases/v1.1.10.md](docs/releases/v1.1.10.md)
295-
- Previous stable: [docs/releases/v0.1.9.md](docs/releases/v0.1.9.md)
296-
- Earlier stable: [docs/releases/v0.1.8.md](docs/releases/v0.1.8.md)
294+
- Current stable: [docs/releases/v1.2.0.md](docs/releases/v1.2.0.md)
295+
- Previous stable: [docs/releases/v1.1.10.md](docs/releases/v1.1.10.md)
296+
- Earlier stable: [docs/releases/v0.1.9.md](docs/releases/v0.1.9.md)
297297
- Archived prerelease: [docs/releases/v0.1.0-beta.0.md](docs/releases/v0.1.0-beta.0.md)
298298

299299
## License

docs/README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@ Public documentation for `codex-multi-auth`.
2626
| [troubleshooting.md](troubleshooting.md) | Recovery playbooks for install, login, switching, and stale state |
2727
| [privacy.md](privacy.md) | Data handling and local storage behavior |
2828
| [upgrade.md](upgrade.md) | Migration from legacy package and path history |
29-
| [releases/v1.1.10.md](releases/v1.1.10.md) | Stable release notes |
30-
| [releases/v0.1.9.md](releases/v0.1.9.md) | Previous stable release notes |
31-
| [releases/v0.1.8.md](releases/v0.1.8.md) | Earlier stable release notes |
29+
| [releases/v1.2.0.md](releases/v1.2.0.md) | Stable release notes |
30+
| [releases/v1.1.10.md](releases/v1.1.10.md) | Previous stable release notes |
31+
| [releases/v0.1.9.md](releases/v0.1.9.md) | Earlier stable release notes |
3232
| [releases/v0.1.7.md](releases/v0.1.7.md) | Archived stable release notes |
3333
| [releases/v0.1.6.md](releases/v0.1.6.md) | Archived stable release notes |
3434
| [releases/v0.1.5.md](releases/v0.1.5.md) | Archived stable release notes |
@@ -45,7 +45,7 @@ Public documentation for `codex-multi-auth`.
4545
| [reference/storage-paths.md](reference/storage-paths.md) | Canonical and compatibility storage paths |
4646
| [reference/public-api.md](reference/public-api.md) | Public API stability and semver contract |
4747
| [reference/error-contracts.md](reference/error-contracts.md) | CLI, JSON, and helper error semantics |
48-
| [releases/v1.1.10.md](releases/v1.1.10.md) | Current stable release notes |
48+
| [releases/v1.2.0.md](releases/v1.2.0.md) | Current stable release notes |
4949
| [releases/v0.1.0-beta.0.md](releases/v0.1.0-beta.0.md) | Archived prerelease reference |
5050
| [User Guides release notes](#user-guides) | Stable, previous, and archived release notes |
5151
| [releases/legacy-pre-0.1-history.md](releases/legacy-pre-0.1-history.md) | Archived pre-0.1 changelog history |

docs/releases/v1.2.0.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Release v1.2.0
2+
3+
Release date: 2026-03-20
4+
Channel: `latest`
5+
6+
## Highlights
7+
8+
- Added manual login fallback for headless or browser-suppressed auth flows.
9+
- Preserved selected workspace identity through request routing, refresh, and failover retries.
10+
- Added proxy-compatible upstream transport plus automatic workspace rotation on disabled or expired workspace errors.
11+
- Added onboarding restore from the latest saved backup and restored experimental settings hotkeys in the TUI.
12+
13+
## Install
14+
15+
```bash
16+
npm i -g @openai/codex
17+
npm i -g codex-multi-auth
18+
```
19+
20+
## Core Operations
21+
22+
```bash
23+
codex auth login
24+
codex auth list
25+
codex auth status
26+
codex auth forecast --live
27+
codex auth fix --live
28+
```
29+
30+
## Validation Snapshot
31+
32+
Release gate commands:
33+
34+
- `npm run clean:repo:check`
35+
- `npm run typecheck`
36+
- `npm run build`
37+
- `npm run lint`
38+
- `npm test -- --run test/documentation.test.ts`
39+
- `npm test`
40+
41+
Broad validation result:
42+
43+
- `repo-hygiene check passed`
44+
- `npm run typecheck` passed
45+
- `npm run build` passed
46+
- `npm run lint` passed
47+
- `19/19` documentation integrity tests passed
48+
- `106/106` test files passed on the integrated `v1.2.0` release branch
49+
- `2640/2640` tests passed on the integrated `v1.2.0` release branch
50+
51+
## Merged PRs
52+
53+
- `#132` `add manual login mode for headless auth flows`
54+
- `#133` `preserve selected workspace in request routing`
55+
- `#134` `add proxy-compatible upstream transport`
56+
- `#136` `feat: auto-rotate on disabled/expired workspace errors`
57+
- `#137` `add onboarding restore for latest saved backup`
58+
- `#138` `fix experimental settings tui hotkeys`
59+
60+
## Commits
61+
62+
- PR `#132` adds manual browser-free login support and the related CLI and docs coverage.
63+
- PR `#133` keeps stored workspace identity stable through refresh and retry paths instead of collapsing back to token-derived IDs.
64+
- PR `#134` adds proxy-aware upstream transport handling without widening into auth or quota probe traffic.
65+
- PR `#136` rotates to successor workspaces when the active workspace is disabled or expired, while preserving the non-workspace fallback path.
66+
- PR `#137` adds empty-pool onboarding restore from named backups and keeps restore state stable across backup scan races.
67+
- PR `#138` restores experimental settings hotkeys and the matching help text, docs, and regression coverage.
68+
- The release bump in this branch promotes `1.2.0` in package metadata and refreshes the stable release-note links in the root docs surfaces.
69+
70+
## Notes
71+
72+
- `codex auth login` now supports manual OAuth completion when browser launch or the local callback listener is unavailable.
73+
- Request routing preserves explicit workspace selections across failover and token refresh, and upstream requests now honor standard proxy environment variables.
74+
- Disabled or expired workspace responses now rotate within the current account before falling back to another account.
75+
- First-run onboarding can restore the latest saved backup before new sign-in, and the experimental settings screens once again honor their documented hotkeys.
76+
77+
## Related
78+
79+
- [../getting-started.md](../getting-started.md)
80+
- [../upgrade.md](../upgrade.md)
81+
- [../reference/commands.md](../reference/commands.md)
82+
- [../reference/settings.md](../reference/settings.md)

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.1.10",
3+
"version": "1.2.0",
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",

test/codex-manager-cli.test.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3073,22 +3073,6 @@ describe("codex manager cli commands", () => {
30733073
expect(storageState.accounts).toHaveLength(1);
30743074
});
30753075

3076-
it("supports interactive manual login selection without waiting for a callback", async () => {
3077-
setInteractiveTTY(true);
3078-
const now = Date.now();
3079-
let storageState = {
3080-
version: 3 as const,
3081-
activeIndex: 0,
3082-
activeIndexByFamily: { codex: 0 },
3083-
accounts: [] as Array<Record<string, unknown>>,
3084-
};
3085-
loadAccountsMock.mockImplementation(async () => structuredClone(storageState));
3086-
saveAccountsMock.mockImplementation(async (nextStorage) => {
3087-
storageState = structuredClone(nextStorage);
3088-
});
3089-
promptLoginModeMock.mockResolvedValueOnce({ mode: "cancel" });
3090-
promptAddAnotherAccountMock.mockResolvedValue(false);
3091-
30923076
it("restores the latest named backup from onboarding when no accounts exist", async () => {
30933077
const now = Date.now();
30943078
setInteractiveTTY(true);

test/index-retry.test.ts

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ function createMockAccount(
2323
index: 0,
2424
accountId: "account-1",
2525
email: "user@example.com",
26-
refreshToken: "refresh-token",
27-
access: "access-token",
26+
refreshToken: "refresh-token-account-1",
27+
access: "access-token-account-1",
2828
expires: Date.now() + 60_000,
2929
addedAt: Date.now(),
3030
lastUsed: Date.now(),
@@ -100,6 +100,8 @@ vi.mock("../lib/accounts.js", async () => {
100100
const tokenUtils = await vi.importActual("../lib/auth/token-utils.js");
101101
const tokenUtilsModule = tokenUtils as typeof import("../lib/auth/token-utils.js");
102102
class AccountManager {
103+
private currentAuthAccount: Record<string, any> | null = null;
104+
103105
static async loadFromDisk() {
104106
return new AccountManager();
105107
}
@@ -133,14 +135,29 @@ vi.mock("../lib/accounts.js", async () => {
133135

134136
recordFailure() {}
135137

136-
toAuthDetails() {
137-
return {
138-
type: "oauth",
139-
access: "access-token",
140-
refresh: "refresh-token",
141-
expires: Date.now() + 60_000,
142-
};
143-
}
138+
toAuthDetails(account?: Record<string, any>) {
139+
const resolvedAccount =
140+
account ??
141+
this.currentAuthAccount ??
142+
accountManagerState.accounts[0] ??
143+
createMockAccount();
144+
this.currentAuthAccount = resolvedAccount;
145+
return {
146+
type: "oauth",
147+
access: String(
148+
resolvedAccount.access ?? `access-token-${resolvedAccount.accountId ?? "account-1"}`,
149+
),
150+
refresh: String(
151+
resolvedAccount.refreshToken ??
152+
`refresh-token-${resolvedAccount.accountId ?? "account-1"}`,
153+
),
154+
expires: Number(resolvedAccount.expires ?? Date.now() + 60_000),
155+
idToken:
156+
typeof resolvedAccount.idToken === "string"
157+
? resolvedAccount.idToken
158+
: undefined,
159+
};
160+
}
144161

145162
hasRefreshToken(_token: string) {
146163
return true;
@@ -252,8 +269,17 @@ vi.mock("../lib/accounts.js", async () => {
252269

253270
return {
254271
AccountManager,
255-
extractAccountEmail: () => "user@example.com",
256-
extractAccountId: () => "account-1",
272+
extractAccountEmail: (accessToken?: string) => {
273+
if (!accessToken) {
274+
return "user@example.com";
275+
}
276+
const match = /account-(\d+)/.exec(accessToken);
277+
return match ? `user${match[1]}@example.com` : "user@example.com";
278+
},
279+
extractAccountId: (accessToken?: string) => {
280+
const match = accessToken ? /account-\d+/.exec(accessToken) : null;
281+
return match?.[0] ?? "account-1";
282+
},
257283
selectBestAccountCandidate: (candidates: Array<{ accountId: string }>) => candidates[0] ?? null,
258284
resolveRuntimeRequestIdentity: ({
259285
storedAccountId,
@@ -268,7 +294,9 @@ vi.mock("../lib/accounts.js", async () => {
268294
accessToken?: string;
269295
idToken?: string;
270296
}) => {
271-
const tokenAccountId = accessToken ? "account-1" : undefined;
297+
const tokenAccountId = accessToken
298+
? tokenUtilsModule.extractAccountId(accessToken)
299+
: undefined;
272300
const tokenEmail = tokenUtilsModule.sanitizeEmail(
273301
tokenUtilsModule.extractAccountEmail(accessToken, idToken),
274302
);

0 commit comments

Comments
 (0)