tokenmaxxing 1.175.0 → 1.176.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/supervisor.ts +15 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tokenmaxxing",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.176.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",
|
|
@@ -5,7 +5,7 @@ import { maxBy, omit } from "es-toolkit";
|
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { claudePool, paths, storeDirFor } from "../lib/paths.ts";
|
|
7
7
|
import { CLAUDE_BIN, UNMANAGED_ENV, WRAP_DEPTH_ENV, resolveRealBin, wrapDepth } from "../lib/claudebin.ts";
|
|
8
|
-
import { apiKeyEnv, clearSessionCost, foldCompactionCost, foldSessionCost, loadApiKeys, readApiKey, sendApiKey, usableApiKey, writeSessionCost } from "../lib/apikeys.ts";
|
|
8
|
+
import { apiKeyEnv, clearSessionCost, foldCompactionCost, foldSessionCost, isOpenRouterKey, loadApiKeys, readApiKey, sendApiKey, usableApiKey, writeSessionCost } from "../lib/apikeys.ts";
|
|
9
9
|
import { claude, pickLaunch, pickSeat, type LaunchTarget } from "../lib/claude.ts";
|
|
10
10
|
import { compactClaudeSession } from "../lib/compact.ts";
|
|
11
11
|
import { evaluateAndMaybeSwap, moveTarget } from "../lib/decide.ts";
|
|
@@ -366,11 +366,14 @@ function depletedLines(sid: string, until: number, text: string): string {
|
|
|
366
366
|
);
|
|
367
367
|
}
|
|
368
368
|
|
|
369
|
-
function resumePrompt(input: { compacted: boolean; origin: z.infer<typeof RespawnMarkerSchema>["origin"]; onKey: boolean }): string {
|
|
369
|
+
function resumePrompt(input: { compacted: boolean; origin: z.infer<typeof RespawnMarkerSchema>["origin"]; onKey: boolean; openRouter: boolean }): string {
|
|
370
370
|
const where = input.onKey ? "on an API key, because every pooled account is at its limit or the previous key ran out" : "on an account with quota headroom";
|
|
371
|
-
const
|
|
371
|
+
const resumed = input.compacted
|
|
372
372
|
? `tokenmaxxing compacted this conversation and resumed the session ${where}.`
|
|
373
373
|
: `tokenmaxxing resumed this session ${where}.`;
|
|
374
|
+
const moved = input.openRouter
|
|
375
|
+
? `${resumed} The session now runs on a base URL that is not an Anthropic host, so Claude Code has turned tool search off: every tool schema is already loaded and the ToolSearch tool does not exist in this session. Call tools directly.`
|
|
376
|
+
: resumed;
|
|
374
377
|
if (input.origin === "stop") {
|
|
375
378
|
return `${moved} The previous turn finished before the move. If it waited on the user or completed the task, end this turn without restating it. If it waited on a background Bash task, Monitor, or Workflow run, relaunch that work, because the move ended it.`;
|
|
376
379
|
}
|
|
@@ -715,7 +718,7 @@ export async function runSupervisor(argv: string[]): Promise<number> {
|
|
|
715
718
|
if (stream) process.stdout.write(systemLine(noticeSid, text));
|
|
716
719
|
else process.stderr.write(terminal);
|
|
717
720
|
};
|
|
718
|
-
let
|
|
721
|
+
let pendingResume: { compacted: boolean; origin: z.infer<typeof RespawnMarkerSchema>["origin"] } | null = null;
|
|
719
722
|
let respawns = 0;
|
|
720
723
|
let wanted: { accountId: string | null; apiKeyId: string | null } | null = null;
|
|
721
724
|
let refused: string[] = [];
|
|
@@ -741,13 +744,17 @@ export async function runSupervisor(argv: string[]): Promise<number> {
|
|
|
741
744
|
}
|
|
742
745
|
const picked = target?.account ?? null;
|
|
743
746
|
const key = target?.apiKey ?? null;
|
|
744
|
-
|
|
747
|
+
const prompt = pendingResume === null ? null : resumePrompt({ ...pendingResume, onKey: key != null, openRouter: key != null && isOpenRouterKey(key) });
|
|
748
|
+
pendingResume = null;
|
|
749
|
+
const args = relay === null && prompt !== null ? [...launchArgs.slice(0, 2), prompt, ...launchArgs.slice(2)] : launchArgs;
|
|
750
|
+
const firstLine = relay !== null && prompt !== null ? userLine(prompt) : null;
|
|
751
|
+
log("supervisor.launch", { sid, respawns, seat: picked?.id.slice(0, 8) ?? null, key: key?.id, args: args.join(" "), injected: firstLine !== null });
|
|
745
752
|
const open: OpenTasks = new Map();
|
|
746
753
|
const tee = stream && (picked || existsSync(claudePool.apiKeysJson)) ? seatTee(picked?.id ?? null, model, open, sid) : null;
|
|
747
754
|
const secret = key ? readApiKey(key) : null;
|
|
748
755
|
const extra: "pipe"[] = secret == null ? [] : ["pipe"];
|
|
749
756
|
const scrubbed = scrubCredEnv(childEnv);
|
|
750
|
-
const spawned = Bun.spawn([real, ...
|
|
757
|
+
const spawned = Bun.spawn([real, ...args], {
|
|
751
758
|
stdio: [relay === null ? "inherit" : "pipe", tee === null ? childStdout() : "pipe", "inherit", ...extra],
|
|
752
759
|
env: {
|
|
753
760
|
...(picked ? { ...scrubbed, CLAUDE_SECURESTORAGE_CONFIG_DIR: storeDirFor(picked.id) } : key ? apiKeyEnv(scrubbed, key) : childEnv),
|
|
@@ -763,7 +770,6 @@ export async function runSupervisor(argv: string[]): Promise<number> {
|
|
|
763
770
|
if (secret != null) sendApiKey(spawned, secret);
|
|
764
771
|
drainStdout = spawned.stdout instanceof ReadableStream ? relayStdout(spawned.stdout, tee ?? undefined) : null;
|
|
765
772
|
if (relay !== null) relay.attach(spawned.stdin!, firstLine, pendingTranscript);
|
|
766
|
-
firstLine = null;
|
|
767
773
|
if (picked || key) {
|
|
768
774
|
await recordPresenceOrStop({
|
|
769
775
|
child: spawned,
|
|
@@ -870,11 +876,10 @@ export async function runSupervisor(argv: string[]): Promise<number> {
|
|
|
870
876
|
wanted = depleted ? (key ? { accountId: null, apiKeyId: key.id } : null) : m.apiKeyId != null ? { accountId: null, apiKeyId: m.apiKeyId } : { accountId: m.accountId, apiKeyId: null };
|
|
871
877
|
refused = m.refused ?? refused;
|
|
872
878
|
saveSessionFlags(m.sessionId, persistable, process.cwd());
|
|
873
|
-
|
|
874
|
-
firstLine = relay !== null && prompt !== null ? userLine(prompt) : null;
|
|
879
|
+
pendingResume = resumable ? { compacted, origin: m.origin } : null;
|
|
875
880
|
pendingTranscript = resumable ? null : transcriptPath(m.sessionId);
|
|
876
881
|
if (!restored.has(m.sessionId)) restored.set(m.sessionId, resumable ? restoredCost(m.sessionId) : 0);
|
|
877
|
-
launchArgs = [resumable ? "--resume" : "--session-id", m.sessionId, ...
|
|
882
|
+
launchArgs = [resumable ? "--resume" : "--session-id", m.sessionId, ...persistable];
|
|
878
883
|
continue;
|
|
879
884
|
}
|
|
880
885
|
clearPresence({ dir: paths.presenceDir, id: sid });
|