tokenmaxxing 1.105.0 → 1.107.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.105.0",
3
+ "version": "1.107.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",
@@ -1,3 +1,5 @@
1
+ import { existsSync, readdirSync } from "node:fs";
2
+ import { basename, dirname, join } from "node:path";
1
3
  import { z } from "zod";
2
4
  import { claude } from "../lib/claude.ts";
3
5
  import { evaluateAndMaybeSwap } from "../lib/decide.ts";
@@ -20,10 +22,18 @@ const StopFailureStdin = z.looseObject({
20
22
  const ROW_WAIT_MS = 3_000;
21
23
  const ROW_POLL_MS = 200;
22
24
 
23
- async function awaitEnforcedRow(input: { transcriptPath: string; error: string; lastAssistantMessage: string | undefined }): Promise<TranscriptRow | null> {
25
+ function subagentTranscript(transcriptPath: string, agentId: string): string {
26
+ const dir = join(dirname(transcriptPath), basename(transcriptPath, ".jsonl"), "subagents");
27
+ const name = `agent-${agentId}.jsonl`;
28
+ const found = existsSync(dir) ? readdirSync(dir, { recursive: true, encoding: "utf8" }).find((p) => basename(p) === name) : undefined;
29
+ return join(dir, found ?? name);
30
+ }
31
+
32
+ async function awaitEnforcedRow(input: { transcriptPath: string; agentId: string | undefined; error: string; lastAssistantMessage: string | undefined }): Promise<TranscriptRow | null> {
24
33
  const deadline = Date.now() + ROW_WAIT_MS;
25
34
  while (true) {
26
- const row = findEnforcedRow({ rows: await readTranscriptTail(input.transcriptPath), error: input.error, lastAssistantMessage: input.lastAssistantMessage });
35
+ const path = input.agentId === undefined ? input.transcriptPath : subagentTranscript(input.transcriptPath, input.agentId);
36
+ const row = findEnforcedRow({ rows: await readTranscriptTail(path), error: input.error, lastAssistantMessage: input.lastAssistantMessage });
27
37
  if (row || Date.now() >= deadline) return row;
28
38
  await Bun.sleep(ROW_POLL_MS);
29
39
  }
@@ -52,7 +62,7 @@ export async function runStopFailureHook(): Promise<number> {
52
62
  const canRespawn = session != null && mainLoop;
53
63
  const cfg = loadConfig();
54
64
  const row = stdin.transcript_path
55
- ? await awaitEnforcedRow({ transcriptPath: stdin.transcript_path, error, lastAssistantMessage: stdin.last_assistant_message })
65
+ ? await awaitEnforcedRow({ transcriptPath: stdin.transcript_path, agentId: stdin.agent_id, error, lastAssistantMessage: stdin.last_assistant_message })
56
66
  : null;
57
67
  const limit = row ? classifyEnforcedLimit(row, cfg.policy.switchModels) : null;
58
68
 
@@ -17,7 +17,7 @@ import { countdownWait, exitStatus, loopGuardTripped, raceMarkerOrExit, recordPr
17
17
  import { saveTermios } from "../lib/tty.ts";
18
18
  import { liveSessionId, loadSessionFlags, pruneStaleSessions, saveSessionFlags, writeRespawnMarker } from "../lib/sessions.ts";
19
19
  import { loadAccounts, loadConfig, readJsonFile, releaseWaitClaim } from "../lib/state.ts";
20
- import { gatedFamilies, modelFromFlag } from "../lib/usage.ts";
20
+ import { gatedFamilies, modelFromFlag, scrubCredEnv } from "../lib/usage.ts";
21
21
  import { RespawnMarkerSchema, type Account, type Config, type ModelInfo } from "../lib/types.ts";
22
22
  import { errorMessage, log } from "../lib/log.ts";
23
23
 
@@ -439,13 +439,12 @@ export async function runSupervisor(argv: string[]): Promise<number> {
439
439
  stdout: "inherit",
440
440
  stderr: "inherit",
441
441
  env: {
442
- ...childEnv,
442
+ ...(picked ? { ...scrubCredEnv(childEnv), CLAUDE_SECURESTORAGE_CONFIG_DIR: storeDirFor(picked.id) } : childEnv),
443
443
  TOKENMAXXING_SUPERVISED: "1",
444
444
  TOKENMAXXING_SESSION_ID: sid,
445
445
  TOKENMAXXING_LAUNCHED_AT: String(gate.launchedAt),
446
446
  TOKENMAXXING_MODEL: effective.model ?? "",
447
447
  TOKENMAXXING_REFUSED: refused.join(","),
448
- ...(picked ? { CLAUDE_SECURESTORAGE_CONFIG_DIR: storeDirFor(picked.id) } : {}),
449
448
  },
450
449
  });
451
450
  child = spawned;
@@ -506,7 +505,7 @@ export async function runSupervisor(argv: string[]): Promise<number> {
506
505
  log("supervisor.compact_skipped", { sid: m.sessionId.slice(0, 8), seat: seat.id.slice(0, 8), until: walledUntil });
507
506
  } else if (m.compact && seat && resumable) {
508
507
  say(`\n\x1b[36m↻ tokenmaxxing: compacting the conversation on ${seat.label} before the move...\x1b[0m\n`, `tokenmaxxing: compacting the conversation on ${seat.label} before the move.`);
509
- const compactEnv = { ...omit(childEnv, ["TOKENMAXXING_SUPERVISED", "TOKENMAXXING_SESSION_ID", "TOKENMAXXING_LAUNCHED_AT", "TOKENMAXXING_MODEL", "TOKENMAXXING_REFUSED"]), TOKENMAXXING_PROBE: "1", CLAUDE_SECURESTORAGE_CONFIG_DIR: storeDirFor(seat.id) };
508
+ const compactEnv = { ...omit(scrubCredEnv(childEnv), ["TOKENMAXXING_SUPERVISED", "TOKENMAXXING_SESSION_ID", "TOKENMAXXING_LAUNCHED_AT", "TOKENMAXXING_MODEL", "TOKENMAXXING_REFUSED"]), TOKENMAXXING_PROBE: "1", CLAUDE_SECURESTORAGE_CONFIG_DIR: storeDirFor(seat.id) };
510
509
  const outcome = await compactClaudeSession({ real, sid: m.sessionId, transcript, env: compactEnv, onSpawn: (p) => { child = p; } });
511
510
  child = null;
512
511
  if (terminating) {
package/src/lib/claude.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { mkdirSync, readFileSync, rmSync } from "node:fs";
2
2
  import { join } from "node:path";
3
- import { countBy, omit } from "es-toolkit";
3
+ import { countBy } from "es-toolkit";
4
4
  import { z } from "zod";
5
5
  import { readItem, writeItem, deleteItem, isolatedTarget, readStore, storeTarget, claudeAiOauthOnly } from "./credstore.ts";
6
6
  import { CLAUDE_BIN, resolveRealBin, resolveVerifiedClaude } from "./claudebin.ts";
@@ -16,7 +16,7 @@ import { StoreUnusableError, type Observation, type Provider, type SampleReport
16
16
  import { foldTee, readyToSample, runSample, sampleAccountUsage, sampleDue, sampleIntervalMs, teeObservation, usageBlockedUntil } from "./sample.ts";
17
17
  import { clearUsageSnapshot, liveWaitClaims, loadAccounts, loadConfig, loadUsageSnapshot, pinBinOverride, readJsonFile, saveAccounts, type Harvest } from "./state.ts";
18
18
  import { saveTermios, restoreTermios } from "./tty.ts";
19
- import { CRED_ENV_OVERRIDES, fetchUsageDirect, gatedFamilies, mergeWindows, modelFromFlag, windowsOf } from "./usage.ts";
19
+ import { fetchUsageDirect, gatedFamilies, mergeWindows, modelFromFlag, scrubCredEnv, windowsOf } from "./usage.ts";
20
20
  import { CredentialBlobSchema, JsonTextSchema, OAuthAccountSchema, type Account, type Config, type ModelInfo } from "./types.ts";
21
21
  import { c } from "../cli/render.ts";
22
22
 
@@ -170,7 +170,7 @@ async function login(): Promise<Harvest | null> {
170
170
  const real = resolveRealBin(CLAUDE_BIN);
171
171
 
172
172
  const savedTermios = saveTermios();
173
- const env = { ...omit(process.env, CRED_ENV_OVERRIDES), CLAUDE_CONFIG_DIR: onboardDir, TOKENMAXXING_PROBE: "1", TOKENMAXXING_SUPERVISED: "" };
173
+ const env = { ...scrubCredEnv(process.env), CLAUDE_CONFIG_DIR: onboardDir, TOKENMAXXING_PROBE: "1", TOKENMAXXING_SUPERVISED: "" };
174
174
  const p = Bun.spawn([real], {
175
175
  stdin: "inherit",
176
176
  stdout: "inherit",
package/src/lib/sample.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import { mkdtempSync, rmSync } from "node:fs";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join } from "node:path";
4
- import { omit } from "es-toolkit";
5
4
  import { CLAUDE_BIN, MAX_WRAP_DEPTH, resolveRealBin, WRAP_DEPTH_ENV } from "./claudebin.ts";
6
5
  import { deleteItem, readStore, storeTarget } from "./credstore.ts";
7
6
  import { withLock } from "./lock.ts";
@@ -12,7 +11,7 @@ import { barFor, gatedWindows, landWindows, liveUsed, thresholdBars } from "./pi
12
11
  import { seatCounts } from "./presence.ts";
13
12
  import type { Observation } from "./provider.ts";
14
13
  import { loadAccounts, loadUsageSnapshot, saveAccounts } from "./state.ts";
15
- import { CRED_ENV_OVERRIDES, fetchUsageDirect, mergeWindows, windowsOf } from "./usage.ts";
14
+ import { fetchUsageDirect, mergeWindows, scrubCredEnv, windowsOf } from "./usage.ts";
16
15
  import type { Account, Config, Thresholds, UsageWindows, Window } from "./types.ts";
17
16
 
18
17
  export type SampleOutcome = { ok: true; usage: UsageWindows; via: "get" } | { ok: false; reason: string; retryAt?: number };
@@ -85,7 +84,7 @@ const REFRESH_KILL_MS = 60_000;
85
84
 
86
85
  async function refreshStore(account: Account): Promise<number | null> {
87
86
  const home = mkdtempSync(join(tmpdir(), "tokenmaxxing-refresh-"));
88
- const env = { ...omit(process.env, CRED_ENV_OVERRIDES), TOKENMAXXING_PROBE: "1", [WRAP_DEPTH_ENV]: String(MAX_WRAP_DEPTH), CLAUDE_CONFIG_DIR: home, CLAUDE_SECURESTORAGE_CONFIG_DIR: storeDirFor(account.id) };
87
+ const env = { ...scrubCredEnv(process.env), TOKENMAXXING_PROBE: "1", [WRAP_DEPTH_ENV]: String(MAX_WRAP_DEPTH), CLAUDE_CONFIG_DIR: home, CLAUDE_SECURESTORAGE_CONFIG_DIR: storeDirFor(account.id) };
89
88
  try {
90
89
  const p = Bun.spawn([resolveRealBin(CLAUDE_BIN), "-p", "/usage", "--no-session-persistence", "--safe-mode"], {
91
90
  env,
package/src/lib/usage.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { omit } from "es-toolkit";
1
2
  import { z } from "zod";
2
3
  import { http } from "./http.ts";
3
4
  import { errorMessage, log } from "./log.ts";
@@ -142,17 +143,28 @@ export function mergeWindows(next: Window[], prev: Window[]): Window[] {
142
143
  return [...next.filter((w) => w.name == null), ...rows];
143
144
  }
144
145
 
145
- export const CRED_ENV_OVERRIDES = [
146
+ const CRED_ENV_OVERRIDES = [
146
147
  "ANTHROPIC_API_KEY",
147
148
  "ANTHROPIC_AUTH_TOKEN",
148
149
  "CLAUDE_CODE_OAUTH_TOKEN",
150
+ "CLAUDE_CODE_OAUTH_TOKEN_FILE_DESCRIPTOR",
151
+ "CLAUDE_CODE_API_KEY_FILE_DESCRIPTOR",
149
152
  "CLAUDE_CODE_SUBSCRIPTION_TYPE",
150
153
  "CLAUDE_CODE_RATE_LIMIT_TIER",
151
154
  "CLAUDE_SECURESTORAGE_CONFIG_DIR",
152
155
  "CLAUDE_CODE_USE_BEDROCK",
153
156
  "CLAUDE_CODE_USE_VERTEX",
157
+ "CLAUDE_CODE_USE_FOUNDRY",
158
+ "CLAUDE_CODE_USE_MANTLE",
159
+ "CLAUDE_CODE_USE_ANTHROPIC_AWS",
160
+ "CLAUDE_CODE_USE_ANTHROPIC_GOOGLE_CLOUD",
154
161
  ] as const;
155
162
 
163
+ export function scrubCredEnv(env: Record<string, string | undefined>): Record<string, string | undefined> {
164
+ const overridden = CRED_ENV_OVERRIDES.some((k) => k !== "CLAUDE_SECURESTORAGE_CONFIG_DIR" && env[k]);
165
+ return omit(env, overridden ? [...CRED_ENV_OVERRIDES, "ANTHROPIC_BASE_URL"] : CRED_ENV_OVERRIDES);
166
+ }
167
+
156
168
  export const OAUTH_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
157
169
  const USAGE_URL = env("TOKENMAXXING_OAUTH_USAGE_URL", OAUTH_USAGE_URL);
158
170
  const USAGE_DEADLINE_MS = 10_000;