tokenmaxxing 1.128.0 → 1.130.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.128.0",
3
+ "version": "1.130.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",
@@ -7,7 +7,7 @@ import { codexPaths, codexPool } from "../lib/paths.ts";
7
7
  import { withLock } from "../lib/lock.ts";
8
8
  import { CODEX_BIN, UNMANAGED_ENV, WRAP_DEPTH_ENV, resolveRealBin, wrapDepth } from "../lib/claudebin.ts";
9
9
  import { codexStoreUsable, ensureCodexStoreHome } from "../lib/codexauth.ts";
10
- import { CODEX_SUPERVISOR_ID_ENV, borrowCodexSeat, codexPickCtx, pickCodexSeat } from "../lib/codex.ts";
10
+ import { CODEX_CRED_ENV, CODEX_SUPERVISOR_ID_ENV, borrowCodexSeat, codexPickCtx, pickCodexSeat } from "../lib/codex.ts";
11
11
  import { clearPresence, livingPresences } from "../lib/presence.ts";
12
12
  import { isExhausted } from "../lib/picker.ts";
13
13
  import { exitStatus, loopGuardTripped, raceMarkerOrExit, recordPresenceOrStop, runPassthrough } from "../lib/supervise.ts";
@@ -100,12 +100,11 @@ export async function runCodexSupervisor(input: { argv: string[] }): Promise<num
100
100
  });
101
101
  const granted = borrowsCodexSeat({ argv }) ? await borrowCodexSeat(process.pid) : undefined;
102
102
  const seat = granted && !("denied" in granted) ? granted : null;
