codex-multi-auth 2.8.0 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codex-multi-auth",
3
- "version": "2.8.0",
3
+ "version": "2.8.1",
4
4
  "description": "Install and operate codex-multi-auth for the official @openai/codex CLI with multi-account OAuth rotation, switching, health checks, and recovery tools.",
5
5
  "interface": {
6
6
  "composerIcon": "./assets/codex-multi-auth-icon.svg"
package/package.json CHANGED
@@ -1,196 +1,198 @@
1
- {
2
- "name": "codex-multi-auth",
3
- "version": "2.8.0",
4
- "description": "Codex CLI multi-account OAuth manager with account switching, health checks, runtime rotation, diagnostics, and recovery tools for @openai/codex",
5
- "main": "./dist/index.js",
6
- "types": "./dist/index.d.ts",
7
- "exports": {
8
- ".": {
9
- "types": "./dist/index.d.ts",
10
- "import": "./dist/index.js",
11
- "default": "./dist/index.js"
12
- },
13
- "./auth": {
14
- "types": "./dist/lib/auth/index.d.ts",
15
- "import": "./dist/lib/auth/index.js",
16
- "default": "./dist/lib/auth/index.js"
17
- },
18
- "./storage": {
19
- "types": "./dist/lib/storage.d.ts",
20
- "import": "./dist/lib/storage.js",
21
- "default": "./dist/lib/storage.js"
22
- },
23
- "./config": {
24
- "types": "./dist/lib/config.d.ts",
25
- "import": "./dist/lib/config.js",
26
- "default": "./dist/lib/config.js"
27
- },
28
- "./request": {
29
- "types": "./dist/lib/request/index.d.ts",
30
- "import": "./dist/lib/request/index.js",
31
- "default": "./dist/lib/request/index.js"
32
- },
33
- "./cli": {
34
- "types": "./dist/lib/codex-cli/index.d.ts",
35
- "import": "./dist/lib/codex-cli/index.js",
36
- "default": "./dist/lib/codex-cli/index.js"
37
- },
38
- "./package.json": "./package.json"
39
- },
40
- "type": "module",
41
- "license": "MIT",
42
- "author": "ndycode",
43
- "repository": {
44
- "type": "git",
45
- "url": "git+https://github.com/ndycode/codex-multi-auth.git"
46
- },
47
- "keywords": [
48
- "openai",
49
- "codex",
50
- "codex-cli",
51
- "codex-auth",
52
- "codex-multi-account",
53
- "chatgpt",
54
- "oauth",
55
- "oauth2",
56
- "pkce",
57
- "multi-account",
58
- "account-switching",
59
- "oauth-manager",
60
- "runtime-rotation",
61
- "responses-api",
62
- "local-proxy",
63
- "quota-management",
64
- "diagnostics",
65
- "fault-tolerance",
66
- "terminal-ui",
67
- "cli-tool",
68
- "typescript",
69
- "nodejs",
70
- "developer-tools",
71
- "authentication",
72
- "account-health",
73
- "recovery-tools",
74
- "project-scoped-storage"
75
- ],
76
- "homepage": "https://github.com/ndycode/codex-multi-auth#readme",
77
- "bugs": {
78
- "url": "https://github.com/ndycode/codex-multi-auth/issues"
79
- },
80
- "scripts": {
81
- "build": "tsc && node scripts/copy-oauth-success.js",
82
- "generate:schema": "npm run build && node scripts/generate-config-schema.mjs",
83
- "typecheck": "tsc --noEmit",
84
- "typecheck:scripts": "tsc -p tsconfig.scripts.json",
85
- "lint": "npm run lint:ts && npm run lint:scripts",
86
- "lint:ts": "eslint . --ext .ts",
87
- "lint:scripts": "eslint scripts --ext .js,.mjs",
88
- "lint:fix": "npm run lint:ts:fix && npm run lint:scripts:fix",
89
- "lint:ts:fix": "eslint . --ext .ts --fix",
90
- "lint:scripts:fix": "eslint scripts --ext .js,.mjs --fix",
91
- "test": "vitest run --maxWorkers=1",
92
- "test:watch": "vitest",
93
- "test:ui": "vitest --ui",
94
- "test:model-matrix": "node scripts/test-model-matrix.js",
95
- "test:model-matrix:smoke": "node scripts/test-model-matrix.js --smoke",
96
- "test:model-matrix:report": "node scripts/test-model-matrix.js --smoke --report-json=.tmp/model-matrix-report.json",
97
- "clean:repo": "node scripts/repo-hygiene.js clean --mode aggressive",
98
- "clean:repo:check": "node scripts/repo-hygiene.js check",
99
- "pack:check": "npm run build && node scripts/check-pack-budget.mjs",
100
- "bench:edit-formats": "node scripts/benchmark-edit-formats.mjs --preset=codex-core",
101
- "bench:edit-formats:smoke": "node scripts/benchmark-edit-formats.mjs --smoke --preset=codex-core",
102
- "bench:edit-formats:render": "node scripts/benchmark-render-dashboard.mjs",
103
- "bench:runtime-path": "npm run build && node scripts/benchmark-runtime-path.mjs",
104
- "bench:runtime-path:quick": "node scripts/benchmark-runtime-path.mjs",
105
- "test:coverage": "vitest run --coverage --maxWorkers=1",
106
- "coverage": "npm run build && vitest run --coverage --maxWorkers=1",
107
- "audit:prod": "npm audit --omit=dev --audit-level=high",
108
- "audit:all": "npm audit --audit-level=high",
109
- "audit:dev:allowlist": "node scripts/audit-dev-allowlist.js",
110
- "audit:ci": "npm run audit:prod && npm run audit:dev:allowlist",
111
- "vendor:verify": "node scripts/verify-vendor-provenance.mjs",
112
- "vendor:update-manifest": "node scripts/update-vendor-provenance.mjs",
113
- "postinstall": "node scripts/postinstall.js",
114
- "prepublishOnly": "npm run build",
115
- "prepare": "husky"
116
- },
117
- "bin": {
118
- "mcodex": "scripts/mcodex.js",
119
- "codex-multi-auth-codex": "scripts/codex.js",
120
- "codex-multi-auth-app-launcher": "scripts/codex-app-launcher.js",
121
- "codex-multi-auth": "scripts/codex-multi-auth.js"
122
- },
123
- "files": [
124
- ".codex-plugin/plugin.json",
125
- "dist/",
126
- "assets/",
127
- "config/",
128
- "scripts/codex.js",
129
- "scripts/codex-app-launcher.js",
130
- "scripts/codex-app-router.js",
131
- "scripts/codex-bin-resolver.js",
132
- "scripts/codex-multi-auth.js",
133
- "scripts/codex-routing.js",
134
- "scripts/mcodex.js",
135
- "scripts/install-codex-auth-utils.js",
136
- "scripts/postinstall.js",
137
- "scripts/preuninstall.js",
138
- "vendor/codex-ai-plugin/",
139
- "vendor/codex-ai-sdk/",
140
- "README.md",
141
- "LICENSE"
142
- ],
143
- "bundleDependencies": [
144
- "@codex-ai/plugin",
145
- "@codex-ai/sdk"
146
- ],
147
- "lint-staged": {
148
- "*.ts": [
149
- "eslint --max-warnings=0 --fix --no-warn-ignored"
150
- ],
151
- "scripts/**/*.{js,mjs}": [
152
- "eslint --max-warnings=0 --fix --no-warn-ignored"
153
- ]
154
- },
155
- "engines": {
156
- "node": ">=18.17.0"
157
- },
158
- "devDependencies": {
159
- "@types/node": "^20.19.42",
160
- "@typescript-eslint/eslint-plugin": "^8.56.0",
161
- "@typescript-eslint/parser": "^8.56.0",
162
- "@vitest/coverage-v8": "^4.1.8",
163
- "@vitest/ui": "^4.1.8",
164
- "eslint": "^10.0.0",
165
- "eslint-import-resolver-typescript": "^4.4.5",
166
- "eslint-plugin-import-x": "^4.16.2",
167
- "fast-check": "^4.5.3",
168
- "husky": "^9.1.7",
169
- "lint-staged": "^16.2.7",
170
- "typescript": "^5.9.3",
171
- "typescript-language-server": "^5.1.3",
172
- "vitest": "^4.1.8"
173
- },
174
- "dependencies": {
175
- "@codex-ai/plugin": "file:vendor/codex-ai-plugin",
176
- "@codex-ai/sdk": "file:vendor/codex-ai-sdk",
177
- "@openauthjs/openauth": "^0.4.3",
178
- "hono": "4.12.21",
179
- "undici": "6.25.0",
180
- "zod": "4.4.3"
181
- },
182
- "overrides": {
183
- "hono": "4.12.21",
184
- "flatted": "3.4.2",
185
- "minimatch": "10.2.4",
186
- "picomatch": "4.0.4",
187
- "rollup": "4.59.0",
188
- "vite": "^7.3.2",
189
- "micromatch": {
190
- "picomatch": "2.3.2"
191
- },
192
- "@typescript-eslint/typescript-estree": {
193
- "minimatch": "9.0.9"
194
- }
195
- }
196
- }
1
+ {
2
+ "name": "codex-multi-auth",
3
+ "version": "2.8.1",
4
+ "description": "Codex CLI multi-account OAuth manager with account switching, health checks, runtime rotation, diagnostics, and recovery tools for @openai/codex",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "import": "./dist/index.js",
11
+ "default": "./dist/index.js"
12
+ },
13
+ "./auth": {
14
+ "types": "./dist/lib/auth/index.d.ts",
15
+ "import": "./dist/lib/auth/index.js",
16
+ "default": "./dist/lib/auth/index.js"
17
+ },
18
+ "./storage": {
19
+ "types": "./dist/lib/storage.d.ts",
20
+ "import": "./dist/lib/storage.js",
21
+ "default": "./dist/lib/storage.js"
22
+ },
23
+ "./config": {
24
+ "types": "./dist/lib/config.d.ts",
25
+ "import": "./dist/lib/config.js",
26
+ "default": "./dist/lib/config.js"
27
+ },
28
+ "./request": {
29
+ "types": "./dist/lib/request/index.d.ts",
30
+ "import": "./dist/lib/request/index.js",
31
+ "default": "./dist/lib/request/index.js"
32
+ },
33
+ "./cli": {
34
+ "types": "./dist/lib/codex-cli/index.d.ts",
35
+ "import": "./dist/lib/codex-cli/index.js",
36
+ "default": "./dist/lib/codex-cli/index.js"
37
+ },
38
+ "./package.json": "./package.json"
39
+ },
40
+ "type": "module",
41
+ "license": "MIT",
42
+ "author": "ndycode",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/ndycode/codex-multi-auth.git"
46
+ },
47
+ "keywords": [
48
+ "openai",
49
+ "codex",
50
+ "codex-cli",
51
+ "codex-auth",
52
+ "codex-multi-account",
53
+ "chatgpt",
54
+ "oauth",
55
+ "oauth2",
56
+ "pkce",
57
+ "multi-account",
58
+ "account-switching",
59
+ "oauth-manager",
60
+ "runtime-rotation",
61
+ "responses-api",
62
+ "local-proxy",
63
+ "quota-management",
64
+ "diagnostics",
65
+ "fault-tolerance",
66
+ "terminal-ui",
67
+ "cli-tool",
68
+ "typescript",
69
+ "nodejs",
70
+ "developer-tools",
71
+ "authentication",
72
+ "account-health",
73
+ "recovery-tools",
74
+ "project-scoped-storage"
75
+ ],
76
+ "homepage": "https://github.com/ndycode/codex-multi-auth#readme",
77
+ "bugs": {
78
+ "url": "https://github.com/ndycode/codex-multi-auth/issues"
79
+ },
80
+ "scripts": {
81
+ "build": "tsc && node scripts/copy-oauth-success.js",
82
+ "generate:schema": "npm run build && node scripts/generate-config-schema.mjs",
83
+ "typecheck": "tsc --noEmit",
84
+ "typecheck:scripts": "tsc -p tsconfig.scripts.json",
85
+ "lint": "npm run lint:ts && npm run lint:scripts",
86
+ "lint:ts": "eslint . --ext .ts",
87
+ "lint:scripts": "eslint scripts --ext .js,.mjs",
88
+ "lint:fix": "npm run lint:ts:fix && npm run lint:scripts:fix",
89
+ "lint:ts:fix": "eslint . --ext .ts --fix",
90
+ "lint:scripts:fix": "eslint scripts --ext .js,.mjs --fix",
91
+ "test": "vitest run --maxWorkers=1",
92
+ "test:watch": "vitest",
93
+ "test:ui": "vitest --ui",
94
+ "test:model-matrix": "node scripts/test-model-matrix.js",
95
+ "test:model-matrix:smoke": "node scripts/test-model-matrix.js --smoke",
96
+ "test:model-matrix:report": "node scripts/test-model-matrix.js --smoke --report-json=.tmp/model-matrix-report.json",
97
+ "clean:repo": "node scripts/repo-hygiene.js clean --mode aggressive",
98
+ "clean:repo:check": "node scripts/repo-hygiene.js check",
99
+ "pack:check": "npm run build && node scripts/check-pack-budget.mjs",
100
+ "bench:edit-formats": "node scripts/benchmark-edit-formats.mjs --preset=codex-core",
101
+ "bench:edit-formats:smoke": "node scripts/benchmark-edit-formats.mjs --smoke --preset=codex-core",
102
+ "bench:edit-formats:render": "node scripts/benchmark-render-dashboard.mjs",
103
+ "bench:runtime-path": "npm run build && node scripts/benchmark-runtime-path.mjs",
104
+ "bench:runtime-path:quick": "node scripts/benchmark-runtime-path.mjs",
105
+ "test:coverage": "vitest run --coverage --maxWorkers=1",
106
+ "coverage": "npm run build && vitest run --coverage --maxWorkers=1",
107
+ "audit:prod": "npm audit --omit=dev --audit-level=high",
108
+ "audit:all": "npm audit --audit-level=high",
109
+ "audit:dev:allowlist": "node scripts/audit-dev-allowlist.js",
110
+ "audit:ci": "npm run audit:prod && npm run audit:dev:allowlist",
111
+ "vendor:verify": "node scripts/verify-vendor-provenance.mjs",
112
+ "vendor:update-manifest": "node scripts/update-vendor-provenance.mjs",
113
+ "postinstall": "node scripts/postinstall.js",
114
+ "prepublishOnly": "npm run build",
115
+ "prepare": "husky"
116
+ },
117
+ "bin": {
118
+ "mcodex": "scripts/mcodex.js",
119
+ "codex-multi-auth-codex": "scripts/codex.js",
120
+ "codex-multi-auth-app-launcher": "scripts/codex-app-launcher.js",
121
+ "codex-multi-auth": "scripts/codex-multi-auth.js"
122
+ },
123
+ "files": [
124
+ ".codex-plugin/plugin.json",
125
+ "dist/",
126
+ "assets/",
127
+ "config/",
128
+ "scripts/codex.js",
129
+ "scripts/codex-app-launcher.js",
130
+ "scripts/codex-app-router.js",
131
+ "scripts/codex-bin-resolver.js",
132
+ "scripts/codex-multi-auth.js",
133
+ "scripts/codex-routing.js",
134
+ "scripts/mcodex.js",
135
+ "scripts/install-codex-auth-utils.js",
136
+ "scripts/postinstall.js",
137
+ "scripts/preuninstall.js",
138
+ "vendor/codex-ai-plugin/",
139
+ "vendor/codex-ai-sdk/",
140
+ "README.md",
141
+ "LICENSE"
142
+ ],
143
+ "bundleDependencies": [
144
+ "@codex-ai/plugin",
145
+ "@codex-ai/sdk"
146
+ ],
147
+ "lint-staged": {
148
+ "*.ts": [
149
+ "eslint --max-warnings=0 --fix --no-warn-ignored"
150
+ ],
151
+ "scripts/**/*.{js,mjs}": [
152
+ "eslint --max-warnings=0 --fix --no-warn-ignored"
153
+ ]
154
+ },
155
+ "engines": {
156
+ "node": ">=18.17.0"
157
+ },
158
+ "devDependencies": {
159
+ "@types/node": "^20.19.42",
160
+ "@typescript-eslint/eslint-plugin": "^8.56.0",
161
+ "@typescript-eslint/parser": "^8.56.0",
162
+ "@vitest/coverage-v8": "^4.1.8",
163
+ "@vitest/ui": "^4.1.8",
164
+ "eslint": "^10.0.0",
165
+ "eslint-import-resolver-typescript": "^4.4.5",
166
+ "eslint-plugin-import-x": "^4.16.2",
167
+ "fast-check": "^4.5.3",
168
+ "husky": "^9.1.7",
169
+ "lint-staged": "^16.2.7",
170
+ "typescript": "^5.9.3",
171
+ "typescript-language-server": "^5.1.3",
172
+ "vitest": "^4.1.8"
173
+ },
174
+ "dependencies": {
175
+ "@codex-ai/plugin": "file:vendor/codex-ai-plugin",
176
+ "@codex-ai/sdk": "file:vendor/codex-ai-sdk",
177
+ "@openauthjs/openauth": "^0.4.3",
178
+ "hono": "4.12.33",
179
+ "undici": "6.28.0",
180
+ "zod": "4.4.3"
181
+ },
182
+ "overrides": {
183
+ "hono": "4.12.33",
184
+ "flatted": "3.4.2",
185
+ "minimatch": "10.2.4",
186
+ "picomatch": "4.0.4",
187
+ "rollup": "4.59.0",
188
+ "vite": "^7.3.2",
189
+ "micromatch": {
190
+ "picomatch": "2.3.2"
191
+ },
192
+ "@typescript-eslint/typescript-estree": {
193
+ "minimatch": "9.0.9"
194
+ },
195
+ "brace-expansion": "5.0.9",
196
+ "postcss": "8.5.25"
197
+ }
198
+ }
package/scripts/codex.js CHANGED
@@ -4003,6 +4003,9 @@ function waitForRuntimeRotationAppHelperExit(helper, timeoutMs = 2_000) {
4003
4003
  if (settled) return;
4004
4004
  settled = true;
4005
4005
  if (timer) clearTimeout(timer);
4006
+ // Drop the listener when the timeout wins, so a helper that outlives the
4007
+ // graceful window does not keep a live reference back into this process.
4008
+ helper.off?.("close", finish);
4006
4009
  resolve();
4007
4010
  };
