codex-multi-auth 2.1.3 → 2.1.5
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 +8 -6
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -1
- package/dist/lib/request/fetch-helpers.js +13 -5
- package/dist/lib/request/fetch-helpers.js.map +1 -1
- package/dist/lib/runtime/config-toml.d.ts +2 -0
- package/dist/lib/runtime/config-toml.d.ts.map +1 -1
- package/dist/lib/runtime/config-toml.js +57 -4
- package/dist/lib/runtime/config-toml.js.map +1 -1
- package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
- package/dist/lib/runtime-rotation-proxy.js +242 -16
- package/dist/lib/runtime-rotation-proxy.js.map +1 -1
- package/dist/lib/update-notice.d.ts +12 -0
- package/dist/lib/update-notice.d.ts.map +1 -0
- package/dist/lib/update-notice.js +315 -0
- package/dist/lib/update-notice.js.map +1 -0
- package/dist/lib/usage/ledger.d.ts.map +1 -1
- package/dist/lib/usage/ledger.js +1 -0
- package/dist/lib/usage/ledger.js.map +1 -1
- package/dist/lib/usage/redaction.d.ts.map +1 -1
- package/dist/lib/usage/redaction.js +1 -0
- package/dist/lib/usage/redaction.js.map +1 -1
- package/dist/lib/usage/types.d.ts +1 -1
- package/dist/lib/usage/types.d.ts.map +1 -1
- package/package.json +4 -4
- package/scripts/codex-app-launcher.js +1 -1
- package/scripts/codex-multi-auth.js +5 -1
- package/scripts/codex-routing.js +8 -0
- package/scripts/codex.js +309 -59
- package/scripts/test-model-matrix.js +97 -13
- package/dist/lib/auto-update-checker.d.ts +0 -32
- package/dist/lib/auto-update-checker.d.ts.map +0 -1
- package/dist/lib/auto-update-checker.js +0 -725
- package/dist/lib/auto-update-checker.js.map +0 -1
package/scripts/codex.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { createHash, randomBytes } from "node:crypto";
|
|
@@ -41,6 +41,23 @@ const RUNTIME_ROTATION_SHADOW_HOME_OMIT_STATE_FILES = new Set([
|
|
|
41
41
|
"auth.json",
|
|
42
42
|
"accounts.json",
|
|
43
43
|
]);
|
|
44
|
+
const RUNTIME_ROTATION_SHADOW_HOME_OMIT_ROOT_DIRS = new Set(["multi-auth"]);
|
|
45
|
+
const RUNTIME_ROTATION_SHADOW_HOME_LINK_ONLY_ROOT_DIRS = new Set([
|
|
46
|
+
".sandbox",
|
|
47
|
+
".sandbox-bin",
|
|
48
|
+
".sandbox-secrets",
|
|
49
|
+
".tmp",
|
|
50
|
+
"ambient-suggestions",
|
|
51
|
+
"archived_sessions",
|
|
52
|
+
"backups",
|
|
53
|
+
"cache",
|
|
54
|
+
"generated_images",
|
|
55
|
+
"log",
|
|
56
|
+
"sqlite",
|
|
57
|
+
"tmp",
|
|
58
|
+
"understand-anything",
|
|
59
|
+
"vendor_imports",
|
|
60
|
+
]);
|
|
44
61
|
const SHADOW_HOME_STATE_FILE_SET = new Set(SHADOW_HOME_STATE_FILES);
|
|
45
62
|
const SHADOW_HOME_CONFIG_FILE = "config.toml";
|
|
46
63
|
const SHADOW_HOME_SYNC_LOCK_DIR = ".codex-multi-auth-shadow-sync.lock";
|
|
@@ -63,8 +80,8 @@ const DEFAULT_APP_RUNTIME_HELPER_DETACH_GRACE_MS = 5_000;
|
|
|
63
80
|
const APP_RUNTIME_HELPER_LAUNCH_TIMEOUT_MS = 15_000;
|
|
64
81
|
const APP_SERVER_SHIM_DIR_NAME = "app-server-shims";
|
|
65
82
|
const APP_SERVER_SHIM_HELPER_PREFIX = "helper-";
|
|
66
|
-
const
|
|
67
|
-
const
|
|
83
|
+
const DEFAULT_STARTUP_UPDATE_NOTICE_BUDGET_MS = 3_000;
|
|
84
|
+
const STARTUP_UPDATE_NOTICE_TIMED_OUT = Symbol("startup-update-notice-timed-out");
|
|
68
85
|
let shadowHomeCleanupBusyFailuresRemaining = Number.parseInt(
|
|
69
86
|
process.env.CODEX_MULTI_AUTH_TEST_SHADOW_CLEANUP_BUSY_FAILURES ?? "0",
|
|
70
87
|
10,
|
|
@@ -89,6 +106,9 @@ const shadowHomeCleanupRetryMarkerDir =
|
|
|
89
106
|
(process.env.CODEX_MULTI_AUTH_TEST_SHADOW_RETRY_MARKER_DIR ?? "").trim();
|
|
90
107
|
let warnedInvalidRuntimeRotationProxyEnv = false;
|
|
91
108
|
let warnedPendingAccountReadIdOverflow = false;
|
|
109
|
+
let warnedShadowHomeSqliteLinkFailure = false;
|
|
110
|
+
const warnedShadowHomeLinkOnlyDirectoryFailures = new Set();
|
|
111
|
+
const warnedShadowHomeSqliteSidecarPlaceholderFailures = new Set();
|
|
92
112
|
|
|
93
113
|
async function loadRuntimeConstants() {
|
|
94
114
|
const fallback = {
|
|
@@ -260,31 +280,27 @@ function readBooleanEnvFlag(name) {
|
|
|
260
280
|
return null;
|
|
261
281
|
}
|
|
262
282
|
|
|
263
|
-
function
|
|
283
|
+
function isStartupUpdateNoticeDebugEnabled() {
|
|
264
284
|
return readBooleanEnvFlag("CODEX_MULTI_AUTH_DEBUG") === true;
|
|
265
285
|
}
|
|
266
286
|
|
|
267
|
-
function
|
|
268
|
-
return process.stderr.isTTY === true ||
|
|
287
|
+
function shouldLogStartupUpdateNotice() {
|
|
288
|
+
return process.stderr.isTTY === true || isStartupUpdateNoticeDebugEnabled();
|
|
269
289
|
}
|
|
270
290
|
|
|
271
|
-
function
|
|
291
|
+
function readStartupUpdateNoticeBudgetMs() {
|
|
272
292
|
const raw =
|
|
273
|
-
process.env.
|
|
274
|
-
process.env.
|
|
275
|
-
if (!raw) return
|
|
293
|
+
process.env.CODEX_MULTI_AUTH_UPDATE_NOTICE_STARTUP_BUDGET_MS ??
|
|
294
|
+
process.env.CODEX_MULTI_AUTH_TEST_STARTUP_UPDATE_NOTICE_BUDGET_MS;
|
|
295
|
+
if (!raw) return DEFAULT_STARTUP_UPDATE_NOTICE_BUDGET_MS;
|
|
276
296
|
const parsed = Number.parseInt(raw, 10);
|
|
277
297
|
return Number.isFinite(parsed) && parsed > 0
|
|
278
298
|
? parsed
|
|
279
|
-
:
|
|
299
|
+
: DEFAULT_STARTUP_UPDATE_NOTICE_BUDGET_MS;
|
|
280
300
|
}
|
|
281
301
|
|
|
282
|
-
function
|
|
283
|
-
|
|
284
|
-
return {
|
|
285
|
-
fetchTimeoutMs,
|
|
286
|
-
updateTimeoutMs: Math.max(1, budgetMs - fetchTimeoutMs),
|
|
287
|
-
};
|
|
302
|
+
function resolveStartupUpdateNoticeTimeoutMs(budgetMs) {
|
|
303
|
+
return Math.max(1, Math.floor(budgetMs * 0.8));
|
|
288
304
|
}
|
|
289
305
|
|
|
290
306
|
function isModuleNotFoundError(error) {
|
|
@@ -296,7 +312,7 @@ function isModuleNotFoundError(error) {
|
|
|
296
312
|
);
|
|
297
313
|
}
|
|
298
314
|
|
|
299
|
-
function
|
|
315
|
+
function shouldRunStartupUpdateNotice(rawArgs, normalizedArgs) {
|
|
300
316
|
if ((process.env.CODEX_MULTI_AUTH_BYPASS ?? "").trim() === "1") {
|
|
301
317
|
return false;
|
|
302
318
|
}
|
|
@@ -309,7 +325,7 @@ function shouldRunStartupAutoUpdate(rawArgs, normalizedArgs) {
|
|
|
309
325
|
return true;
|
|
310
326
|
}
|
|
311
327
|
|
|
312
|
-
async function
|
|
328
|
+
async function withStartupUpdateNoticeBudget(promise, budgetMs) {
|
|
313
329
|
let timeout = null;
|
|
314
330
|
try {
|
|
315
331
|
return await Promise.race([
|
|
@@ -318,7 +334,7 @@ async function withStartupAutoUpdateBudget(promise, budgetMs) {
|
|
|
318
334
|
timeout = setTimeout(
|
|
319
335
|
() => {
|
|
320
336
|
timeout?.unref?.();
|
|
321
|
-
resolve(
|
|
337
|
+
resolve(STARTUP_UPDATE_NOTICE_TIMED_OUT);
|
|
322
338
|
},
|
|
323
339
|
budgetMs,
|
|
324
340
|
);
|
|
@@ -329,51 +345,42 @@ async function withStartupAutoUpdateBudget(promise, budgetMs) {
|
|
|
329
345
|
}
|
|
330
346
|
}
|
|
331
347
|
|
|
332
|
-
function
|
|
333
|
-
if (
|
|
348
|
+
function logStartupUpdateNoticeDebug(message) {
|
|
349
|
+
if (isStartupUpdateNoticeDebugEnabled()) {
|
|
334
350
|
console.error(`codex-multi-auth: ${message}`);
|
|
335
351
|
}
|
|
336
352
|
}
|
|
337
353
|
|
|
338
|
-
async function
|
|
339
|
-
if (!
|
|
340
|
-
const budgetMs =
|
|
341
|
-
const
|
|
342
|
-
resolveStartupAutoUpdateTimeouts(budgetMs);
|
|
354
|
+
async function showUpdateNoticeIfAvailable(rawArgs, normalizedArgs) {
|
|
355
|
+
if (!shouldRunStartupUpdateNotice(rawArgs, normalizedArgs)) return;
|
|
356
|
+
const budgetMs = readStartupUpdateNoticeBudgetMs();
|
|
357
|
+
const fetchTimeoutMs = resolveStartupUpdateNoticeTimeoutMs(budgetMs);
|
|
343
358
|
try {
|
|
344
|
-
const mod = await import("../dist/lib/
|
|
345
|
-
if (typeof mod.
|
|
359
|
+
const mod = await import("../dist/lib/update-notice.js");
|
|
360
|
+
if (typeof mod.checkForUpdates !== "function") {
|
|
346
361
|
return;
|
|
347
362
|
}
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
if (!shouldLogStartupAutoUpdateProgress()) return;
|
|
354
|
-
console.error(
|
|
355
|
-
`codex-multi-auth: auto-update found ${update.latestVersion}; starting npm update -g codex-multi-auth. Startup will continue if it exceeds ${budgetMs}ms.`,
|
|
356
|
-
);
|
|
357
|
-
},
|
|
358
|
-
});
|
|
359
|
-
const result = await withStartupAutoUpdateBudget(updatePromise, budgetMs);
|
|
360
|
-
if (result === STARTUP_AUTO_UPDATE_TIMED_OUT) {
|
|
361
|
-
logStartupAutoUpdateDebug(
|
|
362
|
-
`auto-update skipped: startup budget exceeded after ${budgetMs}ms`,
|
|
363
|
+
const checkPromise = mod.checkForUpdates(false, fetchTimeoutMs);
|
|
364
|
+
const result = await withStartupUpdateNoticeBudget(checkPromise, budgetMs);
|
|
365
|
+
if (result === STARTUP_UPDATE_NOTICE_TIMED_OUT) {
|
|
366
|
+
logStartupUpdateNoticeDebug(
|
|
367
|
+
`update notice skipped: startup budget exceeded after ${budgetMs}ms`,
|
|
363
368
|
);
|
|
364
369
|
return;
|
|
365
370
|
}
|
|
366
|
-
if (result?.
|
|
367
|
-
if (
|
|
371
|
+
if (result?.hasUpdate && result.latestVersion && shouldLogStartupUpdateNotice()) {
|
|
372
|
+
if (typeof mod.formatManualUpdateNotice === "function") {
|
|
373
|
+
console.error(mod.formatManualUpdateNotice(result));
|
|
374
|
+
} else {
|
|
368
375
|
console.error(
|
|
369
|
-
`codex-multi-auth
|
|
376
|
+
`codex-multi-auth update available: v${result.latestVersion}; current: v${result.currentVersion}; run: ${result.updateCommand}`,
|
|
370
377
|
);
|
|
371
378
|
}
|
|
372
379
|
}
|
|
373
380
|
} catch (error) {
|
|
374
381
|
if (isModuleNotFoundError(error)) return;
|
|
375
|
-
|
|
376
|
-
`
|
|
382
|
+
logStartupUpdateNoticeDebug(
|
|
383
|
+
`update notice skipped: ${error instanceof Error ? error.message : String(error)}`,
|
|
377
384
|
);
|
|
378
385
|
}
|
|
379
386
|
}
|
|
@@ -1878,6 +1885,41 @@ function mirrorDirectoryIntoShadowHome(sourcePath, destinationPath) {
|
|
|
1878
1885
|
return "copied";
|
|
1879
1886
|
}
|
|
1880
1887
|
|
|
1888
|
+
function linkDirectoryIntoShadowHome(sourcePath, destinationPath) {
|
|
1889
|
+
try {
|
|
1890
|
+
if ((process.env.CODEX_MULTI_AUTH_TEST_FORCE_SHADOW_DIR_COPY ?? "").trim() === "1") {
|
|
1891
|
+
throw new Error("simulated directory link failure");
|
|
1892
|
+
}
|
|
1893
|
+
symlinkSync(
|
|
1894
|
+
sourcePath,
|
|
1895
|
+
destinationPath,
|
|
1896
|
+
process.platform === "win32" ? "junction" : "dir",
|
|
1897
|
+
);
|
|
1898
|
+
return true;
|
|
1899
|
+
} catch {
|
|
1900
|
+
return false;
|
|
1901
|
+
}
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1904
|
+
function warnSkippedLinkOnlyShadowHomeDirectory(name) {
|
|
1905
|
+
if (warnedShadowHomeLinkOnlyDirectoryFailures.has(name)) {
|
|
1906
|
+
return;
|
|
1907
|
+
}
|
|
1908
|
+
warnedShadowHomeLinkOnlyDirectoryFailures.add(name);
|
|
1909
|
+
console.error(
|
|
1910
|
+
`codex-multi-auth: skipped optional shadow-home directory ${name} because linking failed; refusing to copy generated runtime data.`,
|
|
1911
|
+
);
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
function shouldCopyRuntimeGeneratedShadowHomeDirectoryFallback() {
|
|
1915
|
+
const normalized = (
|
|
1916
|
+
process.env.CODEX_MULTI_AUTH_RUNTIME_SHADOW_COPY_GENERATED_DIRS ?? ""
|
|
1917
|
+
)
|
|
1918
|
+
.trim()
|
|
1919
|
+
.toLowerCase();
|
|
1920
|
+
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1881
1923
|
function linkFileIntoShadowHome(sourcePath, destinationPath) {
|
|
1882
1924
|
try {
|
|
1883
1925
|
symlinkSync(sourcePath, destinationPath, "file");
|
|
@@ -1902,6 +1944,148 @@ function mirrorFileIntoShadowHome(sourcePath, destinationPath, tightenFile) {
|
|
|
1902
1944
|
tightenFile(destinationPath);
|
|
1903
1945
|
}
|
|
1904
1946
|
|
|
1947
|
+
function isSqliteMainFile(name) {
|
|
1948
|
+
return /\.sqlite$/i.test(name);
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
function isSqliteSidecarFile(name) {
|
|
1952
|
+
return /\.sqlite-(?:shm|wal)$/i.test(name);
|
|
1953
|
+
}
|
|
1954
|
+
|
|
1955
|
+
function normalizeRuntimeShadowHomeEntryName(name) {
|
|
1956
|
+
return process.platform === "win32" || process.platform === "darwin"
|
|
1957
|
+
? name.toLowerCase()
|
|
1958
|
+
: name;
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
function isCodexRuntimeLocalSqliteFile(name) {
|
|
1962
|
+
const normalizedName = normalizeRuntimeShadowHomeEntryName(name);
|
|
1963
|
+
return /^(?:state|logs)_\d+\.sqlite(?:-(?:shm|wal))?$/.test(normalizedName);
|
|
1964
|
+
}
|
|
1965
|
+
|
|
1966
|
+
function isCodexRuntimeTransientStateFile(name) {
|
|
1967
|
+
const normalizedName = normalizeRuntimeShadowHomeEntryName(name);
|
|
1968
|
+
return (
|
|
1969
|
+
/^(?:auth|accounts)\.json\.\d+\.[a-z0-9]+\.tmp$/.test(
|
|
1970
|
+
normalizedName,
|
|
1971
|
+
) ||
|
|
1972
|
+
/^\.codex-global-state\.json\.tmp-[a-z0-9-]+$/.test(normalizedName)
|
|
1973
|
+
);
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
function isRuntimeRotationShadowHomeOmittedEntry(name) {
|
|
1977
|
+
const normalizedName = normalizeRuntimeShadowHomeEntryName(name);
|
|
1978
|
+
return (
|
|
1979
|
+
RUNTIME_ROTATION_SHADOW_HOME_OMIT_ROOT_DIRS.has(normalizedName) ||
|
|
1980
|
+
isCodexRuntimeLocalSqliteFile(name) ||
|
|
1981
|
+
isCodexRuntimeTransientStateFile(name)
|
|
1982
|
+
);
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
function isRuntimeRotationShadowHomeLinkOnlyDirectory(name) {
|
|
1986
|
+
const normalizedName = normalizeRuntimeShadowHomeEntryName(name);
|
|
1987
|
+
return RUNTIME_ROTATION_SHADOW_HOME_LINK_ONLY_ROOT_DIRS.has(normalizedName);
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
function shouldMaterializeFileIntoShadowHome(name) {
|
|
1991
|
+
return isSqliteMainFile(name) || isSqliteSidecarFile(name);
|
|
1992
|
+
}
|
|
1993
|
+
|
|
1994
|
+
function warnSkippedSqliteShadowHomeMaterialization() {
|
|
1995
|
+
if (!warnedShadowHomeSqliteLinkFailure) {
|
|
1996
|
+
warnedShadowHomeSqliteLinkFailure = true;
|
|
1997
|
+
console.error(
|
|
1998
|
+
"codex-multi-auth: skipped SQLite shadow-home materialization because linking failed; refusing to copy active SQLite state.",
|
|
1999
|
+
);
|
|
2000
|
+
}
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
function warnSkippedSqliteShadowHomeSidecarPlaceholder(error, destinationPath) {
|
|
2004
|
+
if (!warnedShadowHomeSqliteSidecarPlaceholderFailures.has(destinationPath)) {
|
|
2005
|
+
warnedShadowHomeSqliteSidecarPlaceholderFailures.add(destinationPath);
|
|
2006
|
+
console.error(
|
|
2007
|
+
`codex-multi-auth: skipped SQLite shadow-home sidecar placeholder for ${destinationPath} because linking failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
2008
|
+
);
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
function materializeSqliteSidecarPlaceholder(sourceSidecarPath, destinationSidecarPath) {
|
|
2013
|
+
try {
|
|
2014
|
+
if (
|
|
2015
|
+
(process.env.CODEX_MULTI_AUTH_TEST_FORCE_SHADOW_SIDECAR_PLACEHOLDER_FAILURE ??
|
|
2016
|
+
""
|
|
2017
|
+
).trim() === "1"
|
|
2018
|
+
) {
|
|
2019
|
+
const error = new Error("simulated SQLite sidecar placeholder failure");
|
|
2020
|
+
error.code = "EPERM";
|
|
2021
|
+
throw error;
|
|
2022
|
+
}
|
|
2023
|
+
symlinkSync(sourceSidecarPath, destinationSidecarPath, "file");
|
|
2024
|
+
return true;
|
|
2025
|
+
} catch (error) {
|
|
2026
|
+
if (error?.code === "EEXIST") {
|
|
2027
|
+
return true;
|
|
2028
|
+
}
|
|
2029
|
+
warnSkippedSqliteShadowHomeSidecarPlaceholder(error, destinationSidecarPath);
|
|
2030
|
+
return false;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
function materializeFileIntoShadowHome(sourcePath, destinationPath) {
|
|
2035
|
+
try {
|
|
2036
|
+
if (
|
|
2037
|
+
(process.env.CODEX_MULTI_AUTH_TEST_FORCE_SHADOW_SQLITE_SIDECAR_LINK_FAILURE ??
|
|
2038
|
+
""
|
|
2039
|
+
).trim() === "1" &&
|
|
2040
|
+
isSqliteSidecarFile(basename(sourcePath))
|
|
2041
|
+
) {
|
|
2042
|
+
throw new Error("simulated SQLite sidecar link failure");
|
|
2043
|
+
}
|
|
2044
|
+
if (linkFileIntoShadowHome(sourcePath, destinationPath)) {
|
|
2045
|
+
return true;
|
|
2046
|
+
}
|
|
2047
|
+
warnSkippedSqliteShadowHomeMaterialization();
|
|
2048
|
+
} catch {
|
|
2049
|
+
warnSkippedSqliteShadowHomeMaterialization();
|
|
2050
|
+
}
|
|
2051
|
+
return false;
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
function materializeSqliteSidecarsIntoShadowHome(sourcePath, destinationPath) {
|
|
2055
|
+
for (const suffix of ["-wal", "-shm"]) {
|
|
2056
|
+
const sourceSidecarPath = `${sourcePath}${suffix}`;
|
|
2057
|
+
const destinationSidecarPath = `${destinationPath}${suffix}`;
|
|
2058
|
+
if (existsSync(destinationSidecarPath)) {
|
|
2059
|
+
continue;
|
|
2060
|
+
}
|
|
2061
|
+
if (existsSync(sourceSidecarPath)) {
|
|
2062
|
+
if (!materializeFileIntoShadowHome(sourceSidecarPath, destinationSidecarPath)) {
|
|
2063
|
+
if (!materializeSqliteSidecarPlaceholder(
|
|
2064
|
+
sourceSidecarPath,
|
|
2065
|
+
destinationSidecarPath,
|
|
2066
|
+
)) {
|
|
2067
|
+
return false;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
continue;
|
|
2071
|
+
}
|
|
2072
|
+
if (!materializeSqliteSidecarPlaceholder(sourceSidecarPath, destinationSidecarPath)) {
|
|
2073
|
+
return false;
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
return true;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
function removeSqliteShadowHomeMaterialization(destinationPath) {
|
|
2080
|
+
for (const path of [destinationPath, `${destinationPath}-wal`, `${destinationPath}-shm`]) {
|
|
2081
|
+
try {
|
|
2082
|
+
rmSync(path, { force: true });
|
|
2083
|
+
} catch {
|
|
2084
|
+
// Best-effort cleanup; keep removing the remaining SQLite siblings.
|
|
2085
|
+
}
|
|
2086
|
+
}
|
|
2087
|
+
}
|
|
2088
|
+
|
|
1905
2089
|
function collectShadowHomeSyncFileNames(shadowCodexHome, syncFileNames) {
|
|
1906
2090
|
try {
|
|
1907
2091
|
for (const entry of readdirSync(shadowCodexHome, { withFileTypes: true })) {
|
|
@@ -2011,9 +2195,14 @@ function syncAdditionalShadowHomeFiles(
|
|
|
2011
2195
|
originalFileStates,
|
|
2012
2196
|
tightenFile,
|
|
2013
2197
|
skipSyncBackNames = new Set(),
|
|
2198
|
+
skipSyncBackPredicate = () => false,
|
|
2014
2199
|
) {
|
|
2015
2200
|
for (const name of names) {
|
|
2016
|
-
if (
|
|
2201
|
+
if (
|
|
2202
|
+
SHADOW_HOME_STATE_FILE_SET.has(name) ||
|
|
2203
|
+
skipSyncBackNames.has(name) ||
|
|
2204
|
+
skipSyncBackPredicate(name)
|
|
2205
|
+
) {
|
|
2017
2206
|
continue;
|
|
2018
2207
|
}
|
|
2019
2208
|
const shadowPath = join(shadowCodexHome, name);
|
|
@@ -2049,6 +2238,10 @@ function createShadowHomeMirror(
|
|
|
2049
2238
|
) {
|
|
2050
2239
|
const syncFileNames = new Set(SHADOW_HOME_STATE_FILES);
|
|
2051
2240
|
const skipSyncBackNames = new Set(options.skipSyncBackNames ?? []);
|
|
2241
|
+
const skipMirrorPredicate = options.skipMirrorPredicate ?? (() => false);
|
|
2242
|
+
const skipSyncBackPredicate = options.skipSyncBackPredicate ?? (() => false);
|
|
2243
|
+
const linkOnlyDirectoryPredicate =
|
|
2244
|
+
options.linkOnlyDirectoryPredicate ?? (() => false);
|
|
2052
2245
|
const originalFileStates = new Map();
|
|
2053
2246
|
const copiedDirectoryNames = new Set();
|
|
2054
2247
|
const rememberSyncFile = (name) => {
|
|
@@ -2070,11 +2263,13 @@ function createShadowHomeMirror(
|
|
|
2070
2263
|
if (
|
|
2071
2264
|
name === SHADOW_HOME_CONFIG_FILE ||
|
|
2072
2265
|
name === SHADOW_HOME_SYNC_STATE_FILE ||
|
|
2073
|
-
name === SHADOW_HOME_SYNC_LOCK_DIR
|
|
2266
|
+
name === SHADOW_HOME_SYNC_LOCK_DIR ||
|
|
2267
|
+
skipMirrorPredicate(name)
|
|
2074
2268
|
) {
|
|
2075
2269
|
continue;
|
|
2076
2270
|
}
|
|
2077
2271
|
const isKnownStateFile = SHADOW_HOME_STATE_FILE_SET.has(name);
|
|
2272
|
+
const shouldMaterializeFile = shouldMaterializeFileIntoShadowHome(name);
|
|
2078
2273
|
const sourcePath = join(originalCodexHome, name);
|
|
2079
2274
|
const destinationPath = join(shadowCodexHome, name);
|
|
2080
2275
|
if (existsSync(destinationPath)) {
|
|
@@ -2093,6 +2288,15 @@ function createShadowHomeMirror(
|
|
|
2093
2288
|
throw new Error(`Expected ${name} to be a file`);
|
|
2094
2289
|
}
|
|
2095
2290
|
if (directoryLike) {
|
|
2291
|
+
if (
|
|
2292
|
+
linkOnlyDirectoryPredicate(name) &&
|
|
2293
|
+
!shouldCopyRuntimeGeneratedShadowHomeDirectoryFallback()
|
|
2294
|
+
) {
|
|
2295
|
+
if (!linkDirectoryIntoShadowHome(sourcePath, destinationPath)) {
|
|
2296
|
+
warnSkippedLinkOnlyShadowHomeDirectory(name);
|
|
2297
|
+
}
|
|
2298
|
+
continue;
|
|
2299
|
+
}
|
|
2096
2300
|
if (mirrorDirectoryIntoShadowHome(sourcePath, destinationPath) === "copied") {
|
|
2097
2301
|
copiedDirectoryNames.add(name);
|
|
2098
2302
|
}
|
|
@@ -2103,6 +2307,15 @@ function createShadowHomeMirror(
|
|
|
2103
2307
|
if (isKnownStateFile) {
|
|
2104
2308
|
copyFileSync(sourcePath, destinationPath);
|
|
2105
2309
|
tightenFile(destinationPath);
|
|
2310
|
+
} else if (shouldMaterializeFile) {
|
|
2311
|
+
if (isSqliteSidecarFile(name)) {
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
if (materializeFileIntoShadowHome(sourcePath, destinationPath) && isSqliteMainFile(name)) {
|
|
2315
|
+
if (!materializeSqliteSidecarsIntoShadowHome(sourcePath, destinationPath)) {
|
|
2316
|
+
removeSqliteShadowHomeMaterialization(destinationPath);
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2106
2319
|
} else {
|
|
2107
2320
|
mirrorFileIntoShadowHome(sourcePath, destinationPath, tightenFile);
|
|
2108
2321
|
}
|
|
@@ -2141,6 +2354,7 @@ function createShadowHomeMirror(
|
|
|
2141
2354
|
originalFileStates,
|
|
2142
2355
|
tightenFile,
|
|
2143
2356
|
skipSyncBackNames,
|
|
2357
|
+
skipSyncBackPredicate,
|
|
2144
2358
|
);
|
|
2145
2359
|
} catch {
|
|
2146
2360
|
// Best-effort only; runtime auth refreshes should not fail cleanup.
|
|
@@ -2197,6 +2411,10 @@ function resolveOriginalMultiAuthDir(env) {
|
|
|
2197
2411
|
return undefined;
|
|
2198
2412
|
}
|
|
2199
2413
|
|
|
2414
|
+
function resolveRuntimeRotationOriginalMultiAuthDir(originalCodexHome, env) {
|
|
2415
|
+
return resolveOriginalMultiAuthDir(env) ?? join(originalCodexHome, "multi-auth");
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2200
2418
|
function parseRuntimeRotationProxyEnv(value) {
|
|
2201
2419
|
if (value === undefined) return undefined;
|
|
2202
2420
|
const normalized = value.trim().toLowerCase();
|
|
@@ -2266,6 +2484,16 @@ function resolveRuntimeRotationProxyOriginalCodexHome(baseEnv) {
|
|
|
2266
2484
|
return override || resolveCodexHomeDir(baseEnv);
|
|
2267
2485
|
}
|
|
2268
2486
|
|
|
2487
|
+
function createRuntimeRotationShadowHome(originalCodexHome) {
|
|
2488
|
+
const shadowRoot = join(
|
|
2489
|
+
originalCodexHome,
|
|
2490
|
+
"multi-auth",
|
|
2491
|
+
"runtime-shadow-homes",
|
|
2492
|
+
);
|
|
2493
|
+
mkdirSync(shadowRoot, { recursive: true });
|
|
2494
|
+
return mkdtempSync(join(shadowRoot, "codex-multi-auth-runtime-home-"));
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2269
2497
|
function createRuntimeRotationProxyCodexHome(
|
|
2270
2498
|
baseEnv,
|
|
2271
2499
|
proxyBaseUrl,
|
|
@@ -2273,7 +2501,7 @@ function createRuntimeRotationProxyCodexHome(
|
|
|
2273
2501
|
configTomlModule,
|
|
2274
2502
|
) {
|
|
2275
2503
|
const originalCodexHome = resolveRuntimeRotationProxyOriginalCodexHome(baseEnv);
|
|
2276
|
-
const shadowCodexHome =
|
|
2504
|
+
const shadowCodexHome = createRuntimeRotationShadowHome(originalCodexHome);
|
|
2277
2505
|
let syncShadowHomeStateBack = () => {};
|
|
2278
2506
|
const cleanup = () => {
|
|
2279
2507
|
try {
|
|
@@ -2296,7 +2524,10 @@ function createRuntimeRotationProxyCodexHome(
|
|
|
2296
2524
|
shadowCodexHome,
|
|
2297
2525
|
tightenShadowHomePermissions,
|
|
2298
2526
|
{
|
|
2527
|
+
skipMirrorPredicate: isRuntimeRotationShadowHomeOmittedEntry,
|
|
2299
2528
|
skipSyncBackNames: RUNTIME_ROTATION_SHADOW_HOME_OMIT_STATE_FILES,
|
|
2529
|
+
skipSyncBackPredicate: isRuntimeRotationShadowHomeOmittedEntry,
|
|
2530
|
+
linkOnlyDirectoryPredicate: isRuntimeRotationShadowHomeLinkOnlyDirectory,
|
|
2300
2531
|
},
|
|
2301
2532
|
);
|
|
2302
2533
|
omitRuntimeRotationShadowHomeStateFiles(shadowCodexHome);
|
|
@@ -2321,11 +2552,11 @@ function createRuntimeRotationProxyCodexHome(
|
|
|
2321
2552
|
...baseEnv,
|
|
2322
2553
|
CODEX_HOME: shadowCodexHome,
|
|
2323
2554
|
OPENAI_API_KEY: clientApiKey,
|
|
2555
|
+
CODEX_MULTI_AUTH_DIR: resolveRuntimeRotationOriginalMultiAuthDir(
|
|
2556
|
+
originalCodexHome,
|
|
2557
|
+
baseEnv,
|
|
2558
|
+
),
|
|
2324
2559
|
};
|
|
2325
|
-
const originalMultiAuthDir = resolveOriginalMultiAuthDir(baseEnv);
|
|
2326
|
-
if (originalMultiAuthDir) {
|
|
2327
|
-
forwardedEnv.CODEX_MULTI_AUTH_DIR = originalMultiAuthDir;
|
|
2328
|
-
}
|
|
2329
2560
|
|
|
2330
2561
|
return {
|
|
2331
2562
|
env: forwardedEnv,
|
|
@@ -2780,6 +3011,10 @@ function startRuntimeRotationAppHelper(baseContext) {
|
|
|
2780
3011
|
{
|
|
2781
3012
|
env: {
|
|
2782
3013
|
...baseContext.env,
|
|
3014
|
+
CODEX_MULTI_AUTH_DIR: resolveRuntimeRotationOriginalMultiAuthDir(
|
|
3015
|
+
realCodexHome,
|
|
3016
|
+
baseContext.env,
|
|
3017
|
+
),
|
|
2783
3018
|
[APP_RUNTIME_HELPER_OWNER_PID_ENV]: String(process.pid),
|
|
2784
3019
|
[APP_RUNTIME_HELPER_REAL_CODEX_HOME_ENV]: realCodexHome,
|
|
2785
3020
|
},
|
|
@@ -2841,7 +3076,11 @@ function startRuntimeRotationAppHelper(baseContext) {
|
|
|
2841
3076
|
});
|
|
2842
3077
|
}
|
|
2843
3078
|
|
|
2844
|
-
async function createRuntimeRotationAppHelperContext(
|
|
3079
|
+
async function createRuntimeRotationAppHelperContext(
|
|
3080
|
+
baseContext,
|
|
3081
|
+
configTomlModule,
|
|
3082
|
+
options = {},
|
|
3083
|
+
) {
|
|
2845
3084
|
const startedAt = Date.now();
|
|
2846
3085
|
const { helper, message } = await startRuntimeRotationAppHelper(baseContext);
|
|
2847
3086
|
const helperEnv = message.env ?? {};
|
|
@@ -2849,7 +3088,7 @@ async function createRuntimeRotationAppHelperContext(baseContext, configTomlModu
|
|
|
2849
3088
|
|
|
2850
3089
|
const cleanup = async ({ exitCode } = {}) => {
|
|
2851
3090
|
const livedMs = Date.now() - startedAt;
|
|
2852
|
-
if (exitCode === 0 && livedMs < detachGraceMs) {
|
|
3091
|
+
if (exitCode === 0 && (options.detachOnExit === true || livedMs < detachGraceMs)) {
|
|
2853
3092
|
helper.stdout?.destroy();
|
|
2854
3093
|
helper.stderr?.destroy();
|
|
2855
3094
|
helper.unref();
|
|
@@ -2898,6 +3137,11 @@ async function createRuntimeRotationProxyContextIfEnabled(
|
|
|
2898
3137
|
if (isCodexAppCommand(rawArgs)) {
|
|
2899
3138
|
return createRuntimeRotationAppHelperContext(baseContext, configTomlModule);
|
|
2900
3139
|
}
|
|
3140
|
+
if (isCodexInteractiveTuiCommand(rawArgs)) {
|
|
3141
|
+
return createRuntimeRotationAppHelperContext(baseContext, configTomlModule, {
|
|
3142
|
+
detachOnExit: true,
|
|
3143
|
+
});
|
|
3144
|
+
}
|
|
2901
3145
|
|
|
2902
3146
|
const proxyModule = await loadRuntimeRotationProxyModule();
|
|
2903
3147
|
if (!proxyModule) {
|
|
@@ -3092,6 +3336,10 @@ function isCodexAppServerCommand(rawArgs) {
|
|
|
3092
3336
|
return findForwardedCommand(rawArgs)?.command === "app-server";
|
|
3093
3337
|
}
|
|
3094
3338
|
|
|
3339
|
+
function isCodexInteractiveTuiCommand(rawArgs) {
|
|
3340
|
+
return findForwardedCommand(rawArgs) === null;
|
|
3341
|
+
}
|
|
3342
|
+
|
|
3095
3343
|
function shouldUseRuntimeRoutingForForwardedArgs(rawArgs) {
|
|
3096
3344
|
if (!Array.isArray(rawArgs) || rawArgs.length === 0) {
|
|
3097
3345
|
return true;
|
|
@@ -3495,6 +3743,8 @@ function repairCodexSessionIndex(codexHome) {
|
|
|
3495
3743
|
|
|
3496
3744
|
const additions = [];
|
|
3497
3745
|
for (const rolloutPath of collectRolloutFiles(sessionsDir)) {
|
|
3746
|
+
const idFromName = extractRolloutIdFromFilename(basename(rolloutPath));
|
|
3747
|
+
if (idFromName && seen.has(idFromName)) continue;
|
|
3498
3748
|
const entry = parseRolloutIndexEntry(rolloutPath);
|
|
3499
3749
|
if (!entry || seen.has(entry.id)) continue;
|
|
3500
3750
|
seen.add(entry.id);
|
|
@@ -3825,7 +4075,7 @@ async function main() {
|
|
|
3825
4075
|
}
|
|
3826
4076
|
|
|
3827
4077
|
const normalizedArgs = normalizeAuthAlias(rawArgs);
|
|
3828
|
-
await
|
|
4078
|
+
await showUpdateNoticeIfAvailable(rawArgs, normalizedArgs);
|
|
3829
4079
|
ensureWindowsShellShimGuards();
|
|
3830
4080
|
|
|
3831
4081
|
const bypass = (process.env.CODEX_MULTI_AUTH_BYPASS ?? "").trim() === "1";
|