claude-use 11.44.3 → 11.44.5

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/dist/cli.cjs CHANGED
@@ -34701,7 +34701,7 @@ var init_package = __esm({
34701
34701
  "package.json"() {
34702
34702
  package_default = {
34703
34703
  name: "claude-use",
34704
- version: "11.44.3",
34704
+ version: "11.44.5",
34705
34705
  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.",
34706
34706
  license: "MIT",
34707
34707
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -115419,7 +115419,7 @@ function collectCodexStatus(fsPort, paths, isRunning) {
115419
115419
  usageSnapshotPath: codexUsageSnapshotPath(),
115420
115420
  usageSnapshotExists: fsPort.readFileUtf8(codexUsageSnapshotPath()) !== void 0,
115421
115421
  logPath: paths.frontdoorLogPath,
115422
- logExists: fsPort.readFileUtf8(paths.frontdoorLogPath) !== void 0
115422
+ logExists: fsPort.lstat(paths.frontdoorLogPath) !== void 0
115423
115423
  };
115424
115424
  }
115425
115425
  function formatSignIn(signIn) {
@@ -119379,6 +119379,8 @@ function frontDoorRcControl(transport, token) {
119379
119379
  var HEALTH_TIMEOUT_MS = 2e3;
119380
119380
  var HEALTH_START_BUDGET_MS = 5e3;
119381
119381
  var HEALTH_RETRY_MS = 50;
119382
+ var PREFERRED_PORT_MAX_ATTEMPTS = 6;
119383
+ var PREFERRED_PORT_RETRY_MS = 50;
119382
119384
  function createFrontDoorServer(pipeline, log, tls2, control, apis) {
119383
119385
  const handler = (request7, response) => {
119384
119386
  if (request7.method === "GET" && request7.url === "/healthz") {
@@ -119474,16 +119476,25 @@ async function listenFrontDoor(server, options = {}) {
119474
119476
  resolve2(bound2);
119475
119477
  });
119476
119478
  });
119477
- let bound;
119478
- if (preferredPort !== void 0) {
119479
- try {
119480
- bound = await tryListen(preferredPort);
119481
- } catch {
119482
- bound = await tryListen(0);
119479
+ const bindListener = async () => {
119480
+ if (preferredPort === void 0) {
119481
+ return await tryListen(0);
119483
119482
  }
119484
- } else {
119485
- bound = await tryListen(0);
119486
- }
119483
+ for (let attempt = 1; attempt <= PREFERRED_PORT_MAX_ATTEMPTS; attempt += 1) {
119484
+ try {
119485
+ return await tryListen(preferredPort);
119486
+ } catch {
119487
+ if (attempt === PREFERRED_PORT_MAX_ATTEMPTS) {
119488
+ return await tryListen(0);
119489
+ }
119490
+ await new Promise((resolve2) => {
119491
+ setTimeout(resolve2, PREFERRED_PORT_RETRY_MS);
119492
+ });
119493
+ }
119494
+ }
119495
+ return await tryListen(0);
119496
+ };
119497
+ const bound = await bindListener();
119487
119498
  options.onBound?.(bound);
119488
119499
  if (options.onError !== void 0) {
119489
119500
  server.on("error", options.onError);
@@ -135064,7 +135075,7 @@ const { workerData, parentPort } = require("node:worker_threads");
135064
135075
  const fs = require("node:fs");
135065
135076
  const os = require("node:os");
135066
135077
  const inspector = require("node:inspector");
135067
- const { shared, boundMs, checkEveryMs, pauseWaitMs, stateFile, ownPid, action, logFile, respawn, respawnGeneration, respawnMaxGeneration, awaitPidEnv, respawnGenerationEnv } = workerData;
135078
+ const { shared, boundMs, checkEveryMs, pauseWaitMs, stateFile, ownPid, action, logFile, respawn, respawnGeneration, respawnMaxGeneration, startLockFile, awaitPidEnv, respawnGenerationEnv } = workerData;
135068
135079
  const counter = new Int32Array(shared);
135069
135080
  let lastValue = Atomics.load(counter, 0);
135070
135081
  let lastChangeAt = Date.now();
@@ -135128,17 +135139,59 @@ const describeMainThread = (waitMs, resume) => new Promise((resolve) => {
135128
135139
  finish("the main thread could not be inspected: " + (error instanceof Error ? error.message : String(error)));
135129
135140
  }
135130
135141
  });
135142
+ // Whether a process is alive: signal 0 only tests, and EPERM means it exists under another user.
135143
+ const isRunning = (pid) => {
135144
+ try {
135145
+ process.kill(pid, 0);
135146
+ return true;
135147
+ } catch (error) {
135148
+ return error.code === "EPERM";
135149
+ }
135150
+ };
135151
+ // The pid holding the start lock when that holder is alive, which means a door is already being started and another must not be: the launcher's ensure and this respawn are the two things that start a door, and the lock is the one protocol that keeps them from starting two. A dead holder's lock is litter and is cleared, exactly as the launcher's ensure clears it.
135152
+ const liveLockHolder = () => {
135153
+ let holder;
135154
+ try {
135155
+ holder = JSON.parse(fs.readFileSync(startLockFile, "utf8")).pid;
135156
+ } catch (error) {
135157
+ return undefined;
135158
+ }
135159
+ if (typeof holder === "number" && isRunning(holder)) return holder;
135160
+ fs.rmSync(startLockFile, { force: true });
135161
+ return undefined;
135162
+ };
135163
+ // Creates the lock naming the replacement as its holder, atomically (the wx flag), so the launcher's ensure sees a live holder while the replacement boots and waits for it instead of starting a door of its own; the replacement removes the lock once it is serving, as every door does.
135164
+ const claimStartLock = (holder) => {
135165
+ try {
135166
+ fs.writeFileSync(startLockFile, JSON.stringify({ pid: holder, at: Date.now() }) + "\\n", { flag: "wx" });
135167
+ return true;
135168
+ } catch (error) {
135169
+ if (error.code === "EEXIST") return false;
135170
+ throw error;
135171
+ }
135172
+ };
135131
135173
  const spawnReplacement = () => {
135132
135174
  if (respawn === undefined || logFile === undefined) return;
135133
135175
  if (respawnGeneration >= respawnMaxGeneration) {
135134
135176
  log("not starting another replacement: this door was replacement generation " + String(respawnGeneration) + " of " + String(respawnMaxGeneration) + ", so the stall has recurred through consecutive doors and the machine, not the door, is the one refusing to serve; leaving the next launch's ensure to start one");
135135
135177
  return;
135136
135178
  }
135179
+ const startingBy = liveLockHolder();
135180
+ if (startingBy !== undefined) {
135181
+ log("not starting a replacement: process " + String(startingBy) + " holds the start lock, so a door is already being started and a second one would race it for the sticky ports");
135182
+ return;
135183
+ }
135137
135184
  try {
135138
135185
  const out = fs.openSync(logFile, "a");
135139
135186
  const child = require("node:child_process").spawn(respawn.command, respawn.args, { detached: true, stdio: ["ignore", out, out], env: Object.assign({}, respawn.env, { [awaitPidEnv]: String(ownPid), [respawnGenerationEnv]: String(respawnGeneration + 1) }) });
135140
135187
  child.unref();
135141
135188
  fs.closeSync(out);
135189
+ if (!claimStartLock(child.pid)) {
135190
+ // A launcher took the lock between the check and the spawn, so its door is the one that is starting: this one must not also bind.
135191
+ process.kill(child.pid, "SIGKILL");
135192
+ log("withdrew replacement door " + String(child.pid) + ": a launcher took the start lock first and its door is the one starting");
135193
+ return;
135194
+ }
135142
135195
  log("started replacement door " + String(child.pid) + " of generation " + String(respawnGeneration + 1) + ", which binds once this process is gone");
135143
135196
  } catch (error) {
135144
135197
  log("could not start a replacement door: " + (error instanceof Error ? error.message : String(error)));
@@ -135187,7 +135240,7 @@ function startThreadWatchdog(params) {
135187
135240
  const counter = new Int32Array(shared);
135188
135241
  const worker = new import_node_worker_threads2.Worker(WATCHDOG_SOURCE, {
135189
135242
  eval: true,
135190
- workerData: { shared, boundMs: params.boundMs, checkEveryMs: params.checkEveryMs, pauseWaitMs: params.pauseWaitMs, stateFile: params.stateFile, ownPid: params.ownPid, action: params.action, logFile: params.logFile, respawn: params.respawn, respawnGeneration: params.respawnGeneration, respawnMaxGeneration: params.respawnMaxGeneration, awaitPidEnv: DOOR_AWAIT_PID_ENV, respawnGenerationEnv: DOOR_RESPAWN_GENERATION_ENV }
135243
+ workerData: { shared, boundMs: params.boundMs, checkEveryMs: params.checkEveryMs, pauseWaitMs: params.pauseWaitMs, stateFile: params.stateFile, ownPid: params.ownPid, action: params.action, logFile: params.logFile, respawn: params.respawn, respawnGeneration: params.respawnGeneration, respawnMaxGeneration: params.respawnMaxGeneration, startLockFile: params.startLockFile, awaitPidEnv: DOOR_AWAIT_PID_ENV, respawnGenerationEnv: DOOR_RESPAWN_GENERATION_ENV }
135191
135244
  });
135192
135245
  worker.unref();
135193
135246
  worker.on("message", (message) => {
@@ -135227,7 +135280,7 @@ function collectFrontDoorStatus(fsPort, socketTrust, paths, isRunning) {
135227
135280
  sessions: listFrontDoorSessions(fsPort, paths.frontdoorSessionsDir).map((session) => ({ ...session, alive: isRunning(session.pid) })),
135228
135281
  headroomSocket: headroomSocketTarget(fsPort, socketTrust, paths),
135229
135282
  logPath: paths.frontdoorLogPath,
135230
- logExists: fsPort.readFileUtf8(paths.frontdoorLogPath) !== void 0
135283
+ logExists: fsPort.lstat(paths.frontdoorLogPath) !== void 0
135231
135284
  };
135232
135285
  }
135233
135286
  function formatFrontDoorStatus(status, caCertPath) {
@@ -135763,7 +135816,8 @@ function realFrontDoorSupervisorPorts(paths, respawnGeneration) {
135763
135816
  logFile: paths.frontdoorLogPath,
135764
135817
  respawn: respawnInvocation(paths),
135765
135818
  respawnGeneration,
135766
- respawnMaxGeneration: DOOR_RESPAWN_MAX_GENERATIONS
135819
+ respawnMaxGeneration: DOOR_RESPAWN_MAX_GENERATIONS,
135820
+ startLockFile: paths.frontdoorLockFile
135767
135821
  }),
135768
135822
  // The launch lifecycle publisher over the same backbone the typed API serves: the tick's registry facts go in here, and the door's own register, prune and end moments come out as source-tagged events.
135769
135823
  observeLaunchRegistry: createLaunchEventPublisher(doorEvents, () => Date.now()).observe,
@@ -147003,7 +147057,7 @@ function collectHeadroomStatus(fsPort, paths, processes) {
147003
147057
  settings: settings2,
147004
147058
  settingsDrifted: state.settingsHash !== void 0 && state.settingsHash !== hashSettings(settings2),
147005
147059
  logPath: paths.headroomLogPath,
147006
- logExists: fsPort.readFileUtf8(paths.headroomLogPath) !== void 0
147060
+ logExists: fsPort.lstat(paths.headroomLogPath) !== void 0
147007
147061
  };
147008
147062
  }
147009
147063
  function formatHeadroomStatus(status) {
package/dist/index.cjs CHANGED
@@ -3151,7 +3151,7 @@ var init_package = __esm({
3151
3151
  "package.json"() {
3152
3152
  package_default = {
3153
3153
  name: "claude-use",
3154
- version: "11.44.3",
3154
+ version: "11.44.5",
3155
3155
  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.",
3156
3156
  license: "MIT",
3157
3157
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -17729,7 +17729,7 @@ function collectFrontDoorStatus(fsPort, socketTrust, paths, isRunning) {
17729
17729
  sessions: listFrontDoorSessions(fsPort, paths.frontdoorSessionsDir).map((session) => ({ ...session, alive: isRunning(session.pid) })),
17730
17730
  headroomSocket: headroomSocketTarget(fsPort, socketTrust, paths),
17731
17731
  logPath: paths.frontdoorLogPath,
17732
- logExists: fsPort.readFileUtf8(paths.frontdoorLogPath) !== void 0
17732
+ logExists: fsPort.lstat(paths.frontdoorLogPath) !== void 0
17733
17733
  };
17734
17734
  }
17735
17735
  function formatFrontDoorStatus(status, caCertPath) {
package/dist/index.mjs CHANGED
@@ -3127,7 +3127,7 @@ var init_package = __esm({
3127
3127
  "package.json"() {
3128
3128
  package_default = {
3129
3129
  name: "claude-use",
3130
- version: "11.44.3",
3130
+ version: "11.44.5",
3131
3131
  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.",
3132
3132
  license: "MIT",
3133
3133
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -17316,7 +17316,7 @@ function collectFrontDoorStatus(fsPort, socketTrust, paths, isRunning) {
17316
17316
  sessions: listFrontDoorSessions(fsPort, paths.frontdoorSessionsDir).map((session) => ({ ...session, alive: isRunning(session.pid) })),
17317
17317
  headroomSocket: headroomSocketTarget(fsPort, socketTrust, paths),
17318
17318
  logPath: paths.frontdoorLogPath,
17319
- logExists: fsPort.readFileUtf8(paths.frontdoorLogPath) !== void 0
17319
+ logExists: fsPort.lstat(paths.frontdoorLogPath) !== void 0
17320
17320
  };
17321
17321
  }
17322
17322
  function formatFrontDoorStatus(status, caCertPath) {
@@ -2648,7 +2648,7 @@ declare class UsageError extends CliError {
2648
2648
  type ConfigFileReader = (filepath: string) => unknown;
2649
2649
 
2650
2650
  /** The filesystem operations headroom coordination needs: the same shape as `FarmFs`, injected so every decision over state, sessions, and the start lock runs against an in-memory fake in tests. */
2651
- type HeadroomFs = Pick<FarmFs, "mkdirp" | "mkdirPrivate" | "readFileUtf8" | "writeFileUtf8" | "writeFilePrivate" | "writeFileExclusive" | "readdir" | "removeRecursive">;
2651
+ type HeadroomFs = Pick<FarmFs, "lstat" | "mkdirp" | "mkdirPrivate" | "readFileUtf8" | "writeFileUtf8" | "writeFilePrivate" | "writeFileExclusive" | "readdir" | "removeRecursive">;
2652
2652
 
2653
2653
  /**
2654
2654
  * The record held in one front-door session-registry file: the launcher's pid plus the per-launch capability token its child presents on every request, and the supervisor of the door the launch was sent to. `sessionId` is the id the launch's requests carry in their session header, and `models` the models block this launch resolved when its directory, profile or committed file added definitions of its own to the global block (absent otherwise, so the door follows the global block live). `supervisorPid` is absent on a record written before it existed and on a door's own transparent-surface record; such a launch cannot be attributed to a door, so a superseded door treats it as its own.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-use",
3
- "version": "11.44.3",
3
+ "version": "11.44.5",
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": "MIT",
6
6
  "author": "Joseph Mearman <joseph@mearman.co.uk>",