claude-use 11.48.0 → 11.49.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/dist/index.mjs CHANGED
@@ -2430,8 +2430,8 @@ var init_lock = __esm({
2430
2430
  // src/launcher/farm.ts
2431
2431
  import path7 from "node:path";
2432
2432
  import { z as z2 } from "zod";
2433
- function readFarmManifest(fs13, farmRoot) {
2434
- const raw = fs13.readFileUtf8(path7.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs13.readFileUtf8(path7.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
2433
+ function readFarmManifest(fs14, farmRoot) {
2434
+ const raw = fs14.readFileUtf8(path7.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs14.readFileUtf8(path7.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
2435
2435
  if (raw === void 0) {
2436
2436
  return void 0;
2437
2437
  }
@@ -2489,9 +2489,9 @@ function buildEntryFacts(params) {
2489
2489
  entries
2490
2490
  };
2491
2491
  }
2492
- function listSubtree(fs13, root, rel) {
2492
+ function listSubtree(fs14, root, rel) {
2493
2493
  const absolute = path7.join(root, rel);
2494
- const stat = fs13.lstat(absolute);
2494
+ const stat = fs14.lstat(absolute);
2495
2495
  if (stat === void 0) {
2496
2496
  return [];
2497
2497
  }
@@ -2499,10 +2499,10 @@ function listSubtree(fs13, root, rel) {
2499
2499
  return [{ rel, kind: "symlink" }];
2500
2500
  }
2501
2501
  if (stat.kind === "dir") {
2502
- const children = [...fs13.readdir(absolute)].sort().flatMap((name) => listSubtree(fs13, root, `${rel}/${name}`));
2502
+ const children = [...fs14.readdir(absolute)].sort().flatMap((name) => listSubtree(fs14, root, `${rel}/${name}`));
2503
2503
  return [{ rel, kind: "dir" }, ...children];
2504
2504
  }
2505
- const contentHash = fs13.hashFile(absolute);
2505
+ const contentHash = fs14.hashFile(absolute);
2506
2506
  return [{ rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } }];
2507
2507
  }
2508
2508
  function topLevelScopeRoots(roots) {
@@ -2516,25 +2516,25 @@ function topLevelScopeRoots(roots) {
2516
2516
  }
2517
2517
  return kept;
2518
2518
  }
2519
- function reconciliationScope(fs13, farmRoot, manifest) {
2519
+ function reconciliationScope(fs14, farmRoot, manifest) {
2520
2520
  if (manifest !== void 0) {
2521
2521
  return topLevelScopeRoots(manifest.materialised);
2522
2522
  }
2523
- return [...fs13.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs13.lstat(path7.join(farmRoot, name))?.kind === "dir").sort();
2523
+ return [...fs14.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs14.lstat(path7.join(farmRoot, name))?.kind === "dir").sort();
2524
2524
  }
2525
- function collectFarmListing(fs13, farmRoot, scopeRoots) {
2526
- return scopeRoots.flatMap((root) => listSubtree(fs13, farmRoot, root));
2525
+ function collectFarmListing(fs14, farmRoot, scopeRoots) {
2526
+ return scopeRoots.flatMap((root) => listSubtree(fs14, farmRoot, root));
2527
2527
  }
2528
- function collectCanonicalCounterparts(fs13, claudeHome, farmListing) {
2528
+ function collectCanonicalCounterparts(fs14, claudeHome, farmListing) {
2529
2529
  const out = [];
2530
2530
  for (const entry of farmListing) {
2531
2531
  const absolute = path7.join(claudeHome, entry.rel);
2532
- const stat = fs13.lstat(absolute);
2532
+ const stat = fs14.lstat(absolute);
2533
2533
  if (stat === void 0) {
2534
2534
  continue;
2535
2535
  }
2536
2536
  if (stat.kind === "file") {
2537
- const contentHash = fs13.hashFile(absolute);
2537
+ const contentHash = fs14.hashFile(absolute);
2538
2538
  out.push({ rel: entry.rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } });
2539
2539
  continue;
2540
2540
  }
@@ -3305,10 +3305,10 @@ var init_route = __esm({
3305
3305
  // src/frontdoor/state.ts
3306
3306
  import path8 from "node:path";
3307
3307
  import { z as z3 } from "zod";
3308
- function readFrontDoorState(fs13, stateFile) {
3308
+ function readFrontDoorState(fs14, stateFile) {
3309
3309
  let raw;
3310
3310
  try {
3311
- raw = fs13.readFileUtf8(stateFile);
3311
+ raw = fs14.readFileUtf8(stateFile);
3312
3312
  } catch {
3313
3313
  return void 0;
3314
3314
  }
@@ -3322,9 +3322,9 @@ function readFrontDoorState(fs13, stateFile) {
3322
3322
  return void 0;
3323
3323
  }
3324
3324
  }
3325
- function writeFrontDoorState(fs13, stateFile, state) {
3326
- fs13.mkdirp(path8.dirname(stateFile));
3327
- fs13.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
3325
+ function writeFrontDoorState(fs14, stateFile, state) {
3326
+ fs14.mkdirp(path8.dirname(stateFile));
3327
+ fs14.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
3328
3328
  `);
3329
3329
  }
3330
3330
  function directOrigin(port) {
@@ -3334,27 +3334,37 @@ function frontDoorOrigin(state) {
3334
3334
  const port = state?.directPort ?? state?.lastDirectPort;
3335
3335
  return port === void 0 ? void 0 : directOrigin(port);
3336
3336
  }
3337
- function writeFrontDoorDirectRecord(fs13, recordsDir, record) {
3338
- fs13.mkdirp(recordsDir);
3339
- fs13.writeFilePrivate(path8.join(recordsDir, `${String(record.pid)}.json`), `${JSON.stringify({ directPort: record.directPort })}
3337
+ function writeFrontDoorDirectRecord(fs14, recordsDir, record) {
3338
+ fs14.mkdirp(recordsDir);
3339
+ fs14.writeFilePrivate(path8.join(recordsDir, `${String(record.pid)}.json`), `${JSON.stringify({ directPort: record.directPort })}
3340
3340
  `);
3341
3341
  }
3342
- function removeFrontDoorDirectRecord(fs13, recordsDir, pid) {
3343
- fs13.removeRecursive(path8.join(recordsDir, `${String(pid)}.json`));
3342
+ function removeFrontDoorDirectRecord(fs14, recordsDir, pid) {
3343
+ fs14.removeRecursive(path8.join(recordsDir, `${String(pid)}.json`));
3344
+ }
3345
+ function markFrontDoorDraining(fs14, markersDir, pid) {
3346
+ fs14.mkdirp(markersDir);
3347
+ fs14.writeFilePrivate(path8.join(markersDir, String(pid)), "\n");
3348
+ }
3349
+ function unmarkFrontDoorDraining(fs14, markersDir, pid) {
3350
+ fs14.removeRecursive(path8.join(markersDir, String(pid)));
3351
+ }
3352
+ function listDrainingFrontDoors(fs14, markersDir, isRunning) {
3353
+ return fs14.readdir(markersDir).flatMap((file) => /^[1-9]\d*$/.test(file) && Number.isSafeInteger(Number(file)) ? [Number(file)] : []).filter(isRunning).sort((a, b) => a - b);
3344
3354
  }
3345
3355
  function recordPid(file) {
3346
3356
  const pidText = /^([1-9]\d*)\.json$/.exec(file)?.[1];
3347
3357
  const pid = pidText === void 0 ? void 0 : Number(pidText);
3348
3358
  return pid !== void 0 && Number.isSafeInteger(pid) ? pid : void 0;
3349
3359
  }
3350
- function readDirectRecordEntry(fs13, recordsDir, file) {
3360
+ function readDirectRecordEntry(fs14, recordsDir, file) {
3351
3361
  const pid = recordPid(file);
3352
3362
  if (pid === void 0) {
3353
3363
  return void 0;
3354
3364
  }
3355
3365
  let raw;
3356
3366
  try {
3357
- raw = fs13.readFileUtf8(path8.join(recordsDir, file));
3367
+ raw = fs14.readFileUtf8(path8.join(recordsDir, file));
3358
3368
  } catch {
3359
3369
  return void 0;
3360
3370
  }
@@ -3368,47 +3378,47 @@ function readDirectRecordEntry(fs13, recordsDir, file) {
3368
3378
  return { malformed: true };
3369
3379
  }
3370
3380
  }
3371
- function listFrontDoorDirectRecords(fs13, recordsDir) {
3372
- return fs13.readdir(recordsDir).flatMap((file) => {
3373
- const entry = readDirectRecordEntry(fs13, recordsDir, file);
3381
+ function listFrontDoorDirectRecords(fs14, recordsDir) {
3382
+ return fs14.readdir(recordsDir).flatMap((file) => {
3383
+ const entry = readDirectRecordEntry(fs14, recordsDir, file);
3374
3384
  return entry?.record === void 0 ? [] : [entry.record];
3375
3385
  }).sort((a, b) => a.pid - b.pid);
3376
3386
  }
3377
- function pruneMalformedFrontDoorDirectFiles(fs13, recordsDir, isRunning) {
3378
- for (const file of fs13.readdir(recordsDir)) {
3387
+ function pruneMalformedFrontDoorDirectFiles(fs14, recordsDir, isRunning) {
3388
+ for (const file of fs14.readdir(recordsDir)) {
3379
3389
  const writer = RECORD_TEMPORARY_FILE.exec(file)?.[1];
3380
3390
  const stale = writer !== void 0 && !isRunning(Number(writer));
3381
- if (stale || readDirectRecordEntry(fs13, recordsDir, file)?.malformed === true) {
3382
- fs13.removeRecursive(path8.join(recordsDir, file));
3391
+ if (stale || readDirectRecordEntry(fs14, recordsDir, file)?.malformed === true) {
3392
+ fs14.removeRecursive(path8.join(recordsDir, file));
3383
3393
  }
3384
3394
  }
3385
3395
  }
3386
3396
  function liveFrontDoorDirectRecords(records, liveness) {
3387
3397
  return records.filter((record) => liveness.doors.has(record.pid) || liveness.unknown.has(record.pid));
3388
3398
  }
3389
- function pruneDeadFrontDoorDirectRecords(fs13, recordsDir, records, liveness) {
3399
+ function pruneDeadFrontDoorDirectRecords(fs14, recordsDir, records, liveness) {
3390
3400
  for (const record of records) {
3391
3401
  if (!liveness.doors.has(record.pid) && !liveness.unknown.has(record.pid)) {
3392
- removeFrontDoorDirectRecord(fs13, recordsDir, record.pid);
3402
+ removeFrontDoorDirectRecord(fs14, recordsDir, record.pid);
3393
3403
  }
3394
3404
  }
3395
3405
  }
3396
3406
  function recordOf(details) {
3397
3407
  return details === void 0 ? {} : { sessionId: details.sessionId, ...details.models === void 0 ? {} : { models: details.models } };
3398
3408
  }
3399
- function writeFrontDoorSession(fs13, sessionsDir, session) {
3400
- fs13.mkdirPrivate(sessionsDir);
3401
- fs13.writeFilePrivate(path8.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
3409
+ function writeFrontDoorSession(fs14, sessionsDir, session) {
3410
+ fs14.mkdirPrivate(sessionsDir);
3411
+ fs14.writeFilePrivate(path8.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
3402
3412
  `);
3403
3413
  }
3404
- function listFrontDoorSessions(fs13, sessionsDir) {
3414
+ function listFrontDoorSessions(fs14, sessionsDir) {
3405
3415
  const sessions = [];
3406
- for (const name of fs13.readdir(sessionsDir)) {
3416
+ for (const name of fs14.readdir(sessionsDir)) {
3407
3417
  if (!name.endsWith(".json")) {
3408
3418
  continue;
3409
3419
  }
3410
3420
  try {
3411
- const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs13.readFileUtf8(path8.join(sessionsDir, name)) ?? ""));
3421
+ const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs14.readFileUtf8(path8.join(sessionsDir, name)) ?? ""));
3412
3422
  if (parsed.success) {
3413
3423
  sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt, ...parsed.data.supervisorPid === void 0 ? {} : { supervisorPid: parsed.data.supervisorPid } });
3414
3424
  }
@@ -3418,14 +3428,14 @@ function listFrontDoorSessions(fs13, sessionsDir) {
3418
3428
  }
3419
3429
  return sessions.sort((a, b) => a.pid - b.pid);
3420
3430
  }
3421
- function removeFrontDoorSession(fs13, sessionsDir, pid) {
3422
- fs13.removeRecursive(path8.join(sessionsDir, `${String(pid)}.json`));
3431
+ function removeFrontDoorSession(fs14, sessionsDir, pid) {
3432
+ fs14.removeRecursive(path8.join(sessionsDir, `${String(pid)}.json`));
3423
3433
  }
3424
- function pruneDeadFrontDoorSessions(fs13, sessionsDir, isRunning) {
3434
+ function pruneDeadFrontDoorSessions(fs14, sessionsDir, isRunning) {
3425
3435
  const removed = [];
3426
- for (const session of listFrontDoorSessions(fs13, sessionsDir)) {
3436
+ for (const session of listFrontDoorSessions(fs14, sessionsDir)) {
3427
3437
  if (!isRunning(session.pid)) {
3428
- removeFrontDoorSession(fs13, sessionsDir, session.pid);
3438
+ removeFrontDoorSession(fs14, sessionsDir, session.pid);
3429
3439
  removed.push(session.pid);
3430
3440
  }
3431
3441
  }
@@ -3522,9 +3532,9 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
3522
3532
  }
3523
3533
  }
3524
3534
  async function serveFrontDoor(idleShutdownMinutes, ports, options) {
3525
- const { fs: fs13, paths } = ports;
3535
+ const { fs: fs14, paths } = ports;
3526
3536
  const servingBinary = ports.statOwnExecutable();
3527
- const previous = readFrontDoorState(fs13, paths.frontdoorStateFile);
3537
+ const previous = readFrontDoorState(fs14, paths.frontdoorStateFile);
3528
3538
  let lastPort = previous?.lastPort;
3529
3539
  let lastConnectPort = previous?.lastConnectPort;
3530
3540
  let lastDirectPort = previous?.lastDirectPort;
@@ -3535,12 +3545,12 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
3535
3545
  });
3536
3546
  const fail = (message) => {
3537
3547
  ports.closeRcStreamHub();
3538
- writeFrontDoorState(fs13, paths.frontdoorStateFile, { lastError: message, ...sticky() });
3539
- fs13.removeRecursive(paths.frontdoorLockFile);
3548
+ writeFrontDoorState(fs14, paths.frontdoorStateFile, { lastError: message, ...sticky() });
3549
+ fs14.removeRecursive(paths.frontdoorLockFile);
3540
3550
  ports.log(`agent-shim frontdoor supervisor: ${message}`);
3541
3551
  return 1;
3542
3552
  };
3543
- writeFrontDoorState(fs13, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
3553
+ writeFrontDoorState(fs14, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
3544
3554
  const previousSticky = lastPort;
3545
3555
  let http3;
3546
3556
  try {
@@ -3580,16 +3590,16 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
3580
3590
  ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom admits the new address once its supervisor rewrites the allowlist file)`);
3581
3591
  }
3582
3592
  lastDirectPort = direct.port;
3583
- writeFrontDoorDirectRecord(fs13, paths.frontdoorDirectRecordsDir, { pid: ports.ownPid, directPort: direct.port });
3584
- writeFrontDoorState(fs13, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http3.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
3593
+ writeFrontDoorDirectRecord(fs14, paths.frontdoorDirectRecordsDir, { pid: ports.ownPid, directPort: direct.port });
3594
+ writeFrontDoorState(fs14, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http3.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
3585
3595
  ports.doorHealth.generation({ providerPort: http3.port, connectPort: connect3.port, directPort: direct.port });
3586
- fs13.removeRecursive(paths.frontdoorLockFile);
3596
+ fs14.removeRecursive(paths.frontdoorLockFile);
3587
3597
  ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(http3.port)}, CONNECT surface on 127.0.0.1:${String(connect3.port)}`);
3588
3598
  const watchdog = ports.startWatchdog?.();
3589
3599
  let idleSince;
3590
3600
  let ticks = 0;
3591
3601
  const supersedingOwner = () => {
3592
- const owner = readFrontDoorState(fs13, paths.frontdoorStateFile)?.supervisorPid;
3602
+ const owner = readFrontDoorState(fs14, paths.frontdoorStateFile)?.supervisorPid;
3593
3603
  return owner !== void 0 && owner !== ports.ownPid && ports.isRunning(owner) ? owner : void 0;
3594
3604
  };
3595
3605
  let supersededBy;
@@ -3598,30 +3608,61 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
3598
3608
  const current = ports.statOwnExecutable();
3599
3609
  return current !== void 0 && servingBinary !== void 0 && (current.dev !== servingBinary.dev || current.ino !== servingBinary.ino || current.size !== servingBinary.size || current.mtimeMs !== servingBinary.mtimeMs);
3600
3610
  };
3611
+ const pause = async () => {
3612
+ await new Promise((resolve) => {
3613
+ const wake = () => {
3614
+ resolve();
3615
+ };
3616
+ ports.retire?.addEventListener("abort", wake, { once: true });
3617
+ void ports.sleep(FRONTDOOR_POLL_MS).then(() => {
3618
+ ports.retire?.removeEventListener("abort", wake);
3619
+ resolve();
3620
+ });
3621
+ });
3622
+ };
3623
+ const retireByDrain = async () => {
3624
+ ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: asked to exit; releasing the front door's addresses and finishing the connections it carries`);
3625
+ watchdog?.stop();
3626
+ ports.stopBackgroundWork?.();
3627
+ const drained = [direct.drain(), connect3.drain(), http3.drain()];
3628
+ if (supersedingOwner() === void 0) {
3629
+ writeFrontDoorState(fs14, paths.frontdoorStateFile, sticky());
3630
+ }
3631
+ markFrontDoorDraining(fs14, paths.frontdoorDrainingDir, ports.ownPid);
3632
+ ports.closeRcStreamHub();
3633
+ await Promise.all(drained);
3634
+ unmarkFrontDoorDraining(fs14, paths.frontdoorDrainingDir, ports.ownPid);
3635
+ removeFrontDoorDirectRecord(fs14, paths.frontdoorDirectRecordsDir, ports.ownPid);
3636
+ ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: the connections this door carried have ended; exiting`);
3637
+ return 0;
3638
+ };
3601
3639
  const closeServing = async () => {
3602
3640
  watchdog?.stop();
3603
3641
  await direct.close();
3604
3642
  await connect3.close();
3605
3643
  await http3.close();
3606
3644
  ports.closeRcStreamHub();
3607
- removeFrontDoorDirectRecord(fs13, paths.frontdoorDirectRecordsDir, ports.ownPid);
3645
+ removeFrontDoorDirectRecord(fs14, paths.frontdoorDirectRecordsDir, ports.ownPid);
3608
3646
  };
3609
3647
  const shutdown = async () => {
3610
3648
  await closeServing();
3611
3649
  if (supersedingOwner() === void 0) {
3612
- writeFrontDoorState(fs13, paths.frontdoorStateFile, sticky());
3650
+ writeFrontDoorState(fs14, paths.frontdoorStateFile, sticky());
3613
3651
  }
3614
3652
  return 0;
3615
3653
  };
3616
3654
  for (; ; ) {
3617
3655
  watchdog?.beat();
3656
+ if (ports.retire?.aborted === true) {
3657
+ return await retireByDrain();
3658
+ }
3618
3659
  if (options.tickLimit !== void 0 && ticks >= options.tickLimit) {
3619
3660
  watchdog?.stop();
3620
3661
  return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
3621
3662
  }
3622
3663
  ticks += 1;
3623
- const listed = listFrontDoorSessions(fs13, paths.frontdoorSessionsDir);
3624
- const pruned = pruneDeadFrontDoorSessions(fs13, paths.frontdoorSessionsDir, ports.isRunning);
3664
+ const listed = listFrontDoorSessions(fs14, paths.frontdoorSessionsDir);
3665
+ const pruned = pruneDeadFrontDoorSessions(fs14, paths.frontdoorSessionsDir, ports.isRunning);
3625
3666
  ports.observeLaunchRegistry(listed, pruned);
3626
3667
  ports.checkQuotaExpiry();
3627
3668
  const prunedPids = new Set(pruned);
@@ -3631,7 +3672,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
3631
3672
  if (supersededBy !== void 0) {
3632
3673
  ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: supervisor ${String(supersededBy)} now owns the front door; taking no new sessions and exiting once the sessions this door serves have ended`);
3633
3674
  ports.doorHealth.superseded(supersededBy);
3634
- await ports.sleep(FRONTDOOR_POLL_MS);
3675
+ await pause();
3635
3676
  continue;
3636
3677
  }
3637
3678
  } else {
@@ -3643,7 +3684,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
3643
3684
  await closeServing();
3644
3685
  return 0;
3645
3686
  }
3646
- await ports.sleep(FRONTDOOR_POLL_MS);
3687
+ await pause();
3647
3688
  continue;
3648
3689
  }
3649
3690
  if (live.length === 0) {
@@ -3661,7 +3702,7 @@ async function serveFrontDoor(idleShutdownMinutes, ports, options) {
3661
3702
  } else {
3662
3703
  idleSince = void 0;
3663
3704
  }
3664
- await ports.sleep(FRONTDOOR_POLL_MS);
3705
+ await pause();
3665
3706
  }
3666
3707
  }
3667
3708
  var FRONTDOOR_SUPERVISOR_STILL_RUNNING, FRONTDOOR_POLL_MS, MS_PER_MINUTE;
@@ -3815,25 +3856,35 @@ ${request4.rawHeaders.reduce((accumulated, value, index) => index % 2 === 0 ? `$
3815
3856
  const transparent = config.transparentPort === void 0 || apiSession === void 0 ? void 0 : await effects.listenLoopback(config.transparentPort, (socket) => {
3816
3857
  sniAcceptor.accept(socket);
3817
3858
  });
3859
+ const closeSurface = async () => {
3860
+ ledger.close();
3861
+ await listener.close();
3862
+ await transparent?.close();
3863
+ sniAcceptor.close();
3864
+ for (const { httpSession, tlsAcceptor } of sessions) {
3865
+ tlsAcceptor.close();
3866
+ httpSession?.close();
3867
+ }
3868
+ };
3818
3869
  return {
3819
3870
  port: listener.port,
3820
3871
  ...transparent === void 0 ? {} : { transparentPort: transparent.port },
3821
- close: async () => {
3822
- ledger.close();
3823
- await listener.close();
3872
+ openTunnels: ledger.openTunnels,
3873
+ drain: async () => {
3874
+ listener.stopAccepting();
3824
3875
  await transparent?.close();
3825
- sniAcceptor.close();
3826
- for (const { httpSession, tlsAcceptor } of sessions) {
3827
- tlsAcceptor.close();
3828
- httpSession?.close();
3829
- }
3830
- }
3876
+ await ledger.retire();
3877
+ await closeSurface();
3878
+ },
3879
+ close: closeSurface
3831
3880
  };
3832
3881
  }
3833
3882
  function createConnectionLedger(limits, isLiveCapability2) {
3834
3883
  const pending = /* @__PURE__ */ new Map();
3835
3884
  const authenticated = /* @__PURE__ */ new Map();
3836
3885
  let tunnels = 0;
3886
+ const blind = /* @__PURE__ */ new Set();
3887
+ let onNoBlindTunnels;
3837
3888
  const leavePending = (socket) => {
3838
3889
  const deadline = pending.get(socket);
3839
3890
  if (deadline !== void 0) {
@@ -3870,16 +3921,45 @@ function createConnectionLedger(limits, isLiveCapability2) {
3870
3921
  });
3871
3922
  },
3872
3923
  headReceived: leavePending,
3873
- establish: (socket, capability) => {
3924
+ openTunnels: () => tunnels,
3925
+ retire: async () => {
3926
+ for (const socket of pending.keys()) {
3927
+ socket.destroy();
3928
+ }
3929
+ for (const deadline of pending.values()) {
3930
+ clearTimeout(deadline);
3931
+ }
3932
+ pending.clear();
3933
+ for (const sockets of authenticated.values()) {
3934
+ for (const socket of sockets) {
3935
+ if (!blind.has(socket)) {
3936
+ socket.destroy();
3937
+ }
3938
+ }
3939
+ }
3940
+ if (blind.size > 0) {
3941
+ await new Promise((resolve) => {
3942
+ onNoBlindTunnels = resolve;
3943
+ });
3944
+ }
3945
+ },
3946
+ establish: (socket, capability, kind) => {
3874
3947
  if (tunnels >= limits.maxTunnels) {
3875
3948
  return false;
3876
3949
  }
3877
3950
  tunnels += 1;
3951
+ if (kind === "blind") {
3952
+ blind.add(socket);
3953
+ }
3878
3954
  const sockets = authenticated.get(capability) ?? /* @__PURE__ */ new Set();
3879
3955
  sockets.add(socket);
3880
3956
  authenticated.set(capability, sockets);
3881
3957
  socket.once("close", () => {
3882
3958
  tunnels -= 1;
3959
+ blind.delete(socket);
3960
+ if (blind.size === 0) {
3961
+ onNoBlindTunnels?.();
3962
+ }
3883
3963
  sockets.delete(socket);
3884
3964
  if (sockets.size === 0 && authenticated.get(capability) === sockets) {
3885
3965
  authenticated.delete(capability);
@@ -3961,11 +4041,11 @@ function routeConnect(socket, head, context) {
3961
4041
  refuse(socket, REFUSAL.badRequest);
3962
4042
  return;
3963
4043
  }
3964
- if (!ledger.establish(socket, capability)) {
4044
+ const session = sessions.find((entry) => entry.host === target.host);
4045
+ if (!ledger.establish(socket, capability, session === void 0 ? "blind" : "terminated")) {
3965
4046
  refuse(socket, REFUSAL.serviceUnavailable);
3966
4047
  return;
3967
4048
  }
3968
- const session = sessions.find((entry) => entry.host === target.host);
3969
4049
  config.capture?.connect(target, session !== void 0);
3970
4050
  socket.write(CONNECT_ESTABLISHED);
3971
4051
  if (session !== void 0) {
@@ -4087,7 +4167,7 @@ var init_package = __esm({
4087
4167
  "package.json"() {
4088
4168
  package_default = {
4089
4169
  name: "claude-use",
4090
- version: "11.48.0",
4170
+ version: "11.49.0",
4091
4171
  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.",
4092
4172
  license: "MIT",
4093
4173
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -4295,43 +4375,43 @@ function parseJson(raw, schema) {
4295
4375
  const parsed = schema.safeParse(JSON.parse(raw));
4296
4376
  return parsed.success ? parsed.data : void 0;
4297
4377
  }
4298
- function readHeadroomState(fs13, stateFile) {
4378
+ function readHeadroomState(fs14, stateFile) {
4299
4379
  try {
4300
- return parseJson(fs13.readFileUtf8(stateFile), HeadroomStateSchema);
4380
+ return parseJson(fs14.readFileUtf8(stateFile), HeadroomStateSchema);
4301
4381
  } catch {
4302
4382
  return void 0;
4303
4383
  }
4304
4384
  }
4305
- function writeHeadroomState(fs13, stateFile, state) {
4306
- fs13.mkdirp(path11.dirname(stateFile));
4307
- fs13.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
4385
+ function writeHeadroomState(fs14, stateFile, state) {
4386
+ fs14.mkdirp(path11.dirname(stateFile));
4387
+ fs14.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
4308
4388
  `);
4309
4389
  }
4310
- function resolveServingHeadroomState(fs13, files, isRunning) {
4311
- const current = readHeadroomState(fs13, files.stateFile);
4390
+ function resolveServingHeadroomState(fs14, files, isRunning) {
4391
+ const current = readHeadroomState(fs14, files.stateFile);
4312
4392
  if (current !== void 0) {
4313
4393
  return { path: files.stateFile, state: current };
4314
4394
  }
4315
- const legacy = readHeadroomState(fs13, files.legacyStateFile);
4395
+ const legacy = readHeadroomState(fs14, files.legacyStateFile);
4316
4396
  if (legacy?.supervisorPid !== void 0 && isRunning(legacy.supervisorPid)) {
4317
4397
  return { path: files.legacyStateFile, state: legacy };
4318
4398
  }
4319
4399
  return void 0;
4320
4400
  }
4321
- function migrateHeadroomState(fs13, files, isRunning) {
4322
- const legacy = readHeadroomState(fs13, files.legacyStateFile);
4401
+ function migrateHeadroomState(fs14, files, isRunning) {
4402
+ const legacy = readHeadroomState(fs14, files.legacyStateFile);
4323
4403
  const legacyLive = legacy?.supervisorPid !== void 0 && isRunning(legacy.supervisorPid);
4324
- const current = readHeadroomState(fs13, files.stateFile);
4404
+ const current = readHeadroomState(fs14, files.stateFile);
4325
4405
  if (current !== void 0 || legacyLive) {
4326
- if (!legacyLive && fs13.readFileUtf8(files.legacyStateFile) !== void 0) {
4327
- fs13.removeRecursive(files.legacyStateFile);
4406
+ if (!legacyLive && fs14.readFileUtf8(files.legacyStateFile) !== void 0) {
4407
+ fs14.removeRecursive(files.legacyStateFile);
4328
4408
  }
4329
4409
  return;
4330
4410
  }
4331
4411
  if (legacy !== void 0) {
4332
- writeHeadroomState(fs13, files.stateFile, legacy);
4412
+ writeHeadroomState(fs14, files.stateFile, legacy);
4333
4413
  }
4334
- fs13.removeRecursive(files.legacyStateFile);
4414
+ fs14.removeRecursive(files.legacyStateFile);
4335
4415
  }
4336
4416
  function hashAllowlist(allowlist) {
4337
4417
  return createHash3("sha256").update(allowlist.join("\n")).digest("hex");
@@ -4364,27 +4444,27 @@ function isAdmissibleUrl(entry) {
4364
4444
  function parseAllowlistFile(content) {
4365
4445
  return content.replace(/^\uFEFF/, "").replace(ALLOWLIST_FILE_COMMENT, "").split(ALLOWLIST_FILE_SEPARATORS).map((entry) => entry.replace(ALLOWLIST_SURROUNDING_WHITESPACE, "")).filter((entry) => entry !== "" && !ALLOWLIST_ENTRY_WHITESPACE.test(entry) && (entry.includes("://") ? isAdmissibleUrl(entry) : isBareHost(entry)));
4366
4446
  }
4367
- function writeAllowlistFile(fs13, allowlistFile, allowlist) {
4368
- fs13.mkdirPrivate(path11.dirname(allowlistFile));
4369
- fs13.writeFilePrivate(allowlistFile, formatAllowlistFile(allowlist));
4447
+ function writeAllowlistFile(fs14, allowlistFile, allowlist) {
4448
+ fs14.mkdirPrivate(path11.dirname(allowlistFile));
4449
+ fs14.writeFilePrivate(allowlistFile, formatAllowlistFile(allowlist));
4370
4450
  }
4371
- function pruneStaleAllowlistTemporaries(fs13, allowlistFile, isRunning) {
4451
+ function pruneStaleAllowlistTemporaries(fs14, allowlistFile, isRunning) {
4372
4452
  const prefix = `${path11.basename(allowlistFile)}.`;
4373
- for (const name of fs13.readdir(path11.dirname(allowlistFile))) {
4453
+ for (const name of fs14.readdir(path11.dirname(allowlistFile))) {
4374
4454
  const writer = name.startsWith(prefix) ? /^([1-9]\d*)\.tmp$/.exec(name.slice(prefix.length))?.[1] : void 0;
4375
4455
  if (writer !== void 0 && !isRunning(Number(writer))) {
4376
- fs13.removeRecursive(path11.join(path11.dirname(allowlistFile), name));
4456
+ fs14.removeRecursive(path11.join(path11.dirname(allowlistFile), name));
4377
4457
  }
4378
4458
  }
4379
4459
  }
4380
- function readAllProviders(fs13, providersDir) {
4460
+ function readAllProviders(fs14, providersDir) {
4381
4461
  const result = [];
4382
- for (const name of fs13.readdir(providersDir)) {
4462
+ for (const name of fs14.readdir(providersDir)) {
4383
4463
  if (!name.endsWith(".json")) {
4384
4464
  continue;
4385
4465
  }
4386
4466
  try {
4387
- const parsed = parseJson(fs13.readFileUtf8(path11.join(providersDir, name)), ProviderSchema);
4467
+ const parsed = parseJson(fs14.readFileUtf8(path11.join(providersDir, name)), ProviderSchema);
4388
4468
  if (parsed !== void 0) {
4389
4469
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
4390
4470
  }
@@ -4394,22 +4474,22 @@ function readAllProviders(fs13, providersDir) {
4394
4474
  }
4395
4475
  return result;
4396
4476
  }
4397
- function writeSession(fs13, sessionsDir, session) {
4398
- fs13.mkdirp(sessionsDir);
4399
- fs13.writeFileUtf8(path11.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
4477
+ function writeSession(fs14, sessionsDir, session) {
4478
+ fs14.mkdirp(sessionsDir);
4479
+ fs14.writeFileUtf8(path11.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
4400
4480
  `);
4401
4481
  }
4402
- function removeSession(fs13, sessionsDir, pid) {
4403
- fs13.removeRecursive(path11.join(sessionsDir, `${String(pid)}.json`));
4482
+ function removeSession(fs14, sessionsDir, pid) {
4483
+ fs14.removeRecursive(path11.join(sessionsDir, `${String(pid)}.json`));
4404
4484
  }
4405
- function listSessions(fs13, sessionsDir) {
4485
+ function listSessions(fs14, sessionsDir) {
4406
4486
  const sessions = [];
4407
- for (const name of fs13.readdir(sessionsDir)) {
4487
+ for (const name of fs14.readdir(sessionsDir)) {
4408
4488
  if (!name.endsWith(".json")) {
4409
4489
  continue;
4410
4490
  }
4411
4491
  try {
4412
- const parsed = parseJson(fs13.readFileUtf8(path11.join(sessionsDir, name)), HeadroomSessionSchema);
4492
+ const parsed = parseJson(fs14.readFileUtf8(path11.join(sessionsDir, name)), HeadroomSessionSchema);
4413
4493
  if (parsed !== void 0) {
4414
4494
  sessions.push(parsed);
4415
4495
  }
@@ -4419,22 +4499,22 @@ function listSessions(fs13, sessionsDir) {
4419
4499
  }
4420
4500
  return sessions.sort((a, b) => a.pid - b.pid);
4421
4501
  }
4422
- function sessionsForSupervisor(fs13, sessionsDir, supervisorPid) {
4423
- return listSessions(fs13, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
4502
+ function sessionsForSupervisor(fs14, sessionsDir, supervisorPid) {
4503
+ return listSessions(fs14, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
4424
4504
  }
4425
- function pruneDeadSessions(fs13, sessionsDir, isRunning) {
4505
+ function pruneDeadSessions(fs14, sessionsDir, isRunning) {
4426
4506
  const removed = [];
4427
- for (const session of listSessions(fs13, sessionsDir)) {
4507
+ for (const session of listSessions(fs14, sessionsDir)) {
4428
4508
  if (!isRunning(session.pid)) {
4429
- removeSession(fs13, sessionsDir, session.pid);
4509
+ removeSession(fs14, sessionsDir, session.pid);
4430
4510
  removed.push(session.pid);
4431
4511
  }
4432
4512
  }
4433
4513
  return removed;
4434
4514
  }
4435
- function readStartLock(fs13, lockFile) {
4515
+ function readStartLock(fs14, lockFile) {
4436
4516
  try {
4437
- return parseJson(fs13.readFileUtf8(lockFile), HeadroomLockSchema);
4517
+ return parseJson(fs14.readFileUtf8(lockFile), HeadroomLockSchema);
4438
4518
  } catch {
4439
4519
  return void 0;
4440
4520
  }
@@ -4524,12 +4604,12 @@ function earlierReleaseAllowlistHash(providers, doorOrigin) {
4524
4604
  }
4525
4605
  return hashAllowlist([...entries].sort());
4526
4606
  }
4527
- function earlierReleaseDaemon(fs13, paths, daemon) {
4607
+ function earlierReleaseDaemon(fs14, paths, daemon) {
4528
4608
  if (daemonIdentity(daemon.commandLine, daemon.socketPath) !== "earlier-release") {
4529
4609
  return void 0;
4530
4610
  }
4531
- const providers = readAllProviders(fs13, paths.providersDir).map((entry) => entry.provider);
4532
- const expected = earlierReleaseAllowlistHash(providers, frontDoorOrigin(readFrontDoorState(fs13, paths.frontdoorStateFile)));
4611
+ const providers = readAllProviders(fs14, paths.providersDir).map((entry) => entry.provider);
4612
+ const expected = earlierReleaseAllowlistHash(providers, frontDoorOrigin(readFrontDoorState(fs14, paths.frontdoorStateFile)));
4533
4613
  return { admitsServingDoor: daemon.recordedHash === expected };
4534
4614
  }
4535
4615
  var EARLIER_RELEASE_ALLOWLIST, EARLIER_RELEASE_ANTHROPIC_UPSTREAM;
@@ -4554,8 +4634,8 @@ function awaitingCause(daemonPid, identity, allowlistFile) {
4554
4634
  }
4555
4635
  return `the headroom supervisor has not written an allowlist admitting this launch's upstreams to ${allowlistFile} within ${String(HEADROOM_START_TIMEOUT_MS)}ms`;
4556
4636
  }
4557
- function daemonAdmits(fs13, allowlistFile, recordedHash, required) {
4558
- const content = fs13.readFileUtf8(allowlistFile);
4637
+ function daemonAdmits(fs14, allowlistFile, recordedHash, required) {
4638
+ const content = fs14.readFileUtf8(allowlistFile);
4559
4639
  if (content === void 0 || recordedHash === void 0) {
4560
4640
  return false;
4561
4641
  }
@@ -4818,7 +4898,7 @@ function verifyAllowlistFile(allowlistFile, ports) {
4818
4898
  const replaceable = fileStat === void 0 || fileStat.kind === "file" || fileStat.kind === "symlink";
4819
4899
  return { message: refusal2, repairable: replaceable };
4820
4900
  }
4821
- function prepareHeadroomSocket(fs13, ports, paths, supervisorPid) {
4901
+ function prepareHeadroomSocket(fs14, ports, paths, supervisorPid) {
4822
4902
  const unsupported = platformRefusal(ports.platform);
4823
4903
  if (unsupported !== void 0) {
4824
4904
  return { refused: unsupported };
@@ -4833,18 +4913,18 @@ function prepareHeadroomSocket(fs13, ports, paths, supervisorPid) {
4833
4913
  if (ports.lstat(paths.headroomSocketDir)?.kind === "symlink") {
4834
4914
  return { refused: `the headroom socket directory ${paths.headroomSocketDir} is a symlink; it must be the real directory` };
4835
4915
  }
4836
- fs13.mkdirPrivate(paths.headroomSocketDir);
4916
+ fs14.mkdirPrivate(paths.headroomSocketDir);
4837
4917
  const refusal2 = ownerOnlyRefusal("socket directory", paths.headroomSocketDir, ports.lstat(paths.headroomSocketDir), "dir", ports.currentUid());
4838
4918
  return refusal2 === void 0 ? { socketPath } : { refused: refusal2 };
4839
4919
  }
4840
- function pruneStaleHeadroomSockets(fs13, paths, isRunning) {
4920
+ function pruneStaleHeadroomSockets(fs14, paths, isRunning) {
4841
4921
  const removed = [];
4842
- for (const name of fs13.readdir(paths.headroomSocketDir)) {
4922
+ for (const name of fs14.readdir(paths.headroomSocketDir)) {
4843
4923
  const pid = HEADROOM_SOCKET_NAME.exec(name)?.[1];
4844
4924
  if (pid === void 0 || isRunning(Number.parseInt(pid, 10))) {
4845
4925
  continue;
4846
4926
  }
4847
- fs13.removeRecursive(path12.join(paths.headroomSocketDir, name));
4927
+ fs14.removeRecursive(path12.join(paths.headroomSocketDir, name));
4848
4928
  removed.push(name);
4849
4929
  }
4850
4930
  return removed;
@@ -4956,37 +5036,37 @@ function compareVersions2(a, b) {
4956
5036
  return 0;
4957
5037
  }
4958
5038
  async function runSupervisor(initialConfig, ports, options = {}) {
4959
- const { fs: fs13, paths } = ports;
5039
+ const { fs: fs14, paths } = ports;
4960
5040
  let config = initialConfig;
4961
- migrateHeadroomState(fs13, { stateFile: paths.headroomStateFile, legacyStateFile: paths.headroomLegacyStateFile }, ports.isRunning);
4962
- const previousState = resolveServingHeadroomState(fs13, { stateFile: paths.headroomStateFile, legacyStateFile: paths.headroomLegacyStateFile }, ports.isRunning)?.state;
5041
+ migrateHeadroomState(fs14, { stateFile: paths.headroomStateFile, legacyStateFile: paths.headroomLegacyStateFile }, ports.isRunning);
5042
+ const previousState = resolveServingHeadroomState(fs14, { stateFile: paths.headroomStateFile, legacyStateFile: paths.headroomLegacyStateFile }, ports.isRunning)?.state;
4963
5043
  if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
4964
5044
  ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
4965
5045
  return 0;
4966
5046
  }
4967
5047
  let installedSource = previousState?.installedSource;
4968
5048
  const ownsState = () => {
4969
- const owner = readHeadroomState(fs13, paths.headroomStateFile)?.supervisorPid;
5049
+ const owner = readHeadroomState(fs14, paths.headroomStateFile)?.supervisorPid;
4970
5050
  return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
4971
5051
  };
4972
5052
  const writeOwnState = (state) => {
4973
5053
  if (!ownsState()) {
4974
5054
  return false;
4975
5055
  }
4976
- writeHeadroomState(fs13, paths.headroomStateFile, state);
5056
+ writeHeadroomState(fs14, paths.headroomStateFile, state);
4977
5057
  return true;
4978
5058
  };
4979
5059
  const fail = (message) => {
4980
5060
  if (writeOwnState({ lastError: message })) {
4981
- fs13.removeRecursive(paths.headroomLockFile);
5061
+ fs14.removeRecursive(paths.headroomLockFile);
4982
5062
  }
4983
5063
  ports.log(`agent-shim headroom supervisor: ${message}`);
4984
5064
  return 1;
4985
5065
  };
4986
5066
  const syncAllowlistFile = (allowlist) => {
4987
5067
  try {
4988
- if (fs13.readFileUtf8(paths.headroomAllowlistFile) !== formatAllowlistFile(allowlist)) {
4989
- writeAllowlistFile(fs13, paths.headroomAllowlistFile, allowlist);
5068
+ if (fs14.readFileUtf8(paths.headroomAllowlistFile) !== formatAllowlistFile(allowlist)) {
5069
+ writeAllowlistFile(fs14, paths.headroomAllowlistFile, allowlist);
4990
5070
  ports.log(`agent-shim headroom supervisor: wrote allowlist [${allowlist.join(", ")}] to ${paths.headroomAllowlistFile}`);
4991
5071
  }
4992
5072
  return void 0;
@@ -5004,9 +5084,9 @@ async function runSupervisor(initialConfig, ports, options = {}) {
5004
5084
  }
5005
5085
  ports.log(`agent-shim headroom supervisor: repairing the allowlist file: ${problem.message}`);
5006
5086
  try {
5007
- fs13.mkdirPrivate(paths.headroomDir);
5008
- fs13.mkdirPrivate(path13.dirname(paths.headroomAllowlistFile));
5009
- writeAllowlistFile(fs13, paths.headroomAllowlistFile, allowlist);
5087
+ fs14.mkdirPrivate(paths.headroomDir);
5088
+ fs14.mkdirPrivate(path13.dirname(paths.headroomAllowlistFile));
5089
+ writeAllowlistFile(fs14, paths.headroomAllowlistFile, allowlist);
5010
5090
  } catch (error) {
5011
5091
  return `could not write the headroom allowlist file ${paths.headroomAllowlistFile}: ${error instanceof Error ? error.message : String(error)}`;
5012
5092
  }
@@ -5031,20 +5111,20 @@ async function runSupervisor(initialConfig, ports, options = {}) {
5031
5111
  installedSource = config.source;
5032
5112
  return void 0;
5033
5113
  };
5034
- const socket = prepareHeadroomSocket(fs13, ports.socketTrust, paths, ports.ownPid);
5114
+ const socket = prepareHeadroomSocket(fs14, ports.socketTrust, paths, ports.ownPid);
5035
5115
  if (socket.refused !== void 0) {
5036
5116
  return fail(socket.refused);
5037
5117
  }
5038
5118
  const { socketPath } = socket;
5039
- pruneStaleHeadroomSockets(fs13, paths, ports.isRunning);
5040
- pruneStaleAllowlistTemporaries(fs13, paths.headroomAllowlistFile, ports.isRunning);
5119
+ pruneStaleHeadroomSockets(fs14, paths, ports.isRunning);
5120
+ pruneStaleAllowlistTemporaries(fs14, paths.headroomAllowlistFile, ports.isRunning);
5041
5121
  const installFailure = ensureInstalled();
5042
5122
  if (installFailure !== void 0) {
5043
5123
  return fail(installFailure);
5044
5124
  }
5045
5125
  const version = ports.headroomVersion() ?? "unknown";
5046
5126
  writeOwnState({ supervisorPid: ports.ownPid, version, installedSource });
5047
- ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: managing headroom on allowlist [${currentHeadroomAllowlistInputs(fs13, paths, ports.frontDoorLiveness).frontDoorOrigins.join(", ")}]`);
5127
+ ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: managing headroom on allowlist [${currentHeadroomAllowlistInputs(fs14, paths, ports.frontDoorLiveness).frontDoorOrigins.join(", ")}]`);
5048
5128
  const orphanPid = previousState?.headroomPid;
5049
5129
  const orphanSocket = previousState?.socketPath ?? (previousState?.supervisorPid === void 0 ? void 0 : headroomSocketPath(paths, previousState.supervisorPid));
5050
5130
  const orphanIdentity = orphanPid === void 0 || orphanSocket === void 0 || !ports.isRunning(orphanPid) ? void 0 : daemonIdentity(ports.daemonCommandLine(orphanPid), orphanSocket);
@@ -5079,12 +5159,12 @@ async function runSupervisor(initialConfig, ports, options = {}) {
5079
5159
  ticks += 1;
5080
5160
  config = ports.readConfig();
5081
5161
  const settingsHash = hashSettings(config.settings);
5082
- const inputs = currentHeadroomAllowlistInputs(fs13, paths, ports.frontDoorLiveness);
5083
- pruneDeadFrontDoorDirectRecords(fs13, paths.frontdoorDirectRecordsDir, inputs.frontDoorRecords, inputs.frontDoorLiveness);
5084
- pruneMalformedFrontDoorDirectFiles(fs13, paths.frontdoorDirectRecordsDir, ports.isRunning);
5162
+ const inputs = currentHeadroomAllowlistInputs(fs14, paths, ports.frontDoorLiveness);
5163
+ pruneDeadFrontDoorDirectRecords(fs14, paths.frontdoorDirectRecordsDir, inputs.frontDoorRecords, inputs.frontDoorLiveness);
5164
+ pruneMalformedFrontDoorDirectFiles(fs14, paths.frontdoorDirectRecordsDir, ports.isRunning);
5085
5165
  const allowlist = inputs.frontDoorOrigins;
5086
5166
  const allowlistHash = hashAllowlist(allowlist);
5087
- pruneDeadSessions(fs13, paths.headroomSessionsDir, ports.isRunning);
5167
+ pruneDeadSessions(fs14, paths.headroomSessionsDir, ports.isRunning);
5088
5168
  const ownsNow = ownsState();
5089
5169
  if (!ownsNow && !superseded) {
5090
5170
  ports.log("agent-shim headroom supervisor: another supervisor now owns the state file; serving this daemon's own sessions until they end");
@@ -5131,7 +5211,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
5131
5211
  runningSettingsHash = settingsHash;
5132
5212
  const recorded = writeOwnState(servingState(pid));
5133
5213
  if (recorded) {
5134
- fs13.removeRecursive(paths.headroomLockFile);
5214
+ fs14.removeRecursive(paths.headroomLockFile);
5135
5215
  }
5136
5216
  idleSince = void 0;
5137
5217
  ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on unix socket ${socketPath}`);
@@ -5159,7 +5239,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
5159
5239
  ports.log(`agent-shim headroom supervisor: headroom pid ${String(headroomPid)} now serves allowlist [${allowlist.join(", ")}]`);
5160
5240
  }
5161
5241
  if (runningSettingsHash !== settingsHash || installedSource !== config.source) {
5162
- if (sessionsForSupervisor(fs13, paths.headroomSessionsDir, ports.ownPid).length === 0) {
5242
+ if (sessionsForSupervisor(fs14, paths.headroomSessionsDir, ports.ownPid).length === 0) {
5163
5243
  ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
5164
5244
  ports.stopProcess(headroomPid);
5165
5245
  headroomPid = void 0;
@@ -5168,7 +5248,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
5168
5248
  continue;
5169
5249
  }
5170
5250
  }
5171
- const sessions = sessionsForSupervisor(fs13, paths.headroomSessionsDir, ports.ownPid);
5251
+ const sessions = sessionsForSupervisor(fs14, paths.headroomSessionsDir, ports.ownPid);
5172
5252
  if (sessions.length === 0) {
5173
5253
  idleSince ??= ports.now();
5174
5254
  const idleMs = ports.now() - idleSince;
@@ -5193,9 +5273,9 @@ function undeterminedFrontDoors(inputs) {
5193
5273
  return reason === void 0 ? [] : [{ pid: record.pid, origin: directOrigin(record.directPort), reason }];
5194
5274
  });
5195
5275
  }
5196
- function currentHeadroomAllowlistInputs(fs13, paths, frontDoorLiveness) {
5197
- const named = frontDoorOrigin(readFrontDoorState(fs13, paths.frontdoorStateFile));
5198
- const records = listFrontDoorDirectRecords(fs13, paths.frontdoorDirectRecordsDir);
5276
+ function currentHeadroomAllowlistInputs(fs14, paths, frontDoorLiveness) {
5277
+ const named = frontDoorOrigin(readFrontDoorState(fs14, paths.frontdoorStateFile));
5278
+ const records = listFrontDoorDirectRecords(fs14, paths.frontdoorDirectRecordsDir);
5199
5279
  const liveness = frontDoorLiveness(records.map((record) => record.pid));
5200
5280
  const live = liveFrontDoorDirectRecords(records, liveness).map((record) => directOrigin(record.directPort));
5201
5281
  return {
@@ -5204,8 +5284,8 @@ function currentHeadroomAllowlistInputs(fs13, paths, frontDoorLiveness) {
5204
5284
  frontDoorOrigins: [.../* @__PURE__ */ new Set([...named === void 0 ? [] : [named], ...live])].sort()
5205
5285
  };
5206
5286
  }
5207
- function launchRequiredUpstreams(fs13, paths) {
5208
- const door = frontDoorOrigin(readFrontDoorState(fs13, paths.frontdoorStateFile));
5287
+ function launchRequiredUpstreams(fs14, paths) {
5288
+ const door = frontDoorOrigin(readFrontDoorState(fs14, paths.frontdoorStateFile));
5209
5289
  return door === void 0 ? [] : [door];
5210
5290
  }
5211
5291
  async function waitUntilReady(ports, socketPath, pid) {
@@ -5929,8 +6009,8 @@ import path17 from "node:path";
5929
6009
  function poolNameOf(selector) {
5930
6010
  return selector.startsWith(POOL_SELECTOR_PREFIX) ? selector.slice(POOL_SELECTOR_PREFIX.length) : void 0;
5931
6011
  }
5932
- function readActiveIdentity(fs13, activeIdentityFile) {
5933
- const trimmed = fs13.readFileUtf8(activeIdentityFile)?.trim();
6012
+ function readActiveIdentity(fs14, activeIdentityFile) {
6013
+ const trimmed = fs14.readFileUtf8(activeIdentityFile)?.trim();
5934
6014
  return trimmed === void 0 || trimmed === "" ? void 0 : trimmed;
5935
6015
  }
5936
6016
  function isNonEmpty(value) {
@@ -5977,8 +6057,8 @@ function decideConfigProfile(params) {
5977
6057
  }
5978
6058
  return { source: "none" };
5979
6059
  }
5980
- function loadIdentity(identitiesDir, name, fs13) {
5981
- return loadConfigFile(path17.join(identitiesDir, name, "identity.json"), IdentitySchema, fs13.readConfigFile);
6060
+ function loadIdentity(identitiesDir, name, fs14) {
6061
+ return loadConfigFile(path17.join(identitiesDir, name, "identity.json"), IdentitySchema, fs14.readConfigFile);
5982
6062
  }
5983
6063
  var IDENTITY_DECISION_SOURCES, CONFIG_PROFILE_DECISION_SOURCES;
5984
6064
  var init_identity = __esm({
@@ -6220,14 +6300,14 @@ function isIdentityName(name) {
6220
6300
  function claudeJsonPath(identitiesDir, identity) {
6221
6301
  return path18.join(identitiesDir, identity, CLAUDE_JSON);
6222
6302
  }
6223
- function readAccountMetadata(fs13, identitiesDir, identity) {
6303
+ function readAccountMetadata(fs14, identitiesDir, identity) {
6224
6304
  if (!isIdentityName(identity)) {
6225
6305
  throw new Error(`"${identity}" is not a valid identity name.`);
6226
6306
  }
6227
- return readAccountMetadataFile(fs13, claudeJsonPath(identitiesDir, identity));
6307
+ return readAccountMetadataFile(fs14, claudeJsonPath(identitiesDir, identity));
6228
6308
  }
6229
- function readAccountMetadataFile(fs13, file) {
6230
- const raw = fs13.readFileUtf8(file);
6309
+ function readAccountMetadataFile(fs14, file) {
6310
+ const raw = fs14.readFileUtf8(file);
6231
6311
  if (raw === void 0) {
6232
6312
  return void 0;
6233
6313
  }
@@ -6257,19 +6337,19 @@ function readAccountMetadataFile(fs13, file) {
6257
6337
  }
6258
6338
  return account.data;
6259
6339
  }
6260
- function createAccountReader(fs13, identitiesDir) {
6340
+ function createAccountReader(fs14, identitiesDir) {
6261
6341
  const cache = /* @__PURE__ */ new Map();
6262
6342
  return (identity) => {
6263
6343
  if (!isIdentityName(identity)) {
6264
6344
  throw new Error(`"${identity}" is not a valid identity name.`);
6265
6345
  }
6266
- const stat = fs13.lstat(claudeJsonPath(identitiesDir, identity));
6346
+ const stat = fs14.lstat(claudeJsonPath(identitiesDir, identity));
6267
6347
  const stamp = stat === void 0 ? "absent" : `${String(stat.mtimeMs)}:${String(stat.sizeBytes)}`;
6268
6348
  const cached = cache.get(identity);
6269
6349
  if (cached?.stamp === stamp) {
6270
6350
  return cached.account;
6271
6351
  }
6272
- const account = readAccountMetadata(fs13, identitiesDir, identity);
6352
+ const account = readAccountMetadata(fs14, identitiesDir, identity);
6273
6353
  cache.set(identity, { stamp, account });
6274
6354
  return account;
6275
6355
  };
@@ -6853,8 +6933,8 @@ function segmentDay(epochMs) {
6853
6933
  function segmentName(day, pid) {
6854
6934
  return `${day}.${String(pid)}.jsonl`;
6855
6935
  }
6856
- function listLogSegments(fs13, logDir) {
6857
- return fs13.readdir(logDir).flatMap((name) => {
6936
+ function listLogSegments(fs14, logDir) {
6937
+ return fs14.readdir(logDir).flatMap((name) => {
6858
6938
  const match = SEGMENT_RE.exec(name);
6859
6939
  const day = match?.[1];
6860
6940
  if (day === void 0) {
@@ -6863,15 +6943,15 @@ function listLogSegments(fs13, logDir) {
6863
6943
  return [{ name, day, endsAt: Date.parse(`${day}T00:00:00.000Z`) + DAY_MS }];
6864
6944
  }).sort((left, right) => left.day.localeCompare(right.day) || left.name.localeCompare(right.name));
6865
6945
  }
6866
- function readUsageLog(fs13, logDir, options = {}) {
6946
+ function readUsageLog(fs14, logDir, options = {}) {
6867
6947
  const { sinceMs } = options;
6868
6948
  const records = [];
6869
6949
  let invalidLines = 0;
6870
- for (const segment of listLogSegments(fs13, logDir)) {
6950
+ for (const segment of listLogSegments(fs14, logDir)) {
6871
6951
  if (sinceMs !== void 0 && segment.endsAt <= sinceMs) {
6872
6952
  continue;
6873
6953
  }
6874
- const contents = fs13.readFileUtf8(path19.join(logDir, segment.name));
6954
+ const contents = fs14.readFileUtf8(path19.join(logDir, segment.name));
6875
6955
  if (contents === void 0) {
6876
6956
  continue;
6877
6957
  }
@@ -6907,9 +6987,9 @@ function snapshotPath(snapshotsDir, identity) {
6907
6987
  }
6908
6988
  return path19.join(snapshotsDir, `${identity}.json`);
6909
6989
  }
6910
- function readUsageSnapshot(fs13, snapshotsDir, identity) {
6990
+ function readUsageSnapshot(fs14, snapshotsDir, identity) {
6911
6991
  const file = snapshotPath(snapshotsDir, identity);
6912
- const raw = fs13.readFileUtf8(file);
6992
+ const raw = fs14.readFileUtf8(file);
6913
6993
  if (raw === void 0) {
6914
6994
  return void 0;
6915
6995
  }
@@ -6925,8 +7005,8 @@ function readUsageSnapshot(fs13, snapshotsDir, identity) {
6925
7005
  }
6926
7006
  return snapshot.data;
6927
7007
  }
6928
- function listUsageSnapshots(fs13, snapshotsDir) {
6929
- return fs13.readdir(snapshotsDir).flatMap((name) => {
7008
+ function listUsageSnapshots(fs14, snapshotsDir) {
7009
+ return fs14.readdir(snapshotsDir).flatMap((name) => {
6930
7010
  if (!name.endsWith(".json")) {
6931
7011
  return [];
6932
7012
  }
@@ -6934,7 +7014,7 @@ function listUsageSnapshots(fs13, snapshotsDir) {
6934
7014
  if (!isIdentityName(identity)) {
6935
7015
  return [];
6936
7016
  }
6937
- const snapshot = readUsageSnapshot(fs13, snapshotsDir, identity);
7017
+ const snapshot = readUsageSnapshot(fs14, snapshotsDir, identity);
6938
7018
  return snapshot === void 0 ? [] : [snapshot];
6939
7019
  }).sort((left, right) => left.identity.localeCompare(right.identity));
6940
7020
  }
@@ -6959,11 +7039,11 @@ var init_read = __esm({
6959
7039
 
6960
7040
  // src/usage/store.ts
6961
7041
  import path20 from "node:path";
6962
- function pruneUsageLog(fs13, logDir, nowMs) {
7042
+ function pruneUsageLog(fs14, logDir, nowMs) {
6963
7043
  const cutoff = nowMs - USAGE_RETENTION_MS;
6964
- for (const segment of listLogSegments(fs13, logDir)) {
7044
+ for (const segment of listLogSegments(fs14, logDir)) {
6965
7045
  if (segment.endsAt <= cutoff) {
6966
- fs13.removeRecursive(path20.join(logDir, segment.name));
7046
+ fs14.removeRecursive(path20.join(logDir, segment.name));
6967
7047
  }
6968
7048
  }
6969
7049
  }
@@ -6992,7 +7072,7 @@ function foldProviderState(current, record) {
6992
7072
  };
6993
7073
  }
6994
7074
  function createUsageStore(deps) {
6995
- const { fs: fs13, paths } = deps;
7075
+ const { fs: fs14, paths } = deps;
6996
7076
  let prunedDay;
6997
7077
  const rewriteSnapshot = (identity, fold) => {
6998
7078
  if (!isIdentityName(identity)) {
@@ -7001,7 +7081,7 @@ function createUsageStore(deps) {
7001
7081
  }
7002
7082
  let current;
7003
7083
  try {
7004
- current = readUsageSnapshot(fs13, paths.usageSnapshotsDir, identity);
7084
+ current = readUsageSnapshot(fs14, paths.usageSnapshotsDir, identity);
7005
7085
  } catch (error) {
7006
7086
  if (!(error instanceof UsageSnapshotError)) {
7007
7087
  throw error;
@@ -7028,8 +7108,8 @@ function createUsageStore(deps) {
7028
7108
  ...account === void 0 ? {} : { account },
7029
7109
  providers
7030
7110
  });
7031
- fs13.mkdirPrivate(paths.usageSnapshotsDir);
7032
- fs13.writeFilePrivate(snapshotPath(paths.usageSnapshotsDir, identity), `${JSON.stringify(snapshot, null, 2)}
7111
+ fs14.mkdirPrivate(paths.usageSnapshotsDir);
7112
+ fs14.writeFilePrivate(snapshotPath(paths.usageSnapshotsDir, identity), `${JSON.stringify(snapshot, null, 2)}
7033
7113
  `);
7034
7114
  deps.publish?.(snapshot);
7035
7115
  return true;
@@ -7038,14 +7118,14 @@ function createUsageStore(deps) {
7038
7118
  record: (input) => {
7039
7119
  const record = UsageRecordSchema.parse(input);
7040
7120
  const nowMs = deps.now();
7041
- fs13.mkdirPrivate(paths.usageDir);
7042
- fs13.mkdirPrivate(paths.usageLogDir);
7121
+ fs14.mkdirPrivate(paths.usageDir);
7122
+ fs14.mkdirPrivate(paths.usageLogDir);
7043
7123
  const day = segmentDay(nowMs);
7044
7124
  if (prunedDay !== day) {
7045
- pruneUsageLog(fs13, paths.usageLogDir, nowMs);
7125
+ pruneUsageLog(fs14, paths.usageLogDir, nowMs);
7046
7126
  prunedDay = day;
7047
7127
  }
7048
- fs13.appendFilePrivate(path20.join(paths.usageLogDir, segmentName(day, deps.pid)), `${JSON.stringify(record)}
7128
+ fs14.appendFilePrivate(path20.join(paths.usageLogDir, segmentName(day, deps.pid)), `${JSON.stringify(record)}
7049
7129
  `);
7050
7130
  deps.onRecord?.(record);
7051
7131
  if (record.identity !== void 0) {
@@ -7089,14 +7169,14 @@ import { z as z13 } from "zod";
7089
7169
  function errorMessage(error) {
7090
7170
  return error instanceof Error ? error.message : String(error);
7091
7171
  }
7092
- function loadPoolMembers(fs13, paths, identities, nowMs) {
7172
+ function loadPoolMembers(fs14, paths, identities, nowMs) {
7093
7173
  const windowStartMs = nowMs - FIVE_HOUR_WINDOW_MS;
7094
- const log = readUsageLog(fs13, paths.usageLogDir, { sinceMs: windowStartMs });
7174
+ const log = readUsageLog(fs14, paths.usageLogDir, { sinceMs: windowStartMs });
7095
7175
  return identities.map((identity) => {
7096
7176
  const records = log.records.filter((record) => record.identity === identity && record.provider === ANTHROPIC_PROVIDER && Date.parse(record.at) >= windowStartMs);
7097
7177
  try {
7098
- const snapshot = readUsageSnapshot(fs13, paths.usageSnapshotsDir, identity);
7099
- const account = readAccountMetadata(fs13, paths.identitiesDir, identity) ?? snapshot?.account;
7178
+ const snapshot = readUsageSnapshot(fs14, paths.usageSnapshotsDir, identity);
7179
+ const account = readAccountMetadata(fs14, paths.identitiesDir, identity) ?? snapshot?.account;
7100
7180
  return { identity, records, ...snapshot === void 0 ? {} : { snapshot }, ...account === void 0 ? {} : { account } };
7101
7181
  } catch (error) {
7102
7182
  if (error instanceof UsageSnapshotError || error instanceof AccountMetadataError) {
@@ -7190,9 +7270,9 @@ function collectPoolIdentities(pools, poolName, stack, found) {
7190
7270
  collectPoolIdentities(pools, nestedName, childStack, found);
7191
7271
  }
7192
7272
  }
7193
- function readPicksFile(fs13, file) {
7273
+ function readPicksFile(fs14, file) {
7194
7274
  const empty = { schemaVersion: SCHEMA_VERSION, picks: {} };
7195
- const raw = fs13.readFileUtf8(file);
7275
+ const raw = fs14.readFileUtf8(file);
7196
7276
  if (raw === void 0) {
7197
7277
  return { file: empty };
7198
7278
  }
@@ -7205,17 +7285,17 @@ function readPicksFile(fs13, file) {
7205
7285
  const result = PicksFileSchema.safeParse(parsed);
7206
7286
  return result.success ? { file: result.data } : { file: empty, problem: `${file} is not a picks file this agent-shim can read` };
7207
7287
  }
7208
- function readStickyPick(fs13, picksFile, directory) {
7209
- const read = readPicksFile(fs13, picksFile);
7288
+ function readStickyPick(fs14, picksFile, directory) {
7289
+ const read = readPicksFile(fs14, picksFile);
7210
7290
  const entry = read.file.picks[directory];
7211
7291
  return { ...entry === void 0 ? {} : { sticky: entry }, ...read.problem === void 0 ? {} : { problem: read.problem } };
7212
7292
  }
7213
- function recordStickyPick(fs13, picksFile, directory, identity, nowMs) {
7214
- const current = readPicksFile(fs13, picksFile).file.picks;
7293
+ function recordStickyPick(fs14, picksFile, directory, identity, nowMs) {
7294
+ const current = readPicksFile(fs14, picksFile).file.picks;
7215
7295
  const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
7216
7296
  const next = { schemaVersion: SCHEMA_VERSION, picks: { ...Object.fromEntries(kept), [directory]: { identity, at: new Date(nowMs).toISOString() } } };
7217
- fs13.mkdirPrivate(path21.dirname(picksFile));
7218
- fs13.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
7297
+ fs14.mkdirPrivate(path21.dirname(picksFile));
7298
+ fs14.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
7219
7299
  `);
7220
7300
  }
7221
7301
  var PoolGraphError, SCHEMA_VERSION, PickEntrySchema, PicksFileSchema;
@@ -7491,6 +7571,7 @@ function buildLayoutPaths(root) {
7491
7571
  frontdoorControlTokenFile: path23.join(root, "frontdoor", "control-token"),
7492
7572
  frontdoorSessionsDir: path23.join(root, "frontdoor", "sessions"),
7493
7573
  frontdoorDirectRecordsDir: path23.join(root, "frontdoor", "direct"),
7574
+ frontdoorDrainingDir: path23.join(root, "frontdoor", "draining"),
7494
7575
  frontdoorRcCredentialsDir: path23.join(root, "frontdoor", "rc-credentials"),
7495
7576
  frontdoorLogPath: path23.join(root, "logs", "frontdoor.log"),
7496
7577
  usageDir: path23.join(root, "usage"),
@@ -8565,12 +8646,12 @@ function decideSignIn(facts) {
8565
8646
  function credentialsFilePath(farmRoot) {
8566
8647
  return path26.join(farmRoot, CREDENTIALS_FILE);
8567
8648
  }
8568
- function identitySignIn(fs13, probe, identity) {
8649
+ function identitySignIn(fs14, probe, identity) {
8569
8650
  const probing = !identity.hasCredentialBlock;
8570
8651
  return decideSignIn({
8571
8652
  hasCredentialBlock: identity.hasCredentialBlock,
8572
8653
  keychainItem: probing && probe.platform === "darwin" && probe.run !== void 0 ? keychainHasItem(probe.run, identity.farmRoot) : void 0,
8573
- credentialsFile: probing && fs13.lstat(credentialsFilePath(identity.farmRoot)) !== void 0,
8654
+ credentialsFile: probing && fs14.lstat(credentialsFilePath(identity.farmRoot)) !== void 0,
8574
8655
  platform: probe.platform
8575
8656
  });
8576
8657
  }
@@ -9411,6 +9492,16 @@ var init_update = __esm({
9411
9492
  }
9412
9493
  });
9413
9494
 
9495
+ // src/frontdoor/replacement.ts
9496
+ function replacementLine(facts) {
9497
+ return `launcher ${String(facts.launcherPid)}: replacing front door; reason=${facts.reason} signal=${facts.signal} door=${String(facts.doorPid)} doorProtocol=${String(facts.doorProtocol)} launcherProtocol=${String(facts.launcherProtocol)} liveSessions=${String(facts.liveSessions)}`;
9498
+ }
9499
+ var init_replacement = __esm({
9500
+ "src/frontdoor/replacement.ts"() {
9501
+ "use strict";
9502
+ }
9503
+ });
9504
+
9414
9505
  // src/frontdoor/ensure.ts
9415
9506
  import { randomUUID as randomUUID3 } from "node:crypto";
9416
9507
  function ensureFrontDoor(params) {
@@ -9422,7 +9513,7 @@ function ensureFrontDoor(params) {
9422
9513
  let lastRejection;
9423
9514
  let busyDoor;
9424
9515
  const liveSessionsOn = (doorPid) => listFrontDoorSessions(ports.fs, paths.frontdoorSessionsDir).filter(
9425
- (session) => session.pid !== params.launcherPid && ports.isRunning(session.pid) && (session.supervisorPid === void 0 || session.supervisorPid === doorPid)
9516
+ (session) => session.pid !== params.launcherPid && ports.isRunning(session.pid) && (session.supervisorPid === void 0 || session.supervisorPid === doorPid || !ports.isRunning(session.supervisorPid))
9426
9517
  ).length;
9427
9518
  const verifyWithRetry = (port) => {
9428
9519
  let verdict = ports.verifyListener(port);
@@ -9432,12 +9523,20 @@ function ensureFrontDoor(params) {
9432
9523
  }
9433
9524
  return verdict;
9434
9525
  };
9435
- const stopAndAwaitExit = (supervisorPid, failure) => {
9526
+ const recordReplacement = (doorPid, doorProtocol, reason, signal) => {
9527
+ ports.recordReplacement(
9528
+ replacementLine({ reason, signal, launcherPid: params.launcherPid, launcherProtocol: FRONT_DOOR_PROTOCOL, doorPid, doorProtocol, liveSessions: liveSessionsOn(doorPid) })
9529
+ );
9530
+ };
9531
+ const stopAndAwaitExit = (supervisorPid, doorProtocol, reason, failure) => {
9532
+ recordReplacement(supervisorPid, doorProtocol, reason, "SIGTERM");
9436
9533
  ports.stopSupervisor(supervisorPid);
9437
9534
  const graceEnds = ports.now() + FRONTDOOR_EXIT_GRACE_MS;
9438
9535
  let killed = false;
9439
- while (ports.isRunning(supervisorPid)) {
9536
+ const holdsAddresses = () => ports.isRunning(supervisorPid) && readFrontDoorState(ports.fs, paths.frontdoorStateFile)?.supervisorPid === supervisorPid;
9537
+ while (holdsAddresses()) {
9440
9538
  if (!killed && ports.now() >= graceEnds) {
9539
+ recordReplacement(supervisorPid, doorProtocol, reason, "SIGKILL");
9441
9540
  ports.killSupervisor(supervisorPid);
9442
9541
  killed = true;
9443
9542
  }
@@ -9452,16 +9551,19 @@ function ensureFrontDoor(params) {
9452
9551
  const supervisorPid = state?.supervisorPid;
9453
9552
  if (supervisorPid !== void 0 && !distrusted.has(supervisorPid) && ports.isRunning(supervisorPid)) {
9454
9553
  if (state?.port !== void 0 && state.connectPort !== void 0) {
9455
- if (supervisorPid === params.launcherPid && params.replace !== true && ports.isFrontDoorSupervisor(supervisorPid)) {
9554
+ if (supervisorPid === params.launcherPid && params.replace === void 0 && ports.isFrontDoorSupervisor(supervisorPid)) {
9456
9555
  const token = randomUUID3();
9457
9556
  writeFrontDoorSession(ports.fs, paths.frontdoorSessionsDir, { pid: params.launcherPid, startedAt: ports.now(), token, supervisorPid, ...recordOf(params.session) });
9458
9557
  return { port: state.port, connectPort: state.connectPort, token };
9459
9558
  }
9460
9559
  const verdict = verifyWithRetry(state.port);
9461
- if (verdict.ok && !replaced && !spawned && (params.replace === true || (state.protocol ?? 0) < FRONT_DOOR_PROTOCOL)) {
9560
+ const doorProtocol = state.protocol ?? 0;
9561
+ if (verdict.ok && !replaced && !spawned && (params.replace !== void 0 || doorProtocol < FRONT_DOOR_PROTOCOL)) {
9462
9562
  stopAndAwaitExit(
9463
9563
  supervisorPid,
9464
- `the front door (pid ${String(supervisorPid)}, protocol ${String(state.protocol ?? 0)}; this launcher speaks protocol ${String(FRONT_DOOR_PROTOCOL)}) was asked to be replaced and did not exit`
9564
+ doorProtocol,
9565
+ params.replace ?? "protocol-older",
9566
+ `the front door (pid ${String(supervisorPid)}, protocol ${String(doorProtocol)}; this launcher speaks protocol ${String(FRONT_DOOR_PROTOCOL)}) was asked to be replaced and did not exit`
9465
9567
  );
9466
9568
  replaced = true;
9467
9569
  continue;
@@ -9477,15 +9579,15 @@ function ensureFrontDoor(params) {
9477
9579
  }
9478
9580
  if (ports.isFrontDoorSupervisor(supervisorPid)) {
9479
9581
  const stranded = liveSessionsOn(supervisorPid);
9480
- if (params.replace === true && !replaced) {
9481
- stopAndAwaitExit(supervisorPid, `the front door (pid ${String(supervisorPid)}) stopped answering and did not exit when asked to`);
9582
+ if (params.replace !== void 0 && !replaced) {
9583
+ stopAndAwaitExit(supervisorPid, doorProtocol, "probe-failed-restart", `the front door (pid ${String(supervisorPid)}) stopped answering and did not exit when asked to`);
9482
9584
  replaced = true;
9483
9585
  continue;
9484
9586
  }
9485
9587
  if (stranded > 0) {
9486
9588
  busyDoor = { pid: supervisorPid, sessions: stranded };
9487
9589
  } else {
9488
- stopAndAwaitExit(supervisorPid, `the front door (pid ${String(supervisorPid)}) stopped answering and did not exit when asked to`);
9590
+ stopAndAwaitExit(supervisorPid, doorProtocol, "probe-failed-idle", `the front door (pid ${String(supervisorPid)}) stopped answering and did not exit when asked to`);
9489
9591
  continue;
9490
9592
  }
9491
9593
  } else {
@@ -9526,6 +9628,7 @@ var init_ensure2 = __esm({
9526
9628
  "use strict";
9527
9629
  init_cliError();
9528
9630
  init_state2();
9631
+ init_replacement();
9529
9632
  init_state();
9530
9633
  FRONTDOOR_START_TIMEOUT_MS = 3e4;
9531
9634
  FRONTDOOR_LAUNCHER_POLL_MS = 100;
@@ -10054,15 +10157,15 @@ function contextTokensOfTranscript(text) {
10054
10157
  }
10055
10158
  return void 0;
10056
10159
  }
10057
- function newestTranscript(fs13, projectDir) {
10160
+ function newestTranscript(fs14, projectDir) {
10058
10161
  let newest;
10059
10162
  let newestMs = -Infinity;
10060
- for (const name of fs13.readdir(projectDir)) {
10163
+ for (const name of fs14.readdir(projectDir)) {
10061
10164
  if (!name.endsWith(".jsonl")) {
10062
10165
  continue;
10063
10166
  }
10064
10167
  const candidate = path38.join(projectDir, name);
10065
- const stat = fs13.lstat(candidate);
10168
+ const stat = fs14.lstat(candidate);
10066
10169
  if (stat?.kind === "file" && stat.mtimeMs > newestMs) {
10067
10170
  newestMs = stat.mtimeMs;
10068
10171
  newest = candidate;
@@ -10070,14 +10173,14 @@ function newestTranscript(fs13, projectDir) {
10070
10173
  }
10071
10174
  return newest;
10072
10175
  }
10073
- function resumedContextTokens(fs13, params) {
10176
+ function resumedContextTokens(fs14, params) {
10074
10177
  const target = resumeTargetOf(params.passthrough);
10075
10178
  if (target === void 0) {
10076
10179
  return void 0;
10077
10180
  }
10078
10181
  const projectDir = path38.join(params.claudeHome, "projects", projectDirNameOf(params.cwd));
10079
- const file = target.kind === "id" ? path38.join(projectDir, `${target.id}.jsonl`) : newestTranscript(fs13, projectDir);
10080
- const text = file === void 0 ? void 0 : fs13.readFileUtf8(file);
10182
+ const file = target.kind === "id" ? path38.join(projectDir, `${target.id}.jsonl`) : newestTranscript(fs14, projectDir);
10183
+ const text = file === void 0 ? void 0 : fs14.readFileUtf8(file);
10081
10184
  return text === void 0 ? void 0 : contextTokensOfTranscript(text);
10082
10185
  }
10083
10186
  var init_resumeContext = __esm({
@@ -10530,7 +10633,7 @@ function resolveIdentityCredential(identity, credential, env, port) {
10530
10633
  return resolution.ok ? resolution : { ok: false, status: CREDENTIAL_UNAVAILABLE_EXIT, message: resolution.message };
10531
10634
  }
10532
10635
  function pickFromPool(decided, params, parsedArgv, readOnly) {
10533
- const { paths, fs: fs13, proc, log } = params;
10636
+ const { paths, fs: fs14, proc, log } = params;
10534
10637
  if (decided.pool === void 0) {
10535
10638
  return { identityDecision: decided };
10536
10639
  }
@@ -10549,7 +10652,7 @@ function pickFromPool(decided, params, parsedArgv, readOnly) {
10549
10652
  selectedVia: decided.source,
10550
10653
  pools: params.pools,
10551
10654
  paths,
10552
- fs: fs13,
10655
+ fs: fs14,
10553
10656
  usageFs: farmRuntime.fs,
10554
10657
  cwd: farmRuntime.cwd,
10555
10658
  now: farmRuntime.now,
@@ -10572,7 +10675,7 @@ function pickFromPool(decided, params, parsedArgv, readOnly) {
10572
10675
  };
10573
10676
  }
10574
10677
  function decideLaunch(params, readOnly) {
10575
- const { paths, fs: fs13, proc, log } = params;
10678
+ const { paths, fs: fs14, proc, log } = params;
10576
10679
  const { env, argv } = proc;
10577
10680
  const parsedArgv = parseLauncherArgv(argv);
10578
10681
  const cliOverride = buildCliOverride({
@@ -10587,7 +10690,7 @@ function decideLaunch(params, readOnly) {
10587
10690
  argv0Identity: parsedArgv.identity,
10588
10691
  directoryPinnedIdentity: params.directoryPinnedIdentity,
10589
10692
  readActiveIdentityFile: () => {
10590
- const raw = fs13.readFileUtf8(paths.activeIdentityFile);
10693
+ const raw = fs14.readFileUtf8(paths.activeIdentityFile);
10591
10694
  if (raw === void 0) {
10592
10695
  return void 0;
10593
10696
  }
@@ -10622,7 +10725,7 @@ function decideLaunch(params, readOnly) {
10622
10725
  }
10623
10726
  let loadedIdentity;
10624
10727
  if (identityDecision.name !== void 0) {
10625
- loadedIdentity = loadIdentity(paths.identitiesDir, identityDecision.name, fs13);
10728
+ loadedIdentity = loadIdentity(paths.identitiesDir, identityDecision.name, fs14);
10626
10729
  if (loadedIdentity === void 0) {
10627
10730
  log.error(
10628
10731
  `agent-shim: no identity named "${identityDecision.name}" (selected via ${identityDecision.source}). Run \`agent-shim identity add ${identityDecision.name}\` first.`
@@ -10637,7 +10740,7 @@ function decideLaunch(params, readOnly) {
10637
10740
  identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
10638
10741
  globalDefaultConfigProfile: params.globalDefaultConfigProfile
10639
10742
  });
10640
- if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs13.readConfigFile(path39.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
10743
+ if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs14.readConfigFile(path39.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
10641
10744
  log.error(
10642
10745
  `agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
10643
10746
  );
@@ -10646,7 +10749,7 @@ function decideLaunch(params, readOnly) {
10646
10749
  const farmContext = farm !== void 0 && farmIdentity !== void 0 ? { farm, identity: farmIdentity, cascade: farm.loadCascade(configProfileDecision.name, cliOverride) } : void 0;
10647
10750
  const providerParams = {
10648
10751
  paths,
10649
- port: fs13,
10752
+ port: fs14,
10650
10753
  ...parsedArgv.provider === void 0 || parsedArgv.provider === false ? {} : { cliProvider: parsedArgv.provider },
10651
10754
  ...farmContext === void 0 ? {} : { cascade: farmContext.cascade }
10652
10755
  };
@@ -10745,9 +10848,9 @@ function decideLaunch(params, readOnly) {
10745
10848
  const flags = loginlessProvider === void 0 ? requestedFlags : { ...requestedFlags, remoteControl: false };
10746
10849
  const globalModels = loadConfigFile(paths.globalConfigFile, GlobalConfigSchema, params.fs.readConfigFile)?.config.models;
10747
10850
  const models = launchCascade !== void 0 && params.farm !== void 0 ? cascadeModels : globalModels;
10748
- const listedProviders = listProviderNames(fs13.readdir, paths.providersDir).flatMap((name) => {
10851
+ const listedProviders = listProviderNames(fs14.readdir, paths.providersDir).flatMap((name) => {
10749
10852
  try {
10750
- const definition = loadProvider(paths.providersDir, name, fs13);
10853
+ const definition = loadProvider(paths.providersDir, name, fs14);
10751
10854
  return definition === void 0 ? [] : [[name, definition, parseCatalogueCache(params.fs.readFileUtf8(catalogueCachePath(paths, name)))?.models ?? []]];
10752
10855
  } catch {
10753
10856
  return [];
@@ -11024,6 +11127,19 @@ var init_ownCli = __esm({
11024
11127
  }
11025
11128
  });
11026
11129
 
11130
+ // src/frontdoor/doorLog.ts
11131
+ import fs12 from "node:fs";
11132
+ function appendDoorLog(paths, line) {
11133
+ fs12.mkdirSync(paths.logsDir, { recursive: true });
11134
+ fs12.appendFileSync(paths.frontdoorLogPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
11135
+ `);
11136
+ }
11137
+ var init_doorLog = __esm({
11138
+ "src/frontdoor/doorLog.ts"() {
11139
+ "use strict";
11140
+ }
11141
+ });
11142
+
11027
11143
  // src/frontdoor/selfIdentity.ts
11028
11144
  function isFrontDoorSupervisorPid(pid, identify) {
11029
11145
  return declaredPid !== void 0 && pid === declaredPid && pid === process.pid || identify(pid);
@@ -11039,14 +11155,14 @@ var init_selfIdentity = __esm({
11039
11155
  import { createHash as createHash7 } from "node:crypto";
11040
11156
  import path41 from "node:path";
11041
11157
  function resolveTrustBundle(params) {
11042
- const { caCertFile, bundlesDir, variable, inherited, fs: fs13 } = params;
11158
+ const { caCertFile, bundlesDir, variable, inherited, fs: fs14 } = params;
11043
11159
  if (inherited === void 0 || inherited === "" || path41.resolve(inherited) === path41.resolve(caCertFile)) {
11044
11160
  return { path: caCertFile };
11045
11161
  }
11046
- const caPem = fs13.readFileUtf8(caCertFile);
11162
+ const caPem = fs14.readFileUtf8(caCertFile);
11047
11163
  let inheritedPem;
11048
11164
  try {
11049
- inheritedPem = fs13.readFileUtf8(inherited);
11165
+ inheritedPem = fs14.readFileUtf8(inherited);
11050
11166
  } catch (error) {
11051
11167
  return {
11052
11168
  path: caCertFile,
@@ -11059,9 +11175,9 @@ function resolveTrustBundle(params) {
11059
11175
  const combined = `${inheritedPem.trimEnd()}
11060
11176
  ${caPem}`;
11061
11177
  const bundle = path41.join(bundlesDir, `${createHash7("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
11062
- if (!fs13.exists(bundle)) {
11063
- fs13.mkdirp(bundlesDir);
11064
- fs13.writeFileAtomic(bundle, combined);
11178
+ if (!fs14.exists(bundle)) {
11179
+ fs14.mkdirp(bundlesDir);
11180
+ fs14.writeFileAtomic(bundle, combined);
11065
11181
  }
11066
11182
  return { path: bundle };
11067
11183
  }
@@ -11074,7 +11190,7 @@ var init_trust = __esm({
11074
11190
  });
11075
11191
 
11076
11192
  // src/frontdoor/realFrontDoorPort.ts
11077
- import fs12 from "node:fs";
11193
+ import fs13 from "node:fs";
11078
11194
  function realEnsurePorts(paths, spawnDaemon) {
11079
11195
  return {
11080
11196
  fs: realFarmFs,
@@ -11083,6 +11199,9 @@ function realEnsurePorts(paths, spawnDaemon) {
11083
11199
  sleep: realSleepSync,
11084
11200
  spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
11085
11201
  isFrontDoorSupervisor: (pid) => isFrontDoorSupervisorPid(pid, realIsFrontDoorSupervisor),
11202
+ recordReplacement: (line) => {
11203
+ appendDoorLog(paths, line);
11204
+ },
11086
11205
  stopSupervisor: (pid) => {
11087
11206
  process.kill(pid, "SIGTERM");
11088
11207
  },
@@ -11090,7 +11209,7 @@ function realEnsurePorts(paths, spawnDaemon) {
11090
11209
  process.kill(pid, "SIGKILL");
11091
11210
  },
11092
11211
  // 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.
11093
- verifyListener: (port) => probeFrontDoorSync(port, fs12.readFileSync(paths.frontdoorCaCertFile, "utf8"))
11212
+ verifyListener: (port) => probeFrontDoorSync(port, fs13.readFileSync(paths.frontdoorCaCertFile, "utf8"))
11094
11213
  };
11095
11214
  }
11096
11215
  function realFrontDoorPort(paths, spawnDaemon) {
@@ -11116,16 +11235,17 @@ var init_realFrontDoorPort = __esm({
11116
11235
  "src/frontdoor/realFrontDoorPort.ts"() {
11117
11236
  "use strict";
11118
11237
  init_realPorts();
11238
+ init_doorLog();
11119
11239
  init_ensure2();
11120
11240
  init_state();
11121
11241
  init_probe();
11122
11242
  init_selfIdentity();
11123
11243
  init_trust();
11124
11244
  realTrustBundleFs = {
11125
- readFileUtf8: (file) => fs12.readFileSync(file, "utf8"),
11126
- exists: (file) => fs12.existsSync(file),
11245
+ readFileUtf8: (file) => fs13.readFileSync(file, "utf8"),
11246
+ exists: (file) => fs13.existsSync(file),
11127
11247
  mkdirp: (dir) => {
11128
- fs12.mkdirSync(dir, { recursive: true });
11248
+ fs13.mkdirSync(dir, { recursive: true });
11129
11249
  },
11130
11250
  writeFileAtomic: (file, contents) => {
11131
11251
  realFarmFs.writeFilePrivate(file, contents);
@@ -13485,6 +13605,10 @@ function realConnectEffects(ports = DOOR_SOURCE_PORTS) {
13485
13605
  }
13486
13606
  resolve({
13487
13607
  port: bound,
13608
+ // The listening socket is released by `close` at once; the connections already accepted are untouched and keep the server's `close` callback pending until they end.
13609
+ stopAccepting: () => {
13610
+ server.close();
13611
+ },
13488
13612
  close: async () => {
13489
13613
  await new Promise((closeResolve) => {
13490
13614
  server.close(() => {
@@ -13690,11 +13814,11 @@ function credentialOfJson(parsed) {
13690
13814
  function sequenceNumOfJson(value) {
13691
13815
  return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : void 0;
13692
13816
  }
13693
- function createRcCredentialStore(fs13, dir) {
13694
- fs13.mkdirPrivate(dir);
13817
+ function createRcCredentialStore(fs14, dir) {
13818
+ fs14.mkdirPrivate(dir);
13695
13819
  const fileFor = (sessionId) => path10.join(dir, `${sessionId}.json`);
13696
13820
  const readParsed = (sessionId) => {
13697
- const raw = fs13.readFileUtf8(fileFor(sessionId));
13821
+ const raw = fs14.readFileUtf8(fileFor(sessionId));
13698
13822
  if (raw === void 0) {
13699
13823
  return void 0;
13700
13824
  }
@@ -13719,7 +13843,7 @@ function createRcCredentialStore(fs13, dir) {
13719
13843
  }
13720
13844
  const cursor = sequenceNumOfJson(readParsed(sessionId)?.highestSequenceNum);
13721
13845
  const record = { ...credential, ...cursor === void 0 ? {} : { highestSequenceNum: cursor } };
13722
- fs13.writeFilePrivate(fileFor(sessionId), `${JSON.stringify(record, null, 2)}
13846
+ fs14.writeFilePrivate(fileFor(sessionId), `${JSON.stringify(record, null, 2)}
13723
13847
  `);
13724
13848
  },
13725
13849
  readCursor: (sessionId) => {
@@ -13734,14 +13858,14 @@ function createRcCredentialStore(fs13, dir) {
13734
13858
  }
13735
13859
  const credential = credentialOfJson(readParsed(sessionId));
13736
13860
  const record = credential === void 0 ? { highestSequenceNum } : { ...credential, highestSequenceNum };
13737
- fs13.writeFilePrivate(fileFor(sessionId), `${JSON.stringify(record, null, 2)}
13861
+ fs14.writeFilePrivate(fileFor(sessionId), `${JSON.stringify(record, null, 2)}
13738
13862
  `);
13739
13863
  },
13740
13864
  remove: (sessionId) => {
13741
13865
  if (!isSafeSessionId(sessionId)) {
13742
13866
  return;
13743
13867
  }
13744
- fs13.removeRecursive(fileFor(sessionId));
13868
+ fs14.removeRecursive(fileFor(sessionId));
13745
13869
  }
13746
13870
  };
13747
13871
  }
@@ -15644,14 +15768,18 @@ init_supervisor2();
15644
15768
  init_state();
15645
15769
 
15646
15770
  // src/doctorFrontDoor.ts
15647
- function pushFrontDoor(push, supervisors, registeredPid, liveSessions) {
15771
+ function pushFrontDoor(push, supervisors, registeredPid, liveSessions, draining) {
15648
15772
  if (!supervisors.ok) {
15649
15773
  push("frontdoor", "warn", `Could not list processes to look for duplicate front door supervisors: ${supervisors.message}.`);
15650
15774
  return;
15651
15775
  }
15652
- const { pids } = supervisors;
15776
+ const drainingPids = supervisors.pids.filter((pid) => draining.includes(pid));
15777
+ for (const pid of drainingPids) {
15778
+ push("frontdoor", "warn", `Front door supervisor pid ${String(pid)} is draining: it has released its addresses and exits once the connections it carried have ended.`, String(pid));
15779
+ }
15780
+ const pids = supervisors.pids.filter((pid) => !draining.includes(pid));
15653
15781
  if (pids.length === 0) {
15654
- push("frontdoor", "pass", "No front door supervisor is running.");
15782
+ push("frontdoor", "pass", drainingPids.length === 0 ? "No front door supervisor is running." : "No front door supervisor is serving.");
15655
15783
  return;
15656
15784
  }
15657
15785
  const [only, ...rest] = pids;
@@ -16201,7 +16329,7 @@ function runDoctor(params) {
16201
16329
  }
16202
16330
  if (params.frontDoor !== void 0) {
16203
16331
  const validated3 = params.frontDoor.state.raw === void 0 ? void 0 : validateJson(FrontDoorStateSchema, params.frontDoor.state);
16204
- pushFrontDoor(push, params.frontDoor.supervisors, validated3?.ok === true ? validated3.data.supervisorPid : void 0, params.frontDoor.liveSessions);
16332
+ pushFrontDoor(push, params.frontDoor.supervisors, validated3?.ok === true ? validated3.data.supervisorPid : void 0, params.frontDoor.liveSessions, params.frontDoor.draining ?? []);
16205
16333
  if (params.frontDoor.listeners !== void 0) {
16206
16334
  pushFrontDoorListeners(push, params.frontDoor.listeners);
16207
16335
  }
@@ -16400,7 +16528,7 @@ function collectDoctorReport(params) {
16400
16528
  logPath: paths.headroomLogPath
16401
16529
  }
16402
16530
  },
16403
- ...uid === void 0 ? {} : { frontDoor: { state: { path: paths.frontdoorStateFile, raw: realFsPort.readFileUtf8(paths.frontdoorStateFile) }, supervisors: listFrontDoorSupervisors(realRunPort, uid), liveSessions: listFrontDoorSessions(realFarmFs, paths.frontdoorSessionsDir).filter((session) => realIsProcessRunning(session.pid)), listeners: servingDoorListeners(paths) } }
16531
+ ...uid === void 0 ? {} : { frontDoor: { state: { path: paths.frontdoorStateFile, raw: realFsPort.readFileUtf8(paths.frontdoorStateFile) }, supervisors: listFrontDoorSupervisors(realRunPort, uid), liveSessions: listFrontDoorSessions(realFarmFs, paths.frontdoorSessionsDir).filter((session) => realIsProcessRunning(session.pid)), draining: listDrainingFrontDoors(realFarmFs, paths.frontdoorDrainingDir, realIsProcessRunning), listeners: servingDoorListeners(paths) } }
16404
16532
  });
16405
16533
  return report;
16406
16534
  }
@@ -16446,6 +16574,8 @@ var HeadroomSocketTargetSchema = z26.union([z26.strictObject({ socketPath: z26.s
16446
16574
  var FrontDoorStatusOutputSchema = z26.strictObject({
16447
16575
  state: FrontDoorStateSchema,
16448
16576
  supervisorAlive: z26.boolean(),
16577
+ /** The pids of earlier doors that released their addresses and are finishing the connections they carried: running, but not serving anything new. */
16578
+ draining: z26.readonly(z26.array(z26.number().int().positive())),
16449
16579
  sessions: z26.readonly(z26.array(FrontDoorSessionStatusSchema)),
16450
16580
  headroomSocket: HeadroomSocketTargetSchema.optional(),
16451
16581
  logPath: z26.string(),
@@ -17490,6 +17620,7 @@ function collectFrontDoorStatus(fsPort, socketTrust, paths, isRunning) {
17490
17620
  return {
17491
17621
  state,
17492
17622
  supervisorAlive: state.supervisorPid !== void 0 && isRunning(state.supervisorPid),
17623
+ draining: listDrainingFrontDoors(fsPort, paths.frontdoorDrainingDir, isRunning),
17493
17624
  sessions: listFrontDoorSessions(fsPort, paths.frontdoorSessionsDir).map((session) => ({ ...session, alive: isRunning(session.pid) })),
17494
17625
  headroomSocket: headroomSocketTarget(fsPort, socketTrust, paths),
17495
17626
  logPath: paths.frontdoorLogPath,
@@ -17513,6 +17644,9 @@ function formatFrontDoorStatus(status, caCertPath) {
17513
17644
  } else {
17514
17645
  lines.push(`connect surface: listening on 127.0.0.1:${String(status.state.connectPort)}, CA ${caCertPath}`);
17515
17646
  }
17647
+ if (status.draining.length > 0) {
17648
+ lines.push(`draining: ${status.draining.map(String).join(", ")} (finishing connections opened before the last restart; each exits when they have ended)`);
17649
+ }
17516
17650
  if (status.headroomSocket === void 0) {
17517
17651
  lines.push("headroom hop: the daemon is not serving (sessions asking for headroom fail until it is up)");
17518
17652
  } else if (status.headroomSocket.refused === void 0) {
@@ -17927,6 +18061,7 @@ function createRcEventFanout() {
17927
18061
  }
17928
18062
  function createRcStreamHub(deps) {
17929
18063
  const attachments = /* @__PURE__ */ new Map();
18064
+ let closed = false;
17930
18065
  const lastSavedSequenceNums = /* @__PURE__ */ new Map();
17931
18066
  const persistCursor = (sessionId) => {
17932
18067
  if (deps.saveSequenceNum === void 0) {
@@ -18085,6 +18220,9 @@ function createRcStreamHub(deps) {
18085
18220
  };
18086
18221
  return {
18087
18222
  reconcile: () => {
18223
+ if (closed) {
18224
+ return;
18225
+ }
18088
18226
  const live = new Set(deps.trackedSessions());
18089
18227
  for (const [sessionId, attachment] of attachments) {
18090
18228
  if (!live.has(sessionId)) {
@@ -18107,6 +18245,7 @@ function createRcStreamHub(deps) {
18107
18245
  }
18108
18246
  },
18109
18247
  close: () => {
18248
+ closed = true;
18110
18249
  for (const attachment of attachments.values()) {
18111
18250
  persistCursor(attachment.sessionId);
18112
18251
  const credential = deps.credentialOf(attachment.sessionId);
@@ -19411,8 +19550,8 @@ var SELF_HOST_SUBSCRIPTION_TYPE = "max";
19411
19550
  function isRecord14(value) {
19412
19551
  return typeof value === "object" && value !== null && !Array.isArray(value);
19413
19552
  }
19414
- function readJsonObject(fs13, file) {
19415
- const raw = fs13.readFileUtf8(file);
19553
+ function readJsonObject(fs14, file) {
19554
+ const raw = fs14.readFileUtf8(file);
19416
19555
  if (raw === void 0) {
19417
19556
  return void 0;
19418
19557
  }
@@ -19424,8 +19563,8 @@ function readJsonObject(fs13, file) {
19424
19563
  }
19425
19564
  return isRecord14(parsed) ? parsed : void 0;
19426
19565
  }
19427
- function readRcSelfHostRecord(fs13, frontdoorDir) {
19428
- const parsed = readJsonObject(fs13, path34.join(frontdoorDir, RC_SELF_HOST_RECORD_DIR, RC_SELF_HOST_RECORD_FILE));
19566
+ function readRcSelfHostRecord(fs14, frontdoorDir) {
19567
+ const parsed = readJsonObject(fs14, path34.join(frontdoorDir, RC_SELF_HOST_RECORD_DIR, RC_SELF_HOST_RECORD_FILE));
19429
19568
  if (parsed === void 0) {
19430
19569
  return void 0;
19431
19570
  }
@@ -19526,17 +19665,17 @@ function parseEntry2(project, entry) {
19526
19665
  const base = match?.[1];
19527
19666
  return base === void 0 ? { project, sessionId: entry, superseded: false, entry } : { project, sessionId: base, superseded: true, entry };
19528
19667
  }
19529
- function listSessions2(fs13, configDir) {
19668
+ function listSessions2(fs14, configDir) {
19530
19669
  const found = [];
19531
- for (const project of fs13.readdir(path35.join(configDir, PROJECTS_DIR))) {
19670
+ for (const project of fs14.readdir(path35.join(configDir, PROJECTS_DIR))) {
19532
19671
  const projectDir = path35.join(configDir, PROJECTS_DIR, project);
19533
19672
  const entries = /* @__PURE__ */ new Set();
19534
- for (const name of fs13.readdir(projectDir)) {
19673
+ for (const name of fs14.readdir(projectDir)) {
19535
19674
  if (name.endsWith(TRANSCRIPT_SUFFIX)) {
19536
19675
  entries.add(name.slice(0, -TRANSCRIPT_SUFFIX.length));
19537
19676
  continue;
19538
19677
  }
19539
- const children = fs13.readdir(path35.join(projectDir, name));
19678
+ const children = fs14.readdir(path35.join(projectDir, name));
19540
19679
  if (children.includes(SUBAGENTS_DIR) || children.includes(WORKFLOWS_DIR)) {
19541
19680
  entries.add(name);
19542
19681
  }
@@ -19547,9 +19686,9 @@ function listSessions2(fs13, configDir) {
19547
19686
  }
19548
19687
  return found.sort((left, right) => left.project.localeCompare(right.project) || left.entry.localeCompare(right.entry));
19549
19688
  }
19550
- function locateAgents(fs13, configDir, relativeDir, workflowRunId, report) {
19689
+ function locateAgents(fs14, configDir, relativeDir, workflowRunId, report) {
19551
19690
  const located = [];
19552
- for (const name of listDirOrReport(fs13, configDir, relativeDir, report)) {
19691
+ for (const name of listDirOrReport(fs14, configDir, relativeDir, report)) {
19553
19692
  if (!name.startsWith(AGENT_FILE_PREFIX) || !name.endsWith(META_SUFFIX)) {
19554
19693
  continue;
19555
19694
  }
@@ -19598,17 +19737,17 @@ function toNode(read, children) {
19598
19737
  function describeFailure(error) {
19599
19738
  return error instanceof Error ? error.message : String(error);
19600
19739
  }
19601
- function readFileOrReport(fs13, configDir, relative, report) {
19740
+ function readFileOrReport(fs14, configDir, relative, report) {
19602
19741
  try {
19603
- return fs13.readFileUtf8(path35.join(configDir, relative));
19742
+ return fs14.readFileUtf8(path35.join(configDir, relative));
19604
19743
  } catch (error) {
19605
19744
  report({ path: relative, reason: `could not be read: ${describeFailure(error)}` });
19606
19745
  return void 0;
19607
19746
  }
19608
19747
  }
19609
- function listDirOrReport(fs13, configDir, relative, report) {
19748
+ function listDirOrReport(fs14, configDir, relative, report) {
19610
19749
  try {
19611
- return fs13.readdir(path35.join(configDir, relative));
19750
+ return fs14.readdir(path35.join(configDir, relative));
19612
19751
  } catch (error) {
19613
19752
  report({ path: relative, reason: `could not be listed: ${describeFailure(error)}` });
19614
19753
  return [];
@@ -19631,22 +19770,22 @@ var WorkflowRunFileSchema = z31.object({
19631
19770
  phases: z31.array(z31.object({ title: z31.string() })).default([]),
19632
19771
  summary: z31.string().optional()
19633
19772
  });
19634
- function summariseSession(fs13, configDir, ref) {
19773
+ function summariseSession(fs14, configDir, ref) {
19635
19774
  const sessionRelative = path35.join(PROJECTS_DIR, ref.project, ref.entry);
19636
19775
  const subagentsRelative = path35.join(sessionRelative, SUBAGENTS_DIR);
19637
19776
  const workflowsUnderSubagents = path35.join(subagentsRelative, WORKFLOWS_DIR);
19638
19777
  const isMeta = (name) => name.startsWith(AGENT_FILE_PREFIX) && name.endsWith(META_SUFFIX);
19639
- let agentCount = fs13.readdir(path35.join(configDir, subagentsRelative)).filter(isMeta).length;
19640
- for (const runDir of fs13.readdir(path35.join(configDir, workflowsUnderSubagents))) {
19778
+ let agentCount = fs14.readdir(path35.join(configDir, subagentsRelative)).filter(isMeta).length;
19779
+ for (const runDir of fs14.readdir(path35.join(configDir, workflowsUnderSubagents))) {
19641
19780
  if (runDir.startsWith(WORKFLOW_RUN_PREFIX)) {
19642
- agentCount += fs13.readdir(path35.join(configDir, workflowsUnderSubagents, runDir)).filter(isMeta).length;
19781
+ agentCount += fs14.readdir(path35.join(configDir, workflowsUnderSubagents, runDir)).filter(isMeta).length;
19643
19782
  }
19644
19783
  }
19645
- const workflowRunCount = fs13.readdir(path35.join(configDir, sessionRelative, WORKFLOWS_DIR)).filter((name) => name.startsWith(WORKFLOW_RUN_PREFIX) && name.endsWith(JSON_SUFFIX)).length;
19646
- const transcript = fs13.lstat(path35.join(configDir, PROJECTS_DIR, ref.project, `${ref.entry}${TRANSCRIPT_SUFFIX}`));
19784
+ const workflowRunCount = fs14.readdir(path35.join(configDir, sessionRelative, WORKFLOWS_DIR)).filter((name) => name.startsWith(WORKFLOW_RUN_PREFIX) && name.endsWith(JSON_SUFFIX)).length;
19785
+ const transcript = fs14.lstat(path35.join(configDir, PROJECTS_DIR, ref.project, `${ref.entry}${TRANSCRIPT_SUFFIX}`));
19647
19786
  return { ...ref, agentCount, workflowRunCount, ...transcript === void 0 ? {} : { updatedAt: new Date(transcript.mtimeMs).toISOString() } };
19648
19787
  }
19649
- function readSessionAgentTree(fs13, configDir, ref, options = {}) {
19788
+ function readSessionAgentTree(fs14, configDir, ref, options = {}) {
19650
19789
  const problems = [];
19651
19790
  const report = (problem) => {
19652
19791
  problems.push(problem);
@@ -19654,15 +19793,15 @@ function readSessionAgentTree(fs13, configDir, ref, options = {}) {
19654
19793
  const sessionRelative = path35.join(PROJECTS_DIR, ref.project, ref.entry);
19655
19794
  const subagentsRelative = path35.join(sessionRelative, SUBAGENTS_DIR);
19656
19795
  const workflowsUnderSubagents = path35.join(subagentsRelative, WORKFLOWS_DIR);
19657
- const located = locateAgents(fs13, configDir, subagentsRelative, void 0, report);
19658
- for (const runDir of listDirOrReport(fs13, configDir, workflowsUnderSubagents, report)) {
19796
+ const located = locateAgents(fs14, configDir, subagentsRelative, void 0, report);
19797
+ for (const runDir of listDirOrReport(fs14, configDir, workflowsUnderSubagents, report)) {
19659
19798
  if (runDir.startsWith(WORKFLOW_RUN_PREFIX)) {
19660
- located.push(...locateAgents(fs13, configDir, path35.join(workflowsUnderSubagents, runDir), runDir, report));
19799
+ located.push(...locateAgents(fs14, configDir, path35.join(workflowsUnderSubagents, runDir), runDir, report));
19661
19800
  }
19662
19801
  }
19663
19802
  const agents = /* @__PURE__ */ new Map();
19664
19803
  for (const candidate of located) {
19665
- const text = readFileOrReport(fs13, configDir, candidate.metaPath, report);
19804
+ const text = readFileOrReport(fs14, configDir, candidate.metaPath, report);
19666
19805
  if (text === void 0) {
19667
19806
  continue;
19668
19807
  }
@@ -19674,7 +19813,7 @@ function readSessionAgentTree(fs13, configDir, ref, options = {}) {
19674
19813
  agents.set(candidate.id, { located: candidate, meta: parsed.data });
19675
19814
  }
19676
19815
  const teamNames = [...new Set([...agents.values()].flatMap((agent) => agent.meta.teamName === void 0 ? [] : [agent.meta.teamName]))].sort();
19677
- const parentOf3 = resolveParents(fs13, configDir, agents, report);
19816
+ const parentOf3 = resolveParents(fs14, configDir, agents, report);
19678
19817
  const childrenOf = /* @__PURE__ */ new Map();
19679
19818
  const roots = [];
19680
19819
  for (const id of agents.keys()) {
@@ -19697,12 +19836,12 @@ function readSessionAgentTree(fs13, configDir, ref, options = {}) {
19697
19836
  sessionId: ref.sessionId,
19698
19837
  superseded: ref.superseded,
19699
19838
  agents: roots.sort().map(build),
19700
- tasks: readTasks(fs13, configDir, ownTaskLists(ref.sessionId), [.../* @__PURE__ */ new Set([...teamNames, ...options.taskListIds ?? []])].filter((id) => !ownTaskLists(ref.sessionId).includes(id)), report),
19701
- workflowRuns: readWorkflowRuns(fs13, configDir, path35.join(sessionRelative, WORKFLOWS_DIR), report),
19839
+ tasks: readTasks(fs14, configDir, ownTaskLists(ref.sessionId), [.../* @__PURE__ */ new Set([...teamNames, ...options.taskListIds ?? []])].filter((id) => !ownTaskLists(ref.sessionId).includes(id)), report),
19840
+ workflowRuns: readWorkflowRuns(fs14, configDir, path35.join(sessionRelative, WORKFLOWS_DIR), report),
19702
19841
  problems
19703
19842
  };
19704
19843
  }
19705
- function resolveParents(fs13, configDir, agents, report) {
19844
+ function resolveParents(fs14, configDir, agents, report) {
19706
19845
  const parentOf3 = /* @__PURE__ */ new Map();
19707
19846
  const transcriptCache = /* @__PURE__ */ new Map();
19708
19847
  const transcriptOf = (agent) => {
@@ -19710,7 +19849,7 @@ function resolveParents(fs13, configDir, agents, report) {
19710
19849
  if (cached !== void 0) {
19711
19850
  return cached;
19712
19851
  }
19713
- const text = readFileOrReport(fs13, configDir, agent.located.transcriptPath, report) ?? "";
19852
+ const text = readFileOrReport(fs14, configDir, agent.located.transcriptPath, report) ?? "";
19714
19853
  transcriptCache.set(agent.located.id, text);
19715
19854
  return text;
19716
19855
  };
@@ -19760,16 +19899,16 @@ function resolveParents(fs13, configDir, agents, report) {
19760
19899
  function ownTaskLists(sessionId) {
19761
19900
  return [sessionId, `${SHORT_SESSION_LIST_PREFIX}${sessionId.slice(0, SHORT_SESSION_ID_LENGTH)}`];
19762
19901
  }
19763
- function readTasks(fs13, configDir, ownLists, sharedLists, report) {
19902
+ function readTasks(fs14, configDir, ownLists, sharedLists, report) {
19764
19903
  const tasks = [];
19765
19904
  [...ownLists, ...sharedLists].forEach((scope, index) => {
19766
19905
  const relativeDir = path35.join(TASKS_DIR, scope);
19767
- for (const name of [...listDirOrReport(fs13, configDir, relativeDir, report)].sort()) {
19906
+ for (const name of [...listDirOrReport(fs14, configDir, relativeDir, report)].sort()) {
19768
19907
  if (name.startsWith(".") || !name.endsWith(JSON_SUFFIX)) {
19769
19908
  continue;
19770
19909
  }
19771
19910
  const relative = path35.join(relativeDir, name);
19772
- const text = readFileOrReport(fs13, configDir, relative, report);
19911
+ const text = readFileOrReport(fs14, configDir, relative, report);
19773
19912
  const parsed = TaskFileSchema.safeParse(text === void 0 ? void 0 : parseJson2(text));
19774
19913
  if (parsed.success) {
19775
19914
  tasks.push(index < ownLists.length ? parsed.data : { ...parsed.data, taskList: scope });
@@ -19780,14 +19919,14 @@ function readTasks(fs13, configDir, ownLists, sharedLists, report) {
19780
19919
  });
19781
19920
  return tasks;
19782
19921
  }
19783
- function readWorkflowRuns(fs13, configDir, relativeDir, report) {
19922
+ function readWorkflowRuns(fs14, configDir, relativeDir, report) {
19784
19923
  const runs = [];
19785
- for (const name of [...listDirOrReport(fs13, configDir, relativeDir, report)].sort()) {
19924
+ for (const name of [...listDirOrReport(fs14, configDir, relativeDir, report)].sort()) {
19786
19925
  if (!name.startsWith(WORKFLOW_RUN_PREFIX) || !name.endsWith(JSON_SUFFIX)) {
19787
19926
  continue;
19788
19927
  }
19789
19928
  const relative = path35.join(relativeDir, name);
19790
- const text = readFileOrReport(fs13, configDir, relative, report);
19929
+ const text = readFileOrReport(fs14, configDir, relative, report);
19791
19930
  const parsed = WorkflowRunFileSchema.safeParse(text === void 0 ? void 0 : parseJson2(text));
19792
19931
  if (!parsed.success) {
19793
19932
  if (text !== void 0) {
@@ -19813,11 +19952,11 @@ var SessionLookupError = class extends CliError {
19813
19952
  function identityConfigDir(identitiesDir, identity) {
19814
19953
  return path36.join(identitiesDir, identity);
19815
19954
  }
19816
- function historyStores(fs13, identitiesDir, identities) {
19955
+ function historyStores(fs14, identitiesDir, identities) {
19817
19956
  const byRealPath = /* @__PURE__ */ new Map();
19818
19957
  for (const identity of identities) {
19819
19958
  const configDir = identityConfigDir(identitiesDir, identity);
19820
- const real = fs13.realpath(path36.join(configDir, "projects"));
19959
+ const real = fs14.realpath(path36.join(configDir, "projects"));
19821
19960
  if (real === void 0) {
19822
19961
  continue;
19823
19962
  }
@@ -19830,15 +19969,15 @@ function historyStores(fs13, identitiesDir, identities) {
19830
19969
  }
19831
19970
  return [...byRealPath.values()];
19832
19971
  }
19833
- function collectSessionList(fs13, identitiesDir, identities, filters) {
19972
+ function collectSessionList(fs14, identitiesDir, identities, filters) {
19834
19973
  const names = filters.identity === void 0 ? identities : identities.filter((name) => name === filters.identity);
19835
19974
  if (filters.identity !== void 0 && names.length === 0) {
19836
19975
  throw new SessionLookupError(`no identity named "${filters.identity}"`);
19837
19976
  }
19838
19977
  const sessions = [];
19839
- for (const store of historyStores(fs13, identitiesDir, names)) {
19840
- for (const ref of listSessions2(fs13, store.configDir)) {
19841
- const summary = summariseSession(fs13, store.configDir, ref);
19978
+ for (const store of historyStores(fs14, identitiesDir, names)) {
19979
+ for (const ref of listSessions2(fs14, store.configDir)) {
19980
+ const summary = summariseSession(fs14, store.configDir, ref);
19842
19981
  if (filters.all === true || summary.agentCount > 0 || summary.workflowRunCount > 0) {
19843
19982
  sessions.push({ ...summary, identities: store.identities });
19844
19983
  }
@@ -19846,14 +19985,14 @@ function collectSessionList(fs13, identitiesDir, identities, filters) {
19846
19985
  }
19847
19986
  return sessions.sort((left, right) => (right.updatedAt ?? "").localeCompare(left.updatedAt ?? "") || left.sessionId.localeCompare(right.sessionId));
19848
19987
  }
19849
- function locateSession(fs13, identitiesDir, identities, query, onlyIdentity) {
19988
+ function locateSession(fs14, identitiesDir, identities, query, onlyIdentity) {
19850
19989
  const names = onlyIdentity === void 0 ? identities : identities.filter((name) => name === onlyIdentity);
19851
19990
  if (onlyIdentity !== void 0 && names.length === 0) {
19852
19991
  throw new SessionLookupError(`no identity named "${onlyIdentity}"`);
19853
19992
  }
19854
19993
  const matches = [];
19855
- for (const store of historyStores(fs13, identitiesDir, names)) {
19856
- for (const ref of listSessions2(fs13, store.configDir)) {
19994
+ for (const store of historyStores(fs14, identitiesDir, names)) {
19995
+ for (const ref of listSessions2(fs14, store.configDir)) {
19857
19996
  if (ref.sessionId.startsWith(query)) {
19858
19997
  matches.push({ identities: store.identities, configDir: store.configDir, ref });
19859
19998
  }
@@ -19870,9 +20009,9 @@ function locateSession(fs13, identitiesDir, identities, query, onlyIdentity) {
19870
20009
  }
19871
20010
  throw new SessionLookupError(`"${query}" matches ${String(candidates.length)} sessions: ${candidates.map((match) => `${match.ref.sessionId} (${match.identities.join(", ")})`).join("; ")}; give more of the id or pass --identity`);
19872
20011
  }
19873
- function showSession(fs13, identitiesDir, identities, query, onlyIdentity) {
19874
- const located = locateSession(fs13, identitiesDir, identities, query, onlyIdentity);
19875
- return { identities: located.identities, tree: readSessionAgentTree(fs13, located.configDir, located.ref) };
20012
+ function showSession(fs14, identitiesDir, identities, query, onlyIdentity) {
20013
+ const located = locateSession(fs14, identitiesDir, identities, query, onlyIdentity);
20014
+ return { identities: located.identities, tree: readSessionAgentTree(fs14, located.configDir, located.ref) };
19876
20015
  }
19877
20016
 
19878
20017
  // src/agents/realFs.ts