codex-multi-auth 1.3.1 → 2.0.0

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.
Files changed (69) hide show
  1. package/README.md +39 -26
  2. package/config/README.md +3 -3
  3. package/dist/lib/codex-manager/commands/rotation.d.ts +22 -0
  4. package/dist/lib/codex-manager/commands/rotation.d.ts.map +1 -0
  5. package/dist/lib/codex-manager/commands/rotation.js +287 -0
  6. package/dist/lib/codex-manager/commands/rotation.js.map +1 -0
  7. package/dist/lib/codex-manager/commands/status.d.ts.map +1 -1
  8. package/dist/lib/codex-manager/commands/status.js +38 -7
  9. package/dist/lib/codex-manager/commands/status.js.map +1 -1
  10. package/dist/lib/codex-manager/help.d.ts.map +1 -1
  11. package/dist/lib/codex-manager/help.js +1 -0
  12. package/dist/lib/codex-manager/help.js.map +1 -1
  13. package/dist/lib/codex-manager.d.ts.map +1 -1
  14. package/dist/lib/codex-manager.js +59 -1
  15. package/dist/lib/codex-manager.js.map +1 -1
  16. package/dist/lib/config.d.ts +1 -0
  17. package/dist/lib/config.d.ts.map +1 -1
  18. package/dist/lib/config.js +9 -0
  19. package/dist/lib/config.js.map +1 -1
  20. package/dist/lib/constants.d.ts +2 -0
  21. package/dist/lib/constants.d.ts.map +1 -1
  22. package/dist/lib/constants.js +2 -0
  23. package/dist/lib/constants.js.map +1 -1
  24. package/dist/lib/fs-retry.d.ts +7 -0
  25. package/dist/lib/fs-retry.d.ts.map +1 -0
  26. package/dist/lib/fs-retry.js +35 -0
  27. package/dist/lib/fs-retry.js.map +1 -0
  28. package/dist/lib/index.d.ts +1 -0
  29. package/dist/lib/index.d.ts.map +1 -1
  30. package/dist/lib/index.js +1 -0
  31. package/dist/lib/index.js.map +1 -1
  32. package/dist/lib/logger.d.ts.map +1 -1
  33. package/dist/lib/logger.js +1 -0
  34. package/dist/lib/logger.js.map +1 -1
  35. package/dist/lib/runtime/app-bind.d.ts +74 -0
  36. package/dist/lib/runtime/app-bind.d.ts.map +1 -0
  37. package/dist/lib/runtime/app-bind.js +620 -0
  38. package/dist/lib/runtime/app-bind.js.map +1 -0
  39. package/dist/lib/runtime/config-toml.d.ts +10 -0
  40. package/dist/lib/runtime/config-toml.d.ts.map +1 -0
  41. package/dist/lib/runtime/config-toml.js +128 -0
  42. package/dist/lib/runtime/config-toml.js.map +1 -0
  43. package/dist/lib/runtime/runtime-observability.d.ts +5 -0
  44. package/dist/lib/runtime/runtime-observability.d.ts.map +1 -1
  45. package/dist/lib/runtime/runtime-observability.js +5 -0
  46. package/dist/lib/runtime/runtime-observability.js.map +1 -1
  47. package/dist/lib/runtime-constants.d.ts +3 -0
  48. package/dist/lib/runtime-constants.d.ts.map +1 -0
  49. package/dist/lib/runtime-constants.js +3 -0
  50. package/dist/lib/runtime-constants.js.map +1 -0
  51. package/dist/lib/runtime-rotation-proxy.d.ts +36 -0
  52. package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -0
  53. package/dist/lib/runtime-rotation-proxy.js +828 -0
  54. package/dist/lib/runtime-rotation-proxy.js.map +1 -0
  55. package/dist/lib/schemas.d.ts +1 -0
  56. package/dist/lib/schemas.d.ts.map +1 -1
  57. package/dist/lib/schemas.js +1 -0
  58. package/dist/lib/schemas.js.map +1 -1
  59. package/package.json +13 -11
  60. package/scripts/bench-format/codex-host.mjs +142 -73
  61. package/scripts/bench-format/models.mjs +17 -16
  62. package/scripts/benchmark-edit-formats.mjs +8 -6
  63. package/scripts/check-pack-budget-lib.js +49 -6
  64. package/scripts/codex-app-launcher.js +653 -0
  65. package/scripts/codex-app-router.js +322 -0
  66. package/scripts/codex-multi-auth.js +3 -1
  67. package/scripts/codex-routing.js +6 -0
  68. package/scripts/codex.js +3473 -1618
  69. package/scripts/postinstall.js +237 -0
