oc-auth-switcher 0.3.0 → 0.4.0
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 +10 -4
- package/dist/index.js +17 -8
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -171,8 +171,7 @@ function defaultState() {
|
|
|
171
171
|
authFailures: {}
|
|
172
172
|
};
|
|
173
173
|
}
|
|
174
|
-
function
|
|
175
|
-
const raw = safeReadJSON(STATE_FILE, {});
|
|
174
|
+
function normalizeState(raw) {
|
|
176
175
|
const defaults = defaultState();
|
|
177
176
|
const threshold = raw.config?.threshold;
|
|
178
177
|
const migratedThreshold = typeof threshold === "object" && threshold !== null ? {
|
|
@@ -206,6 +205,9 @@ function loadState() {
|
|
|
206
205
|
authFailures: raw.authFailures ?? defaults.authFailures
|
|
207
206
|
};
|
|
208
207
|
}
|
|
208
|
+
function loadState() {
|
|
209
|
+
return normalizeState(safeReadJSON(STATE_FILE, {}));
|
|
210
|
+
}
|
|
209
211
|
function saveState(state) {
|
|
210
212
|
safeWriteJSON(STATE_FILE, state);
|
|
211
213
|
}
|
|
@@ -649,8 +651,8 @@ ${BOLD}${CYAN}=== Auth Switcher Configuration ===${RESET}
|
|
|
649
651
|
const arg = args[i];
|
|
650
652
|
if (arg === "--threshold" && args[i + 1]) {
|
|
651
653
|
const val = parseFloat(args[++i]);
|
|
652
|
-
if (isNaN(val) || val
|
|
653
|
-
console.error(`${RED}Threshold must be
|
|
654
|
+
if (isNaN(val) || val <= 0 || val > 1) {
|
|
655
|
+
console.error(`${RED}Threshold must be greater than 0 and at most 1 (e.g., 0.90)${RESET}`);
|
|
654
656
|
process.exit(1);
|
|
655
657
|
}
|
|
656
658
|
state.config.threshold = val;
|
|
@@ -662,6 +664,10 @@ ${BOLD}${CYAN}=== Auth Switcher Configuration ===${RESET}
|
|
|
662
664
|
process.exit(1);
|
|
663
665
|
}
|
|
664
666
|
const normalized = parts.map((v) => v > 1 ? v / 100 : v);
|
|
667
|
+
if (normalized.some((v) => v <= 0 || v > 1)) {
|
|
668
|
+
console.error(`${RED}Thresholds must each be greater than 0 and at most 100%${RESET}`);
|
|
669
|
+
process.exit(1);
|
|
670
|
+
}
|
|
665
671
|
const currentFableThreshold = getThresholds(state.config).weekly7dFable;
|
|
666
672
|
state.config.threshold = {
|
|
667
673
|
session5h: normalized[0],
|
package/dist/index.js
CHANGED
|
@@ -539,8 +539,7 @@ function defaultState() {
|
|
|
539
539
|
authFailures: {}
|
|
540
540
|
};
|
|
541
541
|
}
|
|
542
|
-
function
|
|
543
|
-
const raw = safeReadJSON(STATE_FILE, {});
|
|
542
|
+
function normalizeState(raw) {
|
|
544
543
|
const defaults = defaultState();
|
|
545
544
|
const threshold = raw.config?.threshold;
|
|
546
545
|
const migratedThreshold = typeof threshold === "object" && threshold !== null ? {
|
|
@@ -574,6 +573,9 @@ function loadState() {
|
|
|
574
573
|
authFailures: raw.authFailures ?? defaults.authFailures
|
|
575
574
|
};
|
|
576
575
|
}
|
|
576
|
+
function loadState() {
|
|
577
|
+
return normalizeState(safeReadJSON(STATE_FILE, {}));
|
|
578
|
+
}
|
|
577
579
|
function saveState(state) {
|
|
578
580
|
safeWriteJSON(STATE_FILE, state);
|
|
579
581
|
}
|
|
@@ -711,7 +713,8 @@ function updateUsageFromHeaders(state, accountName, headers) {
|
|
|
711
713
|
usage.rejected = {
|
|
712
714
|
utilization: 1,
|
|
713
715
|
reset: Math.max(usage.rejected.reset, reset),
|
|
714
|
-
status: "rejected"
|
|
716
|
+
status: "rejected",
|
|
717
|
+
prefix
|
|
715
718
|
};
|
|
716
719
|
updated = true;
|
|
717
720
|
}
|
|
@@ -736,7 +739,7 @@ function isOverThreshold(usage, state) {
|
|
|
736
739
|
if (!usage)
|
|
737
740
|
return false;
|
|
738
741
|
const thresholds = getThresholds(state.config);
|
|
739
|
-
return usage.rejected.status?.toLowerCase() === "rejected" || usage.session5h.utilization
|
|
742
|
+
return usage.rejected.status?.toLowerCase() === "rejected" || thresholds.session5h > 0 && usage.session5h.utilization >= thresholds.session5h || thresholds.weekly7d > 0 && usage.weekly7d.utilization >= thresholds.weekly7d || thresholds.weekly7dSonnet > 0 && usage.weekly7dSonnet.utilization >= thresholds.weekly7dSonnet || thresholds.weekly7dFable > 0 && usage.weekly7dFable.utilization >= thresholds.weekly7dFable;
|
|
740
743
|
}
|
|
741
744
|
function getUtilizationScore(usage, state) {
|
|
742
745
|
if (!usage)
|
|
@@ -744,14 +747,20 @@ function getUtilizationScore(usage, state) {
|
|
|
744
747
|
const thresholds = getThresholds(state.config);
|
|
745
748
|
if (usage.rejected.status?.toLowerCase() === "rejected")
|
|
746
749
|
return Infinity;
|
|
747
|
-
|
|
750
|
+
const scores = [
|
|
751
|
+
{ util: usage.session5h.utilization, threshold: thresholds.session5h },
|
|
752
|
+
{ util: usage.weekly7d.utilization, threshold: thresholds.weekly7d },
|
|
753
|
+
{ util: usage.weekly7dSonnet.utilization, threshold: thresholds.weekly7dSonnet },
|
|
754
|
+
{ util: usage.weekly7dFable.utilization, threshold: thresholds.weekly7dFable }
|
|
755
|
+
].filter((metric) => metric.threshold > 0).map((metric) => metric.util / metric.threshold);
|
|
756
|
+
return scores.length > 0 ? Math.max(...scores) : 0;
|
|
748
757
|
}
|
|
749
758
|
function getExceededMetric(usage, state) {
|
|
750
759
|
if (!usage)
|
|
751
760
|
return null;
|
|
752
761
|
const thresholds = getThresholds(state.config);
|
|
753
762
|
if (usage.rejected.status?.toLowerCase() === "rejected") {
|
|
754
|
-
return "rejected rate limit";
|
|
763
|
+
return usage.rejected.prefix ? `rejected rate limit (${usage.rejected.prefix})` : "rejected rate limit";
|
|
755
764
|
}
|
|
756
765
|
const metrics = [
|
|
757
766
|
{ name: "session5h", util: usage.session5h.utilization, thresh: thresholds.session5h },
|
|
@@ -759,7 +768,7 @@ function getExceededMetric(usage, state) {
|
|
|
759
768
|
{ name: "weekly7dSonnet", util: usage.weekly7dSonnet.utilization, thresh: thresholds.weekly7dSonnet },
|
|
760
769
|
{ name: "weekly7dFable", util: usage.weekly7dFable.utilization, thresh: thresholds.weekly7dFable }
|
|
761
770
|
];
|
|
762
|
-
const exceeded = metrics.filter((m) => m.
|
|
771
|
+
const exceeded = metrics.filter((m) => m.thresh > 0 && m.util >= m.thresh).sort((a, b) => b.util / b.thresh - a.util / a.thresh);
|
|
763
772
|
return exceeded.length > 0 ? exceeded[0].name : null;
|
|
764
773
|
}
|
|
765
774
|
function getEarliestReset(usage) {
|
|
@@ -800,7 +809,7 @@ function findBestAvailable(candidates, state, exclude) {
|
|
|
800
809
|
if (isTemporarilyUnavailable(state, acct.name))
|
|
801
810
|
continue;
|
|
802
811
|
const score = getUtilizationScore(state.usage[acct.name], state);
|
|
803
|
-
if (score < bestScore) {
|
|
812
|
+
if (!best || score < bestScore) {
|
|
804
813
|
bestScore = score;
|
|
805
814
|
best = acct;
|
|
806
815
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oc-auth-switcher",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "OpenCode auth plugin for multi-account Anthropic Claude Max rotation with automatic failover.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build": "bun build src/index.ts --outdir dist --target node --format esm && bun build src/cli.ts --outdir dist --target bun --format esm",
|
|
12
12
|
"dev": "bun run build --watch",
|
|
13
|
+
"test": "bun test",
|
|
13
14
|
"prepublishOnly": "bun run build"
|
|
14
15
|
},
|
|
15
16
|
"peerDependencies": {
|