tokenmaxxing 1.156.0 → 1.157.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/package.json +1 -1
- package/src/entries/pisupervisor.ts +7 -5
- package/src/lib/claude.ts +12 -15
- package/src/lib/pi.ts +5 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tokenmaxxing",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.157.0",
|
|
4
4
|
"description": "Automatic Claude Code account switching: pool multiple accounts, start each session on its own account, and resume a session on a fresher account when quota fills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -371,8 +371,10 @@ export async function runPiSupervisor(argv: string[]): Promise<number> {
|
|
|
371
371
|
const launched = await withLock(mover.pool.lockFile, async () => {
|
|
372
372
|
clearPresence({ dir: presenceDir, id });
|
|
373
373
|
if (terminating) return null;
|
|
374
|
-
const
|
|
375
|
-
|
|
374
|
+
const kept = validWanted(pool, wanted, id);
|
|
375
|
+
const target = kept ? { account: kept } : pickPiSeat(pool, launchedAt, model);
|
|
376
|
+
const picked = target?.account ?? null;
|
|
377
|
+
log("pisupervisor.launch", { id, pool, respawns, seat: picked?.id.slice(0, 8) ?? null, depletedUntil: target?.depletedUntil, args: launchArgs.join(" ") });
|
|
376
378
|
const spawned = Bun.spawn([real, ...launchArgs], {
|
|
377
379
|
stdin: "inherit",
|
|
378
380
|
stdout: "inherit",
|
|
@@ -398,21 +400,21 @@ export async function runPiSupervisor(argv: string[]): Promise<number> {
|
|
|
398
400
|
log("pisupervisor.claim_release_failed", { err: errorMessage(e) });
|
|
399
401
|
}
|
|
400
402
|
}
|
|
401
|
-
return { proc: spawned, seat: picked };
|
|
403
|
+
return { proc: spawned, seat: picked, overriddenUntil: Math.max(overriddenUntil, target?.depletedUntil ?? 0) };
|
|
402
404
|
});
|
|
403
405
|
if (launched == null) {
|
|
404
406
|
await releaseClaim();
|
|
405
407
|
return 143;
|
|
406
408
|
}
|
|
407
409
|
|
|
408
|
-
const { proc, seat } = launched;
|
|
410
|
+
const { proc, seat, overriddenUntil: gateUntil } = launched;
|
|
409
411
|
const pending: { move: SwapDecision | null; killed: boolean } = { move: null, killed: false };
|
|
410
412
|
let seatCheckAt = 0;
|
|
411
413
|
await raceMarkerOrExit({
|
|
412
414
|
child: proc,
|
|
413
415
|
tick: async () => {
|
|
414
416
|
if (!seat || terminating || Date.now() < seatCheckAt) return false;
|
|
415
|
-
const watched = await watchSeat({ pool, seatId: seat.id, id, families, overriddenUntil });
|
|
417
|
+
const watched = await watchSeat({ pool, seatId: seat.id, id, families, overriddenUntil: gateUntil });
|
|
416
418
|
seatCheckAt = Date.now() + (watched.decided ? SEAT_RETRY_MS : SEAT_POLL_MS);
|
|
417
419
|
pending.move = watched.move;
|
|
418
420
|
return watched.move !== null;
|
package/src/lib/claude.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { withLock } from "./lock.ts";
|
|
|
10
10
|
import { errorMessage, log } from "./log.ts";
|
|
11
11
|
import { claudeTierLabel, describeIdentity, fetchTokenIdentity, isDeadCredential, InvalidGrantError } from "./oauth.ts";
|
|
12
12
|
import { claudePool, env, paths, seatFromEnv, shortId, storeDirFor } from "./paths.ts";
|
|
13
|
-
import { MAX_WAITERS_PER_ACCOUNT, pickBest, pickEarliestReset, pickWaitTarget, thresholdBars, type
|
|
13
|
+
import { MAX_WAITERS_PER_ACCOUNT, pickBest, pickEarliestReset, pickWaitTarget, thresholdBars, type PickCtx } from "./picker.ts";
|
|
14
14
|
import { deletePiStore } from "./piauth.ts";
|
|
15
15
|
import { livingPresences, writePresence } from "./presence.ts";
|
|
16
16
|
import { StoreUnusableError, type Observation, type Provider, type ResetClaim, type SampleReport, type SeatBorrow } from "./provider.ts";
|
|
@@ -139,7 +139,9 @@ async function storeUsable(a: Account): Promise<boolean> {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
export type Seat = { account: Account; depletedUntil?: number };
|
|
143
|
+
|
|
144
|
+
export function pickSeat(now: number, model: ModelInfo | null, eligible: (a: Account) => boolean = () => true): Seat | null {
|
|
143
145
|
const cfg = loadConfig();
|
|
144
146
|
const bars = thresholdBars(cfg);
|
|
145
147
|
const idx = loadAccounts(claudePool);
|
|
@@ -149,27 +151,22 @@ function seatContext(now: number, model: ModelInfo | null, eligible: (a: Account
|
|
|
149
151
|
const seats = presence();
|
|
150
152
|
const ctx: PickCtx = { now, thresholds: bars, currentId: null, families: gatedFamilies(model, cfg.policy.switchModels), seats };
|
|
151
153
|
const candidates = idx.accounts.filter(eligible);
|
|
152
|
-
const
|
|
154
|
+
const best = pickBest(candidates, ctx);
|
|
155
|
+
if (best) return { account: best };
|
|
156
|
+
const wait =
|
|
153
157
|
pickWaitTarget(candidates, ctx, seats, MAX_WAITERS_PER_ACCOUNT, now + cfg.policy.maxWaitMs, now + 2 * cfg.policy.maxWaitMs) ??
|
|
154
158
|
pickEarliestReset(candidates, ctx);
|
|
155
|
-
return {
|
|
159
|
+
return wait ? { account: wait.account, depletedUntil: wait.availableAt } : null;
|
|
156
160
|
}
|
|
157
161
|
|
|
158
|
-
export
|
|
159
|
-
const { candidates, ctx, fallback } = seatContext(now, model, eligible);
|
|
160
|
-
return pickBest(candidates, ctx) ?? fallback()?.account ?? null;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
export type LaunchTarget = { account: Account; apiKey: null; depletedUntil?: number } | { account: null; apiKey: ApiKey };
|
|
162
|
+
export type LaunchTarget = (Seat & { apiKey: null }) | { account: null; apiKey: ApiKey };
|
|
164
163
|
|
|
165
164
|
export function pickLaunch(now: number, model: ModelInfo | null, refused: readonly string[] = []): LaunchTarget | null {
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
if (best) return { account: best, apiKey: null };
|
|
165
|
+
const seat = pickSeat(now, model, (a) => !refused.includes(a.id));
|
|
166
|
+
if (seat && seat.depletedUntil === undefined) return { ...seat, apiKey: null };
|
|
169
167
|
const key = launchApiKey();
|
|
170
168
|
if (key) return { account: null, apiKey: key };
|
|
171
|
-
|
|
172
|
-
return wait ? { account: wait.account, apiKey: null, depletedUntil: wait.availableAt } : null;
|
|
169
|
+
return seat ? { ...seat, apiKey: null } : null;
|
|
173
170
|
}
|
|
174
171
|
|
|
175
172
|
export async function borrowClaudeSeat(pid: number, named?: string): Promise<SeatBorrow | { invalid: string }> {
|
package/src/lib/pi.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { rmSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { claude, ensurePathAhead, pickSeat } from "./claude.ts";
|
|
3
|
+
import { claude, ensurePathAhead, pickSeat, type Seat } from "./claude.ts";
|
|
4
4
|
import { MAX_WRAP_DEPTH, PI_BIN, WRAP_DEPTH_ENV, resolveRealBin, verifyRealBin } from "./claudebin.ts";
|
|
5
5
|
import { codex, pickCodexSeat } from "./codex.ts";
|
|
6
6
|
import { codexSeatIdOf } from "./codexauth.ts";
|
|
@@ -111,9 +111,11 @@ function piMover(base: Provider, pool: PiPool): Provider {
|
|
|
111
111
|
|
|
112
112
|
export const piMovers: Record<PiPool, Provider> = { claude: piMover(claude, "claude"), codex: piMover(codex, "codex") };
|
|
113
113
|
|
|
114
|
-
export function pickPiSeat(pool: PiPool, now: number, model: ModelInfo | null):
|
|
114
|
+
export function pickPiSeat(pool: PiPool, now: number, model: ModelInfo | null): Seat | null {
|
|
115
115
|
const eligible = (a: Account) => piStoreUsable(pool, a.id);
|
|
116
|
-
|
|
116
|
+
if (pool === "claude") return pickSeat(now, model, eligible);
|
|
117
|
+
const account = pickCodexSeat(now, eligible);
|
|
118
|
+
return account ? { account } : null;
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
export function piPreflight(): void {
|