From 960ca3e090a1fcc913680ebe370be7549ce4b93c Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 22:18:29 +0800 Subject: [PATCH 1/5] fix(wrapper): support codex-multi-auth version flags --- README.md | 9 +++-- docs/README.md | 8 ++--- docs/getting-started.md | 6 +++- docs/reference/commands.md | 2 ++ docs/troubleshooting.md | 2 ++ docs/upgrade.md | 3 +- scripts/codex-multi-auth.js | 40 ++++++++++++++++++----- test/codex-multi-auth-bin-wrapper.test.ts | 38 +++++++++++++++++++++ 8 files changed, 90 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f4e5e25f..3e520e70 100644 --- a/README.md +++ b/README.md @@ -62,8 +62,11 @@ npm i -g codex-multi-auth ### Option C: Verify wiring +`codex --version` confirms the official Codex CLI is reachable. `codex-multi-auth --version` confirms the installed wrapper package version. + ```bash codex --version +codex-multi-auth --version codex auth status ``` @@ -291,9 +294,9 @@ codex auth doctor --json ## Release Notes -- Current stable: [docs/releases/v1.2.0.md](docs/releases/v1.2.0.md) -- Previous stable: [docs/releases/v1.1.10.md](docs/releases/v1.1.10.md) -- Earlier stable: [docs/releases/v0.1.9.md](docs/releases/v0.1.9.md) +- Current stable: [docs/releases/v1.1.10.md](docs/releases/v1.1.10.md) +- Previous stable: [docs/releases/v0.1.9.md](docs/releases/v0.1.9.md) +- Earlier stable: [docs/releases/v0.1.8.md](docs/releases/v0.1.8.md) - Archived prerelease: [docs/releases/v0.1.0-beta.0.md](docs/releases/v0.1.0-beta.0.md) ## License diff --git a/docs/README.md b/docs/README.md index f63480fb..926e5675 100644 --- a/docs/README.md +++ b/docs/README.md @@ -26,9 +26,9 @@ Public documentation for `codex-multi-auth`. | [troubleshooting.md](troubleshooting.md) | Recovery playbooks for install, login, switching, and stale state | | [privacy.md](privacy.md) | Data handling and local storage behavior | | [upgrade.md](upgrade.md) | Migration from legacy package and path history | -| [releases/v1.2.0.md](releases/v1.2.0.md) | Stable release notes | -| [releases/v1.1.10.md](releases/v1.1.10.md) | Previous stable release notes | -| [releases/v0.1.9.md](releases/v0.1.9.md) | Earlier stable release notes | +| [releases/v1.1.10.md](releases/v1.1.10.md) | Stable release notes | +| [releases/v0.1.9.md](releases/v0.1.9.md) | Previous stable release notes | +| [releases/v0.1.8.md](releases/v0.1.8.md) | Earlier stable release notes | | [releases/v0.1.7.md](releases/v0.1.7.md) | Archived stable release notes | | [releases/v0.1.6.md](releases/v0.1.6.md) | Archived stable release notes | | [releases/v0.1.5.md](releases/v0.1.5.md) | Archived stable release notes | @@ -45,7 +45,7 @@ Public documentation for `codex-multi-auth`. | [reference/storage-paths.md](reference/storage-paths.md) | Canonical and compatibility storage paths | | [reference/public-api.md](reference/public-api.md) | Public API stability and semver contract | | [reference/error-contracts.md](reference/error-contracts.md) | CLI, JSON, and helper error semantics | -| [releases/v1.2.0.md](releases/v1.2.0.md) | Current stable release notes | +| [releases/v1.1.10.md](releases/v1.1.10.md) | Current stable release notes | | [releases/v0.1.0-beta.0.md](releases/v0.1.0-beta.0.md) | Archived prerelease reference | | [User Guides release notes](#user-guides) | Stable, previous, and archived release notes | | [releases/legacy-pre-0.1-history.md](releases/legacy-pre-0.1-history.md) | Archived pre-0.1 changelog history | diff --git a/docs/getting-started.md b/docs/getting-started.md index ab204379..ab918be9 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -26,10 +26,14 @@ npm uninstall -g @ndycode/codex-multi-auth npm i -g codex-multi-auth ``` -Verify that the wrapper is active: +Verify both installed surfaces: + +- `codex --version` checks the official `@openai/codex` CLI that the wrapper forwards to. +- `codex-multi-auth --version` checks the installed wrapper package version. ```bash codex --version +codex-multi-auth --version codex auth status ``` diff --git a/docs/reference/commands.md b/docs/reference/commands.md index c69b3065..34b04871 100644 --- a/docs/reference/commands.md +++ b/docs/reference/commands.md @@ -69,6 +69,8 @@ Compatibility aliases are supported: ## Compatibility and Non-TTY Behavior - `codex` remains the primary wrapper entrypoint. It routes `codex auth ...` and the compatibility aliases to the multi-auth runtime, and forwards every other command to the official `@openai/codex` CLI. +- `codex --version` reports the official `@openai/codex` CLI version. +- `codex-multi-auth --version` and `codex-multi-auth -v` report the installed wrapper package version. - In non-TTY or host-managed sessions, including `CODEX_TUI=1`, `CODEX_DESKTOP=1`, `TERM_PROGRAM=codex`, or `ELECTRON_RUN_AS_NODE=1`, auth flows degrade to deterministic text behavior. - The non-TTY fallback keeps `codex auth login` predictable: it defaults to add-account mode, skips the extra "add another account" prompt, and auto-picks the default workspace selection when a follow-up choice is needed. - `codex auth login --manual` keeps the login flow usable in browser-restricted shells by printing the OAuth URL and accepting manual callback input instead of trying to open a browser. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index ad0a67e5..c176af7a 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -27,6 +27,7 @@ Check which `codex` executable is running: ```bash where codex codex --version +codex-multi-auth --version codex auth status codex multi auth status npm ls -g codex-multi-auth @@ -118,6 +119,7 @@ Attach these outputs when opening a bug report: - `codex auth report --json` - `codex auth doctor --json` - `codex --version` +- `codex-multi-auth --version` - `npm ls -g codex-multi-auth` - the failing command and full terminal output diff --git a/docs/upgrade.md b/docs/upgrade.md index 00883363..64dd528b 100644 --- a/docs/upgrade.md +++ b/docs/upgrade.md @@ -32,10 +32,11 @@ npm uninstall -g @ndycode/codex-multi-auth npm i -g codex-multi-auth ``` -1. Verify routing and status: +1. Verify routing and wrapper status: ```bash codex --version +codex-multi-auth --version codex auth status ``` diff --git a/scripts/codex-multi-auth.js b/scripts/codex-multi-auth.js index 3634ef30..394f9edf 100755 --- a/scripts/codex-multi-auth.js +++ b/scripts/codex-multi-auth.js @@ -1,18 +1,40 @@ #!/usr/bin/env node import { createRequire } from "node:module"; -import { runCodexMultiAuthCli } from "../dist/lib/codex-manager.js"; -try { +const versionFlags = new Set(["--version", "-v"]); + +function resolveCliVersion() { const require = createRequire(import.meta.url); - const pkg = require("../package.json"); - const version = typeof pkg?.version === "string" ? pkg.version.trim() : ""; - if (version.length > 0) { - process.env.CODEX_MULTI_AUTH_CLI_VERSION = version; + try { + const pkg = require("../package.json"); + const version = typeof pkg?.version === "string" ? pkg.version.trim() : ""; + if (version.length > 0) { + return version; + } + } catch { + // Best effort only. } -} catch { - // Best effort only. + return ""; +} + +const args = process.argv.slice(2); +const version = resolveCliVersion(); + +if (version.length > 0) { + process.env.CODEX_MULTI_AUTH_CLI_VERSION = version; } -const exitCode = await runCodexMultiAuthCli(process.argv.slice(2)); +if (args.length === 1 && versionFlags.has(args[0])) { + if (version.length > 0) { + process.stdout.write(`${version}\n`); + process.exitCode = 0; + } else { + process.stderr.write("codex-multi-auth version is unavailable.\n"); + process.exitCode = 1; + } +} else { + const { runCodexMultiAuthCli } = await import("../dist/lib/codex-manager.js"); + const exitCode = await runCodexMultiAuthCli(args); process.exitCode = Number.isInteger(exitCode) ? exitCode : 1; +} diff --git a/test/codex-multi-auth-bin-wrapper.test.ts b/test/codex-multi-auth-bin-wrapper.test.ts index 2a5c4562..2020f26d 100644 --- a/test/codex-multi-auth-bin-wrapper.test.ts +++ b/test/codex-multi-auth-bin-wrapper.test.ts @@ -42,6 +42,11 @@ function createWrapperFixture(): string { createdDirs.push(fixtureRoot); const scriptDir = join(fixtureRoot, "scripts"); mkdirSync(scriptDir, { recursive: true }); + writeFileSync( + join(fixtureRoot, "package.json"), + JSON.stringify({ type: "module", version: "9.8.7" }, null, "\t"), + "utf8", + ); copyFileSync( join(repoRootDir, "scripts", "codex-multi-auth.js"), join(scriptDir, "codex-multi-auth.js"), @@ -69,6 +74,39 @@ afterEach(async () => { }); describe("codex-multi-auth bin wrapper", () => { + it("prints package version for --version without loading the runtime", () => { + const fixtureRoot = createWrapperFixture(); + const result = runWrapper(fixtureRoot, ["--version"]); + + expect(result.status).toBe(0); + expect(result.stdout).toBe("9.8.7\n"); + expect(result.stderr).toBe(""); + }); + + it("prints package version for -v without loading the runtime", () => { + const fixtureRoot = createWrapperFixture(); + const result = runWrapper(fixtureRoot, ["-v"]); + + expect(result.status).toBe(0); + expect(result.stdout).toBe("9.8.7\n"); + expect(result.stderr).toBe(""); + }); + + it("prints a clear error when the wrapper version cannot be resolved", () => { + const fixtureRoot = createWrapperFixture(); + writeFileSync( + join(fixtureRoot, "package.json"), + JSON.stringify({ type: "module" }, null, "\t"), + "utf8", + ); + + const result = runWrapper(fixtureRoot, ["--version"]); + + expect(result.status).toBe(1); + expect(result.stdout).toBe(""); + expect(result.stderr).toContain("codex-multi-auth version is unavailable."); + }); + it("propagates integer exit codes", () => { const fixtureRoot = createWrapperFixture(); const distLibDir = join(fixtureRoot, "dist", "lib"); From 858f1fa63aa40a4f87d83df16754788617f1347b Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 22:23:05 +0800 Subject: [PATCH 2/5] test(wrapper): cover multi-arg version passthrough --- test/codex-multi-auth-bin-wrapper.test.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/codex-multi-auth-bin-wrapper.test.ts b/test/codex-multi-auth-bin-wrapper.test.ts index 2020f26d..3fef8309 100644 --- a/test/codex-multi-auth-bin-wrapper.test.ts +++ b/test/codex-multi-auth-bin-wrapper.test.ts @@ -107,6 +107,28 @@ describe("codex-multi-auth bin wrapper", () => { expect(result.stderr).toContain("codex-multi-auth version is unavailable."); }); + it("passes multi-argument version flags through to the runtime", () => { + const fixtureRoot = createWrapperFixture(); + const distLibDir = join(fixtureRoot, "dist", "lib"); + mkdirSync(distLibDir, { recursive: true }); + writeFileSync( + join(distLibDir, "codex-manager.js"), + [ + "export async function runCodexMultiAuthCli(args) {", + '\tif (!Array.isArray(args) || args[0] !== "--version" || args[1] !== "extra") throw new Error("bad args");', + "\treturn 6;", + "}", + ].join("\n"), + "utf8", + ); + + const result = runWrapper(fixtureRoot, ["--version", "extra"]); + + expect(result.status).toBe(6); + expect(result.stdout).toBe(""); + expect(result.stderr).toBe(""); + }); + it("propagates integer exit codes", () => { const fixtureRoot = createWrapperFixture(); const distLibDir = join(fixtureRoot, "dist", "lib"); From da495732b48817749ba9e0c1636b505815d8bafc Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 22:29:05 +0800 Subject: [PATCH 3/5] style(wrapper): fix runtime exit indentation --- scripts/codex-multi-auth.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/codex-multi-auth.js b/scripts/codex-multi-auth.js index 394f9edf..9cc1f2bc 100755 --- a/scripts/codex-multi-auth.js +++ b/scripts/codex-multi-auth.js @@ -36,5 +36,5 @@ if (args.length === 1 && versionFlags.has(args[0])) { } else { const { runCodexMultiAuthCli } = await import("../dist/lib/codex-manager.js"); const exitCode = await runCodexMultiAuthCli(args); -process.exitCode = Number.isInteger(exitCode) ? exitCode : 1; + process.exitCode = Number.isInteger(exitCode) ? exitCode : 1; } From 2cb694bbb1b1b8b6b7a67f9b3ee21b11d3b9c801 Mon Sep 17 00:00:00 2001 From: ndycode Date: Sat, 21 Mar 2026 04:47:44 +0800 Subject: [PATCH 4/5] test wrapper cleanup retry enotempty --- test/codex-multi-auth-bin-wrapper.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/codex-multi-auth-bin-wrapper.test.ts b/test/codex-multi-auth-bin-wrapper.test.ts index 3fef8309..3dc039eb 100644 --- a/test/codex-multi-auth-bin-wrapper.test.ts +++ b/test/codex-multi-auth-bin-wrapper.test.ts @@ -16,7 +16,7 @@ function isRetriableFsError(error: unknown): boolean { return false; } const { code } = error as { code?: unknown }; - return code === "EBUSY" || code === "EPERM"; + return code === "EBUSY" || code === "EPERM" || code === "ENOTEMPTY"; } async function removeDirectoryWithRetry(dir: string): Promise { From 70c3651abc6b5b072dd68cf440bda4cf11870383 Mon Sep 17 00:00:00 2001 From: ndycode Date: Sat, 21 Mar 2026 04:56:11 +0800 Subject: [PATCH 5/5] test: harden wrapper version passthrough coverage --- test/codex-multi-auth-bin-wrapper.test.ts | 25 +++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/test/codex-multi-auth-bin-wrapper.test.ts b/test/codex-multi-auth-bin-wrapper.test.ts index 3dc039eb..ad0a8233 100644 --- a/test/codex-multi-auth-bin-wrapper.test.ts +++ b/test/codex-multi-auth-bin-wrapper.test.ts @@ -10,6 +10,7 @@ import { sleep } from "../lib/utils.js"; const createdDirs: string[] = []; const testFileDir = dirname(fileURLToPath(import.meta.url)); const repoRootDir = join(testFileDir, ".."); +const passthroughEnvKeys = ["HOME", "PATH", "SystemRoot", "TEMP", "TMP", "USERPROFILE"] as const; function isRetriableFsError(error: unknown): boolean { if (!error || typeof error !== "object" || !("code" in error)) { @@ -54,15 +55,24 @@ function createWrapperFixture(): string { return fixtureRoot; } +function createChildEnv(): NodeJS.ProcessEnv { + const env: NodeJS.ProcessEnv = {}; + for (const key of passthroughEnvKeys) { + const value = process.env[key]; + if (typeof value === "string" && value.length > 0) { + env[key] = value; + } + } + return env; +} + function runWrapper(fixtureRoot: string, args: string[] = []) { return spawnSync( process.execPath, [join(fixtureRoot, "scripts", "codex-multi-auth.js"), ...args], { encoding: "utf8", - env: { - ...process.env, - }, + env: createChildEnv(), }, ); } @@ -107,7 +117,10 @@ describe("codex-multi-auth bin wrapper", () => { expect(result.stderr).toContain("codex-multi-auth version is unavailable."); }); - it("passes multi-argument version flags through to the runtime", () => { + it.each([ + ["--version", "extra"], + ["-v", "extra"], + ])("passes multi-argument version flags through to the runtime: %s", (flag, extraArg) => { const fixtureRoot = createWrapperFixture(); const distLibDir = join(fixtureRoot, "dist", "lib"); mkdirSync(distLibDir, { recursive: true }); @@ -115,14 +128,14 @@ describe("codex-multi-auth bin wrapper", () => { join(distLibDir, "codex-manager.js"), [ "export async function runCodexMultiAuthCli(args) {", - '\tif (!Array.isArray(args) || args[0] !== "--version" || args[1] !== "extra") throw new Error("bad args");', + `\tif (!Array.isArray(args) || args[0] !== ${JSON.stringify(flag)} || args[1] !== ${JSON.stringify(extraArg)}) throw new Error("bad args");`, "\treturn 6;", "}", ].join("\n"), "utf8", ); - const result = runWrapper(fixtureRoot, ["--version", "extra"]); + const result = runWrapper(fixtureRoot, [flag, extraArg]); expect(result.status).toBe(6); expect(result.stdout).toBe("");