codex-multi-auth 2.1.4 → 2.1.6
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 +50 -25
- package/config/README.md +2 -3
- package/dist/index.js +23 -23
- package/dist/index.js.map +1 -1
- package/dist/lib/auth/device-auth.d.ts.map +1 -1
- package/dist/lib/auth/device-auth.js +18 -1
- package/dist/lib/auth/device-auth.js.map +1 -1
- package/dist/lib/codex-manager/commands/account.js +6 -6
- package/dist/lib/codex-manager/commands/account.js.map +1 -1
- package/dist/lib/codex-manager/commands/best.js +1 -1
- package/dist/lib/codex-manager/commands/best.js.map +1 -1
- package/dist/lib/codex-manager/commands/bridge.js +5 -5
- package/dist/lib/codex-manager/commands/bridge.js.map +1 -1
- package/dist/lib/codex-manager/commands/budget.js +3 -3
- package/dist/lib/codex-manager/commands/budget.js.map +1 -1
- package/dist/lib/codex-manager/commands/forecast.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/forecast.js +18 -4
- package/dist/lib/codex-manager/commands/forecast.js.map +1 -1
- package/dist/lib/codex-manager/commands/integrations.js +1 -1
- package/dist/lib/codex-manager/commands/integrations.js.map +1 -1
- package/dist/lib/codex-manager/commands/models.js +1 -1
- package/dist/lib/codex-manager/commands/models.js.map +1 -1
- package/dist/lib/codex-manager/commands/monitor.js +1 -1
- package/dist/lib/codex-manager/commands/monitor.js.map +1 -1
- package/dist/lib/codex-manager/commands/report.js +1 -1
- package/dist/lib/codex-manager/commands/report.js.map +1 -1
- package/dist/lib/codex-manager/commands/rotation.d.ts.map +1 -1
- package/dist/lib/codex-manager/commands/rotation.js +23 -14
- package/dist/lib/codex-manager/commands/rotation.js.map +1 -1
- package/dist/lib/codex-manager/commands/switch.js +1 -1
- package/dist/lib/codex-manager/commands/switch.js.map +1 -1
- package/dist/lib/codex-manager/commands/uninstall.d.ts +36 -0
- package/dist/lib/codex-manager/commands/uninstall.d.ts.map +1 -0
- package/dist/lib/codex-manager/commands/uninstall.js +284 -0
- package/dist/lib/codex-manager/commands/uninstall.js.map +1 -0
- package/dist/lib/codex-manager/commands/usage.js +2 -2
- package/dist/lib/codex-manager/commands/usage.js.map +1 -1
- package/dist/lib/codex-manager/commands/verify.js +4 -4
- package/dist/lib/codex-manager/commands/verify.js.map +1 -1
- package/dist/lib/codex-manager/commands/why-selected.js +3 -3
- package/dist/lib/codex-manager/commands/why-selected.js.map +1 -1
- package/dist/lib/codex-manager/forecast-report-commands.js +3 -3
- package/dist/lib/codex-manager/forecast-report-commands.js.map +1 -1
- package/dist/lib/codex-manager/help.d.ts.map +1 -1
- package/dist/lib/codex-manager/help.js +27 -26
- package/dist/lib/codex-manager/help.js.map +1 -1
- package/dist/lib/codex-manager/repair-commands.d.ts.map +1 -1
- package/dist/lib/codex-manager/repair-commands.js +23 -11
- package/dist/lib/codex-manager/repair-commands.js.map +1 -1
- package/dist/lib/codex-manager.d.ts.map +1 -1
- package/dist/lib/codex-manager.js +47 -6
- package/dist/lib/codex-manager.js.map +1 -1
- package/dist/lib/forecast.js +1 -1
- package/dist/lib/forecast.js.map +1 -1
- package/dist/lib/request/fetch-helpers.d.ts +1 -1
- package/dist/lib/request/fetch-helpers.js +8 -8
- package/dist/lib/request/fetch-helpers.js.map +1 -1
- package/dist/lib/request/stream-failover.d.ts.map +1 -1
- package/dist/lib/request/stream-failover.js +12 -1
- package/dist/lib/request/stream-failover.js.map +1 -1
- package/dist/lib/rotation.d.ts +1 -1
- package/dist/lib/rotation.js +1 -1
- package/dist/lib/runtime/app-bind.d.ts.map +1 -1
- package/dist/lib/runtime/app-bind.js +28 -3
- package/dist/lib/runtime/app-bind.js.map +1 -1
- package/dist/lib/runtime/config-toml.d.ts.map +1 -1
- package/dist/lib/runtime/config-toml.js +29 -3
- package/dist/lib/runtime/config-toml.js.map +1 -1
- package/dist/lib/runtime/hydrate-emails.d.ts.map +1 -1
- package/dist/lib/runtime/hydrate-emails.js +6 -1
- package/dist/lib/runtime/hydrate-emails.js.map +1 -1
- package/dist/lib/runtime/runtime-current-account.d.ts.map +1 -1
- package/dist/lib/runtime/runtime-current-account.js +10 -1
- package/dist/lib/runtime/runtime-current-account.js.map +1 -1
- package/dist/lib/runtime/storage-scope.js +2 -2
- package/dist/lib/runtime/storage-scope.js.map +1 -1
- package/dist/lib/runtime-rotation-proxy.d.ts.map +1 -1
- package/dist/lib/runtime-rotation-proxy.js +44 -9
- package/dist/lib/runtime-rotation-proxy.js.map +1 -1
- package/dist/lib/storage/transactions.d.ts +2 -1
- package/dist/lib/storage/transactions.d.ts.map +1 -1
- package/dist/lib/storage/transactions.js +9 -3
- package/dist/lib/storage/transactions.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/package.json +26 -17
- package/scripts/codex.js +269 -65
- package/scripts/install-codex-auth-utils.js +48 -0
- package/scripts/preuninstall.js +254 -0
- 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 -730
- package/dist/lib/auto-update-checker.js.map +0 -1
package/scripts/codex.js
CHANGED
|
@@ -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,
|
|
@@ -90,6 +107,8 @@ const shadowHomeCleanupRetryMarkerDir =
|
|
|
90
107
|
let warnedInvalidRuntimeRotationProxyEnv = false;
|
|
91
108
|
let warnedPendingAccountReadIdOverflow = false;
|
|
92
109
|
let warnedShadowHomeSqliteLinkFailure = false;
|
|
110
|
+
const warnedShadowHomeLinkOnlyDirectoryFailures = new Set();
|
|
111
|
+
const warnedShadowHomeSqliteSidecarPlaceholderFailures = new Set();
|
|
93
112
|
|
|
94
113
|
async function loadRuntimeConstants() {
|
|
95
114
|
const fallback = {
|
|
@@ -261,31 +280,27 @@ function readBooleanEnvFlag(name) {
|
|
|
261
280
|
return null;
|
|
262
281
|
}
|
|
263
282
|
|
|
264
|
-
function
|
|
283
|
+
function isStartupUpdateNoticeDebugEnabled() {
|
|
265
284
|
return readBooleanEnvFlag("CODEX_MULTI_AUTH_DEBUG") === true;
|
|
266
285
|
}
|
|
267
286
|
|
|
268
|
-
function
|
|
269
|
-
return process.stderr.isTTY === true ||
|
|
287
|
+
function shouldLogStartupUpdateNotice() {
|
|
288
|
+
return process.stderr.isTTY === true || isStartupUpdateNoticeDebugEnabled();
|
|
270
289
|
}
|
|
271
290
|
|
|
272
|
-
function
|
|
291
|
+
function readStartupUpdateNoticeBudgetMs() {
|
|
273
292
|
const raw =
|
|
274
|
-
process.env.
|
|
275
|
-
process.env.
|
|
276
|
-
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;
|
|
277
296
|
const parsed = Number.parseInt(raw, 10);
|
|
278
297
|
return Number.isFinite(parsed) && parsed > 0
|
|
279
298
|
? parsed
|
|
280
|
-
:
|
|
299
|
+
: DEFAULT_STARTUP_UPDATE_NOTICE_BUDGET_MS;
|
|
281
300
|
}
|
|
282
301
|
|
|
283
|
-
function
|
|
284
|
-
|
|
285
|
-
return {
|
|
286
|
-
fetchTimeoutMs,
|
|
287
|
-
updateTimeoutMs: Math.max(1, budgetMs - fetchTimeoutMs),
|
|
288
|
-
};
|
|
302
|
+
function resolveStartupUpdateNoticeTimeoutMs(budgetMs) {
|
|
303
|
+
return Math.max(1, Math.floor(budgetMs * 0.8));
|
|
289
304
|
}
|
|
290
305
|
|
|
291
306
|
function isModuleNotFoundError(error) {
|
|
@@ -297,7 +312,7 @@ function isModuleNotFoundError(error) {
|
|
|
297
312
|
);
|
|
298
313
|
}
|
|
299
314
|
|
|
300
|
-
function
|
|
315
|
+
function shouldRunStartupUpdateNotice(rawArgs, normalizedArgs) {
|
|
301
316
|
if ((process.env.CODEX_MULTI_AUTH_BYPASS ?? "").trim() === "1") {
|
|
302
317
|
return false;
|
|
303
318
|
}
|
|
@@ -310,7 +325,7 @@ function shouldRunStartupAutoUpdate(rawArgs, normalizedArgs) {
|
|
|
310
325
|
return true;
|
|
311
326
|
}
|
|
312
327
|
|
|
313
|
-
async function
|
|
328
|
+
async function withStartupUpdateNoticeBudget(promise, budgetMs) {
|
|
314
329
|
let timeout = null;
|
|
315
330
|
try {
|
|
316
331
|
return await Promise.race([
|
|
@@ -319,7 +334,7 @@ async function withStartupAutoUpdateBudget(promise, budgetMs) {
|
|
|
319
334
|
timeout = setTimeout(
|
|
320
335
|
() => {
|
|
321
336
|
timeout?.unref?.();
|
|
322
|
-
resolve(
|
|
337
|
+
resolve(STARTUP_UPDATE_NOTICE_TIMED_OUT);
|
|
323
338
|
},
|
|
324
339
|
budgetMs,
|
|
325
340
|
);
|
|
@@ -330,51 +345,42 @@ async function withStartupAutoUpdateBudget(promise, budgetMs) {
|
|
|
330
345
|
}
|
|
331
346
|
}
|
|
332
347
|
|
|
333
|
-
function
|
|
334
|
-
if (
|
|
348
|
+
function logStartupUpdateNoticeDebug(message) {
|
|
349
|
+
if (isStartupUpdateNoticeDebugEnabled()) {
|
|
335
350
|
console.error(`codex-multi-auth: ${message}`);
|
|
336
351
|
}
|
|
337
352
|
}
|
|
338
353
|
|
|
339
|
-
async function
|
|
340
|
-
if (!
|
|
341
|
-
const budgetMs =
|
|
342
|
-
const
|
|
343
|
-
resolveStartupAutoUpdateTimeouts(budgetMs);
|
|
354
|
+
async function showUpdateNoticeIfAvailable(rawArgs, normalizedArgs) {
|
|
355
|
+
if (!shouldRunStartupUpdateNotice(rawArgs, normalizedArgs)) return;
|
|
356
|
+
const budgetMs = readStartupUpdateNoticeBudgetMs();
|
|
357
|
+
const fetchTimeoutMs = resolveStartupUpdateNoticeTimeoutMs(budgetMs);
|
|
344
358
|
try {
|
|
345
|
-
const mod = await import("../dist/lib/
|
|
346
|
-
if (typeof mod.
|
|
359
|
+
const mod = await import("../dist/lib/update-notice.js");
|
|
360
|
+
if (typeof mod.checkForUpdates !== "function") {
|
|
347
361
|
return;
|
|
348
362
|
}
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
if (!shouldLogStartupAutoUpdateProgress()) return;
|
|
355
|
-
console.error(
|
|
356
|
-
`codex-multi-auth: auto-update found ${update.latestVersion}; starting npm update -g codex-multi-auth. Startup will continue if it exceeds ${budgetMs}ms.`,
|
|
357
|
-
);
|
|
358
|
-
},
|
|
359
|
-
});
|
|
360
|
-
const result = await withStartupAutoUpdateBudget(updatePromise, budgetMs);
|
|
361
|
-
if (result === STARTUP_AUTO_UPDATE_TIMED_OUT) {
|
|
362
|
-
logStartupAutoUpdateDebug(
|
|
363
|
-
`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`,
|
|
364
368
|
);
|
|
365
369
|
return;
|
|
366
370
|
}
|
|
367
|
-
if (result?.
|
|
368
|
-
if (
|
|
371
|
+
if (result?.hasUpdate && result.latestVersion && shouldLogStartupUpdateNotice()) {
|
|
372
|
+
if (typeof mod.formatManualUpdateNotice === "function") {
|
|
373
|
+
console.error(mod.formatManualUpdateNotice(result));
|
|
374
|
+
} else {
|
|
369
375
|
console.error(
|
|
370
|
-
`codex-multi-auth
|
|
376
|
+
`codex-multi-auth update available: v${result.latestVersion}; current: v${result.currentVersion}; run: ${result.updateCommand}`,
|
|
371
377
|
);
|
|
372
378
|
}
|
|
373
379
|
}
|
|
374
380
|
} catch (error) {
|
|
375
381
|
if (isModuleNotFoundError(error)) return;
|
|
376
|
-
|
|
377
|
-
`
|
|
382
|
+
logStartupUpdateNoticeDebug(
|
|
383
|
+
`update notice skipped: ${error instanceof Error ? error.message : String(error)}`,
|
|
378
384
|
);
|
|
379
385
|
}
|
|
380
386
|
}
|
|
@@ -1879,6 +1885,41 @@ function mirrorDirectoryIntoShadowHome(sourcePath, destinationPath) {
|
|
|
1879
1885
|
return "copied";
|
|
1880
1886
|
}
|
|
1881
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
|
+
|
|
1882
1923
|
function linkFileIntoShadowHome(sourcePath, destinationPath) {
|
|
1883
1924
|
try {
|
|
1884
1925
|
symlinkSync(sourcePath, destinationPath, "file");
|
|
@@ -1903,25 +1944,148 @@ function mirrorFileIntoShadowHome(sourcePath, destinationPath, tightenFile) {
|
|
|
1903
1944
|
tightenFile(destinationPath);
|
|
1904
1945
|
}
|
|
1905
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
|
+
|
|
1906
1990
|
function shouldMaterializeFileIntoShadowHome(name) {
|
|
1907
|
-
return
|
|
1991
|
+
return isSqliteMainFile(name) || isSqliteSidecarFile(name);
|
|
1908
1992
|
}
|
|
1909
1993
|
|
|
1910
|
-
function
|
|
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) {
|
|
1911
2013
|
try {
|
|
1912
|
-
|
|
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");
|
|
1913
2024
|
return true;
|
|
1914
|
-
} catch {
|
|
1915
|
-
if (
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
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;
|
|
1920
2046
|
}
|
|
2047
|
+
warnSkippedSqliteShadowHomeMaterialization();
|
|
2048
|
+
} catch {
|
|
2049
|
+
warnSkippedSqliteShadowHomeMaterialization();
|
|
1921
2050
|
}
|
|
1922
2051
|
return false;
|
|
1923
2052
|
}
|
|
1924
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
|
+
|
|
1925
2089
|
function collectShadowHomeSyncFileNames(shadowCodexHome, syncFileNames) {
|
|
1926
2090
|
try {
|
|
1927
2091
|
for (const entry of readdirSync(shadowCodexHome, { withFileTypes: true })) {
|
|
@@ -2031,9 +2195,14 @@ function syncAdditionalShadowHomeFiles(
|
|
|
2031
2195
|
originalFileStates,
|
|
2032
2196
|
tightenFile,
|
|
2033
2197
|
skipSyncBackNames = new Set(),
|
|
2198
|
+
skipSyncBackPredicate = () => false,
|
|
2034
2199
|
) {
|
|
2035
2200
|
for (const name of names) {
|
|
2036
|
-
if (
|
|
2201
|
+
if (
|
|
2202
|
+
SHADOW_HOME_STATE_FILE_SET.has(name) ||
|
|
2203
|
+
skipSyncBackNames.has(name) ||
|
|
2204
|
+
skipSyncBackPredicate(name)
|
|
2205
|
+
) {
|
|
2037
2206
|
continue;
|
|
2038
2207
|
}
|
|
2039
2208
|
const shadowPath = join(shadowCodexHome, name);
|
|
@@ -2069,6 +2238,10 @@ function createShadowHomeMirror(
|
|
|
2069
2238
|
) {
|
|
2070
2239
|
const syncFileNames = new Set(SHADOW_HOME_STATE_FILES);
|
|
2071
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);
|
|
2072
2245
|
const originalFileStates = new Map();
|
|
2073
2246
|
const copiedDirectoryNames = new Set();
|
|
2074
2247
|
const rememberSyncFile = (name) => {
|
|
@@ -2090,7 +2263,8 @@ function createShadowHomeMirror(
|
|
|
2090
2263
|
if (
|
|
2091
2264
|
name === SHADOW_HOME_CONFIG_FILE ||
|
|
2092
2265
|
name === SHADOW_HOME_SYNC_STATE_FILE ||
|
|
2093
|
-
name === SHADOW_HOME_SYNC_LOCK_DIR
|
|
2266
|
+
name === SHADOW_HOME_SYNC_LOCK_DIR ||
|
|
2267
|
+
skipMirrorPredicate(name)
|
|
2094
2268
|
) {
|
|
2095
2269
|
continue;
|
|
2096
2270
|
}
|
|
@@ -2114,6 +2288,15 @@ function createShadowHomeMirror(
|
|
|
2114
2288
|
throw new Error(`Expected ${name} to be a file`);
|
|
2115
2289
|
}
|
|
2116
2290
|
if (directoryLike) {
|
|
2291
|
+
if (
|
|
2292
|
+
linkOnlyDirectoryPredicate(name) &&
|
|
2293
|
+
!shouldCopyRuntimeGeneratedShadowHomeDirectoryFallback()
|
|
2294
|
+
) {
|
|
2295
|
+
if (!linkDirectoryIntoShadowHome(sourcePath, destinationPath)) {
|
|
2296
|
+
warnSkippedLinkOnlyShadowHomeDirectory(name);
|
|
2297
|
+
}
|
|
2298
|
+
continue;
|
|
2299
|
+
}
|
|
2117
2300
|
if (mirrorDirectoryIntoShadowHome(sourcePath, destinationPath) === "copied") {
|
|
2118
2301
|
copiedDirectoryNames.add(name);
|
|
2119
2302
|
}
|
|
@@ -2125,7 +2308,14 @@ function createShadowHomeMirror(
|
|
|
2125
2308
|
copyFileSync(sourcePath, destinationPath);
|
|
2126
2309
|
tightenFile(destinationPath);
|
|
2127
2310
|
} else if (shouldMaterializeFile) {
|
|
2128
|
-
|
|
2311
|
+
if (isSqliteSidecarFile(name)) {
|
|
2312
|
+
continue;
|
|
2313
|
+
}
|
|
2314
|
+
if (materializeFileIntoShadowHome(sourcePath, destinationPath) && isSqliteMainFile(name)) {
|
|
2315
|
+
if (!materializeSqliteSidecarsIntoShadowHome(sourcePath, destinationPath)) {
|
|
2316
|
+
removeSqliteShadowHomeMaterialization(destinationPath);
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2129
2319
|
} else {
|
|
2130
2320
|
mirrorFileIntoShadowHome(sourcePath, destinationPath, tightenFile);
|
|
2131
2321
|
}
|
|
@@ -2164,6 +2354,7 @@ function createShadowHomeMirror(
|
|
|
2164
2354
|
originalFileStates,
|
|
2165
2355
|
tightenFile,
|
|
2166
2356
|
skipSyncBackNames,
|
|
2357
|
+
skipSyncBackPredicate,
|
|
2167
2358
|
);
|
|
2168
2359
|
} catch {
|
|
2169
2360
|
// Best-effort only; runtime auth refreshes should not fail cleanup.
|
|
@@ -2220,6 +2411,10 @@ function resolveOriginalMultiAuthDir(env) {
|
|
|
2220
2411
|
return undefined;
|
|
2221
2412
|
}
|
|
2222
2413
|
|
|
2414
|
+
function resolveRuntimeRotationOriginalMultiAuthDir(originalCodexHome, env) {
|
|
2415
|
+
return resolveOriginalMultiAuthDir(env) ?? join(originalCodexHome, "multi-auth");
|
|
2416
|
+
}
|
|
2417
|
+
|
|
2223
2418
|
function parseRuntimeRotationProxyEnv(value) {
|
|
2224
2419
|
if (value === undefined) return undefined;
|
|
2225
2420
|
const normalized = value.trim().toLowerCase();
|
|
@@ -2329,7 +2524,10 @@ function createRuntimeRotationProxyCodexHome(
|
|
|
2329
2524
|
shadowCodexHome,
|
|
2330
2525
|
tightenShadowHomePermissions,
|
|
2331
2526
|
{
|
|
2527
|
+
skipMirrorPredicate: isRuntimeRotationShadowHomeOmittedEntry,
|
|
2332
2528
|
skipSyncBackNames: RUNTIME_ROTATION_SHADOW_HOME_OMIT_STATE_FILES,
|
|
2529
|
+
skipSyncBackPredicate: isRuntimeRotationShadowHomeOmittedEntry,
|
|
2530
|
+
linkOnlyDirectoryPredicate: isRuntimeRotationShadowHomeLinkOnlyDirectory,
|
|
2333
2531
|
},
|
|
2334
2532
|
);
|
|
2335
2533
|
omitRuntimeRotationShadowHomeStateFiles(shadowCodexHome);
|
|
@@ -2354,11 +2552,11 @@ function createRuntimeRotationProxyCodexHome(
|
|
|
2354
2552
|
...baseEnv,
|
|
2355
2553
|
CODEX_HOME: shadowCodexHome,
|
|
2356
2554
|
OPENAI_API_KEY: clientApiKey,
|
|
2555
|
+
CODEX_MULTI_AUTH_DIR: resolveRuntimeRotationOriginalMultiAuthDir(
|
|
2556
|
+
originalCodexHome,
|
|
2557
|
+
baseEnv,
|
|
2558
|
+
),
|
|
2357
2559
|
};
|
|
2358
|
-
const originalMultiAuthDir = resolveOriginalMultiAuthDir(baseEnv);
|
|
2359
|
-
if (originalMultiAuthDir) {
|
|
2360
|
-
forwardedEnv.CODEX_MULTI_AUTH_DIR = originalMultiAuthDir;
|
|
2361
|
-
}
|
|
2362
2560
|
|
|
2363
2561
|
return {
|
|
2364
2562
|
env: forwardedEnv,
|
|
@@ -2813,6 +3011,10 @@ function startRuntimeRotationAppHelper(baseContext) {
|
|
|
2813
3011
|
{
|
|
2814
3012
|
env: {
|
|
2815
3013
|
...baseContext.env,
|
|
3014
|
+
CODEX_MULTI_AUTH_DIR: resolveRuntimeRotationOriginalMultiAuthDir(
|
|
3015
|
+
realCodexHome,
|
|
3016
|
+
baseContext.env,
|
|
3017
|
+
),
|
|
2816
3018
|
[APP_RUNTIME_HELPER_OWNER_PID_ENV]: String(process.pid),
|
|
2817
3019
|
[APP_RUNTIME_HELPER_REAL_CODEX_HOME_ENV]: realCodexHome,
|
|
2818
3020
|
},
|
|
@@ -3541,6 +3743,8 @@ function repairCodexSessionIndex(codexHome) {
|
|
|
3541
3743
|
|
|
3542
3744
|
const additions = [];
|
|
3543
3745
|
for (const rolloutPath of collectRolloutFiles(sessionsDir)) {
|
|
3746
|
+
const idFromName = extractRolloutIdFromFilename(basename(rolloutPath));
|
|
3747
|
+
if (idFromName && seen.has(idFromName)) continue;
|
|
3544
3748
|
const entry = parseRolloutIndexEntry(rolloutPath);
|
|
3545
3749
|
if (!entry || seen.has(entry.id)) continue;
|
|
3546
3750
|
seen.add(entry.id);
|
|
@@ -3871,7 +4075,7 @@ async function main() {
|
|
|
3871
4075
|
}
|
|
3872
4076
|
|
|
3873
4077
|
const normalizedArgs = normalizeAuthAlias(rawArgs);
|
|
3874
|
-
await
|
|
4078
|
+
await showUpdateNoticeIfAvailable(rawArgs, normalizedArgs);
|
|
3875
4079
|
ensureWindowsShellShimGuards();
|
|
3876
4080
|
|
|
3877
4081
|
const bypass = (process.env.CODEX_MULTI_AUTH_BYPASS ?? "").trim() === "1";
|
|
@@ -3,8 +3,47 @@
|
|
|
3
3
|
import { rename as fsRename } from "node:fs/promises";
|
|
4
4
|
import { homedir } from "node:os";
|
|
5
5
|
import { join } from "node:path";
|
|
6
|
+
import process from "node:process";
|
|
6
7
|
|
|
7
8
|
const PLUGIN_NAME = "codex-multi-auth";
|
|
9
|
+
|
|
10
|
+
const TRUE_VALUES = new Set(["1", "true", "yes"]);
|
|
11
|
+
const FALSE_VALUES = new Set(["0", "false", "no"]);
|
|
12
|
+
const CI_ENV_KEYS = [
|
|
13
|
+
"CI",
|
|
14
|
+
"GITHUB_ACTIONS",
|
|
15
|
+
"GITLAB_CI",
|
|
16
|
+
"CIRCLECI",
|
|
17
|
+
"BUILDKITE",
|
|
18
|
+
"TF_BUILD",
|
|
19
|
+
"TEAMCITY_VERSION",
|
|
20
|
+
"JENKINS_URL",
|
|
21
|
+
"TRAVIS",
|
|
22
|
+
"APPVEYOR",
|
|
23
|
+
"BITBUCKET_BUILD_NUMBER",
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/** @param {string | undefined} value */
|
|
27
|
+
function readOptionalBooleanValue(value) {
|
|
28
|
+
if (value === undefined || value.trim().length === 0) return null;
|
|
29
|
+
const normalized = value.trim().toLowerCase();
|
|
30
|
+
if (TRUE_VALUES.has(normalized)) return true;
|
|
31
|
+
if (FALSE_VALUES.has(normalized)) return false;
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** @param {NodeJS.ProcessEnv} env @param {string} key */
|
|
36
|
+
function isEnabledEnvFlag(env, key) {
|
|
37
|
+
const value = env[key];
|
|
38
|
+
if (value === undefined || value.trim().length === 0) return false;
|
|
39
|
+
return readOptionalBooleanValue(value) !== false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** @param {NodeJS.ProcessEnv} [env] */
|
|
43
|
+
export function isCiEnvironment(env = process.env) {
|
|
44
|
+
if (readOptionalBooleanValue(env.npm_config_ignore_scripts) === true) return true;
|
|
45
|
+
return CI_ENV_KEYS.some((key) => isEnabledEnvFlag(env, key));
|
|
46
|
+
}
|
|
8
47
|
export const FILE_RETRY_CODES = new Set([
|
|
9
48
|
"EBUSY",
|
|
10
49
|
"EPERM",
|
|
@@ -48,6 +87,15 @@ export function resolveInstallPaths(
|
|
|
48
87
|
};
|
|
49
88
|
}
|
|
50
89
|
|
|
90
|
+
/** @param {unknown} list */
|
|
91
|
+
export function removePluginFromList(list) {
|
|
92
|
+
const entries = Array.isArray(list) ? list.filter(Boolean) : [];
|
|
93
|
+
return entries.filter((entry) => {
|
|
94
|
+
if (typeof entry !== "string") return true;
|
|
95
|
+
return entry !== PLUGIN_NAME && !entry.startsWith(`${PLUGIN_NAME}@`);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
51
99
|
/** @param {unknown} list */
|
|
52
100
|
export function normalizePluginList(list) {
|
|
53
101
|
const entries = Array.isArray(list) ? list.filter(Boolean) : [];
|