claude-use 7.6.0 → 7.6.1

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
@@ -61053,7 +61053,7 @@ function resolveLaunchIdentity(paths, cwd) {
61053
61053
  // package.json
61054
61054
  var package_default = {
61055
61055
  name: "claude-use",
61056
- version: "7.6.0",
61056
+ version: "7.6.1",
61057
61057
  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.",
61058
61058
  license: "MIT",
61059
61059
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -63791,8 +63791,13 @@ var import_node_path27 = __toESM(require("node:path"), 1);
63791
63791
 
63792
63792
  // src/frontdoor/state.ts
63793
63793
  var import_node_path26 = __toESM(require("node:path"), 1);
63794
+ var FRONT_DOOR_PROTOCOL = 1;
63794
63795
  var FrontDoorSessionSchema = external_exports.strictObject({ pid: external_exports.number().int().positive(), startedAt: external_exports.number(), token: external_exports.string().min(1) });
63795
63796
  var FrontDoorStateSchema = external_exports.strictObject({
63797
+ /**
63798
+ * The launcher-to-door wire protocol this supervisor speaks, written once it is serving; absent in state written by a release that predates the field, which `ensureFrontDoor` reads as protocol 0. A launcher replaces a door whose protocol is lower than its own (see `FRONT_DOOR_PROTOCOL`).
63799
+ */
63800
+ protocol: external_exports.number().int().nonnegative().optional(),
63796
63801
  /** The supervisor process serving the front door. Alive means both listeners are up in that process. */
63797
63802
  supervisorPid: external_exports.number().int().positive().optional(),
63798
63803
  /** The loopback port the HTTPS provider listener serves on. Absent until the listener has bound and answered its health probe, so "port is set" is itself the ready signal a launcher polls for. */
@@ -64908,7 +64913,7 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
64908
64913
  ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom must be restarted to admit the new address)`);
64909
64914
  }
64910
64915
  lastDirectPort = direct.port;
64911
- writeFrontDoorState(fs18, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http5.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
64916
+ writeFrontDoorState(fs18, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http5.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
64912
64917
  fs18.removeRecursive(paths.frontdoorLockFile);
64913
64918
  ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(http5.port)}, CONNECT surface on 127.0.0.1:${String(connect3.port)}`);
64914
64919
  let idleSince;
@@ -65466,6 +65471,7 @@ function ensureFrontDoor(params) {
65466
65471
  const { paths, ports } = params;
65467
65472
  const deadline = ports.now() + FRONTDOOR_START_TIMEOUT_MS;
65468
65473
  let spawned = false;
65474
+ let replaced = false;
65469
65475
  const distrusted = /* @__PURE__ */ new Set();
65470
65476
  let lastRejection;
65471
65477
  for (; ; ) {
@@ -65474,6 +65480,17 @@ function ensureFrontDoor(params) {
65474
65480
  if (supervisorPid !== void 0 && !distrusted.has(supervisorPid) && ports.isRunning(supervisorPid)) {
65475
65481
  if (state?.port !== void 0 && state.connectPort !== void 0) {
65476
65482
  const verdict = ports.verifyListener(state.port);
65483
+ if (verdict.ok && (state.protocol ?? 0) < FRONT_DOOR_PROTOCOL && !replaced) {
65484
+ ports.stopSupervisor(supervisorPid);
65485
+ while (ports.isRunning(supervisorPid)) {
65486
+ if (ports.now() >= deadline) {
65487
+ throw new FrontDoorStartError(`agent-shim: the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}) is older than this launcher (protocol ${String(FRONT_DOOR_PROTOCOL)}) and did not exit when asked. Daemon log: ${paths.frontdoorLogPath}`);
65488
+ }
65489
+ ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
65490
+ }
65491
+ replaced = true;
65492
+ continue;
65493
+ }
65477
65494
  if (verdict.ok) {
65478
65495
  const token = (0, import_node_crypto11.randomUUID)();
65479
65496
  writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token });
@@ -67152,6 +67169,9 @@ function realFrontDoorPort(paths) {
67152
67169
  now: () => Date.now(),
67153
67170
  sleep: realSleepSync,
67154
67171
  spawnSupervisor: (layout) => spawnDetachedSupervisor(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
67172
+ stopSupervisor: (pid) => {
67173
+ process.kill(pid, "SIGTERM");
67174
+ },
67155
67175
  // Read fresh for each probe: a replacement supervisor may have regenerated an unparseable CA, and the probe must trust exactly what the serving door's leaf chains to.
67156
67176
  verifyListener: (port) => probeFrontDoorSync(port, import_node_fs11.default.readFileSync(paths.frontdoorCaCertFile, "utf8"))
67157
67177
  }
package/dist/index.cjs CHANGED
@@ -2228,8 +2228,13 @@ function capabilityFromProxyAuthorization(value) {
2228
2228
  // src/frontdoor/state.ts
2229
2229
  var import_node_path5 = __toESM(require("node:path"), 1);
2230
2230
  var import_zod3 = require("zod");
2231
+ var FRONT_DOOR_PROTOCOL = 1;
2231
2232
  var FrontDoorSessionSchema = import_zod3.z.strictObject({ pid: import_zod3.z.number().int().positive(), startedAt: import_zod3.z.number(), token: import_zod3.z.string().min(1) });
2232
2233
  var FrontDoorStateSchema = import_zod3.z.strictObject({
2234
+ /**
2235
+ * The launcher-to-door wire protocol this supervisor speaks, written once it is serving; absent in state written by a release that predates the field, which `ensureFrontDoor` reads as protocol 0. A launcher replaces a door whose protocol is lower than its own (see `FRONT_DOOR_PROTOCOL`).
2236
+ */
2237
+ protocol: import_zod3.z.number().int().nonnegative().optional(),
2233
2238
  /** The supervisor process serving the front door. Alive means both listeners are up in that process. */
2234
2239
  supervisorPid: import_zod3.z.number().int().positive().optional(),
2235
2240
  /** The loopback port the HTTPS provider listener serves on. Absent until the listener has bound and answered its health probe, so "port is set" is itself the ready signal a launcher polls for. */
@@ -2375,7 +2380,7 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2375
2380
  ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom must be restarted to admit the new address)`);
2376
2381
  }
2377
2382
  lastDirectPort = direct.port;
2378
- writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http2.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
2383
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http2.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
2379
2384
  fs3.removeRecursive(paths.frontdoorLockFile);
2380
2385
  ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(http2.port)}, CONNECT surface on 127.0.0.1:${String(connect3.port)}`);
2381
2386
  let idleSince;
@@ -3064,6 +3069,7 @@ function ensureFrontDoor(params) {
3064
3069
  const { paths, ports } = params;
3065
3070
  const deadline = ports.now() + FRONTDOOR_START_TIMEOUT_MS;
3066
3071
  let spawned = false;
3072
+ let replaced = false;
3067
3073
  const distrusted = /* @__PURE__ */ new Set();
3068
3074
  let lastRejection;
3069
3075
  for (; ; ) {
@@ -3072,6 +3078,17 @@ function ensureFrontDoor(params) {
3072
3078
  if (supervisorPid !== void 0 && !distrusted.has(supervisorPid) && ports.isRunning(supervisorPid)) {
3073
3079
  if (state?.port !== void 0 && state.connectPort !== void 0) {
3074
3080
  const verdict = ports.verifyListener(state.port);
3081
+ if (verdict.ok && (state.protocol ?? 0) < FRONT_DOOR_PROTOCOL && !replaced) {
3082
+ ports.stopSupervisor(supervisorPid);
3083
+ while (ports.isRunning(supervisorPid)) {
3084
+ if (ports.now() >= deadline) {
3085
+ throw new FrontDoorStartError(`agent-shim: the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}) is older than this launcher (protocol ${String(FRONT_DOOR_PROTOCOL)}) and did not exit when asked. Daemon log: ${paths.frontdoorLogPath}`);
3086
+ }
3087
+ ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
3088
+ }
3089
+ replaced = true;
3090
+ continue;
3091
+ }
3075
3092
  if (verdict.ok) {
3076
3093
  const token = (0, import_node_crypto5.randomUUID)();
3077
3094
  writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token });
package/dist/index.mjs CHANGED
@@ -2128,8 +2128,13 @@ function capabilityFromProxyAuthorization(value) {
2128
2128
  // src/frontdoor/state.ts
2129
2129
  import path5 from "node:path";
2130
2130
  import { z as z3 } from "zod";
2131
+ var FRONT_DOOR_PROTOCOL = 1;
2131
2132
  var FrontDoorSessionSchema = z3.strictObject({ pid: z3.number().int().positive(), startedAt: z3.number(), token: z3.string().min(1) });
2132
2133
  var FrontDoorStateSchema = z3.strictObject({
2134
+ /**
2135
+ * The launcher-to-door wire protocol this supervisor speaks, written once it is serving; absent in state written by a release that predates the field, which `ensureFrontDoor` reads as protocol 0. A launcher replaces a door whose protocol is lower than its own (see `FRONT_DOOR_PROTOCOL`).
2136
+ */
2137
+ protocol: z3.number().int().nonnegative().optional(),
2133
2138
  /** The supervisor process serving the front door. Alive means both listeners are up in that process. */
2134
2139
  supervisorPid: z3.number().int().positive().optional(),
2135
2140
  /** The loopback port the HTTPS provider listener serves on. Absent until the listener has bound and answered its health probe, so "port is set" is itself the ready signal a launcher polls for. */
@@ -2275,7 +2280,7 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2275
2280
  ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom must be restarted to admit the new address)`);
2276
2281
  }
2277
2282
  lastDirectPort = direct.port;
2278
- writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http2.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
2283
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http2.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
2279
2284
  fs3.removeRecursive(paths.frontdoorLockFile);
2280
2285
  ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(http2.port)}, CONNECT surface on 127.0.0.1:${String(connect3.port)}`);
2281
2286
  let idleSince;
@@ -2964,6 +2969,7 @@ function ensureFrontDoor(params) {
2964
2969
  const { paths, ports } = params;
2965
2970
  const deadline = ports.now() + FRONTDOOR_START_TIMEOUT_MS;
2966
2971
  let spawned = false;
2972
+ let replaced = false;
2967
2973
  const distrusted = /* @__PURE__ */ new Set();
2968
2974
  let lastRejection;
2969
2975
  for (; ; ) {
@@ -2972,6 +2978,17 @@ function ensureFrontDoor(params) {
2972
2978
  if (supervisorPid !== void 0 && !distrusted.has(supervisorPid) && ports.isRunning(supervisorPid)) {
2973
2979
  if (state?.port !== void 0 && state.connectPort !== void 0) {
2974
2980
  const verdict = ports.verifyListener(state.port);
2981
+ if (verdict.ok && (state.protocol ?? 0) < FRONT_DOOR_PROTOCOL && !replaced) {
2982
+ ports.stopSupervisor(supervisorPid);
2983
+ while (ports.isRunning(supervisorPid)) {
2984
+ if (ports.now() >= deadline) {
2985
+ throw new FrontDoorStartError(`agent-shim: the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}) is older than this launcher (protocol ${String(FRONT_DOOR_PROTOCOL)}) and did not exit when asked. Daemon log: ${paths.frontdoorLogPath}`);
2986
+ }
2987
+ ports.sleep(FRONTDOOR_LAUNCHER_POLL_MS);
2988
+ }
2989
+ replaced = true;
2990
+ continue;
2991
+ }
2975
2992
  if (verdict.ok) {
2976
2993
  const token = randomUUID2();
2977
2994
  writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token });
@@ -17,6 +17,8 @@ export interface EnsureFrontDoorPorts {
17
17
  readonly spawnSupervisor: (paths: LayoutPaths) => number;
18
18
  /** Authenticates the provider listener on `port`: a TLS handshake chaining to agent-shim's CA and a healthy answer, with no capability sent (see `probeFrontDoorSync`). */
19
19
  readonly verifyListener: (port: number) => ListenerVerdict;
20
+ /** Asks a running front-door supervisor to exit, without waiting for it to: the caller polls `isRunning`. Only ever called for a pid whose recorded listener has just authenticated as agent-shim's own. */
21
+ readonly stopSupervisor: (pid: number) => void;
20
22
  }
21
23
  /**
22
24
  * Brings the front door up for this launch, or finds it serving, and registers this launcher pid in its session registry: the fact that keeps the door from idling out while this session lives, and the record that holds this launch's capability token. The same lock-and-poll coordination as headroom's and the old codex daemon's ensure: the exclusive-create start lock decides which of several concurrent launches spawns the one supervisor, everyone waits on state.json, and a lock whose holder died is removed and retried. Ready means state names a live supervisor and both listeners' ports, which the supervisor writes only after both have bound (and the provider listener has answered its own health probe).
@@ -1,5 +1,11 @@
1
1
  import { z } from "zod";
2
2
  import type { HeadroomFs } from "../headroom/state";
3
+ /**
4
+ * The launcher-to-door wire protocol this release speaks: the headers a launch's child presents, the capability registry's record format, and the routes. Bump it when a change would stop a door of this release serving launches made by an older one, or an older door serving this release's launches.
5
+ *
6
+ * The rule that makes a bump safe: a door accepts every lower protocol's launches (protocol 1 accepts the former `x-claude-use-*` header names), and a launcher replaces a door whose protocol is lower than its own, never one that is higher. Replacing is safe because restarts are what the door is designed for: the capability registry is on disk and the listeners keep their sticky ports, so launches already running reach the replacement on the addresses they froze at launch.
7
+ */
8
+ export declare const FRONT_DOOR_PROTOCOL = 1;
3
9
  /** 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. */
4
10
  declare const FrontDoorSessionSchema: z.ZodObject<{
5
11
  pid: z.ZodNumber;
@@ -11,6 +17,7 @@ export type FrontDoorSession = z.infer<typeof FrontDoorSessionSchema>;
11
17
  * The front-door supervisor's state.json under `<home>/frontdoor/`. Every field is optional because the file exists in stages, exactly like headroom's and the old codex daemon's: a fresh supervisor writes its own pid before the listener is up, and a shut-down front door leaves only the sticky `lastPort` and any `lastError` worth surfacing.
12
18
  */
13
19
  declare const FrontDoorStateSchema: z.ZodObject<{
20
+ protocol: z.ZodOptional<z.ZodNumber>;
14
21
  supervisorPid: z.ZodOptional<z.ZodNumber>;
15
22
  port: z.ZodOptional<z.ZodNumber>;
16
23
  lastPort: z.ZodOptional<z.ZodNumber>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-use",
3
- "version": "7.6.0",
3
+ "version": "7.6.1",
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>",