oc-auth-switcher 0.7.1 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +35 -18
- package/dist/index.js +26 -14
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -21,6 +21,14 @@ var METRIC_MODEL_FAMILY = {
|
|
|
21
21
|
weekly7dSonnet: "sonnet",
|
|
22
22
|
weekly7dFable: "fable"
|
|
23
23
|
};
|
|
24
|
+
var UNIFIED_RATE_LIMIT_PREFIX = "anthropic-ratelimit-unified-";
|
|
25
|
+
var QUOTA_WINDOW_SCOPE_PATTERN = /^\d+[hmd](?:_[a-z0-9.\-]+)?$/i;
|
|
26
|
+
function quotaWindowScope(prefix) {
|
|
27
|
+
if (!prefix)
|
|
28
|
+
return;
|
|
29
|
+
const scope = prefix.toLowerCase().startsWith(UNIFIED_RATE_LIMIT_PREFIX) ? prefix.slice(UNIFIED_RATE_LIMIT_PREFIX.length) : prefix;
|
|
30
|
+
return QUOTA_WINDOW_SCOPE_PATTERN.test(scope) ? scope : undefined;
|
|
31
|
+
}
|
|
24
32
|
|
|
25
33
|
// node_modules/@ex-machina/opencode-anthropic-auth/dist/constants.js
|
|
26
34
|
var CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
|
|
@@ -217,17 +225,20 @@ function normalizeState(raw) {
|
|
|
217
225
|
weekly7dSonnet: threshold.weekly7dSonnet ?? DEFAULT_THRESHOLD,
|
|
218
226
|
weekly7dFable: threshold.weekly7dFable ?? DEFAULT_THRESHOLD
|
|
219
227
|
} : threshold ?? defaults.config.threshold;
|
|
220
|
-
const usage = Object.fromEntries(Object.entries(raw.usage ?? {}).map(([name, accountUsage]) =>
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
228
|
+
const usage = Object.fromEntries(Object.entries(raw.usage ?? {}).map(([name, accountUsage]) => {
|
|
229
|
+
const rejected = { ...EMPTY_METRIC, ...accountUsage?.rejected };
|
|
230
|
+
return [
|
|
231
|
+
name,
|
|
232
|
+
{
|
|
233
|
+
session5h: { ...EMPTY_METRIC, ...accountUsage?.session5h },
|
|
234
|
+
weekly7d: { ...EMPTY_METRIC, ...accountUsage?.weekly7d },
|
|
235
|
+
weekly7dSonnet: { ...EMPTY_METRIC, ...accountUsage?.weekly7dSonnet },
|
|
236
|
+
weekly7dFable: { ...EMPTY_METRIC, ...accountUsage?.weekly7dFable },
|
|
237
|
+
rejected: rejected.status?.toLowerCase() === "rejected" && !quotaWindowScope(rejected.prefix) ? { ...EMPTY_METRIC } : rejected,
|
|
238
|
+
timestamp: accountUsage?.timestamp
|
|
239
|
+
}
|
|
240
|
+
];
|
|
241
|
+
}));
|
|
231
242
|
return {
|
|
232
243
|
currentAccount: raw.currentAccount ?? defaults.currentAccount,
|
|
233
244
|
requestCount: raw.requestCount ?? defaults.requestCount,
|
|
@@ -238,8 +249,8 @@ function normalizeState(raw) {
|
|
|
238
249
|
authFailures: raw.authFailures ?? defaults.authFailures
|
|
239
250
|
};
|
|
240
251
|
}
|
|
241
|
-
function loadState() {
|
|
242
|
-
return normalizeState(safeReadJSON(
|
|
252
|
+
function loadState(stateFile = STATE_FILE) {
|
|
253
|
+
return normalizeState(safeReadJSON(stateFile, {}));
|
|
243
254
|
}
|
|
244
255
|
function saveState(state) {
|
|
245
256
|
return safeWriteJSON(STATE_FILE, state);
|
|
@@ -461,6 +472,10 @@ function formatRelativeDuration(targetMs, nowMs = Date.now()) {
|
|
|
461
472
|
parts.push(`${Math.max(1, Math.round(remaining))}s`);
|
|
462
473
|
return difference >= 0 ? `in ${parts.join(" ")}` : `${parts.join(" ")} ago`;
|
|
463
474
|
}
|
|
475
|
+
function formatResetTime(reset, nowMs = Date.now()) {
|
|
476
|
+
const resetMs = reset * 1000;
|
|
477
|
+
return `${new Date(resetMs).toLocaleString()} (${formatRelativeDuration(resetMs, nowMs)})`;
|
|
478
|
+
}
|
|
464
479
|
function displayRejectionPrefix(prefix) {
|
|
465
480
|
return prefix?.replace(/^anthropic-ratelimit-unified-/i, "");
|
|
466
481
|
}
|
|
@@ -865,8 +880,9 @@ ${BOLD}${CYAN}=== Auth Switcher Usage Dashboard ===${RESET}
|
|
|
865
880
|
}
|
|
866
881
|
for (const account of data.accounts) {
|
|
867
882
|
const usage = state.usage[account.name];
|
|
883
|
+
const now = Date.now();
|
|
868
884
|
const isActive = account.name === state.currentAccount;
|
|
869
|
-
const isCooling = !!state.authFailures[account.name] && state.authFailures[account.name] >
|
|
885
|
+
const isCooling = !!state.authFailures[account.name] && state.authFailures[account.name] > now;
|
|
870
886
|
const tag = isActive ? `${GREEN} [ACTIVE]${RESET}` : isCooling ? `${RED} [COOLDOWN]${RESET}` : "";
|
|
871
887
|
console.log(` ${BOLD}${account.name}${RESET}${tag}`);
|
|
872
888
|
if (usage) {
|
|
@@ -874,8 +890,10 @@ ${BOLD}${CYAN}=== Auth Switcher Usage Dashboard ===${RESET}
|
|
|
874
890
|
console.log(` 7d weekly: ${progressBar(usage.weekly7d.utilization, thresholds.weekly7d)}`);
|
|
875
891
|
console.log(` 7d sonnet: ${progressBar(usage.weekly7dSonnet.utilization, thresholds.weekly7dSonnet)}`);
|
|
876
892
|
console.log(` 7d fable: ${progressBar(usage.weekly7dFable.utilization, thresholds.weekly7dFable)}`);
|
|
877
|
-
|
|
878
|
-
|
|
893
|
+
const rejection = deriveAccountHealth(account, usage, thresholds, state.authFailures[account.name], now).reasons.find((reason) => reason.kind === "rejection");
|
|
894
|
+
if (rejection) {
|
|
895
|
+
const reset = rejection.reset ? ` \u2014 resets ${formatResetTime(rejection.reset, now)}` : "";
|
|
896
|
+
console.log(` ${RED}Rate limit status: ${rejection.message}${reset}${RESET}`);
|
|
879
897
|
}
|
|
880
898
|
if (usage.timestamp) {
|
|
881
899
|
console.log(` ${DIM}Last updated: ${usage.timestamp}${RESET}`);
|
|
@@ -1067,8 +1085,7 @@ ${BOLD}${CYAN}=== Auth Switcher Status ===${RESET}
|
|
|
1067
1085
|
console.log(` ${RED}Reason: ${reason.message}${RESET}`);
|
|
1068
1086
|
}
|
|
1069
1087
|
if (health.earliestReset) {
|
|
1070
|
-
|
|
1071
|
-
console.log(` Reset: ${new Date(resetMs).toLocaleString()} (${formatRelativeDuration(resetMs, now)})`);
|
|
1088
|
+
console.log(` Reset: ${formatResetTime(health.earliestReset, now)}`);
|
|
1072
1089
|
}
|
|
1073
1090
|
const tokenColor = health.reasons.some((reason) => reason.kind === "token") ? RED : DIM;
|
|
1074
1091
|
console.log(` ${tokenColor}Token: ${health.tokenExpiry}${RESET}`);
|
package/dist/index.js
CHANGED
|
@@ -423,6 +423,14 @@ var METRIC_MODEL_FAMILY = {
|
|
|
423
423
|
weekly7dSonnet: "sonnet",
|
|
424
424
|
weekly7dFable: "fable"
|
|
425
425
|
};
|
|
426
|
+
var UNIFIED_RATE_LIMIT_PREFIX = "anthropic-ratelimit-unified-";
|
|
427
|
+
var QUOTA_WINDOW_SCOPE_PATTERN = /^\d+[hmd](?:_[a-z0-9.\-]+)?$/i;
|
|
428
|
+
function quotaWindowScope(prefix) {
|
|
429
|
+
if (!prefix)
|
|
430
|
+
return;
|
|
431
|
+
const scope = prefix.toLowerCase().startsWith(UNIFIED_RATE_LIMIT_PREFIX) ? prefix.slice(UNIFIED_RATE_LIMIT_PREFIX.length) : prefix;
|
|
432
|
+
return QUOTA_WINDOW_SCOPE_PATTERN.test(scope) ? scope : undefined;
|
|
433
|
+
}
|
|
426
434
|
|
|
427
435
|
// src/accounts.ts
|
|
428
436
|
function normalizeAccount(raw) {
|
|
@@ -585,17 +593,20 @@ function normalizeState(raw) {
|
|
|
585
593
|
weekly7dSonnet: threshold.weekly7dSonnet ?? DEFAULT_THRESHOLD,
|
|
586
594
|
weekly7dFable: threshold.weekly7dFable ?? DEFAULT_THRESHOLD
|
|
587
595
|
} : threshold ?? defaults.config.threshold;
|
|
588
|
-
const usage = Object.fromEntries(Object.entries(raw.usage ?? {}).map(([name, accountUsage]) =>
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
596
|
+
const usage = Object.fromEntries(Object.entries(raw.usage ?? {}).map(([name, accountUsage]) => {
|
|
597
|
+
const rejected = { ...EMPTY_METRIC, ...accountUsage?.rejected };
|
|
598
|
+
return [
|
|
599
|
+
name,
|
|
600
|
+
{
|
|
601
|
+
session5h: { ...EMPTY_METRIC, ...accountUsage?.session5h },
|
|
602
|
+
weekly7d: { ...EMPTY_METRIC, ...accountUsage?.weekly7d },
|
|
603
|
+
weekly7dSonnet: { ...EMPTY_METRIC, ...accountUsage?.weekly7dSonnet },
|
|
604
|
+
weekly7dFable: { ...EMPTY_METRIC, ...accountUsage?.weekly7dFable },
|
|
605
|
+
rejected: rejected.status?.toLowerCase() === "rejected" && !quotaWindowScope(rejected.prefix) ? { ...EMPTY_METRIC } : rejected,
|
|
606
|
+
timestamp: accountUsage?.timestamp
|
|
607
|
+
}
|
|
608
|
+
];
|
|
609
|
+
}));
|
|
599
610
|
return {
|
|
600
611
|
currentAccount: raw.currentAccount ?? defaults.currentAccount,
|
|
601
612
|
requestCount: raw.requestCount ?? defaults.requestCount,
|
|
@@ -606,8 +617,8 @@ function normalizeState(raw) {
|
|
|
606
617
|
authFailures: raw.authFailures ?? defaults.authFailures
|
|
607
618
|
};
|
|
608
619
|
}
|
|
609
|
-
function loadState() {
|
|
610
|
-
return normalizeState(safeReadJSON(
|
|
620
|
+
function loadState(stateFile = STATE_FILE) {
|
|
621
|
+
return normalizeState(safeReadJSON(stateFile, {}));
|
|
611
622
|
}
|
|
612
623
|
function saveState(state) {
|
|
613
624
|
return safeWriteJSON(STATE_FILE, state);
|
|
@@ -727,7 +738,8 @@ function updateUsageFromHeaders(state, accountName, headers) {
|
|
|
727
738
|
}
|
|
728
739
|
for (const [headerName, headerValue] of headers.entries()) {
|
|
729
740
|
const normalizedName = headerName.toLowerCase();
|
|
730
|
-
|
|
741
|
+
const statusMatch = normalizedName.match(/^anthropic-ratelimit-unified-(.+)-status$/);
|
|
742
|
+
if (!statusMatch || !quotaWindowScope(statusMatch[1]) || headerValue.toLowerCase() !== "rejected") {
|
|
731
743
|
continue;
|
|
732
744
|
}
|
|
733
745
|
const prefix = normalizedName.slice(0, -"-status".length);
|