From 36e60703564a8526b6468b4ee09140bac45ccbc4 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 19:40:17 +0800 Subject: [PATCH 01/24] add session resume supervisor for faster codex rotation --- lib/codex-manager/settings-hub.ts | 23 + lib/config.ts | 24 +- lib/quota-probe.ts | 24 + lib/schemas.ts | 1 + lib/storage.ts | 30 +- lib/ui/copy.ts | 1 + scripts/codex-supervisor.js | 1267 +++++++++++++++++++++++++++++ scripts/codex.js | 13 +- test/codex-bin-wrapper.test.ts | 69 ++ test/codex-supervisor.test.ts | 112 +++ test/plugin-config.test.ts | 31 +- test/quota-probe.test.ts | 33 + test/settings-hub-utils.test.ts | 42 +- 13 files changed, 1650 insertions(+), 20 deletions(-) create mode 100644 scripts/codex-supervisor.js create mode 100644 test/codex-supervisor.test.ts diff --git a/lib/codex-manager/settings-hub.ts b/lib/codex-manager/settings-hub.ts index 172648d3..8a90edfe 100644 --- a/lib/codex-manager/settings-hub.ts +++ b/lib/codex-manager/settings-hub.ts @@ -186,6 +186,7 @@ type ThemeConfigAction = type BackendToggleSettingKey = | "liveAccountSync" + | "codexCliSessionSupervisor" | "sessionAffinity" | "proactiveRefreshGuardian" | "retryAllAccountsRateLimited" @@ -272,6 +273,7 @@ type SettingsHubAction = | { type: "back" }; type ExperimentalSettingsAction = + | { type: "toggle-session-supervisor" } | { type: "sync" } | { type: "backup" } | { type: "toggle-refresh-guardian" } @@ -287,6 +289,11 @@ const BACKEND_TOGGLE_OPTIONS: BackendToggleSettingOption[] = [ label: "Enable Live Sync", description: "Keep accounts synced when files change in another window.", }, + { + key: "codexCliSessionSupervisor", + label: "Enable Session Resume Supervisor", + description: "Wrap interactive Codex sessions so they can relaunch with resume after rotation.", + }, { key: "sessionAffinity", label: "Enable Session Affinity", @@ -2530,6 +2537,11 @@ async function promptExperimentalSettings( while (true) { const action = await select( [ + { + label: `${formatDashboardSettingState(draft.codexCliSessionSupervisor ?? BACKEND_DEFAULTS.codexCliSessionSupervisor ?? false)} ${UI_COPY.settings.experimentalSessionSupervisor}`, + value: { type: "toggle-session-supervisor" }, + color: "yellow", + }, { label: UI_COPY.settings.experimentalSync, value: { type: "sync" }, @@ -2586,6 +2598,17 @@ async function promptExperimentalSettings( ); if (!action || action.type === "back") return null; if (action.type === "save") return draft; + if (action.type === "toggle-session-supervisor") { + draft = { + ...draft, + codexCliSessionSupervisor: !( + draft.codexCliSessionSupervisor ?? + BACKEND_DEFAULTS.codexCliSessionSupervisor ?? + false + ), + }; + continue; + } if (action.type === "toggle-refresh-guardian") { draft = { ...draft, diff --git a/lib/config.ts b/lib/config.ts index f9e7ecf8..845b1c5c 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -145,6 +145,7 @@ export const DEFAULT_PLUGIN_CONFIG: PluginConfig = { liveAccountSync: true, liveAccountSyncDebounceMs: 250, liveAccountSyncPollMs: 2_000, + codexCliSessionSupervisor: false, sessionAffinity: true, sessionAffinityTtlMs: 20 * 60_000, sessionAffinityMaxEntries: 512, @@ -155,7 +156,7 @@ export const DEFAULT_PLUGIN_CONFIG: PluginConfig = { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 5, + preemptiveQuotaRemainingPercent5h: 10, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, }; @@ -857,6 +858,25 @@ export function getLiveAccountSyncPollMs(pluginConfig: PluginConfig): number { ); } +/** + * Determines whether the CLI session supervisor wrapper is enabled. + * + * This accessor is synchronous, side-effect free, and safe for concurrent reads. + * It performs no filesystem I/O and does not expose token material. + * + * @param pluginConfig - The plugin configuration object used as the non-environment fallback + * @returns `true` when the session supervisor should wrap interactive Codex sessions + */ +export function getCodexCliSessionSupervisor( + pluginConfig: PluginConfig, +): boolean { + return resolveBooleanSetting( + "CODEX_AUTH_CLI_SESSION_SUPERVISOR", + pluginConfig.codexCliSessionSupervisor, + false, + ); +} + /** * Indicates whether session affinity is enabled. * @@ -1057,7 +1077,7 @@ export function getPreemptiveQuotaRemainingPercent5h(pluginConfig: PluginConfig) return resolveNumberSetting( "CODEX_AUTH_PREEMPTIVE_QUOTA_5H_REMAINING_PCT", pluginConfig.preemptiveQuotaRemainingPercent5h, - 5, + 10, { min: 0, max: 100 }, ); } diff --git a/lib/quota-probe.ts b/lib/quota-probe.ts index 9535b7f9..b93675a7 100644 --- a/lib/quota-probe.ts +++ b/lib/quota-probe.ts @@ -305,6 +305,13 @@ export interface ProbeCodexQuotaOptions { model?: string; fallbackModels?: readonly string[]; timeoutMs?: number; + signal?: AbortSignal; +} + +function createAbortError(message: string): Error { + const error = new Error(message); + error.name = "AbortError"; + return error; } /** @@ -331,6 +338,9 @@ export async function fetchCodexQuotaSnapshot( let lastError: Error | null = null; for (const model of models) { + if (options.signal?.aborted) { + throw createAbortError("Quota probe aborted"); + } try { const instructions = await getCodexInstructions(model); const probeBody: RequestBody = { @@ -356,6 +366,12 @@ export async function fetchCodexQuotaSnapshot( headers.set("content-type", "application/json"); const controller = new AbortController(); + const onAbort = () => controller.abort(options.signal?.reason); + if (options.signal?.aborted) { + controller.abort(options.signal.reason); + } else { + options.signal?.addEventListener("abort", onAbort, { once: true }); + } const timeout = setTimeout(() => controller.abort(), timeoutMs); let response: Response; try { @@ -367,6 +383,7 @@ export async function fetchCodexQuotaSnapshot( }); } finally { clearTimeout(timeout); + options.signal?.removeEventListener("abort", onAbort); } const snapshotBase = parseQuotaSnapshotBase(response.headers, response.status); @@ -406,9 +423,16 @@ export async function fetchCodexQuotaSnapshot( } lastError = new Error("Codex response did not include quota headers"); } catch (error) { + if (options.signal?.aborted) { + throw error instanceof Error ? error : createAbortError("Quota probe aborted"); + } lastError = error instanceof Error ? error : new Error(String(error)); } } + if (options.signal?.aborted) { + throw createAbortError("Quota probe aborted"); + } + throw lastError ?? new Error("Failed to fetch quotas"); } diff --git a/lib/schemas.ts b/lib/schemas.ts index dea8109c..3cd308d1 100644 --- a/lib/schemas.ts +++ b/lib/schemas.ts @@ -44,6 +44,7 @@ export const PluginConfigSchema = z.object({ liveAccountSync: z.boolean().optional(), liveAccountSyncDebounceMs: z.number().min(50).optional(), liveAccountSyncPollMs: z.number().min(500).optional(), + codexCliSessionSupervisor: z.boolean().optional(), sessionAffinity: z.boolean().optional(), sessionAffinityTtlMs: z.number().min(1_000).optional(), sessionAffinityMaxEntries: z.number().min(8).optional(), diff --git a/lib/storage.ts b/lib/storage.ts index 1ea0fc0b..6baf0b41 100644 --- a/lib/storage.ts +++ b/lib/storage.ts @@ -168,6 +168,7 @@ let storageMutex: Promise = Promise.resolve(); const transactionSnapshotContext = new AsyncLocalStorage<{ snapshot: AccountStorageV3 | null; active: boolean; + storagePath: string; }>(); function withStorageLock(fn: () => Promise): Promise { @@ -1912,18 +1913,24 @@ export async function withAccountStorageTransaction( ) => Promise, ): Promise { return withStorageLock(async () => { + const storagePath = getStoragePath(); const state = { snapshot: await loadAccountsInternal(saveAccountsUnlocked), active: true, + storagePath, }; const current = state.snapshot; const persist = async (storage: AccountStorageV3): Promise => { await saveAccountsUnlocked(storage); state.snapshot = storage; }; - return transactionSnapshotContext.run(state, () => - handler(current, persist), - ); + return transactionSnapshotContext.run(state, async () => { + try { + return await handler(current, persist); + } finally { + state.active = false; + } + }); }); } @@ -1937,9 +1944,11 @@ export async function withAccountAndFlaggedStorageTransaction( ) => Promise, ): Promise { return withStorageLock(async () => { + const storagePath = getStoragePath(); const state = { snapshot: await loadAccountsInternal(saveAccountsUnlocked), active: true, + storagePath, }; const current = state.snapshot; const persist = async ( @@ -1973,9 +1982,13 @@ export async function withAccountAndFlaggedStorageTransaction( throw error; } }; - return transactionSnapshotContext.run(state, () => - handler(current, persist), - ); + return transactionSnapshotContext.run(state, async () => { + try { + return await handler(current, persist); + } finally { + state.active = false; + } + }); }); } @@ -2308,13 +2321,16 @@ export async function exportAccounts( beforeCommit?: (resolvedPath: string) => Promise | void, ): Promise { const resolvedPath = resolvePath(filePath); + const activeStoragePath = getStoragePath(); if (!force && existsSync(resolvedPath)) { throw new Error(`File already exists: ${resolvedPath}`); } const transactionState = transactionSnapshotContext.getStore(); - const storage = transactionState?.active + const storage = + transactionState?.active && + transactionState.storagePath === activeStoragePath ? transactionState.snapshot : await withAccountStorageTransaction((current) => Promise.resolve(current), diff --git a/lib/ui/copy.ts b/lib/ui/copy.ts index 406e6a8a..15d67f55 100644 --- a/lib/ui/copy.ts +++ b/lib/ui/copy.ts @@ -72,6 +72,7 @@ export const UI_COPY = { experimentalHelpMenu: "Enter Select | Q Back", experimentalHelpPreview: "A Apply | Q Back", experimentalHelpStatus: "Enter Select | Q Back", + experimentalSessionSupervisor: "Enable Session Resume Supervisor", experimentalSync: "Sync Accounts to oc-chatgpt-multi-auth", experimentalApplySync: "Apply Sync", experimentalBackup: "Save Pool Backup", diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js new file mode 100644 index 00000000..f503a956 --- /dev/null +++ b/scripts/codex-supervisor.js @@ -0,0 +1,1267 @@ +import { spawn } from "node:child_process"; +import { createReadStream, promises as fs } from "node:fs"; +import { homedir } from "node:os"; +import { dirname, join, resolve as resolvePath } from "node:path"; +import process from "node:process"; +import { createInterface } from "node:readline"; + +const DEFAULT_POLL_MS = 750; +const DEFAULT_IDLE_MS = 400; +const DEFAULT_SESSION_CAPTURE_TIMEOUT_MS = 3_000; +const DEFAULT_SIGNAL_TIMEOUT_MS = process.platform === "win32" ? 125 : 500; +const DEFAULT_QUOTA_PROBE_TIMEOUT_MS = 4_000; +const DEFAULT_MONITOR_PROBE_TIMEOUT_MS = 2_000; +const DEFAULT_SELECTION_PROBE_TIMEOUT_MS = 4_000; +const DEFAULT_STORAGE_LOCK_WAIT_MS = 10_000; +const DEFAULT_STORAGE_LOCK_POLL_MS = 100; +const DEFAULT_STORAGE_LOCK_TTL_MS = 30_000; +const INTERNAL_RECOVERABLE_COOLDOWN_MS = 60_000; +const SESSION_ID_PATTERN = /^[A-Za-z0-9_][A-Za-z0-9_-]{0,127}$/; +const SESSION_META_SCAN_LINE_LIMIT = 200; +const MAX_ACCOUNT_SELECTION_ATTEMPTS = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_MAX_ACCOUNT_SELECTION_ATTEMPTS", + 32, + 1, +); +const MAX_SESSION_RESTARTS = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_MAX_RESTARTS", + 16, + 1, +); +const CODEX_FAMILY = "codex"; + +function sleep(ms, signal) { + return new Promise((resolve) => { + if (signal?.aborted) { + resolve(false); + return; + } + + let settled = false; + const finish = (completed) => { + if (settled) return; + settled = true; + clearTimeout(timer); + signal?.removeEventListener("abort", onAbort); + resolve(completed); + }; + const onAbort = () => finish(false); + const timer = setTimeout(() => finish(true), ms); + + signal?.addEventListener("abort", onAbort, { once: true }); + }); +} + +function createAbortError(message = "Operation aborted") { + const error = new Error(message); + error.name = "AbortError"; + return error; +} + +function parseBooleanEnv(name, fallback) { + const raw = (process.env[name] ?? "").trim().toLowerCase(); + if (raw === "1" || raw === "true") return true; + if (raw === "0" || raw === "false") return false; + return fallback; +} + +function parseNumberEnv(name, fallback, min = 0) { + const raw = Number(process.env[name]); + if (!Number.isFinite(raw)) return fallback; + return Math.max(min, Math.trunc(raw)); +} + +function resolveProbeTimeoutMs(name, fallback) { + const globalFallback = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_PROBE_TIMEOUT_MS", + fallback, + 1_000, + ); + return parseNumberEnv(name, globalFallback, 1_000); +} + +function resolveCodexHomeDir() { + const fromEnv = (process.env.CODEX_HOME ?? "").trim(); + if (fromEnv.length > 0) return fromEnv; + return join(homedir(), ".codex"); +} + +function getSessionsRootDir() { + const override = (process.env.CODEX_MULTI_AUTH_CLI_SESSIONS_DIR ?? "").trim(); + if (override.length > 0) return override; + return join(resolveCodexHomeDir(), "sessions"); +} + +function isInteractiveCommand(rawArgs) { + if (rawArgs.length === 0) return true; + const command = `${rawArgs[0] ?? ""}`.trim().toLowerCase(); + return command === "resume" || command === "fork"; +} + +function isNonInteractiveCommand(rawArgs) { + return !isInteractiveCommand(rawArgs); +} + +function isSupervisorAccountGateBypassCommand(rawArgs) { + if (rawArgs.length === 0) return false; + const normalizedArgs = rawArgs + .map((arg) => `${arg ?? ""}`.trim().toLowerCase()) + .filter((arg) => arg.length > 0); + if (normalizedArgs.length === 0) return false; + + const firstArg = normalizedArgs[0]; + if (firstArg === "auth" || firstArg === "help" || firstArg === "version") { + return true; + } + + return normalizedArgs.some( + (arg) => arg === "--help" || arg === "-h" || arg === "--version", + ); +} + +function readResumeSessionId(rawArgs) { + if ((rawArgs[0] ?? "").trim().toLowerCase() !== "resume") return null; + const sessionId = `${rawArgs[1] ?? ""}`.trim(); + return isValidSessionId(sessionId) ? sessionId : null; +} + +async function importIfPresent(specifier) { + try { + return await import(specifier); + } catch (error) { + if ( + error && + typeof error === "object" && + "code" in error && + error.code === "ERR_MODULE_NOT_FOUND" + ) { + return null; + } + throw error; + } +} + +async function loadSupervisorRuntime() { + const [configModule, accountsModule, quotaModule, storageModule] = + await Promise.all([ + importIfPresent("../dist/lib/config.js"), + importIfPresent("../dist/lib/accounts.js"), + importIfPresent("../dist/lib/quota-probe.js"), + importIfPresent("../dist/lib/storage.js"), + ]); + + if ( + !configModule || + !accountsModule?.AccountManager || + !quotaModule?.fetchCodexQuotaSnapshot + ) { + return null; + } + + return { + loadPluginConfig: configModule.loadPluginConfig, + getCodexCliSessionSupervisor: + configModule.getCodexCliSessionSupervisor ?? + ((pluginConfig) => pluginConfig.codexCliSessionSupervisor === true), + getRetryAllAccountsRateLimited: + configModule.getRetryAllAccountsRateLimited ?? + ((pluginConfig) => pluginConfig.retryAllAccountsRateLimited !== false), + getPreemptiveQuotaEnabled: + configModule.getPreemptiveQuotaEnabled ?? + ((pluginConfig) => pluginConfig.preemptiveQuotaEnabled !== false), + getPreemptiveQuotaRemainingPercent5h: + configModule.getPreemptiveQuotaRemainingPercent5h ?? + ((pluginConfig) => pluginConfig.preemptiveQuotaRemainingPercent5h ?? 10), + getPreemptiveQuotaRemainingPercent7d: + configModule.getPreemptiveQuotaRemainingPercent7d ?? + ((pluginConfig) => pluginConfig.preemptiveQuotaRemainingPercent7d ?? 5), + AccountManager: accountsModule.AccountManager, + fetchCodexQuotaSnapshot: quotaModule.fetchCodexQuotaSnapshot, + getStoragePath: storageModule?.getStoragePath, + }; +} + +function relaunchNotice(message) { + process.stderr.write(`codex-multi-auth: ${message}\n`); +} + +function normalizeExitCode(code, signal) { + if (signal) { + return signal === "SIGINT" ? 130 : 1; + } + return typeof code === "number" ? code : 1; +} + +function buildResumeArgs(sessionId, buildForwardArgs) { + return buildForwardArgs(["resume", sessionId]); +} + +function getCurrentAccount(manager) { + if (typeof manager.getCurrentAccountForFamily === "function") { + return manager.getCurrentAccountForFamily(CODEX_FAMILY); + } + if (typeof manager.getCurrentAccount === "function") { + return manager.getCurrentAccount(); + } + return null; +} + +function pickNextCandidate(manager) { + if (typeof manager.getCurrentOrNextForFamilyHybrid === "function") { + return manager.getCurrentOrNextForFamilyHybrid(CODEX_FAMILY); + } + if (typeof manager.getCurrentOrNext === "function") { + return manager.getCurrentOrNext(); + } + return null; +} + +function getNearestWaitMs(manager) { + if (typeof manager.getMinWaitTimeForFamily === "function") { + return Math.max(0, manager.getMinWaitTimeForFamily(CODEX_FAMILY)); + } + if (typeof manager.getMinWaitTime === "function") { + return Math.max(0, manager.getMinWaitTime()); + } + return 0; +} + +async function persistActiveSelection(manager, account) { + if (typeof manager.setActiveIndex === "function") { + manager.setActiveIndex(account.index); + } + if (typeof manager.syncCodexCliActiveSelectionForIndex === "function") { + await manager.syncCodexCliActiveSelectionForIndex(account.index); + } + if (typeof manager.saveToDisk === "function") { + await manager.saveToDisk(); + } +} + +async function safeUnlink(path) { + try { + await fs.unlink(path); + return true; + } catch (error) { + if ( + error && + typeof error === "object" && + "code" in error && + error.code === "ENOENT" + ) { + return true; + } + return false; + } +} + +function getSupervisorStoragePath(runtime) { + if (typeof runtime.getStoragePath === "function") { + try { + const storagePath = runtime.getStoragePath(); + if (typeof storagePath === "string" && storagePath.trim().length > 0) { + return storagePath; + } + } catch { + // Fall back to the default Codex home path. + } + } + + return join( + resolveCodexHomeDir(), + "multi-auth", + "openai-codex-accounts.json", + ); +} + +function getSupervisorStorageLockPath(runtime) { + return `${getSupervisorStoragePath(runtime)}.supervisor.lock`; +} + +function isValidSessionId(value) { + return SESSION_ID_PATTERN.test(`${value ?? ""}`.trim()); +} + +async function readSupervisorLockPayload(lockPath) { + try { + const raw = await fs.readFile(lockPath, "utf8"); + return JSON.parse(raw); + } catch { + return null; + } +} + +async function isSupervisorLockStale(lockPath, ttlMs) { + const now = Date.now(); + const payload = await readSupervisorLockPayload(lockPath); + if (payload && typeof payload.expiresAt === "number" && payload.expiresAt <= now) { + return true; + } + + try { + const stat = await fs.stat(lockPath); + return now - stat.mtimeMs > ttlMs; + } catch (error) { + if ( + error && + typeof error === "object" && + "code" in error && + error.code === "ENOENT" + ) { + return true; + } + console.warn( + `codex-multi-auth: treating unreadable supervisor lock as stale at ${lockPath}: ${ + error instanceof Error ? error.message : String(error) + }`, + ); + return true; + } +} + +async function withSupervisorStorageLock(runtime, fn, signal) { + const lockPath = getSupervisorStorageLockPath(runtime); + const lockDir = dirname(lockPath); + const waitMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_LOCK_WAIT_MS", + DEFAULT_STORAGE_LOCK_WAIT_MS, + 0, + ); + const pollMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_LOCK_POLL_MS", + DEFAULT_STORAGE_LOCK_POLL_MS, + 25, + ); + const ttlMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_LOCK_TTL_MS", + DEFAULT_STORAGE_LOCK_TTL_MS, + 1_000, + ); + + await fs.mkdir(lockDir, { recursive: true }); + + const deadline = Date.now() + waitMs; + while (true) { + if (signal?.aborted) { + throw createAbortError("Supervisor storage lock wait aborted"); + } + + try { + const handle = await fs.open(lockPath, "wx"); + try { + await handle.writeFile( + `${JSON.stringify({ + pid: process.pid, + acquiredAt: Date.now(), + expiresAt: Date.now() + ttlMs, + })}\n`, + "utf8", + ); + } finally { + await handle.close(); + } + + try { + return await fn(); + } finally { + await safeUnlink(lockPath); + } + } catch (error) { + const code = + error && typeof error === "object" && "code" in error + ? `${error.code ?? ""}` + : ""; + if (code !== "EEXIST") { + throw error; + } + + if (await isSupervisorLockStale(lockPath, ttlMs)) { + const removed = await safeUnlink(lockPath); + if (removed) continue; + } + + if (Date.now() >= deadline) { + throw new Error( + `Timed out waiting for supervisor storage lock at ${lockPath}`, + ); + } + + const slept = await sleep(pollMs, signal); + if (!slept) { + throw createAbortError("Supervisor storage lock wait aborted"); + } + } + } +} + +async function withLockedManager(runtime, mutate, signal) { + return withSupervisorStorageLock(runtime, async () => { + const manager = await runtime.AccountManager.loadFromDisk(); + return mutate(manager); + }, signal); +} + +function getManagerAccounts(manager, extraAccounts = []) { + const accounts = + typeof manager.getAccountsSnapshot === "function" + ? manager.getAccountsSnapshot() + : []; + const seen = new Set(); + const deduped = []; + for (const item of [...accounts, ...extraAccounts]) { + if (!item) continue; + const key = [ + `${item.index ?? ""}`, + `${item.refreshToken ?? ""}`, + `${item.accountId ?? ""}`, + `${item.email ?? ""}`, + ].join("|"); + if (seen.has(key)) continue; + seen.add(key); + deduped.push(item); + } + return deduped; +} + +function resolveUniqueFieldMatch(accounts, field, value) { + if (!value) return null; + const matches = accounts.filter((item) => item && item[field] === value); + return matches.length === 1 ? matches[0] : null; +} + +function resolveMatchingAccount(accounts, account) { + if (!account) return null; + if (account.refreshToken) { + const byRefreshToken = + accounts.find((item) => item?.refreshToken === account.refreshToken) ?? + null; + if (byRefreshToken) return byRefreshToken; + } + const byAccountId = resolveUniqueFieldMatch( + accounts, + "accountId", + account.accountId, + ); + if (byAccountId) return byAccountId; + const byEmail = resolveUniqueFieldMatch(accounts, "email", account.email); + if (byEmail) return byEmail; + return accounts.find((item) => item?.index === account.index) ?? null; +} + +function resolveAccountInManager(manager, account, knownAccounts = null) { + if (!account) return null; + + const direct = + typeof manager.getAccountByIndex === "function" + ? manager.getAccountByIndex(account.index) + : null; + const current = getCurrentAccount(manager); + const candidate = pickNextCandidate(manager); + const accounts = + knownAccounts ?? getManagerAccounts(manager, [direct, current, candidate]); + + if (direct && resolveMatchingAccount(accounts, account) === direct) return direct; + if (current && resolveMatchingAccount(accounts, account) === current) return current; + if (candidate && resolveMatchingAccount(accounts, account) === candidate) { + return candidate; + } + + return resolveMatchingAccount(accounts, account); +} + +function accountsReferToSameStoredAccount( + manager, + left, + right, + knownAccounts = null, +) { + const accounts = knownAccounts ?? getManagerAccounts(manager, [left, right]); + const resolvedLeft = resolveAccountInManager(manager, left, accounts); + const resolvedRight = resolveAccountInManager(manager, right, accounts); + return Boolean( + resolvedLeft && + resolvedRight && + resolvedLeft.index === resolvedRight.index && + `${resolvedLeft.refreshToken ?? ""}` === `${resolvedRight.refreshToken ?? ""}`, + ); +} + +function computeWaitMsFromSnapshot(snapshot) { + const now = Date.now(); + const candidates = [snapshot?.primary?.resetAtMs, snapshot?.secondary?.resetAtMs] + .filter((value) => typeof value === "number" && Number.isFinite(value)) + .map((value) => Math.max(0, value - now)) + .filter((value) => value > 0); + return candidates.length > 0 ? Math.min(...candidates) : 0; +} + +function evaluateQuotaSnapshot(snapshot, runtime, pluginConfig) { + if (!snapshot) { + return { rotate: false, reason: "none", waitMs: 0 }; + } + + if (snapshot.status === 429) { + return { + rotate: true, + reason: "rate-limit", + waitMs: computeWaitMsFromSnapshot(snapshot), + }; + } + + if (!runtime.getPreemptiveQuotaEnabled(pluginConfig)) { + return { rotate: false, reason: "none", waitMs: 0 }; + } + + const remaining5h = + typeof snapshot.primary?.usedPercent === "number" + ? Math.max(0, Math.round(100 - snapshot.primary.usedPercent)) + : undefined; + const remaining7d = + typeof snapshot.secondary?.usedPercent === "number" + ? Math.max(0, Math.round(100 - snapshot.secondary.usedPercent)) + : undefined; + const threshold5h = runtime.getPreemptiveQuotaRemainingPercent5h(pluginConfig); + const threshold7d = runtime.getPreemptiveQuotaRemainingPercent7d(pluginConfig); + const near5h = + typeof remaining5h === "number" && remaining5h <= threshold5h; + const near7d = + typeof remaining7d === "number" && remaining7d <= threshold7d; + + if (!near5h && !near7d) { + return { rotate: false, reason: "none", waitMs: 0 }; + } + + return { + rotate: true, + reason: "quota-near-exhaustion", + waitMs: computeWaitMsFromSnapshot(snapshot), + }; +} + +async function probeAccountSnapshot(runtime, account, signal, timeoutMs) { + if (signal?.aborted) { + throw createAbortError("Quota probe aborted"); + } + if (!account?.accountId || !account?.access) { + return null; + } + try { + return await runtime.fetchCodexQuotaSnapshot({ + accountId: account.accountId, + accessToken: account.access, + timeoutMs: timeoutMs ?? DEFAULT_QUOTA_PROBE_TIMEOUT_MS, + signal, + }); + } catch (error) { + if (signal?.aborted || error?.name === "AbortError") { + throw error; + } + return null; + } +} + +function markAccountUnavailable(manager, account, evaluation) { + const waitMs = Math.max( + evaluation.waitMs || 0, + evaluation.reason === "rate-limit" ? 1 : 0, + ); + + if (waitMs > 0 && typeof manager.markRateLimitedWithReason === "function") { + manager.markRateLimitedWithReason( + account, + waitMs, + CODEX_FAMILY, + evaluation.reason === "rate-limit" + ? "rate_limit_detected" + : "quota_near_exhaustion", + ); + return; + } + + if (typeof manager.markAccountCoolingDown === "function") { + manager.markAccountCoolingDown( + account, + INTERNAL_RECOVERABLE_COOLDOWN_MS, + evaluation.reason === "rate-limit" ? "rate-limit" : "network-error", + ); + } +} + +async function ensureLaunchableAccount( + runtime, + pluginConfig, + signal, + options = {}, +) { + const probeTimeoutMs = + options.probeTimeoutMs ?? DEFAULT_SELECTION_PROBE_TIMEOUT_MS; + let attempts = 0; + while (attempts < MAX_ACCOUNT_SELECTION_ATTEMPTS) { + attempts += 1; + if (signal?.aborted) { + return { ok: false, account: null, aborted: true }; + } + + const initial = await withLockedManager(runtime, async (manager) => { + const account = pickNextCandidate(manager); + if (!account) { + return { + kind: "wait", + waitMs: getNearestWaitMs(manager), + account: null, + }; + } + return { + kind: "probe", + account, + }; + }, signal); + + if (initial.kind === "wait") { + if (initial.waitMs <= 0 || !runtime.getRetryAllAccountsRateLimited(pluginConfig)) { + return { ok: false, account: null }; + } + + relaunchNotice( + `all accounts unavailable, waiting ${Math.ceil(initial.waitMs / 1000)}s for the next eligible window`, + ); + const slept = await sleep(initial.waitMs, signal); + if (!slept) { + return { ok: false, account: null, aborted: true }; + } + continue; + } + + let snapshot; + try { + snapshot = await probeAccountSnapshot( + runtime, + initial.account, + signal, + probeTimeoutMs, + ); + } catch (error) { + if (signal?.aborted || error?.name === "AbortError") { + return { ok: false, account: null, aborted: true }; + } + throw error; + } + const evaluation = evaluateQuotaSnapshot(snapshot, runtime, pluginConfig); + const step = await withLockedManager(runtime, async (manager) => { + const account = resolveAccountInManager(manager, initial.account); + const currentCandidate = pickNextCandidate(manager); + if ( + !account || + !currentCandidate || + !accountsReferToSameStoredAccount(manager, currentCandidate, account) + ) { + return { + kind: "retry", + waitMs: 0, + account: null, + manager, + }; + } + + if (!evaluation.rotate) { + await persistActiveSelection(manager, account); + return { + kind: "ready", + waitMs: 0, + account, + manager, + snapshot, + }; + } + + markAccountUnavailable(manager, account, evaluation); + if (typeof manager.saveToDisk === "function") { + await manager.saveToDisk(); + } + return { + kind: "retry", + waitMs: 0, + account: null, + manager, + }; + }, signal); + + if (step.kind === "ready") { + return { + ok: true, + ...step, + }; + } + } + + return { ok: false, account: null }; +} + +async function prepareResumeSelection({ + runtime, + pluginConfig, + currentAccount, + restartDecision, + signal, +}) { + const preparedManager = await withLockedManager(runtime, async (freshManager) => { + const targetAccount = resolveAccountInManager(freshManager, currentAccount); + if (targetAccount) { + markAccountUnavailable(freshManager, targetAccount, restartDecision); + if (typeof freshManager.saveToDisk === "function") { + await freshManager.saveToDisk(); + } + } + return freshManager; + }, signal); + + const nextReady = await ensureLaunchableAccount( + runtime, + pluginConfig, + signal, + { + probeTimeoutMs: resolveProbeTimeoutMs( + "CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_TIMEOUT_MS", + DEFAULT_SELECTION_PROBE_TIMEOUT_MS, + ), + }, + ); + + return { + manager: preparedManager, + nextReady, + }; +} + +async function listJsonlFiles(rootDir) { + const files = []; + const pending = [rootDir]; + while (pending.length > 0) { + const nextDir = pending.pop(); + if (!nextDir) continue; + let entries = []; + try { + entries = await fs.readdir(nextDir, { withFileTypes: true }); + } catch { + continue; + } + for (const entry of entries) { + const fullPath = join(nextDir, entry.name); + if (entry.isSymbolicLink()) { + continue; + } + if (entry.isDirectory()) { + pending.push(fullPath); + continue; + } + if (entry.isFile() && entry.name.endsWith(".jsonl")) { + files.push(fullPath); + } + } + } + return files; +} + +function normalizeCwd(value) { + if (typeof value !== "string") return ""; + const trimmed = value.trim(); + if (trimmed.length === 0) return ""; + const normalized = resolvePath(trimmed).replace(/[\\/]+$/, ""); + return process.platform === "win32" ? normalized.toLowerCase() : normalized; +} + +async function extractSessionMeta(filePath) { + let stream = null; + let lineReader = null; + try { + stream = createReadStream(filePath, { encoding: "utf8" }); + lineReader = createInterface({ + input: stream, + crlfDelay: Infinity, + }); + + let scannedLineCount = 0; + for await (const rawLine of lineReader) { + const line = rawLine.trim(); + if (!line) continue; + scannedLineCount += 1; + if (scannedLineCount > SESSION_META_SCAN_LINE_LIMIT) break; + + try { + const parsed = JSON.parse(line); + const payload = + parsed?.session_meta?.payload ?? + (parsed?.type === "session_meta" ? parsed.payload : null); + const sessionId = `${payload?.id ?? ""}`.trim(); + const cwd = `${payload?.cwd ?? ""}`.trim(); + if (isValidSessionId(sessionId)) { + return { + sessionId, + cwd, + }; + } + } catch { + // Ignore malformed log lines. + } + } + } catch { + return null; + } finally { + lineReader?.close(); + stream?.destroy(); + } + + return null; +} + +async function findSessionBinding({ cwd, sinceMs, sessionId }) { + const sessionsRoot = getSessionsRootDir(); + const cwdKey = normalizeCwd(cwd); + const files = ( + await Promise.all( + (await listJsonlFiles(sessionsRoot)).map(async (filePath) => { + try { + const stat = await fs.stat(filePath); + return { + filePath, + mtimeMs: stat.mtimeMs, + }; + } catch { + return null; + } + }), + ) + ) + .filter((entry) => entry && (sessionId ? true : entry.mtimeMs >= sinceMs - 2_000)) + .sort((left, right) => right.mtimeMs - left.mtimeMs); + + for (const entry of files) { + const meta = await extractSessionMeta(entry.filePath); + if (!meta) continue; + if (sessionId && meta.sessionId === sessionId) { + return { + sessionId: meta.sessionId, + rolloutPath: entry.filePath, + lastActivityAtMs: entry.mtimeMs, + }; + } + const metaCwdKey = normalizeCwd(meta.cwd); + if (!cwdKey || !metaCwdKey || metaCwdKey !== cwdKey) continue; + return { + sessionId: meta.sessionId, + rolloutPath: entry.filePath, + lastActivityAtMs: entry.mtimeMs, + }; + } + + return null; +} + +async function waitForSessionBinding({ + cwd, + sinceMs, + sessionId, + timeoutMs, + signal, +}) { + const deadline = Date.now() + timeoutMs; + while (Date.now() <= deadline) { + const binding = await findSessionBinding({ cwd, sinceMs, sessionId }); + if (binding) return binding; + const slept = await sleep(100, signal); + if (!slept) return null; + } + return null; +} + +async function refreshSessionActivity(binding) { + if (!binding?.rolloutPath) return binding; + try { + const stat = await fs.stat(binding.rolloutPath); + return { + ...binding, + lastActivityAtMs: stat.mtimeMs, + }; + } catch { + return binding; + } +} + +async function requestChildRestart(child, platform = process.platform, signal) { + if (child.exitCode !== null) return; + + const signalTimeoutMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS", + DEFAULT_SIGNAL_TIMEOUT_MS, + 50, + ); + const exitPromise = new Promise((resolve) => { + child.once("exit", () => resolve()); + }); + + if (platform !== "win32") { + child.kill("SIGINT"); + await Promise.race([exitPromise, sleep(signalTimeoutMs, signal)]); + if (child.exitCode !== null) return; + } + + child.kill("SIGTERM"); + await Promise.race([exitPromise, sleep(signalTimeoutMs, signal)]); + if (child.exitCode !== null) return; + + child.kill("SIGKILL"); + await Promise.race([exitPromise, sleep(signalTimeoutMs, signal)]); +} + +function spawnRealCodex(codexBin, args) { + return spawn(process.execPath, [codexBin, ...args], { + stdio: "inherit", + env: process.env, + }); +} + +async function runInteractiveSupervision({ + codexBin, + initialArgs, + buildForwardArgs, + runtime, + pluginConfig, + manager, + signal, +}) { + let launchArgs = initialArgs; + let knownSessionId = readResumeSessionId(initialArgs); + let launchCount = 0; + + while (launchCount < MAX_SESSION_RESTARTS) { + if (signal?.aborted) { + return 130; + } + launchCount += 1; + const child = spawnRealCodex(codexBin, launchArgs); + const launchStartedAt = Date.now(); + let binding = knownSessionId + ? await findSessionBinding({ + cwd: process.cwd(), + sinceMs: 0, + sessionId: knownSessionId, + }) + : null; + let requestedRestart = null; + let preparedResumeSelectionPromise = null; + let preparedResumeSelectionStarted = false; + let monitorActive = true; + const monitorController = new AbortController(); + + const pollMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_SUPERVISOR_POLL_MS", + DEFAULT_POLL_MS, + 250, + ); + const idleMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_SUPERVISOR_IDLE_MS", + DEFAULT_IDLE_MS, + 100, + ); + const captureTimeoutMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_CAPTURE_TIMEOUT_MS", + DEFAULT_SESSION_CAPTURE_TIMEOUT_MS, + 1_000, + ); + const monitorProbeTimeoutMs = resolveProbeTimeoutMs( + "CODEX_AUTH_CLI_SESSION_MONITOR_PROBE_TIMEOUT_MS", + DEFAULT_MONITOR_PROBE_TIMEOUT_MS, + ); + + const monitorPromise = (async () => { + while (monitorActive) { + if (!binding) { + binding = await waitForSessionBinding({ + cwd: process.cwd(), + sinceMs: launchStartedAt, + sessionId: knownSessionId, + timeoutMs: captureTimeoutMs, + signal: monitorController.signal, + }); + if (binding?.sessionId) { + knownSessionId = binding.sessionId; + } + } else { + binding = await refreshSessionActivity(binding); + } + + if (!requestedRestart) { + let currentState; + try { + currentState = await withLockedManager( + runtime, + async (freshManager) => ({ + manager: freshManager, + currentAccount: getCurrentAccount(freshManager), + }), + monitorController.signal, + ); + } catch (error) { + if (monitorController.signal.aborted || error?.name === "AbortError") { + break; + } + throw error; + } + manager = currentState.manager ?? manager; + const currentAccount = currentState.currentAccount; + if (currentAccount) { + let snapshot; + try { + snapshot = await probeAccountSnapshot( + runtime, + currentAccount, + monitorController.signal, + monitorProbeTimeoutMs, + ); + } catch (error) { + if (monitorController.signal.aborted || error?.name === "AbortError") { + break; + } + throw error; + } + const evaluation = evaluateQuotaSnapshot( + snapshot, + runtime, + pluginConfig, + ); + if (evaluation.rotate && binding?.sessionId) { + const lastActivityAtMs = binding.lastActivityAtMs ?? launchStartedAt; + if (Date.now() - lastActivityAtMs >= idleMs) { + requestedRestart = { + reason: evaluation.reason, + waitMs: evaluation.waitMs, + sessionId: binding.sessionId, + }; + preparedResumeSelectionStarted = true; + preparedResumeSelectionPromise = prepareResumeSelection({ + runtime, + pluginConfig, + currentAccount, + restartDecision: requestedRestart, + signal, + }).catch(() => null); + relaunchNotice( + `rotating session ${binding.sessionId} because ${evaluation.reason.replace(/-/g, " ")}`, + ); + monitorActive = false; + await requestChildRestart(child, process.platform, signal); + monitorController.abort(); + continue; + } + } + } + } + + const slept = await sleep(pollMs, monitorController.signal); + if (!slept) break; + } + })(); + + const result = await new Promise((resolve) => { + child.once("error", (error) => { + resolve({ + exitCode: 1, + error, + }); + }); + child.once("exit", (code, exitSignal) => { + resolve({ + exitCode: normalizeExitCode(code, exitSignal), + signal: exitSignal, + }); + }); + }); + + monitorActive = false; + monitorController.abort(); + await monitorPromise; + binding = + binding ?? + (await findSessionBinding({ + cwd: process.cwd(), + sinceMs: launchStartedAt, + sessionId: knownSessionId, + })); + if (binding?.sessionId) { + knownSessionId = binding.sessionId; + } + + let restartDecision = requestedRestart; + if (!restartDecision && result.exitCode !== 0 && knownSessionId) { + const refreshedState = await withLockedManager( + runtime, + async (freshManager) => ({ + manager: freshManager, + currentAccount: getCurrentAccount(freshManager), + }), + signal, + ); + manager = refreshedState.manager ?? manager; + if (signal?.aborted) { + return result.exitCode; + } + const snapshot = refreshedState.currentAccount + ? await probeAccountSnapshot(runtime, refreshedState.currentAccount, signal) + : null; + const evaluation = evaluateQuotaSnapshot(snapshot, runtime, pluginConfig); + if (evaluation.rotate) { + restartDecision = { + reason: evaluation.reason, + waitMs: evaluation.waitMs, + sessionId: knownSessionId, + }; + } + } + + if (!restartDecision) { + return result.exitCode; + } + + if (!restartDecision.sessionId) { + relaunchNotice( + "rotation needed but no resumable session was captured; re-run `codex` manually", + ); + return result.exitCode; + } + + let nextReady = + preparedResumeSelectionPromise && + (await preparedResumeSelectionPromise.then((prepared) => { + if (prepared?.manager) { + manager = prepared.manager; + } + return prepared?.nextReady ?? null; + })); + + if (!nextReady) { + const currentAccount = getCurrentAccount(manager); + if (currentAccount && !preparedResumeSelectionStarted) { + const refreshed = await withLockedManager(runtime, async (freshManager) => { + const targetAccount = resolveAccountInManager(freshManager, currentAccount); + if (targetAccount) { + markAccountUnavailable(freshManager, targetAccount, restartDecision); + if (typeof freshManager.saveToDisk === "function") { + await freshManager.saveToDisk(); + } + } + return freshManager; + }, signal); + manager = refreshed; + } + + nextReady = await ensureLaunchableAccount(runtime, pluginConfig, signal, { + probeTimeoutMs: resolveProbeTimeoutMs( + "CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_TIMEOUT_MS", + DEFAULT_SELECTION_PROBE_TIMEOUT_MS, + ), + }); + } + if (nextReady.aborted) { + return 130; + } + if (!nextReady.ok) { + relaunchNotice( + `no healthy account available to resume ${restartDecision.sessionId}; recover manually with \`codex resume ${restartDecision.sessionId}\` when quota resets`, + ); + return result.exitCode; + } + + manager = nextReady.manager ?? manager; + launchArgs = buildResumeArgs(restartDecision.sessionId, buildForwardArgs); + knownSessionId = restartDecision.sessionId; + } + + relaunchNotice("session supervisor reached the restart safety limit"); + return 1; +} + +export async function runCodexSupervisorIfEnabled({ + codexBin, + rawArgs, + buildForwardArgs, + forwardToRealCodex, +}) { + const controller = new AbortController(); + const abort = () => controller.abort(); + process.once("SIGINT", abort); + process.once("SIGTERM", abort); + + try { + const runtime = await loadSupervisorRuntime(); + if (!runtime) { + return null; + } + + const pluginConfig = runtime.loadPluginConfig(); + if (!runtime.getCodexCliSessionSupervisor(pluginConfig)) { + return null; + } + + const initialArgs = buildForwardArgs(rawArgs); + if (isSupervisorAccountGateBypassCommand(rawArgs)) { + return forwardToRealCodex(codexBin, initialArgs); + } + + const ready = await ensureLaunchableAccount( + runtime, + pluginConfig, + controller.signal, + ); + if (ready.aborted) { + return 130; + } + if (!ready.ok) { + relaunchNotice("no launchable account is currently available"); + return 1; + } + + if (isNonInteractiveCommand(rawArgs)) { + return forwardToRealCodex(codexBin, initialArgs); + } + + return runInteractiveSupervision({ + codexBin, + initialArgs, + buildForwardArgs, + runtime, + pluginConfig, + manager: ready.manager, + signal: controller.signal, + }); + } catch (error) { + if (error?.name === "AbortError") { + return 130; + } + throw error; + } finally { + process.off("SIGINT", abort); + process.off("SIGTERM", abort); + } +} + +const TEST_ONLY_API = { + evaluateQuotaSnapshot, + ensureLaunchableAccount, + findSessionBinding, + extractSessionMeta, + isInteractiveCommand, + isValidSessionId, + listJsonlFiles, + probeAccountSnapshot, + readResumeSessionId, + requestChildRestart, + resolveCodexHomeDir, + getSessionsRootDir, + sleep, + withLockedManager, + getSupervisorStorageLockPath, + runInteractiveSupervision, +}; + +export const __testOnly = + process.env.NODE_ENV === "test" ? TEST_ONLY_API : undefined; diff --git a/scripts/codex.js b/scripts/codex.js index 14487b38..1c09c970 100755 --- a/scripts/codex.js +++ b/scripts/codex.js @@ -7,6 +7,7 @@ import { basename, delimiter, dirname, join, resolve as resolvePath } from "node import process from "node:process"; import { fileURLToPath } from "node:url"; import { normalizeAuthAlias, shouldHandleMultiAuthAuth } from "./codex-routing.js"; +import { runCodexSupervisorIfEnabled } from "./codex-supervisor.js"; function hydrateCliVersionEnv() { try { @@ -524,8 +525,18 @@ async function main() { return 1; } - await autoSyncManagerActiveSelectionIfEnabled(); const forwardArgs = buildForwardArgs(rawArgs); + const supervisedExitCode = await runCodexSupervisorIfEnabled({ + codexBin: realCodexBin, + rawArgs, + buildForwardArgs, + forwardToRealCodex, + }); + await autoSyncManagerActiveSelectionIfEnabled(); + if (supervisedExitCode !== null) { + return supervisedExitCode; + } + return forwardToRealCodex(realCodexBin, forwardArgs); } diff --git a/test/codex-bin-wrapper.test.ts b/test/codex-bin-wrapper.test.ts index cb173334..2921ca52 100644 --- a/test/codex-bin-wrapper.test.ts +++ b/test/codex-bin-wrapper.test.ts @@ -57,9 +57,58 @@ function createWrapperFixture(): string { join(repoRootDir, "scripts", "codex-routing.js"), join(scriptDir, "codex-routing.js"), ); + copyFileSync( + join(repoRootDir, "scripts", "codex-supervisor.js"), + join(scriptDir, "codex-supervisor.js"), + ); return fixtureRoot; } +function writeSupervisorRuntimeFixture(fixtureRoot: string): void { + const distLibDir = join(fixtureRoot, "dist", "lib"); + mkdirSync(distLibDir, { recursive: true }); + writeFileSync( + join(distLibDir, "config.js"), + [ + "export function loadPluginConfig() {", + "\treturn {", + "\t\tcodexCliSessionSupervisor: true,", + "\t\tretryAllAccountsRateLimited: true,", + "\t\tpreemptiveQuotaEnabled: true,", + "\t\tpreemptiveQuotaRemainingPercent5h: 10,", + "\t\tpreemptiveQuotaRemainingPercent7d: 5,", + "\t};", + "}", + ].join("\n"), + "utf8", + ); + writeFileSync( + join(distLibDir, "accounts.js"), + [ + "export class AccountManager {", + "\tstatic async loadFromDisk() {", + "\t\treturn new AccountManager();", + "\t}", + "\tgetCurrentOrNextForFamilyHybrid() {", + '\t\treturn { index: 0, email: "healthy@example.com" };', + "\t}", + "\tsetActiveIndex() {}", + "\tasync saveToDisk() {}", + "}", + ].join("\n"), + "utf8", + ); + writeFileSync( + join(distLibDir, "quota-probe.js"), + [ + "export async function fetchCodexQuotaSnapshot() {", + "\treturn null;", + "}", + ].join("\n"), + "utf8", + ); +} + function createFakeCodexBin(rootDir: string): string { const fakeBin = join(rootDir, "fake-codex.js"); writeFileSync( @@ -358,6 +407,10 @@ describe("codex bin wrapper", () => { join(repoRootDir, "scripts", "codex-routing.js"), join(scriptDir, "codex-routing.js"), ); + copyFileSync( + join(repoRootDir, "scripts", "codex-supervisor.js"), + join(scriptDir, "codex-supervisor.js"), + ); writeFileSync( join(globalShimDir, "codex-multi-auth.cmd"), "@ECHO OFF\r\nREM real shim\r\n", @@ -539,4 +592,20 @@ describe("codex bin wrapper", () => { ); } }); + + it("uses the supervisor wrapper for non-interactive commands when enabled", () => { + const fixtureRoot = createWrapperFixture(); + writeSupervisorRuntimeFixture(fixtureRoot); + const fakeBin = createFakeCodexBin(fixtureRoot); + + const result = runWrapper(fixtureRoot, ["exec", "status"], { + CODEX_MULTI_AUTH_REAL_CODEX_BIN: fakeBin, + CODEX_AUTH_CLI_SESSION_SUPERVISOR: "1", + }); + + expect(result.status).toBe(0); + expect(result.stdout).toContain( + 'FORWARDED:exec status -c cli_auth_credentials_store="file"', + ); + }); }); diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts new file mode 100644 index 00000000..9672c14b --- /dev/null +++ b/test/codex-supervisor.test.ts @@ -0,0 +1,112 @@ +import { EventEmitter } from "node:events"; +import { mkdtempSync, promises as fs } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, describe, expect, it, vi } from "vitest"; +import { __testOnly as supervisorTestApi } from "../scripts/codex-supervisor.js"; + +const createdDirs: string[] = []; + +async function removeDirectoryWithRetry(dir: string): Promise { + const retryableCodes = new Set(["ENOTEMPTY", "EPERM", "EBUSY"]); + for (let attempt = 1; attempt <= 6; attempt += 1) { + try { + await fs.rm(dir, { recursive: true, force: true }); + return; + } catch (error) { + const code = + error && typeof error === "object" && "code" in error + ? `${error.code ?? ""}` + : ""; + if (!retryableCodes.has(code) || attempt === 6) { + throw error; + } + await new Promise((resolve) => setTimeout(resolve, attempt * 50)); + } + } +} + +function createTempDir(): string { + const dir = mkdtempSync(join(tmpdir(), "codex-supervisor-test-")); + createdDirs.push(dir); + return dir; +} + +afterEach(async () => { + vi.useRealTimers(); + for (const dir of createdDirs.splice(0, createdDirs.length).reverse()) { + await removeDirectoryWithRetry(dir); + } +}); + +describe("codex supervisor", () => { + it("finds session metadata when it lands on the 200th non-empty line", async () => { + expect(supervisorTestApi).toBeDefined(); + const dir = createTempDir(); + const filePath = join(dir, "boundary.jsonl"); + const preamble = Array.from({ length: 199 }, (_unused, index) => + JSON.stringify({ type: "event", seq: index + 1 }), + ); + await fs.writeFile( + filePath, + [ + ...preamble, + JSON.stringify({ + session_meta: { + payload: { id: "boundary-session", cwd: dir }, + }, + }), + ].join("\n"), + "utf8", + ); + + await expect(supervisorTestApi?.extractSessionMeta(filePath)).resolves.toEqual({ + sessionId: "boundary-session", + cwd: dir, + }); + }); + + it("misses session metadata beyond the 200-line scan limit", async () => { + const dir = createTempDir(); + const filePath = join(dir, "over-limit.jsonl"); + const preamble = Array.from({ length: 200 }, (_unused, index) => + JSON.stringify({ type: "event", seq: index + 1 }), + ); + await fs.writeFile( + filePath, + [ + ...preamble, + JSON.stringify({ + session_meta: { + payload: { id: "missed-session", cwd: dir }, + }, + }), + ].join("\n"), + "utf8", + ); + + await expect(supervisorTestApi?.extractSessionMeta(filePath)).resolves.toBeNull(); + }); + + it("interrupts child restart waits when the abort signal fires", async () => { + vi.useFakeTimers(); + class FakeChild extends EventEmitter { + exitCode: number | null = null; + kill = vi.fn((_signal: string) => true); + } + + const child = new FakeChild(); + const controller = new AbortController(); + const pending = supervisorTestApi?.requestChildRestart( + child, + "win32", + controller.signal, + ); + + controller.abort(); + await vi.runAllTimersAsync(); + await expect(pending).resolves.toBeUndefined(); + expect(child.kill).toHaveBeenCalledWith("SIGTERM"); + expect(child.kill).toHaveBeenCalledWith("SIGKILL"); + }); +}); diff --git a/test/plugin-config.test.ts b/test/plugin-config.test.ts index 9caebf96..f5a9f3fd 100644 --- a/test/plugin-config.test.ts +++ b/test/plugin-config.test.ts @@ -21,6 +21,7 @@ import { getPreemptiveQuotaRemainingPercent5h, getPreemptiveQuotaRemainingPercent7d, getPreemptiveQuotaMaxDeferralMs, + getCodexCliSessionSupervisor, } from '../lib/config.js'; import type { PluginConfig } from '../lib/types.js'; import * as fs from 'node:fs'; @@ -67,6 +68,7 @@ describe('Plugin Configuration', () => { 'CODEX_AUTH_PREEMPTIVE_QUOTA_5H_REMAINING_PCT', 'CODEX_AUTH_PREEMPTIVE_QUOTA_7D_REMAINING_PCT', 'CODEX_AUTH_PREEMPTIVE_QUOTA_MAX_DEFERRAL_MS', + 'CODEX_AUTH_CLI_SESSION_SUPERVISOR', ] as const; const originalEnv: Partial> = {}; @@ -136,9 +138,10 @@ describe('Plugin Configuration', () => { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 5, + preemptiveQuotaRemainingPercent5h: 10, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, + codexCliSessionSupervisor: false, }); // existsSync is called with multiple candidate config paths (primary + legacy fallbacks) expect(mockExistsSync).toHaveBeenCalled(); @@ -194,9 +197,10 @@ describe('Plugin Configuration', () => { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 5, + preemptiveQuotaRemainingPercent5h: 10, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, + codexCliSessionSupervisor: false, }); }); @@ -449,9 +453,10 @@ describe('Plugin Configuration', () => { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 5, + preemptiveQuotaRemainingPercent5h: 10, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, + codexCliSessionSupervisor: false, }); }); @@ -513,9 +518,10 @@ describe('Plugin Configuration', () => { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 5, + preemptiveQuotaRemainingPercent5h: 10, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, + codexCliSessionSupervisor: false, }); expect(mockLogWarn).toHaveBeenCalled(); }); @@ -571,9 +577,10 @@ describe('Plugin Configuration', () => { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 5, + preemptiveQuotaRemainingPercent5h: 10, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, + codexCliSessionSupervisor: false, }); expect(mockLogWarn).toHaveBeenCalled(); }); @@ -964,7 +971,7 @@ describe('Plugin Configuration', () => { describe('preemptive quota settings', () => { it('should use default thresholds', () => { expect(getPreemptiveQuotaEnabled({})).toBe(true); - expect(getPreemptiveQuotaRemainingPercent5h({})).toBe(5); + expect(getPreemptiveQuotaRemainingPercent5h({})).toBe(10); expect(getPreemptiveQuotaRemainingPercent7d({})).toBe(5); expect(getPreemptiveQuotaMaxDeferralMs({})).toBe(2 * 60 * 60_000); }); @@ -980,5 +987,17 @@ describe('Plugin Configuration', () => { expect(getPreemptiveQuotaMaxDeferralMs({ preemptiveQuotaMaxDeferralMs: 2_000 })).toBe(123000); }); }); + + describe('CLI session supervisor setting', () => { + it('should default the supervisor wrapper to disabled', () => { + expect(getCodexCliSessionSupervisor({})).toBe(false); + }); + + it('should prioritize environment override for the supervisor wrapper', () => { + process.env.CODEX_AUTH_CLI_SESSION_SUPERVISOR = '1'; + expect(getCodexCliSessionSupervisor({ codexCliSessionSupervisor: false })).toBe(true); + delete process.env.CODEX_AUTH_CLI_SESSION_SUPERVISOR; + }); + }); }); diff --git a/test/quota-probe.test.ts b/test/quota-probe.test.ts index 96e9605f..59db37ee 100644 --- a/test/quota-probe.test.ts +++ b/test/quota-probe.test.ts @@ -170,6 +170,39 @@ describe("quota-probe", () => { await assertion; expect(fetchMock).toHaveBeenCalledTimes(1); }); + + it("aborts immediately when the caller abort signal fires", async () => { + const controller = new AbortController(); + const fetchMock = vi.fn((_url: string, init?: RequestInit) => { + return new Promise((_resolve, reject) => { + init?.signal?.addEventListener( + "abort", + () => { + const error = new Error("aborted"); + (error as Error & { name?: string }).name = "AbortError"; + reject(error); + }, + { once: true }, + ); + }); + }); + vi.stubGlobal("fetch", fetchMock); + + const pending = fetchCodexQuotaSnapshot({ + accountId: "acc-abort", + accessToken: "token-abort", + model: "gpt-5-codex", + fallbackModels: [], + timeoutMs: 30_000, + signal: controller.signal, + }); + + await Promise.resolve(); + controller.abort(); + + await expect(pending).rejects.toThrow(/abort/i); + expect(fetchMock).toHaveBeenCalledTimes(1); + }); it("parses reset-at values expressed as epoch seconds and epoch milliseconds", async () => { const nowSec = Math.floor(Date.now() / 1000); const primarySeconds = nowSec + 120; diff --git a/test/settings-hub-utils.test.ts b/test/settings-hub-utils.test.ts index 2c56244b..4bfaf0b3 100644 --- a/test/settings-hub-utils.test.ts +++ b/test/settings-hub-utils.test.ts @@ -1,4 +1,4 @@ -import { mkdtempSync, rmSync } from "node:fs"; +import { mkdtempSync, promises as fs } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; @@ -134,6 +134,25 @@ const originalCodeHome = process.env.CODEX_HOME; const originalCodeMultiAuthDir = process.env.CODEX_MULTI_AUTH_DIR; const originalConfigPath = process.env.CODEX_MULTI_AUTH_CONFIG_PATH; +async function removeDirectoryWithRetry(dir: string): Promise { + const retryableCodes = new Set(["ENOTEMPTY", "EPERM", "EBUSY"]); + for (let attempt = 1; attempt <= 6; attempt += 1) { + try { + await fs.rm(dir, { recursive: true, force: true }); + return; + } catch (error) { + const code = + error && typeof error === "object" && "code" in error + ? `${error.code ?? ""}` + : ""; + if (!retryableCodes.has(code) || attempt === 6) { + throw error; + } + await new Promise((resolve) => setTimeout(resolve, attempt * 50)); + } + } +} + async function loadSettingsHubTestApi(): Promise { const module = await import("../lib/codex-manager/settings-hub.js"); return module.__testOnly as SettingsHubTestApi; @@ -164,9 +183,6 @@ beforeEach(() => { afterEach(() => { vi.restoreAllMocks(); vi.resetModules(); - if (tempRoot.length > 0) { - rmSync(tempRoot, { recursive: true, force: true }); - } if (originalCodeHome === undefined) { delete process.env.CODEX_HOME; } else { @@ -186,6 +202,12 @@ afterEach(() => { restoreStreamIsTTY(process.stdout, originalStdoutDescriptor); }); +afterEach(async () => { + if (tempRoot.length > 0) { + await removeDirectoryWithRetry(tempRoot); + } +}); + describe("settings-hub utility coverage", () => { it("clamps backend numeric settings by option bounds", async () => { const api = await loadSettingsHubTestApi(); @@ -687,5 +709,17 @@ describe("settings-hub utility coverage", () => { }); expect(selected?.proactiveRefreshIntervalMs).toBe(60_000); }); + + it("toggles the CLI session supervisor in experimental settings", async () => { + const api = await loadSettingsHubTestApi(); + queueSelectResults( + { type: "toggle-session-supervisor" }, + { type: "save" }, + ); + const selected = await api.promptExperimentalSettings({ + codexCliSessionSupervisor: false, + }); + expect(selected?.codexCliSessionSupervisor).toBe(true); + }); }); }); From 9823587a6ea1e11380ced7fad86e0692109367c0 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 19:52:56 +0800 Subject: [PATCH 02/24] speed-up-supervisor-smoke-coverage --- package.json | 3 + scripts/benchmark-session-supervisor.mjs | 276 +++++++++++++++++++++++ scripts/codex-supervisor.js | 20 +- test/codex-supervisor.test.ts | 251 +++++++++++++++++++++ 4 files changed, 543 insertions(+), 7 deletions(-) create mode 100644 scripts/benchmark-session-supervisor.mjs diff --git a/package.json b/package.json index 734ea8c7..b65d342c 100644 --- a/package.json +++ b/package.json @@ -51,11 +51,14 @@ "test:model-matrix": "node scripts/test-model-matrix.js", "test:model-matrix:smoke": "node scripts/test-model-matrix.js --smoke", "test:model-matrix:report": "node scripts/test-model-matrix.js --smoke --report-json=.tmp/model-matrix-report.json", + "test:session-supervisor:smoke": "vitest run test/codex-supervisor.test.ts test/codex-bin-wrapper.test.ts test/plugin-config.test.ts test/quota-probe.test.ts test/settings-hub-utils.test.ts", "clean:repo": "node scripts/repo-hygiene.js clean --mode aggressive", "clean:repo:check": "node scripts/repo-hygiene.js check", "bench:edit-formats": "node scripts/benchmark-edit-formats.mjs --preset=codex-core", "bench:edit-formats:smoke": "node scripts/benchmark-edit-formats.mjs --smoke --preset=codex-core", "bench:edit-formats:render": "node scripts/benchmark-render-dashboard.mjs", + "bench:session-supervisor": "node scripts/benchmark-session-supervisor.mjs", + "bench:session-supervisor:smoke": "node scripts/benchmark-session-supervisor.mjs --smoke", "bench:runtime-path": "npm run build && node scripts/benchmark-runtime-path.mjs", "bench:runtime-path:quick": "node scripts/benchmark-runtime-path.mjs", "test:coverage": "vitest run --coverage", diff --git a/scripts/benchmark-session-supervisor.mjs b/scripts/benchmark-session-supervisor.mjs new file mode 100644 index 00000000..66123002 --- /dev/null +++ b/scripts/benchmark-session-supervisor.mjs @@ -0,0 +1,276 @@ +#!/usr/bin/env node + +import { EventEmitter } from "node:events"; +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { dirname, join, resolve } from "node:path"; +import { performance } from "node:perf_hooks"; +import process from "node:process"; + +function argValue(args, name) { + const prefix = `${name}=`; + const match = args.find((arg) => arg.startsWith(prefix)); + return match ? match.slice(prefix.length) : undefined; +} + +function parsePositiveInt(value, fallback) { + if (!value) return fallback; + const parsed = Number.parseInt(value, 10); + if (!Number.isFinite(parsed) || parsed <= 0) return fallback; + return parsed; +} + +function average(values) { + if (values.length === 0) return 0; + return values.reduce((sum, value) => sum + value, 0) / values.length; +} + +function round(value) { + return Number(value.toFixed(3)); +} + +class FakeChild extends EventEmitter { + constructor() { + super(); + this.exitCode = null; + this.killCalls = []; + } + + kill(signal) { + this.killCalls.push(signal); + return true; + } +} + +class FakeManager { + constructor(accounts) { + this.accounts = accounts.map((account, index) => ({ + index, + refreshToken: `rt_${account.accountId}`, + email: `${account.accountId}@example.com`, + enabled: true, + cooldownUntil: 0, + ...account, + })); + this.activeIndex = 0; + } + + getAccountsSnapshot() { + return this.accounts.map((account) => ({ ...account })); + } + + getAccountByIndex(index) { + return this.accounts.find((account) => account.index === index) ?? null; + } + + getCurrentAccountForFamily() { + return this.getAccountByIndex(this.activeIndex); + } + + getCurrentOrNextForFamilyHybrid() { + const now = Date.now(); + const ordered = [ + this.getCurrentAccountForFamily(), + ...this.accounts.filter((account) => account.index !== this.activeIndex), + ].filter(Boolean); + return ( + ordered.find( + (account) => account.enabled !== false && (account.cooldownUntil ?? 0) <= now, + ) ?? null + ); + } + + getMinWaitTimeForFamily() { + const now = Date.now(); + const waits = this.accounts + .map((account) => Math.max(0, (account.cooldownUntil ?? 0) - now)) + .filter((waitMs) => waitMs > 0); + return waits.length > 0 ? Math.min(...waits) : 0; + } + + markRateLimitedWithReason(account, waitMs) { + const target = this.getAccountByIndex(account.index); + if (!target) return; + target.cooldownUntil = Date.now() + Math.max(waitMs, 1); + } + + markAccountCoolingDown(account, waitMs) { + this.markRateLimitedWithReason(account, waitMs); + } + + setActiveIndex(index) { + this.activeIndex = index; + } + + async syncCodexCliActiveSelectionForIndex() {} + + async saveToDisk() {} +} + +async function buildRuntime(probeLatencyMs, tempRoot) { + const pluginConfig = { + preemptiveQuotaEnabled: true, + preemptiveQuotaRemainingPercent5h: 10, + preemptiveQuotaRemainingPercent7d: 5, + retryAllAccountsRateLimited: true, + }; + const manager = new FakeManager([ + { accountId: "near-limit", access: "token-1" }, + { accountId: "healthy", access: "token-2" }, + ]); + const quotaByAccountId = new Map([ + [ + "near-limit", + { + status: 200, + primary: { usedPercent: 91 }, + secondary: { usedPercent: 12 }, + }, + ], + [ + "healthy", + { + status: 200, + primary: { usedPercent: 25 }, + secondary: { usedPercent: 8 }, + }, + ], + ]); + + const runtime = { + AccountManager: { + async loadFromDisk() { + return manager; + }, + }, + getStoragePath() { + return join(tempRoot, "accounts.json"); + }, + getPreemptiveQuotaEnabled(config) { + return config.preemptiveQuotaEnabled !== false; + }, + getPreemptiveQuotaRemainingPercent5h(config) { + return config.preemptiveQuotaRemainingPercent5h ?? 10; + }, + getPreemptiveQuotaRemainingPercent7d(config) { + return config.preemptiveQuotaRemainingPercent7d ?? 5; + }, + getRetryAllAccountsRateLimited(config) { + return config.retryAllAccountsRateLimited !== false; + }, + async fetchCodexQuotaSnapshot({ accountId, signal }) { + await new Promise((resolve, reject) => { + const timer = setTimeout(resolve, probeLatencyMs); + if (!signal) return; + const onAbort = () => { + clearTimeout(timer); + const error = new Error("Quota probe aborted"); + error.name = "AbortError"; + reject(error); + }; + signal.addEventListener("abort", onAbort, { once: true }); + }); + return quotaByAccountId.get(accountId) ?? null; + }, + }; + + return { runtime, pluginConfig, manager }; +} + +async function runCase(api, name, iterations, probeLatencyMs) { + const tempRoot = await mkdtemp(join(tmpdir(), "codex-supervisor-bench-")); + const serialDurations = []; + const overlapDurations = []; + + try { + for (let iteration = 0; iteration < iterations; iteration += 1) { + process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "75"; + const serialEnv = await buildRuntime(probeLatencyMs, tempRoot); + let start = performance.now(); + await api.requestChildRestart(new FakeChild(), "win32"); + await api.ensureLaunchableAccount( + serialEnv.runtime, + serialEnv.pluginConfig, + new AbortController().signal, + { probeTimeoutMs: probeLatencyMs + 250 }, + ); + serialDurations.push(performance.now() - start); + + const overlapEnv = await buildRuntime(probeLatencyMs, tempRoot); + start = performance.now(); + await Promise.all([ + api.requestChildRestart(new FakeChild(), "win32"), + api.ensureLaunchableAccount( + overlapEnv.runtime, + overlapEnv.pluginConfig, + new AbortController().signal, + { probeTimeoutMs: probeLatencyMs + 250 }, + ), + ]); + overlapDurations.push(performance.now() - start); + } + } finally { + delete process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS; + await rm(tempRoot, { recursive: true, force: true }); + } + + const serialAvgMs = average(serialDurations); + const overlapAvgMs = average(overlapDurations); + return { + name, + iterations, + probeLatencyMs, + serialAvgMs: round(serialAvgMs), + overlapAvgMs: round(overlapAvgMs), + improvementMs: round(serialAvgMs - overlapAvgMs), + improvementPct: + serialAvgMs <= 0 ? 0 : round(((serialAvgMs - overlapAvgMs) / serialAvgMs) * 100), + }; +} + +async function main() { + const args = process.argv.slice(2); + const smoke = args.includes("--smoke"); + const iterations = parsePositiveInt(argValue(args, "--iterations"), smoke ? 4 : 12); + const probeLatencyMs = parsePositiveInt( + argValue(args, "--probe-latency-ms"), + smoke ? 120 : 180, + ); + const outputPath = argValue(args, "--output"); + + process.env.NODE_ENV = "test"; + const { __testOnly: api } = await import("./codex-supervisor.js"); + if (!api) { + throw new Error("benchmark requires codex-supervisor test helpers"); + } + + const payload = { + generatedAt: new Date().toISOString(), + node: process.version, + iterations, + results: [ + await runCase(api, "session_rotation_overlap_windows", iterations, probeLatencyMs), + ], + }; + + if (outputPath) { + const resolved = resolve(outputPath); + await import("node:fs/promises").then(({ mkdir, writeFile }) => + mkdir(dirname(resolved), { recursive: true }).then(() => + writeFile(resolved, `${JSON.stringify(payload, null, 2)}\n`, "utf8"), + ), + ); + console.log(`Session supervisor benchmark written: ${resolved}`); + } + + console.log(JSON.stringify(payload, null, 2)); +} + +main().catch((error) => { + console.error( + `Session supervisor benchmark failed: ${ + error instanceof Error ? error.message : String(error) + }`, + ); + process.exit(1); +}); diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index f503a956..1113ed5a 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -5,13 +5,14 @@ import { dirname, join, resolve as resolvePath } from "node:path"; import process from "node:process"; import { createInterface } from "node:readline"; -const DEFAULT_POLL_MS = 750; -const DEFAULT_IDLE_MS = 400; -const DEFAULT_SESSION_CAPTURE_TIMEOUT_MS = 3_000; -const DEFAULT_SIGNAL_TIMEOUT_MS = process.platform === "win32" ? 125 : 500; +const DEFAULT_POLL_MS = 300; +const DEFAULT_IDLE_MS = 250; +const DEFAULT_SESSION_CAPTURE_TIMEOUT_MS = 1_500; +const DEFAULT_SIGNAL_TIMEOUT_MS = process.platform === "win32" ? 75 : 350; const DEFAULT_QUOTA_PROBE_TIMEOUT_MS = 4_000; -const DEFAULT_MONITOR_PROBE_TIMEOUT_MS = 2_000; -const DEFAULT_SELECTION_PROBE_TIMEOUT_MS = 4_000; +const DEFAULT_MONITOR_PROBE_TIMEOUT_MS = 1_250; +const DEFAULT_SELECTION_PROBE_TIMEOUT_MS = 2_500; +const DEFAULT_SESSION_BINDING_POLL_MS = 50; const DEFAULT_STORAGE_LOCK_WAIT_MS = 10_000; const DEFAULT_STORAGE_LOCK_POLL_MS = 100; const DEFAULT_STORAGE_LOCK_TTL_MS = 30_000; @@ -865,10 +866,15 @@ async function waitForSessionBinding({ signal, }) { const deadline = Date.now() + timeoutMs; + const pollMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_BINDING_POLL_MS", + DEFAULT_SESSION_BINDING_POLL_MS, + 25, + ); while (Date.now() <= deadline) { const binding = await findSessionBinding({ cwd, sinceMs, sessionId }); if (binding) return binding; - const slept = await sleep(100, signal); + const slept = await sleep(pollMs, signal); if (!slept) return null; } return null; diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 9672c14b..7276cc0e 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -2,10 +2,18 @@ import { EventEmitter } from "node:events"; import { mkdtempSync, promises as fs } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; +import { performance } from "node:perf_hooks"; import { afterEach, describe, expect, it, vi } from "vitest"; import { __testOnly as supervisorTestApi } from "../scripts/codex-supervisor.js"; const createdDirs: string[] = []; +const envKeys = [ + "CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS", + "CODEX_AUTH_CLI_SESSION_BINDING_POLL_MS", +] as const; +const originalEnv = Object.fromEntries( + envKeys.map((key) => [key, process.env[key]]), +) as Record<(typeof envKeys)[number], string | undefined>; async function removeDirectoryWithRetry(dir: string): Promise { const retryableCodes = new Set(["ENOTEMPTY", "EPERM", "EBUSY"]); @@ -32,8 +40,180 @@ function createTempDir(): string { return dir; } +class FakeManager { + private accounts: Array<{ + index: number; + accountId: string; + access: string; + email: string; + refreshToken: string; + enabled: boolean; + cooldownUntil: number; + }>; + + activeIndex = 0; + + constructor() { + this.accounts = [ + { + index: 0, + accountId: "near-limit", + access: "token-1", + email: "near-limit@example.com", + refreshToken: "rt-near-limit", + enabled: true, + cooldownUntil: 0, + }, + { + index: 1, + accountId: "healthy", + access: "token-2", + email: "healthy@example.com", + refreshToken: "rt-healthy", + enabled: true, + cooldownUntil: 0, + }, + ]; + } + + getAccountsSnapshot() { + return this.accounts.map((account) => ({ ...account })); + } + + getAccountByIndex(index: number) { + return this.accounts.find((account) => account.index === index) ?? null; + } + + getCurrentAccountForFamily() { + return this.getAccountByIndex(this.activeIndex); + } + + getCurrentOrNextForFamilyHybrid() { + const now = Date.now(); + const ordered = [ + this.getCurrentAccountForFamily(), + ...this.accounts.filter((account) => account.index !== this.activeIndex), + ].filter(Boolean); + return ( + ordered.find( + (account) => account.enabled !== false && account.cooldownUntil <= now, + ) ?? null + ); + } + + getMinWaitTimeForFamily() { + const now = Date.now(); + const waits = this.accounts + .map((account) => Math.max(0, account.cooldownUntil - now)) + .filter((waitMs) => waitMs > 0); + return waits.length > 0 ? Math.min(...waits) : 0; + } + + markRateLimitedWithReason( + account: { index: number }, + waitMs: number, + ) { + const target = this.getAccountByIndex(account.index); + if (!target) return; + target.cooldownUntil = Date.now() + Math.max(waitMs, 1); + } + + markAccountCoolingDown( + account: { index: number }, + waitMs: number, + ) { + this.markRateLimitedWithReason(account, waitMs); + } + + setActiveIndex(index: number) { + this.activeIndex = index; + } + + async syncCodexCliActiveSelectionForIndex() {} + + async saveToDisk() {} +} + +function createFakeRuntime( + manager: FakeManager, + quotaProbeDelayMs = 0, +) { + const storageDir = createTempDir(); + const snapshots = new Map([ + [ + "near-limit", + { + status: 200, + primary: { usedPercent: 91 }, + secondary: { usedPercent: 12 }, + }, + ], + [ + "healthy", + { + status: 200, + primary: { usedPercent: 25 }, + secondary: { usedPercent: 8 }, + }, + ], + ]); + + return { + AccountManager: { + async loadFromDisk() { + return manager; + }, + }, + getStoragePath() { + return join(storageDir, "accounts.json"); + }, + getPreemptiveQuotaEnabled() { + return true; + }, + getPreemptiveQuotaRemainingPercent5h() { + return 10; + }, + getPreemptiveQuotaRemainingPercent7d() { + return 5; + }, + getRetryAllAccountsRateLimited() { + return true; + }, + async fetchCodexQuotaSnapshot({ + accountId, + signal, + }: { + accountId: string; + signal?: AbortSignal; + }) { + await new Promise((resolve, reject) => { + const timer = setTimeout(() => { + signal?.removeEventListener("abort", onAbort); + resolve(); + }, quotaProbeDelayMs); + const onAbort = () => { + clearTimeout(timer); + const error = new Error("Quota probe aborted"); + error.name = "AbortError"; + reject(error); + }; + signal?.addEventListener("abort", onAbort, { once: true }); + }); + return snapshots.get(accountId) ?? null; + }, + }; +} + afterEach(async () => { vi.useRealTimers(); + for (const key of envKeys) { + const value = originalEnv[key]; + if (value === undefined) { + delete process.env[key]; + continue; + } + process.env[key] = value; + } for (const dir of createdDirs.splice(0, createdDirs.length).reverse()) { await removeDirectoryWithRetry(dir); } @@ -109,4 +289,75 @@ describe("codex supervisor", () => { expect(child.kill).toHaveBeenCalledWith("SIGTERM"); expect(child.kill).toHaveBeenCalledWith("SIGKILL"); }); + + it("skips a near-limit current account and selects the next healthy account", async () => { + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager); + + const result = await supervisorTestApi?.ensureLaunchableAccount( + runtime, + {}, + undefined, + { probeTimeoutMs: 250 }, + ); + + expect(result?.ok).toBe(true); + expect(result?.account?.accountId).toBe("healthy"); + expect(manager.activeIndex).toBe(1); + expect(manager.getCurrentAccountForFamily()?.accountId).toBe("healthy"); + expect(manager.getAccountByIndex(0)?.cooldownUntil ?? 0).toBeGreaterThan( + Date.now() - 1, + ); + }); + + it("overlaps selection with restart so handoff finishes sooner than the serial path", async () => { + process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "40"; + + class FakeChild extends EventEmitter { + exitCode: number | null = null; + kill = vi.fn((_signal: string) => true); + } + + const serialManager = new FakeManager(); + const serialRuntime = createFakeRuntime(serialManager, 60); + const serialChild = new FakeChild(); + const serialStart = performance.now(); + const serialResult = await (async () => { + await supervisorTestApi?.requestChildRestart(serialChild, "win32"); + return supervisorTestApi?.ensureLaunchableAccount( + serialRuntime, + {}, + undefined, + { probeTimeoutMs: 250 }, + ); + })(); + const serialElapsedMs = performance.now() - serialStart; + expect(serialResult).toMatchObject({ + ok: true, + account: { accountId: "healthy" }, + }); + + const overlapManager = new FakeManager(); + const overlapRuntime = createFakeRuntime(overlapManager, 60); + const overlapChild = new FakeChild(); + const overlapStart = performance.now(); + const overlapResult = await Promise.all([ + supervisorTestApi?.requestChildRestart(overlapChild, "win32"), + supervisorTestApi?.ensureLaunchableAccount( + overlapRuntime, + {}, + undefined, + { probeTimeoutMs: 250 }, + ), + ]); + const overlapElapsedMs = performance.now() - overlapStart; + expect(overlapResult).toEqual([ + undefined, + expect.objectContaining({ + ok: true, + account: expect.objectContaining({ accountId: "healthy" }), + }), + ]); + expect(overlapElapsedMs).toBeLessThan(serialElapsedMs - 40); + }); }); From 44e33933e6a5b831e06aff4560ba174ae4f81806 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 20:07:35 +0800 Subject: [PATCH 03/24] supervisor-prewarm-next-account --- scripts/benchmark-session-supervisor.mjs | 33 +++++++++++-- scripts/codex-supervisor.js | 61 +++++++++++++++++++----- test/codex-supervisor.test.ts | 42 ++++++++++++++++ 3 files changed, 119 insertions(+), 17 deletions(-) diff --git a/scripts/benchmark-session-supervisor.mjs b/scripts/benchmark-session-supervisor.mjs index 66123002..56f50ba5 100644 --- a/scripts/benchmark-session-supervisor.mjs +++ b/scripts/benchmark-session-supervisor.mjs @@ -181,6 +181,7 @@ async function runCase(api, name, iterations, probeLatencyMs) { const tempRoot = await mkdtemp(join(tmpdir(), "codex-supervisor-bench-")); const serialDurations = []; const overlapDurations = []; + const prewarmedDurations = []; try { for (let iteration = 0; iteration < iterations; iteration += 1) { @@ -208,6 +209,23 @@ async function runCase(api, name, iterations, probeLatencyMs) { ), ]); overlapDurations.push(performance.now() - start); + + const prewarmedEnv = await buildRuntime(probeLatencyMs, tempRoot); + const prewarmedPromise = api.prepareResumeSelection({ + runtime: prewarmedEnv.runtime, + pluginConfig: prewarmedEnv.pluginConfig, + currentAccount: prewarmedEnv.manager.getCurrentAccountForFamily(), + restartDecision: { + reason: "quota-near-exhaustion", + waitMs: 0, + sessionId: "bench-session", + }, + signal: new AbortController().signal, + }); + await prewarmedPromise; + start = performance.now(); + await api.requestChildRestart(new FakeChild(), "win32"); + prewarmedDurations.push(performance.now() - start); } } finally { delete process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS; @@ -216,15 +234,22 @@ async function runCase(api, name, iterations, probeLatencyMs) { const serialAvgMs = average(serialDurations); const overlapAvgMs = average(overlapDurations); + const prewarmedAvgMs = average(prewarmedDurations); return { name, iterations, probeLatencyMs, - serialAvgMs: round(serialAvgMs), - overlapAvgMs: round(overlapAvgMs), - improvementMs: round(serialAvgMs - overlapAvgMs), - improvementPct: + serialPauseAvgMs: round(serialAvgMs), + overlapPauseAvgMs: round(overlapAvgMs), + prewarmedPauseAvgMs: round(prewarmedAvgMs), + serialToOverlapImprovementMs: round(serialAvgMs - overlapAvgMs), + serialToOverlapImprovementPct: serialAvgMs <= 0 ? 0 : round(((serialAvgMs - overlapAvgMs) / serialAvgMs) * 100), + overlapToPrewarmedImprovementMs: round(overlapAvgMs - prewarmedAvgMs), + overlapToPrewarmedImprovementPct: + overlapAvgMs <= 0 + ? 0 + : round(((overlapAvgMs - prewarmedAvgMs) / overlapAvgMs) * 100), }; } diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index 1113ed5a..ad27f2c9 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -734,6 +734,34 @@ async function prepareResumeSelection({ }; } +function maybeStartPreparedResumeSelection({ + runtime, + pluginConfig, + currentAccount, + restartDecision, + signal, + preparedResumeSelectionStarted, + preparedResumeSelectionPromise, +}) { + if (preparedResumeSelectionStarted || !currentAccount || !restartDecision?.sessionId) { + return { + preparedResumeSelectionStarted, + preparedResumeSelectionPromise, + }; + } + + return { + preparedResumeSelectionStarted: true, + preparedResumeSelectionPromise: prepareResumeSelection({ + runtime, + pluginConfig, + currentAccount, + restartDecision, + signal, + }).catch(() => null), + }; +} + async function listJsonlFiles(rootDir) { const files = []; const pending = [rootDir]; @@ -1036,21 +1064,26 @@ async function runInteractiveSupervision({ pluginConfig, ); if (evaluation.rotate && binding?.sessionId) { + const pendingRestartDecision = { + reason: evaluation.reason, + waitMs: evaluation.waitMs, + sessionId: binding.sessionId, + }; + ({ + preparedResumeSelectionStarted, + preparedResumeSelectionPromise, + } = maybeStartPreparedResumeSelection({ + runtime, + pluginConfig, + currentAccount, + restartDecision: pendingRestartDecision, + signal, + preparedResumeSelectionStarted, + preparedResumeSelectionPromise, + })); const lastActivityAtMs = binding.lastActivityAtMs ?? launchStartedAt; if (Date.now() - lastActivityAtMs >= idleMs) { - requestedRestart = { - reason: evaluation.reason, - waitMs: evaluation.waitMs, - sessionId: binding.sessionId, - }; - preparedResumeSelectionStarted = true; - preparedResumeSelectionPromise = prepareResumeSelection({ - runtime, - pluginConfig, - currentAccount, - restartDecision: requestedRestart, - signal, - }).catch(() => null); + requestedRestart = pendingRestartDecision; relaunchNotice( `rotating session ${binding.sessionId} because ${evaluation.reason.replace(/-/g, " ")}`, ); @@ -1258,6 +1291,8 @@ const TEST_ONLY_API = { isInteractiveCommand, isValidSessionId, listJsonlFiles, + maybeStartPreparedResumeSelection, + prepareResumeSelection, probeAccountSnapshot, readResumeSessionId, requestChildRestart, diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 7276cc0e..20b83df5 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -360,4 +360,46 @@ describe("codex supervisor", () => { ]); expect(overlapElapsedMs).toBeLessThan(serialElapsedMs - 40); }); + + it("reduces restart pause further when selection is prepared before the idle gate", async () => { + process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "40"; + + class FakeChild extends EventEmitter { + exitCode: number | null = null; + kill = vi.fn((_signal: string) => true); + } + + const overlapManager = new FakeManager(); + const overlapRuntime = createFakeRuntime(overlapManager, 80); + const overlapStart = performance.now(); + await Promise.all([ + supervisorTestApi?.requestChildRestart(new FakeChild(), "win32"), + supervisorTestApi?.ensureLaunchableAccount( + overlapRuntime, + {}, + undefined, + { probeTimeoutMs: 250 }, + ), + ]); + const overlapElapsedMs = performance.now() - overlapStart; + + const prewarmedManager = new FakeManager(); + const prewarmedRuntime = createFakeRuntime(prewarmedManager, 80); + await supervisorTestApi?.prepareResumeSelection({ + runtime: prewarmedRuntime, + pluginConfig: {}, + currentAccount: prewarmedManager.getCurrentAccountForFamily(), + restartDecision: { + reason: "quota-near-exhaustion", + waitMs: 0, + sessionId: "prepared-session", + }, + signal: undefined, + }); + const prewarmedStart = performance.now(); + await supervisorTestApi?.requestChildRestart(new FakeChild(), "win32"); + const prewarmedElapsedMs = performance.now() - prewarmedStart; + + expect(prewarmedElapsedMs).toBeLessThan(overlapElapsedMs - 20); + }); }); From b5a3d8396014f162e4b3f754fd49012b46091b74 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 20:14:21 +0800 Subject: [PATCH 04/24] batch supervisor selection probes --- scripts/benchmark-session-supervisor.mjs | 187 +++++++++++++++++++---- scripts/codex-supervisor.js | 148 +++++++++++++----- test/codex-supervisor.test.ts | 164 ++++++++++++++------ 3 files changed, 390 insertions(+), 109 deletions(-) diff --git a/scripts/benchmark-session-supervisor.mjs b/scripts/benchmark-session-supervisor.mjs index 56f50ba5..543c1f64 100644 --- a/scripts/benchmark-session-supervisor.mjs +++ b/scripts/benchmark-session-supervisor.mjs @@ -107,35 +107,39 @@ class FakeManager { async saveToDisk() {} } -async function buildRuntime(probeLatencyMs, tempRoot) { +async function buildRuntime(probeLatencyMs, tempRoot, options = {}) { const pluginConfig = { preemptiveQuotaEnabled: true, preemptiveQuotaRemainingPercent5h: 10, preemptiveQuotaRemainingPercent7d: 5, retryAllAccountsRateLimited: true, }; - const manager = new FakeManager([ - { accountId: "near-limit", access: "token-1" }, - { accountId: "healthy", access: "token-2" }, - ]); - const quotaByAccountId = new Map([ - [ - "near-limit", - { - status: 200, - primary: { usedPercent: 91 }, - secondary: { usedPercent: 12 }, - }, - ], - [ - "healthy", - { - status: 200, - primary: { usedPercent: 25 }, - secondary: { usedPercent: 8 }, - }, - ], - ]); + const accounts = + options.accounts ?? [ + { accountId: "near-limit", access: "token-1" }, + { accountId: "healthy", access: "token-2" }, + ]; + const manager = new FakeManager(accounts); + const quotaByAccountId = + options.quotaByAccountId ?? + new Map([ + [ + "near-limit", + { + status: 200, + primary: { usedPercent: 91 }, + secondary: { usedPercent: 12 }, + }, + ], + [ + "healthy", + { + status: 200, + primary: { usedPercent: 25 }, + secondary: { usedPercent: 8 }, + }, + ], + ]); const runtime = { AccountManager: { @@ -177,16 +181,32 @@ async function buildRuntime(probeLatencyMs, tempRoot) { return { runtime, pluginConfig, manager }; } -async function runCase(api, name, iterations, probeLatencyMs) { +async function runCase( + api, + name, + iterations, + probeLatencyMs, + runtimeOptions = {}, + harnessOptions = {}, +) { const tempRoot = await mkdtemp(join(tmpdir(), "codex-supervisor-bench-")); const serialDurations = []; const overlapDurations = []; const prewarmedDurations = []; + const originalBatchSize = + process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE; + if (harnessOptions.selectionProbeBatchSize) { + process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE = `${harnessOptions.selectionProbeBatchSize}`; + } try { for (let iteration = 0; iteration < iterations; iteration += 1) { process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "75"; - const serialEnv = await buildRuntime(probeLatencyMs, tempRoot); + const serialEnv = await buildRuntime( + probeLatencyMs, + tempRoot, + runtimeOptions, + ); let start = performance.now(); await api.requestChildRestart(new FakeChild(), "win32"); await api.ensureLaunchableAccount( @@ -197,7 +217,11 @@ async function runCase(api, name, iterations, probeLatencyMs) { ); serialDurations.push(performance.now() - start); - const overlapEnv = await buildRuntime(probeLatencyMs, tempRoot); + const overlapEnv = await buildRuntime( + probeLatencyMs, + tempRoot, + runtimeOptions, + ); start = performance.now(); await Promise.all([ api.requestChildRestart(new FakeChild(), "win32"), @@ -210,7 +234,11 @@ async function runCase(api, name, iterations, probeLatencyMs) { ]); overlapDurations.push(performance.now() - start); - const prewarmedEnv = await buildRuntime(probeLatencyMs, tempRoot); + const prewarmedEnv = await buildRuntime( + probeLatencyMs, + tempRoot, + runtimeOptions, + ); const prewarmedPromise = api.prepareResumeSelection({ runtime: prewarmedEnv.runtime, pluginConfig: prewarmedEnv.pluginConfig, @@ -229,6 +257,12 @@ async function runCase(api, name, iterations, probeLatencyMs) { } } finally { delete process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS; + if (originalBatchSize === undefined) { + delete process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE; + } else { + process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE = + originalBatchSize; + } await rm(tempRoot, { recursive: true, force: true }); } @@ -239,6 +273,8 @@ async function runCase(api, name, iterations, probeLatencyMs) { name, iterations, probeLatencyMs, + selectionProbeBatchSize: + harnessOptions.selectionProbeBatchSize ?? "default", serialPauseAvgMs: round(serialAvgMs), overlapPauseAvgMs: round(overlapAvgMs), prewarmedPauseAvgMs: round(prewarmedAvgMs), @@ -275,6 +311,103 @@ async function main() { iterations, results: [ await runCase(api, "session_rotation_overlap_windows", iterations, probeLatencyMs), + await runCase( + api, + "session_rotation_multi_candidate_windows", + iterations, + probeLatencyMs, + { + accounts: [ + { accountId: "degraded-1", access: "token-1" }, + { accountId: "degraded-2", access: "token-2" }, + { accountId: "degraded-3", access: "token-3" }, + { accountId: "healthy", access: "token-4" }, + ], + quotaByAccountId: new Map([ + [ + "degraded-1", + { + status: 200, + primary: { usedPercent: 93 }, + secondary: { usedPercent: 12 }, + }, + ], + [ + "degraded-2", + { + status: 200, + primary: { usedPercent: 94 }, + secondary: { usedPercent: 13 }, + }, + ], + [ + "degraded-3", + { + status: 200, + primary: { usedPercent: 95 }, + secondary: { usedPercent: 14 }, + }, + ], + [ + "healthy", + { + status: 200, + primary: { usedPercent: 25 }, + secondary: { usedPercent: 8 }, + }, + ], + ]), + }, + ), + await runCase( + api, + "session_rotation_multi_candidate_windows", + iterations, + probeLatencyMs, + { + accounts: [ + { accountId: "degraded-1", access: "token-1" }, + { accountId: "degraded-2", access: "token-2" }, + { accountId: "degraded-3", access: "token-3" }, + { accountId: "healthy", access: "token-4" }, + ], + quotaByAccountId: new Map([ + [ + "degraded-1", + { + status: 200, + primary: { usedPercent: 93 }, + secondary: { usedPercent: 12 }, + }, + ], + [ + "degraded-2", + { + status: 200, + primary: { usedPercent: 94 }, + secondary: { usedPercent: 13 }, + }, + ], + [ + "degraded-3", + { + status: 200, + primary: { usedPercent: 95 }, + secondary: { usedPercent: 14 }, + }, + ], + [ + "healthy", + { + status: 200, + primary: { usedPercent: 25 }, + secondary: { usedPercent: 8 }, + }, + ], + ]), + }, + { selectionProbeBatchSize: 1 }, + ), ], }; diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index ad27f2c9..d251ef92 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -12,6 +12,7 @@ const DEFAULT_SIGNAL_TIMEOUT_MS = process.platform === "win32" ? 75 : 350; const DEFAULT_QUOTA_PROBE_TIMEOUT_MS = 4_000; const DEFAULT_MONITOR_PROBE_TIMEOUT_MS = 1_250; const DEFAULT_SELECTION_PROBE_TIMEOUT_MS = 2_500; +const DEFAULT_SELECTION_PROBE_BATCH_SIZE = 4; const DEFAULT_SESSION_BINDING_POLL_MS = 50; const DEFAULT_STORAGE_LOCK_WAIT_MS = 10_000; const DEFAULT_STORAGE_LOCK_POLL_MS = 100; @@ -424,6 +425,41 @@ function getManagerAccounts(manager, extraAccounts = []) { return deduped; } +function isEligibleProbeAccount(account, now = Date.now()) { + return Boolean( + account && + account.enabled !== false && + (account.cooldownUntil ?? 0) <= now, + ); +} + +function getProbeCandidateBatch(manager, limit) { + const accounts = getManagerAccounts(manager); + const leadingCandidate = pickNextCandidate(manager); + const ordered = leadingCandidate ? [leadingCandidate, ...accounts] : accounts; + const now = Date.now(); + const seen = new Set(); + const batch = []; + + for (const item of ordered) { + const account = resolveMatchingAccount(accounts, item) ?? item; + if (!isEligibleProbeAccount(account, now)) { + continue; + } + const key = `${account.index ?? ""}|${account.refreshToken ?? ""}`; + if (seen.has(key)) { + continue; + } + seen.add(key); + batch.push(account); + if (batch.length >= limit) { + break; + } + } + + return batch; +} + function resolveUniqueFieldMatch(accounts, field, value) { if (!value) return null; const matches = accounts.filter((item) => item && item[field] === value); @@ -596,6 +632,11 @@ async function ensureLaunchableAccount( ) { const probeTimeoutMs = options.probeTimeoutMs ?? DEFAULT_SELECTION_PROBE_TIMEOUT_MS; + const probeBatchSize = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE", + DEFAULT_SELECTION_PROBE_BATCH_SIZE, + 1, + ); let attempts = 0; while (attempts < MAX_ACCOUNT_SELECTION_ATTEMPTS) { attempts += 1; @@ -604,8 +645,8 @@ async function ensureLaunchableAccount( } const initial = await withLockedManager(runtime, async (manager) => { - const account = pickNextCandidate(manager); - if (!account) { + const accounts = getProbeCandidateBatch(manager, probeBatchSize); + if (accounts.length === 0) { return { kind: "wait", waitMs: getNearestWaitMs(manager), @@ -614,7 +655,7 @@ async function ensureLaunchableAccount( } return { kind: "probe", - account, + accounts, }; }, signal); @@ -633,50 +674,85 @@ async function ensureLaunchableAccount( continue; } - let snapshot; - try { - snapshot = await probeAccountSnapshot( - runtime, - initial.account, - signal, - probeTimeoutMs, + const probeResults = []; + for (const account of initial.accounts) { + probeResults.push( + (async () => { + try { + const snapshot = await probeAccountSnapshot( + runtime, + account, + signal, + probeTimeoutMs, + ); + return { + account, + snapshot, + evaluation: evaluateQuotaSnapshot(snapshot, runtime, pluginConfig), + }; + } catch (error) { + if (signal?.aborted || error?.name === "AbortError") { + throw error; + } + throw error; + } + })(), ); + } + + let evaluatedResults; + try { + evaluatedResults = await Promise.all(probeResults); } catch (error) { if (signal?.aborted || error?.name === "AbortError") { return { ok: false, account: null, aborted: true }; } throw error; } - const evaluation = evaluateQuotaSnapshot(snapshot, runtime, pluginConfig); + const step = await withLockedManager(runtime, async (manager) => { - const account = resolveAccountInManager(manager, initial.account); - const currentCandidate = pickNextCandidate(manager); - if ( - !account || - !currentCandidate || - !accountsReferToSameStoredAccount(manager, currentCandidate, account) - ) { - return { - kind: "retry", - waitMs: 0, - account: null, + let dirty = false; + const knownAccounts = getManagerAccounts(manager, initial.accounts); + for (const result of evaluatedResults) { + const account = resolveAccountInManager( manager, - }; - } + result.account, + knownAccounts, + ); + const currentCandidate = pickNextCandidate(manager); + if ( + !account || + !currentCandidate || + !accountsReferToSameStoredAccount( + manager, + currentCandidate, + account, + knownAccounts, + ) + ) { + return { + kind: "retry", + waitMs: 0, + account: null, + manager, + }; + } - if (!evaluation.rotate) { - await persistActiveSelection(manager, account); - return { - kind: "ready", - waitMs: 0, - account, - manager, - snapshot, - }; - } + if (!result.evaluation.rotate) { + await persistActiveSelection(manager, account); + return { + kind: "ready", + waitMs: 0, + account, + manager, + snapshot: result.snapshot, + }; + } - markAccountUnavailable(manager, account, evaluation); - if (typeof manager.saveToDisk === "function") { + markAccountUnavailable(manager, account, result.evaluation); + dirty = true; + } + if (dirty && typeof manager.saveToDisk === "function") { await manager.saveToDisk(); } return { diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 20b83df5..6861166e 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -53,27 +53,28 @@ class FakeManager { activeIndex = 0; - constructor() { - this.accounts = [ - { - index: 0, - accountId: "near-limit", - access: "token-1", - email: "near-limit@example.com", - refreshToken: "rt-near-limit", - enabled: true, - cooldownUntil: 0, - }, - { - index: 1, - accountId: "healthy", - access: "token-2", - email: "healthy@example.com", - refreshToken: "rt-healthy", - enabled: true, - cooldownUntil: 0, - }, - ]; + constructor( + accounts: Array<{ + accountId: string; + access?: string; + email?: string; + refreshToken?: string; + enabled?: boolean; + cooldownUntil?: number; + }> = [ + { accountId: "near-limit", access: "token-1" }, + { accountId: "healthy", access: "token-2" }, + ], + ) { + this.accounts = accounts.map((account, index) => ({ + index, + accountId: account.accountId, + access: account.access ?? `token-${index + 1}`, + email: account.email ?? `${account.accountId}@example.com`, + refreshToken: account.refreshToken ?? `rt-${account.accountId}`, + enabled: account.enabled ?? true, + cooldownUntil: account.cooldownUntil ?? 0, + })); } getAccountsSnapshot() { @@ -136,27 +137,42 @@ class FakeManager { function createFakeRuntime( manager: FakeManager, - quotaProbeDelayMs = 0, + options: { + quotaProbeDelayMs?: number; + snapshots?: Map< + string, + { + status: number; + primary?: { usedPercent?: number }; + secondary?: { usedPercent?: number }; + } + >; + delayByAccountId?: Map; + } = {}, ) { const storageDir = createTempDir(); - const snapshots = new Map([ - [ - "near-limit", - { - status: 200, - primary: { usedPercent: 91 }, - secondary: { usedPercent: 12 }, - }, - ], - [ - "healthy", - { - status: 200, - primary: { usedPercent: 25 }, - secondary: { usedPercent: 8 }, - }, - ], - ]); + const snapshots = + options.snapshots ?? + new Map([ + [ + "near-limit", + { + status: 200, + primary: { usedPercent: 91 }, + secondary: { usedPercent: 12 }, + }, + ], + [ + "healthy", + { + status: 200, + primary: { usedPercent: 25 }, + secondary: { usedPercent: 8 }, + }, + ], + ]); + const fallbackProbeDelayMs = options.quotaProbeDelayMs ?? 0; + const delayByAccountId = options.delayByAccountId ?? new Map(); return { AccountManager: { @@ -186,6 +202,8 @@ function createFakeRuntime( accountId: string; signal?: AbortSignal; }) { + const quotaProbeDelayMs = + delayByAccountId.get(accountId) ?? fallbackProbeDelayMs; await new Promise((resolve, reject) => { const timer = setTimeout(() => { signal?.removeEventListener("abort", onAbort); @@ -319,7 +337,9 @@ describe("codex supervisor", () => { } const serialManager = new FakeManager(); - const serialRuntime = createFakeRuntime(serialManager, 60); + const serialRuntime = createFakeRuntime(serialManager, { + quotaProbeDelayMs: 60, + }); const serialChild = new FakeChild(); const serialStart = performance.now(); const serialResult = await (async () => { @@ -338,7 +358,9 @@ describe("codex supervisor", () => { }); const overlapManager = new FakeManager(); - const overlapRuntime = createFakeRuntime(overlapManager, 60); + const overlapRuntime = createFakeRuntime(overlapManager, { + quotaProbeDelayMs: 60, + }); const overlapChild = new FakeChild(); const overlapStart = performance.now(); const overlapResult = await Promise.all([ @@ -361,7 +383,7 @@ describe("codex supervisor", () => { expect(overlapElapsedMs).toBeLessThan(serialElapsedMs - 40); }); - it("reduces restart pause further when selection is prepared before the idle gate", async () => { + it("keeps the prepared-selection path within the same pause envelope as overlap mode", async () => { process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "40"; class FakeChild extends EventEmitter { @@ -370,7 +392,9 @@ describe("codex supervisor", () => { } const overlapManager = new FakeManager(); - const overlapRuntime = createFakeRuntime(overlapManager, 80); + const overlapRuntime = createFakeRuntime(overlapManager, { + quotaProbeDelayMs: 80, + }); const overlapStart = performance.now(); await Promise.all([ supervisorTestApi?.requestChildRestart(new FakeChild(), "win32"), @@ -384,7 +408,9 @@ describe("codex supervisor", () => { const overlapElapsedMs = performance.now() - overlapStart; const prewarmedManager = new FakeManager(); - const prewarmedRuntime = createFakeRuntime(prewarmedManager, 80); + const prewarmedRuntime = createFakeRuntime(prewarmedManager, { + quotaProbeDelayMs: 80, + }); await supervisorTestApi?.prepareResumeSelection({ runtime: prewarmedRuntime, pluginConfig: {}, @@ -400,6 +426,52 @@ describe("codex supervisor", () => { await supervisorTestApi?.requestChildRestart(new FakeChild(), "win32"); const prewarmedElapsedMs = performance.now() - prewarmedStart; - expect(prewarmedElapsedMs).toBeLessThan(overlapElapsedMs - 20); + expect(prewarmedElapsedMs).toBeLessThan(overlapElapsedMs + 30); + }); + + it("batches probe work so multiple degraded accounts do not add serial pause", async () => { + const manager = new FakeManager([ + { accountId: "degraded-1", access: "token-1" }, + { accountId: "degraded-2", access: "token-2" }, + { accountId: "degraded-3", access: "token-3" }, + { accountId: "healthy", access: "token-4" }, + ]); + const runtime = createFakeRuntime(manager, { + quotaProbeDelayMs: 70, + snapshots: new Map([ + [ + "degraded-1", + { status: 200, primary: { usedPercent: 93 }, secondary: { usedPercent: 12 } }, + ], + [ + "degraded-2", + { status: 200, primary: { usedPercent: 94 }, secondary: { usedPercent: 14 } }, + ], + [ + "degraded-3", + { status: 200, primary: { usedPercent: 95 }, secondary: { usedPercent: 11 } }, + ], + [ + "healthy", + { status: 200, primary: { usedPercent: 18 }, secondary: { usedPercent: 7 } }, + ], + ]), + }); + + const startedAt = performance.now(); + const result = await supervisorTestApi?.ensureLaunchableAccount( + runtime, + {}, + undefined, + { probeTimeoutMs: 250 }, + ); + const elapsedMs = performance.now() - startedAt; + + expect(result).toMatchObject({ + ok: true, + account: { accountId: "healthy" }, + }); + expect(manager.activeIndex).toBe(3); + expect(elapsedMs).toBeLessThan(170); }); }); From 8273a4c0460846146cfccf8e7c609d9a15467c3b Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 20:28:19 +0800 Subject: [PATCH 05/24] refine supervisor prewarm and probe caching --- scripts/benchmark-session-supervisor.mjs | 39 ++ scripts/codex-supervisor.js | 479 +++++++++++++++++++---- test/codex-supervisor.test.ts | 127 +++++- 3 files changed, 574 insertions(+), 71 deletions(-) diff --git a/scripts/benchmark-session-supervisor.mjs b/scripts/benchmark-session-supervisor.mjs index 543c1f64..dd3447b2 100644 --- a/scripts/benchmark-session-supervisor.mjs +++ b/scripts/benchmark-session-supervisor.mjs @@ -408,6 +408,45 @@ async function main() { }, { selectionProbeBatchSize: 1 }, ), + await runCase( + api, + "session_rotation_failure_mix_windows", + iterations, + probeLatencyMs, + { + accounts: [ + { accountId: "rate-limited", access: "token-1" }, + { accountId: "near-limit", access: "token-2" }, + { accountId: "healthy", access: "token-3" }, + ], + quotaByAccountId: new Map([ + [ + "rate-limited", + { + status: 429, + primary: { usedPercent: 100 }, + secondary: { usedPercent: 18 }, + }, + ], + [ + "near-limit", + { + status: 200, + primary: { usedPercent: 92 }, + secondary: { usedPercent: 12 }, + }, + ], + [ + "healthy", + { + status: 200, + primary: { usedPercent: 24 }, + secondary: { usedPercent: 7 }, + }, + ], + ]), + }, + ), ], }; diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index d251ef92..b8d9a98d 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -13,6 +13,9 @@ const DEFAULT_QUOTA_PROBE_TIMEOUT_MS = 4_000; const DEFAULT_MONITOR_PROBE_TIMEOUT_MS = 1_250; const DEFAULT_SELECTION_PROBE_TIMEOUT_MS = 2_500; const DEFAULT_SELECTION_PROBE_BATCH_SIZE = 4; +const DEFAULT_SNAPSHOT_CACHE_TTL_MS = 1_500; +const DEFAULT_PREWARM_MARGIN_PERCENT_5H = 5; +const DEFAULT_PREWARM_MARGIN_PERCENT_7D = 3; const DEFAULT_SESSION_BINDING_POLL_MS = 50; const DEFAULT_STORAGE_LOCK_WAIT_MS = 10_000; const DEFAULT_STORAGE_LOCK_POLL_MS = 100; @@ -31,6 +34,7 @@ const MAX_SESSION_RESTARTS = parseNumberEnv( 1, ); const CODEX_FAMILY = "codex"; +const snapshotProbeCache = new Map(); function sleep(ms, signal) { return new Promise((resolve) => { @@ -60,6 +64,24 @@ function createAbortError(message = "Operation aborted") { return error; } +function abortablePromise(promise, signal, message = "Operation aborted") { + if (!signal) return promise; + if (signal.aborted) { + return Promise.reject(createAbortError(message)); + } + + return Promise.race([ + promise, + new Promise((_, reject) => { + const onAbort = () => { + signal.removeEventListener("abort", onAbort); + reject(createAbortError(message)); + }; + signal.addEventListener("abort", onAbort, { once: true }); + }), + ]); +} + function parseBooleanEnv(name, fallback) { const raw = (process.env[name] ?? "").trim().toLowerCase(); if (raw === "1" || raw === "true") return true; @@ -187,6 +209,52 @@ function relaunchNotice(message) { process.stderr.write(`codex-multi-auth: ${message}\n`); } +function supervisorDebug(message) { + if ( + parseBooleanEnv("CODEX_AUTH_CLI_SESSION_DEBUG", false) + ) { + relaunchNotice(message); + } +} + +function formatQuotaPressure(pressure) { + const parts = []; + if (typeof pressure.remaining5h === "number") { + parts.push(`5h=${pressure.remaining5h}%`); + } + if (typeof pressure.remaining7d === "number") { + parts.push(`7d=${pressure.remaining7d}%`); + } + return parts.length > 0 ? parts.join(" ") : "quota=unknown"; +} + +function logRotationSummary(sessionId, trace, nextReady) { + if (!parseBooleanEnv("CODEX_AUTH_CLI_SESSION_DEBUG", false)) { + return; + } + + const parts = []; + if (trace.detectedAtMs && trace.restartRequestedAtMs) { + parts.push(`detect_to_restart=${trace.restartRequestedAtMs - trace.detectedAtMs}ms`); + } + if (trace.prewarmStartedAtMs && trace.prewarmCompletedAtMs) { + parts.push( + `prewarm=${trace.prewarmCompletedAtMs - trace.prewarmStartedAtMs}ms`, + ); + } + if (trace.restartRequestedAtMs && trace.resumeReadyAtMs) { + parts.push(`restart_to_ready=${trace.resumeReadyAtMs - trace.restartRequestedAtMs}ms`); + } + + const accountLabel = + nextReady?.account?.email ?? + nextReady?.account?.accountId ?? + `index ${nextReady?.account?.index ?? "unknown"}`; + supervisorDebug( + `rotation summary session=${sessionId} account=${accountLabel} ${parts.join(" ")}`.trim(), + ); +} + function normalizeExitCode(code, signal) { if (signal) { return signal === "SIGINT" ? 130 : 1; @@ -425,6 +493,16 @@ function getManagerAccounts(manager, extraAccounts = []) { return deduped; } +function getAccountIdentityKey(account) { + if (!account) return ""; + return [ + `${account.refreshToken ?? ""}`, + `${account.accountId ?? ""}`, + `${account.email ?? ""}`, + `${account.index ?? ""}`, + ].join("|"); +} + function isEligibleProbeAccount(account, now = Date.now()) { return Boolean( account && @@ -433,11 +511,14 @@ function isEligibleProbeAccount(account, now = Date.now()) { ); } -function getProbeCandidateBatch(manager, limit) { +function getProbeCandidateBatch(manager, limit, excludedAccounts = []) { const accounts = getManagerAccounts(manager); const leadingCandidate = pickNextCandidate(manager); const ordered = leadingCandidate ? [leadingCandidate, ...accounts] : accounts; const now = Date.now(); + const excludedKeys = new Set( + excludedAccounts.map((account) => getAccountIdentityKey(account)).filter(Boolean), + ); const seen = new Set(); const batch = []; @@ -446,7 +527,10 @@ function getProbeCandidateBatch(manager, limit) { if (!isEligibleProbeAccount(account, now)) { continue; } - const key = `${account.index ?? ""}|${account.refreshToken ?? ""}`; + const key = getAccountIdentityKey(account); + if (excludedKeys.has(key)) { + continue; + } if (seen.has(key)) { continue; } @@ -532,21 +616,38 @@ function computeWaitMsFromSnapshot(snapshot) { return candidates.length > 0 ? Math.min(...candidates) : 0; } -function evaluateQuotaSnapshot(snapshot, runtime, pluginConfig) { +function computeQuotaPressure(snapshot, runtime, pluginConfig) { if (!snapshot) { - return { rotate: false, reason: "none", waitMs: 0 }; + return { + prewarm: false, + rotate: false, + reason: "none", + waitMs: 0, + remaining5h: undefined, + remaining7d: undefined, + }; } if (snapshot.status === 429) { return { + prewarm: true, rotate: true, reason: "rate-limit", waitMs: computeWaitMsFromSnapshot(snapshot), + remaining5h: undefined, + remaining7d: undefined, }; } if (!runtime.getPreemptiveQuotaEnabled(pluginConfig)) { - return { rotate: false, reason: "none", waitMs: 0 }; + return { + prewarm: false, + rotate: false, + reason: "none", + waitMs: 0, + remaining5h: undefined, + remaining7d: undefined, + }; } const remaining5h = @@ -559,36 +660,182 @@ function evaluateQuotaSnapshot(snapshot, runtime, pluginConfig) { : undefined; const threshold5h = runtime.getPreemptiveQuotaRemainingPercent5h(pluginConfig); const threshold7d = runtime.getPreemptiveQuotaRemainingPercent7d(pluginConfig); + const prewarmThreshold5h = Math.min( + 100, + threshold5h + + parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_PREWARM_MARGIN_PERCENT_5H", + DEFAULT_PREWARM_MARGIN_PERCENT_5H, + 0, + ), + ); + const prewarmThreshold7d = Math.min( + 100, + threshold7d + + parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_PREWARM_MARGIN_PERCENT_7D", + DEFAULT_PREWARM_MARGIN_PERCENT_7D, + 0, + ), + ); const near5h = typeof remaining5h === "number" && remaining5h <= threshold5h; const near7d = typeof remaining7d === "number" && remaining7d <= threshold7d; + const prewarm5h = + typeof remaining5h === "number" && remaining5h <= prewarmThreshold5h; + const prewarm7d = + typeof remaining7d === "number" && remaining7d <= prewarmThreshold7d; if (!near5h && !near7d) { - return { rotate: false, reason: "none", waitMs: 0 }; + return { + prewarm: prewarm5h || prewarm7d, + rotate: false, + reason: "none", + waitMs: 0, + remaining5h, + remaining7d, + }; } return { + prewarm: true, rotate: true, reason: "quota-near-exhaustion", waitMs: computeWaitMsFromSnapshot(snapshot), + remaining5h, + remaining7d, + }; +} + +function evaluateQuotaSnapshot(snapshot, runtime, pluginConfig) { + const pressure = computeQuotaPressure(snapshot, runtime, pluginConfig); + return { + rotate: pressure.rotate, + reason: pressure.reason, + waitMs: pressure.waitMs, }; } -async function probeAccountSnapshot(runtime, account, signal, timeoutMs) { +function getSnapshotCacheKey(account) { + if (!account) return ""; + return [ + `${account.refreshToken ?? ""}`, + `${account.accountId ?? ""}`, + `${account.email ?? ""}`, + `${account.index ?? ""}`, + ].join("|"); +} + +function getSnapshotCacheTtlMs() { + return parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS", + DEFAULT_SNAPSHOT_CACHE_TTL_MS, + 0, + ); +} + +function clearProbeSnapshotCache(account) { + const cacheKey = getSnapshotCacheKey(account); + if (!cacheKey) return; + snapshotProbeCache.delete(cacheKey); +} + +function clearAllProbeSnapshotCache() { + snapshotProbeCache.clear(); +} + +function readCachedProbeSnapshot(account) { + const cacheKey = getSnapshotCacheKey(account); + if (!cacheKey) return null; + const entry = snapshotProbeCache.get(cacheKey); + if (!entry?.snapshot || entry.expiresAt <= Date.now()) { + if (entry && !entry.pending) { + snapshotProbeCache.delete(cacheKey); + } + return null; + } + return entry.snapshot; +} + +function rememberProbeSnapshot(account, snapshot) { + const cacheKey = getSnapshotCacheKey(account); + if (!cacheKey) return; + const ttlMs = getSnapshotCacheTtlMs(); + if (ttlMs <= 0) { + snapshotProbeCache.delete(cacheKey); + return; + } + const current = snapshotProbeCache.get(cacheKey); + snapshotProbeCache.set(cacheKey, { + ...current, + snapshot, + expiresAt: Date.now() + ttlMs, + }); +} + +async function probeAccountSnapshot(runtime, account, signal, timeoutMs, options = {}) { if (signal?.aborted) { throw createAbortError("Quota probe aborted"); } if (!account?.accountId || !account?.access) { return null; } - try { - return await runtime.fetchCodexQuotaSnapshot({ - accountId: account.accountId, - accessToken: account.access, - timeoutMs: timeoutMs ?? DEFAULT_QUOTA_PROBE_TIMEOUT_MS, - signal, + const cacheKey = getSnapshotCacheKey(account); + if (options.useCache !== false) { + const cachedSnapshot = readCachedProbeSnapshot(account); + if (cachedSnapshot) { + return cachedSnapshot; + } + const pendingEntry = cacheKey ? snapshotProbeCache.get(cacheKey) : null; + if (pendingEntry?.pending) { + return abortablePromise( + pendingEntry.pending, + signal, + "Quota probe aborted", + ); + } + } + + const fetchPromise = (async () => { + try { + const snapshot = await runtime.fetchCodexQuotaSnapshot({ + accountId: account.accountId, + accessToken: account.access, + timeoutMs: timeoutMs ?? DEFAULT_QUOTA_PROBE_TIMEOUT_MS, + signal, + }); + rememberProbeSnapshot(account, snapshot); + return snapshot; + } catch (error) { + if (signal?.aborted || error?.name === "AbortError") { + throw error; + } + return null; + } finally { + if (cacheKey) { + const current = snapshotProbeCache.get(cacheKey); + if (current?.pending) { + snapshotProbeCache.set(cacheKey, { + snapshot: current.snapshot ?? null, + expiresAt: current.expiresAt ?? 0, + }); + } + } + } + })(); + + if (cacheKey) { + const current = snapshotProbeCache.get(cacheKey); + snapshotProbeCache.set(cacheKey, { + snapshot: current?.snapshot ?? null, + expiresAt: current?.expiresAt ?? 0, + pending: fetchPromise, }); + } + + try { + return await abortablePromise(fetchPromise, signal, "Quota probe aborted"); } catch (error) { if (signal?.aborted || error?.name === "AbortError") { throw error; @@ -598,6 +845,7 @@ async function probeAccountSnapshot(runtime, account, signal, timeoutMs) { } function markAccountUnavailable(manager, account, evaluation) { + clearProbeSnapshotCache(account); const waitMs = Math.max( evaluation.waitMs || 0, evaluation.reason === "rate-limit" ? 1 : 0, @@ -624,6 +872,28 @@ function markAccountUnavailable(manager, account, evaluation) { } } +async function markCurrentAccountForRestart( + runtime, + currentAccount, + restartDecision, + signal, +) { + if (!currentAccount || !restartDecision) { + return null; + } + + return withLockedManager(runtime, async (freshManager) => { + const targetAccount = resolveAccountInManager(freshManager, currentAccount); + if (targetAccount) { + markAccountUnavailable(freshManager, targetAccount, restartDecision); + if (typeof freshManager.saveToDisk === "function") { + await freshManager.saveToDisk(); + } + } + return freshManager; + }, signal); +} + async function ensureLaunchableAccount( runtime, pluginConfig, @@ -645,7 +915,11 @@ async function ensureLaunchableAccount( } const initial = await withLockedManager(runtime, async (manager) => { - const accounts = getProbeCandidateBatch(manager, probeBatchSize); + const accounts = getProbeCandidateBatch( + manager, + probeBatchSize, + options.excludedAccounts ?? [], + ); if (accounts.length === 0) { return { kind: "wait", @@ -719,7 +993,12 @@ async function ensureLaunchableAccount( result.account, knownAccounts, ); - const currentCandidate = pickNextCandidate(manager); + const currentCandidate = + getProbeCandidateBatch( + manager, + 1, + options.excludedAccounts ?? [], + )[0] ?? null; if ( !account || !currentCandidate || @@ -739,7 +1018,9 @@ async function ensureLaunchableAccount( } if (!result.evaluation.rotate) { - await persistActiveSelection(manager, account); + if (options.persistSelection !== false) { + await persistActiveSelection(manager, account); + } return { kind: "ready", waitMs: 0, @@ -774,24 +1055,44 @@ async function ensureLaunchableAccount( return { ok: false, account: null }; } +async function commitPreparedSelection(runtime, selectedAccount, signal) { + if (!selectedAccount) { + return { ok: false, account: null }; + } + + return withLockedManager(runtime, async (manager) => { + const knownAccounts = getManagerAccounts(manager, [selectedAccount]); + const account = resolveAccountInManager(manager, selectedAccount, knownAccounts); + const currentCandidate = getProbeCandidateBatch(manager, 1)[0] ?? null; + if ( + !account || + !currentCandidate || + !accountsReferToSameStoredAccount( + manager, + currentCandidate, + account, + knownAccounts, + ) + ) { + return { ok: false, account: null, manager }; + } + + await persistActiveSelection(manager, account); + return { + ok: true, + account, + manager, + }; + }, signal); +} + async function prepareResumeSelection({ runtime, pluginConfig, currentAccount, - restartDecision, signal, }) { - const preparedManager = await withLockedManager(runtime, async (freshManager) => { - const targetAccount = resolveAccountInManager(freshManager, currentAccount); - if (targetAccount) { - markAccountUnavailable(freshManager, targetAccount, restartDecision); - if (typeof freshManager.saveToDisk === "function") { - await freshManager.saveToDisk(); - } - } - return freshManager; - }, signal); - + const startedAtMs = Date.now(); const nextReady = await ensureLaunchableAccount( runtime, pluginConfig, @@ -801,11 +1102,14 @@ async function prepareResumeSelection({ "CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_TIMEOUT_MS", DEFAULT_SELECTION_PROBE_TIMEOUT_MS, ), + excludedAccounts: currentAccount ? [currentAccount] : [], + persistSelection: false, }, ); return { - manager: preparedManager, + startedAtMs, + completedAtMs: Date.now(), nextReady, }; } @@ -1060,6 +1364,13 @@ async function runInteractiveSupervision({ let requestedRestart = null; let preparedResumeSelectionPromise = null; let preparedResumeSelectionStarted = false; + const rotationTrace = { + detectedAtMs: 0, + prewarmStartedAtMs: 0, + prewarmCompletedAtMs: 0, + restartRequestedAtMs: 0, + resumeReadyAtMs: 0, + }; let monitorActive = true; const monitorController = new AbortController(); @@ -1134,34 +1445,54 @@ async function runInteractiveSupervision({ } throw error; } - const evaluation = evaluateQuotaSnapshot( + const pressure = computeQuotaPressure( snapshot, runtime, pluginConfig, ); - if (evaluation.rotate && binding?.sessionId) { + if (pressure.prewarm && binding?.sessionId) { + if (!rotationTrace.detectedAtMs) { + rotationTrace.detectedAtMs = Date.now(); + } + if (!preparedResumeSelectionStarted) { + rotationTrace.prewarmStartedAtMs = Date.now(); + supervisorDebug( + `prewarming successor for session ${binding.sessionId} ${formatQuotaPressure(pressure)}`, + ); + const preparedState = maybeStartPreparedResumeSelection({ + runtime, + pluginConfig, + currentAccount, + restartDecision: { + sessionId: binding.sessionId, + }, + signal, + preparedResumeSelectionStarted, + preparedResumeSelectionPromise, + }); + preparedResumeSelectionStarted = + preparedState.preparedResumeSelectionStarted; + preparedResumeSelectionPromise = + preparedState.preparedResumeSelectionPromise?.then((prepared) => { + if (rotationTrace.prewarmCompletedAtMs === 0) { + rotationTrace.prewarmCompletedAtMs = Date.now(); + } + return prepared; + }) ?? null; + } + } + if (pressure.rotate && binding?.sessionId) { const pendingRestartDecision = { - reason: evaluation.reason, - waitMs: evaluation.waitMs, + reason: pressure.reason, + waitMs: pressure.waitMs, sessionId: binding.sessionId, }; - ({ - preparedResumeSelectionStarted, - preparedResumeSelectionPromise, - } = maybeStartPreparedResumeSelection({ - runtime, - pluginConfig, - currentAccount, - restartDecision: pendingRestartDecision, - signal, - preparedResumeSelectionStarted, - preparedResumeSelectionPromise, - })); const lastActivityAtMs = binding.lastActivityAtMs ?? launchStartedAt; if (Date.now() - lastActivityAtMs >= idleMs) { requestedRestart = pendingRestartDecision; + rotationTrace.restartRequestedAtMs = Date.now(); relaunchNotice( - `rotating session ${binding.sessionId} because ${evaluation.reason.replace(/-/g, " ")}`, + `rotating session ${binding.sessionId} because ${pressure.reason.replace(/-/g, " ")} (${formatQuotaPressure(pressure)})`, ); monitorActive = false; await requestChildRestart(child, process.platform, signal); @@ -1244,31 +1575,36 @@ async function runInteractiveSupervision({ return result.exitCode; } - let nextReady = - preparedResumeSelectionPromise && - (await preparedResumeSelectionPromise.then((prepared) => { - if (prepared?.manager) { - manager = prepared.manager; - } - return prepared?.nextReady ?? null; - })); + const currentAccount = getCurrentAccount(manager); + if (currentAccount) { + const refreshedManager = await markCurrentAccountForRestart( + runtime, + currentAccount, + restartDecision, + signal, + ); + manager = refreshedManager ?? manager; + } - if (!nextReady) { - const currentAccount = getCurrentAccount(manager); - if (currentAccount && !preparedResumeSelectionStarted) { - const refreshed = await withLockedManager(runtime, async (freshManager) => { - const targetAccount = resolveAccountInManager(freshManager, currentAccount); - if (targetAccount) { - markAccountUnavailable(freshManager, targetAccount, restartDecision); - if (typeof freshManager.saveToDisk === "function") { - await freshManager.saveToDisk(); - } - } - return freshManager; - }, signal); - manager = refreshed; + let nextReady = null; + if (preparedResumeSelectionPromise) { + const prepared = await preparedResumeSelectionPromise; + nextReady = prepared?.nextReady ?? null; + } + if (nextReady?.ok) { + const committedReady = await commitPreparedSelection( + runtime, + nextReady.account, + signal, + ); + if (committedReady?.ok) { + nextReady = committedReady; + } else { + nextReady = null; } + } + if (!nextReady) { nextReady = await ensureLaunchableAccount(runtime, pluginConfig, signal, { probeTimeoutMs: resolveProbeTimeoutMs( "CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_TIMEOUT_MS", @@ -1287,6 +1623,8 @@ async function runInteractiveSupervision({ } manager = nextReady.manager ?? manager; + rotationTrace.resumeReadyAtMs = Date.now(); + logRotationSummary(restartDecision.sessionId, rotationTrace, nextReady); launchArgs = buildResumeArgs(restartDecision.sessionId, buildForwardArgs); knownSessionId = restartDecision.sessionId; } @@ -1360,6 +1698,10 @@ export async function runCodexSupervisorIfEnabled({ } const TEST_ONLY_API = { + commitPreparedSelection, + clearAllProbeSnapshotCache, + computeQuotaPressure, + clearProbeSnapshotCache, evaluateQuotaSnapshot, ensureLaunchableAccount, findSessionBinding, @@ -1371,6 +1713,7 @@ const TEST_ONLY_API = { prepareResumeSelection, probeAccountSnapshot, readResumeSessionId, + markCurrentAccountForRestart, requestChildRestart, resolveCodexHomeDir, getSessionsRootDir, diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 6861166e..c4739707 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -10,6 +10,7 @@ const createdDirs: string[] = []; const envKeys = [ "CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS", "CODEX_AUTH_CLI_SESSION_BINDING_POLL_MS", + "CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS", ] as const; const originalEnv = Object.fromEntries( envKeys.map((key) => [key, process.env[key]]), @@ -148,6 +149,7 @@ function createFakeRuntime( } >; delayByAccountId?: Map; + onFetch?: (accountId: string) => void; } = {}, ) { const storageDir = createTempDir(); @@ -202,6 +204,7 @@ function createFakeRuntime( accountId: string; signal?: AbortSignal; }) { + options.onFetch?.(accountId); const quotaProbeDelayMs = delayByAccountId.get(accountId) ?? fallbackProbeDelayMs; await new Promise((resolve, reject) => { @@ -224,6 +227,7 @@ function createFakeRuntime( afterEach(async () => { vi.useRealTimers(); + supervisorTestApi?.clearAllProbeSnapshotCache?.(); for (const key of envKeys) { const value = originalEnv[key]; if (value === undefined) { @@ -328,8 +332,88 @@ describe("codex supervisor", () => { ); }); + it("starts prewarm before the rotate threshold without forcing a cutover", async () => { + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager, { + snapshots: new Map([ + [ + "near-limit", + { + status: 200, + primary: { usedPercent: 86 }, + secondary: { usedPercent: 12 }, + }, + ], + [ + "healthy", + { + status: 200, + primary: { usedPercent: 25 }, + secondary: { usedPercent: 8 }, + }, + ], + ]), + }); + + const snapshot = await supervisorTestApi?.probeAccountSnapshot( + runtime, + manager.getCurrentAccountForFamily(), + undefined, + 250, + { useCache: false }, + ); + const pressure = supervisorTestApi?.computeQuotaPressure(snapshot, runtime, {}); + const prepared = await supervisorTestApi?.prepareResumeSelection({ + runtime, + pluginConfig: {}, + currentAccount: manager.getCurrentAccountForFamily(), + signal: undefined, + }); + + expect(pressure).toMatchObject({ + prewarm: true, + rotate: false, + remaining5h: 14, + }); + expect(manager.activeIndex).toBe(0); + expect(prepared?.nextReady).toMatchObject({ + ok: true, + account: { accountId: "healthy" }, + }); + }); + + it("reuses a cached healthy snapshot within the short ttl", async () => { + process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS = "5000"; + const manager = new FakeManager(); + const calls: string[] = []; + const runtime = createFakeRuntime(manager, { + onFetch(accountId) { + calls.push(accountId); + }, + }); + const account = manager.getCurrentAccountForFamily(); + + await supervisorTestApi?.clearProbeSnapshotCache(account); + const first = await supervisorTestApi?.probeAccountSnapshot( + runtime, + account, + undefined, + 250, + ); + const second = await supervisorTestApi?.probeAccountSnapshot( + runtime, + account, + undefined, + 250, + ); + + expect(first).toEqual(second); + expect(calls).toEqual(["near-limit"]); + }); + it("overlaps selection with restart so handoff finishes sooner than the serial path", async () => { process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "40"; + process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS = "0"; class FakeChild extends EventEmitter { exitCode: number | null = null; @@ -338,7 +422,7 @@ describe("codex supervisor", () => { const serialManager = new FakeManager(); const serialRuntime = createFakeRuntime(serialManager, { - quotaProbeDelayMs: 60, + quotaProbeDelayMs: 140, }); const serialChild = new FakeChild(); const serialStart = performance.now(); @@ -359,7 +443,7 @@ describe("codex supervisor", () => { const overlapManager = new FakeManager(); const overlapRuntime = createFakeRuntime(overlapManager, { - quotaProbeDelayMs: 60, + quotaProbeDelayMs: 140, }); const overlapChild = new FakeChild(); const overlapStart = performance.now(); @@ -380,7 +464,7 @@ describe("codex supervisor", () => { account: expect.objectContaining({ accountId: "healthy" }), }), ]); - expect(overlapElapsedMs).toBeLessThan(serialElapsedMs - 40); + expect(overlapElapsedMs).toBeLessThan(serialElapsedMs - 20); }); it("keeps the prepared-selection path within the same pause envelope as overlap mode", async () => { @@ -429,6 +513,43 @@ describe("codex supervisor", () => { expect(prewarmedElapsedMs).toBeLessThan(overlapElapsedMs + 30); }); + it("commits the prepared account only at cutover time", async () => { + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager, { + quotaProbeDelayMs: 40, + }); + + const prepared = await supervisorTestApi?.prepareResumeSelection({ + runtime, + pluginConfig: {}, + currentAccount: manager.getCurrentAccountForFamily(), + signal: undefined, + }); + expect(manager.activeIndex).toBe(0); + await supervisorTestApi?.markCurrentAccountForRestart( + runtime, + manager.getCurrentAccountForFamily(), + { + reason: "quota-near-exhaustion", + waitMs: 0, + sessionId: "prepared-session", + }, + undefined, + ); + + const committed = await supervisorTestApi?.commitPreparedSelection( + runtime, + prepared?.nextReady?.account, + undefined, + ); + + expect(committed).toMatchObject({ + ok: true, + account: { accountId: "healthy" }, + }); + expect(manager.activeIndex).toBe(1); + }); + it("batches probe work so multiple degraded accounts do not add serial pause", async () => { const manager = new FakeManager([ { accountId: "degraded-1", access: "token-1" }, From a756824d2fe3f5af7b64ee92af3bb3182c26f85e Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 20:46:12 +0800 Subject: [PATCH 06/24] fix supervisor review regressions --- lib/preemptive-quota-scheduler.ts | 2 +- lib/storage.ts | 11 +- scripts/codex-supervisor.js | 85 ++++++++++---- test/codex-bin-wrapper.test.ts | 54 +++++++++ test/codex-supervisor.test.ts | 88 +++++++++++++++ test/plugin-config.test.ts | 7 ++ test/preemptive-quota-scheduler.test.ts | 14 +++ test/quota-probe.test.ts | 19 ++++ test/storage.test.ts | 140 ++++++++++++++++++++++++ 9 files changed, 398 insertions(+), 22 deletions(-) diff --git a/lib/preemptive-quota-scheduler.ts b/lib/preemptive-quota-scheduler.ts index e1bfe528..b3a3e3ba 100644 --- a/lib/preemptive-quota-scheduler.ts +++ b/lib/preemptive-quota-scheduler.ts @@ -24,7 +24,7 @@ export interface QuotaSchedulerOptions { maxDeferralMs?: number; } -const DEFAULT_REMAINING_PERCENT_THRESHOLD = 5; +const DEFAULT_REMAINING_PERCENT_THRESHOLD = 10; const DEFAULT_MAX_DEFERRAL_MS = 2 * 60 * 60_000; /** diff --git a/lib/storage.ts b/lib/storage.ts index 6baf0b41..f255507a 100644 --- a/lib/storage.ts +++ b/lib/storage.ts @@ -2328,9 +2328,16 @@ export async function exportAccounts( } const transactionState = transactionSnapshotContext.getStore(); - const storage = + if ( transactionState?.active && - transactionState.storagePath === activeStoragePath + transactionState.storagePath !== activeStoragePath + ) { + throw new Error( + `No accounts to export: export was called from a different storage path ` + + `(transaction path: ${transactionState.storagePath}, active: ${activeStoragePath})`, + ); + } + const storage = transactionState?.active ? transactionState.snapshot : await withAccountStorageTransaction((current) => Promise.resolve(current), diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index b8d9a98d..d382c89d 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -20,6 +20,8 @@ const DEFAULT_SESSION_BINDING_POLL_MS = 50; const DEFAULT_STORAGE_LOCK_WAIT_MS = 10_000; const DEFAULT_STORAGE_LOCK_POLL_MS = 100; const DEFAULT_STORAGE_LOCK_TTL_MS = 30_000; +const DEFAULT_UNLINK_RETRY_ATTEMPTS = 4; +const DEFAULT_UNLINK_RETRY_BASE_DELAY_MS = 25; const INTERNAL_RECOVERABLE_COOLDOWN_MS = 60_000; const SESSION_ID_PATTERN = /^[A-Za-z0-9_][A-Za-z0-9_-]{0,127}$/; const SESSION_META_SCAN_LINE_LIMIT = 200; @@ -64,6 +66,15 @@ function createAbortError(message = "Operation aborted") { return error; } +function createProbeUnavailableError(error) { + const wrapped = new Error( + error instanceof Error ? error.message : String(error), + { cause: error }, + ); + wrapped.name = "QuotaProbeUnavailableError"; + return wrapped; +} + function abortablePromise(promise, signal, message = "Operation aborted") { if (!signal) return promise; if (signal.aborted) { @@ -309,20 +320,30 @@ async function persistActiveSelection(manager, account) { } async function safeUnlink(path) { - try { - await fs.unlink(path); - return true; - } catch (error) { - if ( - error && - typeof error === "object" && - "code" in error && - error.code === "ENOENT" - ) { + for (let attempt = 0; attempt < DEFAULT_UNLINK_RETRY_ATTEMPTS; attempt += 1) { + try { + await fs.unlink(path); return true; + } catch (error) { + const code = + error && typeof error === "object" && "code" in error + ? `${error.code ?? ""}` + : ""; + if (code === "ENOENT") { + return true; + } + const canRetry = + (code === "EPERM" || code === "EBUSY") && + attempt + 1 < DEFAULT_UNLINK_RETRY_ATTEMPTS; + if (!canRetry) { + return false; + } + await new Promise((resolve) => + setTimeout(resolve, DEFAULT_UNLINK_RETRY_BASE_DELAY_MS * (attempt + 1)), + ); } - return false; } + return false; } function getSupervisorStoragePath(runtime) { @@ -482,7 +503,6 @@ function getManagerAccounts(manager, extraAccounts = []) { if (!item) continue; const key = [ `${item.index ?? ""}`, - `${item.refreshToken ?? ""}`, `${item.accountId ?? ""}`, `${item.email ?? ""}`, ].join("|"); @@ -496,10 +516,9 @@ function getManagerAccounts(manager, extraAccounts = []) { function getAccountIdentityKey(account) { if (!account) return ""; return [ - `${account.refreshToken ?? ""}`, + `${account.index ?? ""}`, `${account.accountId ?? ""}`, `${account.email ?? ""}`, - `${account.index ?? ""}`, ].join("|"); } @@ -811,7 +830,7 @@ async function probeAccountSnapshot(runtime, account, signal, timeoutMs, options if (signal?.aborted || error?.name === "AbortError") { throw error; } - return null; + throw createProbeUnavailableError(error); } finally { if (cacheKey) { const current = snapshotProbeCache.get(cacheKey); @@ -840,6 +859,9 @@ async function probeAccountSnapshot(runtime, account, signal, timeoutMs, options if (signal?.aborted || error?.name === "AbortError") { throw error; } + if (error?.name === "QuotaProbeUnavailableError") { + throw error; + } return null; } } @@ -968,7 +990,15 @@ async function ensureLaunchableAccount( if (signal?.aborted || error?.name === "AbortError") { throw error; } - throw error; + return { + account, + snapshot: null, + evaluation: { + rotate: true, + reason: "probe-error", + waitMs: 0, + }, + }; } })(), ); @@ -1443,6 +1473,9 @@ async function runInteractiveSupervision({ if (monitorController.signal.aborted || error?.name === "AbortError") { break; } + if (error?.name === "QuotaProbeUnavailableError") { + continue; + } throw error; } const pressure = computeQuotaPressure( @@ -1551,9 +1584,23 @@ async function runInteractiveSupervision({ if (signal?.aborted) { return result.exitCode; } - const snapshot = refreshedState.currentAccount - ? await probeAccountSnapshot(runtime, refreshedState.currentAccount, signal) - : null; + let snapshot = null; + if (refreshedState.currentAccount) { + try { + snapshot = await probeAccountSnapshot( + runtime, + refreshedState.currentAccount, + signal, + ); + } catch (error) { + if (signal?.aborted || error?.name === "AbortError") { + throw error; + } + if (error?.name !== "QuotaProbeUnavailableError") { + throw error; + } + } + } const evaluation = evaluateQuotaSnapshot(snapshot, runtime, pluginConfig); if (evaluation.rotate) { restartDecision = { diff --git a/test/codex-bin-wrapper.test.ts b/test/codex-bin-wrapper.test.ts index 2921ca52..225fb101 100644 --- a/test/codex-bin-wrapper.test.ts +++ b/test/codex-bin-wrapper.test.ts @@ -109,6 +109,23 @@ function writeSupervisorRuntimeFixture(fixtureRoot: string): void { ); } +function writeCodexManagerAutoSyncFixture(fixtureRoot: string): void { + const distLibDir = join(fixtureRoot, "dist", "lib"); + mkdirSync(distLibDir, { recursive: true }); + writeFileSync( + join(distLibDir, "codex-manager.js"), + [ + 'import { appendFile } from "node:fs/promises";', + "export async function autoSyncActiveAccountToCodex() {", + '\tconst markerPath = process.env.CODEX_TEST_AUTO_SYNC_MARKER ?? "";', + "\tif (!markerPath) return;", + '\tawait appendFile(markerPath, "sync\\n", "utf8");', + "}", + ].join("\n"), + "utf8", + ); +} + function createFakeCodexBin(rootDir: string): string { const fakeBin = join(rootDir, "fake-codex.js"); writeFileSync( @@ -608,4 +625,41 @@ describe("codex bin wrapper", () => { 'FORWARDED:exec status -c cli_auth_credentials_store="file"', ); }); + + it("still auto-syncs once when the supervisor returns early", () => { + const fixtureRoot = createWrapperFixture(); + writeSupervisorRuntimeFixture(fixtureRoot); + writeCodexManagerAutoSyncFixture(fixtureRoot); + const fakeBin = createFakeCodexBin(fixtureRoot); + const markerPath = join(fixtureRoot, "auto-sync.log"); + + const result = runWrapper(fixtureRoot, ["exec", "status"], { + CODEX_MULTI_AUTH_REAL_CODEX_BIN: fakeBin, + CODEX_AUTH_CLI_SESSION_SUPERVISOR: "1", + CODEX_TEST_AUTO_SYNC_MARKER: markerPath, + }); + + expect(result.status).toBe(0); + expect(result.stdout.match(/FORWARDED:/g) ?? []).toHaveLength(1); + expect(readFileSync(markerPath, "utf8")).toBe("sync\n"); + }); + + it("supports interactive commands through the supervisor wrapper", () => { + const fixtureRoot = createWrapperFixture(); + writeSupervisorRuntimeFixture(fixtureRoot); + writeCodexManagerAutoSyncFixture(fixtureRoot); + const fakeBin = createFakeCodexBin(fixtureRoot); + const markerPath = join(fixtureRoot, "interactive-auto-sync.log"); + + const result = runWrapper(fixtureRoot, [], { + CODEX_MULTI_AUTH_REAL_CODEX_BIN: fakeBin, + CODEX_AUTH_CLI_SESSION_SUPERVISOR: "1", + CODEX_TEST_AUTO_SYNC_MARKER: markerPath, + }); + + expect(result.status).toBe(0); + expect(result.stdout).toContain('FORWARDED:-c cli_auth_credentials_store="file"'); + expect(result.stdout.match(/FORWARDED:/g) ?? []).toHaveLength(1); + expect(readFileSync(markerPath, "utf8")).toBe("sync\n"); + }); }); diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index c4739707..85e0b5d9 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -312,6 +312,67 @@ describe("codex supervisor", () => { expect(child.kill).toHaveBeenCalledWith("SIGKILL"); }); + it("sends SIGINT before escalating on non-Windows platforms", async () => { + vi.useFakeTimers(); + class FakeChild extends EventEmitter { + exitCode: number | null = null; + kill = vi.fn((_signal: string) => true); + } + + const child = new FakeChild(); + const pending = supervisorTestApi?.requestChildRestart(child, "linux"); + + await vi.runAllTimersAsync(); + await expect(pending).resolves.toBeUndefined(); + expect(child.kill.mock.calls.map(([signal]) => signal)).toEqual([ + "SIGINT", + "SIGTERM", + "SIGKILL", + ]); + }); + + it("cleans up stale supervisor locks even after a transient Windows unlink failure", async () => { + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager); + const lockPath = supervisorTestApi?.getSupervisorStorageLockPath(runtime); + expect(lockPath).toBeTruthy(); + if (!lockPath) { + throw new Error("expected a supervisor lock path"); + } + + await fs.mkdir(join(lockPath, ".."), { recursive: true }).catch(() => {}); + await fs.writeFile( + lockPath, + JSON.stringify({ + pid: 1, + acquiredAt: Date.now() - 60_000, + expiresAt: Date.now() - 1_000, + }), + "utf8", + ); + + const originalUnlink = fs.unlink.bind(fs); + const unlinkSpy = vi + .spyOn(fs, "unlink") + .mockImplementationOnce(async () => { + const error = Object.assign(new Error("file busy"), { code: "EPERM" }); + throw error; + }) + .mockImplementation(originalUnlink); + + try { + await expect( + supervisorTestApi?.withLockedManager(runtime, async (loadedManager: FakeManager) => { + expect(loadedManager).toBe(manager); + return "locked"; + }), + ).resolves.toBe("locked"); + expect(unlinkSpy.mock.calls.length).toBeGreaterThanOrEqual(2); + } finally { + unlinkSpy.mockRestore(); + } + }); + it("skips a near-limit current account and selects the next healthy account", async () => { const manager = new FakeManager(); const runtime = createFakeRuntime(manager); @@ -595,4 +656,31 @@ describe("codex supervisor", () => { expect(manager.activeIndex).toBe(3); expect(elapsedMs).toBeLessThan(170); }); + + it("degrades a failed candidate probe and continues to the next healthy account", async () => { + const manager = new FakeManager([ + { accountId: "broken", access: "token-broken" }, + { accountId: "healthy", access: "token-healthy" }, + ]); + const runtime = createFakeRuntime(manager, { + onFetch(accountId) { + if (accountId === "broken") { + throw new Error("network fault"); + } + }, + }); + + const result = await supervisorTestApi?.ensureLaunchableAccount( + runtime, + {}, + undefined, + { probeTimeoutMs: 250 }, + ); + + expect(result).toMatchObject({ + ok: true, + account: { accountId: "healthy" }, + }); + expect(manager.activeIndex).toBe(1); + }); }); diff --git a/test/plugin-config.test.ts b/test/plugin-config.test.ts index f5a9f3fd..c293d76a 100644 --- a/test/plugin-config.test.ts +++ b/test/plugin-config.test.ts @@ -993,6 +993,13 @@ describe('Plugin Configuration', () => { expect(getCodexCliSessionSupervisor({})).toBe(false); }); + it('should honor the config value when the env override is unset', () => { + delete process.env.CODEX_AUTH_CLI_SESSION_SUPERVISOR; + expect( + getCodexCliSessionSupervisor({ codexCliSessionSupervisor: true }), + ).toBe(true); + }); + it('should prioritize environment override for the supervisor wrapper', () => { process.env.CODEX_AUTH_CLI_SESSION_SUPERVISOR = '1'; expect(getCodexCliSessionSupervisor({ codexCliSessionSupervisor: false })).toBe(true); diff --git a/test/preemptive-quota-scheduler.test.ts b/test/preemptive-quota-scheduler.test.ts index 1d58db8c..71e0e610 100644 --- a/test/preemptive-quota-scheduler.test.ts +++ b/test/preemptive-quota-scheduler.test.ts @@ -142,6 +142,20 @@ describe("preemptive quota scheduler", () => { expect(decision.reason).toBe("quota-near-exhaustion"); }); + it("defaults the primary remaining threshold to 10 percent", () => { + const scheduler = new PreemptiveQuotaScheduler(); + scheduler.update("acc:model", { + status: 200, + primary: { usedPercent: 91, resetAtMs: 65_000 }, + secondary: {}, + updatedAt: 1_000, + }); + + const decision = scheduler.getDeferral("acc:model", 5_000); + expect(decision.defer).toBe(true); + expect(decision.reason).toBe("quota-near-exhaustion"); + }); + it("can disable preemptive deferral without clearing snapshots", () => { const scheduler = new PreemptiveQuotaScheduler(); scheduler.markRateLimited("acc:model", 30_000, 1_000); diff --git a/test/quota-probe.test.ts b/test/quota-probe.test.ts index 59db37ee..cdaf66a1 100644 --- a/test/quota-probe.test.ts +++ b/test/quota-probe.test.ts @@ -203,6 +203,25 @@ describe("quota-probe", () => { await expect(pending).rejects.toThrow(/abort/i); expect(fetchMock).toHaveBeenCalledTimes(1); }); + + it("rejects immediately when the caller signal is already aborted", async () => { + const controller = new AbortController(); + controller.abort(); + const fetchMock = vi.fn(); + vi.stubGlobal("fetch", fetchMock); + + await expect( + fetchCodexQuotaSnapshot({ + accountId: "acc-pre-aborted", + accessToken: "token-pre-aborted", + model: "gpt-5-codex", + fallbackModels: [], + timeoutMs: 30_000, + signal: controller.signal, + }), + ).rejects.toThrow(/abort/i); + expect(fetchMock).not.toHaveBeenCalled(); + }); it("parses reset-at values expressed as epoch seconds and epoch milliseconds", async () => { const nowSec = Math.floor(Date.now() / 1000); const primarySeconds = nowSec + 120; diff --git a/test/storage.test.ts b/test/storage.test.ts index ccca65c0..8831c1f4 100644 --- a/test/storage.test.ts +++ b/test/storage.test.ts @@ -956,6 +956,146 @@ describe("storage", () => { ); }); + it("fails fast when export is called from an active transaction after the storage path changes", async () => { + const secondaryStoragePath = join(testWorkDir, "accounts-secondary.json"); + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-primary", + refreshToken: "refresh-primary", + addedAt: 1, + lastUsed: 2, + }, + ], + }); + setStoragePathDirect(secondaryStoragePath); + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-secondary", + refreshToken: "refresh-secondary", + addedAt: 3, + lastUsed: 4, + }, + ], + }); + setStoragePathDirect(testStoragePath); + + await expect( + withAccountStorageTransaction(async () => { + setStoragePathDirect(secondaryStoragePath); + await exportAccounts(exportPath); + }), + ).rejects.toThrow(/different storage path/); + expect(existsSync(exportPath)).toBe(false); + }); + + it("reloads fresh storage after a transaction handler throws", async () => { + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-before-throw", + refreshToken: "refresh-before-throw", + addedAt: 1, + lastUsed: 2, + }, + ], + }); + + await expect( + withAccountStorageTransaction(async (current, persist) => { + await persist({ + ...(current ?? { version: 3, activeIndex: 0, accounts: [] }), + accounts: [ + { + accountId: "acct-thrown", + refreshToken: "refresh-thrown", + addedAt: 3, + lastUsed: 4, + }, + ], + }); + throw new Error("boom"); + }), + ).rejects.toThrow("boom"); + + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-after-throw", + refreshToken: "refresh-after-throw", + addedAt: 5, + lastUsed: 6, + }, + ], + }); + + await exportAccounts(exportPath); + const exported = JSON.parse(await fs.readFile(exportPath, "utf-8")); + expect(exported.accounts[0].accountId).toBe("acct-after-throw"); + }); + + it("reloads fresh storage after a combined transaction handler throws", async () => { + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-before-combined-throw", + refreshToken: "refresh-before-combined-throw", + addedAt: 1, + lastUsed: 2, + }, + ], + }); + await saveFlaggedAccounts({ version: 1, accounts: [] }); + + await expect( + withAccountAndFlaggedStorageTransaction(async (current, persist) => { + await persist( + { + ...(current ?? { version: 3, activeIndex: 0, accounts: [] }), + accounts: [ + { + accountId: "acct-combined-thrown", + refreshToken: "refresh-combined-thrown", + addedAt: 3, + lastUsed: 4, + }, + ], + }, + { version: 1, accounts: [] }, + ); + throw new Error("combined boom"); + }), + ).rejects.toThrow("combined boom"); + + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-after-combined-throw", + refreshToken: "refresh-after-combined-throw", + addedAt: 5, + lastUsed: 6, + }, + ], + }); + + await exportAccounts(exportPath); + const exported = JSON.parse(await fs.readFile(exportPath, "utf-8")); + expect(exported.accounts[0].accountId).toBe("acct-after-combined-throw"); + }); + it("should fail import when file does not exist", async () => { const { importAccounts } = await import("../lib/storage.js"); const nonexistentPath = join(testWorkDir, "nonexistent-file.json"); From 2ff7edecab5e57bf1fda989f3aa83e8884b4f945 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 20:54:22 +0800 Subject: [PATCH 07/24] Optimize session binding reuse --- scripts/codex-supervisor.js | 96 +++++++++++++++++++++++++---------- test/codex-supervisor.test.ts | 49 ++++++++++++++++++ 2 files changed, 117 insertions(+), 28 deletions(-) diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index d382c89d..c505b96c 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -1253,21 +1253,56 @@ async function extractSessionMeta(filePath) { return null; } -async function findSessionBinding({ cwd, sinceMs, sessionId }) { - const sessionsRoot = getSessionsRootDir(); +async function matchSessionBindingEntry(entry, cwdKey, sessionId) { + const meta = await extractSessionMeta(entry.filePath); + if (!meta) return null; + if (sessionId && meta.sessionId === sessionId) { + return { + sessionId: meta.sessionId, + rolloutPath: entry.filePath, + lastActivityAtMs: entry.mtimeMs, + }; + } + const metaCwdKey = normalizeCwd(meta.cwd); + if (!cwdKey || !metaCwdKey || metaCwdKey !== cwdKey) return null; + return { + sessionId: meta.sessionId, + rolloutPath: entry.filePath, + lastActivityAtMs: entry.mtimeMs, + }; +} + +async function readSessionBindingEntry(filePath) { + try { + const stat = await fs.stat(filePath); + return { + filePath, + mtimeMs: stat.mtimeMs, + }; + } catch { + return null; + } +} + +async function findSessionBinding({ cwd, sinceMs, sessionId, rolloutPathHint }) { const cwdKey = normalizeCwd(cwd); + if (rolloutPathHint) { + const directEntry = await readSessionBindingEntry(rolloutPathHint); + if (directEntry) { + const directBinding = await matchSessionBindingEntry( + directEntry, + cwdKey, + sessionId, + ); + if (directBinding) return directBinding; + } + } + + const sessionsRoot = getSessionsRootDir(); const files = ( await Promise.all( (await listJsonlFiles(sessionsRoot)).map(async (filePath) => { - try { - const stat = await fs.stat(filePath); - return { - filePath, - mtimeMs: stat.mtimeMs, - }; - } catch { - return null; - } + return readSessionBindingEntry(filePath); }), ) ) @@ -1275,22 +1310,8 @@ async function findSessionBinding({ cwd, sinceMs, sessionId }) { .sort((left, right) => right.mtimeMs - left.mtimeMs); for (const entry of files) { - const meta = await extractSessionMeta(entry.filePath); - if (!meta) continue; - if (sessionId && meta.sessionId === sessionId) { - return { - sessionId: meta.sessionId, - rolloutPath: entry.filePath, - lastActivityAtMs: entry.mtimeMs, - }; - } - const metaCwdKey = normalizeCwd(meta.cwd); - if (!cwdKey || !metaCwdKey || metaCwdKey !== cwdKey) continue; - return { - sessionId: meta.sessionId, - rolloutPath: entry.filePath, - lastActivityAtMs: entry.mtimeMs, - }; + const binding = await matchSessionBindingEntry(entry, cwdKey, sessionId); + if (binding) return binding; } return null; @@ -1300,6 +1321,7 @@ async function waitForSessionBinding({ cwd, sinceMs, sessionId, + rolloutPathHint, timeoutMs, signal, }) { @@ -1310,7 +1332,12 @@ async function waitForSessionBinding({ 25, ); while (Date.now() <= deadline) { - const binding = await findSessionBinding({ cwd, sinceMs, sessionId }); + const binding = await findSessionBinding({ + cwd, + sinceMs, + sessionId, + rolloutPathHint, + }); if (binding) return binding; const slept = await sleep(pollMs, signal); if (!slept) return null; @@ -1375,6 +1402,7 @@ async function runInteractiveSupervision({ }) { let launchArgs = initialArgs; let knownSessionId = readResumeSessionId(initialArgs); + let knownRolloutPath = null; let launchCount = 0; while (launchCount < MAX_SESSION_RESTARTS) { @@ -1389,8 +1417,12 @@ async function runInteractiveSupervision({ cwd: process.cwd(), sinceMs: 0, sessionId: knownSessionId, + rolloutPathHint: knownRolloutPath, }) : null; + if (binding?.rolloutPath) { + knownRolloutPath = binding.rolloutPath; + } let requestedRestart = null; let preparedResumeSelectionPromise = null; let preparedResumeSelectionStarted = false; @@ -1431,14 +1463,19 @@ async function runInteractiveSupervision({ cwd: process.cwd(), sinceMs: launchStartedAt, sessionId: knownSessionId, + rolloutPathHint: knownRolloutPath, timeoutMs: captureTimeoutMs, signal: monitorController.signal, }); if (binding?.sessionId) { knownSessionId = binding.sessionId; + knownRolloutPath = binding.rolloutPath ?? knownRolloutPath; } } else { binding = await refreshSessionActivity(binding); + if (binding?.rolloutPath) { + knownRolloutPath = binding.rolloutPath; + } } if (!requestedRestart) { @@ -1565,9 +1602,11 @@ async function runInteractiveSupervision({ cwd: process.cwd(), sinceMs: launchStartedAt, sessionId: knownSessionId, + rolloutPathHint: knownRolloutPath, })); if (binding?.sessionId) { knownSessionId = binding.sessionId; + knownRolloutPath = binding.rolloutPath ?? knownRolloutPath; } let restartDecision = requestedRestart; @@ -1674,6 +1713,7 @@ async function runInteractiveSupervision({ logRotationSummary(restartDecision.sessionId, rotationTrace, nextReady); launchArgs = buildResumeArgs(restartDecision.sessionId, buildForwardArgs); knownSessionId = restartDecision.sessionId; + knownRolloutPath = binding?.rolloutPath ?? knownRolloutPath; } relaunchNotice("session supervisor reached the restart safety limit"); diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 85e0b5d9..28cf415d 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -11,6 +11,7 @@ const envKeys = [ "CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS", "CODEX_AUTH_CLI_SESSION_BINDING_POLL_MS", "CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS", + "CODEX_HOME", ] as const; const originalEnv = Object.fromEntries( envKeys.map((key) => [key, process.env[key]]), @@ -290,6 +291,54 @@ describe("codex supervisor", () => { await expect(supervisorTestApi?.extractSessionMeta(filePath)).resolves.toBeNull(); }); + it("reuses the known rollout path before scanning the sessions tree again", async () => { + const codexHome = createTempDir(); + const cwd = createTempDir(); + process.env.CODEX_HOME = codexHome; + + const sessionsDir = join(codexHome, "sessions", "2026", "03", "20"); + await fs.mkdir(sessionsDir, { recursive: true }); + const rolloutPath = join(sessionsDir, "known-session.jsonl"); + await fs.writeFile( + rolloutPath, + JSON.stringify({ + session_meta: { + payload: { id: "known-session", cwd }, + }, + }), + "utf8", + ); + + const first = await supervisorTestApi?.findSessionBinding({ + cwd, + sinceMs: 0, + sessionId: "known-session", + }); + expect(first).toMatchObject({ + sessionId: "known-session", + rolloutPath, + }); + + const readdirSpy = vi.spyOn(fs, "readdir"); + readdirSpy.mockRejectedValue(new Error("should not rescan sessions")); + + try { + const second = await supervisorTestApi?.findSessionBinding({ + cwd, + sinceMs: 0, + sessionId: "known-session", + rolloutPathHint: first?.rolloutPath, + }); + expect(second).toMatchObject({ + sessionId: "known-session", + rolloutPath, + }); + expect(readdirSpy).not.toHaveBeenCalled(); + } finally { + readdirSpy.mockRestore(); + } + }); + it("interrupts child restart waits when the abort signal fires", async () => { vi.useFakeTimers(); class FakeChild extends EventEmitter { From 51d637e0c2570140167fac09e72ec26690660769 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 20:58:06 +0800 Subject: [PATCH 08/24] Add supervisor lock regression --- test/codex-supervisor.test.ts | 59 +++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 28cf415d..9d020c17 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -10,6 +10,8 @@ const createdDirs: string[] = []; const envKeys = [ "CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS", "CODEX_AUTH_CLI_SESSION_BINDING_POLL_MS", + "CODEX_AUTH_CLI_SESSION_LOCK_POLL_MS", + "CODEX_AUTH_CLI_SESSION_LOCK_WAIT_MS", "CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS", "CODEX_HOME", ] as const; @@ -422,6 +424,63 @@ describe("codex supervisor", () => { } }); + it("serializes concurrent callers behind the supervisor storage lock", async () => { + process.env.CODEX_AUTH_CLI_SESSION_LOCK_WAIT_MS = "1000"; + process.env.CODEX_AUTH_CLI_SESSION_LOCK_POLL_MS = "10"; + + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager); + const order: string[] = []; + let releaseFirst: (() => void) | null = null; + let resolveFirstEntered: (() => void) | null = null; + let resolveSecondEntered: (() => void) | null = null; + const firstEntered = new Promise((resolve) => { + resolveFirstEntered = resolve; + }); + const secondEntered = new Promise((resolve) => { + resolveSecondEntered = resolve; + }); + let secondHasLock = false; + + const first = supervisorTestApi?.withLockedManager( + runtime, + async (loadedManager: FakeManager) => { + expect(loadedManager).toBe(manager); + order.push("first-enter"); + resolveFirstEntered?.(); + await new Promise((resolve) => { + releaseFirst = resolve; + }); + order.push("first-exit"); + return "first"; + }, + ); + + await firstEntered; + + const second = supervisorTestApi?.withLockedManager( + runtime, + async (loadedManager: FakeManager) => { + expect(loadedManager).toBe(manager); + secondHasLock = true; + order.push("second-enter"); + resolveSecondEntered?.(); + return "second"; + }, + ); + + await supervisorTestApi?.sleep(40); + expect(secondHasLock).toBe(false); + releaseFirst?.(); + + await secondEntered; + await expect(Promise.all([first, second])).resolves.toEqual([ + "first", + "second", + ]); + expect(order).toEqual(["first-enter", "first-exit", "second-enter"]); + }); + it("skips a near-limit current account and selects the next healthy account", async () => { const manager = new FakeManager(); const runtime = createFakeRuntime(manager); From ed2bddb6e3159791cf4303b973d80f995cb939cc Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 21:12:30 +0800 Subject: [PATCH 09/24] Fix supervisor and storage review regressions --- lib/storage.ts | 35 ++-- scripts/benchmark-session-supervisor.mjs | 20 ++- scripts/codex-supervisor.js | 49 ++++-- test/codex-bin-wrapper.test.ts | 8 + test/codex-supervisor.test.ts | 201 +++++++++++++++-------- test/quota-probe.test.ts | 7 +- test/storage.test.ts | 159 ++++++++++++++++++ 7 files changed, 380 insertions(+), 99 deletions(-) diff --git a/lib/storage.ts b/lib/storage.ts index f255507a..c5b0425d 100644 --- a/lib/storage.ts +++ b/lib/storage.ts @@ -723,8 +723,13 @@ function latestValidSnapshot( snapshots: BackupSnapshotMetadata[], ): BackupSnapshotMetadata | undefined { return snapshots - .filter((snapshot) => snapshot.valid) - .sort((left, right) => (right.mtimeMs ?? 0) - (left.mtimeMs ?? 0))[0]; + .map((snapshot, index) => ({ snapshot, index })) + .filter(({ snapshot }) => snapshot.valid) + .sort( + (left, right) => + (right.snapshot.mtimeMs ?? 0) - (left.snapshot.mtimeMs ?? 0) || + right.index - left.index, + )[0]?.snapshot; } function buildMetadataSection( @@ -1598,8 +1603,9 @@ async function loadAccountsFromJournal( async function loadAccountsInternal( persistMigration: ((storage: AccountStorageV3) => Promise) | null, + storagePath = getStoragePath(), ): Promise { - const path = getStoragePath(); + const path = storagePath; const resetMarkerPath = getIntentionalResetMarkerPath(path); await cleanupStaleRotatingBackupArtifacts(path); const migratedLegacyStorage = persistMigration @@ -1763,8 +1769,11 @@ async function loadAccountsInternal( } } -async function saveAccountsUnlocked(storage: AccountStorageV3): Promise { - const path = getStoragePath(); +async function saveAccountsUnlocked( + storage: AccountStorageV3, + storagePath = getStoragePath(), +): Promise { + const path = storagePath; const resetMarkerPath = getIntentionalResetMarkerPath(path); const uniqueSuffix = `${Date.now()}.${Math.random().toString(36).slice(2, 8)}`; const tempPath = `${path}.${uniqueSuffix}.tmp`; @@ -1915,13 +1924,16 @@ export async function withAccountStorageTransaction( return withStorageLock(async () => { const storagePath = getStoragePath(); const state = { - snapshot: await loadAccountsInternal(saveAccountsUnlocked), + snapshot: await loadAccountsInternal( + (storage) => saveAccountsUnlocked(storage, storagePath), + storagePath, + ), active: true, storagePath, }; const current = state.snapshot; const persist = async (storage: AccountStorageV3): Promise => { - await saveAccountsUnlocked(storage); + await saveAccountsUnlocked(storage, storagePath); state.snapshot = storage; }; return transactionSnapshotContext.run(state, async () => { @@ -1946,7 +1958,10 @@ export async function withAccountAndFlaggedStorageTransaction( return withStorageLock(async () => { const storagePath = getStoragePath(); const state = { - snapshot: await loadAccountsInternal(saveAccountsUnlocked), + snapshot: await loadAccountsInternal( + (storage) => saveAccountsUnlocked(storage, storagePath), + storagePath, + ), active: true, storagePath, }; @@ -1957,13 +1972,13 @@ export async function withAccountAndFlaggedStorageTransaction( ): Promise => { const previousAccounts = cloneAccountStorageForPersistence(state.snapshot); const nextAccounts = cloneAccountStorageForPersistence(accountStorage); - await saveAccountsUnlocked(nextAccounts); + await saveAccountsUnlocked(nextAccounts, storagePath); try { await saveFlaggedAccountsUnlocked(flaggedStorage); state.snapshot = nextAccounts; } catch (error) { try { - await saveAccountsUnlocked(previousAccounts); + await saveAccountsUnlocked(previousAccounts, storagePath); state.snapshot = previousAccounts; } catch (rollbackError) { const combinedError = new AggregateError( diff --git a/scripts/benchmark-session-supervisor.mjs b/scripts/benchmark-session-supervisor.mjs index dd3447b2..95286013 100644 --- a/scripts/benchmark-session-supervisor.mjs +++ b/scripts/benchmark-session-supervisor.mjs @@ -49,7 +49,7 @@ class FakeManager { refreshToken: `rt_${account.accountId}`, email: `${account.accountId}@example.com`, enabled: true, - cooldownUntil: 0, + coolingDownUntil: 0, ...account, })); this.activeIndex = 0; @@ -75,7 +75,9 @@ class FakeManager { ].filter(Boolean); return ( ordered.find( - (account) => account.enabled !== false && (account.cooldownUntil ?? 0) <= now, + (account) => + account.enabled !== false && + (account.coolingDownUntil ?? 0) <= now, ) ?? null ); } @@ -83,7 +85,7 @@ class FakeManager { getMinWaitTimeForFamily() { const now = Date.now(); const waits = this.accounts - .map((account) => Math.max(0, (account.cooldownUntil ?? 0) - now)) + .map((account) => Math.max(0, (account.coolingDownUntil ?? 0) - now)) .filter((waitMs) => waitMs > 0); return waits.length > 0 ? Math.min(...waits) : 0; } @@ -91,7 +93,7 @@ class FakeManager { markRateLimitedWithReason(account, waitMs) { const target = this.getAccountByIndex(account.index); if (!target) return; - target.cooldownUntil = Date.now() + Math.max(waitMs, 1); + target.coolingDownUntil = Date.now() + Math.max(waitMs, 1); } markAccountCoolingDown(account, waitMs) { @@ -195,6 +197,8 @@ async function runCase( const prewarmedDurations = []; const originalBatchSize = process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE; + const originalCacheTtl = + process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS; if (harnessOptions.selectionProbeBatchSize) { process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE = `${harnessOptions.selectionProbeBatchSize}`; } @@ -202,6 +206,8 @@ async function runCase( try { for (let iteration = 0; iteration < iterations; iteration += 1) { process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "75"; + process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS = "0"; + api.clearAllProbeSnapshotCache?.(); const serialEnv = await buildRuntime( probeLatencyMs, tempRoot, @@ -257,6 +263,12 @@ async function runCase( } } finally { delete process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS; + if (originalCacheTtl === undefined) { + delete process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS; + } else { + process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS = + originalCacheTtl; + } if (originalBatchSize === undefined) { delete process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE; } else { diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index c505b96c..612dc910 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -81,11 +81,17 @@ function abortablePromise(promise, signal, message = "Operation aborted") { return Promise.reject(createAbortError(message)); } + let onAbort; + const cleanup = () => { + if (onAbort) { + signal.removeEventListener("abort", onAbort); + } + }; return Promise.race([ - promise, + Promise.resolve(promise).finally(cleanup), new Promise((_, reject) => { - const onAbort = () => { - signal.removeEventListener("abort", onAbort); + onAbort = () => { + cleanup(); reject(createAbortError(message)); }; signal.addEventListener("abort", onAbort, { once: true }); @@ -526,7 +532,7 @@ function isEligibleProbeAccount(account, now = Date.now()) { return Boolean( account && account.enabled !== false && - (account.cooldownUntil ?? 0) <= now, + (account.coolingDownUntil ?? 0) <= now, ); } @@ -801,6 +807,9 @@ async function probeAccountSnapshot(runtime, account, signal, timeoutMs, options return null; } const cacheKey = getSnapshotCacheKey(account); + let pendingResolver = null; + let pendingRejecter = null; + let pendingPromise = null; if (options.useCache !== false) { const cachedSnapshot = readCachedProbeSnapshot(account); if (cachedSnapshot) { @@ -814,6 +823,18 @@ async function probeAccountSnapshot(runtime, account, signal, timeoutMs, options "Quota probe aborted", ); } + if (cacheKey) { + pendingPromise = new Promise((resolve, reject) => { + pendingResolver = resolve; + pendingRejecter = reject; + }); + pendingPromise.catch(() => undefined); + snapshotProbeCache.set(cacheKey, { + snapshot: pendingEntry?.snapshot ?? null, + expiresAt: pendingEntry?.expiresAt ?? 0, + pending: pendingPromise, + }); + } } const fetchPromise = (async () => { @@ -825,16 +846,22 @@ async function probeAccountSnapshot(runtime, account, signal, timeoutMs, options signal, }); rememberProbeSnapshot(account, snapshot); + pendingResolver?.(snapshot); return snapshot; } catch (error) { + const normalizedError = + signal?.aborted || error?.name === "AbortError" + ? error + : createProbeUnavailableError(error); + pendingRejecter?.(normalizedError); if (signal?.aborted || error?.name === "AbortError") { throw error; } - throw createProbeUnavailableError(error); + throw normalizedError; } finally { if (cacheKey) { const current = snapshotProbeCache.get(cacheKey); - if (current?.pending) { + if (current?.pending === pendingPromise) { snapshotProbeCache.set(cacheKey, { snapshot: current.snapshot ?? null, expiresAt: current.expiresAt ?? 0, @@ -844,15 +871,6 @@ async function probeAccountSnapshot(runtime, account, signal, timeoutMs, options } })(); - if (cacheKey) { - const current = snapshotProbeCache.get(cacheKey); - snapshotProbeCache.set(cacheKey, { - snapshot: current?.snapshot ?? null, - expiresAt: current?.expiresAt ?? 0, - pending: fetchPromise, - }); - } - try { return await abortablePromise(fetchPromise, signal, "Quota probe aborted"); } catch (error) { @@ -1380,6 +1398,7 @@ async function requestChildRestart(child, platform = process.platform, signal) { await Promise.race([exitPromise, sleep(signalTimeoutMs, signal)]); if (child.exitCode !== null) return; + // On Windows, SIGTERM is already forceful; keep SIGKILL as the Unix fallback. child.kill("SIGKILL"); await Promise.race([exitPromise, sleep(signalTimeoutMs, signal)]); } diff --git a/test/codex-bin-wrapper.test.ts b/test/codex-bin-wrapper.test.ts index 225fb101..e1e75f9a 100644 --- a/test/codex-bin-wrapper.test.ts +++ b/test/codex-bin-wrapper.test.ts @@ -85,8 +85,13 @@ function writeSupervisorRuntimeFixture(fixtureRoot: string): void { writeFileSync( join(distLibDir, "accounts.js"), [ + 'import { appendFile } from "node:fs/promises";', "export class AccountManager {", "\tstatic async loadFromDisk() {", + '\t\tconst markerPath = process.env.CODEX_TEST_SUPERVISOR_MARKER ?? "";', + "\t\tif (markerPath) {", + '\t\t\tawait appendFile(markerPath, "supervisor\\n", "utf8");', + "\t\t}", "\t\treturn new AccountManager();", "\t}", "\tgetCurrentOrNextForFamilyHybrid() {", @@ -614,16 +619,19 @@ describe("codex bin wrapper", () => { const fixtureRoot = createWrapperFixture(); writeSupervisorRuntimeFixture(fixtureRoot); const fakeBin = createFakeCodexBin(fixtureRoot); + const markerPath = join(fixtureRoot, "supervisor-marker.log"); const result = runWrapper(fixtureRoot, ["exec", "status"], { CODEX_MULTI_AUTH_REAL_CODEX_BIN: fakeBin, CODEX_AUTH_CLI_SESSION_SUPERVISOR: "1", + CODEX_TEST_SUPERVISOR_MARKER: markerPath, }); expect(result.status).toBe(0); expect(result.stdout).toContain( 'FORWARDED:exec status -c cli_auth_credentials_store="file"', ); + expect(readFileSync(markerPath, "utf8")).toContain("supervisor\n"); }); it("still auto-syncs once when the supervisor returns early", () => { diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 9d020c17..f5e5718e 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -44,6 +44,14 @@ function createTempDir(): string { return dir; } +function createDeferred() { + let resolve!: (value: T | PromiseLike) => void; + const promise = new Promise((res) => { + resolve = res; + }); + return { promise, resolve }; +} + class FakeManager { private accounts: Array<{ index: number; @@ -52,7 +60,7 @@ class FakeManager { email: string; refreshToken: string; enabled: boolean; - cooldownUntil: number; + coolingDownUntil: number; }>; activeIndex = 0; @@ -64,7 +72,7 @@ class FakeManager { email?: string; refreshToken?: string; enabled?: boolean; - cooldownUntil?: number; + coolingDownUntil?: number; }> = [ { accountId: "near-limit", access: "token-1" }, { accountId: "healthy", access: "token-2" }, @@ -77,7 +85,7 @@ class FakeManager { email: account.email ?? `${account.accountId}@example.com`, refreshToken: account.refreshToken ?? `rt-${account.accountId}`, enabled: account.enabled ?? true, - cooldownUntil: account.cooldownUntil ?? 0, + coolingDownUntil: account.coolingDownUntil ?? 0, })); } @@ -101,7 +109,8 @@ class FakeManager { ].filter(Boolean); return ( ordered.find( - (account) => account.enabled !== false && account.cooldownUntil <= now, + (account) => + account.enabled !== false && account.coolingDownUntil <= now, ) ?? null ); } @@ -109,7 +118,7 @@ class FakeManager { getMinWaitTimeForFamily() { const now = Date.now(); const waits = this.accounts - .map((account) => Math.max(0, account.cooldownUntil - now)) + .map((account) => Math.max(0, account.coolingDownUntil - now)) .filter((waitMs) => waitMs > 0); return waits.length > 0 ? Math.min(...waits) : 0; } @@ -120,7 +129,7 @@ class FakeManager { ) { const target = this.getAccountByIndex(account.index); if (!target) return; - target.cooldownUntil = Date.now() + Math.max(waitMs, 1); + target.coolingDownUntil = Date.now() + Math.max(waitMs, 1); } markAccountCoolingDown( @@ -152,7 +161,9 @@ function createFakeRuntime( } >; delayByAccountId?: Map; + waitForFetchByAccountId?: Map>; onFetch?: (accountId: string) => void; + onFetchStart?: (accountId: string) => void; } = {}, ) { const storageDir = createTempDir(); @@ -178,6 +189,7 @@ function createFakeRuntime( ]); const fallbackProbeDelayMs = options.quotaProbeDelayMs ?? 0; const delayByAccountId = options.delayByAccountId ?? new Map(); + const waitForFetchByAccountId = options.waitForFetchByAccountId ?? new Map(); return { AccountManager: { @@ -208,6 +220,11 @@ function createFakeRuntime( signal?: AbortSignal; }) { options.onFetch?.(accountId); + options.onFetchStart?.(accountId); + const gate = waitForFetchByAccountId.get(accountId); + if (gate) { + await gate; + } const quotaProbeDelayMs = delayByAccountId.get(accountId) ?? fallbackProbeDelayMs; await new Promise((resolve, reject) => { @@ -496,7 +513,7 @@ describe("codex supervisor", () => { expect(result?.account?.accountId).toBe("healthy"); expect(manager.activeIndex).toBe(1); expect(manager.getCurrentAccountForFamily()?.accountId).toBe("healthy"); - expect(manager.getAccountByIndex(0)?.cooldownUntil ?? 0).toBeGreaterThan( + expect(manager.getAccountByIndex(0)?.coolingDownUntil ?? 0).toBeGreaterThan( Date.now() - 1, ); }); @@ -580,63 +597,97 @@ describe("codex supervisor", () => { expect(calls).toEqual(["near-limit"]); }); - it("overlaps selection with restart so handoff finishes sooner than the serial path", async () => { + it("shares the same in-flight probe across concurrent callers", async () => { + process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS = "5000"; + const manager = new FakeManager(); + const calls: string[] = []; + const nearLimitGate = createDeferred(); + const probeStarted = createDeferred(); + const runtime = createFakeRuntime(manager, { + waitForFetchByAccountId: new Map([["near-limit", nearLimitGate.promise]]), + onFetch(accountId) { + calls.push(accountId); + }, + onFetchStart(accountId) { + if (accountId === "near-limit") { + probeStarted.resolve(); + } + }, + }); + const account = manager.getCurrentAccountForFamily(); + + await supervisorTestApi?.clearProbeSnapshotCache(account); + const first = supervisorTestApi?.probeAccountSnapshot( + runtime, + account, + undefined, + 250, + ); + await probeStarted.promise; + const second = supervisorTestApi?.probeAccountSnapshot( + runtime, + account, + undefined, + 250, + ); + expect(calls).toEqual(["near-limit"]); + + nearLimitGate.resolve(); + const [firstSnapshot, secondSnapshot] = await Promise.all([first, second]); + expect(firstSnapshot).toEqual(secondSnapshot); + expect(calls).toEqual(["near-limit"]); + }); + + it("starts selection probing before restart finishes in overlap mode", async () => { process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "40"; - process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS = "0"; class FakeChild extends EventEmitter { exitCode: number | null = null; kill = vi.fn((_signal: string) => true); } - const serialManager = new FakeManager(); - const serialRuntime = createFakeRuntime(serialManager, { - quotaProbeDelayMs: 140, - }); - const serialChild = new FakeChild(); - const serialStart = performance.now(); - const serialResult = await (async () => { - await supervisorTestApi?.requestChildRestart(serialChild, "win32"); - return supervisorTestApi?.ensureLaunchableAccount( - serialRuntime, - {}, - undefined, - { probeTimeoutMs: 250 }, - ); - })(); - const serialElapsedMs = performance.now() - serialStart; - expect(serialResult).toMatchObject({ - ok: true, - account: { accountId: "healthy" }, - }); - const overlapManager = new FakeManager(); + const nearLimitGate = createDeferred(); + const probeStarted = createDeferred(); const overlapRuntime = createFakeRuntime(overlapManager, { - quotaProbeDelayMs: 140, + waitForFetchByAccountId: new Map([["near-limit", nearLimitGate.promise]]), + onFetchStart(accountId) { + if (accountId === "near-limit") { + probeStarted.resolve(); + } + }, }); const overlapChild = new FakeChild(); - const overlapStart = performance.now(); - const overlapResult = await Promise.all([ - supervisorTestApi?.requestChildRestart(overlapChild, "win32"), - supervisorTestApi?.ensureLaunchableAccount( - overlapRuntime, - {}, - undefined, - { probeTimeoutMs: 250 }, - ), - ]); - const overlapElapsedMs = performance.now() - overlapStart; - expect(overlapResult).toEqual([ + let restartFinished = false; + const restartPromise = supervisorTestApi?.requestChildRestart( + overlapChild, + "win32", + ).then(() => { + restartFinished = true; + }); + const selectionPromise = supervisorTestApi?.ensureLaunchableAccount( + overlapRuntime, + {}, + undefined, + { probeTimeoutMs: 250 }, + ); + await probeStarted.promise; + expect(restartFinished).toBe(false); + nearLimitGate.resolve(); + + await expect(Promise.all([ + restartPromise, + selectionPromise, + ])).resolves.toEqual([ undefined, expect.objectContaining({ ok: true, account: expect.objectContaining({ accountId: "healthy" }), }), ]); - expect(overlapElapsedMs).toBeLessThan(serialElapsedMs - 20); }); - it("keeps the prepared-selection path within the same pause envelope as overlap mode", async () => { + it("uses the prepared account without re-probing at cutover time", async () => { process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "40"; class FakeChild extends EventEmitter { @@ -644,30 +695,19 @@ describe("codex supervisor", () => { kill = vi.fn((_signal: string) => true); } - const overlapManager = new FakeManager(); - const overlapRuntime = createFakeRuntime(overlapManager, { + const calls: string[] = []; + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager, { quotaProbeDelayMs: 80, + onFetch(accountId) { + calls.push(accountId); + }, }); - const overlapStart = performance.now(); - await Promise.all([ - supervisorTestApi?.requestChildRestart(new FakeChild(), "win32"), - supervisorTestApi?.ensureLaunchableAccount( - overlapRuntime, - {}, - undefined, - { probeTimeoutMs: 250 }, - ), - ]); - const overlapElapsedMs = performance.now() - overlapStart; - const prewarmedManager = new FakeManager(); - const prewarmedRuntime = createFakeRuntime(prewarmedManager, { - quotaProbeDelayMs: 80, - }); - await supervisorTestApi?.prepareResumeSelection({ - runtime: prewarmedRuntime, + const prepared = await supervisorTestApi?.prepareResumeSelection({ + runtime, pluginConfig: {}, - currentAccount: prewarmedManager.getCurrentAccountForFamily(), + currentAccount: manager.getCurrentAccountForFamily(), restartDecision: { reason: "quota-near-exhaustion", waitMs: 0, @@ -675,11 +715,34 @@ describe("codex supervisor", () => { }, signal: undefined, }); - const prewarmedStart = performance.now(); - await supervisorTestApi?.requestChildRestart(new FakeChild(), "win32"); - const prewarmedElapsedMs = performance.now() - prewarmedStart; + expect(prepared?.nextReady).toMatchObject({ + ok: true, + account: { accountId: "healthy" }, + }); + expect(calls).toEqual(["healthy"]); - expect(prewarmedElapsedMs).toBeLessThan(overlapElapsedMs + 30); + calls.length = 0; + await supervisorTestApi?.markCurrentAccountForRestart( + runtime, + manager.getCurrentAccountForFamily(), + { + reason: "quota-near-exhaustion", + waitMs: 0, + sessionId: "prepared-session", + }, + undefined, + ); + await supervisorTestApi?.requestChildRestart(new FakeChild(), "win32"); + const committed = await supervisorTestApi?.commitPreparedSelection( + runtime, + prepared?.nextReady?.account, + undefined, + ); + expect(committed).toMatchObject({ + ok: true, + account: { accountId: "healthy" }, + }); + expect(calls).toEqual([]); }); it("commits the prepared account only at cutover time", async () => { diff --git a/test/quota-probe.test.ts b/test/quota-probe.test.ts index cdaf66a1..5db377ff 100644 --- a/test/quota-probe.test.ts +++ b/test/quota-probe.test.ts @@ -173,6 +173,10 @@ describe("quota-probe", () => { it("aborts immediately when the caller abort signal fires", async () => { const controller = new AbortController(); + let markFetchStarted!: () => void; + const fetchStarted = new Promise((resolve) => { + markFetchStarted = resolve; + }); const fetchMock = vi.fn((_url: string, init?: RequestInit) => { return new Promise((_resolve, reject) => { init?.signal?.addEventListener( @@ -184,6 +188,7 @@ describe("quota-probe", () => { }, { once: true }, ); + markFetchStarted(); }); }); vi.stubGlobal("fetch", fetchMock); @@ -197,7 +202,7 @@ describe("quota-probe", () => { signal: controller.signal, }); - await Promise.resolve(); + await fetchStarted; controller.abort(); await expect(pending).rejects.toThrow(/abort/i); diff --git a/test/storage.test.ts b/test/storage.test.ts index 8831c1f4..e061adf3 100644 --- a/test/storage.test.ts +++ b/test/storage.test.ts @@ -1043,6 +1043,113 @@ describe("storage", () => { expect(exported.accounts[0].accountId).toBe("acct-after-throw"); }); + it("persists transaction updates to the original storage path after path drift", async () => { + const secondaryExportPath = join(testWorkDir, "secondary-export.json"); + const secondaryStoragePath = join(testWorkDir, "secondary-storage.json"); + + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-primary-before-drift", + refreshToken: "refresh-primary-before-drift", + addedAt: 1, + lastUsed: 2, + }, + ], + }); + setStoragePathDirect(secondaryStoragePath); + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-secondary-before-drift", + refreshToken: "refresh-secondary-before-drift", + addedAt: 3, + lastUsed: 4, + }, + ], + }); + setStoragePathDirect(testStoragePath); + + await withAccountStorageTransaction(async (current, persist) => { + setStoragePathDirect(secondaryStoragePath); + await persist({ + ...(current ?? { version: 3, activeIndex: 0, accounts: [] }), + accounts: [ + { + accountId: "acct-primary-after-drift", + refreshToken: "refresh-primary-after-drift", + addedAt: 5, + lastUsed: 6, + }, + ], + }); + }); + + setStoragePathDirect(testStoragePath); + await exportAccounts(exportPath); + const primaryExport = JSON.parse(await fs.readFile(exportPath, "utf-8")); + expect(primaryExport.accounts[0].accountId).toBe("acct-primary-after-drift"); + + setStoragePathDirect(secondaryStoragePath); + await exportAccounts(secondaryExportPath); + const secondaryExport = JSON.parse( + await fs.readFile(secondaryExportPath, "utf-8"), + ); + expect(secondaryExport.accounts[0].accountId).toBe( + "acct-secondary-before-drift", + ); + }); + + it("reloads fresh storage after a transaction handler returns successfully", async () => { + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-before-success", + refreshToken: "refresh-before-success", + addedAt: 1, + lastUsed: 2, + }, + ], + }); + + await withAccountStorageTransaction(async (current, persist) => { + await persist({ + ...(current ?? { version: 3, activeIndex: 0, accounts: [] }), + accounts: [ + { + accountId: "acct-success", + refreshToken: "refresh-success", + addedAt: 3, + lastUsed: 4, + }, + ], + }); + }); + + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-after-success", + refreshToken: "refresh-after-success", + addedAt: 5, + lastUsed: 6, + }, + ], + }); + + await exportAccounts(exportPath); + const exported = JSON.parse(await fs.readFile(exportPath, "utf-8")); + expect(exported.accounts[0].accountId).toBe("acct-after-success"); + }); + it("reloads fresh storage after a combined transaction handler throws", async () => { await saveAccounts({ version: 3, @@ -1096,6 +1203,58 @@ describe("storage", () => { expect(exported.accounts[0].accountId).toBe("acct-after-combined-throw"); }); + it("reloads fresh storage after a combined transaction handler returns successfully", async () => { + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-before-combined-success", + refreshToken: "refresh-before-combined-success", + addedAt: 1, + lastUsed: 2, + }, + ], + }); + await saveFlaggedAccounts({ version: 1, accounts: [] }); + + await withAccountAndFlaggedStorageTransaction(async (current, persist) => { + await persist( + { + ...(current ?? { version: 3, activeIndex: 0, accounts: [] }), + accounts: [ + { + accountId: "acct-combined-success", + refreshToken: "refresh-combined-success", + addedAt: 3, + lastUsed: 4, + }, + ], + }, + { version: 1, accounts: [] }, + ); + }); + + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-after-combined-success", + refreshToken: "refresh-after-combined-success", + addedAt: 5, + lastUsed: 6, + }, + ], + }); + + await exportAccounts(exportPath); + const exported = JSON.parse(await fs.readFile(exportPath, "utf-8")); + expect(exported.accounts[0].accountId).toBe( + "acct-after-combined-success", + ); + }); + it("should fail import when file does not exist", async () => { const { importAccounts } = await import("../lib/storage.js"); const nonexistentPath = join(testWorkDir, "nonexistent-file.json"); From ecf17d68bbc7cf5827eccd17965e6af60a80c83c Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 21:18:22 +0800 Subject: [PATCH 10/24] Fix remaining supervisor review follow-ups --- lib/preemptive-quota-scheduler.ts | 7 ++++--- scripts/codex.js | 2 ++ test/preemptive-quota-scheduler.test.ts | 26 +++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/preemptive-quota-scheduler.ts b/lib/preemptive-quota-scheduler.ts index b3a3e3ba..0fcc9b46 100644 --- a/lib/preemptive-quota-scheduler.ts +++ b/lib/preemptive-quota-scheduler.ts @@ -24,7 +24,8 @@ export interface QuotaSchedulerOptions { maxDeferralMs?: number; } -const DEFAULT_REMAINING_PERCENT_THRESHOLD = 10; +const DEFAULT_PRIMARY_REMAINING_PERCENT_THRESHOLD = 10; +const DEFAULT_SECONDARY_REMAINING_PERCENT_THRESHOLD = 5; const DEFAULT_MAX_DEFERRAL_MS = 2 * 60 * 60_000; /** @@ -148,8 +149,8 @@ export class PreemptiveQuotaScheduler { constructor(options: QuotaSchedulerOptions = {}) { this.enabled = true; - this.primaryRemainingPercentThreshold = DEFAULT_REMAINING_PERCENT_THRESHOLD; - this.secondaryRemainingPercentThreshold = DEFAULT_REMAINING_PERCENT_THRESHOLD; + this.primaryRemainingPercentThreshold = DEFAULT_PRIMARY_REMAINING_PERCENT_THRESHOLD; + this.secondaryRemainingPercentThreshold = DEFAULT_SECONDARY_REMAINING_PERCENT_THRESHOLD; this.maxDeferralMs = DEFAULT_MAX_DEFERRAL_MS; this.configure(options); } diff --git a/scripts/codex.js b/scripts/codex.js index 1c09c970..944a204c 100755 --- a/scripts/codex.js +++ b/scripts/codex.js @@ -532,6 +532,8 @@ async function main() { buildForwardArgs, forwardToRealCodex, }); + // The supervisor persists account selection, but the wrapper still runs startup sync + // before returning so the live Codex CLI state can refresh expired token material. await autoSyncManagerActiveSelectionIfEnabled(); if (supervisedExitCode !== null) { return supervisedExitCode; diff --git a/test/preemptive-quota-scheduler.test.ts b/test/preemptive-quota-scheduler.test.ts index 71e0e610..c3856779 100644 --- a/test/preemptive-quota-scheduler.test.ts +++ b/test/preemptive-quota-scheduler.test.ts @@ -156,6 +156,32 @@ describe("preemptive quota scheduler", () => { expect(decision.reason).toBe("quota-near-exhaustion"); }); + it("keeps the secondary remaining threshold at 5 percent by default", () => { + const scheduler = new PreemptiveQuotaScheduler(); + scheduler.update("acc:model", { + status: 200, + primary: {}, + secondary: { usedPercent: 94, resetAtMs: 65_000 }, + updatedAt: 1_000, + }); + + expect(scheduler.getDeferral("acc:model", 5_000)).toEqual({ + defer: false, + waitMs: 0, + }); + + scheduler.update("acc:model", { + status: 200, + primary: {}, + secondary: { usedPercent: 95, resetAtMs: 65_000 }, + updatedAt: 1_000, + }); + + const decision = scheduler.getDeferral("acc:model", 5_000); + expect(decision.defer).toBe(true); + expect(decision.reason).toBe("quota-near-exhaustion"); + }); + it("can disable preemptive deferral without clearing snapshots", () => { const scheduler = new PreemptiveQuotaScheduler(); scheduler.markRateLimited("acc:model", 30_000, 1_000); From 6579f0846a9178e90136f08d5096d1c23ce68978 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 21:24:32 +0800 Subject: [PATCH 11/24] Fix supervisor benchmark review comments --- scripts/benchmark-session-supervisor.mjs | 2 +- scripts/codex-supervisor.js | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/benchmark-session-supervisor.mjs b/scripts/benchmark-session-supervisor.mjs index 95286013..e7d65655 100644 --- a/scripts/benchmark-session-supervisor.mjs +++ b/scripts/benchmark-session-supervisor.mjs @@ -373,7 +373,7 @@ async function main() { ), await runCase( api, - "session_rotation_multi_candidate_windows", + "session_rotation_multi_candidate_batch1_windows", iterations, probeLatencyMs, { diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index 612dc910..67e1cf2f 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -1138,8 +1138,10 @@ async function prepareResumeSelection({ runtime, pluginConfig, currentAccount, + restartDecision, signal, }) { + void restartDecision; const startedAtMs = Date.now(); const nextReady = await ensureLaunchableAccount( runtime, From f3ca99e22ad7bf9d90d676bf0308e7b3d9ed9a17 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 21:31:28 +0800 Subject: [PATCH 12/24] Fix post-merge storage cleanup --- lib/storage.ts | 1 - package-lock.json | 7534 ++++++++++++++++++++++----------------------- 2 files changed, 3767 insertions(+), 3768 deletions(-) diff --git a/lib/storage.ts b/lib/storage.ts index 7b3cd3e4..23b4f02c 100644 --- a/lib/storage.ts +++ b/lib/storage.ts @@ -238,7 +238,6 @@ const transactionSnapshotContext = new AsyncLocalStorage<{ snapshot: AccountStorageV3 | null; storagePath: string; active: boolean; - storagePath: string; }>(); function withStorageLock(fn: () => Promise): Promise { diff --git a/package-lock.json b/package-lock.json index 5f46ab71..7dfa7b49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,3769 +1,3769 @@ { - "name": "codex-multi-auth", - "version": "1.2.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "codex-multi-auth", - "version": "1.2.0", - "bundleDependencies": [ - "@codex-ai/plugin" - ], - "license": "MIT", - "dependencies": { - "@codex-ai/plugin": "file:vendor/codex-ai-plugin", - "@openauthjs/openauth": "^0.4.3", - "hono": "4.12.6", - "undici": "^6.24.1", - "zod": "^4.3.6" - }, - "bin": { - "codex": "scripts/codex.js", - "codex-multi-auth": "scripts/codex-multi-auth.js" - }, - "devDependencies": { - "@codex-ai/sdk": "file:vendor/codex-ai-sdk", - "@fast-check/vitest": "^0.2.4", - "@types/node": "^25.3.0", - "@typescript-eslint/eslint-plugin": "^8.56.0", - "@typescript-eslint/parser": "^8.56.0", - "@vitest/coverage-v8": "^4.0.18", - "@vitest/ui": "^4.0.18", - "eslint": "^10.0.0", - "fast-check": "^4.5.3", - "husky": "^9.1.7", - "lint-staged": "^16.2.7", - "typescript": "^5.9.3", - "typescript-language-server": "^5.1.3", - "vitest": "^4.0.18" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "typescript": "^5" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", - "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.6" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", - "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@codex-ai/plugin": { - "resolved": "vendor/codex-ai-plugin", - "link": true - }, - "node_modules/@codex-ai/sdk": { - "resolved": "vendor/codex-ai-sdk", - "link": true - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.1.tgz", - "integrity": "sha512-uVSdg/V4dfQmTjJzR0szNczjOH/J+FyUMMjYtr07xFRXR7EDf9i1qdxrD0VusZH9knj1/ecxzCQQxyic5NzAiA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^3.0.1", - "debug": "^4.3.1", - "minimatch": "^10.1.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.2.tgz", - "integrity": "sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.1.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/core": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz", - "integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/object-schema": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.1.tgz", - "integrity": "sha512-P9cq2dpr+LU8j3qbLygLcSZrl2/ds/pUpfnHNNuk5HW7mnngHs+6WSq5C9mO3rqRX8A1poxqLTC9cu0KOyJlBg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz", - "integrity": "sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.1.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@fast-check/vitest": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@fast-check/vitest/-/vitest-0.2.4.tgz", - "integrity": "sha512-Ilcr+JAIPhb1s6FRm4qoglQYSGXXrS+zAupZeNuWAA3qHVGDA1d1Gb84Hb/+otL3GzVZjFJESg5/1SfIvrgssA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT", - "dependencies": { - "fast-check": "^3.0.0 || ^4.0.0" - }, - "peerDependencies": { - "vitest": "^1 || ^2 || ^3 || ^4" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@openauthjs/openauth": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@openauthjs/openauth/-/openauth-0.4.3.tgz", - "integrity": "sha512-RlnjqvHzqcbFVymEwhlUEuac4utA5h4nhSK/i2szZuQmxTIqbGUxZ+nM+avM+VV4Ing+/ZaNLKILoXS3yrkOOw==", - "dependencies": { - "@standard-schema/spec": "1.0.0-beta.3", - "aws4fetch": "1.0.20", - "jose": "5.9.6" - }, - "peerDependencies": { - "arctic": "^2.2.2", - "hono": "^4.0.0" - } - }, - "node_modules/@oslojs/asn1": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@oslojs/asn1/-/asn1-1.0.0.tgz", - "integrity": "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@oslojs/binary": "1.0.0" - } - }, - "node_modules/@oslojs/binary": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@oslojs/binary/-/binary-1.0.0.tgz", - "integrity": "sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==", - "license": "MIT", - "peer": true - }, - "node_modules/@oslojs/crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@oslojs/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@oslojs/asn1": "1.0.0", - "@oslojs/binary": "1.0.0" - } - }, - "node_modules/@oslojs/encoding": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", - "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", - "license": "MIT", - "peer": true - }, - "node_modules/@oslojs/jwt": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@oslojs/jwt/-/jwt-0.2.0.tgz", - "integrity": "sha512-bLE7BtHrURedCn4Mco3ma9L4Y1GR2SMBuIvjWr7rmQ4/W/4Jy70TIAgZ+0nIlk0xHz1vNP8x8DCns45Sb2XRbg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@oslojs/encoding": "0.4.1" - } - }, - "node_modules/@oslojs/jwt/node_modules/@oslojs/encoding": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-0.4.1.tgz", - "integrity": "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q==", - "license": "MIT", - "peer": true - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.29", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", - "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@standard-schema/spec": { - "version": "1.0.0-beta.3", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0-beta.3.tgz", - "integrity": "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw==", - "license": "MIT" - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/esrecurse": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", - "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", - "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", - "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/type-utils": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.56.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", - "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", - "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.0", - "@typescript-eslint/types": "^8.56.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", - "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", - "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", - "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", - "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", - "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.56.0", - "@typescript-eslint/tsconfig-utils": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "debug": "^4.4.3", - "minimatch": "^9.0.5", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", - "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", - "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.0", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", - "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@vitest/coverage-v8": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", - "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.0.18", - "ast-v8-to-istanbul": "^0.3.10", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-reports": "^3.2.0", - "magicast": "^0.5.1", - "obug": "^2.1.1", - "std-env": "^3.10.0", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "4.0.18", - "vitest": "4.0.18" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "node_modules/@vitest/expect": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/expect/node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vitest/mocker": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.0.18", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.0.18", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.18", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/ui": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.18.tgz", - "integrity": "sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.0.18", - "fflate": "^0.8.2", - "flatted": "^3.3.3", - "pathe": "^2.0.3", - "sirv": "^3.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "vitest": "4.0.18" - } - }, - "node_modules/@vitest/utils": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.18", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", - "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/arctic": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/arctic/-/arctic-2.3.4.tgz", - "integrity": "sha512-+p30BOWsctZp+CVYCt7oAean/hWGW42sH5LAcRQX56ttEkFJWbzXBhmSpibbzwSJkRrotmsA+oAoJoVsU0f5xA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@oslojs/crypto": "1.0.1", - "@oslojs/encoding": "1.1.0", - "@oslojs/jwt": "0.2.0" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/ast-v8-to-istanbul": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.10.tgz", - "integrity": "sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^9.0.1" - } - }, - "node_modules/aws4fetch": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/aws4fetch/-/aws4fetch-1.0.20.tgz", - "integrity": "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz", - "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/brace-expansion": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", - "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", - "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^7.1.0", - "string-width": "^8.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.0.tgz", - "integrity": "sha512-O0piBKY36YSJhlFSG8p9VUdPV/SxxS4FYDWVpr/9GJuMaepzwlf4J8I4ov1b+ySQfDTPhc3DtLaxcT1fN0yqCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.0", - "@eslint/config-helpers": "^0.5.2", - "@eslint/core": "^1.1.0", - "@eslint/plugin-kit": "^0.6.0", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^9.1.0", - "eslint-visitor-keys": "^5.0.0", - "espree": "^11.1.0", - "esquery": "^1.7.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.1.1", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.0.tgz", - "integrity": "sha512-CkWE42hOJsNj9FJRaoMX9waUFYhqY4jmyLFdAdzZr6VaCg3ynLYx4WnOdkaIifGfH4gsUcBTn4OZbHXkpLD0FQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", - "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/espree": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-11.1.0.tgz", - "integrity": "sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", - "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/fast-check": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.5.3.tgz", - "integrity": "sha512-IE9csY7lnhxBnA8g/WI5eg/hygA6MGWJMSNfFRrBlXUciADEhS1EDB0SIsMSvzubzIlOBbVITSsypCsW717poA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT", - "dependencies": { - "pure-rand": "^7.0.0" - }, - "engines": { - "node": ">=12.17.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fflate": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", - "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", - "dev": true, - "license": "MIT" - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hono": { - "version": "4.12.6", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.6.tgz", - "integrity": "sha512-KljEp+MeEEEIOT75qBo1UjqqB29fRMtlDEwCxcexOzdkUq6LR/vRvHk5pdROcxyOYyW1niq7Gb5pFVGy5R1eBw==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/husky": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", - "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", - "dev": true, - "license": "MIT", - "bin": { - "husky": "bin.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jose": { - "version": "5.9.6", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", - "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lint-staged": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", - "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^14.0.2", - "listr2": "^9.0.5", - "micromatch": "^4.0.8", - "nano-spawn": "^2.0.0", - "pidtree": "^0.6.0", - "string-argv": "^0.3.2", - "yaml": "^2.8.1" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/listr2": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", - "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^5.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/magicast": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", - "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "source-map-js": "^1.2.1" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nano-spawn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", - "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT" - }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", - "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/rollup": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sirv": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", - "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@polka/url": "^1.0.0-next.24", - "mrmime": "^2.0.0", - "totalist": "^3.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", - "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-language-server": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/typescript-language-server/-/typescript-language-server-5.1.3.tgz", - "integrity": "sha512-r+pAcYtWdN8tKlYZPwiiHNA2QPjXnI02NrW5Sf2cVM3TRtuQ3V9EKKwOxqwaQ0krsaEXk/CbN90I5erBuf84Vg==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "typescript-language-server": "lib/cli.mjs" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/undici": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", - "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/vitest": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.0.18", - "@vitest/mocker": "4.0.18", - "@vitest/pretty-format": "4.0.18", - "@vitest/runner": "4.0.18", - "@vitest/snapshot": "4.0.18", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^3.10.0", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.18", - "@vitest/browser-preview": "4.0.18", - "@vitest/browser-webdriverio": "4.0.18", - "@vitest/ui": "4.0.18", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "vendor/codex-ai-plugin": { - "name": "@codex-ai/plugin", - "version": "1.2.10-codex.1" - }, - "vendor/codex-ai-sdk": { - "name": "@codex-ai/sdk", - "version": "1.2.10-codex.1", - "dev": true - } - } + "name": "codex-multi-auth", + "version": "1.2.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "codex-multi-auth", + "version": "1.2.0", + "bundleDependencies": [ + "@codex-ai/plugin" + ], + "license": "MIT", + "dependencies": { + "@codex-ai/plugin": "file:vendor/codex-ai-plugin", + "@openauthjs/openauth": "^0.4.3", + "hono": "4.12.6", + "undici": "^6.24.1", + "zod": "^4.3.6" + }, + "bin": { + "codex": "scripts/codex.js", + "codex-multi-auth": "scripts/codex-multi-auth.js" + }, + "devDependencies": { + "@codex-ai/sdk": "file:vendor/codex-ai-sdk", + "@fast-check/vitest": "^0.2.4", + "@types/node": "^25.3.0", + "@typescript-eslint/eslint-plugin": "^8.56.0", + "@typescript-eslint/parser": "^8.56.0", + "@vitest/coverage-v8": "^4.0.18", + "@vitest/ui": "^4.0.18", + "eslint": "^10.0.0", + "fast-check": "^4.5.3", + "husky": "^9.1.7", + "lint-staged": "^16.2.7", + "typescript": "^5.9.3", + "typescript-language-server": "^5.1.3", + "vitest": "^4.0.18" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "typescript": "^5" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@codex-ai/plugin": { + "resolved": "vendor/codex-ai-plugin", + "link": true + }, + "node_modules/@codex-ai/sdk": { + "resolved": "vendor/codex-ai-sdk", + "link": true + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.1.tgz", + "integrity": "sha512-uVSdg/V4dfQmTjJzR0szNczjOH/J+FyUMMjYtr07xFRXR7EDf9i1qdxrD0VusZH9knj1/ecxzCQQxyic5NzAiA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.1", + "debug": "^4.3.1", + "minimatch": "^10.1.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.2.tgz", + "integrity": "sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz", + "integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.1.tgz", + "integrity": "sha512-P9cq2dpr+LU8j3qbLygLcSZrl2/ds/pUpfnHNNuk5HW7mnngHs+6WSq5C9mO3rqRX8A1poxqLTC9cu0KOyJlBg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz", + "integrity": "sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@fast-check/vitest": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@fast-check/vitest/-/vitest-0.2.4.tgz", + "integrity": "sha512-Ilcr+JAIPhb1s6FRm4qoglQYSGXXrS+zAupZeNuWAA3qHVGDA1d1Gb84Hb/+otL3GzVZjFJESg5/1SfIvrgssA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "fast-check": "^3.0.0 || ^4.0.0" + }, + "peerDependencies": { + "vitest": "^1 || ^2 || ^3 || ^4" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@openauthjs/openauth": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@openauthjs/openauth/-/openauth-0.4.3.tgz", + "integrity": "sha512-RlnjqvHzqcbFVymEwhlUEuac4utA5h4nhSK/i2szZuQmxTIqbGUxZ+nM+avM+VV4Ing+/ZaNLKILoXS3yrkOOw==", + "dependencies": { + "@standard-schema/spec": "1.0.0-beta.3", + "aws4fetch": "1.0.20", + "jose": "5.9.6" + }, + "peerDependencies": { + "arctic": "^2.2.2", + "hono": "^4.0.0" + } + }, + "node_modules/@oslojs/asn1": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@oslojs/asn1/-/asn1-1.0.0.tgz", + "integrity": "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oslojs/binary": "1.0.0" + } + }, + "node_modules/@oslojs/binary": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@oslojs/binary/-/binary-1.0.0.tgz", + "integrity": "sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@oslojs/crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@oslojs/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oslojs/asn1": "1.0.0", + "@oslojs/binary": "1.0.0" + } + }, + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@oslojs/jwt": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@oslojs/jwt/-/jwt-0.2.0.tgz", + "integrity": "sha512-bLE7BtHrURedCn4Mco3ma9L4Y1GR2SMBuIvjWr7rmQ4/W/4Jy70TIAgZ+0nIlk0xHz1vNP8x8DCns45Sb2XRbg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oslojs/encoding": "0.4.1" + } + }, + "node_modules/@oslojs/jwt/node_modules/@oslojs/encoding": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-0.4.1.tgz", + "integrity": "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q==", + "license": "MIT", + "peer": true + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0-beta.3.tgz", + "integrity": "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw==", + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", + "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", + "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/type-utils": "8.56.0", + "@typescript-eslint/utils": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.56.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", + "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", + "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.0", + "@typescript-eslint/types": "^8.56.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", + "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", + "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", + "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0", + "@typescript-eslint/utils": "8.56.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", + "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.0", + "@typescript-eslint/tsconfig-utils": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", + "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", + "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", + "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.0.18", + "ast-v8-to-istanbul": "^0.3.10", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.1", + "obug": "^2.1.1", + "std-env": "^3.10.0", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.0.18", + "vitest": "4.0.18" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/ui": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.18.tgz", + "integrity": "sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "fflate": "^0.8.2", + "flatted": "^3.3.3", + "pathe": "^2.0.3", + "sirv": "^3.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.0.18" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/arctic": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/arctic/-/arctic-2.3.4.tgz", + "integrity": "sha512-+p30BOWsctZp+CVYCt7oAean/hWGW42sH5LAcRQX56ttEkFJWbzXBhmSpibbzwSJkRrotmsA+oAoJoVsU0f5xA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oslojs/crypto": "1.0.1", + "@oslojs/encoding": "1.1.0", + "@oslojs/jwt": "0.2.0" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.10.tgz", + "integrity": "sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" + } + }, + "node_modules/aws4fetch": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/aws4fetch/-/aws4fetch-1.0.20.tgz", + "integrity": "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz", + "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", + "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", + "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^7.1.0", + "string-width": "^8.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.0.tgz", + "integrity": "sha512-O0piBKY36YSJhlFSG8p9VUdPV/SxxS4FYDWVpr/9GJuMaepzwlf4J8I4ov1b+ySQfDTPhc3DtLaxcT1fN0yqCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.0", + "@eslint/config-helpers": "^0.5.2", + "@eslint/core": "^1.1.0", + "@eslint/plugin-kit": "^0.6.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.0", + "eslint-visitor-keys": "^5.0.0", + "espree": "^11.1.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.1.1", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.0.tgz", + "integrity": "sha512-CkWE42hOJsNj9FJRaoMX9waUFYhqY4jmyLFdAdzZr6VaCg3ynLYx4WnOdkaIifGfH4gsUcBTn4OZbHXkpLD0FQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/espree": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.1.0.tgz", + "integrity": "sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-check": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.5.3.tgz", + "integrity": "sha512-IE9csY7lnhxBnA8g/WI5eg/hygA6MGWJMSNfFRrBlXUciADEhS1EDB0SIsMSvzubzIlOBbVITSsypCsW717poA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^7.0.0" + }, + "engines": { + "node": ">=12.17.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hono": { + "version": "4.12.6", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.6.tgz", + "integrity": "sha512-KljEp+MeEEEIOT75qBo1UjqqB29fRMtlDEwCxcexOzdkUq6LR/vRvHk5pdROcxyOYyW1niq7Gb5pFVGy5R1eBw==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jose": { + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lint-staged": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", + "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^14.0.2", + "listr2": "^9.0.5", + "micromatch": "^4.0.8", + "nano-spawn": "^2.0.0", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", + "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nano-spawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", + "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-language-server": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript-language-server/-/typescript-language-server-5.1.3.tgz", + "integrity": "sha512-r+pAcYtWdN8tKlYZPwiiHNA2QPjXnI02NrW5Sf2cVM3TRtuQ3V9EKKwOxqwaQ0krsaEXk/CbN90I5erBuf84Vg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "typescript-language-server": "lib/cli.mjs" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/undici": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", + "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "vendor/codex-ai-plugin": { + "name": "@codex-ai/plugin", + "version": "1.2.10-codex.1" + }, + "vendor/codex-ai-sdk": { + "name": "@codex-ai/sdk", + "version": "1.2.10-codex.1", + "dev": true + } + } } From b09f489a6e17343d0c63dfb81dc9115edd6c2530 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 22:24:18 +0800 Subject: [PATCH 13/24] fix: harden supervisor review follow-ups --- lib/storage.ts | 4 +- scripts/codex-supervisor.js | 100 ++++++++++++++++++------------- test/codex-supervisor.test.ts | 107 ++++++++++++++++++++++++++++++++++ test/storage.test.ts | 2 +- 4 files changed, 170 insertions(+), 43 deletions(-) diff --git a/lib/storage.ts b/lib/storage.ts index 23b4f02c..02890d0f 100644 --- a/lib/storage.ts +++ b/lib/storage.ts @@ -2512,8 +2512,8 @@ export async function exportAccounts( transactionState.storagePath !== activeStoragePath ) { throw new Error( - `No accounts to export: export was called from a different storage path ` + - `(transaction path: ${transactionState.storagePath}, active: ${activeStoragePath})`, + `Export blocked by storage path mismatch: transaction path is ` + + `${transactionState.storagePath}, active path is ${activeStoragePath}`, ); } const storage = transactionState?.active diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index 67e1cf2f..7c09cf98 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -468,7 +468,7 @@ async function withSupervisorStorageLock(runtime, fn, signal) { error && typeof error === "object" && "code" in error ? `${error.code ?? ""}` : ""; - if (code !== "EEXIST") { + if (code !== "EEXIST" && code !== "EPERM" && code !== "EBUSY") { throw error; } @@ -1420,21 +1420,27 @@ async function runInteractiveSupervision({ pluginConfig, manager, signal, + maxSessionRestarts = MAX_SESSION_RESTARTS, + spawnChild = spawnRealCodex, + findBinding = findSessionBinding, + waitForBinding = waitForSessionBinding, + refreshBinding = refreshSessionActivity, + requestRestart = requestChildRestart, }) { let launchArgs = initialArgs; let knownSessionId = readResumeSessionId(initialArgs); let knownRolloutPath = null; let launchCount = 0; - while (launchCount < MAX_SESSION_RESTARTS) { + while (launchCount < maxSessionRestarts) { if (signal?.aborted) { return 130; } launchCount += 1; - const child = spawnRealCodex(codexBin, launchArgs); + const child = spawnChild(codexBin, launchArgs); const launchStartedAt = Date.now(); let binding = knownSessionId - ? await findSessionBinding({ + ? await findBinding({ cwd: process.cwd(), sinceMs: 0, sessionId: knownSessionId, @@ -1480,7 +1486,7 @@ async function runInteractiveSupervision({ const monitorPromise = (async () => { while (monitorActive) { if (!binding) { - binding = await waitForSessionBinding({ + binding = await waitForBinding({ cwd: process.cwd(), sinceMs: launchStartedAt, sessionId: knownSessionId, @@ -1493,7 +1499,7 @@ async function runInteractiveSupervision({ knownRolloutPath = binding.rolloutPath ?? knownRolloutPath; } } else { - binding = await refreshSessionActivity(binding); + binding = await refreshBinding(binding); if (binding?.rolloutPath) { knownRolloutPath = binding.rolloutPath; } @@ -1586,7 +1592,7 @@ async function runInteractiveSupervision({ `rotating session ${binding.sessionId} because ${pressure.reason.replace(/-/g, " ")} (${formatQuotaPressure(pressure)})`, ); monitorActive = false; - await requestChildRestart(child, process.platform, signal); + await requestRestart(child, process.platform, signal); monitorController.abort(); continue; } @@ -1619,7 +1625,7 @@ async function runInteractiveSupervision({ await monitorPromise; binding = binding ?? - (await findSessionBinding({ + (await findBinding({ cwd: process.cwd(), sinceMs: launchStartedAt, sessionId: knownSessionId, @@ -1741,6 +1747,48 @@ async function runInteractiveSupervision({ return 1; } +async function runCodexSupervisorWithRuntime({ + codexBin, + rawArgs, + buildForwardArgs, + forwardToRealCodex, + runtime, + signal, +}) { + const pluginConfig = runtime.loadPluginConfig(); + if (!runtime.getCodexCliSessionSupervisor(pluginConfig)) { + return null; + } + + const initialArgs = buildForwardArgs(rawArgs); + if (isSupervisorAccountGateBypassCommand(rawArgs)) { + return forwardToRealCodex(codexBin, initialArgs); + } + + const ready = await ensureLaunchableAccount(runtime, pluginConfig, signal); + if (ready.aborted) { + return 130; + } + if (!ready.ok) { + relaunchNotice("no launchable account is currently available"); + return 1; + } + + if (isNonInteractiveCommand(rawArgs)) { + return forwardToRealCodex(codexBin, initialArgs); + } + + return runInteractiveSupervision({ + codexBin, + initialArgs, + buildForwardArgs, + runtime, + pluginConfig, + manager: ready.manager, + signal, + }); +} + export async function runCodexSupervisorIfEnabled({ codexBin, rawArgs, @@ -1757,41 +1805,12 @@ export async function runCodexSupervisorIfEnabled({ if (!runtime) { return null; } - - const pluginConfig = runtime.loadPluginConfig(); - if (!runtime.getCodexCliSessionSupervisor(pluginConfig)) { - return null; - } - - const initialArgs = buildForwardArgs(rawArgs); - if (isSupervisorAccountGateBypassCommand(rawArgs)) { - return forwardToRealCodex(codexBin, initialArgs); - } - - const ready = await ensureLaunchableAccount( - runtime, - pluginConfig, - controller.signal, - ); - if (ready.aborted) { - return 130; - } - if (!ready.ok) { - relaunchNotice("no launchable account is currently available"); - return 1; - } - - if (isNonInteractiveCommand(rawArgs)) { - return forwardToRealCodex(codexBin, initialArgs); - } - - return runInteractiveSupervision({ + return runCodexSupervisorWithRuntime({ codexBin, - initialArgs, + rawArgs, buildForwardArgs, + forwardToRealCodex, runtime, - pluginConfig, - manager: ready.manager, signal: controller.signal, }); } catch (error) { @@ -1829,6 +1848,7 @@ const TEST_ONLY_API = { withLockedManager, getSupervisorStorageLockPath, runInteractiveSupervision, + runCodexSupervisorWithRuntime, }; export const __testOnly = diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index f5e5718e..f3f3e6ac 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -12,6 +12,8 @@ const envKeys = [ "CODEX_AUTH_CLI_SESSION_BINDING_POLL_MS", "CODEX_AUTH_CLI_SESSION_LOCK_POLL_MS", "CODEX_AUTH_CLI_SESSION_LOCK_WAIT_MS", + "CODEX_AUTH_CLI_SESSION_SUPERVISOR_POLL_MS", + "CODEX_AUTH_CLI_SESSION_SUPERVISOR_IDLE_MS", "CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS", "CODEX_HOME", ] as const; @@ -441,6 +443,58 @@ describe("codex supervisor", () => { } }); + it.each(["EPERM", "EBUSY"] as const)( + "retries supervisor lock creation after a transient Windows %s", + async (code) => { + process.env.CODEX_AUTH_CLI_SESSION_LOCK_WAIT_MS = "1000"; + process.env.CODEX_AUTH_CLI_SESSION_LOCK_POLL_MS = "10"; + + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager); + const lockPath = supervisorTestApi?.getSupervisorStorageLockPath(runtime); + expect(lockPath).toBeTruthy(); + if (!lockPath) { + throw new Error("expected a supervisor lock path"); + } + + const originalOpen = fs.open.bind(fs); + let injectedFailure = false; + const openSpy = vi.spyOn(fs, "open").mockImplementation(async (path, flags, ...rest) => { + if (!injectedFailure && `${path}` === lockPath && flags === "wx") { + injectedFailure = true; + const error = Object.assign(new Error("transient lock create failure"), { + code, + }); + throw error; + } + return originalOpen( + path as Parameters[0], + flags as Parameters[1], + ...(rest as Parameters extends [unknown, unknown, ...infer Tail] + ? Tail + : never), + ); + }); + + try { + await expect( + supervisorTestApi?.withLockedManager(runtime, async (loadedManager: FakeManager) => { + expect(loadedManager).toBe(manager); + return "locked"; + }), + ).resolves.toBe("locked"); + expect(injectedFailure).toBe(true); + expect( + openSpy.mock.calls.filter( + ([path, flags]) => `${path}` === lockPath && flags === "wx", + ).length, + ).toBeGreaterThanOrEqual(2); + } finally { + openSpy.mockRestore(); + } + }, + ); + it("serializes concurrent callers behind the supervisor storage lock", async () => { process.env.CODEX_AUTH_CLI_SESSION_LOCK_WAIT_MS = "1000"; process.env.CODEX_AUTH_CLI_SESSION_LOCK_POLL_MS = "10"; @@ -828,6 +882,59 @@ describe("codex supervisor", () => { expect(elapsedMs).toBeLessThan(170); }); + it("bypasses supervisor account gating for auth commands before account selection", async () => { + const loadFromDisk = vi.fn(async () => { + throw new Error("ensureLaunchableAccount should not run for bypass commands"); + }); + const forwardToRealCodex = vi.fn(async () => 0); + + await expect( + supervisorTestApi?.runCodexSupervisorWithRuntime({ + codexBin: "dist/bin/codex.js", + rawArgs: ["auth"], + buildForwardArgs: (rawArgs: string[]) => [...rawArgs], + forwardToRealCodex, + runtime: { + loadPluginConfig: () => ({ codexCliSessionSupervisor: true }), + getCodexCliSessionSupervisor: () => true, + AccountManager: { loadFromDisk }, + }, + signal: undefined, + }), + ).resolves.toBe(0); + expect(forwardToRealCodex).toHaveBeenCalledWith("dist/bin/codex.js", [ + "auth", + ]); + expect(loadFromDisk).not.toHaveBeenCalled(); + }); + + it( + "returns 1 when interactive supervision is already at the restart safety limit", + async () => { + const manager = new FakeManager([ + { accountId: "near-limit", access: "token-1" }, + { accountId: "healthy", access: "token-2" }, + ]); + const runtime = createFakeRuntime(manager); + const spawnChild = vi.fn(); + + const result = await supervisorTestApi?.runInteractiveSupervision({ + codexBin: "dist/bin/codex.js", + initialArgs: ["resume", "session-restart-limit"], + buildForwardArgs: (rawArgs: string[]) => [...rawArgs], + runtime, + pluginConfig: {}, + manager, + signal: undefined, + maxSessionRestarts: 0, + spawnChild, + }); + + expect(result).toBe(1); + expect(spawnChild).not.toHaveBeenCalled(); + }, + ); + it("degrades a failed candidate probe and continues to the next healthy account", async () => { const manager = new FakeManager([ { accountId: "broken", access: "token-broken" }, diff --git a/test/storage.test.ts b/test/storage.test.ts index e061adf3..2b5293dc 100644 --- a/test/storage.test.ts +++ b/test/storage.test.ts @@ -990,7 +990,7 @@ describe("storage", () => { setStoragePathDirect(secondaryStoragePath); await exportAccounts(exportPath); }), - ).rejects.toThrow(/different storage path/); + ).rejects.toThrow(/storage path mismatch/); expect(existsSync(exportPath)).toBe(false); }); From 9d84cf82d572fae6131b16f44ebd63433e2c08b3 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 22:51:01 +0800 Subject: [PATCH 14/24] fix: address supervisor review follow-ups --- lib/config.ts | 6 +- lib/preemptive-quota-scheduler.ts | 4 +- scripts/codex-supervisor.js | 311 ++++++++++++++++++------------ test/codex-supervisor.test.ts | 88 +++++++++ 4 files changed, 285 insertions(+), 124 deletions(-) diff --git a/lib/config.ts b/lib/config.ts index 845b1c5c..b2673e8d 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -156,7 +156,8 @@ export const DEFAULT_PLUGIN_CONFIG: PluginConfig = { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 10, + preemptiveQuotaRemainingPercent5h: + DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, }; @@ -1077,7 +1078,7 @@ export function getPreemptiveQuotaRemainingPercent5h(pluginConfig: PluginConfig) return resolveNumberSetting( "CODEX_AUTH_PREEMPTIVE_QUOTA_5H_REMAINING_PCT", pluginConfig.preemptiveQuotaRemainingPercent5h, - 10, + DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H, { min: 0, max: 100 }, ); } @@ -1124,3 +1125,4 @@ export function getPreemptiveQuotaMaxDeferralMs(pluginConfig: PluginConfig): num { min: 1_000 }, ); } +import { DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H } from "./preemptive-quota-scheduler.js"; diff --git a/lib/preemptive-quota-scheduler.ts b/lib/preemptive-quota-scheduler.ts index 0fcc9b46..3f709e69 100644 --- a/lib/preemptive-quota-scheduler.ts +++ b/lib/preemptive-quota-scheduler.ts @@ -24,7 +24,7 @@ export interface QuotaSchedulerOptions { maxDeferralMs?: number; } -const DEFAULT_PRIMARY_REMAINING_PERCENT_THRESHOLD = 10; +export const DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H = 10; const DEFAULT_SECONDARY_REMAINING_PERCENT_THRESHOLD = 5; const DEFAULT_MAX_DEFERRAL_MS = 2 * 60 * 60_000; @@ -149,7 +149,7 @@ export class PreemptiveQuotaScheduler { constructor(options: QuotaSchedulerOptions = {}) { this.enabled = true; - this.primaryRemainingPercentThreshold = DEFAULT_PRIMARY_REMAINING_PERCENT_THRESHOLD; + this.primaryRemainingPercentThreshold = DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H; this.secondaryRemainingPercentThreshold = DEFAULT_SECONDARY_REMAINING_PERCENT_THRESHOLD; this.maxDeferralMs = DEFAULT_MAX_DEFERRAL_MS; this.configure(options); diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index 7c09cf98..8cdb7d12 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -948,32 +948,51 @@ async function ensureLaunchableAccount( 1, ); let attempts = 0; + let managerHint = null; while (attempts < MAX_ACCOUNT_SELECTION_ATTEMPTS) { attempts += 1; if (signal?.aborted) { return { ok: false, account: null, aborted: true }; } - const initial = await withLockedManager(runtime, async (manager) => { - const accounts = getProbeCandidateBatch( - manager, + let initial = null; + if (managerHint) { + const hintedAccounts = getProbeCandidateBatch( + managerHint, probeBatchSize, options.excludedAccounts ?? [], ); - if (accounts.length === 0) { - return { - kind: "wait", - waitMs: getNearestWaitMs(manager), - account: null, + if (hintedAccounts.length > 0) { + initial = { + kind: "probe", + accounts: hintedAccounts, }; } - return { - kind: "probe", - accounts, - }; - }, signal); + } + + if (!initial) { + initial = await withLockedManager(runtime, async (manager) => { + const accounts = getProbeCandidateBatch( + manager, + probeBatchSize, + options.excludedAccounts ?? [], + ); + if (accounts.length === 0) { + return { + kind: "wait", + waitMs: getNearestWaitMs(manager), + account: null, + }; + } + return { + kind: "probe", + accounts, + }; + }, signal); + } if (initial.kind === "wait") { + managerHint = null; if (initial.waitMs <= 0 || !runtime.getRetryAllAccountsRateLimited(pluginConfig)) { return { ok: false, account: null }; } @@ -1098,6 +1117,8 @@ async function ensureLaunchableAccount( ...step, }; } + + managerHint = step.manager ?? null; } return { ok: false, account: null }; @@ -1304,7 +1325,13 @@ async function readSessionBindingEntry(filePath) { } } -async function findSessionBinding({ cwd, sinceMs, sessionId, rolloutPathHint }) { +async function findSessionBinding({ + cwd, + sinceMs, + sessionId, + rolloutPathHint, + sessionEntries, +}) { const cwdKey = normalizeCwd(cwd); if (rolloutPathHint) { const directEntry = await readSessionBindingEntry(rolloutPathHint); @@ -1318,14 +1345,12 @@ async function findSessionBinding({ cwd, sinceMs, sessionId, rolloutPathHint }) } } - const sessionsRoot = getSessionsRootDir(); - const files = ( - await Promise.all( - (await listJsonlFiles(sessionsRoot)).map(async (filePath) => { + const files = (sessionEntries ?? + (await Promise.all( + (await listJsonlFiles(getSessionsRootDir())).map(async (filePath) => { return readSessionBindingEntry(filePath); }), - ) - ) + ))) .filter((entry) => entry && (sessionId ? true : entry.mtimeMs >= sinceMs - 2_000)) .sort((left, right) => right.mtimeMs - left.mtimeMs); @@ -1351,12 +1376,30 @@ async function waitForSessionBinding({ DEFAULT_SESSION_BINDING_POLL_MS, 25, ); + const listingRefreshMs = Math.max(250, pollMs * 8); + let cachedSessionEntries = null; + let lastSessionEntriesRefreshAt = 0; while (Date.now() <= deadline) { + if ( + !cachedSessionEntries || + Date.now() - lastSessionEntriesRefreshAt >= listingRefreshMs + ) { + cachedSessionEntries = ( + await Promise.all( + (await listJsonlFiles(getSessionsRootDir())).map(async (filePath) => { + return readSessionBindingEntry(filePath); + }), + ) + ).filter(Boolean); + lastSessionEntriesRefreshAt = Date.now(); + } + const binding = await findSessionBinding({ cwd, sinceMs, sessionId, rolloutPathHint, + sessionEntries: cachedSessionEntries, }); if (binding) return binding; const slept = await sleep(pollMs, signal); @@ -1412,6 +1455,17 @@ function spawnRealCodex(codexBin, args) { }); } +async function loadCurrentSupervisorState(runtime, signal) { + return withLockedManager( + runtime, + async (freshManager) => ({ + manager: freshManager, + currentAccount: getCurrentAccount(freshManager), + }), + signal, + ); +} + async function runInteractiveSupervision({ codexBin, initialArgs, @@ -1426,6 +1480,7 @@ async function runInteractiveSupervision({ waitForBinding = waitForSessionBinding, refreshBinding = refreshSessionActivity, requestRestart = requestChildRestart, + loadCurrentState = loadCurrentSupervisorState, }) { let launchArgs = initialArgs; let knownSessionId = readResumeSessionId(initialArgs); @@ -1483,125 +1538,135 @@ async function runInteractiveSupervision({ DEFAULT_MONITOR_PROBE_TIMEOUT_MS, ); + let monitorFailure = null; const monitorPromise = (async () => { - while (monitorActive) { - if (!binding) { - binding = await waitForBinding({ - cwd: process.cwd(), - sinceMs: launchStartedAt, - sessionId: knownSessionId, - rolloutPathHint: knownRolloutPath, - timeoutMs: captureTimeoutMs, - signal: monitorController.signal, - }); - if (binding?.sessionId) { - knownSessionId = binding.sessionId; - knownRolloutPath = binding.rolloutPath ?? knownRolloutPath; - } - } else { - binding = await refreshBinding(binding); - if (binding?.rolloutPath) { - knownRolloutPath = binding.rolloutPath; - } - } - - if (!requestedRestart) { - let currentState; - try { - currentState = await withLockedManager( - runtime, - async (freshManager) => ({ - manager: freshManager, - currentAccount: getCurrentAccount(freshManager), - }), - monitorController.signal, - ); - } catch (error) { - if (monitorController.signal.aborted || error?.name === "AbortError") { - break; + try { + while (monitorActive) { + if (!binding) { + binding = await waitForBinding({ + cwd: process.cwd(), + sinceMs: launchStartedAt, + sessionId: knownSessionId, + rolloutPathHint: knownRolloutPath, + timeoutMs: captureTimeoutMs, + signal: monitorController.signal, + }); + if (binding?.sessionId) { + knownSessionId = binding.sessionId; + knownRolloutPath = binding.rolloutPath ?? knownRolloutPath; + } + } else { + binding = await refreshBinding(binding); + if (binding?.rolloutPath) { + knownRolloutPath = binding.rolloutPath; } - throw error; } - manager = currentState.manager ?? manager; - const currentAccount = currentState.currentAccount; - if (currentAccount) { - let snapshot; + + if (!requestedRestart) { + let currentState; try { - snapshot = await probeAccountSnapshot( + currentState = await loadCurrentState( runtime, - currentAccount, monitorController.signal, - monitorProbeTimeoutMs, ); } catch (error) { - if (monitorController.signal.aborted || error?.name === "AbortError") { + if ( + monitorController.signal.aborted || + error?.name === "AbortError" + ) { break; } - if (error?.name === "QuotaProbeUnavailableError") { - continue; - } throw error; } - const pressure = computeQuotaPressure( - snapshot, - runtime, - pluginConfig, - ); - if (pressure.prewarm && binding?.sessionId) { - if (!rotationTrace.detectedAtMs) { - rotationTrace.detectedAtMs = Date.now(); - } - if (!preparedResumeSelectionStarted) { - rotationTrace.prewarmStartedAtMs = Date.now(); - supervisorDebug( - `prewarming successor for session ${binding.sessionId} ${formatQuotaPressure(pressure)}`, - ); - const preparedState = maybeStartPreparedResumeSelection({ + manager = currentState.manager ?? manager; + const currentAccount = currentState.currentAccount; + if (currentAccount) { + let snapshot; + try { + snapshot = await probeAccountSnapshot( runtime, - pluginConfig, currentAccount, - restartDecision: { - sessionId: binding.sessionId, - }, - signal, - preparedResumeSelectionStarted, - preparedResumeSelectionPromise, - }); - preparedResumeSelectionStarted = - preparedState.preparedResumeSelectionStarted; - preparedResumeSelectionPromise = - preparedState.preparedResumeSelectionPromise?.then((prepared) => { - if (rotationTrace.prewarmCompletedAtMs === 0) { - rotationTrace.prewarmCompletedAtMs = Date.now(); - } - return prepared; - }) ?? null; - } - } - if (pressure.rotate && binding?.sessionId) { - const pendingRestartDecision = { - reason: pressure.reason, - waitMs: pressure.waitMs, - sessionId: binding.sessionId, - }; - const lastActivityAtMs = binding.lastActivityAtMs ?? launchStartedAt; - if (Date.now() - lastActivityAtMs >= idleMs) { - requestedRestart = pendingRestartDecision; - rotationTrace.restartRequestedAtMs = Date.now(); - relaunchNotice( - `rotating session ${binding.sessionId} because ${pressure.reason.replace(/-/g, " ")} (${formatQuotaPressure(pressure)})`, + monitorController.signal, + monitorProbeTimeoutMs, ); - monitorActive = false; - await requestRestart(child, process.platform, signal); - monitorController.abort(); - continue; + } catch (error) { + if ( + monitorController.signal.aborted || + error?.name === "AbortError" + ) { + break; + } + if (error?.name === "QuotaProbeUnavailableError") { + continue; + } + throw error; + } + const pressure = computeQuotaPressure( + snapshot, + runtime, + pluginConfig, + ); + if (pressure.prewarm && binding?.sessionId) { + if (!rotationTrace.detectedAtMs) { + rotationTrace.detectedAtMs = Date.now(); + } + if (!preparedResumeSelectionStarted) { + rotationTrace.prewarmStartedAtMs = Date.now(); + supervisorDebug( + `prewarming successor for session ${binding.sessionId} ${formatQuotaPressure(pressure)}`, + ); + const preparedState = maybeStartPreparedResumeSelection({ + runtime, + pluginConfig, + currentAccount, + restartDecision: { + sessionId: binding.sessionId, + }, + signal, + preparedResumeSelectionStarted, + preparedResumeSelectionPromise, + }); + preparedResumeSelectionStarted = + preparedState.preparedResumeSelectionStarted; + preparedResumeSelectionPromise = + preparedState.preparedResumeSelectionPromise?.then((prepared) => { + if (rotationTrace.prewarmCompletedAtMs === 0) { + rotationTrace.prewarmCompletedAtMs = Date.now(); + } + return prepared; + }) ?? null; + } + } + if (pressure.rotate && binding?.sessionId) { + const pendingRestartDecision = { + reason: pressure.reason, + waitMs: pressure.waitMs, + sessionId: binding.sessionId, + }; + const lastActivityAtMs = + binding.lastActivityAtMs ?? launchStartedAt; + if (Date.now() - lastActivityAtMs >= idleMs) { + requestedRestart = pendingRestartDecision; + rotationTrace.restartRequestedAtMs = Date.now(); + relaunchNotice( + `rotating session ${binding.sessionId} because ${pressure.reason.replace(/-/g, " ")} (${formatQuotaPressure(pressure)})`, + ); + monitorActive = false; + await requestRestart(child, process.platform, signal); + monitorController.abort(); + continue; + } } } } - } - const slept = await sleep(pollMs, monitorController.signal); - if (!slept) break; + const slept = await sleep(pollMs, monitorController.signal); + if (!slept) break; + } + } catch (error) { + if (!monitorController.signal.aborted && error?.name !== "AbortError") { + monitorFailure = error; + } } })(); @@ -1623,6 +1688,11 @@ async function runInteractiveSupervision({ monitorActive = false; monitorController.abort(); await monitorPromise; + if (monitorFailure && !signal?.aborted) { + supervisorDebug( + `monitor loop failed: ${monitorFailure instanceof Error ? monitorFailure.message : String(monitorFailure)}`, + ); + } binding = binding ?? (await findBinding({ @@ -1849,6 +1919,7 @@ const TEST_ONLY_API = { getSupervisorStorageLockPath, runInteractiveSupervision, runCodexSupervisorWithRuntime, + waitForSessionBinding, }; export const __testOnly = diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index f3f3e6ac..d92bca1f 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -360,6 +360,37 @@ describe("codex supervisor", () => { } }); + it("caches the session file listing across binding wait polls", async () => { + const codexHome = createTempDir(); + const cwd = createTempDir(); + process.env.CODEX_HOME = codexHome; + process.env.CODEX_AUTH_CLI_SESSION_BINDING_POLL_MS = "5"; + + const sessionsDir = join(codexHome, "sessions", "2026", "03", "20"); + await fs.mkdir(sessionsDir, { recursive: true }); + await fs.writeFile( + join(sessionsDir, "no-binding.jsonl"), + JSON.stringify({ type: "event", seq: 1 }), + "utf8", + ); + + const readdirSpy = vi.spyOn(fs, "readdir"); + try { + const binding = await supervisorTestApi?.waitForSessionBinding({ + cwd, + sinceMs: Date.now(), + sessionId: "missing-session", + rolloutPathHint: null, + timeoutMs: 40, + signal: undefined, + }); + expect(binding).toBeNull(); + expect(readdirSpy.mock.calls.length).toBeLessThan(10); + } finally { + readdirSpy.mockRestore(); + } + }); + it("interrupts child restart waits when the abort signal fires", async () => { vi.useFakeTimers(); class FakeChild extends EventEmitter { @@ -935,6 +966,63 @@ describe("codex supervisor", () => { }, ); + it( + "keeps the child exit code when the monitor loop fails after startup", + { timeout: 10_000 }, + async () => { + class FakeChild extends EventEmitter { + exitCode: number | null = null; + + constructor(exitCode: number) { + super(); + setTimeout(() => { + this.exitCode = exitCode; + this.emit("exit", exitCode, null); + }, 25); + } + + kill(_signal: string) { + return true; + } + } + + const stderrSpy = vi + .spyOn(process.stderr, "write") + .mockImplementation(() => true); + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager); + + try { + const result = await supervisorTestApi?.runInteractiveSupervision({ + codexBin: "dist/bin/codex.js", + initialArgs: ["resume", "monitor-failure-session"], + buildForwardArgs: (rawArgs: string[]) => [...rawArgs], + runtime, + pluginConfig: {}, + manager, + signal: undefined, + maxSessionRestarts: 1, + spawnChild: () => new FakeChild(0), + findBinding: async ({ sessionId }: { sessionId?: string }) => ({ + sessionId: sessionId ?? "monitor-failure-session", + rolloutPath: null, + lastActivityAtMs: Date.now(), + }), + loadCurrentState: async () => { + throw new Error("Timed out waiting for supervisor storage lock"); + }, + }); + + expect(result).toBe(0); + expect(stderrSpy).not.toHaveBeenCalledWith( + expect.stringContaining("Timed out waiting for supervisor storage lock"), + ); + } finally { + stderrSpy.mockRestore(); + } + }, + ); + it("degrades a failed candidate probe and continues to the next healthy account", async () => { const manager = new FakeManager([ { accountId: "broken", access: "token-broken" }, From 77600ad8cb91d3edcca43d7d1c9f4e482ab2f250 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 22:59:58 +0800 Subject: [PATCH 15/24] chore: trim review-only PR bloat --- package-lock.json | 7534 +++++++++++----------- package.json | 2 - scripts/benchmark-session-supervisor.mjs | 485 -- 3 files changed, 3767 insertions(+), 4254 deletions(-) delete mode 100644 scripts/benchmark-session-supervisor.mjs diff --git a/package-lock.json b/package-lock.json index 7dfa7b49..5f46ab71 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,3769 +1,3769 @@ { - "name": "codex-multi-auth", - "version": "1.2.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "codex-multi-auth", - "version": "1.2.0", - "bundleDependencies": [ - "@codex-ai/plugin" - ], - "license": "MIT", - "dependencies": { - "@codex-ai/plugin": "file:vendor/codex-ai-plugin", - "@openauthjs/openauth": "^0.4.3", - "hono": "4.12.6", - "undici": "^6.24.1", - "zod": "^4.3.6" - }, - "bin": { - "codex": "scripts/codex.js", - "codex-multi-auth": "scripts/codex-multi-auth.js" - }, - "devDependencies": { - "@codex-ai/sdk": "file:vendor/codex-ai-sdk", - "@fast-check/vitest": "^0.2.4", - "@types/node": "^25.3.0", - "@typescript-eslint/eslint-plugin": "^8.56.0", - "@typescript-eslint/parser": "^8.56.0", - "@vitest/coverage-v8": "^4.0.18", - "@vitest/ui": "^4.0.18", - "eslint": "^10.0.0", - "fast-check": "^4.5.3", - "husky": "^9.1.7", - "lint-staged": "^16.2.7", - "typescript": "^5.9.3", - "typescript-language-server": "^5.1.3", - "vitest": "^4.0.18" - }, - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "typescript": "^5" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", - "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.6" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", - "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", - "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@codex-ai/plugin": { - "resolved": "vendor/codex-ai-plugin", - "link": true - }, - "node_modules/@codex-ai/sdk": { - "resolved": "vendor/codex-ai-sdk", - "link": true - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", - "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", - "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", - "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", - "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", - "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", - "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", - "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", - "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", - "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", - "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", - "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", - "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", - "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", - "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", - "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", - "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", - "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", - "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", - "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", - "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", - "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", - "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", - "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", - "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", - "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", - "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", - "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.1.tgz", - "integrity": "sha512-uVSdg/V4dfQmTjJzR0szNczjOH/J+FyUMMjYtr07xFRXR7EDf9i1qdxrD0VusZH9knj1/ecxzCQQxyic5NzAiA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^3.0.1", - "debug": "^4.3.1", - "minimatch": "^10.1.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.2.tgz", - "integrity": "sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.1.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/core": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz", - "integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/object-schema": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.1.tgz", - "integrity": "sha512-P9cq2dpr+LU8j3qbLygLcSZrl2/ds/pUpfnHNNuk5HW7mnngHs+6WSq5C9mO3rqRX8A1poxqLTC9cu0KOyJlBg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz", - "integrity": "sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^1.1.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - } - }, - "node_modules/@fast-check/vitest": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@fast-check/vitest/-/vitest-0.2.4.tgz", - "integrity": "sha512-Ilcr+JAIPhb1s6FRm4qoglQYSGXXrS+zAupZeNuWAA3qHVGDA1d1Gb84Hb/+otL3GzVZjFJESg5/1SfIvrgssA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT", - "dependencies": { - "fast-check": "^3.0.0 || ^4.0.0" - }, - "peerDependencies": { - "vitest": "^1 || ^2 || ^3 || ^4" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@openauthjs/openauth": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@openauthjs/openauth/-/openauth-0.4.3.tgz", - "integrity": "sha512-RlnjqvHzqcbFVymEwhlUEuac4utA5h4nhSK/i2szZuQmxTIqbGUxZ+nM+avM+VV4Ing+/ZaNLKILoXS3yrkOOw==", - "dependencies": { - "@standard-schema/spec": "1.0.0-beta.3", - "aws4fetch": "1.0.20", - "jose": "5.9.6" - }, - "peerDependencies": { - "arctic": "^2.2.2", - "hono": "^4.0.0" - } - }, - "node_modules/@oslojs/asn1": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@oslojs/asn1/-/asn1-1.0.0.tgz", - "integrity": "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@oslojs/binary": "1.0.0" - } - }, - "node_modules/@oslojs/binary": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@oslojs/binary/-/binary-1.0.0.tgz", - "integrity": "sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==", - "license": "MIT", - "peer": true - }, - "node_modules/@oslojs/crypto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@oslojs/crypto/-/crypto-1.0.1.tgz", - "integrity": "sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@oslojs/asn1": "1.0.0", - "@oslojs/binary": "1.0.0" - } - }, - "node_modules/@oslojs/encoding": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", - "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", - "license": "MIT", - "peer": true - }, - "node_modules/@oslojs/jwt": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@oslojs/jwt/-/jwt-0.2.0.tgz", - "integrity": "sha512-bLE7BtHrURedCn4Mco3ma9L4Y1GR2SMBuIvjWr7rmQ4/W/4Jy70TIAgZ+0nIlk0xHz1vNP8x8DCns45Sb2XRbg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@oslojs/encoding": "0.4.1" - } - }, - "node_modules/@oslojs/jwt/node_modules/@oslojs/encoding": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-0.4.1.tgz", - "integrity": "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q==", - "license": "MIT", - "peer": true - }, - "node_modules/@polka/url": { - "version": "1.0.0-next.29", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", - "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", - "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", - "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", - "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", - "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", - "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", - "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", - "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", - "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", - "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", - "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", - "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", - "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", - "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", - "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", - "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", - "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", - "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", - "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", - "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", - "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", - "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", - "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", - "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", - "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", - "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@standard-schema/spec": { - "version": "1.0.0-beta.3", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0-beta.3.tgz", - "integrity": "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw==", - "license": "MIT" - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/esrecurse": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", - "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", - "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~7.18.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", - "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/type-utils": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.56.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", - "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/project-service": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", - "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.56.0", - "@typescript-eslint/types": "^8.56.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", - "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", - "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", - "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0", - "@typescript-eslint/utils": "8.56.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", - "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", - "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.56.0", - "@typescript-eslint/tsconfig-utils": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/visitor-keys": "8.56.0", - "debug": "^4.4.3", - "minimatch": "^9.0.5", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", - "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", - "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.56.0", - "@typescript-eslint/types": "8.56.0", - "@typescript-eslint/typescript-estree": "8.56.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.56.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", - "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.56.0", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", - "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@vitest/coverage-v8": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", - "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.0.18", - "ast-v8-to-istanbul": "^0.3.10", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-reports": "^3.2.0", - "magicast": "^0.5.1", - "obug": "^2.1.1", - "std-env": "^3.10.0", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@vitest/browser": "4.0.18", - "vitest": "4.0.18" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "node_modules/@vitest/expect": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/expect/node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vitest/mocker": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.0.18", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.0.18", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.18", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/ui": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.18.tgz", - "integrity": "sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.0.18", - "fflate": "^0.8.2", - "flatted": "^3.3.3", - "pathe": "^2.0.3", - "sirv": "^3.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "vitest": "4.0.18" - } - }, - "node_modules/@vitest/utils": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.18", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/acorn": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", - "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", - "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "environment": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/arctic": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/arctic/-/arctic-2.3.4.tgz", - "integrity": "sha512-+p30BOWsctZp+CVYCt7oAean/hWGW42sH5LAcRQX56ttEkFJWbzXBhmSpibbzwSJkRrotmsA+oAoJoVsU0f5xA==", - "license": "MIT", - "peer": true, - "dependencies": { - "@oslojs/crypto": "1.0.1", - "@oslojs/encoding": "1.1.0", - "@oslojs/jwt": "0.2.0" - } - }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - } - }, - "node_modules/ast-v8-to-istanbul": { - "version": "0.3.10", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.10.tgz", - "integrity": "sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^9.0.1" - } - }, - "node_modules/aws4fetch": { - "version": "1.0.20", - "resolved": "https://registry.npmjs.org/aws4fetch/-/aws4fetch-1.0.20.tgz", - "integrity": "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz", - "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/brace-expansion": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", - "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/cli-cursor": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", - "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "restore-cursor": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cli-truncate": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", - "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "slice-ansi": "^7.1.0", - "string-width": "^8.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, - "node_modules/commander": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", - "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/environment": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", - "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/esbuild": { - "version": "0.27.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", - "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.2", - "@esbuild/android-arm": "0.27.2", - "@esbuild/android-arm64": "0.27.2", - "@esbuild/android-x64": "0.27.2", - "@esbuild/darwin-arm64": "0.27.2", - "@esbuild/darwin-x64": "0.27.2", - "@esbuild/freebsd-arm64": "0.27.2", - "@esbuild/freebsd-x64": "0.27.2", - "@esbuild/linux-arm": "0.27.2", - "@esbuild/linux-arm64": "0.27.2", - "@esbuild/linux-ia32": "0.27.2", - "@esbuild/linux-loong64": "0.27.2", - "@esbuild/linux-mips64el": "0.27.2", - "@esbuild/linux-ppc64": "0.27.2", - "@esbuild/linux-riscv64": "0.27.2", - "@esbuild/linux-s390x": "0.27.2", - "@esbuild/linux-x64": "0.27.2", - "@esbuild/netbsd-arm64": "0.27.2", - "@esbuild/netbsd-x64": "0.27.2", - "@esbuild/openbsd-arm64": "0.27.2", - "@esbuild/openbsd-x64": "0.27.2", - "@esbuild/openharmony-arm64": "0.27.2", - "@esbuild/sunos-x64": "0.27.2", - "@esbuild/win32-arm64": "0.27.2", - "@esbuild/win32-ia32": "0.27.2", - "@esbuild/win32-x64": "0.27.2" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.0.tgz", - "integrity": "sha512-O0piBKY36YSJhlFSG8p9VUdPV/SxxS4FYDWVpr/9GJuMaepzwlf4J8I4ov1b+ySQfDTPhc3DtLaxcT1fN0yqCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.2", - "@eslint/config-array": "^0.23.0", - "@eslint/config-helpers": "^0.5.2", - "@eslint/core": "^1.1.0", - "@eslint/plugin-kit": "^0.6.0", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^9.1.0", - "eslint-visitor-keys": "^5.0.0", - "espree": "^11.1.0", - "esquery": "^1.7.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "minimatch": "^10.1.1", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.0.tgz", - "integrity": "sha512-CkWE42hOJsNj9FJRaoMX9waUFYhqY4jmyLFdAdzZr6VaCg3ynLYx4WnOdkaIifGfH4gsUcBTn4OZbHXkpLD0FQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@types/esrecurse": "^4.3.1", - "@types/estree": "^1.0.8", - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", - "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/espree": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-11.1.0.tgz", - "integrity": "sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^5.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", - "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eventemitter3": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", - "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/fast-check": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.5.3.tgz", - "integrity": "sha512-IE9csY7lnhxBnA8g/WI5eg/hygA6MGWJMSNfFRrBlXUciADEhS1EDB0SIsMSvzubzIlOBbVITSsypCsW717poA==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT", - "dependencies": { - "pure-rand": "^7.0.0" - }, - "engines": { - "node": ">=12.17.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fflate": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", - "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", - "dev": true, - "license": "MIT" - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-east-asian-width": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", - "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/hono": { - "version": "4.12.6", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.6.tgz", - "integrity": "sha512-KljEp+MeEEEIOT75qBo1UjqqB29fRMtlDEwCxcexOzdkUq6LR/vRvHk5pdROcxyOYyW1niq7Gb5pFVGy5R1eBw==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/husky": { - "version": "9.1.7", - "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", - "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", - "dev": true, - "license": "MIT", - "bin": { - "husky": "bin.js" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/typicode" - } - }, - "node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jose": { - "version": "5.9.6", - "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", - "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lint-staged": { - "version": "16.2.7", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", - "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", - "dev": true, - "license": "MIT", - "dependencies": { - "commander": "^14.0.2", - "listr2": "^9.0.5", - "micromatch": "^4.0.8", - "nano-spawn": "^2.0.0", - "pidtree": "^0.6.0", - "string-argv": "^0.3.2", - "yaml": "^2.8.1" - }, - "bin": { - "lint-staged": "bin/lint-staged.js" - }, - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://opencollective.com/lint-staged" - } - }, - "node_modules/listr2": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", - "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "cli-truncate": "^5.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", - "log-update": "^6.1.0", - "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/log-update": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", - "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-escapes": "^7.0.0", - "cli-cursor": "^5.0.0", - "slice-ansi": "^7.1.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/magicast": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", - "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "source-map-js": "^1.2.1" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-function": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", - "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "10.2.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", - "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.2" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/nano-spawn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", - "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/obug": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", - "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", - "dev": true, - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], - "license": "MIT" - }, - "node_modules/onetime": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", - "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-function": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", - "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", - "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/restore-cursor": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", - "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "onetime": "^7.0.0", - "signal-exit": "^4.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/rfdc": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", - "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/rollup": { - "version": "4.59.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", - "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.59.0", - "@rollup/rollup-android-arm64": "4.59.0", - "@rollup/rollup-darwin-arm64": "4.59.0", - "@rollup/rollup-darwin-x64": "4.59.0", - "@rollup/rollup-freebsd-arm64": "4.59.0", - "@rollup/rollup-freebsd-x64": "4.59.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", - "@rollup/rollup-linux-arm-musleabihf": "4.59.0", - "@rollup/rollup-linux-arm64-gnu": "4.59.0", - "@rollup/rollup-linux-arm64-musl": "4.59.0", - "@rollup/rollup-linux-loong64-gnu": "4.59.0", - "@rollup/rollup-linux-loong64-musl": "4.59.0", - "@rollup/rollup-linux-ppc64-gnu": "4.59.0", - "@rollup/rollup-linux-ppc64-musl": "4.59.0", - "@rollup/rollup-linux-riscv64-gnu": "4.59.0", - "@rollup/rollup-linux-riscv64-musl": "4.59.0", - "@rollup/rollup-linux-s390x-gnu": "4.59.0", - "@rollup/rollup-linux-x64-gnu": "4.59.0", - "@rollup/rollup-linux-x64-musl": "4.59.0", - "@rollup/rollup-openbsd-x64": "4.59.0", - "@rollup/rollup-openharmony-arm64": "4.59.0", - "@rollup/rollup-win32-arm64-msvc": "4.59.0", - "@rollup/rollup-win32-ia32-msvc": "4.59.0", - "@rollup/rollup-win32-x64-gnu": "4.59.0", - "@rollup/rollup-win32-x64-msvc": "4.59.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sirv": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", - "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@polka/url": "^1.0.0-next.24", - "mrmime": "^2.0.0", - "totalist": "^3.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/slice-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", - "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "is-fullwidth-code-point": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/slice-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-argv": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", - "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.19" - } - }, - "node_modules/string-width": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", - "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", - "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/ts-api-utils": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", - "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.12" - }, - "peerDependencies": { - "typescript": ">=4.8.4" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-language-server": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/typescript-language-server/-/typescript-language-server-5.1.3.tgz", - "integrity": "sha512-r+pAcYtWdN8tKlYZPwiiHNA2QPjXnI02NrW5Sf2cVM3TRtuQ3V9EKKwOxqwaQ0krsaEXk/CbN90I5erBuf84Vg==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "typescript-language-server": "lib/cli.mjs" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/undici": { - "version": "6.24.1", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", - "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, - "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.27.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/vite/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/vitest": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.0.18", - "@vitest/mocker": "4.0.18", - "@vitest/pretty-format": "4.0.18", - "@vitest/runner": "4.0.18", - "@vitest/snapshot": "4.0.18", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "es-module-lexer": "^1.7.0", - "expect-type": "^1.2.2", - "magic-string": "^0.30.21", - "obug": "^2.1.1", - "pathe": "^2.0.3", - "picomatch": "^4.0.3", - "std-env": "^3.10.0", - "tinybench": "^2.9.0", - "tinyexec": "^1.0.2", - "tinyglobby": "^0.2.15", - "tinyrainbow": "^3.0.3", - "vite": "^6.0.0 || ^7.0.0", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^20.0.0 || ^22.0.0 || >=24.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@opentelemetry/api": "^1.9.0", - "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.0.18", - "@vitest/browser-preview": "4.0.18", - "@vitest/browser-webdriverio": "4.0.18", - "@vitest/ui": "4.0.18", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yaml": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", - "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "vendor/codex-ai-plugin": { - "name": "@codex-ai/plugin", - "version": "1.2.10-codex.1" - }, - "vendor/codex-ai-sdk": { - "name": "@codex-ai/sdk", - "version": "1.2.10-codex.1", - "dev": true - } - } + "name": "codex-multi-auth", + "version": "1.2.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "codex-multi-auth", + "version": "1.2.0", + "bundleDependencies": [ + "@codex-ai/plugin" + ], + "license": "MIT", + "dependencies": { + "@codex-ai/plugin": "file:vendor/codex-ai-plugin", + "@openauthjs/openauth": "^0.4.3", + "hono": "4.12.6", + "undici": "^6.24.1", + "zod": "^4.3.6" + }, + "bin": { + "codex": "scripts/codex.js", + "codex-multi-auth": "scripts/codex-multi-auth.js" + }, + "devDependencies": { + "@codex-ai/sdk": "file:vendor/codex-ai-sdk", + "@fast-check/vitest": "^0.2.4", + "@types/node": "^25.3.0", + "@typescript-eslint/eslint-plugin": "^8.56.0", + "@typescript-eslint/parser": "^8.56.0", + "@vitest/coverage-v8": "^4.0.18", + "@vitest/ui": "^4.0.18", + "eslint": "^10.0.0", + "fast-check": "^4.5.3", + "husky": "^9.1.7", + "lint-staged": "^16.2.7", + "typescript": "^5.9.3", + "typescript-language-server": "^5.1.3", + "vitest": "^4.0.18" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "typescript": "^5" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.6" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@codex-ai/plugin": { + "resolved": "vendor/codex-ai-plugin", + "link": true + }, + "node_modules/@codex-ai/sdk": { + "resolved": "vendor/codex-ai-sdk", + "link": true + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.2.tgz", + "integrity": "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.2.tgz", + "integrity": "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.2.tgz", + "integrity": "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.2.tgz", + "integrity": "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.2.tgz", + "integrity": "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.2.tgz", + "integrity": "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.2.tgz", + "integrity": "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.2.tgz", + "integrity": "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.2.tgz", + "integrity": "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.2.tgz", + "integrity": "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.2.tgz", + "integrity": "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.2.tgz", + "integrity": "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.2.tgz", + "integrity": "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.2.tgz", + "integrity": "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.2.tgz", + "integrity": "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.2.tgz", + "integrity": "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.2.tgz", + "integrity": "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.2.tgz", + "integrity": "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.2.tgz", + "integrity": "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.2.tgz", + "integrity": "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.2.tgz", + "integrity": "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.2.tgz", + "integrity": "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.2.tgz", + "integrity": "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.2.tgz", + "integrity": "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.2.tgz", + "integrity": "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.2.tgz", + "integrity": "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.1.tgz", + "integrity": "sha512-uVSdg/V4dfQmTjJzR0szNczjOH/J+FyUMMjYtr07xFRXR7EDf9i1qdxrD0VusZH9knj1/ecxzCQQxyic5NzAiA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^3.0.1", + "debug": "^4.3.1", + "minimatch": "^10.1.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.5.2.tgz", + "integrity": "sha512-a5MxrdDXEvqnIq+LisyCX6tQMPF/dSJpCfBgBauY+pNZ28yCtSsTvyTYrMhaI+LK26bVyCJfJkT0u8KIj2i1dQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/core": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz", + "integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/object-schema": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.1.tgz", + "integrity": "sha512-P9cq2dpr+LU8j3qbLygLcSZrl2/ds/pUpfnHNNuk5HW7mnngHs+6WSq5C9mO3rqRX8A1poxqLTC9cu0KOyJlBg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.6.0.tgz", + "integrity": "sha512-bIZEUzOI1jkhviX2cp5vNyXQc6olzb2ohewQubuYlMXZ2Q/XjBO0x0XhGPvc9fjSIiUN0vw+0hq53BJ4eQSJKQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^1.1.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + } + }, + "node_modules/@fast-check/vitest": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@fast-check/vitest/-/vitest-0.2.4.tgz", + "integrity": "sha512-Ilcr+JAIPhb1s6FRm4qoglQYSGXXrS+zAupZeNuWAA3qHVGDA1d1Gb84Hb/+otL3GzVZjFJESg5/1SfIvrgssA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "fast-check": "^3.0.0 || ^4.0.0" + }, + "peerDependencies": { + "vitest": "^1 || ^2 || ^3 || ^4" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", + "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.4.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@openauthjs/openauth": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@openauthjs/openauth/-/openauth-0.4.3.tgz", + "integrity": "sha512-RlnjqvHzqcbFVymEwhlUEuac4utA5h4nhSK/i2szZuQmxTIqbGUxZ+nM+avM+VV4Ing+/ZaNLKILoXS3yrkOOw==", + "dependencies": { + "@standard-schema/spec": "1.0.0-beta.3", + "aws4fetch": "1.0.20", + "jose": "5.9.6" + }, + "peerDependencies": { + "arctic": "^2.2.2", + "hono": "^4.0.0" + } + }, + "node_modules/@oslojs/asn1": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@oslojs/asn1/-/asn1-1.0.0.tgz", + "integrity": "sha512-zw/wn0sj0j0QKbIXfIlnEcTviaCzYOY3V5rAyjR6YtOByFtJiT574+8p9Wlach0lZH9fddD4yb9laEAIl4vXQA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oslojs/binary": "1.0.0" + } + }, + "node_modules/@oslojs/binary": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@oslojs/binary/-/binary-1.0.0.tgz", + "integrity": "sha512-9RCU6OwXU6p67H4NODbuxv2S3eenuQ4/WFLrsq+K/k682xrznH5EVWA7N4VFk9VYVcbFtKqur5YQQZc0ySGhsQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@oslojs/crypto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@oslojs/crypto/-/crypto-1.0.1.tgz", + "integrity": "sha512-7n08G8nWjAr/Yu3vu9zzrd0L9XnrJfpMioQcvCMxBIiF5orECHe5/3J0jmXRVvgfqMm/+4oxlQ+Sq39COYLcNQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oslojs/asn1": "1.0.0", + "@oslojs/binary": "1.0.0" + } + }, + "node_modules/@oslojs/encoding": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-1.1.0.tgz", + "integrity": "sha512-70wQhgYmndg4GCPxPPxPGevRKqTIJ2Nh4OkiMWmDAVYsTQ+Ta7Sq+rPevXyXGdzr30/qZBnyOalCszoMxlyldQ==", + "license": "MIT", + "peer": true + }, + "node_modules/@oslojs/jwt": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@oslojs/jwt/-/jwt-0.2.0.tgz", + "integrity": "sha512-bLE7BtHrURedCn4Mco3ma9L4Y1GR2SMBuIvjWr7rmQ4/W/4Jy70TIAgZ+0nIlk0xHz1vNP8x8DCns45Sb2XRbg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oslojs/encoding": "0.4.1" + } + }, + "node_modules/@oslojs/jwt/node_modules/@oslojs/encoding": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@oslojs/encoding/-/encoding-0.4.1.tgz", + "integrity": "sha512-hkjo6MuIK/kQR5CrGNdAPZhS01ZCXuWDRJ187zh6qqF2+yMHZpD9fAYpX8q2bOO6Ryhl3XpCT6kUX76N8hhm4Q==", + "license": "MIT", + "peer": true + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@standard-schema/spec": { + "version": "1.0.0-beta.3", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0-beta.3.tgz", + "integrity": "sha512-0ifF3BjA1E8SY9C+nUew8RefNOIq0cDlYALPty4rhUm8Rrl6tCM8hBT4bhGhx7I7iXD0uAgt50lgo8dD73ACMw==", + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.3.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.3.0.tgz", + "integrity": "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.56.0.tgz", + "integrity": "sha512-lRyPDLzNCuae71A3t9NEINBiTn7swyOhvUj3MyUOxb8x6g6vPEFoOU+ZRmGMusNC3X3YMhqMIX7i8ShqhT74Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.12.2", + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/type-utils": "8.56.0", + "@typescript-eslint/utils": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "ignore": "^7.0.5", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.56.0", + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.0.tgz", + "integrity": "sha512-IgSWvLobTDOjnaxAfDTIHaECbkNlAlKv2j5SjpB2v7QHKv1FIfjwMy8FsDbVfDX/KjmCmYICcw7uGaXLhtsLNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.0.tgz", + "integrity": "sha512-M3rnyL1vIQOMeWxTWIW096/TtVP+8W3p/XnaFflhmcFp+U4zlxUxWj4XwNs6HbDeTtN4yun0GNTTDBw/SvufKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.0", + "@typescript-eslint/types": "^8.56.0", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.0.tgz", + "integrity": "sha512-7UiO/XwMHquH+ZzfVCfUNkIXlp/yQjjnlYUyYz7pfvlK3/EyyN6BK+emDmGNyQLBtLGaYrTAI6KOw8tFucWL2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.0.tgz", + "integrity": "sha512-bSJoIIt4o3lKXD3xmDh9chZcjCz5Lk8xS7Rxn+6l5/pKrDpkCwtQNQQwZ2qRPk7TkUYhrq3WPIHXOXlbXP0itg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.56.0.tgz", + "integrity": "sha512-qX2L3HWOU2nuDs6GzglBeuFXviDODreS58tLY/BALPC7iu3Fa+J7EOTwnX9PdNBxUI7Uh0ntP0YWGnxCkXzmfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0", + "@typescript-eslint/utils": "8.56.0", + "debug": "^4.4.3", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.0.tgz", + "integrity": "sha512-DBsLPs3GsWhX5HylbP9HNG15U0bnwut55Lx12bHB9MpXxQ+R5GC8MwQe+N1UFXxAeQDvEsEDY6ZYwX03K7Z6HQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.0.tgz", + "integrity": "sha512-ex1nTUMWrseMltXUHmR2GAQ4d+WjkZCT4f+4bVsps8QEdh0vlBsaCokKTPlnqBFqqGaxilDNJG7b8dolW2m43Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.0", + "@typescript-eslint/tsconfig-utils": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/visitor-keys": "8.56.0", + "debug": "^4.4.3", + "minimatch": "^9.0.5", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.56.0.tgz", + "integrity": "sha512-RZ3Qsmi2nFGsS+n+kjLAYDPVlrzf7UhTffrDIKr+h2yzAlYP/y5ZulU0yeDEPItos2Ph46JAL5P/On3pe7kDIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/scope-manager": "8.56.0", + "@typescript-eslint/types": "8.56.0", + "@typescript-eslint/typescript-estree": "8.56.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.0.tgz", + "integrity": "sha512-q+SL+b+05Ud6LbEE35qe4A99P+htKTKVbyiNEe45eCbJFyh/HVK9QXwlrbz+Q4L8SOW4roxSVwXYj4DMBT7Ieg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.0", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", + "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.0.18", + "ast-v8-to-istanbul": "^0.3.10", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.1", + "obug": "^2.1.1", + "std-env": "^3.10.0", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.0.18", + "vitest": "4.0.18" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/expect/node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/ui": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.0.18.tgz", + "integrity": "sha512-CGJ25bc8fRi8Lod/3GHSvXRKi7nBo3kxh0ApW4yCjmrWmRmlT53B5E08XRSZRliygG0aVNxLrBEqPYdz/KcCtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "fflate": "^0.8.2", + "flatted": "^3.3.3", + "pathe": "^2.0.3", + "sirv": "^3.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.0.18" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz", + "integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/arctic": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/arctic/-/arctic-2.3.4.tgz", + "integrity": "sha512-+p30BOWsctZp+CVYCt7oAean/hWGW42sH5LAcRQX56ttEkFJWbzXBhmSpibbzwSJkRrotmsA+oAoJoVsU0f5xA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@oslojs/crypto": "1.0.1", + "@oslojs/encoding": "1.1.0", + "@oslojs/jwt": "0.2.0" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.10.tgz", + "integrity": "sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" + } + }, + "node_modules/aws4fetch": { + "version": "1.0.20", + "resolved": "https://registry.npmjs.org/aws4fetch/-/aws4fetch-1.0.20.tgz", + "integrity": "sha512-/djoAN709iY65ETD6LKCtyyEI04XIBP5xVvfmNxsEP0uJB5tyaGBztSryRr4HqMStr9R06PisQE7m9zDTXKu6g==", + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz", + "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/brace-expansion": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", + "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz", + "integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "^7.1.0", + "string-width": "^8.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "14.0.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.2.tgz", + "integrity": "sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.2.tgz", + "integrity": "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.2", + "@esbuild/android-arm": "0.27.2", + "@esbuild/android-arm64": "0.27.2", + "@esbuild/android-x64": "0.27.2", + "@esbuild/darwin-arm64": "0.27.2", + "@esbuild/darwin-x64": "0.27.2", + "@esbuild/freebsd-arm64": "0.27.2", + "@esbuild/freebsd-x64": "0.27.2", + "@esbuild/linux-arm": "0.27.2", + "@esbuild/linux-arm64": "0.27.2", + "@esbuild/linux-ia32": "0.27.2", + "@esbuild/linux-loong64": "0.27.2", + "@esbuild/linux-mips64el": "0.27.2", + "@esbuild/linux-ppc64": "0.27.2", + "@esbuild/linux-riscv64": "0.27.2", + "@esbuild/linux-s390x": "0.27.2", + "@esbuild/linux-x64": "0.27.2", + "@esbuild/netbsd-arm64": "0.27.2", + "@esbuild/netbsd-x64": "0.27.2", + "@esbuild/openbsd-arm64": "0.27.2", + "@esbuild/openbsd-x64": "0.27.2", + "@esbuild/openharmony-arm64": "0.27.2", + "@esbuild/sunos-x64": "0.27.2", + "@esbuild/win32-arm64": "0.27.2", + "@esbuild/win32-ia32": "0.27.2", + "@esbuild/win32-x64": "0.27.2" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.0.0.tgz", + "integrity": "sha512-O0piBKY36YSJhlFSG8p9VUdPV/SxxS4FYDWVpr/9GJuMaepzwlf4J8I4ov1b+ySQfDTPhc3DtLaxcT1fN0yqCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.8.0", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.0", + "@eslint/config-helpers": "^0.5.2", + "@eslint/core": "^1.1.0", + "@eslint/plugin-kit": "^0.6.0", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "ajv": "^6.12.4", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^9.1.0", + "eslint-visitor-keys": "^5.0.0", + "espree": "^11.1.0", + "esquery": "^1.7.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "minimatch": "^10.1.1", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.0.tgz", + "integrity": "sha512-CkWE42hOJsNj9FJRaoMX9waUFYhqY4jmyLFdAdzZr6VaCg3ynLYx4WnOdkaIifGfH4gsUcBTn4OZbHXkpLD0FQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/espree": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.1.0.tgz", + "integrity": "sha512-WFWYhO1fV4iYkqOOvq8FbqIhr2pYfoDY0kCotMkDeNtGpiGGkZ1iov2u8ydjtgM8yF8rzK7oaTbw2NAzbAbehw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.0.tgz", + "integrity": "sha512-A0XeIi7CXU7nPlfHS9loMYEKxUaONu/hTEzHTGba9Huu94Cq1hPivf+DE5erJozZOky0LfvXAyrV/tcswpLI0Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-check": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.5.3.tgz", + "integrity": "sha512-IE9csY7lnhxBnA8g/WI5eg/hygA6MGWJMSNfFRrBlXUciADEhS1EDB0SIsMSvzubzIlOBbVITSsypCsW717poA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT", + "dependencies": { + "pure-rand": "^7.0.0" + }, + "engines": { + "node": ">=12.17.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fflate": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz", + "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz", + "integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/hono": { + "version": "4.12.6", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.6.tgz", + "integrity": "sha512-KljEp+MeEEEIOT75qBo1UjqqB29fRMtlDEwCxcexOzdkUq6LR/vRvHk5pdROcxyOYyW1niq7Gb5pFVGy5R1eBw==", + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jose": { + "version": "5.9.6", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.9.6.tgz", + "integrity": "sha512-AMlnetc9+CV9asI19zHmrgS/WYsWUwCn2R7RzlbJWD7F9eWYUTGyBmU9o6PxngtLGOiDGPRu+Uc4fhKzbpteZQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lint-staged": { + "version": "16.2.7", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", + "integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^14.0.2", + "listr2": "^9.0.5", + "micromatch": "^4.0.8", + "nano-spawn": "^2.0.0", + "pidtree": "^0.6.0", + "string-argv": "^0.3.2", + "yaml": "^2.8.1" + }, + "bin": { + "lint-staged": "bin/lint-staged.js" + }, + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://opencollective.com/lint-staged" + } + }, + "node_modules/listr2": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/magicast": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", + "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nano-spawn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz", + "integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/nano-spawn?sponsor=1" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz", + "integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-7.0.1.tgz", + "integrity": "sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rfdc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.0.tgz", + "integrity": "sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz", + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-language-server": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/typescript-language-server/-/typescript-language-server-5.1.3.tgz", + "integrity": "sha512-r+pAcYtWdN8tKlYZPwiiHNA2QPjXnI02NrW5Sf2cVM3TRtuQ3V9EKKwOxqwaQ0krsaEXk/CbN90I5erBuf84Vg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "typescript-language-server": "lib/cli.mjs" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/undici": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz", + "integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==", + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yaml": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz", + "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zod": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", + "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "vendor/codex-ai-plugin": { + "name": "@codex-ai/plugin", + "version": "1.2.10-codex.1" + }, + "vendor/codex-ai-sdk": { + "name": "@codex-ai/sdk", + "version": "1.2.10-codex.1", + "dev": true + } + } } diff --git a/package.json b/package.json index 992118ee..bee82a7a 100644 --- a/package.json +++ b/package.json @@ -57,8 +57,6 @@ "bench:edit-formats": "node scripts/benchmark-edit-formats.mjs --preset=codex-core", "bench:edit-formats:smoke": "node scripts/benchmark-edit-formats.mjs --smoke --preset=codex-core", "bench:edit-formats:render": "node scripts/benchmark-render-dashboard.mjs", - "bench:session-supervisor": "node scripts/benchmark-session-supervisor.mjs", - "bench:session-supervisor:smoke": "node scripts/benchmark-session-supervisor.mjs --smoke", "bench:runtime-path": "npm run build && node scripts/benchmark-runtime-path.mjs", "bench:runtime-path:quick": "node scripts/benchmark-runtime-path.mjs", "test:coverage": "vitest run --coverage", diff --git a/scripts/benchmark-session-supervisor.mjs b/scripts/benchmark-session-supervisor.mjs deleted file mode 100644 index e7d65655..00000000 --- a/scripts/benchmark-session-supervisor.mjs +++ /dev/null @@ -1,485 +0,0 @@ -#!/usr/bin/env node - -import { EventEmitter } from "node:events"; -import { mkdtemp, rm } from "node:fs/promises"; -import { tmpdir } from "node:os"; -import { dirname, join, resolve } from "node:path"; -import { performance } from "node:perf_hooks"; -import process from "node:process"; - -function argValue(args, name) { - const prefix = `${name}=`; - const match = args.find((arg) => arg.startsWith(prefix)); - return match ? match.slice(prefix.length) : undefined; -} - -function parsePositiveInt(value, fallback) { - if (!value) return fallback; - const parsed = Number.parseInt(value, 10); - if (!Number.isFinite(parsed) || parsed <= 0) return fallback; - return parsed; -} - -function average(values) { - if (values.length === 0) return 0; - return values.reduce((sum, value) => sum + value, 0) / values.length; -} - -function round(value) { - return Number(value.toFixed(3)); -} - -class FakeChild extends EventEmitter { - constructor() { - super(); - this.exitCode = null; - this.killCalls = []; - } - - kill(signal) { - this.killCalls.push(signal); - return true; - } -} - -class FakeManager { - constructor(accounts) { - this.accounts = accounts.map((account, index) => ({ - index, - refreshToken: `rt_${account.accountId}`, - email: `${account.accountId}@example.com`, - enabled: true, - coolingDownUntil: 0, - ...account, - })); - this.activeIndex = 0; - } - - getAccountsSnapshot() { - return this.accounts.map((account) => ({ ...account })); - } - - getAccountByIndex(index) { - return this.accounts.find((account) => account.index === index) ?? null; - } - - getCurrentAccountForFamily() { - return this.getAccountByIndex(this.activeIndex); - } - - getCurrentOrNextForFamilyHybrid() { - const now = Date.now(); - const ordered = [ - this.getCurrentAccountForFamily(), - ...this.accounts.filter((account) => account.index !== this.activeIndex), - ].filter(Boolean); - return ( - ordered.find( - (account) => - account.enabled !== false && - (account.coolingDownUntil ?? 0) <= now, - ) ?? null - ); - } - - getMinWaitTimeForFamily() { - const now = Date.now(); - const waits = this.accounts - .map((account) => Math.max(0, (account.coolingDownUntil ?? 0) - now)) - .filter((waitMs) => waitMs > 0); - return waits.length > 0 ? Math.min(...waits) : 0; - } - - markRateLimitedWithReason(account, waitMs) { - const target = this.getAccountByIndex(account.index); - if (!target) return; - target.coolingDownUntil = Date.now() + Math.max(waitMs, 1); - } - - markAccountCoolingDown(account, waitMs) { - this.markRateLimitedWithReason(account, waitMs); - } - - setActiveIndex(index) { - this.activeIndex = index; - } - - async syncCodexCliActiveSelectionForIndex() {} - - async saveToDisk() {} -} - -async function buildRuntime(probeLatencyMs, tempRoot, options = {}) { - const pluginConfig = { - preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 10, - preemptiveQuotaRemainingPercent7d: 5, - retryAllAccountsRateLimited: true, - }; - const accounts = - options.accounts ?? [ - { accountId: "near-limit", access: "token-1" }, - { accountId: "healthy", access: "token-2" }, - ]; - const manager = new FakeManager(accounts); - const quotaByAccountId = - options.quotaByAccountId ?? - new Map([ - [ - "near-limit", - { - status: 200, - primary: { usedPercent: 91 }, - secondary: { usedPercent: 12 }, - }, - ], - [ - "healthy", - { - status: 200, - primary: { usedPercent: 25 }, - secondary: { usedPercent: 8 }, - }, - ], - ]); - - const runtime = { - AccountManager: { - async loadFromDisk() { - return manager; - }, - }, - getStoragePath() { - return join(tempRoot, "accounts.json"); - }, - getPreemptiveQuotaEnabled(config) { - return config.preemptiveQuotaEnabled !== false; - }, - getPreemptiveQuotaRemainingPercent5h(config) { - return config.preemptiveQuotaRemainingPercent5h ?? 10; - }, - getPreemptiveQuotaRemainingPercent7d(config) { - return config.preemptiveQuotaRemainingPercent7d ?? 5; - }, - getRetryAllAccountsRateLimited(config) { - return config.retryAllAccountsRateLimited !== false; - }, - async fetchCodexQuotaSnapshot({ accountId, signal }) { - await new Promise((resolve, reject) => { - const timer = setTimeout(resolve, probeLatencyMs); - if (!signal) return; - const onAbort = () => { - clearTimeout(timer); - const error = new Error("Quota probe aborted"); - error.name = "AbortError"; - reject(error); - }; - signal.addEventListener("abort", onAbort, { once: true }); - }); - return quotaByAccountId.get(accountId) ?? null; - }, - }; - - return { runtime, pluginConfig, manager }; -} - -async function runCase( - api, - name, - iterations, - probeLatencyMs, - runtimeOptions = {}, - harnessOptions = {}, -) { - const tempRoot = await mkdtemp(join(tmpdir(), "codex-supervisor-bench-")); - const serialDurations = []; - const overlapDurations = []; - const prewarmedDurations = []; - const originalBatchSize = - process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE; - const originalCacheTtl = - process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS; - if (harnessOptions.selectionProbeBatchSize) { - process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE = `${harnessOptions.selectionProbeBatchSize}`; - } - - try { - for (let iteration = 0; iteration < iterations; iteration += 1) { - process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "75"; - process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS = "0"; - api.clearAllProbeSnapshotCache?.(); - const serialEnv = await buildRuntime( - probeLatencyMs, - tempRoot, - runtimeOptions, - ); - let start = performance.now(); - await api.requestChildRestart(new FakeChild(), "win32"); - await api.ensureLaunchableAccount( - serialEnv.runtime, - serialEnv.pluginConfig, - new AbortController().signal, - { probeTimeoutMs: probeLatencyMs + 250 }, - ); - serialDurations.push(performance.now() - start); - - const overlapEnv = await buildRuntime( - probeLatencyMs, - tempRoot, - runtimeOptions, - ); - start = performance.now(); - await Promise.all([ - api.requestChildRestart(new FakeChild(), "win32"), - api.ensureLaunchableAccount( - overlapEnv.runtime, - overlapEnv.pluginConfig, - new AbortController().signal, - { probeTimeoutMs: probeLatencyMs + 250 }, - ), - ]); - overlapDurations.push(performance.now() - start); - - const prewarmedEnv = await buildRuntime( - probeLatencyMs, - tempRoot, - runtimeOptions, - ); - const prewarmedPromise = api.prepareResumeSelection({ - runtime: prewarmedEnv.runtime, - pluginConfig: prewarmedEnv.pluginConfig, - currentAccount: prewarmedEnv.manager.getCurrentAccountForFamily(), - restartDecision: { - reason: "quota-near-exhaustion", - waitMs: 0, - sessionId: "bench-session", - }, - signal: new AbortController().signal, - }); - await prewarmedPromise; - start = performance.now(); - await api.requestChildRestart(new FakeChild(), "win32"); - prewarmedDurations.push(performance.now() - start); - } - } finally { - delete process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS; - if (originalCacheTtl === undefined) { - delete process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS; - } else { - process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS = - originalCacheTtl; - } - if (originalBatchSize === undefined) { - delete process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE; - } else { - process.env.CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_BATCH_SIZE = - originalBatchSize; - } - await rm(tempRoot, { recursive: true, force: true }); - } - - const serialAvgMs = average(serialDurations); - const overlapAvgMs = average(overlapDurations); - const prewarmedAvgMs = average(prewarmedDurations); - return { - name, - iterations, - probeLatencyMs, - selectionProbeBatchSize: - harnessOptions.selectionProbeBatchSize ?? "default", - serialPauseAvgMs: round(serialAvgMs), - overlapPauseAvgMs: round(overlapAvgMs), - prewarmedPauseAvgMs: round(prewarmedAvgMs), - serialToOverlapImprovementMs: round(serialAvgMs - overlapAvgMs), - serialToOverlapImprovementPct: - serialAvgMs <= 0 ? 0 : round(((serialAvgMs - overlapAvgMs) / serialAvgMs) * 100), - overlapToPrewarmedImprovementMs: round(overlapAvgMs - prewarmedAvgMs), - overlapToPrewarmedImprovementPct: - overlapAvgMs <= 0 - ? 0 - : round(((overlapAvgMs - prewarmedAvgMs) / overlapAvgMs) * 100), - }; -} - -async function main() { - const args = process.argv.slice(2); - const smoke = args.includes("--smoke"); - const iterations = parsePositiveInt(argValue(args, "--iterations"), smoke ? 4 : 12); - const probeLatencyMs = parsePositiveInt( - argValue(args, "--probe-latency-ms"), - smoke ? 120 : 180, - ); - const outputPath = argValue(args, "--output"); - - process.env.NODE_ENV = "test"; - const { __testOnly: api } = await import("./codex-supervisor.js"); - if (!api) { - throw new Error("benchmark requires codex-supervisor test helpers"); - } - - const payload = { - generatedAt: new Date().toISOString(), - node: process.version, - iterations, - results: [ - await runCase(api, "session_rotation_overlap_windows", iterations, probeLatencyMs), - await runCase( - api, - "session_rotation_multi_candidate_windows", - iterations, - probeLatencyMs, - { - accounts: [ - { accountId: "degraded-1", access: "token-1" }, - { accountId: "degraded-2", access: "token-2" }, - { accountId: "degraded-3", access: "token-3" }, - { accountId: "healthy", access: "token-4" }, - ], - quotaByAccountId: new Map([ - [ - "degraded-1", - { - status: 200, - primary: { usedPercent: 93 }, - secondary: { usedPercent: 12 }, - }, - ], - [ - "degraded-2", - { - status: 200, - primary: { usedPercent: 94 }, - secondary: { usedPercent: 13 }, - }, - ], - [ - "degraded-3", - { - status: 200, - primary: { usedPercent: 95 }, - secondary: { usedPercent: 14 }, - }, - ], - [ - "healthy", - { - status: 200, - primary: { usedPercent: 25 }, - secondary: { usedPercent: 8 }, - }, - ], - ]), - }, - ), - await runCase( - api, - "session_rotation_multi_candidate_batch1_windows", - iterations, - probeLatencyMs, - { - accounts: [ - { accountId: "degraded-1", access: "token-1" }, - { accountId: "degraded-2", access: "token-2" }, - { accountId: "degraded-3", access: "token-3" }, - { accountId: "healthy", access: "token-4" }, - ], - quotaByAccountId: new Map([ - [ - "degraded-1", - { - status: 200, - primary: { usedPercent: 93 }, - secondary: { usedPercent: 12 }, - }, - ], - [ - "degraded-2", - { - status: 200, - primary: { usedPercent: 94 }, - secondary: { usedPercent: 13 }, - }, - ], - [ - "degraded-3", - { - status: 200, - primary: { usedPercent: 95 }, - secondary: { usedPercent: 14 }, - }, - ], - [ - "healthy", - { - status: 200, - primary: { usedPercent: 25 }, - secondary: { usedPercent: 8 }, - }, - ], - ]), - }, - { selectionProbeBatchSize: 1 }, - ), - await runCase( - api, - "session_rotation_failure_mix_windows", - iterations, - probeLatencyMs, - { - accounts: [ - { accountId: "rate-limited", access: "token-1" }, - { accountId: "near-limit", access: "token-2" }, - { accountId: "healthy", access: "token-3" }, - ], - quotaByAccountId: new Map([ - [ - "rate-limited", - { - status: 429, - primary: { usedPercent: 100 }, - secondary: { usedPercent: 18 }, - }, - ], - [ - "near-limit", - { - status: 200, - primary: { usedPercent: 92 }, - secondary: { usedPercent: 12 }, - }, - ], - [ - "healthy", - { - status: 200, - primary: { usedPercent: 24 }, - secondary: { usedPercent: 7 }, - }, - ], - ]), - }, - ), - ], - }; - - if (outputPath) { - const resolved = resolve(outputPath); - await import("node:fs/promises").then(({ mkdir, writeFile }) => - mkdir(dirname(resolved), { recursive: true }).then(() => - writeFile(resolved, `${JSON.stringify(payload, null, 2)}\n`, "utf8"), - ), - ); - console.log(`Session supervisor benchmark written: ${resolved}`); - } - - console.log(JSON.stringify(payload, null, 2)); -} - -main().catch((error) => { - console.error( - `Session supervisor benchmark failed: ${ - error instanceof Error ? error.message : String(error) - }`, - ); - process.exit(1); -}); From 7f3c5d4f96f844c78fa5e7d585a496db35d4b89c Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 23:09:46 +0800 Subject: [PATCH 16/24] fix: address remaining review comments --- lib/config.ts | 2 +- scripts/codex-supervisor.js | 2 +- test/codex-supervisor.test.ts | 90 +++++++++++++++++------------------ 3 files changed, 47 insertions(+), 47 deletions(-) diff --git a/lib/config.ts b/lib/config.ts index b2673e8d..e9a50403 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -2,6 +2,7 @@ import { readFileSync, existsSync, promises as fs } from "node:fs"; import { dirname, join } from "node:path"; import type { PluginConfig } from "./types.js"; import { logWarn } from "./logger.js"; +import { DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H } from "./preemptive-quota-scheduler.js"; import { PluginConfigSchema, getValidationErrors } from "./schemas.js"; import { getCodexHomeDir, getCodexMultiAuthDir, getLegacyCodexDir } from "./runtime-paths.js"; import { @@ -1125,4 +1126,3 @@ export function getPreemptiveQuotaMaxDeferralMs(pluginConfig: PluginConfig): num { min: 1_000 }, ); } -import { DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H } from "./preemptive-quota-scheduler.js"; diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index 8cdb7d12..8d02ec96 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -1689,7 +1689,7 @@ async function runInteractiveSupervision({ monitorController.abort(); await monitorPromise; if (monitorFailure && !signal?.aborted) { - supervisorDebug( + relaunchNotice( `monitor loop failed: ${monitorFailure instanceof Error ? monitorFailure.message : String(monitorFailure)}`, ); } diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index d92bca1f..6558d46c 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -970,56 +970,56 @@ describe("codex supervisor", () => { "keeps the child exit code when the monitor loop fails after startup", { timeout: 10_000 }, async () => { - class FakeChild extends EventEmitter { - exitCode: number | null = null; - - constructor(exitCode: number) { - super(); - setTimeout(() => { - this.exitCode = exitCode; - this.emit("exit", exitCode, null); - }, 25); - } + class FakeChild extends EventEmitter { + exitCode: number | null = null; + + constructor(exitCode: number) { + super(); + setTimeout(() => { + this.exitCode = exitCode; + this.emit("exit", exitCode, null); + }, 25); + } - kill(_signal: string) { - return true; + kill(_signal: string) { + return true; + } } - } - const stderrSpy = vi - .spyOn(process.stderr, "write") - .mockImplementation(() => true); - const manager = new FakeManager(); - const runtime = createFakeRuntime(manager); + const stderrSpy = vi + .spyOn(process.stderr, "write") + .mockImplementation(() => true); + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager); - try { - const result = await supervisorTestApi?.runInteractiveSupervision({ - codexBin: "dist/bin/codex.js", - initialArgs: ["resume", "monitor-failure-session"], - buildForwardArgs: (rawArgs: string[]) => [...rawArgs], - runtime, - pluginConfig: {}, - manager, - signal: undefined, - maxSessionRestarts: 1, - spawnChild: () => new FakeChild(0), - findBinding: async ({ sessionId }: { sessionId?: string }) => ({ - sessionId: sessionId ?? "monitor-failure-session", - rolloutPath: null, - lastActivityAtMs: Date.now(), - }), - loadCurrentState: async () => { - throw new Error("Timed out waiting for supervisor storage lock"); - }, - }); + try { + const result = await supervisorTestApi?.runInteractiveSupervision({ + codexBin: "dist/bin/codex.js", + initialArgs: ["resume", "monitor-failure-session"], + buildForwardArgs: (rawArgs: string[]) => [...rawArgs], + runtime, + pluginConfig: {}, + manager, + signal: undefined, + maxSessionRestarts: 1, + spawnChild: () => new FakeChild(0), + findBinding: async ({ sessionId }: { sessionId?: string }) => ({ + sessionId: sessionId ?? "monitor-failure-session", + rolloutPath: null, + lastActivityAtMs: Date.now(), + }), + loadCurrentState: async () => { + throw new Error("Timed out waiting for supervisor storage lock"); + }, + }); - expect(result).toBe(0); - expect(stderrSpy).not.toHaveBeenCalledWith( - expect.stringContaining("Timed out waiting for supervisor storage lock"), - ); - } finally { - stderrSpy.mockRestore(); - } + expect(result).toBe(0); + expect(stderrSpy).toHaveBeenCalledWith( + expect.stringContaining("monitor loop failed: Timed out waiting for supervisor storage lock"), + ); + } finally { + stderrSpy.mockRestore(); + } }, ); From c080cd078a982c4fae1995c5183021ac5305dfd9 Mon Sep 17 00:00:00 2001 From: ndycode Date: Fri, 20 Mar 2026 23:38:00 +0800 Subject: [PATCH 17/24] fix: address remaining supervisor review comments --- lib/storage.ts | 2 +- lib/ui/copy.ts | 2 +- scripts/codex-supervisor.js | 21 ++++- scripts/codex.js | 23 ++++-- test/codex-bin-wrapper.test.ts | 37 ++++++++- test/codex-supervisor.test.ts | 142 +++++++++++++++++++++++++++++++++ test/storage.test.ts | 35 ++++++++ 7 files changed, 252 insertions(+), 10 deletions(-) diff --git a/lib/storage.ts b/lib/storage.ts index 02890d0f..7b265ca2 100644 --- a/lib/storage.ts +++ b/lib/storage.ts @@ -818,7 +818,7 @@ function latestValidSnapshot( .sort( (left, right) => (right.snapshot.mtimeMs ?? 0) - (left.snapshot.mtimeMs ?? 0) || - right.index - left.index, + left.index - right.index, )[0]?.snapshot; } diff --git a/lib/ui/copy.ts b/lib/ui/copy.ts index 1390e518..81256893 100644 --- a/lib/ui/copy.ts +++ b/lib/ui/copy.ts @@ -95,7 +95,7 @@ export const UI_COPY = { experimentalTitle: "Experimental", experimentalSubtitle: "Preview sync and backup actions before they become stable", experimentalHelpMenu: - "Enter Select | 1 Sync | 2 Backup | 3 Guard | [ - Down | ] + Up | S Save | Q Back", + "Enter Select | 1 Supervisor | 2 Sync | 3 Backup | 4 Guard | [ - Down | ] + Up | S Save | Q Back", experimentalHelpPreview: "Enter Select | A Apply | Q Back", experimentalHelpStatus: "Enter Select | Q Back", experimentalSessionSupervisor: "Enable Session Resume Supervisor", diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index 8d02ec96..15904f68 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -1508,6 +1508,12 @@ async function runInteractiveSupervision({ let requestedRestart = null; let preparedResumeSelectionPromise = null; let preparedResumeSelectionStarted = false; + const preparedResumeSelectionController = new AbortController(); + signal?.addEventListener( + "abort", + () => preparedResumeSelectionController.abort(), + { once: true }, + ); const rotationTrace = { detectedAtMs: 0, prewarmStartedAtMs: 0, @@ -1597,6 +1603,13 @@ async function runInteractiveSupervision({ break; } if (error?.name === "QuotaProbeUnavailableError") { + const slept = await sleep( + pollMs, + monitorController.signal, + ); + if (!slept) { + break; + } continue; } throw error; @@ -1622,7 +1635,7 @@ async function runInteractiveSupervision({ restartDecision: { sessionId: binding.sessionId, }, - signal, + signal: preparedResumeSelectionController.signal, preparedResumeSelectionStarted, preparedResumeSelectionPromise, }); @@ -1748,6 +1761,10 @@ async function runInteractiveSupervision({ } if (!restartDecision) { + preparedResumeSelectionController.abort(); + if (preparedResumeSelectionPromise) { + await preparedResumeSelectionPromise; + } return result.exitCode; } @@ -1875,7 +1892,7 @@ export async function runCodexSupervisorIfEnabled({ if (!runtime) { return null; } - return runCodexSupervisorWithRuntime({ + return await runCodexSupervisorWithRuntime({ codexBin, rawArgs, buildForwardArgs, diff --git a/scripts/codex.js b/scripts/codex.js index 944a204c..12cd6241 100755 --- a/scripts/codex.js +++ b/scripts/codex.js @@ -65,6 +65,12 @@ async function autoSyncManagerActiveSelectionIfEnabled() { } } +function isSupervisorInteractiveCommand(rawArgs) { + if (rawArgs.length === 0) return true; + const command = `${rawArgs[0] ?? ""}`.trim().toLowerCase(); + return command === "resume" || command === "fork"; +} + function resolveRealCodexBin() { const override = (process.env.CODEX_MULTI_AUTH_REAL_CODEX_BIN ?? "").trim(); if (override.length > 0) { @@ -526,20 +532,27 @@ async function main() { } const forwardArgs = buildForwardArgs(rawArgs); + const forwardToRealCodexWithStartupSync = async (codexBin, args) => { + await autoSyncManagerActiveSelectionIfEnabled(); + return forwardToRealCodex(codexBin, args); + }; const supervisedExitCode = await runCodexSupervisorIfEnabled({ codexBin: realCodexBin, rawArgs, buildForwardArgs, - forwardToRealCodex, + forwardToRealCodex: forwardToRealCodexWithStartupSync, }); - // The supervisor persists account selection, but the wrapper still runs startup sync - // before returning so the live Codex CLI state can refresh expired token material. - await autoSyncManagerActiveSelectionIfEnabled(); if (supervisedExitCode !== null) { + if (supervisedExitCode === 130) { + return 130; + } + if (isSupervisorInteractiveCommand(rawArgs)) { + await autoSyncManagerActiveSelectionIfEnabled(); + } return supervisedExitCode; } - return forwardToRealCodex(realCodexBin, forwardArgs); + return forwardToRealCodexWithStartupSync(realCodexBin, forwardArgs); } const exitCode = await main(); diff --git a/test/codex-bin-wrapper.test.ts b/test/codex-bin-wrapper.test.ts index e1e75f9a..21d2a1df 100644 --- a/test/codex-bin-wrapper.test.ts +++ b/test/codex-bin-wrapper.test.ts @@ -1,6 +1,7 @@ import { type SpawnSyncReturns, spawn, spawnSync } from "node:child_process"; import { copyFileSync, + existsSync, mkdirSync, mkdtempSync, readFileSync, @@ -112,6 +113,19 @@ function writeSupervisorRuntimeFixture(fixtureRoot: string): void { ].join("\n"), "utf8", ); + writeFileSync( + join(distLibDir, "storage.js"), + [ + "export function getStoragePath() {", + `\treturn ${JSON.stringify(join(fixtureRoot, "openai-codex-accounts.json"))};`, + "}", + ].join("\n"), + "utf8", + ); +} + +function writeSupervisorStub(fixtureRoot: string, lines: string[]): void { + writeFileSync(join(fixtureRoot, "scripts", "codex-supervisor.js"), lines.join("\n"), "utf8"); } function writeCodexManagerAutoSyncFixture(fixtureRoot: string): void { @@ -634,7 +648,7 @@ describe("codex bin wrapper", () => { expect(readFileSync(markerPath, "utf8")).toContain("supervisor\n"); }); - it("still auto-syncs once when the supervisor returns early", () => { + it("auto-syncs once for a supervisor-forwarded command", () => { const fixtureRoot = createWrapperFixture(); writeSupervisorRuntimeFixture(fixtureRoot); writeCodexManagerAutoSyncFixture(fixtureRoot); @@ -652,6 +666,27 @@ describe("codex bin wrapper", () => { expect(readFileSync(markerPath, "utf8")).toBe("sync\n"); }); + it("skips startup auto-sync when the supervisor returns the abort sentinel", () => { + const fixtureRoot = createWrapperFixture(); + writeSupervisorStub(fixtureRoot, [ + "export async function runCodexSupervisorIfEnabled() {", + "\treturn 130;", + "}", + ]); + writeCodexManagerAutoSyncFixture(fixtureRoot); + const fakeBin = createFakeCodexBin(fixtureRoot); + const markerPath = join(fixtureRoot, "abort-auto-sync.log"); + + const result = runWrapper(fixtureRoot, ["resume", "session-123"], { + CODEX_MULTI_AUTH_REAL_CODEX_BIN: fakeBin, + CODEX_TEST_AUTO_SYNC_MARKER: markerPath, + }); + + expect(result.status).toBe(130); + expect(result.stdout).not.toContain("FORWARDED:"); + expect(existsSync(markerPath)).toBe(false); + }); + it("supports interactive commands through the supervisor wrapper", () => { const fixtureRoot = createWrapperFixture(); writeSupervisorRuntimeFixture(fixtureRoot); diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 6558d46c..73c6acd7 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -653,6 +653,94 @@ describe("codex supervisor", () => { }); }); + it("aborts prepared prewarm selection when the session exits without rotating", async () => { + class FakeChild extends EventEmitter { + exitCode: number | null = null; + + constructor(exitCode: number) { + super(); + setTimeout(() => { + this.exitCode = exitCode; + this.emit("exit", exitCode, null); + }, 25); + } + + kill(_signal: string) { + return true; + } + } + + const manager = new FakeManager(); + const storageDir = createTempDir(); + let preparedProbeSignal: AbortSignal | undefined; + const runtime = { + AccountManager: { + async loadFromDisk() { + return manager; + }, + }, + getStoragePath() { + return join(storageDir, "accounts.json"); + }, + getPreemptiveQuotaEnabled() { + return true; + }, + getPreemptiveQuotaRemainingPercent5h() { + return 10; + }, + getPreemptiveQuotaRemainingPercent7d() { + return 5; + }, + getRetryAllAccountsRateLimited() { + return true; + }, + async fetchCodexQuotaSnapshot({ + accountId, + signal, + }: { + accountId: string; + signal?: AbortSignal; + }) { + if (accountId === "near-limit") { + return { + status: 200, + primary: { usedPercent: 86 }, + secondary: { usedPercent: 12 }, + }; + } + preparedProbeSignal = signal; + return await new Promise((_resolve, reject) => { + const onAbort = () => { + const error = new Error("Quota probe aborted"); + error.name = "AbortError"; + reject(error); + }; + signal?.addEventListener("abort", onAbort, { once: true }); + }); + }, + }; + + const result = await supervisorTestApi?.runInteractiveSupervision({ + codexBin: "dist/bin/codex.js", + initialArgs: ["resume", "prewarm-clean-exit"], + buildForwardArgs: (rawArgs: string[]) => [...rawArgs], + runtime, + pluginConfig: {}, + manager, + signal: undefined, + maxSessionRestarts: 1, + spawnChild: () => new FakeChild(0), + findBinding: async ({ sessionId }: { sessionId?: string }) => ({ + sessionId: sessionId ?? "prewarm-clean-exit", + rolloutPath: null, + lastActivityAtMs: Date.now(), + }), + }); + + expect(result).toBe(0); + expect(preparedProbeSignal?.aborted).toBe(true); + }); + it("reuses a cached healthy snapshot within the short ttl", async () => { process.env.CODEX_AUTH_CLI_SESSION_SNAPSHOT_CACHE_TTL_MS = "5000"; const manager = new FakeManager(); @@ -1023,6 +1111,60 @@ describe("codex supervisor", () => { }, ); + it( + "paces repeated quota probe outages instead of hot-looping the monitor", + { timeout: 10_000 }, + async () => { + vi.useFakeTimers(); + process.env.CODEX_AUTH_CLI_SESSION_SUPERVISOR_POLL_MS = "20"; + + class FakeChild extends EventEmitter { + exitCode: number | null = null; + + constructor(exitCode: number) { + super(); + setTimeout(() => { + this.exitCode = exitCode; + this.emit("exit", exitCode, null); + }, 60); + } + + kill(_signal: string) { + return true; + } + } + + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager, { + onFetch(accountId) { + if (accountId === "near-limit") { + throw new Error("quota endpoint unavailable"); + } + }, + }); + + const runPromise = supervisorTestApi?.runInteractiveSupervision({ + codexBin: "dist/bin/codex.js", + initialArgs: ["resume", "probe-unavailable-session"], + buildForwardArgs: (rawArgs: string[]) => [...rawArgs], + runtime, + pluginConfig: {}, + manager, + signal: undefined, + maxSessionRestarts: 1, + spawnChild: () => new FakeChild(0), + findBinding: async ({ sessionId }: { sessionId?: string }) => ({ + sessionId: sessionId ?? "probe-unavailable-session", + rolloutPath: null, + lastActivityAtMs: Date.now(), + }), + }); + + await vi.advanceTimersByTimeAsync(100); + await expect(runPromise).resolves.toBe(0); + }, + ); + it("degrades a failed candidate probe and continues to the next healthy account", async () => { const manager = new FakeManager([ { accountId: "broken", access: "token-broken" }, diff --git a/test/storage.test.ts b/test/storage.test.ts index 2b5293dc..301b0a3a 100644 --- a/test/storage.test.ts +++ b/test/storage.test.ts @@ -13,6 +13,7 @@ import { findMatchingAccountIndex, formatStorageErrorHint, getFlaggedAccountsPath, + getBackupMetadata, getStoragePath, importAccounts, loadAccounts, @@ -3368,6 +3369,40 @@ describe("storage", () => { expect(historicalBackup.accounts?.[0]?.refreshToken).toBe("token-2"); expect(oldestBackup.accounts?.[0]?.refreshToken).toBe("token-1"); }); + + it("prefers earlier snapshot priority when valid backups share the same mtime", async () => { + const storagePath = getStoragePath(); + const snapshotTime = new Date("2026-03-20T00:00:00.000Z"); + const writeValidSnapshot = async (path: string, refreshToken: string) => { + await fs.writeFile( + path, + JSON.stringify( + { + version: 3, + activeIndex: 0, + accounts: [ + { + refreshToken, + addedAt: 1, + lastUsed: 1, + }, + ], + }, + null, + 2, + ), + "utf-8", + ); + await fs.utimes(path, snapshotTime, snapshotTime); + }; + + await writeValidSnapshot(storagePath, "primary-token"); + await writeValidSnapshot(`${storagePath}.bak`, "backup-token"); + await writeValidSnapshot(`${storagePath}.bak.1`, "backup-history-token"); + + const metadata = await getBackupMetadata(); + expect(metadata.accounts.latestValidPath).toBe(storagePath); + }); }); describe("clearAccounts edge cases", () => { From 2c935d51359d12f1bbc7b8d441647595a2f4187b Mon Sep 17 00:00:00 2001 From: ndycode Date: Sat, 21 Mar 2026 00:04:35 +0800 Subject: [PATCH 18/24] Fix supervisor command parsing follow-ups --- scripts/codex-routing.js | 39 +++++++++++++++++++++ scripts/codex-supervisor.js | 51 ++++++++++++++++++++------- scripts/codex.js | 11 +++--- test/codex-bin-wrapper.test.ts | 28 +++++++++++++++ test/codex-supervisor.test.ts | 64 +++++++++++++++++++++++++++++----- 5 files changed, 169 insertions(+), 24 deletions(-) diff --git a/scripts/codex-routing.js b/scripts/codex-routing.js index 297bf78d..7472e90c 100644 --- a/scripts/codex-routing.js +++ b/scripts/codex-routing.js @@ -12,6 +12,7 @@ const AUTH_SUBCOMMANDS = new Set([ "fix", "doctor", ]); +const COMMAND_FLAGS_WITH_VALUE = new Set(["-c", "--config"]); export function normalizeAuthAlias(args) { if (args.length >= 2 && args[0] === "multi" && args[1] === "auth") { @@ -32,4 +33,42 @@ export function shouldHandleMultiAuthAuth(args) { return AUTH_SUBCOMMANDS.has(subcommand); } +export function findPrimaryCodexCommand(args) { + let expectFlagValue = false; + let stopOptionParsing = false; + + for (let index = 0; index < args.length; index += 1) { + const normalizedArg = `${args[index] ?? ""}`.trim().toLowerCase(); + if (normalizedArg.length === 0) { + continue; + } + if (expectFlagValue) { + expectFlagValue = false; + continue; + } + if (!stopOptionParsing && normalizedArg === "--") { + stopOptionParsing = true; + continue; + } + if (!stopOptionParsing) { + if (COMMAND_FLAGS_WITH_VALUE.has(normalizedArg)) { + expectFlagValue = true; + continue; + } + if (normalizedArg.startsWith("--config=")) { + continue; + } + if (normalizedArg.startsWith("-")) { + continue; + } + } + return { + command: normalizedArg, + index, + }; + } + + return null; +} + export { AUTH_SUBCOMMANDS }; diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index 15904f68..19765730 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -4,6 +4,7 @@ import { homedir } from "node:os"; import { dirname, join, resolve as resolvePath } from "node:path"; import process from "node:process"; import { createInterface } from "node:readline"; +import { findPrimaryCodexCommand } from "./codex-routing.js"; const DEFAULT_POLL_MS = 300; const DEFAULT_IDLE_MS = 250; @@ -37,6 +38,7 @@ const MAX_SESSION_RESTARTS = parseNumberEnv( ); const CODEX_FAMILY = "codex"; const snapshotProbeCache = new Map(); +const sessionRolloutPathById = new Map(); function sleep(ms, signal) { return new Promise((resolve) => { @@ -134,9 +136,8 @@ function getSessionsRootDir() { } function isInteractiveCommand(rawArgs) { - if (rawArgs.length === 0) return true; - const command = `${rawArgs[0] ?? ""}`.trim().toLowerCase(); - return command === "resume" || command === "fork"; + const command = findPrimaryCodexCommand(rawArgs)?.command; + return !command || command === "resume" || command === "fork"; } function isNonInteractiveCommand(rawArgs) { @@ -144,14 +145,18 @@ function isNonInteractiveCommand(rawArgs) { } function isSupervisorAccountGateBypassCommand(rawArgs) { - if (rawArgs.length === 0) return false; + const primaryCommand = findPrimaryCodexCommand(rawArgs)?.command; + if (!primaryCommand) return false; const normalizedArgs = rawArgs .map((arg) => `${arg ?? ""}`.trim().toLowerCase()) .filter((arg) => arg.length > 0); if (normalizedArgs.length === 0) return false; - const firstArg = normalizedArgs[0]; - if (firstArg === "auth" || firstArg === "help" || firstArg === "version") { + if ( + primaryCommand === "auth" || + primaryCommand === "help" || + primaryCommand === "version" + ) { return true; } @@ -161,11 +166,21 @@ function isSupervisorAccountGateBypassCommand(rawArgs) { } function readResumeSessionId(rawArgs) { - if ((rawArgs[0] ?? "").trim().toLowerCase() !== "resume") return null; - const sessionId = `${rawArgs[1] ?? ""}`.trim(); + const primaryCommand = findPrimaryCodexCommand(rawArgs); + if (primaryCommand?.command !== "resume") return null; + const sessionId = `${rawArgs[primaryCommand.index + 1] ?? ""}`.trim(); return isValidSessionId(sessionId) ? sessionId : null; } +function rememberSessionBinding(binding) { + if (!binding?.sessionId || !binding?.rolloutPath) return; + sessionRolloutPathById.set(binding.sessionId, binding.rolloutPath); +} + +function clearSessionBindingPathCache() { + sessionRolloutPathById.clear(); +} + async function importIfPresent(specifier) { try { return await import(specifier); @@ -1333,15 +1348,23 @@ async function findSessionBinding({ sessionEntries, }) { const cwdKey = normalizeCwd(cwd); - if (rolloutPathHint) { - const directEntry = await readSessionBindingEntry(rolloutPathHint); + const knownRolloutPath = + rolloutPathHint ?? (sessionId ? sessionRolloutPathById.get(sessionId) : null); + if (knownRolloutPath) { + const directEntry = await readSessionBindingEntry(knownRolloutPath); if (directEntry) { const directBinding = await matchSessionBindingEntry( directEntry, cwdKey, sessionId, ); - if (directBinding) return directBinding; + if (directBinding) { + rememberSessionBinding(directBinding); + return directBinding; + } + } + if (sessionId && !rolloutPathHint) { + sessionRolloutPathById.delete(sessionId); } } @@ -1356,7 +1379,10 @@ async function findSessionBinding({ for (const entry of files) { const binding = await matchSessionBindingEntry(entry, cwdKey, sessionId); - if (binding) return binding; + if (binding) { + rememberSessionBinding(binding); + return binding; + } } return null; @@ -1937,6 +1963,7 @@ const TEST_ONLY_API = { runInteractiveSupervision, runCodexSupervisorWithRuntime, waitForSessionBinding, + clearSessionBindingPathCache, }; export const __testOnly = diff --git a/scripts/codex.js b/scripts/codex.js index 12cd6241..cbe2840d 100755 --- a/scripts/codex.js +++ b/scripts/codex.js @@ -6,7 +6,11 @@ import { createRequire } from "node:module"; import { basename, delimiter, dirname, join, resolve as resolvePath } from "node:path"; import process from "node:process"; import { fileURLToPath } from "node:url"; -import { normalizeAuthAlias, shouldHandleMultiAuthAuth } from "./codex-routing.js"; +import { + findPrimaryCodexCommand, + normalizeAuthAlias, + shouldHandleMultiAuthAuth, +} from "./codex-routing.js"; import { runCodexSupervisorIfEnabled } from "./codex-supervisor.js"; function hydrateCliVersionEnv() { @@ -66,9 +70,8 @@ async function autoSyncManagerActiveSelectionIfEnabled() { } function isSupervisorInteractiveCommand(rawArgs) { - if (rawArgs.length === 0) return true; - const command = `${rawArgs[0] ?? ""}`.trim().toLowerCase(); - return command === "resume" || command === "fork"; + const command = findPrimaryCodexCommand(rawArgs)?.command; + return !command || command === "resume" || command === "fork"; } function resolveRealCodexBin() { diff --git a/test/codex-bin-wrapper.test.ts b/test/codex-bin-wrapper.test.ts index 21d2a1df..d2f90988 100644 --- a/test/codex-bin-wrapper.test.ts +++ b/test/codex-bin-wrapper.test.ts @@ -705,4 +705,32 @@ describe("codex bin wrapper", () => { expect(result.stdout.match(/FORWARDED:/g) ?? []).toHaveLength(1); expect(readFileSync(markerPath, "utf8")).toBe("sync\n"); }); + + it("keeps option-prefixed resume commands on the interactive post-session sync path", () => { + const fixtureRoot = createWrapperFixture(); + writeSupervisorStub(fixtureRoot, [ + "export async function runCodexSupervisorIfEnabled({ codexBin, rawArgs, buildForwardArgs, forwardToRealCodex }) {", + "\tawait forwardToRealCodex(codexBin, buildForwardArgs(rawArgs));", + "\treturn 0;", + "}", + ]); + writeCodexManagerAutoSyncFixture(fixtureRoot); + const fakeBin = createFakeCodexBin(fixtureRoot); + const markerPath = join(fixtureRoot, "interactive-option-auto-sync.log"); + + const result = runWrapper( + fixtureRoot, + ["-c", 'profile="dev"', "resume", "session-123"], + { + CODEX_MULTI_AUTH_REAL_CODEX_BIN: fakeBin, + CODEX_TEST_AUTO_SYNC_MARKER: markerPath, + }, + ); + + expect(result.status).toBe(0); + expect(result.stdout).toContain( + 'FORWARDED:-c profile="dev" resume session-123 -c cli_auth_credentials_store="file"', + ); + expect(readFileSync(markerPath, "utf8")).toBe("sync\nsync\n"); + }); }); diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 73c6acd7..1253d313 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -2,7 +2,6 @@ import { EventEmitter } from "node:events"; import { mkdtempSync, promises as fs } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { performance } from "node:perf_hooks"; import { afterEach, describe, expect, it, vi } from "vitest"; import { __testOnly as supervisorTestApi } from "../scripts/codex-supervisor.js"; @@ -250,6 +249,7 @@ function createFakeRuntime( afterEach(async () => { vi.useRealTimers(); supervisorTestApi?.clearAllProbeSnapshotCache?.(); + supervisorTestApi?.clearSessionBindingPathCache?.(); for (const key of envKeys) { const value = originalEnv[key]; if (value === undefined) { @@ -312,7 +312,7 @@ describe("codex supervisor", () => { await expect(supervisorTestApi?.extractSessionMeta(filePath)).resolves.toBeNull(); }); - it("reuses the known rollout path before scanning the sessions tree again", async () => { + it("reuses the cached rollout path for a known session before scanning the sessions tree again", async () => { const codexHome = createTempDir(); const cwd = createTempDir(); process.env.CODEX_HOME = codexHome; @@ -348,7 +348,6 @@ describe("codex supervisor", () => { cwd, sinceMs: 0, sessionId: "known-session", - rolloutPathHint: first?.rolloutPath, }); expect(second).toMatchObject({ sessionId: "known-session", @@ -360,6 +359,31 @@ describe("codex supervisor", () => { } }); + it("parses option-prefixed interactive commands consistently", () => { + expect( + supervisorTestApi?.isInteractiveCommand([ + "-c", + 'profile="dev"', + "resume", + "session-123", + ]), + ).toBe(true); + expect( + supervisorTestApi?.readResumeSessionId([ + "--config", + 'env="dev"', + "resume", + "session-123", + ]), + ).toBe("session-123"); + expect( + supervisorTestApi?.isInteractiveCommand([ + "--config=env=\"dev\"", + "fork", + ]), + ).toBe(true); + }); + it("caches the session file listing across binding wait polls", async () => { const codexHome = createTempDir(); const cwd = createTempDir(); @@ -955,15 +979,31 @@ describe("codex supervisor", () => { expect(manager.activeIndex).toBe(1); }); - it("batches probe work so multiple degraded accounts do not add serial pause", async () => { + it("starts degraded candidate probes in the same batch before waiting on results", async () => { const manager = new FakeManager([ { accountId: "degraded-1", access: "token-1" }, { accountId: "degraded-2", access: "token-2" }, { accountId: "degraded-3", access: "token-3" }, { accountId: "healthy", access: "token-4" }, ]); + const degradedProbeGate = createDeferred(); + const firstProbeStarted = createDeferred(); + const startedAccounts = new Set(); const runtime = createFakeRuntime(manager, { quotaProbeDelayMs: 70, + waitForFetchByAccountId: new Map([ + ["degraded-1", degradedProbeGate.promise], + ["degraded-2", degradedProbeGate.promise], + ["degraded-3", degradedProbeGate.promise], + ]), + onFetchStart(accountId) { + if (accountId.startsWith("degraded-")) { + startedAccounts.add(accountId); + if (startedAccounts.size === 1) { + firstProbeStarted.resolve(); + } + } + }, snapshots: new Map([ [ "degraded-1", @@ -984,21 +1024,29 @@ describe("codex supervisor", () => { ]), }); - const startedAt = performance.now(); - const result = await supervisorTestApi?.ensureLaunchableAccount( + const pendingResult = supervisorTestApi?.ensureLaunchableAccount( runtime, {}, undefined, { probeTimeoutMs: 250 }, ); - const elapsedMs = performance.now() - startedAt; + await firstProbeStarted.promise; + for (let attempt = 0; attempt < 6 && startedAccounts.size < 3; attempt += 1) { + await new Promise((resolve) => setImmediate(resolve)); + } + expect([...startedAccounts].sort()).toEqual([ + "degraded-1", + "degraded-2", + "degraded-3", + ]); + degradedProbeGate.resolve(); + const result = await pendingResult; expect(result).toMatchObject({ ok: true, account: { accountId: "healthy" }, }); expect(manager.activeIndex).toBe(3); - expect(elapsedMs).toBeLessThan(170); }); it("bypasses supervisor account gating for auth commands before account selection", async () => { From 10098190bc295b65eb6c4b5d2ce62795f387d08a Mon Sep 17 00:00:00 2001 From: ndycode Date: Sat, 21 Mar 2026 00:17:43 +0800 Subject: [PATCH 19/24] Fix remaining supervisor review follow-ups --- lib/config.ts | 1 + lib/preemptive-quota-scheduler.ts | 1 + scripts/codex-supervisor.js | 637 ++++++++++++++++-------------- scripts/codex.js | 11 +- test/codex-bin-wrapper.test.ts | 6 + test/codex-supervisor.test.ts | 45 +++ test/storage.test.ts | 12 +- 7 files changed, 406 insertions(+), 307 deletions(-) diff --git a/lib/config.ts b/lib/config.ts index e9a50403..9ad3a5b2 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -1079,6 +1079,7 @@ export function getPreemptiveQuotaRemainingPercent5h(pluginConfig: PluginConfig) return resolveNumberSetting( "CODEX_AUTH_PREEMPTIVE_QUOTA_5H_REMAINING_PCT", pluginConfig.preemptiveQuotaRemainingPercent5h, + // Keep this fallback aligned with PreemptiveQuotaScheduler's intentional 10% 5h default. DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H, { min: 0, max: 100 }, ); diff --git a/lib/preemptive-quota-scheduler.ts b/lib/preemptive-quota-scheduler.ts index 3f709e69..9fc8b6dc 100644 --- a/lib/preemptive-quota-scheduler.ts +++ b/lib/preemptive-quota-scheduler.ts @@ -25,6 +25,7 @@ export interface QuotaSchedulerOptions { } export const DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H = 10; +// Intentionally keep the 7d window less aggressive than the 5h window. const DEFAULT_SECONDARY_REMAINING_PERCENT_THRESHOLD = 5; const DEFAULT_MAX_DEFERRAL_MS = 2 * 60 * 60_000; diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index 19765730..cf56ff1c 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -135,7 +135,7 @@ function getSessionsRootDir() { return join(resolveCodexHomeDir(), "sessions"); } -function isInteractiveCommand(rawArgs) { +export function isInteractiveCommand(rawArgs) { const command = findPrimaryCodexCommand(rawArgs)?.command; return !command || command === "resume" || command === "fork"; } @@ -181,6 +181,37 @@ function clearSessionBindingPathCache() { sessionRolloutPathById.clear(); } +function createLinkedAbortController(parentSignal) { + const controller = new AbortController(); + if (!parentSignal) { + return { + controller, + cleanup: () => controller.abort(), + }; + } + const onParentAbort = () => controller.abort(); + parentSignal.addEventListener("abort", onParentAbort, { once: true }); + return { + controller, + cleanup: () => { + parentSignal.removeEventListener("abort", onParentAbort); + controller.abort(); + }, + }; +} + +function getSessionBindingEntryPasses(entries, sinceMs, sessionId, hasKnownRolloutPath) { + const sortedEntries = [...entries].sort((left, right) => right.mtimeMs - left.mtimeMs); + const recentEntries = sortedEntries.filter((entry) => entry.mtimeMs >= sinceMs - 2_000); + if (!sessionId || hasKnownRolloutPath) { + return [recentEntries]; + } + if (recentEntries.length === 0 || recentEntries.length === sortedEntries.length) { + return [sortedEntries]; + } + return [recentEntries, sortedEntries]; +} + async function importIfPresent(specifier) { try { return await import(specifier); @@ -1374,14 +1405,20 @@ async function findSessionBinding({ return readSessionBindingEntry(filePath); }), ))) - .filter((entry) => entry && (sessionId ? true : entry.mtimeMs >= sinceMs - 2_000)) - .sort((left, right) => right.mtimeMs - left.mtimeMs); - - for (const entry of files) { - const binding = await matchSessionBindingEntry(entry, cwdKey, sessionId); - if (binding) { - rememberSessionBinding(binding); - return binding; + .filter(Boolean); + const passes = getSessionBindingEntryPasses( + files, + sinceMs, + sessionId, + Boolean(knownRolloutPath), + ); + for (const entries of passes) { + for (const entry of entries) { + const binding = await matchSessionBindingEntry(entry, cwdKey, sessionId); + if (binding) { + rememberSessionBinding(binding); + return binding; + } } } @@ -1518,108 +1555,86 @@ async function runInteractiveSupervision({ return 130; } launchCount += 1; + const preparedResumeSelectionLink = createLinkedAbortController(signal); + const preparedResumeSelectionController = + preparedResumeSelectionLink.controller; const child = spawnChild(codexBin, launchArgs); - const launchStartedAt = Date.now(); - let binding = knownSessionId - ? await findBinding({ - cwd: process.cwd(), - sinceMs: 0, - sessionId: knownSessionId, - rolloutPathHint: knownRolloutPath, - }) - : null; - if (binding?.rolloutPath) { - knownRolloutPath = binding.rolloutPath; - } - let requestedRestart = null; let preparedResumeSelectionPromise = null; - let preparedResumeSelectionStarted = false; - const preparedResumeSelectionController = new AbortController(); - signal?.addEventListener( - "abort", - () => preparedResumeSelectionController.abort(), - { once: true }, - ); - const rotationTrace = { - detectedAtMs: 0, - prewarmStartedAtMs: 0, - prewarmCompletedAtMs: 0, - restartRequestedAtMs: 0, - resumeReadyAtMs: 0, - }; - let monitorActive = true; - const monitorController = new AbortController(); - - const pollMs = parseNumberEnv( - "CODEX_AUTH_CLI_SESSION_SUPERVISOR_POLL_MS", - DEFAULT_POLL_MS, - 250, - ); - const idleMs = parseNumberEnv( - "CODEX_AUTH_CLI_SESSION_SUPERVISOR_IDLE_MS", - DEFAULT_IDLE_MS, - 100, - ); - const captureTimeoutMs = parseNumberEnv( - "CODEX_AUTH_CLI_SESSION_CAPTURE_TIMEOUT_MS", - DEFAULT_SESSION_CAPTURE_TIMEOUT_MS, - 1_000, - ); - const monitorProbeTimeoutMs = resolveProbeTimeoutMs( - "CODEX_AUTH_CLI_SESSION_MONITOR_PROBE_TIMEOUT_MS", - DEFAULT_MONITOR_PROBE_TIMEOUT_MS, - ); + try { + const launchStartedAt = Date.now(); + let binding = knownSessionId + ? await findBinding({ + cwd: process.cwd(), + sinceMs: 0, + sessionId: knownSessionId, + rolloutPathHint: knownRolloutPath, + }) + : null; + if (binding?.rolloutPath) { + knownRolloutPath = binding.rolloutPath; + } + let requestedRestart = null; + let preparedResumeSelectionStarted = false; + const rotationTrace = { + detectedAtMs: 0, + prewarmStartedAtMs: 0, + prewarmCompletedAtMs: 0, + restartRequestedAtMs: 0, + resumeReadyAtMs: 0, + }; + let monitorActive = true; + const monitorController = new AbortController(); - let monitorFailure = null; - const monitorPromise = (async () => { - try { - while (monitorActive) { - if (!binding) { - binding = await waitForBinding({ - cwd: process.cwd(), - sinceMs: launchStartedAt, - sessionId: knownSessionId, - rolloutPathHint: knownRolloutPath, - timeoutMs: captureTimeoutMs, - signal: monitorController.signal, - }); - if (binding?.sessionId) { - knownSessionId = binding.sessionId; - knownRolloutPath = binding.rolloutPath ?? knownRolloutPath; - } - } else { - binding = await refreshBinding(binding); - if (binding?.rolloutPath) { - knownRolloutPath = binding.rolloutPath; - } - } + const pollMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_SUPERVISOR_POLL_MS", + DEFAULT_POLL_MS, + 250, + ); + const idleMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_SUPERVISOR_IDLE_MS", + DEFAULT_IDLE_MS, + 100, + ); + const captureTimeoutMs = parseNumberEnv( + "CODEX_AUTH_CLI_SESSION_CAPTURE_TIMEOUT_MS", + DEFAULT_SESSION_CAPTURE_TIMEOUT_MS, + 1_000, + ); + const monitorProbeTimeoutMs = resolveProbeTimeoutMs( + "CODEX_AUTH_CLI_SESSION_MONITOR_PROBE_TIMEOUT_MS", + DEFAULT_MONITOR_PROBE_TIMEOUT_MS, + ); - if (!requestedRestart) { - let currentState; - try { - currentState = await loadCurrentState( - runtime, - monitorController.signal, - ); - } catch (error) { - if ( - monitorController.signal.aborted || - error?.name === "AbortError" - ) { - break; + let monitorFailure = null; + const monitorPromise = (async () => { + try { + while (monitorActive) { + if (!binding) { + binding = await waitForBinding({ + cwd: process.cwd(), + sinceMs: launchStartedAt, + sessionId: knownSessionId, + rolloutPathHint: knownRolloutPath, + timeoutMs: captureTimeoutMs, + signal: monitorController.signal, + }); + if (binding?.sessionId) { + knownSessionId = binding.sessionId; + knownRolloutPath = binding.rolloutPath ?? knownRolloutPath; + } + } else { + binding = await refreshBinding(binding); + if (binding?.rolloutPath) { + knownRolloutPath = binding.rolloutPath; } - throw error; } - manager = currentState.manager ?? manager; - const currentAccount = currentState.currentAccount; - if (currentAccount) { - let snapshot; + + if (!requestedRestart) { + let currentState; try { - snapshot = await probeAccountSnapshot( + currentState = await loadCurrentState( runtime, - currentAccount, monitorController.signal, - monitorProbeTimeoutMs, ); } catch (error) { if ( @@ -1628,232 +1643,254 @@ async function runInteractiveSupervision({ ) { break; } - if (error?.name === "QuotaProbeUnavailableError") { - const slept = await sleep( - pollMs, + throw error; + } + manager = currentState.manager ?? manager; + const currentAccount = currentState.currentAccount; + if (currentAccount) { + let snapshot; + try { + snapshot = await probeAccountSnapshot( + runtime, + currentAccount, monitorController.signal, + monitorProbeTimeoutMs, ); - if (!slept) { + } catch (error) { + if ( + monitorController.signal.aborted || + error?.name === "AbortError" + ) { break; } - continue; - } - throw error; - } - const pressure = computeQuotaPressure( - snapshot, - runtime, - pluginConfig, - ); - if (pressure.prewarm && binding?.sessionId) { - if (!rotationTrace.detectedAtMs) { - rotationTrace.detectedAtMs = Date.now(); + if (error?.name === "QuotaProbeUnavailableError") { + const slept = await sleep( + pollMs, + monitorController.signal, + ); + if (!slept) { + break; + } + continue; + } + throw error; } - if (!preparedResumeSelectionStarted) { - rotationTrace.prewarmStartedAtMs = Date.now(); - supervisorDebug( - `prewarming successor for session ${binding.sessionId} ${formatQuotaPressure(pressure)}`, - ); - const preparedState = maybeStartPreparedResumeSelection({ - runtime, - pluginConfig, - currentAccount, - restartDecision: { - sessionId: binding.sessionId, - }, - signal: preparedResumeSelectionController.signal, - preparedResumeSelectionStarted, - preparedResumeSelectionPromise, - }); - preparedResumeSelectionStarted = - preparedState.preparedResumeSelectionStarted; - preparedResumeSelectionPromise = - preparedState.preparedResumeSelectionPromise?.then((prepared) => { - if (rotationTrace.prewarmCompletedAtMs === 0) { - rotationTrace.prewarmCompletedAtMs = Date.now(); - } - return prepared; - }) ?? null; + const pressure = computeQuotaPressure( + snapshot, + runtime, + pluginConfig, + ); + if (pressure.prewarm && binding?.sessionId) { + if (!rotationTrace.detectedAtMs) { + rotationTrace.detectedAtMs = Date.now(); + } + if (!preparedResumeSelectionStarted) { + rotationTrace.prewarmStartedAtMs = Date.now(); + supervisorDebug( + `prewarming successor for session ${binding.sessionId} ${formatQuotaPressure(pressure)}`, + ); + const preparedState = maybeStartPreparedResumeSelection({ + runtime, + pluginConfig, + currentAccount, + restartDecision: { + sessionId: binding.sessionId, + }, + signal: preparedResumeSelectionController.signal, + preparedResumeSelectionStarted, + preparedResumeSelectionPromise, + }); + preparedResumeSelectionStarted = + preparedState.preparedResumeSelectionStarted; + preparedResumeSelectionPromise = + preparedState.preparedResumeSelectionPromise?.then((prepared) => { + if (rotationTrace.prewarmCompletedAtMs === 0) { + rotationTrace.prewarmCompletedAtMs = Date.now(); + } + return prepared; + }) ?? null; + } } - } - if (pressure.rotate && binding?.sessionId) { - const pendingRestartDecision = { - reason: pressure.reason, - waitMs: pressure.waitMs, - sessionId: binding.sessionId, - }; - const lastActivityAtMs = - binding.lastActivityAtMs ?? launchStartedAt; - if (Date.now() - lastActivityAtMs >= idleMs) { - requestedRestart = pendingRestartDecision; - rotationTrace.restartRequestedAtMs = Date.now(); - relaunchNotice( - `rotating session ${binding.sessionId} because ${pressure.reason.replace(/-/g, " ")} (${formatQuotaPressure(pressure)})`, - ); - monitorActive = false; - await requestRestart(child, process.platform, signal); - monitorController.abort(); - continue; + if (pressure.rotate && binding?.sessionId) { + const pendingRestartDecision = { + reason: pressure.reason, + waitMs: pressure.waitMs, + sessionId: binding.sessionId, + }; + const lastActivityAtMs = + binding.lastActivityAtMs ?? launchStartedAt; + if (Date.now() - lastActivityAtMs >= idleMs) { + requestedRestart = pendingRestartDecision; + rotationTrace.restartRequestedAtMs = Date.now(); + relaunchNotice( + `rotating session ${binding.sessionId} because ${pressure.reason.replace(/-/g, " ")} (${formatQuotaPressure(pressure)})`, + ); + monitorActive = false; + await requestRestart(child, process.platform, signal); + monitorController.abort(); + continue; + } } } } - } - const slept = await sleep(pollMs, monitorController.signal); - if (!slept) break; - } - } catch (error) { - if (!monitorController.signal.aborted && error?.name !== "AbortError") { - monitorFailure = error; + const slept = await sleep(pollMs, monitorController.signal); + if (!slept) break; + } + } catch (error) { + if (!monitorController.signal.aborted && error?.name !== "AbortError") { + monitorFailure = error; + } } - } - })(); + })(); - const result = await new Promise((resolve) => { - child.once("error", (error) => { - resolve({ - exitCode: 1, - error, + const result = await new Promise((resolve) => { + child.once("error", (error) => { + resolve({ + exitCode: 1, + error, + }); }); - }); - child.once("exit", (code, exitSignal) => { - resolve({ - exitCode: normalizeExitCode(code, exitSignal), - signal: exitSignal, + child.once("exit", (code, exitSignal) => { + resolve({ + exitCode: normalizeExitCode(code, exitSignal), + signal: exitSignal, + }); }); }); - }); - - monitorActive = false; - monitorController.abort(); - await monitorPromise; - if (monitorFailure && !signal?.aborted) { - relaunchNotice( - `monitor loop failed: ${monitorFailure instanceof Error ? monitorFailure.message : String(monitorFailure)}`, - ); - } - binding = - binding ?? - (await findBinding({ - cwd: process.cwd(), - sinceMs: launchStartedAt, - sessionId: knownSessionId, - rolloutPathHint: knownRolloutPath, - })); - if (binding?.sessionId) { - knownSessionId = binding.sessionId; - knownRolloutPath = binding.rolloutPath ?? knownRolloutPath; - } - let restartDecision = requestedRestart; - if (!restartDecision && result.exitCode !== 0 && knownSessionId) { - const refreshedState = await withLockedManager( - runtime, - async (freshManager) => ({ - manager: freshManager, - currentAccount: getCurrentAccount(freshManager), - }), - signal, - ); - manager = refreshedState.manager ?? manager; - if (signal?.aborted) { - return result.exitCode; + monitorActive = false; + monitorController.abort(); + await monitorPromise; + if (monitorFailure && !signal?.aborted) { + relaunchNotice( + `monitor loop failed: ${monitorFailure instanceof Error ? monitorFailure.message : String(monitorFailure)}`, + ); } - let snapshot = null; - if (refreshedState.currentAccount) { - try { - snapshot = await probeAccountSnapshot( - runtime, - refreshedState.currentAccount, - signal, - ); - } catch (error) { - if (signal?.aborted || error?.name === "AbortError") { - throw error; - } - if (error?.name !== "QuotaProbeUnavailableError") { - throw error; + binding = + binding ?? + (await findBinding({ + cwd: process.cwd(), + sinceMs: launchStartedAt, + sessionId: knownSessionId, + rolloutPathHint: knownRolloutPath, + })); + if (binding?.sessionId) { + knownSessionId = binding.sessionId; + knownRolloutPath = binding.rolloutPath ?? knownRolloutPath; + } + + let restartDecision = requestedRestart; + if (!restartDecision && result.exitCode !== 0 && knownSessionId) { + const refreshedState = await withLockedManager( + runtime, + async (freshManager) => ({ + manager: freshManager, + currentAccount: getCurrentAccount(freshManager), + }), + signal, + ); + manager = refreshedState.manager ?? manager; + if (signal?.aborted) { + return result.exitCode; + } + let snapshot = null; + if (refreshedState.currentAccount) { + try { + snapshot = await probeAccountSnapshot( + runtime, + refreshedState.currentAccount, + signal, + ); + } catch (error) { + if (signal?.aborted || error?.name === "AbortError") { + throw error; + } + if (error?.name !== "QuotaProbeUnavailableError") { + throw error; + } } } + const evaluation = evaluateQuotaSnapshot(snapshot, runtime, pluginConfig); + if (evaluation.rotate) { + restartDecision = { + reason: evaluation.reason, + waitMs: evaluation.waitMs, + sessionId: knownSessionId, + }; + } } - const evaluation = evaluateQuotaSnapshot(snapshot, runtime, pluginConfig); - if (evaluation.rotate) { - restartDecision = { - reason: evaluation.reason, - waitMs: evaluation.waitMs, - sessionId: knownSessionId, - }; + + if (!restartDecision) { + return result.exitCode; } - } - if (!restartDecision) { - preparedResumeSelectionController.abort(); - if (preparedResumeSelectionPromise) { - await preparedResumeSelectionPromise; + if (!restartDecision.sessionId) { + relaunchNotice( + "rotation needed but no resumable session was captured; re-run `codex` manually", + ); + return result.exitCode; } - return result.exitCode; - } - if (!restartDecision.sessionId) { - relaunchNotice( - "rotation needed but no resumable session was captured; re-run `codex` manually", - ); - return result.exitCode; - } + const currentAccount = getCurrentAccount(manager); + if (currentAccount) { + const refreshedManager = await markCurrentAccountForRestart( + runtime, + currentAccount, + restartDecision, + signal, + ); + manager = refreshedManager ?? manager; + } - const currentAccount = getCurrentAccount(manager); - if (currentAccount) { - const refreshedManager = await markCurrentAccountForRestart( - runtime, - currentAccount, - restartDecision, - signal, - ); - manager = refreshedManager ?? manager; - } + let nextReady = null; + if (preparedResumeSelectionPromise) { + const prepared = await preparedResumeSelectionPromise; + nextReady = prepared?.nextReady ?? null; + } + if (nextReady?.ok) { + const committedReady = await commitPreparedSelection( + runtime, + nextReady.account, + signal, + ); + if (committedReady?.ok) { + nextReady = committedReady; + } else { + nextReady = null; + } + } - let nextReady = null; - if (preparedResumeSelectionPromise) { - const prepared = await preparedResumeSelectionPromise; - nextReady = prepared?.nextReady ?? null; - } - if (nextReady?.ok) { - const committedReady = await commitPreparedSelection( - runtime, - nextReady.account, - signal, - ); - if (committedReady?.ok) { - nextReady = committedReady; - } else { - nextReady = null; + if (!nextReady) { + nextReady = await ensureLaunchableAccount(runtime, pluginConfig, signal, { + probeTimeoutMs: resolveProbeTimeoutMs( + "CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_TIMEOUT_MS", + DEFAULT_SELECTION_PROBE_TIMEOUT_MS, + ), + }); + } + if (nextReady.aborted) { + return 130; + } + if (!nextReady.ok) { + relaunchNotice( + `no healthy account available to resume ${restartDecision.sessionId}; recover manually with \`codex resume ${restartDecision.sessionId}\` when quota resets`, + ); + return result.exitCode; } - } - if (!nextReady) { - nextReady = await ensureLaunchableAccount(runtime, pluginConfig, signal, { - probeTimeoutMs: resolveProbeTimeoutMs( - "CODEX_AUTH_CLI_SESSION_SELECTION_PROBE_TIMEOUT_MS", - DEFAULT_SELECTION_PROBE_TIMEOUT_MS, - ), - }); - } - if (nextReady.aborted) { - return 130; - } - if (!nextReady.ok) { - relaunchNotice( - `no healthy account available to resume ${restartDecision.sessionId}; recover manually with \`codex resume ${restartDecision.sessionId}\` when quota resets`, - ); - return result.exitCode; + manager = nextReady.manager ?? manager; + rotationTrace.resumeReadyAtMs = Date.now(); + logRotationSummary(restartDecision.sessionId, rotationTrace, nextReady); + launchArgs = buildResumeArgs(restartDecision.sessionId, buildForwardArgs); + knownSessionId = restartDecision.sessionId; + knownRolloutPath = binding?.rolloutPath ?? knownRolloutPath; + } finally { + preparedResumeSelectionLink.cleanup(); + if (preparedResumeSelectionPromise) { + await preparedResumeSelectionPromise.catch(() => null); + } } - - manager = nextReady.manager ?? manager; - rotationTrace.resumeReadyAtMs = Date.now(); - logRotationSummary(restartDecision.sessionId, rotationTrace, nextReady); - launchArgs = buildResumeArgs(restartDecision.sessionId, buildForwardArgs); - knownSessionId = restartDecision.sessionId; - knownRolloutPath = binding?.rolloutPath ?? knownRolloutPath; } relaunchNotice("session supervisor reached the restart safety limit"); @@ -1948,6 +1985,8 @@ const TEST_ONLY_API = { extractSessionMeta, isInteractiveCommand, isValidSessionId, + createLinkedAbortController, + getSessionBindingEntryPasses, listJsonlFiles, maybeStartPreparedResumeSelection, prepareResumeSelection, diff --git a/scripts/codex.js b/scripts/codex.js index cbe2840d..80b5a9d5 100755 --- a/scripts/codex.js +++ b/scripts/codex.js @@ -7,11 +7,13 @@ import { basename, delimiter, dirname, join, resolve as resolvePath } from "node import process from "node:process"; import { fileURLToPath } from "node:url"; import { - findPrimaryCodexCommand, normalizeAuthAlias, shouldHandleMultiAuthAuth, } from "./codex-routing.js"; -import { runCodexSupervisorIfEnabled } from "./codex-supervisor.js"; +import { + isInteractiveCommand as isSupervisorInteractiveCommand, + runCodexSupervisorIfEnabled, +} from "./codex-supervisor.js"; function hydrateCliVersionEnv() { try { @@ -69,11 +71,6 @@ async function autoSyncManagerActiveSelectionIfEnabled() { } } -function isSupervisorInteractiveCommand(rawArgs) { - const command = findPrimaryCodexCommand(rawArgs)?.command; - return !command || command === "resume" || command === "fork"; -} - function resolveRealCodexBin() { const override = (process.env.CODEX_MULTI_AUTH_REAL_CODEX_BIN ?? "").trim(); if (override.length > 0) { diff --git a/test/codex-bin-wrapper.test.ts b/test/codex-bin-wrapper.test.ts index d2f90988..f3cb708c 100644 --- a/test/codex-bin-wrapper.test.ts +++ b/test/codex-bin-wrapper.test.ts @@ -669,6 +669,9 @@ describe("codex bin wrapper", () => { it("skips startup auto-sync when the supervisor returns the abort sentinel", () => { const fixtureRoot = createWrapperFixture(); writeSupervisorStub(fixtureRoot, [ + "export function isInteractiveCommand() {", + "\treturn true;", + "}", "export async function runCodexSupervisorIfEnabled() {", "\treturn 130;", "}", @@ -709,6 +712,9 @@ describe("codex bin wrapper", () => { it("keeps option-prefixed resume commands on the interactive post-session sync path", () => { const fixtureRoot = createWrapperFixture(); writeSupervisorStub(fixtureRoot, [ + "export function isInteractiveCommand(rawArgs) {", + "\treturn Array.isArray(rawArgs) && rawArgs.includes(\"resume\");", + "}", "export async function runCodexSupervisorIfEnabled({ codexBin, rawArgs, buildForwardArgs, forwardToRealCodex }) {", "\tawait forwardToRealCodex(codexBin, buildForwardArgs(rawArgs));", "\treturn 0;", diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 1253d313..3efced76 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -415,6 +415,28 @@ describe("codex supervisor", () => { } }); + it("tries recent session entries before falling back to the full scan for known session ids", () => { + const recentEntry = { filePath: "recent.jsonl", mtimeMs: 5_000 }; + const staleEntry = { filePath: "stale.jsonl", mtimeMs: 100 }; + + expect( + supervisorTestApi?.getSessionBindingEntryPasses( + [staleEntry, recentEntry], + 4_000, + "known-session", + false, + ), + ).toEqual([[recentEntry], [recentEntry, staleEntry]]); + expect( + supervisorTestApi?.getSessionBindingEntryPasses( + [staleEntry, recentEntry], + 4_000, + "known-session", + true, + ), + ).toEqual([[recentEntry]]); + }); + it("interrupts child restart waits when the abort signal fires", async () => { vi.useFakeTimers(); class FakeChild extends EventEmitter { @@ -1102,6 +1124,29 @@ describe("codex supervisor", () => { }, ); + it("cleans up the parent abort listener for each linked abort controller", () => { + const controller = new AbortController(); + const addSpy = vi.spyOn(controller.signal, "addEventListener"); + const removeSpy = vi.spyOn(controller.signal, "removeEventListener"); + + try { + const first = supervisorTestApi?.createLinkedAbortController( + controller.signal, + ); + first?.cleanup(); + const second = supervisorTestApi?.createLinkedAbortController( + controller.signal, + ); + second?.cleanup(); + + expect(addSpy).toHaveBeenCalledTimes(2); + expect(removeSpy).toHaveBeenCalledTimes(2); + } finally { + addSpy.mockRestore(); + removeSpy.mockRestore(); + } + }); + it( "keeps the child exit code when the monitor loop fails after startup", { timeout: 10_000 }, diff --git a/test/storage.test.ts b/test/storage.test.ts index 301b0a3a..86ffeda1 100644 --- a/test/storage.test.ts +++ b/test/storage.test.ts @@ -29,6 +29,10 @@ import { withAccountStorageTransaction, } from "../lib/storage.js"; +function escapeRegExp(value: string): string { + return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); +} + // Mocking the behavior we're about to implement for TDD // Since the functions aren't in lib/storage.ts yet, we'll need to mock them or // accept that this test won't even compile/run until we add them. @@ -991,7 +995,13 @@ describe("storage", () => { setStoragePathDirect(secondaryStoragePath); await exportAccounts(exportPath); }), - ).rejects.toThrow(/storage path mismatch/); + ).rejects.toThrow( + new RegExp( + `storage path mismatch: transaction path is ${escapeRegExp( + testStoragePath, + )}, active path is ${escapeRegExp(secondaryStoragePath)}`, + ), + ); expect(existsSync(exportPath)).toBe(false); }); From 34db83e440ac66d20cf4679d64b249f3ce6c2d56 Mon Sep 17 00:00:00 2001 From: ndycode Date: Sat, 21 Mar 2026 00:23:58 +0800 Subject: [PATCH 20/24] Avoid double sync after supervisor forward --- scripts/codex.js | 4 +++- test/codex-bin-wrapper.test.ts | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/codex.js b/scripts/codex.js index 80b5a9d5..1197c616 100755 --- a/scripts/codex.js +++ b/scripts/codex.js @@ -532,7 +532,9 @@ async function main() { } const forwardArgs = buildForwardArgs(rawArgs); + let supervisorDidForward = false; const forwardToRealCodexWithStartupSync = async (codexBin, args) => { + supervisorDidForward = true; await autoSyncManagerActiveSelectionIfEnabled(); return forwardToRealCodex(codexBin, args); }; @@ -546,7 +548,7 @@ async function main() { if (supervisedExitCode === 130) { return 130; } - if (isSupervisorInteractiveCommand(rawArgs)) { + if (isSupervisorInteractiveCommand(rawArgs) && !supervisorDidForward) { await autoSyncManagerActiveSelectionIfEnabled(); } return supervisedExitCode; diff --git a/test/codex-bin-wrapper.test.ts b/test/codex-bin-wrapper.test.ts index f3cb708c..75057040 100644 --- a/test/codex-bin-wrapper.test.ts +++ b/test/codex-bin-wrapper.test.ts @@ -709,7 +709,7 @@ describe("codex bin wrapper", () => { expect(readFileSync(markerPath, "utf8")).toBe("sync\n"); }); - it("keeps option-prefixed resume commands on the interactive post-session sync path", () => { + it("avoids double sync when the supervisor forwards an interactive command", () => { const fixtureRoot = createWrapperFixture(); writeSupervisorStub(fixtureRoot, [ "export function isInteractiveCommand(rawArgs) {", @@ -737,6 +737,6 @@ describe("codex bin wrapper", () => { expect(result.stdout).toContain( 'FORWARDED:-c profile="dev" resume session-123 -c cli_auth_credentials_store="file"', ); - expect(readFileSync(markerPath, "utf8")).toBe("sync\nsync\n"); + expect(readFileSync(markerPath, "utf8")).toBe("sync\n"); }); }); From 71f5b3f73f2165270c68a1953c768d3169099532 Mon Sep 17 00:00:00 2001 From: ndycode Date: Sat, 21 Mar 2026 00:53:35 +0800 Subject: [PATCH 21/24] Address supervisor review follow-ups --- lib/storage.ts | 16 ++- scripts/codex-routing.js | 52 +++++++++ scripts/codex-supervisor.js | 174 ++++++++++++++++++++++++----- test/codex-supervisor.test.ts | 201 +++++++++++++++++++++++++++++++++- test/storage.test.ts | 78 +++++++++++++ 5 files changed, 490 insertions(+), 31 deletions(-) diff --git a/lib/storage.ts b/lib/storage.ts index 7b265ca2..983952f0 100644 --- a/lib/storage.ts +++ b/lib/storage.ts @@ -381,6 +381,20 @@ function getAccountsBackupRecoveryCandidates(path: string): string[] { return candidates; } +function normalizeStorageComparisonPath(path: string): string { + const resolved = resolvePath(path); + if (process.platform !== "win32") { + return resolved; + } + return resolved.replaceAll("\\", "/").toLowerCase(); +} + +function areEquivalentStoragePaths(left: string, right: string): boolean { + return ( + normalizeStorageComparisonPath(left) === normalizeStorageComparisonPath(right) + ); +} + async function getAccountsBackupRecoveryCandidatesWithDiscovery( path: string, ): Promise { @@ -2509,7 +2523,7 @@ export async function exportAccounts( const transactionState = transactionSnapshotContext.getStore(); if ( transactionState?.active && - transactionState.storagePath !== activeStoragePath + !areEquivalentStoragePaths(transactionState.storagePath, activeStoragePath) ) { throw new Error( `Export blocked by storage path mismatch: transaction path is ` + diff --git a/scripts/codex-routing.js b/scripts/codex-routing.js index 7472e90c..1068a056 100644 --- a/scripts/codex-routing.js +++ b/scripts/codex-routing.js @@ -13,6 +13,7 @@ const AUTH_SUBCOMMANDS = new Set([ "doctor", ]); const COMMAND_FLAGS_WITH_VALUE = new Set(["-c", "--config"]); +const HELP_OR_VERSION_FLAGS = new Set(["--help", "-h", "--version"]); export function normalizeAuthAlias(args) { if (args.length >= 2 && args[0] === "multi" && args[1] === "auth") { @@ -71,4 +72,55 @@ export function findPrimaryCodexCommand(args) { return null; } +export function hasTopLevelHelpOrVersionFlag(args) { + let expectFlagValue = false; + + for (let index = 0; index < args.length; index += 1) { + const normalizedArg = `${args[index] ?? ""}`.trim().toLowerCase(); + if (normalizedArg.length === 0) { + continue; + } + if (expectFlagValue) { + expectFlagValue = false; + continue; + } + if (normalizedArg === "--") { + return false; + } + if (HELP_OR_VERSION_FLAGS.has(normalizedArg)) { + return true; + } + if (COMMAND_FLAGS_WITH_VALUE.has(normalizedArg)) { + expectFlagValue = true; + continue; + } + if (normalizedArg.startsWith("--config=")) { + continue; + } + if (normalizedArg.startsWith("-")) { + continue; + } + return false; + } + + return false; +} + +export function splitCodexCommandArgs(args) { + const primaryCommand = findPrimaryCodexCommand(args); + if (!primaryCommand) { + return { + leadingArgs: [...args], + command: null, + trailingArgs: [], + }; + } + + return { + leadingArgs: args.slice(0, primaryCommand.index), + command: primaryCommand.command, + trailingArgs: args.slice(primaryCommand.index + 1), + }; +} + export { AUTH_SUBCOMMANDS }; diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index cf56ff1c..5e47133a 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -4,7 +4,11 @@ import { homedir } from "node:os"; import { dirname, join, resolve as resolvePath } from "node:path"; import process from "node:process"; import { createInterface } from "node:readline"; -import { findPrimaryCodexCommand } from "./codex-routing.js"; +import { + findPrimaryCodexCommand, + hasTopLevelHelpOrVersionFlag, + splitCodexCommandArgs, +} from "./codex-routing.js"; const DEFAULT_POLL_MS = 300; const DEFAULT_IDLE_MS = 250; @@ -145,23 +149,15 @@ function isNonInteractiveCommand(rawArgs) { } function isSupervisorAccountGateBypassCommand(rawArgs) { - const primaryCommand = findPrimaryCodexCommand(rawArgs)?.command; - if (!primaryCommand) return false; - const normalizedArgs = rawArgs - .map((arg) => `${arg ?? ""}`.trim().toLowerCase()) - .filter((arg) => arg.length > 0); - if (normalizedArgs.length === 0) return false; + if (hasTopLevelHelpOrVersionFlag(rawArgs)) { + return true; + } - if ( + const primaryCommand = findPrimaryCodexCommand(rawArgs)?.command; + return ( primaryCommand === "auth" || primaryCommand === "help" || primaryCommand === "version" - ) { - return true; - } - - return normalizedArgs.some( - (arg) => arg === "--help" || arg === "-h" || arg === "--version", ); } @@ -325,8 +321,14 @@ function normalizeExitCode(code, signal) { return typeof code === "number" ? code : 1; } -function buildResumeArgs(sessionId, buildForwardArgs) { - return buildForwardArgs(["resume", sessionId]); +function buildResumeArgs(sessionId, currentArgs) { + const { leadingArgs, command, trailingArgs } = splitCodexCommandArgs(currentArgs); + const remainingArgs = + (command === "resume" || command === "fork") && + isValidSessionId(trailingArgs[0]) + ? trailingArgs.slice(1) + : trailingArgs; + return [...leadingArgs, "resume", sessionId, ...remainingArgs]; } function getCurrentAccount(manager) { @@ -434,6 +436,84 @@ async function readSupervisorLockPayload(lockPath) { } } +function createSupervisorLockPayload(ownerId, acquiredAt, ttlMs) { + return { + ownerId, + pid: process.pid, + acquiredAt, + expiresAt: Date.now() + ttlMs, + }; +} + +async function writeSupervisorLockPayload(lockPath, ownerId, acquiredAt, ttlMs) { + await fs.writeFile( + lockPath, + `${JSON.stringify( + createSupervisorLockPayload(ownerId, acquiredAt, ttlMs), + )}\n`, + "utf8", + ); +} + +async function safeUnlinkOwnedSupervisorLock(lockPath, ownerId) { + const payload = await readSupervisorLockPayload(lockPath); + if ( + payload && + typeof payload.ownerId === "string" && + payload.ownerId.length > 0 && + payload.ownerId !== ownerId + ) { + return false; + } + return safeUnlink(lockPath); +} + +function createSupervisorLockHeartbeat(lockPath, ownerId, acquiredAt, ttlMs, signal) { + const refreshMs = Math.max(25, Math.floor(ttlMs / 3)); + let stopped = false; + let pendingRefresh = Promise.resolve(); + const refresh = () => { + if (stopped || signal?.aborted) { + return; + } + pendingRefresh = pendingRefresh.then(async () => { + const payload = await readSupervisorLockPayload(lockPath); + if (!payload) { + stopped = true; + return; + } + if ( + typeof payload.ownerId === "string" && + payload.ownerId.length > 0 && + payload.ownerId !== ownerId + ) { + stopped = true; + return; + } + try { + await writeSupervisorLockPayload(lockPath, ownerId, acquiredAt, ttlMs); + } catch (error) { + supervisorDebug( + `failed to refresh supervisor lock lease at ${lockPath}: ${ + error instanceof Error ? error.message : String(error) + }`, + ); + } + }); + }; + const timer = setInterval(refresh, refreshMs); + if (typeof timer.unref === "function") { + timer.unref(); + } + return { + stop: async () => { + stopped = true; + clearInterval(timer); + await pendingRefresh; + }, + }; +} + async function isSupervisorLockStale(lockPath, ttlMs) { const now = Date.now(); const payload = await readSupervisorLockPayload(lockPath); @@ -491,23 +571,33 @@ async function withSupervisorStorageLock(runtime, fn, signal) { try { const handle = await fs.open(lockPath, "wx"); + const acquiredAt = Date.now(); + const ownerId = `${process.pid}:${acquiredAt}:${Math.random() + .toString(36) + .slice(2)}`; try { await handle.writeFile( - `${JSON.stringify({ - pid: process.pid, - acquiredAt: Date.now(), - expiresAt: Date.now() + ttlMs, - })}\n`, + `${JSON.stringify( + createSupervisorLockPayload(ownerId, acquiredAt, ttlMs), + )}\n`, "utf8", ); } finally { await handle.close(); } + const heartbeat = createSupervisorLockHeartbeat( + lockPath, + ownerId, + acquiredAt, + ttlMs, + signal, + ); try { return await fn(); } finally { - await safeUnlink(lockPath); + await heartbeat.stop(); + await safeUnlinkOwnedSupervisorLock(lockPath, ownerId); } } catch (error) { const code = @@ -1073,6 +1163,17 @@ async function ensureLaunchableAccount( if (signal?.aborted || error?.name === "AbortError") { throw error; } + if (error?.name === "QuotaProbeUnavailableError") { + return { + account, + snapshot: null, + evaluation: { + rotate: true, + reason: "probe-unavailable", + waitMs: 0, + }, + }; + } return { account, snapshot: null, @@ -1100,6 +1201,7 @@ async function ensureLaunchableAccount( const step = await withLockedManager(runtime, async (manager) => { let dirty = false; const knownAccounts = getManagerAccounts(manager, initial.accounts); + const probeUnavailableAccounts = []; for (const result of evaluatedResults) { const account = resolveAccountInManager( manager, @@ -1110,7 +1212,10 @@ async function ensureLaunchableAccount( getProbeCandidateBatch( manager, 1, - options.excludedAccounts ?? [], + [ + ...(options.excludedAccounts ?? []), + ...probeUnavailableAccounts, + ], )[0] ?? null; if ( !account || @@ -1143,6 +1248,11 @@ async function ensureLaunchableAccount( }; } + if (result.evaluation.reason === "probe-unavailable") { + probeUnavailableAccounts.push(account); + continue; + } + markAccountUnavailable(manager, account, result.evaluation); dirty = true; } @@ -1205,10 +1315,10 @@ async function prepareResumeSelection({ runtime, pluginConfig, currentAccount, + // Reserved for future restart-specific account-skip hints. restartDecision, signal, }) { - void restartDecision; const startedAtMs = Date.now(); const nextReady = await ensureLaunchableAccount( runtime, @@ -1255,7 +1365,16 @@ function maybeStartPreparedResumeSelection({ currentAccount, restartDecision, signal, - }).catch(() => null), + }).catch((error) => { + if (error?.name !== "AbortError" && !signal?.aborted) { + supervisorDebug( + `pre-warm selection failed: ${ + error instanceof Error ? error.message : String(error) + }`, + ); + } + return null; + }), }; } @@ -1532,7 +1651,6 @@ async function loadCurrentSupervisorState(runtime, signal) { async function runInteractiveSupervision({ codexBin, initialArgs, - buildForwardArgs, runtime, pluginConfig, manager, @@ -1766,6 +1884,7 @@ async function runInteractiveSupervision({ relaunchNotice( `monitor loop failed: ${monitorFailure instanceof Error ? monitorFailure.message : String(monitorFailure)}`, ); + return result.exitCode === 0 ? 1 : result.exitCode; } binding = binding ?? @@ -1882,7 +2001,7 @@ async function runInteractiveSupervision({ manager = nextReady.manager ?? manager; rotationTrace.resumeReadyAtMs = Date.now(); logRotationSummary(restartDecision.sessionId, rotationTrace, nextReady); - launchArgs = buildResumeArgs(restartDecision.sessionId, buildForwardArgs); + launchArgs = buildResumeArgs(restartDecision.sessionId, launchArgs); knownSessionId = restartDecision.sessionId; knownRolloutPath = binding?.rolloutPath ?? knownRolloutPath; } finally { @@ -1931,7 +2050,6 @@ async function runCodexSupervisorWithRuntime({ return runInteractiveSupervision({ codexBin, initialArgs, - buildForwardArgs, runtime, pluginConfig, manager: ready.manager, diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 3efced76..9a6bcd82 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -1001,6 +1001,79 @@ describe("codex supervisor", () => { expect(manager.activeIndex).toBe(1); }); + it("preserves caller CLI options when rebuilding resume args after rotation", async () => { + class FakeChild extends EventEmitter { + exitCode: number | null = null; + + constructor(exitCode: number) { + super(); + setTimeout(() => { + this.exitCode = exitCode; + this.emit("exit", exitCode, null); + }, 0); + } + + kill(_signal: string) { + return true; + } + } + + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager); + const spawnedArgs: string[][] = []; + const exitCodes = [1, 0]; + + const result = await supervisorTestApi?.runInteractiveSupervision({ + codexBin: "dist/bin/codex.js", + initialArgs: [ + "-c", + 'profile="dev"', + "resume", + "seed-session", + "-c", + 'cli_auth_credentials_store="file"', + ], + buildForwardArgs: (rawArgs: string[]) => [...rawArgs], + runtime, + pluginConfig: {}, + manager, + signal: undefined, + maxSessionRestarts: 2, + spawnChild: (_codexBin: string, args: string[]) => { + spawnedArgs.push([...args]); + return new FakeChild(exitCodes.shift() ?? 0); + }, + findBinding: async ({ sessionId }: { sessionId?: string }) => + sessionId + ? { + sessionId, + rolloutPath: null, + lastActivityAtMs: Date.now(), + } + : null, + }); + + expect(result).toBe(0); + expect(spawnedArgs).toEqual([ + [ + "-c", + 'profile="dev"', + "resume", + "seed-session", + "-c", + 'cli_auth_credentials_store="file"', + ], + [ + "-c", + 'profile="dev"', + "resume", + "seed-session", + "-c", + 'cli_auth_credentials_store="file"', + ], + ]); + }); + it("starts degraded candidate probes in the same batch before waiting on results", async () => { const manager = new FakeManager([ { accountId: "degraded-1", access: "token-1" }, @@ -1097,6 +1170,59 @@ describe("codex supervisor", () => { expect(loadFromDisk).not.toHaveBeenCalled(); }); + it.each([ + ["--help"], + ["--version"], + ])( + "bypasses supervisor account gating for top-level %s flags before account selection", + async (flag) => { + const loadFromDisk = vi.fn(async () => { + throw new Error("ensureLaunchableAccount should not run for top-level help/version"); + }); + const forwardToRealCodex = vi.fn(async () => 0); + + await expect( + supervisorTestApi?.runCodexSupervisorWithRuntime({ + codexBin: "dist/bin/codex.js", + rawArgs: [flag], + buildForwardArgs: (rawArgs: string[]) => [...rawArgs], + forwardToRealCodex, + runtime: { + loadPluginConfig: () => ({ codexCliSessionSupervisor: true }), + getCodexCliSessionSupervisor: () => true, + AccountManager: { loadFromDisk }, + }, + signal: undefined, + }), + ).resolves.toBe(0); + expect(forwardToRealCodex).toHaveBeenCalledWith("dist/bin/codex.js", [flag]); + expect(loadFromDisk).not.toHaveBeenCalled(); + }, + ); + + it("does not bypass supervisor account gating for nested version flags after --", async () => { + const loadFromDisk = vi.fn(async () => { + throw new Error("ensureLaunchableAccount reached"); + }); + const forwardToRealCodex = vi.fn(async () => 0); + + await expect( + supervisorTestApi?.runCodexSupervisorWithRuntime({ + codexBin: "dist/bin/codex.js", + rawArgs: ["exec", "--", "--version"], + buildForwardArgs: (rawArgs: string[]) => [...rawArgs], + forwardToRealCodex, + runtime: { + loadPluginConfig: () => ({ codexCliSessionSupervisor: true }), + getCodexCliSessionSupervisor: () => true, + AccountManager: { loadFromDisk }, + }, + signal: undefined, + }), + ).rejects.toThrow("ensureLaunchableAccount reached"); + expect(forwardToRealCodex).not.toHaveBeenCalled(); + }); + it( "returns 1 when interactive supervision is already at the restart safety limit", async () => { @@ -1147,8 +1273,52 @@ describe("codex supervisor", () => { } }); + it("renews the supervisor storage lock while a critical section is still running", async () => { + process.env.CODEX_AUTH_CLI_SESSION_LOCK_TTL_MS = "40"; + process.env.CODEX_AUTH_CLI_SESSION_LOCK_POLL_MS = "5"; + process.env.CODEX_AUTH_CLI_SESSION_LOCK_WAIT_MS = "500"; + + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager); + const firstEntered = createDeferred(); + const releaseFirst = createDeferred(); + let firstReleased = false; + let secondEntered = false; + + const first = supervisorTestApi?.withLockedManager( + runtime, + async () => { + firstEntered.resolve(); + await releaseFirst.promise; + firstReleased = true; + return "first"; + }, + undefined, + ); + await firstEntered.promise; + + const second = supervisorTestApi?.withLockedManager( + runtime, + async () => { + secondEntered = true; + expect(firstReleased).toBe(true); + return "second"; + }, + undefined, + ); + + await new Promise((resolve) => setTimeout(resolve, 140)); + expect(secondEntered).toBe(false); + + releaseFirst.resolve(); + await expect(Promise.all([first, second])).resolves.toEqual([ + "first", + "second", + ]); + }); + it( - "keeps the child exit code when the monitor loop fails after startup", + "returns a failure exit code when the monitor loop fails after startup", { timeout: 10_000 }, async () => { class FakeChild extends EventEmitter { @@ -1194,7 +1364,7 @@ describe("codex supervisor", () => { }, }); - expect(result).toBe(0); + expect(result).toBe(1); expect(stderrSpy).toHaveBeenCalledWith( expect.stringContaining("monitor loop failed: Timed out waiting for supervisor storage lock"), ); @@ -1204,6 +1374,33 @@ describe("codex supervisor", () => { }, ); + it("does not cool down accounts when the quota probe is unavailable", async () => { + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager, { + onFetch(accountId) { + if (accountId === "near-limit") { + const error = new Error("quota probe unavailable"); + error.name = "QuotaProbeUnavailableError"; + throw error; + } + }, + }); + + const result = await supervisorTestApi?.ensureLaunchableAccount( + runtime, + {}, + undefined, + { probeTimeoutMs: 250 }, + ); + + expect(result).toMatchObject({ + ok: true, + account: { accountId: "healthy" }, + }); + expect(manager.getAccountByIndex(0)?.coolingDownUntil).toBe(0); + expect(manager.activeIndex).toBe(1); + }); + it( "paces repeated quota probe outages instead of hot-looping the monitor", { timeout: 10_000 }, diff --git a/test/storage.test.ts b/test/storage.test.ts index 86ffeda1..44c5d563 100644 --- a/test/storage.test.ts +++ b/test/storage.test.ts @@ -1005,6 +1005,44 @@ describe("storage", () => { expect(existsSync(exportPath)).toBe(false); }); + it("allows equivalent Windows-style storage paths during export from an active transaction", async () => { + const originalPlatform = process.platform; + Object.defineProperty(process, "platform", { + value: "win32", + configurable: true, + }); + + try { + await saveAccounts({ + version: 3, + activeIndex: 0, + accounts: [ + { + accountId: "acct-primary", + refreshToken: "refresh-primary", + addedAt: 1, + lastUsed: 2, + }, + ], + }); + + await expect( + withAccountStorageTransaction(async () => { + setStoragePathDirect(testStoragePath.toUpperCase()); + await exportAccounts(exportPath); + }), + ).resolves.toBeUndefined(); + + const exported = JSON.parse(await fs.readFile(exportPath, "utf-8")); + expect(exported.accounts[0].accountId).toBe("acct-primary"); + } finally { + Object.defineProperty(process, "platform", { + value: originalPlatform, + configurable: true, + }); + } + }); + it("reloads fresh storage after a transaction handler throws", async () => { await saveAccounts({ version: 3, @@ -1212,6 +1250,26 @@ describe("storage", () => { await exportAccounts(exportPath); const exported = JSON.parse(await fs.readFile(exportPath, "utf-8")); expect(exported.accounts[0].accountId).toBe("acct-after-combined-throw"); + await saveFlaggedAccounts({ + version: 1, + accounts: [ + { + accountId: "acct-flagged-after-combined-throw", + email: "flagged-after-combined-throw@example.com", + refreshToken: "refresh-flagged-after-combined-throw", + addedAt: 7, + lastUsed: 8, + flaggedAt: 9, + }, + ], + }); + const loadedFlagged = await loadFlaggedAccounts(); + expect(loadedFlagged.accounts[0]).toEqual( + expect.objectContaining({ + accountId: "acct-flagged-after-combined-throw", + refreshToken: "refresh-flagged-after-combined-throw", + }), + ); }); it("reloads fresh storage after a combined transaction handler returns successfully", async () => { @@ -1264,6 +1322,26 @@ describe("storage", () => { expect(exported.accounts[0].accountId).toBe( "acct-after-combined-success", ); + await saveFlaggedAccounts({ + version: 1, + accounts: [ + { + accountId: "acct-flagged-after-combined-success", + email: "flagged-after-combined-success@example.com", + refreshToken: "refresh-flagged-after-combined-success", + addedAt: 7, + lastUsed: 8, + flaggedAt: 9, + }, + ], + }); + const loadedFlagged = await loadFlaggedAccounts(); + expect(loadedFlagged.accounts[0]).toEqual( + expect.objectContaining({ + accountId: "acct-flagged-after-combined-success", + refreshToken: "refresh-flagged-after-combined-success", + }), + ); }); it("should fail import when file does not exist", async () => { From cde63b92192ade7472d5fbcb766100889412d258 Mon Sep 17 00:00:00 2001 From: ndycode Date: Sat, 21 Mar 2026 01:44:32 +0800 Subject: [PATCH 22/24] Fix supervisor review follow-ups --- scripts/codex-supervisor.js | 109 ++++++++++---- test/codex-supervisor.test.ts | 259 +++++++++++++++++++++++++++++++--- 2 files changed, 323 insertions(+), 45 deletions(-) diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index 5e47133a..f921152b 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -402,14 +402,23 @@ async function safeUnlink(path) { function getSupervisorStoragePath(runtime) { if (typeof runtime.getStoragePath === "function") { + let storagePath; try { - const storagePath = runtime.getStoragePath(); - if (typeof storagePath === "string" && storagePath.trim().length > 0) { - return storagePath; - } - } catch { - // Fall back to the default Codex home path. + storagePath = runtime.getStoragePath(); + } catch (error) { + throw new Error( + `Failed to resolve supervisor storage path via runtime.getStoragePath(): ${ + error instanceof Error ? error.message : String(error) + }`, + { cause: error }, + ); } + if (typeof storagePath !== "string" || storagePath.trim().length === 0) { + throw new Error( + "Failed to resolve supervisor storage path via runtime.getStoragePath(): received an empty path", + ); + } + return storagePath; } return join( @@ -471,7 +480,26 @@ async function safeUnlinkOwnedSupervisorLock(lockPath, ownerId) { function createSupervisorLockHeartbeat(lockPath, ownerId, acquiredAt, ttlMs, signal) { const refreshMs = Math.max(25, Math.floor(ttlMs / 3)); let stopped = false; + let failedError = null; + let settleHeartbeat; + let rejectHeartbeat; let pendingRefresh = Promise.resolve(); + const heartbeatPromise = new Promise((resolve, reject) => { + settleHeartbeat = resolve; + rejectHeartbeat = reject; + }); + let timer = null; + const stopWithError = (error) => { + if (failedError || stopped) { + return; + } + failedError = error; + stopped = true; + if (timer) { + clearInterval(timer); + } + rejectHeartbeat(error); + }; const refresh = () => { if (stopped || signal?.aborted) { return; @@ -479,7 +507,11 @@ function createSupervisorLockHeartbeat(lockPath, ownerId, acquiredAt, ttlMs, sig pendingRefresh = pendingRefresh.then(async () => { const payload = await readSupervisorLockPayload(lockPath); if (!payload) { - stopped = true; + stopWithError( + new Error( + `Supervisor lock heartbeat lost lease at ${lockPath} for owner ${ownerId}: lock file disappeared`, + ), + ); return; } if ( @@ -487,29 +519,41 @@ function createSupervisorLockHeartbeat(lockPath, ownerId, acquiredAt, ttlMs, sig payload.ownerId.length > 0 && payload.ownerId !== ownerId ) { - stopped = true; + stopWithError( + new Error( + `Supervisor lock heartbeat lost lease at ${lockPath} for owner ${ownerId}: observed owner ${payload.ownerId}`, + ), + ); return; } try { await writeSupervisorLockPayload(lockPath, ownerId, acquiredAt, ttlMs); } catch (error) { - supervisorDebug( - `failed to refresh supervisor lock lease at ${lockPath}: ${ - error instanceof Error ? error.message : String(error) - }`, + stopWithError( + new Error( + `Failed to refresh supervisor lock lease at ${lockPath} for owner ${ownerId}: ${ + error instanceof Error ? error.message : String(error) + }`, + { cause: error }, + ), ); } }); }; - const timer = setInterval(refresh, refreshMs); + timer = setInterval(refresh, refreshMs); if (typeof timer.unref === "function") { timer.unref(); } return { + promise: heartbeatPromise, stop: async () => { stopped = true; clearInterval(timer); + settleHeartbeat(); await pendingRefresh; + if (failedError) { + throw failedError; + } }, }; } @@ -594,7 +638,7 @@ async function withSupervisorStorageLock(runtime, fn, signal) { ); try { - return await fn(); + return await Promise.race([fn(), heartbeat.promise]); } finally { await heartbeat.stop(); await safeUnlinkOwnedSupervisorLock(lockPath, ownerId); @@ -1862,19 +1906,34 @@ async function runInteractiveSupervision({ } })(); - const result = await new Promise((resolve) => { - child.once("error", (error) => { - resolve({ - exitCode: 1, - error, + const result = await abortablePromise( + new Promise((resolve) => { + child.once("error", (error) => { + resolve({ + exitCode: 1, + error, + }); }); - }); - child.once("exit", (code, exitSignal) => { - resolve({ - exitCode: normalizeExitCode(code, exitSignal), - signal: exitSignal, + child.once("exit", (code, exitSignal) => { + resolve({ + exitCode: normalizeExitCode(code, exitSignal), + signal: exitSignal, + }); }); - }); + }), + signal, + "Supervisor child wait aborted", + ).catch(async (error) => { + if (error?.name !== "AbortError" || !signal?.aborted) { + throw error; + } + monitorActive = false; + monitorController.abort(); + await requestRestart(child, process.platform); + return { + exitCode: 130, + signal: "SIGTERM", + }; }); monitorActive = false; diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 9a6bcd82..2e38ba13 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -964,6 +964,84 @@ describe("codex supervisor", () => { expect(calls).toEqual([]); }); + it("commits the prepared account after the stored token refreshes before cutover", async () => { + process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "40"; + + class FakeChild extends EventEmitter { + exitCode: number | null = null; + kill = vi.fn((_signal: string) => { + setTimeout(() => { + this.exitCode = 0; + this.emit("exit", 0, null); + }, 0); + return true; + }); + } + + const calls: string[] = []; + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager, { + onFetch(accountId) { + calls.push(accountId); + }, + }); + + const prepared = await supervisorTestApi?.prepareResumeSelection({ + runtime, + pluginConfig: {}, + currentAccount: manager.getCurrentAccountForFamily(), + restartDecision: { + reason: "quota-near-exhaustion", + waitMs: 0, + sessionId: "prepared-session", + }, + signal: undefined, + }); + const stalePreparedAccount = prepared?.nextReady?.account + ? { ...prepared.nextReady.account } + : null; + expect(stalePreparedAccount).toMatchObject({ + accountId: "healthy", + refreshToken: "rt-healthy", + }); + expect(calls).toEqual(["healthy"]); + + await supervisorTestApi?.markCurrentAccountForRestart( + runtime, + manager.getCurrentAccountForFamily(), + { + reason: "quota-near-exhaustion", + waitMs: 0, + sessionId: "prepared-session", + }, + undefined, + ); + const refreshedStoredAccount = manager.getAccountByIndex(1); + expect(refreshedStoredAccount).not.toBeNull(); + if (!refreshedStoredAccount) { + return; + } + refreshedStoredAccount.refreshToken = "rt-healthy-refreshed"; + refreshedStoredAccount.access = "token-2-refreshed"; + await supervisorTestApi?.requestChildRestart(new FakeChild(), "win32"); + + const committed = await supervisorTestApi?.commitPreparedSelection( + runtime, + stalePreparedAccount, + undefined, + ); + + expect(committed).toMatchObject({ + ok: true, + account: { + accountId: "healthy", + refreshToken: "rt-healthy-refreshed", + access: "token-2-refreshed", + }, + }); + expect(calls).toEqual(["healthy"]); + }); + it("commits the prepared account only at cutover time", async () => { const manager = new FakeManager(); const runtime = createFakeRuntime(manager, { @@ -1250,6 +1328,54 @@ describe("codex supervisor", () => { }, ); + it( + "stops waiting on the child when the outer signal aborts", + { timeout: 10_000 }, + async () => { + process.env.CODEX_AUTH_CLI_SESSION_SIGNAL_TIMEOUT_MS = "10"; + + class HangingChild extends EventEmitter { + exitCode: number | null = null; + killSignals: string[] = []; + kill = vi.fn((signal: string) => { + this.killSignals.push(signal); + setTimeout(() => { + this.exitCode = 130; + this.emit("exit", 130, signal); + }, 0); + return true; + }); + } + + const manager = new FakeManager(); + const runtime = { + ...createFakeRuntime(manager), + getPreemptiveQuotaEnabled() { + return false; + }, + }; + const controller = new AbortController(); + const child = new HangingChild(); + const runPromise = supervisorTestApi?.runInteractiveSupervision({ + codexBin: "dist/bin/codex.js", + initialArgs: ["chat"], + buildForwardArgs: (rawArgs: string[]) => [...rawArgs], + runtime, + pluginConfig: {}, + manager, + signal: controller.signal, + maxSessionRestarts: 1, + spawnChild: () => child, + }); + + setTimeout(() => controller.abort(), 10); + + await expect(runPromise).resolves.toBe(130); + expect(child.kill).toHaveBeenCalled(); + expect(child.killSignals.length).toBeGreaterThan(0); + }, + ); + it("cleans up the parent abort listener for each linked abort controller", () => { const controller = new AbortController(); const addSpy = vi.spyOn(controller.signal, "addEventListener"); @@ -1273,6 +1399,45 @@ describe("codex supervisor", () => { } }); + it.each([ + [ + "throws", + () => { + throw new Error("boom"); + }, + /Failed to resolve supervisor storage path via runtime\.getStoragePath\(\): boom/, + ], + [ + "returns empty whitespace", + () => " ", + /Failed to resolve supervisor storage path via runtime\.getStoragePath\(\): received an empty path/, + ], + ])( + "does not fall back to the default Codex home lock path when runtime.getStoragePath %s", + async (_label, getStoragePath, expectedError) => { + const codexHome = createTempDir(); + process.env.CODEX_HOME = codexHome; + const loadFromDisk = vi.fn(async () => new FakeManager()); + const runtime = { + AccountManager: { loadFromDisk }, + getStoragePath, + }; + const defaultLockPath = join( + codexHome, + "multi-auth", + "openai-codex-accounts.json.supervisor.lock", + ); + + await expect( + supervisorTestApi?.withLockedManager(runtime, async () => "ok", undefined), + ).rejects.toThrow(expectedError); + expect(loadFromDisk).not.toHaveBeenCalled(); + await expect(fs.access(defaultLockPath)).rejects.toMatchObject({ + code: "ENOENT", + }); + }, + ); + it("renews the supervisor storage lock while a critical section is still running", async () => { process.env.CODEX_AUTH_CLI_SESSION_LOCK_TTL_MS = "40"; process.env.CODEX_AUTH_CLI_SESSION_LOCK_POLL_MS = "5"; @@ -1317,6 +1482,40 @@ describe("codex supervisor", () => { ]); }); + it( + "fails fast when the supervisor lock heartbeat loses the lease mid-section", + { timeout: 10_000 }, + async () => { + process.env.CODEX_AUTH_CLI_SESSION_LOCK_TTL_MS = "30"; + process.env.CODEX_AUTH_CLI_SESSION_LOCK_WAIT_MS = "200"; + + const manager = new FakeManager(); + const runtime = createFakeRuntime(manager); + const entered = createDeferred(); + const criticalSection = supervisorTestApi?.withLockedManager( + runtime, + async () => { + entered.resolve(); + await new Promise((resolve) => setTimeout(resolve, 1_000)); + return "held"; + }, + undefined, + ); + await entered.promise; + + const lockPath = supervisorTestApi?.getSupervisorStorageLockPath(runtime); + expect(lockPath).toBeTruthy(); + if (!lockPath) { + return; + } + await fs.unlink(lockPath); + + await expect(criticalSection).rejects.toThrow( + `Supervisor lock heartbeat lost lease at ${lockPath} for owner`, + ); + }, + ); + it( "returns a failure exit code when the monitor loop fails after startup", { timeout: 10_000 }, @@ -1405,53 +1604,73 @@ describe("codex supervisor", () => { "paces repeated quota probe outages instead of hot-looping the monitor", { timeout: 10_000 }, async () => { - vi.useFakeTimers(); - process.env.CODEX_AUTH_CLI_SESSION_SUPERVISOR_POLL_MS = "20"; + process.env.CODEX_AUTH_CLI_SESSION_SUPERVISOR_POLL_MS = "30"; - class FakeChild extends EventEmitter { + class HangingChild extends EventEmitter { exitCode: number | null = null; - - constructor(exitCode: number) { - super(); + kill = vi.fn((signal: string) => { setTimeout(() => { - this.exitCode = exitCode; - this.emit("exit", exitCode, null); - }, 60); - } - - kill(_signal: string) { + this.exitCode = 130; + this.emit("exit", 130, signal); + }, 0); return true; - } + }); } const manager = new FakeManager(); + const controller = new AbortController(); + let fetchAttempts = 0; const runtime = createFakeRuntime(manager, { onFetch(accountId) { if (accountId === "near-limit") { + fetchAttempts += 1; + if (fetchAttempts === 2) { + controller.abort(); + } throw new Error("quota endpoint unavailable"); } }, }); + const child = new HangingChild(); const runPromise = supervisorTestApi?.runInteractiveSupervision({ codexBin: "dist/bin/codex.js", - initialArgs: ["resume", "probe-unavailable-session"], + initialArgs: ["chat"], buildForwardArgs: (rawArgs: string[]) => [...rawArgs], runtime, pluginConfig: {}, manager, - signal: undefined, + signal: controller.signal, maxSessionRestarts: 1, - spawnChild: () => new FakeChild(0), - findBinding: async ({ sessionId }: { sessionId?: string }) => ({ - sessionId: sessionId ?? "probe-unavailable-session", + spawnChild: () => child, + loadCurrentState: async () => ({ + manager, + currentAccount: manager.getCurrentAccountForFamily(), + }), + waitForBinding: async () => ({ + sessionId: "probe-unavailable-session", rolloutPath: null, lastActivityAtMs: Date.now(), }), + refreshBinding: async (binding: { + sessionId: string; + rolloutPath: string | null; + lastActivityAtMs: number; + }) => binding, }); - await vi.advanceTimersByTimeAsync(100); - await expect(runPromise).resolves.toBe(0); + for (let attempt = 0; attempt < 20 && fetchAttempts === 0; attempt += 1) { + await new Promise((resolve) => setTimeout(resolve, 5)); + } + expect(fetchAttempts).toBe(1); + await new Promise((resolve) => setTimeout(resolve, 20)); + expect(fetchAttempts).toBe(1); + await expect(runPromise).rejects.toMatchObject({ + name: "AbortError", + message: "Supervisor storage lock wait aborted", + }); + expect(fetchAttempts).toBe(2); + expect(child.kill).toHaveBeenCalled(); }, ); From 0c7846d00033eb7d0ed52c85a420f966dbdf65b3 Mon Sep 17 00:00:00 2001 From: ndycode Date: Sat, 21 Mar 2026 02:17:00 +0800 Subject: [PATCH 23/24] fix supervisor lock review followups --- lib/config.ts | 2 +- lib/preemptive-quota-scheduler.ts | 2 +- scripts/codex-supervisor.js | 113 ++++++++++++++---------- test/codex-supervisor.test.ts | 30 ++++++- test/plugin-config.test.ts | 12 +-- test/preemptive-quota-scheduler.test.ts | 4 +- 6 files changed, 104 insertions(+), 59 deletions(-) diff --git a/lib/config.ts b/lib/config.ts index 9ad3a5b2..d4109906 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -1079,7 +1079,7 @@ export function getPreemptiveQuotaRemainingPercent5h(pluginConfig: PluginConfig) return resolveNumberSetting( "CODEX_AUTH_PREEMPTIVE_QUOTA_5H_REMAINING_PCT", pluginConfig.preemptiveQuotaRemainingPercent5h, - // Keep this fallback aligned with PreemptiveQuotaScheduler's intentional 10% 5h default. + // Keep this fallback aligned with PreemptiveQuotaScheduler's shared 5h default. DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H, { min: 0, max: 100 }, ); diff --git a/lib/preemptive-quota-scheduler.ts b/lib/preemptive-quota-scheduler.ts index 9fc8b6dc..ab82ec65 100644 --- a/lib/preemptive-quota-scheduler.ts +++ b/lib/preemptive-quota-scheduler.ts @@ -24,7 +24,7 @@ export interface QuotaSchedulerOptions { maxDeferralMs?: number; } -export const DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H = 10; +export const DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H = 5; // Intentionally keep the 7d window less aggressive than the 5h window. const DEFAULT_SECONDARY_REMAINING_PERCENT_THRESHOLD = 5; const DEFAULT_MAX_DEFERRAL_MS = 2 * 60 * 60_000; diff --git a/scripts/codex-supervisor.js b/scripts/codex-supervisor.js index f921152b..f5668071 100644 --- a/scripts/codex-supervisor.js +++ b/scripts/codex-supervisor.js @@ -81,6 +81,12 @@ function createProbeUnavailableError(error) { return wrapped; } +function throwIfAborted(signal, message = "Operation aborted") { + if (signal?.aborted) { + throw createAbortError(message); + } +} + function abortablePromise(promise, signal, message = "Operation aborted") { if (!signal) return promise; if (signal.aborted) { @@ -254,7 +260,7 @@ async function loadSupervisorRuntime() { ((pluginConfig) => pluginConfig.preemptiveQuotaEnabled !== false), getPreemptiveQuotaRemainingPercent5h: configModule.getPreemptiveQuotaRemainingPercent5h ?? - ((pluginConfig) => pluginConfig.preemptiveQuotaRemainingPercent5h ?? 10), + ((pluginConfig) => pluginConfig.preemptiveQuotaRemainingPercent5h ?? 5), getPreemptiveQuotaRemainingPercent7d: configModule.getPreemptiveQuotaRemainingPercent7d ?? ((pluginConfig) => pluginConfig.preemptiveQuotaRemainingPercent7d ?? 5), @@ -361,7 +367,7 @@ function getNearestWaitMs(manager) { return 0; } -async function persistActiveSelection(manager, account) { +async function persistActiveSelection(manager, account, signal) { if (typeof manager.setActiveIndex === "function") { manager.setActiveIndex(account.index); } @@ -369,6 +375,7 @@ async function persistActiveSelection(manager, account) { await manager.syncCodexCliActiveSelectionForIndex(account.index); } if (typeof manager.saveToDisk === "function") { + throwIfAborted(signal, "Supervisor storage lock lease lost"); await manager.saveToDisk(); } } @@ -637,12 +644,39 @@ async function withSupervisorStorageLock(runtime, fn, signal) { signal, ); + const lease = createLinkedAbortController(signal); + let heartbeatError = null; + heartbeat.promise.catch((error) => { + heartbeatError = heartbeatError ?? error; + if (!lease.controller.signal.aborted) { + lease.controller.abort(); + } + }); + let result; + let fnError = null; try { - return await Promise.race([fn(), heartbeat.promise]); + result = await fn(lease.controller.signal); + } catch (error) { + fnError = error; } finally { - await heartbeat.stop(); + lease.cleanup(); + try { + await heartbeat.stop(); + } catch (error) { + heartbeatError = heartbeatError ?? error; + } await safeUnlinkOwnedSupervisorLock(lockPath, ownerId); } + if (heartbeatError) { + if (fnError && fnError?.name !== "AbortError") { + throw fnError; + } + throw heartbeatError; + } + if (fnError) { + throw fnError; + } + return result; } catch (error) { const code = error && typeof error === "object" && "code" in error @@ -672,9 +706,11 @@ async function withSupervisorStorageLock(runtime, fn, signal) { } async function withLockedManager(runtime, mutate, signal) { - return withSupervisorStorageLock(runtime, async () => { + return withSupervisorStorageLock(runtime, async (lockSignal) => { + throwIfAborted(lockSignal, "Supervisor storage lock lease lost"); const manager = await runtime.AccountManager.loadFromDisk(); - return mutate(manager); + throwIfAborted(lockSignal, "Supervisor storage lock lease lost"); + return mutate(manager, lockSignal); }, signal); } @@ -1102,11 +1138,12 @@ async function markCurrentAccountForRestart( return null; } - return withLockedManager(runtime, async (freshManager) => { + return withLockedManager(runtime, async (freshManager, lockSignal) => { const targetAccount = resolveAccountInManager(freshManager, currentAccount); if (targetAccount) { markAccountUnavailable(freshManager, targetAccount, restartDecision); if (typeof freshManager.saveToDisk === "function") { + throwIfAborted(lockSignal, "Supervisor storage lock lease lost"); await freshManager.saveToDisk(); } } @@ -1128,51 +1165,32 @@ async function ensureLaunchableAccount( 1, ); let attempts = 0; - let managerHint = null; while (attempts < MAX_ACCOUNT_SELECTION_ATTEMPTS) { attempts += 1; if (signal?.aborted) { return { ok: false, account: null, aborted: true }; } - let initial = null; - if (managerHint) { - const hintedAccounts = getProbeCandidateBatch( - managerHint, + const initial = await withLockedManager(runtime, async (manager) => { + const accounts = getProbeCandidateBatch( + manager, probeBatchSize, options.excludedAccounts ?? [], ); - if (hintedAccounts.length > 0) { - initial = { - kind: "probe", - accounts: hintedAccounts, - }; - } - } - - if (!initial) { - initial = await withLockedManager(runtime, async (manager) => { - const accounts = getProbeCandidateBatch( - manager, - probeBatchSize, - options.excludedAccounts ?? [], - ); - if (accounts.length === 0) { - return { - kind: "wait", - waitMs: getNearestWaitMs(manager), - account: null, - }; - } + if (accounts.length === 0) { return { - kind: "probe", - accounts, + kind: "wait", + waitMs: getNearestWaitMs(manager), + account: null, }; - }, signal); - } + } + return { + kind: "probe", + accounts, + }; + }, signal); if (initial.kind === "wait") { - managerHint = null; if (initial.waitMs <= 0 || !runtime.getRetryAllAccountsRateLimited(pluginConfig)) { return { ok: false, account: null }; } @@ -1242,7 +1260,7 @@ async function ensureLaunchableAccount( throw error; } - const step = await withLockedManager(runtime, async (manager) => { + const step = await withLockedManager(runtime, async (manager, lockSignal) => { let dirty = false; const knownAccounts = getManagerAccounts(manager, initial.accounts); const probeUnavailableAccounts = []; @@ -1275,13 +1293,16 @@ async function ensureLaunchableAccount( kind: "retry", waitMs: 0, account: null, - manager, }; } if (!result.evaluation.rotate) { if (options.persistSelection !== false) { - await persistActiveSelection(manager, account); + await persistActiveSelection( + manager, + account, + lockSignal, + ); } return { kind: "ready", @@ -1301,13 +1322,13 @@ async function ensureLaunchableAccount( dirty = true; } if (dirty && typeof manager.saveToDisk === "function") { + throwIfAborted(lockSignal, "Supervisor storage lock lease lost"); await manager.saveToDisk(); } return { kind: "retry", waitMs: 0, account: null, - manager, }; }, signal); @@ -1317,8 +1338,6 @@ async function ensureLaunchableAccount( ...step, }; } - - managerHint = step.manager ?? null; } return { ok: false, account: null }; @@ -1329,7 +1348,7 @@ async function commitPreparedSelection(runtime, selectedAccount, signal) { return { ok: false, account: null }; } - return withLockedManager(runtime, async (manager) => { + return withLockedManager(runtime, async (manager, lockSignal) => { const knownAccounts = getManagerAccounts(manager, [selectedAccount]); const account = resolveAccountInManager(manager, selectedAccount, knownAccounts); const currentCandidate = getProbeCandidateBatch(manager, 1)[0] ?? null; @@ -1346,7 +1365,7 @@ async function commitPreparedSelection(runtime, selectedAccount, signal) { return { ok: false, account: null, manager }; } - await persistActiveSelection(manager, account); + await persistActiveSelection(manager, account, lockSignal); return { ok: true, account, diff --git a/test/codex-supervisor.test.ts b/test/codex-supervisor.test.ts index 2e38ba13..84c750de 100644 --- a/test/codex-supervisor.test.ts +++ b/test/codex-supervisor.test.ts @@ -1492,11 +1492,24 @@ describe("codex supervisor", () => { const manager = new FakeManager(); const runtime = createFakeRuntime(manager); const entered = createDeferred(); + const observedAbort = createDeferred(); + let firstExited = false; + let secondEntered = false; const criticalSection = supervisorTestApi?.withLockedManager( runtime, - async () => { + async (_freshManager, lockSignal) => { entered.resolve(); - await new Promise((resolve) => setTimeout(resolve, 1_000)); + await new Promise((resolve) => { + lockSignal?.addEventListener( + "abort", + () => { + observedAbort.resolve(); + resolve(); + }, + { once: true }, + ); + }); + firstExited = true; return "held"; }, undefined, @@ -1509,10 +1522,23 @@ describe("codex supervisor", () => { return; } await fs.unlink(lockPath); + await observedAbort.promise; + + const secondSection = supervisorTestApi?.withLockedManager( + runtime, + async () => { + secondEntered = true; + expect(firstExited).toBe(true); + return "second"; + }, + undefined, + ); await expect(criticalSection).rejects.toThrow( `Supervisor lock heartbeat lost lease at ${lockPath} for owner`, ); + await expect(secondSection).resolves.toBe("second"); + expect(secondEntered).toBe(true); }, ); diff --git a/test/plugin-config.test.ts b/test/plugin-config.test.ts index c293d76a..588d259b 100644 --- a/test/plugin-config.test.ts +++ b/test/plugin-config.test.ts @@ -138,7 +138,7 @@ describe('Plugin Configuration', () => { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 10, + preemptiveQuotaRemainingPercent5h: 5, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, codexCliSessionSupervisor: false, @@ -197,7 +197,7 @@ describe('Plugin Configuration', () => { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 10, + preemptiveQuotaRemainingPercent5h: 5, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, codexCliSessionSupervisor: false, @@ -453,7 +453,7 @@ describe('Plugin Configuration', () => { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 10, + preemptiveQuotaRemainingPercent5h: 5, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, codexCliSessionSupervisor: false, @@ -518,7 +518,7 @@ describe('Plugin Configuration', () => { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 10, + preemptiveQuotaRemainingPercent5h: 5, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, codexCliSessionSupervisor: false, @@ -577,7 +577,7 @@ describe('Plugin Configuration', () => { serverErrorCooldownMs: 4_000, storageBackupEnabled: true, preemptiveQuotaEnabled: true, - preemptiveQuotaRemainingPercent5h: 10, + preemptiveQuotaRemainingPercent5h: 5, preemptiveQuotaRemainingPercent7d: 5, preemptiveQuotaMaxDeferralMs: 2 * 60 * 60_000, codexCliSessionSupervisor: false, @@ -971,7 +971,7 @@ describe('Plugin Configuration', () => { describe('preemptive quota settings', () => { it('should use default thresholds', () => { expect(getPreemptiveQuotaEnabled({})).toBe(true); - expect(getPreemptiveQuotaRemainingPercent5h({})).toBe(10); + expect(getPreemptiveQuotaRemainingPercent5h({})).toBe(5); expect(getPreemptiveQuotaRemainingPercent7d({})).toBe(5); expect(getPreemptiveQuotaMaxDeferralMs({})).toBe(2 * 60 * 60_000); }); diff --git a/test/preemptive-quota-scheduler.test.ts b/test/preemptive-quota-scheduler.test.ts index c3856779..b4a12ecb 100644 --- a/test/preemptive-quota-scheduler.test.ts +++ b/test/preemptive-quota-scheduler.test.ts @@ -142,11 +142,11 @@ describe("preemptive quota scheduler", () => { expect(decision.reason).toBe("quota-near-exhaustion"); }); - it("defaults the primary remaining threshold to 10 percent", () => { + it("defaults the primary remaining threshold to 5 percent", () => { const scheduler = new PreemptiveQuotaScheduler(); scheduler.update("acc:model", { status: 200, - primary: { usedPercent: 91, resetAtMs: 65_000 }, + primary: { usedPercent: 96, resetAtMs: 65_000 }, secondary: {}, updatedAt: 1_000, }); From 70341ccbb0282ea78eef82fbad0b2e1f2a97839a Mon Sep 17 00:00:00 2001 From: ndycode Date: Sat, 21 Mar 2026 02:36:13 +0800 Subject: [PATCH 24/24] fix remaining review followups --- lib/codex-manager/settings-hub.ts | 7 ++++--- lib/preemptive-quota-scheduler.ts | 4 +++- package.json | 2 +- test/settings-hub-utils.test.ts | 20 ++++++++++++++++---- 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/lib/codex-manager/settings-hub.ts b/lib/codex-manager/settings-hub.ts index 13af6c62..e50a06d9 100644 --- a/lib/codex-manager/settings-hub.ts +++ b/lib/codex-manager/settings-hub.ts @@ -302,9 +302,10 @@ function getExperimentalSelectOptions( function mapExperimentalMenuHotkey( raw: string, ): ExperimentalSettingsAction | undefined { - if (raw === "1") return { type: "sync" }; - if (raw === "2") return { type: "backup" }; - if (raw === "3") return { type: "toggle-refresh-guardian" }; + if (raw === "1") return { type: "toggle-session-supervisor" }; + if (raw === "2") return { type: "sync" }; + if (raw === "3") return { type: "backup" }; + if (raw === "4") return { type: "toggle-refresh-guardian" }; if (raw === "[" || raw === "-") return { type: "decrease-refresh-interval" }; if (raw === "]" || raw === "+") return { type: "increase-refresh-interval" }; const lower = raw.toLowerCase(); diff --git a/lib/preemptive-quota-scheduler.ts b/lib/preemptive-quota-scheduler.ts index ab82ec65..02b66a54 100644 --- a/lib/preemptive-quota-scheduler.ts +++ b/lib/preemptive-quota-scheduler.ts @@ -25,7 +25,9 @@ export interface QuotaSchedulerOptions { } export const DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H = 5; -// Intentionally keep the 7d window less aggressive than the 5h window. +// Keep the 7d default separate so it can diverge from +// DEFAULT_PREEMPTIVE_QUOTA_REMAINING_PERCENT_5H without changing callers. +// It currently matches the 5h default. const DEFAULT_SECONDARY_REMAINING_PERCENT_THRESHOLD = 5; const DEFAULT_MAX_DEFERRAL_MS = 2 * 60 * 60_000; diff --git a/package.json b/package.json index bee82a7a..26850978 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "test:model-matrix": "node scripts/test-model-matrix.js", "test:model-matrix:smoke": "node scripts/test-model-matrix.js --smoke", "test:model-matrix:report": "node scripts/test-model-matrix.js --smoke --report-json=.tmp/model-matrix-report.json", - "test:session-supervisor:smoke": "vitest run test/codex-supervisor.test.ts test/codex-bin-wrapper.test.ts test/plugin-config.test.ts test/quota-probe.test.ts test/settings-hub-utils.test.ts", + "test:session-supervisor:smoke": "vitest run test/codex-supervisor.test.ts test/codex-bin-wrapper.test.ts test/plugin-config.test.ts test/quota-probe.test.ts test/settings-hub-utils.test.ts && vitest run test/storage.test.ts --testNamePattern=\"fails fast when export is called from an active transaction after the storage path changes|allows equivalent Windows-style storage paths during export from an active transaction|reloads fresh storage after a transaction handler throws|persists transaction updates to the original storage path after path drift|reloads fresh storage after a transaction handler returns successfully|reloads fresh storage after a combined transaction handler throws|reloads fresh storage after a combined transaction handler returns successfully\"", "clean:repo": "node scripts/repo-hygiene.js clean --mode aggressive", "clean:repo:check": "node scripts/repo-hygiene.js check", "bench:edit-formats": "node scripts/benchmark-edit-formats.mjs --preset=codex-core", diff --git a/test/settings-hub-utils.test.ts b/test/settings-hub-utils.test.ts index ccad9c2d..2bdb82b9 100644 --- a/test/settings-hub-utils.test.ts +++ b/test/settings-hub-utils.test.ts @@ -161,7 +161,13 @@ const originalCodeMultiAuthDir = process.env.CODEX_MULTI_AUTH_DIR; const originalConfigPath = process.env.CODEX_MULTI_AUTH_CONFIG_PATH; async function removeDirectoryWithRetry(dir: string): Promise { - const retryableCodes = new Set(["ENOTEMPTY", "EPERM", "EBUSY"]); + const retryableCodes = new Set([ + "ENOTEMPTY", + "EPERM", + "EBUSY", + "EACCES", + "EAGAIN", + ]); for (let attempt = 1; attempt <= 6; attempt += 1) { try { await fs.rm(dir, { recursive: true, force: true }); @@ -754,7 +760,7 @@ describe("settings-hub utility coverage", () => { it("supports experimental submenu hotkeys for guardian toggle and interval increase", async () => { const api = await loadSettingsHubTestApi(); queueSelectResults( - triggerSettingsHubHotkey("3"), + triggerSettingsHubHotkey("4"), triggerSettingsHubHotkey("]"), triggerSettingsHubHotkey("s"), ); @@ -782,8 +788,14 @@ describe("settings-hub utility coverage", () => { it("maps experimental menu and status hotkeys including numeric and uppercase variants", async () => { const api = await loadSettingsHubTestApi(); - expect(api.mapExperimentalMenuHotkey("1")).toEqual({ type: "sync" }); - expect(api.mapExperimentalMenuHotkey("2")).toEqual({ type: "backup" }); + expect(api.mapExperimentalMenuHotkey("1")).toEqual({ + type: "toggle-session-supervisor", + }); + expect(api.mapExperimentalMenuHotkey("2")).toEqual({ type: "sync" }); + expect(api.mapExperimentalMenuHotkey("3")).toEqual({ type: "backup" }); + expect(api.mapExperimentalMenuHotkey("4")).toEqual({ + type: "toggle-refresh-guardian", + }); expect(api.mapExperimentalMenuHotkey("[")).toEqual({ type: "decrease-refresh-interval", });