claude-use 2.5.3 → 2.5.4

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 +51 -10
  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.5.4",
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>",
@@ -243749,6 +243749,7 @@ function resolveLayoutPaths() {
243749
243749
  var import_node_child_process2 = require("node:child_process");
243750
243750
  var import_node_crypto4 = require("node:crypto");
243751
243751
  var import_node_fs3 = __toESM(require("node:fs"), 1);
243752
+ var import_node_net = __toESM(require("node:net"), 1);
243752
243753
  var import_node_path13 = __toESM(require("node:path"), 1);
243753
243754
  var import_node_sea = require("node:sea");
243754
243755
 
@@ -243829,6 +243830,10 @@ var HeadroomStateSchema = external_exports.strictObject({
243829
243830
  headroomPid: external_exports.number().int().positive().optional(),
243830
243831
  /** 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
243832
  port: external_exports.number().int().positive().optional(),
243833
+ /**
243834
+ * 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.
243835
+ */
243836
+ lastPort: external_exports.number().int().positive().optional(),
243832
243837
  /** The `headroom --version` output of the running install. */
243833
243838
  version: external_exports.string().optional(),
243834
243839
  /** Hash of the allowlist the running proxy was started with, so a provider-file change is detected as drift. */
@@ -244153,6 +244158,21 @@ function spawnHeadroomSupervisor(paths) {
244153
244158
  import_node_fs3.default.closeSync(logFd);
244154
244159
  }
244155
244160
  }
244161
+ async function realIsPortFree(port) {
244162
+ return await new Promise((resolve) => {
244163
+ const server2 = import_node_net.default.createServer();
244164
+ server2.unref();
244165
+ server2.once("error", () => {
244166
+ resolve(false);
244167
+ });
244168
+ server2.once("close", () => {
244169
+ resolve(true);
244170
+ });
244171
+ server2.listen(port, "127.0.0.1", () => {
244172
+ server2.close();
244173
+ });
244174
+ });
244175
+ }
244156
244176
  function realHeadroomPort(paths) {
244157
244177
  return {
244158
244178
  ensure: () => {
@@ -247421,7 +247441,7 @@ function registerDoctorCommand(program2, paths) {
247421
247441
 
247422
247442
  // src/headroom/commands.ts
247423
247443
  var import_node_fs9 = __toESM(require("node:fs"), 1);
247424
- var import_node_net = __toESM(require("node:net"), 1);
247444
+ var import_node_net2 = __toESM(require("node:net"), 1);
247425
247445
  var import_node_child_process3 = require("node:child_process");
247426
247446
 
247427
247447
  // src/headroom/supervisor.ts
@@ -247523,14 +247543,18 @@ function compareVersions2(a2, b) {
247523
247543
  var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
247524
247544
  async function runSupervisor(config2, ports, options = {}) {
247525
247545
  const { fs: fs11, paths } = ports;
247546
+ const previousState = readHeadroomState(fs11, paths.headroomStateFile);
247547
+ let installedSource = previousState?.installedSource;
247548
+ let lastPort = previousState?.lastPort;
247526
247549
  const fail = (message) => {
247527
- writeHeadroomState(fs11, paths.headroomStateFile, { lastError: message });
247550
+ writeHeadroomState(fs11, paths.headroomStateFile, {
247551
+ lastError: message,
247552
+ ...lastPort === void 0 ? {} : { lastPort }
247553
+ });
247528
247554
  fs11.removeRecursive(paths.headroomLockFile);
247529
247555
  ports.log(`claude-use headroom supervisor: ${message}`);
247530
247556
  return 1;
247531
247557
  };
247532
- const previousState = readHeadroomState(fs11, paths.headroomStateFile);
247533
- let installedSource = previousState?.installedSource;
247534
247558
  const ensureInstalled = () => {
247535
247559
  const version3 = ports.headroomVersion();
247536
247560
  const versionOk = version3 !== void 0 && versionSatisfies(version3, config2.source);
@@ -247550,7 +247574,7 @@ async function runSupervisor(config2, ports, options = {}) {
247550
247574
  return fail(`could not install headroom from ${config2.source}: install failed (is uv installed and on PATH?)`);
247551
247575
  }
247552
247576
  const version2 = ports.headroomVersion() ?? "unknown";
247553
- writeHeadroomState(fs11, paths.headroomStateFile, { supervisorPid: ports.ownPid, version: version2, installedSource });
247577
+ writeHeadroomState(fs11, paths.headroomStateFile, { supervisorPid: ports.ownPid, version: version2, installedSource, ...lastPort === void 0 ? {} : { lastPort } });
247554
247578
  ports.log(`claude-use headroom supervisor ${String(ports.ownPid)}: managing headroom on allowlist [${allowlistOf(ports).join(", ")}]`);
247555
247579
  const orphanPid = previousState?.headroomPid;
247556
247580
  if (orphanPid !== void 0 && ports.isRunning(orphanPid)) {
@@ -247576,7 +247600,12 @@ async function runSupervisor(config2, ports, options = {}) {
247576
247600
  ports.log(`claude-use headroom supervisor: headroom pid ${String(headroomPid)} died`);
247577
247601
  headroomPid = void 0;
247578
247602
  runningHash = void 0;
247579
- writeHeadroomState(fs11, paths.headroomStateFile, { supervisorPid: ports.ownPid, version: version2, installedSource });
247603
+ writeHeadroomState(fs11, paths.headroomStateFile, {
247604
+ supervisorPid: ports.ownPid,
247605
+ version: version2,
247606
+ installedSource,
247607
+ ...lastPort === void 0 ? {} : { lastPort }
247608
+ });
247580
247609
  }
247581
247610
  if (consecutiveFailures >= HEADROOM_START_RETRY_BUDGET) {
247582
247611
  return fail(`headroom failed to become ready ${String(consecutiveFailures)} times in a row; giving up`);
@@ -247584,17 +247613,25 @@ async function runSupervisor(config2, ports, options = {}) {
247584
247613
  if (installedSource !== config2.source && !ensureInstalled()) {
247585
247614
  return fail(`could not install headroom from ${config2.source}: install failed (is uv installed and on PATH?)`);
247586
247615
  }
247587
- const port = await ports.freePort();
247616
+ const previousSticky = lastPort;
247617
+ const port = lastPort !== void 0 && await ports.isPortFree(lastPort) ? lastPort : await ports.freePort();
247588
247618
  const pid = ports.spawnHeadroom(port, allowlist);
247589
247619
  const ready = await waitUntilReady(ports, port);
247590
247620
  if (ready) {
247591
247621
  consecutiveFailures = 0;
247592
247622
  headroomPid = pid;
247593
247623
  runningHash = allowlistHash;
247624
+ lastPort = port;
247625
+ if (previousSticky !== void 0 && port !== previousSticky) {
247626
+ ports.log(
247627
+ `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)`
247628
+ );
247629
+ }
247594
247630
  writeHeadroomState(fs11, paths.headroomStateFile, {
247595
247631
  supervisorPid: ports.ownPid,
247596
247632
  headroomPid: pid,
247597
247633
  port,
247634
+ lastPort: port,
247598
247635
  version: version2,
247599
247636
  allowlistHash,
247600
247637
  installedSource: config2.source
@@ -247630,7 +247667,10 @@ async function runSupervisor(config2, ports, options = {}) {
247630
247667
  `claude-use headroom supervisor: no sessions for ${String(config2.idleShutdownMinutes)} minute(s); stopping headroom and exiting`
247631
247668
  );
247632
247669
  ports.stopProcess(headroomPid);
247633
- writeHeadroomState(fs11, paths.headroomStateFile, { version: version2 });
247670
+ writeHeadroomState(fs11, paths.headroomStateFile, {
247671
+ version: version2,
247672
+ ...lastPort === void 0 ? {} : { lastPort }
247673
+ });
247634
247674
  return 0;
247635
247675
  }
247636
247676
  } else {
@@ -247706,7 +247746,7 @@ function formatHeadroomStatus(status) {
247706
247746
  }
247707
247747
  async function realFreePort() {
247708
247748
  return await new Promise((resolve, reject) => {
247709
- const server2 = import_node_net.default.createServer();
247749
+ const server2 = import_node_net2.default.createServer();
247710
247750
  server2.unref();
247711
247751
  server2.on("error", reject);
247712
247752
  server2.listen(0, "127.0.0.1", () => {
@@ -247742,6 +247782,7 @@ function realSupervisorPorts(paths) {
247742
247782
  },
247743
247783
  isRunning: headroomPidRunning,
247744
247784
  freePort: realFreePort,
247785
+ isPortFree: realIsPortFree,
247745
247786
  spawnHeadroom: (port, allowlist) => {
247746
247787
  import_node_fs9.default.mkdirSync(paths.logsDir, { recursive: true });
247747
247788
  const logFd = import_node_fs9.default.openSync(paths.headroomLogPath, "a");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-use",
3
- "version": "2.5.3",
3
+ "version": "2.5.4",
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>",