codex-multi-auth 1.2.1 → 1.2.4
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.
- package/README.md +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +55 -21
- package/dist/index.js.map +1 -1
- package/dist/lib/accounts.d.ts +11 -0
- package/dist/lib/accounts.d.ts.map +1 -1
- package/dist/lib/accounts.js +320 -70
- package/dist/lib/accounts.js.map +1 -1
- package/dist/lib/circuit-breaker.d.ts +4 -0
- package/dist/lib/circuit-breaker.d.ts.map +1 -1
- package/dist/lib/circuit-breaker.js +33 -1
- package/dist/lib/circuit-breaker.js.map +1 -1
- package/dist/lib/codex-manager/commands/forecast.d.ts +2 -1
- package/dist/lib/codex-manager/commands/forecast.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/forecast.js +92 -2
- package/dist/lib/codex-manager/commands/forecast.js.map +1 -1
- package/dist/lib/codex-manager/commands/report.d.ts +3 -1
- package/dist/lib/codex-manager/commands/report.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/report.js +102 -12
- package/dist/lib/codex-manager/commands/report.js.map +1 -1
- package/dist/lib/codex-manager.d.ts.map +1 -1
- package/dist/lib/codex-manager.js +50 -40
- package/dist/lib/codex-manager.js.map +1 -1
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +172 -17
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/forecast.d.ts.map +1 -1
- package/dist/lib/forecast.js +1 -19
- package/dist/lib/forecast.js.map +1 -1
- package/dist/lib/health.d.ts +1 -0
- package/dist/lib/health.d.ts.map +1 -1
- package/dist/lib/health.js +6 -2
- package/dist/lib/health.js.map +1 -1
- package/dist/lib/parallel-probe.d.ts +1 -1
- package/dist/lib/parallel-probe.d.ts.map +1 -1
- package/dist/lib/parallel-probe.js +5 -2
- package/dist/lib/parallel-probe.js.map +1 -1
- package/dist/lib/preemptive-quota-scheduler.d.ts.map +1 -1
- package/dist/lib/preemptive-quota-scheduler.js +6 -3
- package/dist/lib/preemptive-quota-scheduler.js.map +1 -1
- package/dist/lib/proactive-refresh.d.ts +1 -1
- package/dist/lib/proactive-refresh.d.ts.map +1 -1
- package/dist/lib/proactive-refresh.js +14 -5
- package/dist/lib/proactive-refresh.js.map +1 -1
- package/dist/lib/refresh-guardian.d.ts +3 -0
- package/dist/lib/refresh-guardian.d.ts.map +1 -1
- package/dist/lib/refresh-guardian.js +142 -52
- package/dist/lib/refresh-guardian.js.map +1 -1
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +180 -43
- package/dist/lib/request/fetch-helpers.js.map +1 -1
- package/dist/lib/rotation.d.ts +14 -11
- package/dist/lib/rotation.d.ts.map +1 -1
- package/dist/lib/rotation.js +36 -30
- package/dist/lib/rotation.js.map +1 -1
- package/dist/lib/runtime/account-check.d.ts +4 -0
- package/dist/lib/runtime/account-check.d.ts.map +1 -1
- package/dist/lib/runtime/account-check.js +15 -10
- package/dist/lib/runtime/account-check.js.map +1 -1
- package/dist/lib/runtime/account-state.d.ts +1 -12
- package/dist/lib/runtime/account-state.d.ts.map +1 -1
- package/dist/lib/runtime/account-state.js +1 -37
- package/dist/lib/runtime/account-state.js.map +1 -1
- package/dist/lib/runtime/verify-flagged.d.ts +4 -0
- package/dist/lib/runtime/verify-flagged.d.ts.map +1 -1
- package/dist/lib/runtime/verify-flagged.js +32 -23
- package/dist/lib/runtime/verify-flagged.js.map +1 -1
- package/dist/lib/storage/flagged-load-entry.d.ts +2 -0
- package/dist/lib/storage/flagged-load-entry.d.ts.map +1 -1
- package/dist/lib/storage/flagged-load-entry.js +1 -0
- package/dist/lib/storage/flagged-load-entry.js.map +1 -1
- package/dist/lib/storage/flagged-storage-file.d.ts +4 -0
- package/dist/lib/storage/flagged-storage-file.d.ts.map +1 -1
- package/dist/lib/storage/flagged-storage-file.js +1 -1
- package/dist/lib/storage/flagged-storage-file.js.map +1 -1
- package/dist/lib/storage/flagged-storage-io.d.ts +1 -0
- package/dist/lib/storage/flagged-storage-io.d.ts.map +1 -1
- package/dist/lib/storage/flagged-storage-io.js +130 -5
- package/dist/lib/storage/flagged-storage-io.js.map +1 -1
- package/dist/lib/storage/identity.d.ts +6 -0
- package/dist/lib/storage/identity.d.ts.map +1 -1
- package/dist/lib/storage/identity.js +14 -3
- package/dist/lib/storage/identity.js.map +1 -1
- package/dist/lib/storage/path-state.d.ts +1 -0
- package/dist/lib/storage/path-state.d.ts.map +1 -1
- package/dist/lib/storage/path-state.js +3 -0
- package/dist/lib/storage/path-state.js.map +1 -1
- package/dist/lib/storage/paths.d.ts.map +1 -1
- package/dist/lib/storage/paths.js +3 -2
- package/dist/lib/storage/paths.js.map +1 -1
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/storage.js +7 -0
- package/dist/lib/storage.js.map +1 -1
- package/dist/lib/unified-settings.d.ts.map +1 -1
- package/dist/lib/unified-settings.js +226 -28
- package/dist/lib/unified-settings.js.map +1 -1
- package/package.json +8 -3
- package/scripts/codex-bin-resolver.js +99 -0
- package/scripts/codex.js +709 -81
- package/dist/lib/codex-manager/best.d.ts +0 -26
- package/dist/lib/codex-manager/best.d.ts.map +0 -1
- package/dist/lib/codex-manager/best.js +0 -249
- package/dist/lib/codex-manager/best.js.map +0 -1
- package/dist/lib/codex-manager/config-explain.d.ts +0 -2
- package/dist/lib/codex-manager/config-explain.d.ts.map +0 -1
- package/dist/lib/codex-manager/config-explain.js +0 -62
- package/dist/lib/codex-manager/config-explain.js.map +0 -1
- package/dist/lib/codex-manager/config-template.d.ts +0 -2
- package/dist/lib/codex-manager/config-template.d.ts.map +0 -1
- package/dist/lib/codex-manager/config-template.js +0 -112
- package/dist/lib/codex-manager/config-template.js.map +0 -1
- package/dist/lib/codex-manager/debug-bundle.d.ts +0 -2
- package/dist/lib/codex-manager/debug-bundle.d.ts.map +0 -1
- package/dist/lib/codex-manager/debug-bundle.js +0 -128
- package/dist/lib/codex-manager/debug-bundle.js.map +0 -1
- package/dist/lib/codex-manager/doctor.d.ts +0 -20
- package/dist/lib/codex-manager/doctor.d.ts.map +0 -1
- package/dist/lib/codex-manager/doctor.js +0 -546
- package/dist/lib/codex-manager/doctor.js.map +0 -1
- package/dist/lib/codex-manager/fix.d.ts +0 -26
- package/dist/lib/codex-manager/fix.d.ts.map +0 -1
- package/dist/lib/codex-manager/fix.js +0 -366
- package/dist/lib/codex-manager/fix.js.map +0 -1
- package/dist/lib/codex-manager/forecast.d.ts +0 -26
- package/dist/lib/codex-manager/forecast.d.ts.map +0 -1
- package/dist/lib/codex-manager/forecast.js +0 -218
- package/dist/lib/codex-manager/forecast.js.map +0 -1
- package/dist/lib/codex-manager/info.d.ts +0 -11
- package/dist/lib/codex-manager/info.d.ts.map +0 -1
- package/dist/lib/codex-manager/info.js +0 -91
- package/dist/lib/codex-manager/info.js.map +0 -1
- package/dist/lib/codex-manager/login.d.ts +0 -40
- package/dist/lib/codex-manager/login.d.ts.map +0 -1
- package/dist/lib/codex-manager/login.js +0 -1041
- package/dist/lib/codex-manager/login.js.map +0 -1
- package/dist/lib/codex-manager/report.d.ts +0 -39
- package/dist/lib/codex-manager/report.d.ts.map +0 -1
- package/dist/lib/codex-manager/report.js +0 -243
- package/dist/lib/codex-manager/report.js.map +0 -1
- package/dist/lib/codex-manager/switch.d.ts +0 -31
- package/dist/lib/codex-manager/switch.d.ts.map +0 -1
- package/dist/lib/codex-manager/switch.js +0 -103
- package/dist/lib/codex-manager/switch.js.map +0 -1
- package/dist/lib/codex-manager/verify-flagged.d.ts +0 -20
- package/dist/lib/codex-manager/verify-flagged.d.ts.map +0 -1
- package/dist/lib/codex-manager/verify-flagged.js +0 -316
- package/dist/lib/codex-manager/verify-flagged.js.map +0 -1
- package/dist/lib/request/trace-mode.d.ts +0 -9
- package/dist/lib/request/trace-mode.d.ts.map +0 -1
- package/dist/lib/request/trace-mode.js +0 -14
- package/dist/lib/request/trace-mode.js.map +0 -1
package/scripts/codex.js
CHANGED
|
@@ -1,13 +1,70 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { spawn
|
|
4
|
-
import {
|
|
3
|
+
import { spawn } from "node:child_process";
|
|
4
|
+
import {
|
|
5
|
+
chmodSync,
|
|
6
|
+
copyFileSync,
|
|
7
|
+
existsSync,
|
|
8
|
+
mkdirSync,
|
|
9
|
+
mkdtempSync,
|
|
10
|
+
renameSync,
|
|
11
|
+
readFileSync,
|
|
12
|
+
rmSync,
|
|
13
|
+
statSync,
|
|
14
|
+
writeFileSync,
|
|
15
|
+
} from "node:fs";
|
|
5
16
|
import { createRequire } from "node:module";
|
|
17
|
+
import { homedir, tmpdir } from "node:os";
|
|
6
18
|
import { basename, delimiter, dirname, join, resolve as resolvePath } from "node:path";
|
|
7
19
|
import process from "node:process";
|
|
8
20
|
import { fileURLToPath } from "node:url";
|
|
21
|
+
import { resolveRealCodexBin as resolveRealCodexBinFromEnvironment } from "./codex-bin-resolver.js";
|
|
9
22
|
import { normalizeAuthAlias, shouldHandleMultiAuthAuth } from "./codex-routing.js";
|
|
10
23
|
|
|
24
|
+
const RETRYABLE_SHADOW_HOME_CLEANUP_CODES = new Set(["EBUSY", "EPERM", "ENOTEMPTY"]);
|
|
25
|
+
const SHADOW_HOME_CLEANUP_BACKOFF_MS = [20, 60, 120];
|
|
26
|
+
const SHADOW_HOME_STATE_FILES = ["auth.json", "accounts.json", ".codex-global-state.json"];
|
|
27
|
+
let shadowHomeCleanupBusyFailuresRemaining = Number.parseInt(
|
|
28
|
+
process.env.CODEX_MULTI_AUTH_TEST_SHADOW_CLEANUP_BUSY_FAILURES ?? "0",
|
|
29
|
+
10,
|
|
30
|
+
);
|
|
31
|
+
let shadowHomeCleanupPreflightReadBusyFailuresRemaining = Number.parseInt(
|
|
32
|
+
process.env.CODEX_MULTI_AUTH_TEST_SHADOW_PREFLIGHT_READ_BUSY_FAILURES ?? "0",
|
|
33
|
+
10,
|
|
34
|
+
);
|
|
35
|
+
const shadowHomeCleanupRetryMarkerDir =
|
|
36
|
+
(process.env.CODEX_MULTI_AUTH_TEST_SHADOW_RETRY_MARKER_DIR ?? "").trim();
|
|
37
|
+
|
|
38
|
+
function isRetryableShadowHomeCleanupError(error) {
|
|
39
|
+
const code = error && typeof error === "object" && "code" in error ? error.code : undefined;
|
|
40
|
+
return typeof code === "string" && RETRYABLE_SHADOW_HOME_CLEANUP_CODES.has(code);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function sleepSync(ms) {
|
|
44
|
+
if (!Number.isFinite(ms) || ms <= 0) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function removeDirectoryWithRetry(targetPath) {
|
|
51
|
+
for (let attempt = 0; attempt <= SHADOW_HOME_CLEANUP_BACKOFF_MS.length; attempt += 1) {
|
|
52
|
+
try {
|
|
53
|
+
maybeThrowSimulatedShadowHomeBusyError();
|
|
54
|
+
rmSync(targetPath, { recursive: true, force: true });
|
|
55
|
+
return;
|
|
56
|
+
} catch (error) {
|
|
57
|
+
if (
|
|
58
|
+
!isRetryableShadowHomeCleanupError(error) ||
|
|
59
|
+
attempt === SHADOW_HOME_CLEANUP_BACKOFF_MS.length
|
|
60
|
+
) {
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
sleepSync(SHADOW_HOME_CLEANUP_BACKOFF_MS[attempt]);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
11
68
|
function hydrateCliVersionEnv() {
|
|
12
69
|
try {
|
|
13
70
|
const require = createRequire(import.meta.url);
|
|
@@ -74,73 +131,37 @@ function resolveRealCodexBin() {
|
|
|
74
131
|
return null;
|
|
75
132
|
}
|
|
76
133
|
|
|
77
|
-
|
|
78
|
-
const require = createRequire(import.meta.url);
|
|
79
|
-
const resolved = require.resolve("@openai/codex/bin/codex.js");
|
|
80
|
-
if (existsSync(resolved)) return resolved;
|
|
81
|
-
} catch {
|
|
82
|
-
// Fall through to sibling lookup.
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const searchRoots = [];
|
|
86
|
-
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
|
87
|
-
searchRoots.push(join(scriptDir, "..", ".."));
|
|
88
|
-
|
|
89
|
-
const invokedScript = process.argv[1];
|
|
90
|
-
if (typeof invokedScript === "string" && invokedScript.length > 0) {
|
|
91
|
-
searchRoots.push(join(dirname(invokedScript), "..", ".."));
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const npmPrefix = (process.env.npm_config_prefix ?? process.env.PREFIX ?? "").trim();
|
|
95
|
-
if (npmPrefix.length > 0) {
|
|
96
|
-
searchRoots.push(join(npmPrefix, "node_modules"));
|
|
97
|
-
searchRoots.push(join(npmPrefix, "lib", "node_modules"));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
for (const root of searchRoots) {
|
|
101
|
-
const candidate = join(root, "@openai", "codex", "bin", "codex.js");
|
|
102
|
-
if (existsSync(candidate)) return candidate;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
106
|
-
try {
|
|
107
|
-
const rootResult = spawnSync(npmCmd, ["root", "-g"], {
|
|
108
|
-
encoding: "utf8",
|
|
109
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
110
|
-
});
|
|
111
|
-
if (rootResult.status === 0) {
|
|
112
|
-
const globalRoot = rootResult.stdout.trim();
|
|
113
|
-
if (globalRoot.length > 0) {
|
|
114
|
-
const globalBin = join(globalRoot, "@openai", "codex", "bin", "codex.js");
|
|
115
|
-
if (existsSync(globalBin)) return globalBin;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
} catch {
|
|
119
|
-
// Ignore and fall through to null.
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return null;
|
|
134
|
+
return resolveRealCodexBinFromEnvironment({ moduleUrl: import.meta.url });
|
|
123
135
|
}
|
|
124
136
|
|
|
125
|
-
function forwardToRealCodex(codexBin, args) {
|
|
137
|
+
function forwardToRealCodex(codexBin, args, env = process.env, cleanup) {
|
|
126
138
|
return new Promise((resolve) => {
|
|
139
|
+
const finalize = (exitCode) => {
|
|
140
|
+
try {
|
|
141
|
+
cleanup?.();
|
|
142
|
+
} catch {
|
|
143
|
+
// Best-effort cleanup only.
|
|
144
|
+
}
|
|
145
|
+
resolve(exitCode);
|
|
146
|
+
};
|
|
147
|
+
|
|
127
148
|
const child = spawn(process.execPath, [codexBin, ...args], {
|
|
128
149
|
stdio: "inherit",
|
|
129
|
-
env
|
|
150
|
+
env,
|
|
130
151
|
});
|
|
131
152
|
|
|
132
153
|
child.once("error", (error) => {
|
|
133
154
|
console.error(`Failed to launch real Codex CLI: ${String(error)}`);
|
|
134
|
-
|
|
155
|
+
finalize(1);
|
|
135
156
|
});
|
|
136
157
|
|
|
137
158
|
child.once("exit", (code, signal) => {
|
|
138
159
|
if (signal) {
|
|
139
160
|
const signalNumber = signal === "SIGINT" ? 130 : 1;
|
|
140
|
-
|
|
161
|
+
finalize(signalNumber);
|
|
141
162
|
return;
|
|
142
163
|
}
|
|
143
|
-
|
|
164
|
+
finalize(typeof code === "number" ? code : 1);
|
|
144
165
|
});
|
|
145
166
|
});
|
|
146
167
|
}
|
|
@@ -168,16 +189,604 @@ function hasCliAuthCredentialsStoreOverride(args) {
|
|
|
168
189
|
return false;
|
|
169
190
|
}
|
|
170
191
|
|
|
192
|
+
// IMPORTANT: Keep this mapping in sync with
|
|
193
|
+
// `lib/request/helpers/model-map.ts` `MODEL_PROFILES`.
|
|
194
|
+
// This wrapper runs before the TypeScript build, so it cannot import that source.
|
|
195
|
+
const SUPPORTED_REASONING_EFFORTS_BY_MODEL = {
|
|
196
|
+
"gpt-5-codex": ["low", "medium", "high", "xhigh"],
|
|
197
|
+
"gpt-5.1-codex-max": ["medium", "high", "xhigh"],
|
|
198
|
+
"gpt-5.1-codex-mini": ["medium", "high"],
|
|
199
|
+
"gpt-5.4": ["none", "low", "medium", "high", "xhigh"],
|
|
200
|
+
"gpt-5.4-pro": ["medium", "high", "xhigh"],
|
|
201
|
+
"gpt-5.2-pro": ["medium", "high", "xhigh"],
|
|
202
|
+
"gpt-5-pro": ["high"],
|
|
203
|
+
"gpt-5.2": ["none", "low", "medium", "high", "xhigh"],
|
|
204
|
+
"gpt-5.1": ["none", "low", "medium", "high"],
|
|
205
|
+
"gpt-5": ["minimal", "low", "medium", "high"],
|
|
206
|
+
"gpt-5-mini": ["medium"],
|
|
207
|
+
"gpt-5-nano": ["medium"],
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const REASONING_FALLBACKS = {
|
|
211
|
+
none: ["none", "low", "minimal", "medium", "high", "xhigh"],
|
|
212
|
+
minimal: ["minimal", "low", "none", "medium", "high", "xhigh"],
|
|
213
|
+
low: ["low", "minimal", "none", "medium", "high", "xhigh"],
|
|
214
|
+
medium: ["medium", "low", "high", "minimal", "none", "xhigh"],
|
|
215
|
+
high: ["high", "medium", "xhigh", "low", "minimal", "none"],
|
|
216
|
+
xhigh: ["xhigh", "high", "medium", "low", "minimal", "none"],
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const KNOWN_REASONING_EFFORTS = new Set(Object.keys(REASONING_FALLBACKS));
|
|
220
|
+
const REQUESTED_MODEL_ALIASES = new Map();
|
|
221
|
+
|
|
222
|
+
function addRequestedModelAlias(alias, normalizedModel) {
|
|
223
|
+
REQUESTED_MODEL_ALIASES.set(alias, normalizedModel);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function addRequestedModelReasoningAliases(alias, normalizedModel) {
|
|
227
|
+
addRequestedModelAlias(alias, normalizedModel);
|
|
228
|
+
for (const effort of KNOWN_REASONING_EFFORTS) {
|
|
229
|
+
addRequestedModelAlias(`${alias}-${effort}`, normalizedModel);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function maybeThrowSimulatedShadowHomeBusyError() {
|
|
234
|
+
if (shadowHomeCleanupBusyFailuresRemaining > 0) {
|
|
235
|
+
shadowHomeCleanupBusyFailuresRemaining -= 1;
|
|
236
|
+
const error = new Error("simulated busy shadow-home operation");
|
|
237
|
+
error.code = "EBUSY";
|
|
238
|
+
throw error;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function maybeThrowSimulatedShadowHomePreflightReadBusyError() {
|
|
243
|
+
if (shadowHomeCleanupPreflightReadBusyFailuresRemaining > 0) {
|
|
244
|
+
shadowHomeCleanupPreflightReadBusyFailuresRemaining -= 1;
|
|
245
|
+
const error = new Error("simulated busy shadow-home preflight read");
|
|
246
|
+
error.code = "EBUSY";
|
|
247
|
+
throw error;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function writeShadowHomeCleanupRetryMarker(destinationPath, attempt) {
|
|
252
|
+
if (shadowHomeCleanupRetryMarkerDir.length === 0) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
try {
|
|
256
|
+
mkdirSync(shadowHomeCleanupRetryMarkerDir, { recursive: true });
|
|
257
|
+
writeFileSync(
|
|
258
|
+
join(
|
|
259
|
+
shadowHomeCleanupRetryMarkerDir,
|
|
260
|
+
`${basename(destinationPath)}.retry-${attempt + 1}`,
|
|
261
|
+
),
|
|
262
|
+
`${attempt + 1}\n`,
|
|
263
|
+
"utf8",
|
|
264
|
+
);
|
|
265
|
+
} catch {
|
|
266
|
+
// Best-effort test hook only.
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function ensureShadowHomeDestinationMatchesSnapshot(destinationPath, expectedState) {
|
|
271
|
+
if (!expectedState) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const currentState = captureShadowHomeState(destinationPath, {
|
|
275
|
+
rethrowRetryableReadErrors: true,
|
|
276
|
+
});
|
|
277
|
+
if (!shadowHomeStateMatches(currentState, expectedState)) {
|
|
278
|
+
const error = new Error("shadow-home destination changed during sync-back retry");
|
|
279
|
+
error.code = "EEXIST";
|
|
280
|
+
throw error;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function renameFileWithRetry(sourcePath, destinationPath, expectedDestinationState) {
|
|
285
|
+
for (let attempt = 0; attempt <= SHADOW_HOME_CLEANUP_BACKOFF_MS.length; attempt += 1) {
|
|
286
|
+
try {
|
|
287
|
+
ensureShadowHomeDestinationMatchesSnapshot(
|
|
288
|
+
destinationPath,
|
|
289
|
+
expectedDestinationState,
|
|
290
|
+
);
|
|
291
|
+
maybeThrowSimulatedShadowHomeBusyError();
|
|
292
|
+
renameSync(sourcePath, destinationPath);
|
|
293
|
+
return;
|
|
294
|
+
} catch (error) {
|
|
295
|
+
if (
|
|
296
|
+
!isRetryableShadowHomeCleanupError(error) ||
|
|
297
|
+
attempt === SHADOW_HOME_CLEANUP_BACKOFF_MS.length
|
|
298
|
+
) {
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
301
|
+
writeShadowHomeCleanupRetryMarker(destinationPath, attempt);
|
|
302
|
+
sleepSync(SHADOW_HOME_CLEANUP_BACKOFF_MS[attempt]);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function seedRequestedModelAliases() {
|
|
308
|
+
addRequestedModelReasoningAliases("gpt-5.4", "gpt-5.4");
|
|
309
|
+
addRequestedModelReasoningAliases("gpt-5.4-pro", "gpt-5.4-pro");
|
|
310
|
+
addRequestedModelReasoningAliases("gpt-5.2-pro", "gpt-5.2-pro");
|
|
311
|
+
addRequestedModelReasoningAliases("gpt-5-pro", "gpt-5-pro");
|
|
312
|
+
addRequestedModelReasoningAliases("gpt-5.2", "gpt-5.2");
|
|
313
|
+
addRequestedModelReasoningAliases("gpt-5.1", "gpt-5.1");
|
|
314
|
+
addRequestedModelReasoningAliases("gpt-5", "gpt-5");
|
|
315
|
+
addRequestedModelReasoningAliases("gpt-5-mini", "gpt-5-mini");
|
|
316
|
+
addRequestedModelReasoningAliases("gpt-5-nano", "gpt-5-nano");
|
|
317
|
+
addRequestedModelReasoningAliases("gpt-5.1-chat-latest", "gpt-5.1");
|
|
318
|
+
addRequestedModelReasoningAliases("gpt-5-chat-latest", "gpt-5");
|
|
319
|
+
addRequestedModelReasoningAliases("gpt-5.4-mini", "gpt-5-mini");
|
|
320
|
+
addRequestedModelReasoningAliases("gpt-5.4-nano", "gpt-5-nano");
|
|
321
|
+
addRequestedModelReasoningAliases("gpt-5-codex", "gpt-5-codex");
|
|
322
|
+
addRequestedModelReasoningAliases("gpt-5.3-codex-spark", "gpt-5-codex");
|
|
323
|
+
addRequestedModelReasoningAliases("gpt-5.3-codex", "gpt-5-codex");
|
|
324
|
+
addRequestedModelReasoningAliases("gpt-5.2-codex", "gpt-5-codex");
|
|
325
|
+
addRequestedModelReasoningAliases("gpt-5.1-codex", "gpt-5-codex");
|
|
326
|
+
addRequestedModelAlias("gpt_5_codex", "gpt-5-codex");
|
|
327
|
+
addRequestedModelReasoningAliases("codex-max", "gpt-5.1-codex-max");
|
|
328
|
+
addRequestedModelReasoningAliases("gpt-5.1-codex-max", "gpt-5.1-codex-max");
|
|
329
|
+
addRequestedModelAlias("codex-mini-latest", "gpt-5.1-codex-mini");
|
|
330
|
+
addRequestedModelReasoningAliases("gpt-5-codex-mini", "gpt-5.1-codex-mini");
|
|
331
|
+
addRequestedModelReasoningAliases("gpt-5.1-codex-mini", "gpt-5.1-codex-mini");
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
seedRequestedModelAliases();
|
|
335
|
+
|
|
336
|
+
function stripProviderPrefix(model) {
|
|
337
|
+
return typeof model === "string" && model.includes("/")
|
|
338
|
+
? model.split("/").pop() ?? model
|
|
339
|
+
: model;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function normalizeRequestedModel(model) {
|
|
343
|
+
const stripped = stripProviderPrefix(model ?? "");
|
|
344
|
+
const normalized = stripped.trim().toLowerCase();
|
|
345
|
+
if (normalized.length === 0) return "";
|
|
346
|
+
const exactMatch = REQUESTED_MODEL_ALIASES.get(normalized);
|
|
347
|
+
if (exactMatch) {
|
|
348
|
+
return exactMatch;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (
|
|
352
|
+
normalized.includes("gpt-5.1-codex-max") ||
|
|
353
|
+
normalized.includes("gpt 5.1 codex max") ||
|
|
354
|
+
normalized.includes("codex-max")
|
|
355
|
+
) {
|
|
356
|
+
return "gpt-5.1-codex-max";
|
|
357
|
+
}
|
|
358
|
+
if (
|
|
359
|
+
normalized.includes("gpt-5.1-codex-mini") ||
|
|
360
|
+
normalized.includes("gpt 5.1 codex mini") ||
|
|
361
|
+
normalized.includes("gpt-5-codex-mini") ||
|
|
362
|
+
normalized.includes("gpt 5 codex mini") ||
|
|
363
|
+
normalized.includes("codex-mini-latest")
|
|
364
|
+
) {
|
|
365
|
+
return "gpt-5.1-codex-mini";
|
|
366
|
+
}
|
|
367
|
+
if (
|
|
368
|
+
normalized.includes("gpt-5.3-codex-spark") ||
|
|
369
|
+
normalized.includes("gpt 5.3 codex spark") ||
|
|
370
|
+
normalized.includes("gpt-5.3-codex") ||
|
|
371
|
+
normalized.includes("gpt 5.3 codex") ||
|
|
372
|
+
normalized.includes("gpt-5.2-codex") ||
|
|
373
|
+
normalized.includes("gpt 5.2 codex") ||
|
|
374
|
+
normalized.includes("gpt-5.1-codex") ||
|
|
375
|
+
normalized.includes("gpt 5.1 codex") ||
|
|
376
|
+
normalized.includes("gpt-5-codex") ||
|
|
377
|
+
normalized.includes("gpt 5 codex") ||
|
|
378
|
+
normalized === "codex"
|
|
379
|
+
) {
|
|
380
|
+
return "gpt-5-codex";
|
|
381
|
+
}
|
|
382
|
+
if (normalized.includes("gpt-5.4-pro") || normalized.includes("gpt 5.4 pro")) {
|
|
383
|
+
return "gpt-5.4-pro";
|
|
384
|
+
}
|
|
385
|
+
if (normalized.includes("gpt-5.2-pro") || normalized.includes("gpt 5.2 pro")) {
|
|
386
|
+
return "gpt-5.2-pro";
|
|
387
|
+
}
|
|
388
|
+
if (normalized.includes("gpt-5-pro") || normalized.includes("gpt 5 pro")) {
|
|
389
|
+
return "gpt-5-pro";
|
|
390
|
+
}
|
|
391
|
+
if (
|
|
392
|
+
normalized.includes("gpt-5.4-mini") ||
|
|
393
|
+
normalized.includes("gpt 5.4 mini") ||
|
|
394
|
+
normalized.includes("gpt-5-mini") ||
|
|
395
|
+
normalized.includes("gpt 5 mini")
|
|
396
|
+
) {
|
|
397
|
+
return "gpt-5-mini";
|
|
398
|
+
}
|
|
399
|
+
if (
|
|
400
|
+
normalized.includes("gpt-5.4-nano") ||
|
|
401
|
+
normalized.includes("gpt 5.4 nano") ||
|
|
402
|
+
normalized.includes("gpt-5-nano") ||
|
|
403
|
+
normalized.includes("gpt 5 nano")
|
|
404
|
+
) {
|
|
405
|
+
return "gpt-5-nano";
|
|
406
|
+
}
|
|
407
|
+
if (normalized.includes("gpt-5.4") || normalized.includes("gpt 5.4")) {
|
|
408
|
+
return "gpt-5.4";
|
|
409
|
+
}
|
|
410
|
+
if (normalized.includes("gpt-5.2") || normalized.includes("gpt 5.2")) {
|
|
411
|
+
return "gpt-5.2";
|
|
412
|
+
}
|
|
413
|
+
if (
|
|
414
|
+
normalized.includes("gpt-5.1-chat-latest") ||
|
|
415
|
+
normalized.includes("gpt-5.1") ||
|
|
416
|
+
normalized.includes("gpt 5.1")
|
|
417
|
+
) {
|
|
418
|
+
return "gpt-5.1";
|
|
419
|
+
}
|
|
420
|
+
if (
|
|
421
|
+
normalized === "gpt-5-chat-latest" ||
|
|
422
|
+
normalized === "gpt-5" ||
|
|
423
|
+
normalized.includes("gpt 5")
|
|
424
|
+
) {
|
|
425
|
+
return "gpt-5";
|
|
426
|
+
}
|
|
427
|
+
return "";
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function coerceReasoningEffortForModel(model, effort) {
|
|
431
|
+
if (typeof effort !== "string") return effort;
|
|
432
|
+
const normalizedEffort = effort.trim().toLowerCase();
|
|
433
|
+
if (!KNOWN_REASONING_EFFORTS.has(normalizedEffort)) {
|
|
434
|
+
return effort;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
const normalizedModel = normalizeRequestedModel(model);
|
|
438
|
+
const supportedEfforts =
|
|
439
|
+
SUPPORTED_REASONING_EFFORTS_BY_MODEL[normalizedModel] ?? null;
|
|
440
|
+
if (!supportedEfforts || supportedEfforts.includes(normalizedEffort)) {
|
|
441
|
+
return normalizedEffort;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
const fallbackOrder = REASONING_FALLBACKS[normalizedEffort] ?? [normalizedEffort];
|
|
445
|
+
for (const candidate of fallbackOrder) {
|
|
446
|
+
if (supportedEfforts.includes(candidate)) {
|
|
447
|
+
return candidate;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return normalizedEffort;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
function extractRequestedModel(args) {
|
|
455
|
+
for (let i = 0; i < args.length; i += 1) {
|
|
456
|
+
const arg = args[i];
|
|
457
|
+
if (arg === "--model") {
|
|
458
|
+
const next = args[i + 1];
|
|
459
|
+
if (typeof next === "string" && next.trim().length > 0) {
|
|
460
|
+
return next.trim();
|
|
461
|
+
}
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
if (typeof arg === "string" && arg.startsWith("--model=")) {
|
|
465
|
+
const value = arg.slice("--model=".length).trim();
|
|
466
|
+
if (value.length > 0) {
|
|
467
|
+
return value;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return null;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function parseConfigAssignment(value) {
|
|
475
|
+
if (typeof value !== "string") return null;
|
|
476
|
+
const separatorIndex = value.indexOf("=");
|
|
477
|
+
if (separatorIndex < 0) return null;
|
|
478
|
+
return {
|
|
479
|
+
key: value.slice(0, separatorIndex).trim(),
|
|
480
|
+
value: value.slice(separatorIndex + 1).trim(),
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
function parseQuotedValue(value) {
|
|
485
|
+
if (typeof value !== "string") {
|
|
486
|
+
return { quote: '"', inner: "" };
|
|
487
|
+
}
|
|
488
|
+
const trimmed = value.trim();
|
|
489
|
+
const first = trimmed[0];
|
|
490
|
+
const last = trimmed.at(-1);
|
|
491
|
+
if ((first === '"' || first === "'") && last === first) {
|
|
492
|
+
return {
|
|
493
|
+
quote: first,
|
|
494
|
+
inner: trimmed.slice(1, -1),
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
return { quote: '"', inner: trimmed };
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function rewriteReasoningConfigAssignment(assignment, requestedModel) {
|
|
501
|
+
const parsed = parseConfigAssignment(assignment);
|
|
502
|
+
if (!parsed || parsed.key !== "model_reasoning_effort") {
|
|
503
|
+
return assignment;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const { quote, inner } = parseQuotedValue(parsed.value);
|
|
507
|
+
const coercedEffort = coerceReasoningEffortForModel(requestedModel, inner);
|
|
508
|
+
if (coercedEffort === inner) {
|
|
509
|
+
return assignment;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
return `${parsed.key}=${quote}${coercedEffort}${quote}`;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
function rewriteReasoningConfigArgs(rawArgs) {
|
|
516
|
+
const requestedModel = extractRequestedModel(rawArgs);
|
|
517
|
+
if (!requestedModel) {
|
|
518
|
+
return {
|
|
519
|
+
args: [...rawArgs],
|
|
520
|
+
requestedModel: null,
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
const nextArgs = [...rawArgs];
|
|
525
|
+
for (let i = 0; i < nextArgs.length; i += 1) {
|
|
526
|
+
const arg = nextArgs[i];
|
|
527
|
+
if ((arg === "-c" || arg === "--config") && typeof nextArgs[i + 1] === "string") {
|
|
528
|
+
nextArgs[i + 1] = rewriteReasoningConfigAssignment(
|
|
529
|
+
nextArgs[i + 1],
|
|
530
|
+
requestedModel,
|
|
531
|
+
);
|
|
532
|
+
i += 1;
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
if (typeof arg === "string" && arg.startsWith("--config=")) {
|
|
536
|
+
const assignment = arg.slice("--config=".length);
|
|
537
|
+
nextArgs[i] = `--config=${rewriteReasoningConfigAssignment(
|
|
538
|
+
assignment,
|
|
539
|
+
requestedModel,
|
|
540
|
+
)}`;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
return {
|
|
545
|
+
args: nextArgs,
|
|
546
|
+
requestedModel,
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function resolveCodexHomeDir(env = process.env) {
|
|
551
|
+
const override = (env.CODEX_HOME ?? "").trim();
|
|
552
|
+
if (override.length > 0) return override;
|
|
553
|
+
if (process.platform === "win32") {
|
|
554
|
+
const homeDir = resolveWindowsUserHomeDir();
|
|
555
|
+
if (homeDir) {
|
|
556
|
+
return join(homeDir, ".codex");
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return join(env.HOME ?? homedir(), ".codex");
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
function ensureTrailingNewline(value) {
|
|
563
|
+
return value.endsWith("\n") ? value : `${value}\n`;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
function captureShadowHomeState(filePath, options = {}) {
|
|
567
|
+
try {
|
|
568
|
+
if (!existsSync(filePath)) {
|
|
569
|
+
return { exists: false, content: null };
|
|
570
|
+
}
|
|
571
|
+
if (options.rethrowRetryableReadErrors) {
|
|
572
|
+
maybeThrowSimulatedShadowHomePreflightReadBusyError();
|
|
573
|
+
}
|
|
574
|
+
return {
|
|
575
|
+
exists: true,
|
|
576
|
+
content: readFileSync(filePath, "utf8"),
|
|
577
|
+
};
|
|
578
|
+
} catch (error) {
|
|
579
|
+
if (options.rethrowRetryableReadErrors && isRetryableShadowHomeCleanupError(error)) {
|
|
580
|
+
throw error;
|
|
581
|
+
}
|
|
582
|
+
return { exists: true, content: null, unreadable: true };
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
function shadowHomeStateMatches(left, right) {
|
|
587
|
+
return (
|
|
588
|
+
left.exists === right.exists &&
|
|
589
|
+
left.content === right.content &&
|
|
590
|
+
Boolean(left.unreadable) === Boolean(right.unreadable)
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
function syncShadowHomeStateFile(
|
|
595
|
+
sourcePath,
|
|
596
|
+
destinationPath,
|
|
597
|
+
expectedDestinationState,
|
|
598
|
+
) {
|
|
599
|
+
const tempPath = join(
|
|
600
|
+
dirname(destinationPath),
|
|
601
|
+
`.${basename(destinationPath)}.codex-multi-auth-sync-${process.pid}.tmp`,
|
|
602
|
+
);
|
|
603
|
+
try {
|
|
604
|
+
mkdirSync(dirname(destinationPath), { recursive: true });
|
|
605
|
+
copyFileSync(sourcePath, tempPath);
|
|
606
|
+
renameFileWithRetry(tempPath, destinationPath, expectedDestinationState);
|
|
607
|
+
} catch (error) {
|
|
608
|
+
try {
|
|
609
|
+
rmSync(tempPath, { force: true });
|
|
610
|
+
} catch {
|
|
611
|
+
// Best-effort cleanup only.
|
|
612
|
+
}
|
|
613
|
+
throw error;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
function rewriteConfigTomlReasoningEffort(rawConfig, requestedModel) {
|
|
618
|
+
const lineEnding = rawConfig.includes("\r\n") ? "\r\n" : "\n";
|
|
619
|
+
let changed = false;
|
|
620
|
+
const nextLines = rawConfig.split(/\r?\n/).map((line) => {
|
|
621
|
+
const quotedMatch = line.match(
|
|
622
|
+
/^(\s*model_reasoning_effort\s*=\s*)(["'])([^"']+)(\2.*)$/,
|
|
623
|
+
);
|
|
624
|
+
const bareMatch = quotedMatch
|
|
625
|
+
? null
|
|
626
|
+
: line.match(
|
|
627
|
+
/^(\s*model_reasoning_effort\s*=\s*)([^\s#]+)(\s*(?:#.*)?)$/,
|
|
628
|
+
);
|
|
629
|
+
if (!quotedMatch && !bareMatch) return line;
|
|
630
|
+
|
|
631
|
+
const prefix = quotedMatch?.[1] ?? bareMatch?.[1] ?? "";
|
|
632
|
+
const openingQuote = quotedMatch?.[2] ?? "";
|
|
633
|
+
const currentEffort = quotedMatch?.[3] ?? bareMatch?.[2] ?? "";
|
|
634
|
+
const suffix = quotedMatch?.[4] ?? bareMatch?.[3] ?? "";
|
|
635
|
+
const coercedEffort = coerceReasoningEffortForModel(
|
|
636
|
+
requestedModel,
|
|
637
|
+
currentEffort,
|
|
638
|
+
);
|
|
639
|
+
if (coercedEffort === currentEffort) {
|
|
640
|
+
return line;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
changed = true;
|
|
644
|
+
return quotedMatch
|
|
645
|
+
? `${prefix}${openingQuote}${coercedEffort}${suffix}`
|
|
646
|
+
: `${prefix}${coercedEffort}${suffix}`;
|
|
647
|
+
});
|
|
648
|
+
|
|
649
|
+
if (!changed) {
|
|
650
|
+
return rawConfig;
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
return ensureTrailingNewline(nextLines.join(lineEnding));
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function resolveOriginalMultiAuthDir(env) {
|
|
657
|
+
const explicit = (env.CODEX_MULTI_AUTH_DIR ?? "").trim();
|
|
658
|
+
if (explicit.length > 0) {
|
|
659
|
+
return explicit;
|
|
660
|
+
}
|
|
661
|
+
return undefined;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function createCompatibilityCodexHome(
|
|
665
|
+
processedArgs,
|
|
666
|
+
requestedModel,
|
|
667
|
+
baseEnv = process.env,
|
|
668
|
+
) {
|
|
669
|
+
if (!requestedModel) {
|
|
670
|
+
return { args: processedArgs, env: baseEnv, cleanup: undefined };
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
const originalCodexHome = resolveCodexHomeDir(baseEnv);
|
|
674
|
+
const configPath = join(originalCodexHome, "config.toml");
|
|
675
|
+
if (!existsSync(configPath)) {
|
|
676
|
+
return { args: processedArgs, env: baseEnv, cleanup: undefined };
|
|
677
|
+
}
|
|
678
|
+
const originalShadowHomeState = new Map(
|
|
679
|
+
SHADOW_HOME_STATE_FILES.map((name) => [
|
|
680
|
+
name,
|
|
681
|
+
captureShadowHomeState(join(originalCodexHome, name)),
|
|
682
|
+
]),
|
|
683
|
+
);
|
|
684
|
+
|
|
685
|
+
const rawConfig = readFileSync(configPath, "utf8");
|
|
686
|
+
const compatConfig = rewriteConfigTomlReasoningEffort(
|
|
687
|
+
rawConfig,
|
|
688
|
+
requestedModel,
|
|
689
|
+
);
|
|
690
|
+
if (compatConfig === rawConfig) {
|
|
691
|
+
return { args: processedArgs, env: baseEnv, cleanup: undefined };
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
const shadowCodexHome = mkdtempSync(join(tmpdir(), "codex-multi-auth-home-"));
|
|
695
|
+
const cleanup = () => {
|
|
696
|
+
try {
|
|
697
|
+
removeDirectoryWithRetry(shadowCodexHome);
|
|
698
|
+
} catch {
|
|
699
|
+
// Best-effort cleanup only.
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
const tightenShadowHomePermissions = (path) => {
|
|
703
|
+
try {
|
|
704
|
+
chmodSync(path, 0o600);
|
|
705
|
+
} catch {
|
|
706
|
+
// Best-effort only; permission semantics vary by platform.
|
|
707
|
+
}
|
|
708
|
+
};
|
|
709
|
+
const syncShadowHomeStateBack = () => {
|
|
710
|
+
for (const name of SHADOW_HOME_STATE_FILES) {
|
|
711
|
+
const shadowPath = join(shadowCodexHome, name);
|
|
712
|
+
const shadowState = captureShadowHomeState(shadowPath);
|
|
713
|
+
if (!shadowState.exists || shadowState.unreadable) {
|
|
714
|
+
continue;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
try {
|
|
718
|
+
const originalPath = join(originalCodexHome, name);
|
|
719
|
+
const originalSnapshot =
|
|
720
|
+
originalShadowHomeState.get(name) ?? { exists: false, content: null };
|
|
721
|
+
const currentOriginalState = captureShadowHomeState(originalPath);
|
|
722
|
+
if (!shadowHomeStateMatches(currentOriginalState, originalSnapshot)) {
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
if (shadowHomeStateMatches(shadowState, originalSnapshot)) {
|
|
726
|
+
continue;
|
|
727
|
+
}
|
|
728
|
+
syncShadowHomeStateFile(shadowPath, originalPath, originalSnapshot);
|
|
729
|
+
tightenShadowHomePermissions(originalPath);
|
|
730
|
+
} catch {
|
|
731
|
+
// Best-effort only; runtime auth refreshes should not fail cleanup.
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
try {
|
|
736
|
+
const compatConfigPath = join(shadowCodexHome, "config.toml");
|
|
737
|
+
writeFileSync(compatConfigPath, compatConfig, "utf8");
|
|
738
|
+
tightenShadowHomePermissions(compatConfigPath);
|
|
739
|
+
for (const name of SHADOW_HOME_STATE_FILES) {
|
|
740
|
+
const sourcePath = join(originalCodexHome, name);
|
|
741
|
+
if (existsSync(sourcePath)) {
|
|
742
|
+
const destinationPath = join(shadowCodexHome, name);
|
|
743
|
+
copyFileSync(sourcePath, destinationPath);
|
|
744
|
+
tightenShadowHomePermissions(destinationPath);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
} catch (error) {
|
|
748
|
+
cleanup();
|
|
749
|
+
throw error;
|
|
750
|
+
}
|
|
751
|
+
const cleanupWithSync = () => {
|
|
752
|
+
syncShadowHomeStateBack();
|
|
753
|
+
cleanup();
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
const forwardedEnv = {
|
|
757
|
+
...baseEnv,
|
|
758
|
+
CODEX_HOME: shadowCodexHome,
|
|
759
|
+
};
|
|
760
|
+
const originalMultiAuthDir = resolveOriginalMultiAuthDir(baseEnv);
|
|
761
|
+
if (originalMultiAuthDir) {
|
|
762
|
+
forwardedEnv.CODEX_MULTI_AUTH_DIR = originalMultiAuthDir;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
return {
|
|
766
|
+
args: processedArgs,
|
|
767
|
+
env: forwardedEnv,
|
|
768
|
+
cleanup: cleanupWithSync,
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
|
|
171
772
|
function buildForwardArgs(rawArgs) {
|
|
773
|
+
const { args: compatibilityArgs, requestedModel } = rewriteReasoningConfigArgs(rawArgs);
|
|
172
774
|
const forceFileAuthStore = (process.env.CODEX_MULTI_AUTH_FORCE_FILE_AUTH_STORE ?? "1").trim() !== "0";
|
|
173
|
-
if (!forceFileAuthStore)
|
|
174
|
-
|
|
775
|
+
if (!forceFileAuthStore) {
|
|
776
|
+
return { args: compatibilityArgs, requestedModel };
|
|
777
|
+
}
|
|
778
|
+
if (hasCliAuthCredentialsStoreOverride(compatibilityArgs)) {
|
|
779
|
+
return { args: compatibilityArgs, requestedModel };
|
|
780
|
+
}
|
|
175
781
|
|
|
176
|
-
return
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
782
|
+
return {
|
|
783
|
+
args: [
|
|
784
|
+
...compatibilityArgs,
|
|
785
|
+
"-c",
|
|
786
|
+
'cli_auth_credentials_store="file"',
|
|
787
|
+
],
|
|
788
|
+
requestedModel,
|
|
789
|
+
};
|
|
181
790
|
}
|
|
182
791
|
|
|
183
792
|
function normalizeExitCode(value) {
|
|
@@ -197,7 +806,7 @@ const POWERSHELL_PROFILE_MARKER_END = "# <<< codex-multi-auth shell guard <<<";
|
|
|
197
806
|
|
|
198
807
|
function shouldInstallWindowsBatchShimGuard() {
|
|
199
808
|
if (process.platform !== "win32") return false;
|
|
200
|
-
const override = (process.env.CODEX_MULTI_AUTH_WINDOWS_BATCH_SHIM_GUARD ?? "
|
|
809
|
+
const override = (process.env.CODEX_MULTI_AUTH_WINDOWS_BATCH_SHIM_GUARD ?? "0").trim();
|
|
201
810
|
return override !== "0";
|
|
202
811
|
}
|
|
203
812
|
|
|
@@ -370,7 +979,7 @@ function ensureWindowsShellShim(filePath, desiredContent, options = {}) {
|
|
|
370
979
|
|
|
371
980
|
function shouldInstallPowerShellProfileGuard() {
|
|
372
981
|
if (process.platform !== "win32") return false;
|
|
373
|
-
const override = (process.env.CODEX_MULTI_AUTH_PWSH_PROFILE_GUARD ?? "
|
|
982
|
+
const override = (process.env.CODEX_MULTI_AUTH_PWSH_PROFILE_GUARD ?? "0").trim();
|
|
374
983
|
return override !== "0";
|
|
375
984
|
}
|
|
376
985
|
|
|
@@ -455,7 +1064,9 @@ function ensurePowerShellProfileGuard(shimDirectory) {
|
|
|
455
1064
|
}
|
|
456
1065
|
|
|
457
1066
|
function ensureWindowsShellShimGuards() {
|
|
458
|
-
|
|
1067
|
+
const shouldInstallBatchGuard = shouldInstallWindowsBatchShimGuard();
|
|
1068
|
+
const shouldInstallProfileGuard = shouldInstallPowerShellProfileGuard();
|
|
1069
|
+
if (!shouldInstallBatchGuard && !shouldInstallProfileGuard) return;
|
|
459
1070
|
const shimDirectory = resolveWindowsShimDirectoryFromPath();
|
|
460
1071
|
if (!shimDirectory) return;
|
|
461
1072
|
|
|
@@ -464,23 +1075,31 @@ function ensureWindowsShellShimGuards() {
|
|
|
464
1075
|
|
|
465
1076
|
const overwriteCustomShim =
|
|
466
1077
|
(process.env.CODEX_MULTI_AUTH_OVERWRITE_CUSTOM_BATCH_SHIM ?? "0").trim() === "1";
|
|
467
|
-
const installedBatch =
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
1078
|
+
const installedBatch = shouldInstallBatchGuard
|
|
1079
|
+
? ensureWindowsShellShim(
|
|
1080
|
+
join(shimDirectory, "codex.bat"),
|
|
1081
|
+
buildWindowsBatchShimContent(),
|
|
1082
|
+
{ overwriteCustomShim },
|
|
1083
|
+
)
|
|
1084
|
+
: false;
|
|
1085
|
+
const installedCmd = shouldInstallBatchGuard
|
|
1086
|
+
? ensureWindowsShellShim(
|
|
1087
|
+
join(shimDirectory, "codex.cmd"),
|
|
1088
|
+
buildWindowsCmdShimContent(),
|
|
1089
|
+
{ overwriteCustomShim },
|
|
1090
|
+
)
|
|
1091
|
+
: false;
|
|
1092
|
+
const installedPs1 = shouldInstallBatchGuard
|
|
1093
|
+
? ensureWindowsShellShim(
|
|
1094
|
+
join(shimDirectory, "codex.ps1"),
|
|
1095
|
+
buildWindowsPowerShellShimContent(),
|
|
1096
|
+
{ overwriteCustomShim },
|
|
1097
|
+
)
|
|
1098
|
+
: false;
|
|
482
1099
|
const installedAny = installedBatch || installedCmd || installedPs1;
|
|
483
|
-
const installedProfileGuard =
|
|
1100
|
+
const installedProfileGuard = shouldInstallProfileGuard
|
|
1101
|
+
? ensurePowerShellProfileGuard(shimDirectory)
|
|
1102
|
+
: false;
|
|
484
1103
|
if (installedAny || installedProfileGuard) {
|
|
485
1104
|
console.error(
|
|
486
1105
|
"codex-multi-auth: installed Windows shell guards to keep multi-auth routing after codex npm updates.",
|
|
@@ -525,8 +1144,17 @@ async function main() {
|
|
|
525
1144
|
}
|
|
526
1145
|
|
|
527
1146
|
await autoSyncManagerActiveSelectionIfEnabled();
|
|
528
|
-
const forwardArgs = buildForwardArgs(rawArgs);
|
|
529
|
-
|
|
1147
|
+
const { args: forwardArgs, requestedModel } = buildForwardArgs(rawArgs);
|
|
1148
|
+
const compatibility = createCompatibilityCodexHome(
|
|
1149
|
+
forwardArgs,
|
|
1150
|
+
requestedModel,
|
|
1151
|
+
);
|
|
1152
|
+
return forwardToRealCodex(
|
|
1153
|
+
realCodexBin,
|
|
1154
|
+
compatibility.args,
|
|
1155
|
+
compatibility.env,
|
|
1156
|
+
compatibility.cleanup,
|
|
1157
|
+
);
|
|
530
1158
|
}
|
|
531
1159
|
|
|
532
1160
|
const exitCode = await main();
|