@@ -0,0 +1,237 @@
1
+ #!/usr/bin/env node
2
+
3
+ // @ts-check
4
+
5
+ import { existsSync, readdirSync } from "node:fs";
6
+ import { homedir } from "node:os";
7
+ import { join, resolve } from "node:path";
8
+ import process from "node:process";
9
+ import { fileURLToPath } from "node:url";
10
+
11
+ const TRUE_VALUES = new Set(["1", "true", "yes"]);
12
+ const FALSE_VALUES = new Set(["0", "false", "no"]);
13
+ const CI_ENV_KEYS = [
14
+ "CI",
15
+ "GITHUB_ACTIONS",
16
+ "GITLAB_CI",
17
+ "CIRCLECI",
18
+ "BUILDKITE",
19
+ "TF_BUILD",
20
+ "TEAMCITY_VERSION",
21
+ "JENKINS_URL",
22
+ "TRAVIS",
23
+ "APPVEYOR",
24
+ "BITBUCKET_BUILD_NUMBER",
25
+ ];
26
+
27
+ /**
28
+ * @param {string | undefined} value
29
+ */
30
+ export function readOptionalBoolean(value) {
31
+ if (value === undefined || value.trim().length === 0) return null;
32
+ const normalized = value.trim().toLowerCase();
33
+ if (TRUE_VALUES.has(normalized)) return true;
34
+ if (FALSE_VALUES.has(normalized)) return false;
35
+ return null;
36
+ }
37
+
38
+ /**
39
+ * @param {NodeJS.ProcessEnv} env
40
+ */
41
+ export function isGlobalNpmInstall(env = process.env) {
42
+ const globalFlag = readOptionalBoolean(env.npm_config_global);
43
+ if (globalFlag === true) return true;
44
+ return (env.npm_config_location ?? "").trim().toLowerCase() === "global";
45
+ }
46
+
47
+ /**
48
+ * @param {NodeJS.ProcessEnv} env
49
+ * @param {string} key
50
+ */
51
+ function isEnabledEnvFlag(env, key) {
52
+ const value = env[key];
53
+ if (value === undefined || value.trim().length === 0) return false;
54
+ const parsed = readOptionalBoolean(value);
55
+ return parsed !== false;
56
+ }
57
+
58
+ /**
59
+ * @param {NodeJS.ProcessEnv} [env]
60
+ */
61
+ export function isCiEnvironment(env = process.env) {
62
+ if (readOptionalBoolean(env.npm_config_ignore_scripts) === true) return true;
63
+ return CI_ENV_KEYS.some((key) => isEnabledEnvFlag(env, key));
64
+ }
65
+
66
+ /**
67
+ * @param {string} directory
68
+ * @param {string} prefix
69
+ */
70
+ function directoryContainsEntryWithPrefix(directory, prefix) {
71
+ try {
72
+ return readdirSync(directory, { withFileTypes: true }).some((entry) =>
73
+ entry.name.startsWith(prefix),
74
+ );
75
+ } catch {
76
+ return false;
77
+ }
78
+ }
79
+
80
+ /**
81
+ * @param {{ env?: NodeJS.ProcessEnv, platform?: NodeJS.Platform, home?: string }} [options]
82
+ */
83
+ export function hasCodexDesktopApp(options = {}) {
84
+ const env = options.env ?? process.env;
85
+ const platform = options.platform ?? process.platform;
86
+ const home = options.home ?? homedir();
87
+
88
+ if (platform === "win32") {
89
+ const localAppData =
90
+ (env.LOCALAPPDATA ?? "").trim() || join(home, "AppData", "Local");
91
+ const programFiles =
92
+ (env.ProgramFiles ?? env.ProgramW6432 ?? "").trim() || "C:\\Program Files";
93
+ return (
94
+ directoryContainsEntryWithPrefix(
95
+ join(localAppData, "Packages"),
96
+ "OpenAI.Codex_",
97
+ ) ||
98
+ directoryContainsEntryWithPrefix(
99
+ join(programFiles, "WindowsApps"),
100
+ "OpenAI.Codex_",
101
+ )
102
+ );
103
+ }
104
+
105
+ if (platform === "darwin") {
106
+ return (
107
+ existsSync("/Applications/Codex.app") ||
108
+ existsSync(join(home, "Applications", "Codex.app"))
109
+ );
110
+ }
111
+
112
+ return false;
113
+ }
114
+
115
+ /**
116
+ * @param {{
117
+ * env?: NodeJS.ProcessEnv,
118
+ * platform?: NodeJS.Platform,
119
+ * home?: string,
120
+ * rotationEnabled: boolean,
121
+ * appDetected?: boolean,
122
+ * }} options
123
+ */
124
+ export function shouldAutoBindCodexAppOnInstall(options) {
125
+ const env = options.env ?? process.env;
126
+ if (isCiEnvironment(env)) return false;
127
+
128
+ const bindOverride = readOptionalBoolean(env.CODEX_MULTI_AUTH_APP_BIND);
129
+ if (bindOverride !== null) return bindOverride;
130
+
131
+ const installOverride = readOptionalBoolean(
132
+ env.CODEX_MULTI_AUTH_APP_BIND_INSTALL,
133
+ );
134
+ if (installOverride !== null) return installOverride;
135
+
136
+ if (!isGlobalNpmInstall(env)) return false;
137
+ if (!options.rotationEnabled) return false;
138
+ return (
139
+ options.appDetected ??
140
+ hasCodexDesktopApp({
141
+ env,
142
+ platform: options.platform,
143
+ home: options.home,
144
+ })
145
+ );
146
+ }
147
+
148
+ async function loadConfigModule() {
149
+ try {
150
+ return await import("../dist/lib/config.js");
151
+ } catch (error) {
152
+ if (
153
+ error &&
154
+ typeof error === "object" &&
155
+ "code" in error &&
156
+ error.code === "ERR_MODULE_NOT_FOUND"
157
+ ) {
158
+ return null;
159
+ }
160
+ throw error;
161
+ }
162
+ }
163
+
164
+ async function loadAppBindModule() {
165
+ try {
166
+ return await import("../dist/lib/runtime/app-bind.js");
167
+ } catch (error) {
168
+ if (
169
+ error &&
170
+ typeof error === "object" &&
171
+ "code" in error &&
172
+ error.code === "ERR_MODULE_NOT_FOUND"
173
+ ) {
174
+ return null;
175
+ }
176
+ throw error;
177
+ }
178
+ }
179
+
180
+ function resolveRotationEnabled(configModule) {
181
+ const envOverride = readOptionalBoolean(
182
+ process.env.CODEX_MULTI_AUTH_RUNTIME_ROTATION_PROXY,
183
+ );
184
+ if (envOverride !== null) return envOverride;
185
+ if (
186
+ !configModule ||
187
+ typeof configModule.loadPluginConfig !== "function" ||
188
+ typeof configModule.getCodexRuntimeRotationProxy !== "function"
189
+ ) {
190
+ return false;
191
+ }
192
+ return (
193
+ configModule.getCodexRuntimeRotationProxy(configModule.loadPluginConfig()) ===
194
+ true
195
+ );
196
+ }
197
+
198
+ async function main() {
199
+ const appBindModule = await loadAppBindModule();
200
+ if (!appBindModule || typeof appBindModule.bindCodexAppRuntimeRotation !== "function") {
201
+ return 0;
202
+ }
203
+
204
+ const configModule = await loadConfigModule();
205
+ const rotationEnabled = resolveRotationEnabled(configModule);
206
+ const currentStatus =
207
+ typeof appBindModule.getAppBindStatus === "function"
208
+ ? await appBindModule.getAppBindStatus().catch(() => null)
209
+ : null;
210
+ const appDetected = hasCodexDesktopApp() || currentStatus?.bound === true;
211
+ if (!shouldAutoBindCodexAppOnInstall({ rotationEnabled, appDetected })) {
212
+ return 0;
213
+ }
214
+
215
+ const result = await appBindModule.bindCodexAppRuntimeRotation();
216
+ if (result?.message) {
217
+ console.error(`codex-multi-auth: ${result.message}`);
218
+ }
219
+ return 0;
220
+ }
221
+
222
+ const isDirectRun = (() => {
223
+ try {
224
+ return resolve(process.argv[1] ?? "") === fileURLToPath(import.meta.url);
225
+ } catch {
226
+ return false;
227
+ }
228
+ })();
229
+
230
+ if (isDirectRun) {
231
+ main().catch((error) => {
232
+ console.error(
233
+ `codex-multi-auth: app bind postinstall skipped: ${error instanceof Error ? error.message : String(error)}`,
234
+ );
235
+ process.exitCode = 0;
236
+ });
237
+ }