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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tokenmaxxing",
3
- "version": "1.175.0",
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 moved = input.compacted
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 firstLine: string | null = null;
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
- log("supervisor.launch", { sid, respawns, seat: picked?.id.slice(0, 8) ?? null, key: key?.id, args: launchArgs.join(" "), injected: firstLine !== null });
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, ...launchArgs], {
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
- const prompt = resumable ? resumePrompt({ compacted, origin: m.origin, onKey: m.apiKeyId != null }) : null;
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, ...(relay === null && prompt !== null ? [prompt] : []), ...persistable];
882
+ launchArgs = [resumable ? "--resume" : "--session-id", m.sessionId, ...persistable];
878
883
  continue;
879
884
  }
880
885
  clearPresence({ dir: paths.presenceDir, id: sid });