diff --git a/src/cliproxy/account-safety.ts b/src/cliproxy/account-safety.ts index 351f78d0..8c9c2136 100644 --- a/src/cliproxy/account-safety.ts +++ b/src/cliproxy/account-safety.ts @@ -273,7 +273,8 @@ export function enforceProviderIsolation(provider: CLIProxyProvider): number { pauseAccount(p, accountId); } - // Record for crash recovery (re-read to reduce concurrent write race window) + // Record for crash recovery (re-read to reduce concurrent write race window). + // TOCTOU race is acceptable for a single-user CLI tool — self-heals on next launch. const freshData = loadAutoPaused(); freshData.sessions = freshData.sessions.filter((s) => s.initiator !== provider); freshData.sessions.push({ @@ -457,7 +458,7 @@ export async function handleQuotaExhaustion( writeQuotaExhausted(accountId, alternative.id, cooldownMinutes); return { switchedTo: alternative.id, - reason: `Quota exhausted, switched to ${alternative.id}`, + reason: `Quota exhausted, switched to ${maskEmail(alternative.id)}`, }; } diff --git a/src/cliproxy/executor/index.ts b/src/cliproxy/executor/index.ts index 08ec5be0..4f7d430d 100644 --- a/src/cliproxy/executor/index.ts +++ b/src/cliproxy/executor/index.ts @@ -521,6 +521,7 @@ export async function execClaudeWithCLIProxy( // No enforcement — still warn about duplicates for awareness warnCrossProviderDuplicates(provider); } else { + // 'exit' handlers must be synchronous — restoreAutoPausedAccounts uses sync fs APIs process.on('exit', () => { restoreAutoPausedAccounts(provider); }); diff --git a/tests/unit/cliproxy/account-safety-quota-exhaustion.test.ts b/tests/unit/cliproxy/account-safety-quota-exhaustion.test.ts index 7c84c8ec..855832e7 100644 --- a/tests/unit/cliproxy/account-safety-quota-exhaustion.test.ts +++ b/tests/unit/cliproxy/account-safety-quota-exhaustion.test.ts @@ -173,7 +173,7 @@ describe('Quota Exhaustion Handlers', () => { normal_interval_seconds: 300, critical_interval_seconds: 60, warn_threshold: 20, - exhaustion_threshold: 0, + exhaustion_threshold: 5, cooldown_minutes: 10, }, }); @@ -214,7 +214,7 @@ describe('Quota Exhaustion Handlers', () => { normal_interval_seconds: 300, critical_interval_seconds: 60, warn_threshold: 20, - exhaustion_threshold: 0, + exhaustion_threshold: 5, cooldown_minutes: 10, }, }); @@ -252,7 +252,7 @@ describe('Quota Exhaustion Handlers', () => { normal_interval_seconds: 300, critical_interval_seconds: 60, warn_threshold: 20, - exhaustion_threshold: 0, + exhaustion_threshold: 5, cooldown_minutes: 10, }, }); @@ -299,7 +299,7 @@ describe('Quota Exhaustion Handlers', () => { normal_interval_seconds: 300, critical_interval_seconds: 60, warn_threshold: 20, - exhaustion_threshold: 0, + exhaustion_threshold: 5, cooldown_minutes: 5, }, }); diff --git a/tests/unit/cliproxy/quota-monitor-runtime.test.ts b/tests/unit/cliproxy/quota-monitor-runtime.test.ts index 32d28b8f..9bb57284 100644 --- a/tests/unit/cliproxy/quota-monitor-runtime.test.ts +++ b/tests/unit/cliproxy/quota-monitor-runtime.test.ts @@ -59,7 +59,7 @@ describe('Runtime Quota Monitor', () => { normal_interval_seconds: 300, critical_interval_seconds: 60, warn_threshold: 20, - exhaustion_threshold: 0, + exhaustion_threshold: 5, cooldown_minutes: 5, }, }, @@ -92,7 +92,7 @@ describe('Runtime Quota Monitor', () => { normal_interval_seconds: 300, critical_interval_seconds: 60, warn_threshold: 20, - exhaustion_threshold: 0, + exhaustion_threshold: 5, cooldown_minutes: 5, }, }, @@ -118,7 +118,7 @@ describe('Runtime Quota Monitor', () => { normal_interval_seconds: 300, critical_interval_seconds: 60, warn_threshold: 20, - exhaustion_threshold: 0, + exhaustion_threshold: 5, cooldown_minutes: 5, }, }, @@ -161,7 +161,7 @@ describe('Runtime Quota Monitor', () => { normal_interval_seconds: 300, critical_interval_seconds: 60, warn_threshold: 20, - exhaustion_threshold: 0, + exhaustion_threshold: 5, cooldown_minutes: 5, }, },