4008
4011
  timer = setTimeout(finish, timeoutMs);
@@ -4010,16 +4013,49 @@ function waitForRuntimeRotationAppHelperExit(helper, timeoutMs = 2_000) {
4010
4013
  });
4011
4014
  }
4012
4015
 
4013
- function stopRuntimeRotationAppHelper(helper) {
4014
- if (!helper || helper.killed) {
4015
- return Promise.resolve();
4016
- }
4016
+ function hasRuntimeRotationAppHelperExited(helper) {
4017
+ return helper.exitCode !== null || helper.signalCode !== null;
4018
+ }
4019
+
4020
+ // Releases every handle the helper still holds in this process. The helper is
4021
+ // spawned with piped stdio, so those pipes keep the parent event loop alive on
4022
+ // their own — destroying and unref-ing them is what actually lets `mcodex` return
4023
+ // to the shell when the child ignores or outlives SIGTERM (#647).
4024
+ function releaseRuntimeRotationAppHelperResources(helper) {
4025
+ helper.stdout?.destroy();
4026
+ helper.stderr?.destroy();
4017
4027
  try {
4018
- helper.kill("SIGTERM");
4028
+ helper.unref();
4019
4029
  } catch {
4020
- return Promise.resolve();
4030
+ // Best-effort only.
4031
+ }
4032
+ }
4033
+
4034
+ async function stopRuntimeRotationAppHelper(helper) {
4035
+ if (!helper) {
4036
+ return;
4037
+ }
4038
+ if (hasRuntimeRotationAppHelperExited(helper)) {
4039
+ releaseRuntimeRotationAppHelperResources(helper);
4040
+ return;
4041
+ }
4042
+ if (!helper.killed) {
4043
+ try {
4044
+ helper.kill("SIGTERM");
4045
+ } catch {
4046
+ releaseRuntimeRotationAppHelperResources(helper);
4047
+ return;
4048
+ }
4049
+ }
4050
+ await waitForRuntimeRotationAppHelperExit(helper);
4051
+ if (!hasRuntimeRotationAppHelperExited(helper)) {
4052
+ try {
4053
+ helper.kill("SIGKILL");
4054
+ } catch {
4055
+ // Best-effort force-stop once the graceful shutdown window has elapsed.
4056
+ }
4021
4057
  }
4022
- return waitForRuntimeRotationAppHelperExit(helper);
4058
+ releaseRuntimeRotationAppHelperResources(helper);
4023
4059
  }
4024
4060
 
4025
4061
  function startRuntimeRotationAppHelper(baseContext, options = {}) {
@@ -4171,7 +4207,10 @@ async function createRuntimeRotationProxyContextIfEnabled(
4171
4207
  if (isCodexAppCommand(rawArgs)) {
4172
4208
  return createRuntimeRotationAppHelperContext(baseContext, configTomlModule);
4173
4209
  }
4174
- if (isCodexInteractiveTuiCommand(rawArgs)) {
4210
+ if (
4211
+ isCodexInteractiveTuiCommand(rawArgs) ||
4212
+ isCodexInteractiveResumeCommand(rawArgs)
4213
+ ) {
4175
4214
  return createRuntimeRotationAppHelperContext(baseContext, configTomlModule, {
4176
4215
  detachOnExit: true,
4177
4216
  useCanonicalHome: true,
@@ -4375,6 +4414,17 @@ function isCodexInteractiveTuiCommand(rawArgs) {
4375
4414
  return findForwardedCommand(rawArgs) === null;
4376
4415
  }
4377
4416
 
4417
+ // `resume` and `fork` are interactive TUI entry points that happen to carry a
4418
+ // forwarded subcommand, so the bare-invocation predicate above misses them. They
4419
+ // must not take the shadow-home transport: the shadow mirror deliberately omits the
4420
+ // runtime SQLite state (`isRuntimeRotationShadowHomeOmittedEntry`), so the requested
4421
+ // thread is absent from the shadow session index and the resumed TUI hangs on a
4422
+ // blank screen (#647).
4423
+ function isCodexInteractiveResumeCommand(rawArgs) {
4424
+ const command = findForwardedCommand(rawArgs)?.command;
4425
+ return command === "resume" || command === "fork";
4426
+ }
4427
+
4378
4428
  function shouldUseRuntimeRoutingForForwardedArgs(rawArgs) {
4379
4429
  if (!Array.isArray(rawArgs) || rawArgs.length === 0) {
4380
4430
  return true;
@@ -4414,7 +4464,17 @@ function shouldUseRuntimeRoutingForForwardedArgs(rawArgs) {
4414
4464
  );
4415
4465
  }
4416
4466
 
4417
- if (command.command === "app" && hasHelpFlagAfterCommand(rawArgs, command.index)) {
4467
+ // Request commands still print their help without making a single model
4468
+ // request, so the help form skips the transport entirely: no proxy, no shadow
4469
+ // home, no detached helper. This matters most for the interactive commands,
4470
+ // which detach their helper on a clean exit — help always exits clean, so
4471
+ // `resume --help` would otherwise strand a helper until its idle timeout. It is
4472
+ // keyed off the help flag rather than the command, so a real run still routes
4473
+ // through rotation, and it matches how `app-server` help is handled above (#647).
4474
+ if (
4475
+ requestCommands.has(command.command) &&
4476
+ hasHelpFlagAfterCommand(rawArgs, command.index)
4477
+ ) {
4418
4478
  return false;
4419
4479
  }
4420
4480
  if (requestCommands.has(command.command)) {