103
- if (seat) passthroughEnv.CODEX_HOME = seat.store;
104
- else if (granted !== undefined) log("codexsupervisor.borrow_none", { reason: granted && "denied" in granted ? granted.denied : "no usable account" });
103
+ if (!seat && granted !== undefined) log("codexsupervisor.borrow_none", { reason: granted && "denied" in granted ? granted.denied : "no usable account" });
105
104
  return runPassthrough({
106
105
  real,
107
106
  argv,
108
- env: passthroughEnv,
107
+ env: seat ? { ...omit(passthroughEnv, CODEX_CRED_ENV), CODEX_HOME: seat.store } : passthroughEnv,
109
108
  onSpawn: (p) => {
110
109
  child = p;
111
110
  return seat
@@ -148,7 +147,7 @@ export async function runCodexSupervisor(input: { argv: string[] }): Promise<num
148
147
  stdout: "inherit",
149
148
  stderr: "inherit",
150
149
  env: {
151
- ...childEnv,
150
+ ...(store ? omit(childEnv, CODEX_CRED_ENV) : childEnv),
152
151
  [CODEX_SUPERVISOR_ID_ENV]: supervisorId,
153
152
  ...(store ? { CODEX_HOME: store } : {}),
154
153
  },
package/src/lib/codex.ts CHANGED
@@ -21,6 +21,7 @@ import type { Account, CodexAuthJson, CodexUsage, Config } from "./types.ts";
21
21
  import { c } from "../cli/render.ts";
22
22
 
23
23
  export const CODEX_SUPERVISOR_ID_ENV = "TOKENMAXXING_CODEX_SUPERVISOR_ID";
24
+ export const CODEX_CRED_ENV = ["CODEX_ACCESS_TOKEN", "CODEX_API_KEY"] as const;
24
25
 
25
26
  function liveId(): string | null {
26
27
  return codexSeatFromEnv(loadAccounts(codexPool).accounts.map((a) => a.id));
@@ -5,6 +5,7 @@ import { escape } from "es-toolkit";
5
5
  import { z } from "zod";
6
6
  import { codexPaths, codexStoreDirFor, HOME, optionalEnv, paths } from "./paths.ts";
7
7
  import { writeFileAtomic } from "./atomic.ts";
8
+ import { shellQuote } from "./proc.ts";
8
9
  import { installedBin, installSettings, isOurHookCommand, uninstallSettings } from "./settings.ts";
9
10
  import { CLAUDE_BIN, resolveRealBin } from "./claudebin.ts";
10
11
  import { loadConfig, readJsonFile, type BinKey } from "./state.ts";
@@ -84,7 +85,7 @@ export PATH
84
85
  if command -v tokenmaxxing >/dev/null 2>&1; then
85
86
  exec tokenmaxxing "$@"
86
87
  fi
87
- exec ${JSON.stringify(bun)} --no-env-file run ${JSON.stringify(entry)} "$@"
88
+ exec ${shellQuote(bun)} --no-env-file run ${shellQuote(entry)} "$@"
88
89
  `;
89
90
  }
90
91
 
@@ -94,15 +95,15 @@ function installEntryPoints(): string {
94
95
  if (isNixPackaged()) {
95
96
  writeFileAtomic(target, nixSupervisorShim(process.execPath, entry), 0o755);
96
97
  } else {
97
- writeFileAtomic(target, `#!/bin/sh\nexec ${JSON.stringify(process.execPath)} --no-env-file run ${JSON.stringify(entry)} "$@"\n`, 0o755);
98
+ writeFileAtomic(target, `#!/bin/sh\nexec ${shellQuote(process.execPath)} --no-env-file run ${shellQuote(entry)} "$@"\n`, 0o755);
98
99
  }
99
- writeFileAtomic(join(paths.binDir, "xx"), `#!/bin/sh\nexec ${JSON.stringify(target)} "$@"\n`, 0o755);
100
+ writeFileAtomic(join(paths.binDir, "xx"), `#!/bin/sh\nexec ${shellQuote(target)} "$@"\n`, 0o755);
100
101
  return target;
101
102
  }
102
103
 
103
104
  export function installSupervisor(): InstallOutcome {
104
105
  const target = installEntryPoints();
105
- writeFileAtomic(paths.supervisorLink, `#!/bin/sh\nexec ${JSON.stringify(target)} __supervise "$@"\n`, 0o755);
106
+ writeFileAtomic(paths.supervisorLink, `#!/bin/sh\nexec ${shellQuote(target)} __supervise "$@"\n`, 0o755);
106
107
 
107
108
  installSettings();
108
109
  const checkIntervalS = Math.ceil(loadConfig().policy.checkIntervalMs / 1000);
@@ -127,7 +128,7 @@ const CodexHooksFileSchema = z.looseObject({
127
128
  const CODEX_STOP_HOOK_SUBCOMMAND = "__codex-stop-hook";
128
129
 
129
130
  function codexStopHookCommand(): string {
130
- return `${JSON.stringify(installedBin())} ${CODEX_STOP_HOOK_SUBCOMMAND}`;
131
+ return `${shellQuote(installedBin())} ${CODEX_STOP_HOOK_SUBCOMMAND}`;
131
132
  }
132
133
 
133
134
  function withoutOurCodexStopHooks(groups: { hooks: { type?: string; command?: string }[] }[]): typeof groups {
@@ -200,7 +201,7 @@ export function codexSupervisorLink(): string {
200
201
  }
201
202
 
202
203
  export function installCodexSupervisor(): void {
203
- writeFileAtomic(codexSupervisorLink(), `#!/bin/sh\nexec ${JSON.stringify(installEntryPoints())} __supervise-codex "$@"\n`, 0o755);
204
+ writeFileAtomic(codexSupervisorLink(), `#!/bin/sh\nexec ${shellQuote(installEntryPoints())} __supervise-codex "$@"\n`, 0o755);
204
205
  installCodexStopHook();
205
206
  }
206
207
 
@@ -214,7 +215,7 @@ export function piSupervisorLink(): string {
214
215
  }
215
216
 
216
217
  export function installPiSupervisor(): void {
217
- writeFileAtomic(piSupervisorLink(), `#!/bin/sh\nexec ${JSON.stringify(installEntryPoints())} __supervise-pi "$@"\n`, 0o755);
218
+ writeFileAtomic(piSupervisorLink(), `#!/bin/sh\nexec ${shellQuote(installEntryPoints())} __supervise-pi "$@"\n`, 0o755);
218
219
  }
219
220
 
220
221
  export type UnitJob = {
package/src/lib/proc.ts CHANGED
@@ -1,6 +1,10 @@
1
1
  import { basename } from "node:path";
2
2
  import { ErrnoSchema } from "./types.ts";
3
3
 
4
+ export function shellQuote(s: string): string {
5
+ return `'${s.replaceAll("'", "'\\''")}'`;
6
+ }
7
+
4
8
  const SHELLS = new Set(["sh", "bash", "dash", "zsh", "ksh", "fish"]);
5
9
  const MAX_SHELL_HOPS = 4;
6
10
 
@@ -4,6 +4,7 @@ import { z } from "zod";
4
4
  import { paths } from "./paths.ts";
5
5
  import { writeFileAtomic } from "./atomic.ts";
6
6
  import { readJsonFile } from "./state.ts";
7
+ import { shellQuote } from "./proc.ts";
7
8
  import { JsonTextSchema } from "./types.ts";
8
9
  import { ENFORCED_ERRORS } from "./usage.ts";
9
10
 
@@ -55,7 +56,7 @@ function isOurCommand(cmd: string | undefined): boolean {
55
56
  }
56
57
 
57
58
  function ourCommand(sub: string): string {
58
- return `${JSON.stringify(installedBin())} ${sub}`;
59
+ return `${shellQuote(installedBin())} ${sub}`;
59
60
  }
60
61
 
61
62
  function ourHookGroup(sub: string, matcher?: string): HookGroup {
@@ -73,9 +74,13 @@ function appendHook(s: Settings, event: string, sub: string, matcher?: string):
73
74
  export function isOurHookCommand(cmd: string, sub: string): boolean {
74
75
  if (!cmd.endsWith(` ${sub}`)) return false;
75
76
  const quotedPath = cmd.slice(0, cmd.length - (sub.length + 1));
76
- if (!quotedPath.startsWith('"') || !quotedPath.endsWith('"')) return false;
77
- const parsed = z.string().safeParse(JsonTextSchema.safeParse(quotedPath).data);
78
- return parsed.success && parsed.data.endsWith("/tokenmaxxing");
77
+ const unquoted = quotedPath.slice(1, -1).replaceAll("'\\''", "'");
78
+ const path = quotedPath.startsWith("'")
79
+ ? shellQuote(unquoted) === quotedPath
80
+ ? unquoted
81
+ : undefined
82
+ : z.string().safeParse(JsonTextSchema.safeParse(quotedPath).data).data;
83
+ return path?.endsWith("/tokenmaxxing") === true;
79
84
  }
80
85
 
81
86
  function removeHook(s: Settings, event: string, sub: string): void {