claude-use 2.5.3 → 2.6.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.
Files changed (2) hide show
  1. package/dist/cli.cjs +62 -17
  2. package/package.json +1 -1
package/dist/cli.cjs CHANGED
@@ -221824,7 +221824,7 @@ var program = new Command();
221824
221824
  // package.json
221825
221825
  var package_default = {
221826
221826
  name: "claude-use",
221827
- version: "2.5.3",
221827
+ version: "2.6.0",
221828
221828
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
221829
221829
  license: "Apache-2.0",
221830
221830
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -241675,8 +241675,10 @@ var ProviderSchema = external_exports.strictObject({
241675
241675
  $schema: external_exports.string().optional(),
241676
241676
  displayName: external_exports.string().min(1),
241677
241677
  baseUrl: external_exports.url(),
241678
- tokenEnv: external_exports.string().min(1),
241678
+ tokenEnv: external_exports.string().min(1).optional(),
241679
241679
  env: external_exports.record(external_exports.string().min(1), external_exports.string()).optional()
241680
+ }).refine((provider) => provider.tokenEnv !== void 0 || (provider.env?.ANTHROPIC_AUTH_TOKEN ?? "") !== "", {
241681
+ message: "a provider needs either tokenEnv (the name of the environment variable holding its token) or a non-empty env.ANTHROPIC_AUTH_TOKEN"
241680
241682
  });
241681
241683
  var ConfigProfileSchema = external_exports.strictObject({
241682
241684
  $schema: external_exports.string().optional(),
@@ -243749,6 +243751,7 @@ function resolveLayoutPaths() {
243749
243751
  var import_node_child_process2 = require("node:child_process");
243750
243752
  var import_node_crypto4 = require("node:crypto");
243751
243753
  var import_node_fs3 = __toESM(require("node:fs"), 1);
243754
+ var import_node_net = __toESM(require("node:net"), 1);
243752
243755
  var import_node_path13 = __toESM(require("node:path"), 1);
243753
243756
  var import_node_sea = require("node:sea");
243754
243757
 
@@ -243829,6 +243832,10 @@ var HeadroomStateSchema = external_exports.strictObject({
243829
243832
  headroomPid: external_exports.number().int().positive().optional(),
243830
243833
  /** The loopback port the proxy listens on. Absent until the proxy has passed its readiness check, so "port is set" is itself the ready signal a launcher polls for. */
243831
243834
  port: external_exports.number().int().positive().optional(),
243835
+ /**
243836
+ * The sticky port preference: the address the daemon last served on, kept across crashes, restarts, and idle shutdowns so the next start reuses it. Distinct from `port` on purpose: `port` is the ready signal (absent whenever nothing is serving), while `lastPort` survives every shutdown, because every live session's environment was frozen at launch pointing at this address and a restart that moves strands them.
243837
+ */
243838
+ lastPort: external_exports.number().int().positive().optional(),
243832
243839
  /** The `headroom --version` output of the running install. */
243833
243840
  version: external_exports.string().optional(),
243834
243841
  /** Hash of the allowlist the running proxy was started with, so a provider-file change is detected as drift. */
@@ -244153,6 +244160,21 @@ function spawnHeadroomSupervisor(paths) {
244153
244160
  import_node_fs3.default.closeSync(logFd);
244154
244161
  }
244155
244162
  }
244163
+ async function realIsPortFree(port) {
244164
+ return await new Promise((resolve) => {
244165
+ const server2 = import_node_net.default.createServer();
244166
+ server2.unref();
244167
+ server2.once("error", () => {
244168
+ resolve(false);
244169
+ });
244170
+ server2.once("close", () => {
244171
+ resolve(true);
244172
+ });
244173
+ server2.listen(port, "127.0.0.1", () => {
244174
+ server2.close();
244175
+ });
244176
+ });
244177
+ }
244156
244178
  function realHeadroomPort(paths) {
244157
244179
  return {
244158
244180
  ensure: () => {
@@ -247421,7 +247443,7 @@ function registerDoctorCommand(program2, paths) {
247421
247443
 
247422
247444
  // src/headroom/commands.ts
247423
247445
  var import_node_fs9 = __toESM(require("node:fs"), 1);
247424
- var import_node_net = __toESM(require("node:net"), 1);
247446
+ var import_node_net2 = __toESM(require("node:net"), 1);
247425
247447
  var import_node_child_process3 = require("node:child_process");
247426
247448
 
247427
247449
  // src/headroom/supervisor.ts
@@ -247523,14 +247545,18 @@ function compareVersions2(a2, b) {
247523
247545
  var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
247524
247546
  async function runSupervisor(config2, ports, options = {}) {
247525
247547
  const { fs: fs11, paths } = ports;
247548
+ const previousState = readHeadroomState(fs11, paths.headroomStateFile);
247549
+ let installedSource = previousState?.installedSource;
247550
+ let lastPort = previousState?.lastPort;
247526
247551
  const fail = (message) => {
247527
- writeHeadroomState(fs11, paths.headroomStateFile, { lastError: message });
247552
+ writeHeadroomState(fs11, paths.headroomStateFile, {
247553
+ lastError: message,
247554
+ ...lastPort === void 0 ? {} : { lastPort }
247555
+ });
247528
247556
  fs11.removeRecursive(paths.headroomLockFile);
247529
247557
  ports.log(`claude-use headroom supervisor: ${message}`);
247530
247558
  return 1;
247531
247559
  };
247532
- const previousState = readHeadroomState(fs11, paths.headroomStateFile);
247533
- let installedSource = previousState?.installedSource;
247534
247560
  const ensureInstalled = () => {
247535
247561
  const version3 = ports.headroomVersion();
247536
247562
  const versionOk = version3 !== void 0 && versionSatisfies(version3, config2.source);
@@ -247550,7 +247576,7 @@ async function runSupervisor(config2, ports, options = {}) {
247550
247576
  return fail(`could not install headroom from ${config2.source}: install failed (is uv installed and on PATH?)`);
247551
247577
  }
247552
247578
  const version2 = ports.headroomVersion() ?? "unknown";
247553
- writeHeadroomState(fs11, paths.headroomStateFile, { supervisorPid: ports.ownPid, version: version2, installedSource });
247579
+ writeHeadroomState(fs11, paths.headroomStateFile, { supervisorPid: ports.ownPid, version: version2, installedSource, ...lastPort === void 0 ? {} : { lastPort } });
247554
247580
  ports.log(`claude-use headroom supervisor ${String(ports.ownPid)}: managing headroom on allowlist [${allowlistOf(ports).join(", ")}]`);
247555
247581
  const orphanPid = previousState?.headroomPid;
247556
247582
  if (orphanPid !== void 0 && ports.isRunning(orphanPid)) {
@@ -247576,7 +247602,12 @@ async function runSupervisor(config2, ports, options = {}) {
247576
247602
  ports.log(`claude-use headroom supervisor: headroom pid ${String(headroomPid)} died`);
247577
247603
  headroomPid = void 0;
247578
247604
  runningHash = void 0;
247579
- writeHeadroomState(fs11, paths.headroomStateFile, { supervisorPid: ports.ownPid, version: version2, installedSource });
247605
+ writeHeadroomState(fs11, paths.headroomStateFile, {
247606
+ supervisorPid: ports.ownPid,
247607
+ version: version2,
247608
+ installedSource,
247609
+ ...lastPort === void 0 ? {} : { lastPort }
247610
+ });
247580
247611
  }
247581
247612
  if (consecutiveFailures >= HEADROOM_START_RETRY_BUDGET) {
247582
247613
  return fail(`headroom failed to become ready ${String(consecutiveFailures)} times in a row; giving up`);
@@ -247584,17 +247615,25 @@ async function runSupervisor(config2, ports, options = {}) {
247584
247615
  if (installedSource !== config2.source && !ensureInstalled()) {
247585
247616
  return fail(`could not install headroom from ${config2.source}: install failed (is uv installed and on PATH?)`);
247586
247617
  }
247587
- const port = await ports.freePort();
247618
+ const previousSticky = lastPort;
247619
+ const port = lastPort !== void 0 && await ports.isPortFree(lastPort) ? lastPort : await ports.freePort();
247588
247620
  const pid = ports.spawnHeadroom(port, allowlist);
247589
247621
  const ready = await waitUntilReady(ports, port);
247590
247622
  if (ready) {
247591
247623
  consecutiveFailures = 0;
247592
247624
  headroomPid = pid;
247593
247625
  runningHash = allowlistHash;
247626
+ lastPort = port;
247627
+ if (previousSticky !== void 0 && port !== previousSticky) {
247628
+ ports.log(
247629
+ `claude-use headroom supervisor: sticky port ${String(previousSticky)} was occupied; moving to ${String(port)} (sessions launched against the old port are stale until they relaunch)`
247630
+ );
247631
+ }
247594
247632
  writeHeadroomState(fs11, paths.headroomStateFile, {
247595
247633
  supervisorPid: ports.ownPid,
247596
247634
  headroomPid: pid,
247597
247635
  port,
247636
+ lastPort: port,
247598
247637
  version: version2,
247599
247638
  allowlistHash,
247600
247639
  installedSource: config2.source
@@ -247630,7 +247669,10 @@ async function runSupervisor(config2, ports, options = {}) {
247630
247669
  `claude-use headroom supervisor: no sessions for ${String(config2.idleShutdownMinutes)} minute(s); stopping headroom and exiting`
247631
247670
  );
247632
247671
  ports.stopProcess(headroomPid);
247633
- writeHeadroomState(fs11, paths.headroomStateFile, { version: version2 });
247672
+ writeHeadroomState(fs11, paths.headroomStateFile, {
247673
+ version: version2,
247674
+ ...lastPort === void 0 ? {} : { lastPort }
247675
+ });
247634
247676
  return 0;
247635
247677
  }
247636
247678
  } else {
@@ -247706,7 +247748,7 @@ function formatHeadroomStatus(status) {
247706
247748
  }
247707
247749
  async function realFreePort() {
247708
247750
  return await new Promise((resolve, reject) => {
247709
- const server2 = import_node_net.default.createServer();
247751
+ const server2 = import_node_net2.default.createServer();
247710
247752
  server2.unref();
247711
247753
  server2.on("error", reject);
247712
247754
  server2.listen(0, "127.0.0.1", () => {
@@ -247742,6 +247784,7 @@ function realSupervisorPorts(paths) {
247742
247784
  },
247743
247785
  isRunning: headroomPidRunning,
247744
247786
  freePort: realFreePort,
247787
+ isPortFree: realIsPortFree,
247745
247788
  spawnHeadroom: (port, allowlist) => {
247746
247789
  import_node_fs9.default.mkdirSync(paths.logsDir, { recursive: true });
247747
247790
  const logFd = import_node_fs9.default.openSync(paths.headroomLogPath, "a");
@@ -247937,7 +247980,7 @@ function addProvider(paths, name, input2) {
247937
247980
  const parsed = ProviderSchema.safeParse({
247938
247981
  displayName: input2.displayName,
247939
247982
  baseUrl: input2.baseUrl,
247940
- tokenEnv: input2.tokenEnv,
247983
+ ...input2.tokenEnv === void 0 ? {} : { tokenEnv: input2.tokenEnv },
247941
247984
  ...input2.env === void 0 || Object.keys(input2.env).length === 0 ? {} : { env: input2.env }
247942
247985
  });
247943
247986
  if (!parsed.success) {
@@ -247976,12 +248019,12 @@ function resolveProvider(params) {
247976
248019
  message: `claude-use: no provider named "${name}". ` + (known.length > 0 ? `Known providers: ${known.join(", ")}.` : "No providers are defined yet; run `claude-use provider add`.")
247977
248020
  };
247978
248021
  }
247979
- const token = params.env[definition.tokenEnv];
248022
+ const token = definition.tokenEnv !== void 0 ? params.env[definition.tokenEnv] : definition.env?.ANTHROPIC_AUTH_TOKEN;
247980
248023
  if (token === void 0 || token === "") {
247981
248024
  return {
247982
248025
  ok: false,
247983
248026
  status: PROVIDER_MISSING_TOKEN_EXIT,
247984
- message: `claude-use: provider ${name} needs ${definition.tokenEnv} set in your environment`
248027
+ message: definition.tokenEnv !== void 0 ? `claude-use: provider ${name} needs ${definition.tokenEnv} set in your environment` : `claude-use: provider ${name} has no usable credential: its env.ANTHROPIC_AUTH_TOKEN is empty`
247985
248028
  };
247986
248029
  }
247987
248030
  return { ok: true, provider: { name, definition, token } };
@@ -248000,14 +248043,16 @@ function collectEnvPairs(value, previous = {}) {
248000
248043
  }
248001
248044
  function registerProviderCommand(program2, paths) {
248002
248045
  const provider = program2.command("provider").description("Manage API providers the launcher can route a session through.");
248003
- provider.command("add <name>").description("Create a new API provider definition.").requiredOption("--display-name <name>", "Human-readable name, exported to the child as CLAUDE_USE_PROVIDER.").requiredOption("--base-url <url>", "Anthropic-compatible base URL the child's requests are sent to.").requiredOption("--token-env <var>", "NAME of the environment variable holding the provider's token (never the token itself).").option("--env <pair>", "Extra KEY=VALUE environment entry for the child (repeatable).", collectEnvPairs).action((name, options) => {
248046
+ provider.command("add <name>").description("Create a new API provider definition.").requiredOption("--display-name <name>", "Human-readable name, exported to the child as CLAUDE_USE_PROVIDER.").requiredOption("--base-url <url>", "Anthropic-compatible base URL the child's requests are sent to.").option("--token-env <var>", "NAME of the environment variable holding the provider's token (never the token itself). Optional only when --env carries ANTHROPIC_AUTH_TOKEN (a local proxy's fixed dummy token).").option("--env <pair>", "Extra KEY=VALUE environment entry for the child (repeatable).", collectEnvPairs).action((name, options) => {
248004
248047
  addProvider(paths, name, {
248005
248048
  displayName: options.displayName,
248006
248049
  baseUrl: options.baseUrl,
248007
- tokenEnv: options.tokenEnv,
248050
+ ...options.tokenEnv === void 0 ? {} : { tokenEnv: options.tokenEnv },
248008
248051
  ...options.env === void 0 ? {} : { env: options.env }
248009
248052
  });
248010
- console.log(`Created provider "${name}" (${options.baseUrl}, token from ${options.tokenEnv}).`);
248053
+ console.log(
248054
+ options.tokenEnv === void 0 ? `Created provider "${name}" (${options.baseUrl}, fixed env credential).` : `Created provider "${name}" (${options.baseUrl}, token from ${options.tokenEnv}).`
248055
+ );
248011
248056
  });
248012
248057
  provider.command("list").description("List every API provider.").action(() => {
248013
248058
  const entries = listProviders(paths);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-use",
3
- "version": "2.5.3",
3
+ "version": "2.6.0",
4
4
  "description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Joseph Mearman <joseph@mearman.co.uk>",