agent-shim 7.12.1 → 7.13.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
@@ -1626,8 +1626,8 @@ var FarmManifestSchema = z2.strictObject({
1626
1626
  materialised: z2.array(z2.string()),
1627
1627
  links: z2.array(z2.strictObject({ rel: z2.string(), target: z2.string() }))
1628
1628
  });
1629
- function readFarmManifest(fs10, farmRoot) {
1630
- const raw = fs10.readFileUtf8(path6.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs10.readFileUtf8(path6.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1629
+ function readFarmManifest(fs12, farmRoot) {
1630
+ const raw = fs12.readFileUtf8(path6.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs12.readFileUtf8(path6.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1631
1631
  if (raw === void 0) {
1632
1632
  return void 0;
1633
1633
  }
@@ -1685,9 +1685,9 @@ function buildEntryFacts(params) {
1685
1685
  entries
1686
1686
  };
1687
1687
  }
1688
- function listSubtree(fs10, root, rel) {
1688
+ function listSubtree(fs12, root, rel) {
1689
1689
  const absolute = path6.join(root, rel);
1690
- const stat = fs10.lstat(absolute);
1690
+ const stat = fs12.lstat(absolute);
1691
1691
  if (stat === void 0) {
1692
1692
  return [];
1693
1693
  }
@@ -1695,10 +1695,10 @@ function listSubtree(fs10, root, rel) {
1695
1695
  return [{ rel, kind: "symlink" }];
1696
1696
  }
1697
1697
  if (stat.kind === "dir") {
1698
- const children = [...fs10.readdir(absolute)].sort().flatMap((name) => listSubtree(fs10, root, `${rel}/${name}`));
1698
+ const children = [...fs12.readdir(absolute)].sort().flatMap((name) => listSubtree(fs12, root, `${rel}/${name}`));
1699
1699
  return [{ rel, kind: "dir" }, ...children];
1700
1700
  }
1701
- const contentHash = fs10.hashFile(absolute);
1701
+ const contentHash = fs12.hashFile(absolute);
1702
1702
  return [{ rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } }];
1703
1703
  }
1704
1704
  function topLevelScopeRoots(roots) {
@@ -1712,25 +1712,25 @@ function topLevelScopeRoots(roots) {
1712
1712
  }
1713
1713
  return kept;
1714
1714
  }
1715
- function reconciliationScope(fs10, farmRoot, manifest) {
1715
+ function reconciliationScope(fs12, farmRoot, manifest) {
1716
1716
  if (manifest !== void 0) {
1717
1717
  return topLevelScopeRoots(manifest.materialised);
1718
1718
  }
1719
- return [...fs10.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs10.lstat(path6.join(farmRoot, name))?.kind === "dir").sort();
1719
+ return [...fs12.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs12.lstat(path6.join(farmRoot, name))?.kind === "dir").sort();
1720
1720
  }
1721
- function collectFarmListing(fs10, farmRoot, scopeRoots) {
1722
- return scopeRoots.flatMap((root) => listSubtree(fs10, farmRoot, root));
1721
+ function collectFarmListing(fs12, farmRoot, scopeRoots) {
1722
+ return scopeRoots.flatMap((root) => listSubtree(fs12, farmRoot, root));
1723
1723
  }
1724
- function collectCanonicalCounterparts(fs10, claudeHome, farmListing) {
1724
+ function collectCanonicalCounterparts(fs12, claudeHome, farmListing) {
1725
1725
  const out = [];
1726
1726
  for (const entry of farmListing) {
1727
1727
  const absolute = path6.join(claudeHome, entry.rel);
1728
- const stat = fs10.lstat(absolute);
1728
+ const stat = fs12.lstat(absolute);
1729
1729
  if (stat === void 0) {
1730
1730
  continue;
1731
1731
  }
1732
1732
  if (stat.kind === "file") {
1733
- const contentHash = fs10.hashFile(absolute);
1733
+ const contentHash = fs12.hashFile(absolute);
1734
1734
  out.push({ rel: entry.rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } });
1735
1735
  continue;
1736
1736
  }
@@ -2414,8 +2414,12 @@ function pumpTapSession(secure, openUpstream, tap, prefix = Buffer.alloc(0)) {
2414
2414
  }
2415
2415
 
2416
2416
  // src/frontdoor/capability.ts
2417
+ var CONNECT_PROXY_USER = "agent-shim";
2417
2418
  var CONNECT_PROXY_REALM = "agent-shim front door";
2418
2419
  var BASIC_SCHEME = "basic";
2420
+ function connectProxyUrl(port, token) {
2421
+ return `http://${encodeURIComponent(CONNECT_PROXY_USER)}:${encodeURIComponent(token)}@127.0.0.1:${String(port)}`;
2422
+ }
2419
2423
  function capabilityFromProxyAuthorization(value) {
2420
2424
  const trimmed = value.trim();
2421
2425
  const space = trimmed.indexOf(" ");
@@ -2432,7 +2436,15 @@ function capabilityFromProxyAuthorization(value) {
2432
2436
  }
2433
2437
 
2434
2438
  // src/frontdoor/route.ts
2439
+ var IDENTITY_HEADER = "x-agent-shim-identity";
2440
+ var SESSION_HEADER = "x-agent-shim-session";
2441
+ var HEADROOM_FLAG_HEADER = "x-agent-shim-headroom";
2442
+ var PROJECT_ID_HEADER = "x-headroom-project-id";
2435
2443
  var AUTH_HEADER = "x-agent-shim-auth";
2444
+ var PROVIDER_PATH_PREFIX = "/providers/";
2445
+ function providerBaseUrl(port, provider) {
2446
+ return `https://127.0.0.1:${String(port)}${PROVIDER_PATH_PREFIX}${encodeURIComponent(provider)}`;
2447
+ }
2436
2448
 
2437
2449
  // src/frontdoor/state.ts
2438
2450
  import path7 from "node:path";
@@ -2469,10 +2481,10 @@ var FrontDoorStateSchema = z3.strictObject({
2469
2481
  /** The last fatal error, kept across shutdowns so `frontdoor status` can explain a front door that is not running. */
2470
2482
  lastError: z3.string().optional()
2471
2483
  });
2472
- function readFrontDoorState(fs10, stateFile) {
2484
+ function readFrontDoorState(fs12, stateFile) {
2473
2485
  let raw;
2474
2486
  try {
2475
- raw = fs10.readFileUtf8(stateFile);
2487
+ raw = fs12.readFileUtf8(stateFile);
2476
2488
  } catch {
2477
2489
  return void 0;
2478
2490
  }
@@ -2486,28 +2498,28 @@ function readFrontDoorState(fs10, stateFile) {
2486
2498
  return void 0;
2487
2499
  }
2488
2500
  }
2489
- function writeFrontDoorState(fs10, stateFile, state) {
2490
- fs10.mkdirp(path7.dirname(stateFile));
2491
- fs10.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
2501
+ function writeFrontDoorState(fs12, stateFile, state) {
2502
+ fs12.mkdirp(path7.dirname(stateFile));
2503
+ fs12.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
2492
2504
  `);
2493
2505
  }
2494
2506
  function frontDoorOrigin(state) {
2495
2507
  const port = state?.directPort ?? state?.lastDirectPort;
2496
2508
  return port === void 0 ? void 0 : `http://127.0.0.1:${String(port)}`;
2497
2509
  }
2498
- function writeFrontDoorSession(fs10, sessionsDir, session) {
2499
- fs10.mkdirPrivate(sessionsDir);
2500
- fs10.writeFilePrivate(path7.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2510
+ function writeFrontDoorSession(fs12, sessionsDir, session) {
2511
+ fs12.mkdirPrivate(sessionsDir);
2512
+ fs12.writeFilePrivate(path7.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2501
2513
  `);
2502
2514
  }
2503
- function listFrontDoorSessions(fs10, sessionsDir) {
2515
+ function listFrontDoorSessions(fs12, sessionsDir) {
2504
2516
  const sessions = [];
2505
- for (const name of fs10.readdir(sessionsDir)) {
2517
+ for (const name of fs12.readdir(sessionsDir)) {
2506
2518
  if (!name.endsWith(".json")) {
2507
2519
  continue;
2508
2520
  }
2509
2521
  try {
2510
- const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs10.readFileUtf8(path7.join(sessionsDir, name)) ?? ""));
2522
+ const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs12.readFileUtf8(path7.join(sessionsDir, name)) ?? ""));
2511
2523
  if (parsed.success) {
2512
2524
  sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
2513
2525
  }
@@ -2517,14 +2529,14 @@ function listFrontDoorSessions(fs10, sessionsDir) {
2517
2529
  }
2518
2530
  return sessions.sort((a, b) => a.pid - b.pid);
2519
2531
  }
2520
- function removeFrontDoorSession(fs10, sessionsDir, pid) {
2521
- fs10.removeRecursive(path7.join(sessionsDir, `${String(pid)}.json`));
2532
+ function removeFrontDoorSession(fs12, sessionsDir, pid) {
2533
+ fs12.removeRecursive(path7.join(sessionsDir, `${String(pid)}.json`));
2522
2534
  }
2523
- function pruneDeadFrontDoorSessions(fs10, sessionsDir, isRunning) {
2535
+ function pruneDeadFrontDoorSessions(fs12, sessionsDir, isRunning) {
2524
2536
  const removed = [];
2525
- for (const session of listFrontDoorSessions(fs10, sessionsDir)) {
2537
+ for (const session of listFrontDoorSessions(fs12, sessionsDir)) {
2526
2538
  if (!isRunning(session.pid)) {
2527
- removeFrontDoorSession(fs10, sessionsDir, session.pid);
2539
+ removeFrontDoorSession(fs12, sessionsDir, session.pid);
2528
2540
  removed.push(session.pid);
2529
2541
  }
2530
2542
  }
@@ -2536,8 +2548,8 @@ var FRONTDOOR_SUPERVISOR_STILL_RUNNING = -1;
2536
2548
  var FRONTDOOR_POLL_MS = 1e3;
2537
2549
  var MS_PER_MINUTE = 6e4;
2538
2550
  async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {}) {
2539
- const { fs: fs10, paths } = ports;
2540
- const previous = readFrontDoorState(fs10, paths.frontdoorStateFile);
2551
+ const { fs: fs12, paths } = ports;
2552
+ const previous = readFrontDoorState(fs12, paths.frontdoorStateFile);
2541
2553
  let lastPort = previous?.lastPort;
2542
2554
  let lastConnectPort = previous?.lastConnectPort;
2543
2555
  let lastDirectPort = previous?.lastDirectPort;
@@ -2547,12 +2559,12 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2547
2559
  ...lastDirectPort === void 0 ? {} : { lastDirectPort }
2548
2560
  });
2549
2561
  const fail = (message) => {
2550
- writeFrontDoorState(fs10, paths.frontdoorStateFile, { lastError: message, ...sticky() });
2551
- fs10.removeRecursive(paths.frontdoorLockFile);
2562
+ writeFrontDoorState(fs12, paths.frontdoorStateFile, { lastError: message, ...sticky() });
2563
+ fs12.removeRecursive(paths.frontdoorLockFile);
2552
2564
  ports.log(`agent-shim frontdoor supervisor: ${message}`);
2553
2565
  return 1;
2554
2566
  };
2555
- writeFrontDoorState(fs10, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
2567
+ writeFrontDoorState(fs12, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
2556
2568
  const previousSticky = lastPort;
2557
2569
  let http2;
2558
2570
  try {
@@ -2589,8 +2601,8 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2589
2601
  ports.log(`agent-shim frontdoor supervisor: sticky direct port ${String(previousStickyDirect)} was occupied; moving to ${String(direct.port)} (headroom must be restarted to admit the new address)`);
2590
2602
  }
2591
2603
  lastDirectPort = direct.port;
2592
- writeFrontDoorState(fs10, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http2.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
2593
- fs10.removeRecursive(paths.frontdoorLockFile);
2604
+ writeFrontDoorState(fs12, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http2.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
2605
+ fs12.removeRecursive(paths.frontdoorLockFile);
2594
2606
  ports.log(`agent-shim frontdoor supervisor ${String(ports.ownPid)}: front door on 127.0.0.1:${String(http2.port)}, CONNECT surface on 127.0.0.1:${String(connect3.port)}`);
2595
2607
  let idleSince;
2596
2608
  let ticks = 0;
@@ -2599,15 +2611,15 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2599
2611
  return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
2600
2612
  }
2601
2613
  ticks += 1;
2602
- pruneDeadFrontDoorSessions(fs10, paths.frontdoorSessionsDir, ports.isRunning);
2603
- if (listFrontDoorSessions(fs10, paths.frontdoorSessionsDir).length === 0) {
2614
+ pruneDeadFrontDoorSessions(fs12, paths.frontdoorSessionsDir, ports.isRunning);
2615
+ if (listFrontDoorSessions(fs12, paths.frontdoorSessionsDir).length === 0) {
2604
2616
  idleSince ??= ports.now();
2605
2617
  if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE) {
2606
2618
  ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
2607
2619
  await direct.close();
2608
2620
  await connect3.close();
2609
2621
  await http2.close();
2610
- writeFrontDoorState(fs10, paths.frontdoorStateFile, sticky());
2622
+ writeFrontDoorState(fs12, paths.frontdoorStateFile, sticky());
2611
2623
  return 0;
2612
2624
  }
2613
2625
  } else {
@@ -2662,8 +2674,8 @@ function parseConnectTarget(authority) {
2662
2674
  function isInterceptedHost(host, interceptHosts) {
2663
2675
  return interceptHosts.includes(host);
2664
2676
  }
2665
- function servedByPipeline(path23) {
2666
- return path23?.startsWith(ROUTED_PATH_PREFIX) === true;
2677
+ function servedByPipeline(path28) {
2678
+ return path28?.startsWith(ROUTED_PATH_PREFIX) === true;
2667
2679
  }
2668
2680
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
2669
2681
  "connection",
@@ -3197,16 +3209,16 @@ function parseJson(raw, schema) {
3197
3209
  const parsed = schema.safeParse(JSON.parse(raw));
3198
3210
  return parsed.success ? parsed.data : void 0;
3199
3211
  }
3200
- function readHeadroomState(fs10, stateFile) {
3212
+ function readHeadroomState(fs12, stateFile) {
3201
3213
  try {
3202
- return parseJson(fs10.readFileUtf8(stateFile), HeadroomStateSchema);
3214
+ return parseJson(fs12.readFileUtf8(stateFile), HeadroomStateSchema);
3203
3215
  } catch {
3204
3216
  return void 0;
3205
3217
  }
3206
3218
  }
3207
- function writeHeadroomState(fs10, stateFile, state) {
3208
- fs10.mkdirp(path8.dirname(stateFile));
3209
- fs10.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
3219
+ function writeHeadroomState(fs12, stateFile, state) {
3220
+ fs12.mkdirp(path8.dirname(stateFile));
3221
+ fs12.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
3210
3222
  `);
3211
3223
  }
3212
3224
  function headroomAllowlist(providers) {
@@ -3226,14 +3238,14 @@ function headroomUpstreams(providers, frontDoorOrigin2) {
3226
3238
  function hashAllowlist(allowlist) {
3227
3239
  return createHash2("sha256").update(allowlist.join("\n")).digest("hex");
3228
3240
  }
3229
- function readAllProviders(fs10, providersDir) {
3241
+ function readAllProviders(fs12, providersDir) {
3230
3242
  const result = [];
3231
- for (const name of fs10.readdir(providersDir)) {
3243
+ for (const name of fs12.readdir(providersDir)) {
3232
3244
  if (!name.endsWith(".json")) {
3233
3245
  continue;
3234
3246
  }
3235
3247
  try {
3236
- const parsed = parseJson(fs10.readFileUtf8(path8.join(providersDir, name)), ProviderSchema);
3248
+ const parsed = parseJson(fs12.readFileUtf8(path8.join(providersDir, name)), ProviderSchema);
3237
3249
  if (parsed !== void 0) {
3238
3250
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
3239
3251
  }
@@ -3243,22 +3255,22 @@ function readAllProviders(fs10, providersDir) {
3243
3255
  }
3244
3256
  return result;
3245
3257
  }
3246
- function writeSession(fs10, sessionsDir, session) {
3247
- fs10.mkdirp(sessionsDir);
3248
- fs10.writeFileUtf8(path8.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
3258
+ function writeSession(fs12, sessionsDir, session) {
3259
+ fs12.mkdirp(sessionsDir);
3260
+ fs12.writeFileUtf8(path8.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
3249
3261
  `);
3250
3262
  }
3251
- function removeSession(fs10, sessionsDir, pid) {
3252
- fs10.removeRecursive(path8.join(sessionsDir, `${String(pid)}.json`));
3263
+ function removeSession(fs12, sessionsDir, pid) {
3264
+ fs12.removeRecursive(path8.join(sessionsDir, `${String(pid)}.json`));
3253
3265
  }
3254
- function listSessions(fs10, sessionsDir) {
3266
+ function listSessions(fs12, sessionsDir) {
3255
3267
  const sessions = [];
3256
- for (const name of fs10.readdir(sessionsDir)) {
3268
+ for (const name of fs12.readdir(sessionsDir)) {
3257
3269
  if (!name.endsWith(".json")) {
3258
3270
  continue;
3259
3271
  }
3260
3272
  try {
3261
- const parsed = parseJson(fs10.readFileUtf8(path8.join(sessionsDir, name)), HeadroomSessionSchema);
3273
+ const parsed = parseJson(fs12.readFileUtf8(path8.join(sessionsDir, name)), HeadroomSessionSchema);
3262
3274
  if (parsed !== void 0) {
3263
3275
  sessions.push(parsed);
3264
3276
  }
@@ -3268,22 +3280,22 @@ function listSessions(fs10, sessionsDir) {
3268
3280
  }
3269
3281
  return sessions.sort((a, b) => a.pid - b.pid);
3270
3282
  }
3271
- function sessionsForSupervisor(fs10, sessionsDir, supervisorPid) {
3272
- return listSessions(fs10, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
3283
+ function sessionsForSupervisor(fs12, sessionsDir, supervisorPid) {
3284
+ return listSessions(fs12, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
3273
3285
  }
3274
- function pruneDeadSessions(fs10, sessionsDir, isRunning) {
3286
+ function pruneDeadSessions(fs12, sessionsDir, isRunning) {
3275
3287
  const removed = [];
3276
- for (const session of listSessions(fs10, sessionsDir)) {
3288
+ for (const session of listSessions(fs12, sessionsDir)) {
3277
3289
  if (!isRunning(session.pid)) {
3278
- removeSession(fs10, sessionsDir, session.pid);
3290
+ removeSession(fs12, sessionsDir, session.pid);
3279
3291
  removed.push(session.pid);
3280
3292
  }
3281
3293
  }
3282
3294
  return removed;
3283
3295
  }
3284
- function readStartLock(fs10, lockFile) {
3296
+ function readStartLock(fs12, lockFile) {
3285
3297
  try {
3286
- return parseJson(fs10.readFileUtf8(lockFile), HeadroomLockSchema);
3298
+ return parseJson(fs12.readFileUtf8(lockFile), HeadroomLockSchema);
3287
3299
  } catch {
3288
3300
  return void 0;
3289
3301
  }
@@ -3534,12 +3546,12 @@ function isIdentityName(name) {
3534
3546
  function claudeJsonPath(identitiesDir, identity) {
3535
3547
  return path9.join(identitiesDir, identity, CLAUDE_JSON);
3536
3548
  }
3537
- function readAccountMetadata(fs10, identitiesDir, identity) {
3549
+ function readAccountMetadata(fs12, identitiesDir, identity) {
3538
3550
  if (!isIdentityName(identity)) {
3539
3551
  throw new Error(`"${identity}" is not a valid identity name.`);
3540
3552
  }
3541
3553
  const file = claudeJsonPath(identitiesDir, identity);
3542
- const raw = fs10.readFileUtf8(file);
3554
+ const raw = fs12.readFileUtf8(file);
3543
3555
  if (raw === void 0) {
3544
3556
  return void 0;
3545
3557
  }
@@ -3573,8 +3585,8 @@ function readAccountMetadata(fs10, identitiesDir, identity) {
3573
3585
  // src/usage/read.ts
3574
3586
  var SEGMENT_RE = /^(\d{4}-\d{2}-\d{2})\.(\d+)\.jsonl$/;
3575
3587
  var DAY_MS = 864e5;
3576
- function listLogSegments(fs10, logDir) {
3577
- return fs10.readdir(logDir).flatMap((name) => {
3588
+ function listLogSegments(fs12, logDir) {
3589
+ return fs12.readdir(logDir).flatMap((name) => {
3578
3590
  const match = SEGMENT_RE.exec(name);
3579
3591
  const day = match?.[1];
3580
3592
  if (day === void 0) {
@@ -3583,15 +3595,15 @@ function listLogSegments(fs10, logDir) {
3583
3595
  return [{ name, day, endsAt: Date.parse(`${day}T00:00:00.000Z`) + DAY_MS }];
3584
3596
  }).sort((left, right) => left.day.localeCompare(right.day) || left.name.localeCompare(right.name));
3585
3597
  }
3586
- function readUsageLog(fs10, logDir, options = {}) {
3598
+ function readUsageLog(fs12, logDir, options = {}) {
3587
3599
  const { sinceMs } = options;
3588
3600
  const records = [];
3589
3601
  let invalidLines = 0;
3590
- for (const segment of listLogSegments(fs10, logDir)) {
3602
+ for (const segment of listLogSegments(fs12, logDir)) {
3591
3603
  if (sinceMs !== void 0 && segment.endsAt <= sinceMs) {
3592
3604
  continue;
3593
3605
  }
3594
- const contents = fs10.readFileUtf8(path10.join(logDir, segment.name));
3606
+ const contents = fs12.readFileUtf8(path10.join(logDir, segment.name));
3595
3607
  if (contents === void 0) {
3596
3608
  continue;
3597
3609
  }
@@ -3635,9 +3647,9 @@ function snapshotPath(snapshotsDir, identity) {
3635
3647
  }
3636
3648
  return path10.join(snapshotsDir, `${identity}.json`);
3637
3649
  }
3638
- function readUsageSnapshot(fs10, snapshotsDir, identity) {
3650
+ function readUsageSnapshot(fs12, snapshotsDir, identity) {
3639
3651
  const file = snapshotPath(snapshotsDir, identity);
3640
- const raw = fs10.readFileUtf8(file);
3652
+ const raw = fs12.readFileUtf8(file);
3641
3653
  if (raw === void 0) {
3642
3654
  return void 0;
3643
3655
  }
@@ -3653,8 +3665,8 @@ function readUsageSnapshot(fs10, snapshotsDir, identity) {
3653
3665
  }
3654
3666
  return snapshot.data;
3655
3667
  }
3656
- function listUsageSnapshots(fs10, snapshotsDir) {
3657
- return fs10.readdir(snapshotsDir).flatMap((name) => {
3668
+ function listUsageSnapshots(fs12, snapshotsDir) {
3669
+ return fs12.readdir(snapshotsDir).flatMap((name) => {
3658
3670
  if (!name.endsWith(".json")) {
3659
3671
  return [];
3660
3672
  }
@@ -3662,7 +3674,7 @@ function listUsageSnapshots(fs10, snapshotsDir) {
3662
3674
  if (!isIdentityName(identity)) {
3663
3675
  return [];
3664
3676
  }
3665
- const snapshot = readUsageSnapshot(fs10, snapshotsDir, identity);
3677
+ const snapshot = readUsageSnapshot(fs12, snapshotsDir, identity);
3666
3678
  return snapshot === void 0 ? [] : [snapshot];
3667
3679
  }).sort((left, right) => left.identity.localeCompare(right.identity));
3668
3680
  }
@@ -3837,9 +3849,9 @@ function compareVersions(a, b) {
3837
3849
  }
3838
3850
  var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
3839
3851
  async function runSupervisor(initialConfig, ports, options = {}) {
3840
- const { fs: fs10, paths } = ports;
3852
+ const { fs: fs12, paths } = ports;
3841
3853
  let config = initialConfig;
3842
- const previousState = readHeadroomState(fs10, paths.headroomStateFile);
3854
+ const previousState = readHeadroomState(fs12, paths.headroomStateFile);
3843
3855
  if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
3844
3856
  ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
3845
3857
  return 0;
@@ -3848,19 +3860,19 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3848
3860
  let lastPort = previousState?.lastPort;
3849
3861
  const sticky = () => lastPort === void 0 ? {} : { lastPort };
3850
3862
  const ownsState = () => {
3851
- const owner = readHeadroomState(fs10, paths.headroomStateFile)?.supervisorPid;
3863
+ const owner = readHeadroomState(fs12, paths.headroomStateFile)?.supervisorPid;
3852
3864
  return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
3853
3865
  };
3854
3866
  const writeOwnState = (state) => {
3855
3867
  if (!ownsState()) {
3856
3868
  return false;
3857
3869
  }
3858
- writeHeadroomState(fs10, paths.headroomStateFile, state);
3870
+ writeHeadroomState(fs12, paths.headroomStateFile, state);
3859
3871
  return true;
3860
3872
  };
3861
3873
  const fail = (message) => {
3862
3874
  if (writeOwnState({ lastError: message, ...sticky() })) {
3863
- fs10.removeRecursive(paths.headroomLockFile);
3875
+ fs12.removeRecursive(paths.headroomLockFile);
3864
3876
  }
3865
3877
  ports.log(`agent-shim headroom supervisor: ${message}`);
3866
3878
  return 1;
@@ -3909,7 +3921,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3909
3921
  const settingsHash = hashSettings(config.settings);
3910
3922
  const allowlist = allowlistOf(ports);
3911
3923
  const allowlistHash = hashAllowlist(allowlist);
3912
- pruneDeadSessions(fs10, paths.headroomSessionsDir, ports.isRunning);
3924
+ pruneDeadSessions(fs12, paths.headroomSessionsDir, ports.isRunning);
3913
3925
  const ownsNow = ownsState();
3914
3926
  if (!ownsNow && !superseded) {
3915
3927
  ports.log("agent-shim headroom supervisor: another supervisor now owns state.json; serving this daemon's own sessions until they end");
@@ -3961,7 +3973,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3961
3973
  ...sticky()
3962
3974
  });
3963
3975
  if (recorded) {
3964
- fs10.removeRecursive(paths.headroomLockFile);
3976
+ fs12.removeRecursive(paths.headroomLockFile);
3965
3977
  }
3966
3978
  idleSince = void 0;
3967
3979
  ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on 127.0.0.1:${String(port)}`);
@@ -3976,7 +3988,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3976
3988
  }
3977
3989
  } else {
3978
3990
  if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
3979
- if (sessionsForSupervisor(fs10, paths.headroomSessionsDir, ports.ownPid).length === 0) {
3991
+ if (sessionsForSupervisor(fs12, paths.headroomSessionsDir, ports.ownPid).length === 0) {
3980
3992
  ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
3981
3993
  ports.stopProcess(headroomPid);
3982
3994
  headroomPid = void 0;
@@ -3985,7 +3997,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3985
3997
  continue;
3986
3998
  }
3987
3999
  }
3988
- const sessions = sessionsForSupervisor(fs10, paths.headroomSessionsDir, ports.ownPid);
4000
+ const sessions = sessionsForSupervisor(fs12, paths.headroomSessionsDir, ports.ownPid);
3989
4001
  if (sessions.length === 0) {
3990
4002
  idleSince ??= ports.now();
3991
4003
  const idleMs = ports.now() - idleSince;
@@ -4007,9 +4019,9 @@ async function runSupervisor(initialConfig, ports, options = {}) {
4007
4019
  await ports.sleep(HEADROOM_POLL_MS);
4008
4020
  }
4009
4021
  }
4010
- function currentHeadroomAllowlist(fs10, paths) {
4011
- const providers = readAllProviders(fs10, paths.providersDir).map((entry) => entry.provider);
4012
- return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs10, paths.frontdoorStateFile))));
4022
+ function currentHeadroomAllowlist(fs12, paths) {
4023
+ const providers = readAllProviders(fs12, paths.providersDir).map((entry) => entry.provider);
4024
+ return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs12, paths.frontdoorStateFile))));
4013
4025
  }
4014
4026
  function allowlistOf(ports) {
4015
4027
  return currentHeadroomAllowlist(ports.fs, ports.paths);
@@ -4186,8 +4198,8 @@ function decideConfigProfile(params) {
4186
4198
  }
4187
4199
  return { source: "none" };
4188
4200
  }
4189
- function loadIdentity(identitiesDir, name, fs10) {
4190
- return loadConfigFile(path12.join(identitiesDir, name, "identity.json"), IdentitySchema, fs10.readConfigFile);
4201
+ function loadIdentity(identitiesDir, name, fs12) {
4202
+ return loadConfigFile(path12.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
4191
4203
  }
4192
4204
 
4193
4205
  // src/configProfilesStore.ts
@@ -4529,13 +4541,59 @@ import path15 from "node:path";
4529
4541
 
4530
4542
  // src/credentialCache.ts
4531
4543
  import { z as z7 } from "zod";
4544
+ var MS_PER_UNIT = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
4532
4545
  var CachedCredentialSchema = z7.strictObject({
4533
4546
  token: z7.string().min(1),
4534
4547
  fetchedAt: z7.number().int().nonnegative(),
4535
4548
  source: CredentialSourceSchema
4536
4549
  });
4550
+ function effectiveStore(cache, platform) {
4551
+ return cache.store ?? (platform === "darwin" ? "keychain" : "file");
4552
+ }
4553
+ function ttlMs(cache) {
4554
+ if (cache.ttl === void 0) {
4555
+ return void 0;
4556
+ }
4557
+ const multiplier = MS_PER_UNIT[cache.ttl.slice(-1)];
4558
+ if (multiplier === void 0) {
4559
+ throw new Error(`credential cache ttl "${cache.ttl}" has no recognised unit`);
4560
+ }
4561
+ return Number(cache.ttl.slice(0, -1)) * multiplier;
4562
+ }
4563
+ function isFresh(entry, cache, now) {
4564
+ const limit = ttlMs(cache);
4565
+ if (entry.fetchedAt > now) {
4566
+ return false;
4567
+ }
4568
+ return limit === void 0 || now - entry.fetchedAt < limit;
4569
+ }
4537
4570
 
4538
4571
  // src/credential.ts
4572
+ var CREDENTIAL_UNAVAILABLE_EXIT = 64;
4573
+ var CREDENTIAL_COMMAND_TIMEOUT_MS = 1e4;
4574
+ var CREDENTIAL_INTERACTIVE_TIMEOUT_MS = 12e4;
4575
+ var GROUP_OTHER_PERMISSION_BITS = 63;
4576
+ var PERMISSION_BITS = 511;
4577
+ var OCTAL_RADIX = 8;
4578
+ function commandArgv(source) {
4579
+ if ("command" in source) {
4580
+ return source.command;
4581
+ }
4582
+ if ("op" in source) {
4583
+ return ["op", "read", source.op];
4584
+ }
4585
+ const account = source.keychain.account;
4586
+ return ["security", "find-generic-password", "-s", source.keychain.service, ...account === void 0 ? [] : ["-a", account], "-w"];
4587
+ }
4588
+ function isInteractiveSource(source, env) {
4589
+ if ("command" in source || "keychain" in source) {
4590
+ return source.interactive ?? false;
4591
+ }
4592
+ if ("op" in source) {
4593
+ return source.interactive ?? (env.OP_SERVICE_ACCOUNT_TOKEN ?? "") === "";
4594
+ }
4595
+ return false;
4596
+ }
4539
4597
  function summariseSource(source) {
4540
4598
  if ("env" in source) {
4541
4599
  return { kind: "env", variable: source.env };
@@ -4583,6 +4641,9 @@ function formatSourceSummary(summary) {
4583
4641
  return summary;
4584
4642
  }
4585
4643
  }
4644
+ function describeSource(source) {
4645
+ return formatSourceSummary(summariseSource(source));
4646
+ }
4586
4647
  function formatCredentialSummary(summary) {
4587
4648
  const cache = summary.cache === void 0 ? "" : `, cached ${summary.cache.ttl === void 0 ? "with no expiry" : `for ${summary.cache.ttl}`}${summary.cache.store === void 0 ? "" : ` in the ${summary.cache.store} store`}`;
4588
4649
  return `${summary.target} from ${summary.sources.map(formatSourceSummary).join(", then ")}${cache}`;
@@ -4590,6 +4651,88 @@ function formatCredentialSummary(summary) {
4590
4651
  function describeCredential(credential) {
4591
4652
  return formatCredentialSummary(summariseCredential(credential));
4592
4653
  }
4654
+ function trySource(source, params) {
4655
+ const none = (reason, warn = false) => ({ ok: false, reason, warn });
4656
+ if ("env" in source) {
4657
+ const value = params.env[source.env];
4658
+ return value === void 0 || value === "" ? none("is unset or empty") : { ok: true, token: value };
4659
+ }
4660
+ if ("literal" in source) {
4661
+ return { ok: true, token: source.literal };
4662
+ }
4663
+ if ("file" in source) {
4664
+ const read = params.port.readSecretFile(source.file);
4665
+ if (!read.found) {
4666
+ return none("does not exist");
4667
+ }
4668
+ if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
4669
+ return none(
4670
+ `is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS).toString(OCTAL_RADIX)}); run \`chmod 600 ${source.file}\``,
4671
+ true
4672
+ );
4673
+ }
4674
+ const token2 = read.content.trim();
4675
+ return token2 === "" ? none("is empty") : { ok: true, token: token2 };
4676
+ }
4677
+ const argv = commandArgv(source);
4678
+ const interactive = isInteractiveSource(source, params.env);
4679
+ if (interactive && !params.port.personPresent()) {
4680
+ return none("needs a person to approve it, but there is no terminal or desktop session");
4681
+ }
4682
+ const timeoutMs = source.timeoutMs ?? (interactive ? CREDENTIAL_INTERACTIVE_TIMEOUT_MS : CREDENTIAL_COMMAND_TIMEOUT_MS);
4683
+ const result = params.port.runCommand(argv, { timeoutMs, interactive });
4684
+ if (result.timedOut) {
4685
+ return none(`timed out after ${String(timeoutMs)}ms`);
4686
+ }
4687
+ if (result.status !== 0) {
4688
+ const stderr = result.stderr.trim();
4689
+ const outcome = result.status === null ? "could not be run or was killed by a signal" : `exited with status ${String(result.status)}`;
4690
+ return none(`${outcome}${stderr === "" ? "" : `: ${stderr}`}`);
4691
+ }
4692
+ const token = result.stdout.trim();
4693
+ return token === "" ? none("printed no token") : { ok: true, token };
4694
+ }
4695
+ function warmCommandFor(subject) {
4696
+ const [kind, name] = subject.split(" ");
4697
+ return kind === "provider" ? `agent-shim credential warm --provider ${name ?? ""}` : `agent-shim credential warm ${name ?? ""}`;
4698
+ }
4699
+ function resolveCredential(params) {
4700
+ const target = params.credential.target ?? "bearer";
4701
+ const cacheBlock = params.credential.cache;
4702
+ const cache = cacheBlock === void 0 ? void 0 : params.port.cache;
4703
+ const store = cacheBlock === void 0 || cache === void 0 ? void 0 : effectiveStore(cacheBlock, cache.platform);
4704
+ if (cacheBlock !== void 0 && cache !== void 0 && store !== void 0 && params.refresh !== true) {
4705
+ const entry = cache.port.read(store, params.subject);
4706
+ if (entry !== void 0 && isFresh(entry, cacheBlock, cache.now())) {
4707
+ return { ok: true, credential: { target, token: entry.token, source: entry.source, warnings: [], cachedAt: entry.fetchedAt } };
4708
+ }
4709
+ }
4710
+ const attempts = [];
4711
+ const warnings = [];
4712
+ for (const source of params.credential.sources) {
4713
+ const outcome = trySource(source, params);
4714
+ if (outcome.ok) {
4715
+ if (cache !== void 0 && store !== void 0) {
4716
+ cache.port.write(store, params.subject, { token: outcome.token, fetchedAt: cache.now(), source });
4717
+ }
4718
+ return { ok: true, credential: { target, token: outcome.token, source, warnings } };
4719
+ }
4720
+ const line = `${describeSource(source)} ${outcome.reason}`;
4721
+ attempts.push(line);
4722
+ if (outcome.warn) {
4723
+ warnings.push(`agent-shim: ${params.subject}: skipped ${line}`);
4724
+ }
4725
+ }
4726
+ const hint = cacheBlock === void 0 ? "" : `; fill the cache from a terminal with \`${warmCommandFor(params.subject)}\``;
4727
+ return { ok: false, message: `agent-shim: ${params.subject} has no usable credential: ${attempts.join("; ")}${hint}` };
4728
+ }
4729
+ function credentialVariables(target, token) {
4730
+ return {
4731
+ ANTHROPIC_AUTH_TOKEN: target === "bearer" ? token : void 0,
4732
+ ANTHROPIC_API_KEY: target === "apiKey" ? token : void 0,
4733
+ CLAUDE_CODE_OAUTH_TOKEN: target === "oauthToken" ? token : void 0
4734
+ };
4735
+ }
4593
4736
 
4594
4737
  // src/providersStore.ts
4595
4738
  var ProviderNotFoundError = class extends CliError {
@@ -4695,6 +4838,11 @@ function readProvider(paths, name) {
4695
4838
  const raw = JSON.parse(fs6.readFileSync(filePath, "utf8"));
4696
4839
  return parseProviderFile(filePath, raw);
4697
4840
  }
4841
+ function loadProvider(providersDir, name, port) {
4842
+ const filePath = path15.join(providersDir, `${name}.json`);
4843
+ const raw = port.readConfigFile(filePath);
4844
+ return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
4845
+ }
4698
4846
  function listProviders(paths) {
4699
4847
  const names = listProviderNames(
4700
4848
  (dir) => fs6.readdirSync(dir),
@@ -4827,6 +4975,30 @@ function cascadeProviderName(cascade) {
4827
4975
  }
4828
4976
  return name;
4829
4977
  }
4978
+ function resolveProvider(params) {
4979
+ const cliName = params.cliProvider !== void 0 && params.cliProvider !== "" ? params.cliProvider : void 0;
4980
+ const name = cliName ?? (params.cascade === void 0 ? void 0 : cascadeProviderName(params.cascade));
4981
+ if (name === void 0) {
4982
+ return void 0;
4983
+ }
4984
+ const definition = loadProvider(params.paths.providersDir, name, params.port);
4985
+ if (definition === void 0) {
4986
+ const known = listProviderNames(params.port.readdir, params.paths.providersDir);
4987
+ return {
4988
+ ok: false,
4989
+ status: 1,
4990
+ message: `agent-shim: no provider named "${name}". ` + (known.length > 0 ? `Known providers: ${known.join(", ")}.` : "No providers are defined yet; run `agent-shim provider add`.")
4991
+ };
4992
+ }
4993
+ if (params.credentials === void 0) {
4994
+ return { ok: false, status: 1, message: `agent-shim: provider ${name} needs its credential resolved, but this launcher has no credential port wired` };
4995
+ }
4996
+ const resolution = resolveCredential({ credential: definition.credential, env: params.env, port: params.credentials, subject: `provider ${name}` });
4997
+ if (!resolution.ok) {
4998
+ return { ok: false, status: CREDENTIAL_UNAVAILABLE_EXIT, message: resolution.message };
4999
+ }
5000
+ return { ok: true, provider: { name, definition, credential: resolution.credential }, warnings: resolution.credential.warnings };
5001
+ }
4830
5002
 
4831
5003
  // src/directoryRulesStore.ts
4832
5004
  var DirectoryRuleNotFoundError = class extends CliError {
@@ -4919,7 +5091,7 @@ function removeDirectoryRule(paths, rulePath) {
4919
5091
  }
4920
5092
 
4921
5093
  // src/checkReport.ts
4922
- import os3 from "node:os";
5094
+ import os4 from "node:os";
4923
5095
 
4924
5096
  // src/launcher/cascade.ts
4925
5097
  import path17 from "node:path";
@@ -5015,6 +5187,7 @@ var MS_PER_SECOND2 = 1e3;
5015
5187
  var SECONDS_PER_MINUTE = 60;
5016
5188
  var MINUTES_PER_HOUR = 60;
5017
5189
  var HOURS_PER_DAY = 24;
5190
+ var WARNING_STATUSES = /* @__PURE__ */ new Set(["allowed_warning", "rejected"]);
5018
5191
  function formatAge(ms) {
5019
5192
  const minutes = Math.floor(ms / (MS_PER_SECOND2 * SECONDS_PER_MINUTE));
5020
5193
  if (minutes < MINUTES_PER_HOUR) {
@@ -5035,8 +5208,30 @@ function effectiveWindow(window, nowMs) {
5035
5208
  ...window.status === void 0 ? {} : { status: window.status }
5036
5209
  };
5037
5210
  }
5211
+ function quotaWarnings(snapshot, provider, nowMs) {
5212
+ const rateLimit = snapshot?.providers[provider]?.rateLimit;
5213
+ const unified = rateLimit?.unified;
5214
+ if (snapshot === void 0 || rateLimit === void 0 || unified === void 0) {
5215
+ return [];
5216
+ }
5217
+ const age = formatAge(nowMs - Date.parse(rateLimit.observedAt));
5218
+ const windows = [
5219
+ { name: "five-hour", window: unified.fiveHour },
5220
+ { name: "seven-day", window: unified.sevenDay }
5221
+ ];
5222
+ return windows.flatMap(({ name, window }) => {
5223
+ const effective = window === void 0 ? void 0 : effectiveWindow(window, nowMs);
5224
+ if (window === void 0 || effective?.status === void 0 || !WARNING_STATUSES.has(effective.status)) {
5225
+ return [];
5226
+ }
5227
+ const reset = window.resetsAt === void 0 ? "" : `, resets ${window.resetsAt}`;
5228
+ const verdict = effective.status === "rejected" ? "exhausted" : "nearly used";
5229
+ return [`agent-shim: identity ${snapshot.identity}: the ${name} quota is ${verdict}${reset} (last seen ${age} ago)`];
5230
+ });
5231
+ }
5038
5232
 
5039
5233
  // src/usage/poolPick.ts
5234
+ import path18 from "node:path";
5040
5235
  import { z as z9 } from "zod";
5041
5236
 
5042
5237
  // src/usage/plan.ts
@@ -5289,14 +5484,14 @@ var PicksFileSchema = z9.strictObject({
5289
5484
  function errorMessage(error) {
5290
5485
  return error instanceof Error ? error.message : String(error);
5291
5486
  }
5292
- function loadPoolMembers(fs10, paths, identities, nowMs) {
5487
+ function loadPoolMembers(fs12, paths, identities, nowMs) {
5293
5488
  const windowStartMs = nowMs - FIVE_HOUR_WINDOW_MS;
5294
- const log = readUsageLog(fs10, paths.usageLogDir, { sinceMs: windowStartMs });
5489
+ const log = readUsageLog(fs12, paths.usageLogDir, { sinceMs: windowStartMs });
5295
5490
  return identities.map((identity) => {
5296
5491
  const records = log.records.filter((record) => record.identity === identity && record.provider === ANTHROPIC_PROVIDER && Date.parse(record.at) >= windowStartMs);
5297
5492
  try {
5298
- const snapshot = readUsageSnapshot(fs10, paths.usageSnapshotsDir, identity);
5299
- const account = readAccountMetadata(fs10, paths.identitiesDir, identity) ?? snapshot?.account;
5493
+ const snapshot = readUsageSnapshot(fs12, paths.usageSnapshotsDir, identity);
5494
+ const account = readAccountMetadata(fs12, paths.identitiesDir, identity) ?? snapshot?.account;
5300
5495
  return { identity, records, ...snapshot === void 0 ? {} : { snapshot }, ...account === void 0 ? {} : { account } };
5301
5496
  } catch (error) {
5302
5497
  if (error instanceof UsageSnapshotError || error instanceof AccountMetadataError) {
@@ -5314,9 +5509,9 @@ function rankPoolFromStore(params) {
5314
5509
  ...params.sticky === void 0 ? {} : { sticky: params.sticky }
5315
5510
  });
5316
5511
  }
5317
- function readPicksFile(fs10, file) {
5512
+ function readPicksFile(fs12, file) {
5318
5513
  const empty = { schemaVersion: SCHEMA_VERSION, picks: {} };
5319
- const raw = fs10.readFileUtf8(file);
5514
+ const raw = fs12.readFileUtf8(file);
5320
5515
  if (raw === void 0) {
5321
5516
  return { file: empty };
5322
5517
  }
@@ -5329,17 +5524,72 @@ function readPicksFile(fs10, file) {
5329
5524
  const result = PicksFileSchema.safeParse(parsed);
5330
5525
  return result.success ? { file: result.data } : { file: empty, problem: `${file} is not a picks file this agent-shim can read` };
5331
5526
  }
5332
- function readStickyPick(fs10, picksFile, directory) {
5333
- const read = readPicksFile(fs10, picksFile);
5527
+ function readStickyPick(fs12, picksFile, directory) {
5528
+ const read = readPicksFile(fs12, picksFile);
5334
5529
  const entry = read.file.picks[directory];
5335
5530
  return { ...entry === void 0 ? {} : { sticky: entry }, ...read.problem === void 0 ? {} : { problem: read.problem } };
5336
5531
  }
5532
+ function recordStickyPick(fs12, picksFile, directory, identity, nowMs) {
5533
+ const current = readPicksFile(fs12, picksFile).file.picks;
5534
+ const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
5535
+ const next = { schemaVersion: SCHEMA_VERSION, picks: { ...Object.fromEntries(kept), [directory]: { identity, at: new Date(nowMs).toISOString() } } };
5536
+ fs12.mkdirPrivate(path18.dirname(picksFile));
5537
+ fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
5538
+ `);
5539
+ }
5337
5540
 
5338
5541
  // src/launcher/pool.ts
5339
- function splitMembers(pool, paths, fs10) {
5340
- const exists = (name) => loadIdentity(paths.identitiesDir, name, fs10) !== void 0;
5542
+ var RESUME_FLAGS = /* @__PURE__ */ new Set(["--continue", "-c", "--resume", "-r"]);
5543
+ var TERMINATOR = "--";
5544
+ var REASONS_LOGGED = 3;
5545
+ function splitMembers(pool, paths, fs12) {
5546
+ const exists = (name) => loadIdentity(paths.identitiesDir, name, fs12) !== void 0;
5341
5547
  return { present: pool.identities.filter(exists), missing: pool.identities.filter((name) => !exists(name)) };
5342
5548
  }
5549
+ function isResuming(passthrough) {
5550
+ const end = passthrough.indexOf(TERMINATOR);
5551
+ return (end === -1 ? passthrough : passthrough.slice(0, end)).some((token) => RESUME_FLAGS.has(token));
5552
+ }
5553
+ function resolvePoolLaunch(params) {
5554
+ const { poolName, log } = params;
5555
+ const pool = params.pools?.[poolName];
5556
+ if (pool === void 0) {
5557
+ return { ok: false, message: `agent-shim: no pool named "${poolName}" (selected via ${params.selectedVia}). Run \`agent-shim pool add ${poolName} --identity <name>...\` first.` };
5558
+ }
5559
+ const { present: identities, missing } = splitMembers(pool, params.paths, params.fs);
5560
+ for (const name of missing) {
5561
+ log.warn(`agent-shim: pool "${poolName}" names identity "${name}", which does not exist; skipping it`);
5562
+ }
5563
+ if (identities.length === 0) {
5564
+ return { ok: false, message: `agent-shim: no member of pool "${poolName}" is an existing identity.` };
5565
+ }
5566
+ const resuming = isResuming(params.passthrough);
5567
+ const stickyRead = readStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd);
5568
+ if (stickyRead.problem !== void 0) {
5569
+ log.warn(`agent-shim: ${stickyRead.problem}; ignoring the last-pick record`);
5570
+ }
5571
+ for (; ; ) {
5572
+ const nowMs = params.now();
5573
+ const ranking = rankPoolFromStore({ fs: params.usageFs, paths: params.paths, identities, nowMs, resuming, ...stickyRead.sticky === void 0 ? {} : { sticky: stickyRead.sticky } });
5574
+ const { pick, earliestReturn } = ranking;
5575
+ if (pick !== void 0) {
5576
+ recordStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd, pick.identity, nowMs);
5577
+ return { ok: true, identity: pick.identity, explanation: `pool ${poolName}: ${pick.reasons.slice(0, REASONS_LOGGED).join("; ")}` };
5578
+ }
5579
+ if (earliestReturn === void 0) {
5580
+ return { ok: false, message: `agent-shim: no member of pool "${poolName}" can be picked.` };
5581
+ }
5582
+ const until = new Date(earliestReturn.atMs).toISOString();
5583
+ if (!params.wait) {
5584
+ return {
5585
+ ok: false,
5586
+ message: `agent-shim: every member of pool "${poolName}" is refused right now; the earliest, ${earliestReturn.identity}, returns at ${until} (in ${formatAge(earliestReturn.atMs - nowMs)}). Pass --wait to sleep until then.`
5587
+ };
5588
+ }
5589
+ log.info(`agent-shim: every member of pool "${poolName}" is refused; waiting until ${until} for ${earliestReturn.identity}`);
5590
+ params.sleep(Math.max(earliestReturn.atMs - nowMs, 0));
5591
+ }
5592
+ }
5343
5593
 
5344
5594
  // src/poolPickReport.ts
5345
5595
  function candidateView(candidate) {
@@ -5379,14 +5629,15 @@ function collectPoolPick(params) {
5379
5629
  import { spawn, spawnSync } from "node:child_process";
5380
5630
  import { createHash as createHash4 } from "node:crypto";
5381
5631
  import fs7 from "node:fs";
5382
- import path19 from "node:path";
5632
+ import os3 from "node:os";
5633
+ import path20 from "node:path";
5383
5634
  import { isSea } from "node:sea";
5384
5635
 
5385
5636
  // src/versionDiscovery.ts
5386
5637
  import os2 from "node:os";
5387
- import path18 from "node:path";
5638
+ import path19 from "node:path";
5388
5639
  function defaultVersionsDir() {
5389
- return path18.join(os2.homedir(), ".local", "share", "claude", "versions");
5640
+ return path19.join(os2.homedir(), ".local", "share", "claude", "versions");
5390
5641
  }
5391
5642
  var NUMERIC_DOTTED_VERSION_RE = /^\d+(?:\.\d+)*$/;
5392
5643
  function isNumericDottedVersion(name) {
@@ -5428,14 +5679,14 @@ function discoverClaudeBinary(options) {
5428
5679
  const highestVersion = pickHighestVersion(entries);
5429
5680
  if (highestVersion !== void 0) {
5430
5681
  return {
5431
- path: path18.join(versionsDir, highestVersion),
5682
+ path: path19.join(versionsDir, highestVersion),
5432
5683
  source: "versions-dir",
5433
5684
  version: highestVersion
5434
5685
  };
5435
5686
  }
5436
- const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) => path18.resolve(dir)));
5687
+ const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) => path19.resolve(dir)));
5437
5688
  for (const dir of options.pathDirs) {
5438
- if (ownInstallDirs.has(path18.resolve(dir))) {
5689
+ if (ownInstallDirs.has(path19.resolve(dir))) {
5439
5690
  continue;
5440
5691
  }
5441
5692
  const found = options.findExecutableInDir(dir, "claude");
@@ -5480,7 +5731,7 @@ function isErrorWithCode(error, code) {
5480
5731
  }
5481
5732
  var OWNER_ONLY_DIR_MODE = 448;
5482
5733
  var OWNER_ONLY_FILE_MODE = 384;
5483
- var PERMISSION_BITS = 511;
5734
+ var PERMISSION_BITS2 = 511;
5484
5735
  var realFarmFs = {
5485
5736
  lstat(filePath) {
5486
5737
  let stat;
@@ -5546,7 +5797,7 @@ var realFarmFs = {
5546
5797
  appendFilePrivate(filePath, contents) {
5547
5798
  const descriptor = fs7.openSync(filePath, "a", OWNER_ONLY_FILE_MODE);
5548
5799
  try {
5549
- if ((fs7.fstatSync(descriptor).mode & PERMISSION_BITS) !== OWNER_ONLY_FILE_MODE) {
5800
+ if ((fs7.fstatSync(descriptor).mode & PERMISSION_BITS2) !== OWNER_ONLY_FILE_MODE) {
5550
5801
  fs7.fchmodSync(descriptor, OWNER_ONLY_FILE_MODE);
5551
5802
  }
5552
5803
  const bytes = Buffer.from(contents, "utf8");
@@ -5580,6 +5831,10 @@ var realFarmFs = {
5580
5831
  }
5581
5832
  }
5582
5833
  };
5834
+ var INT32_BYTE_LENGTH = 4;
5835
+ function realSleepSync(ms) {
5836
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(INT32_BYTE_LENGTH)), 0, 0, ms);
5837
+ }
5583
5838
  function realIsProcessAlive(pid) {
5584
5839
  try {
5585
5840
  process.kill(pid, 0);
@@ -5601,6 +5856,51 @@ var realRunPort = {
5601
5856
  return { status: result.status, stdout: result.stdout, stderr: result.stderr };
5602
5857
  }
5603
5858
  };
5859
+ function expandHome2(filePath) {
5860
+ return filePath.startsWith("~/") ? path20.join(os3.homedir(), filePath.slice(1)) : filePath;
5861
+ }
5862
+ var MACOS_GUI_SESSION_MANAGER = "Aqua";
5863
+ function hasDesktopSession() {
5864
+ if (process.platform === "darwin") {
5865
+ const result = spawnSync("launchctl", ["managername"], { encoding: "utf8" });
5866
+ return result.status === 0 && result.stdout.trim() === MACOS_GUI_SESSION_MANAGER;
5867
+ }
5868
+ if (process.platform === "win32") {
5869
+ return false;
5870
+ }
5871
+ return (process.env.DISPLAY ?? "") !== "" || (process.env.WAYLAND_DISPLAY ?? "") !== "";
5872
+ }
5873
+ var realCredentialPort = {
5874
+ readSecretFile(filePath) {
5875
+ const resolved = expandHome2(filePath);
5876
+ let content;
5877
+ let stat;
5878
+ try {
5879
+ stat = fs7.statSync(resolved);
5880
+ content = fs7.readFileSync(resolved, "utf8");
5881
+ } catch (error) {
5882
+ if (isEnoent3(error)) {
5883
+ return { found: false };
5884
+ }
5885
+ throw error;
5886
+ }
5887
+ return { found: true, content, mode: process.platform === "win32" ? void 0 : stat.mode };
5888
+ },
5889
+ runCommand(argv, options) {
5890
+ const [command, ...args] = argv;
5891
+ const result = spawnSync(command, args, {
5892
+ encoding: "utf8",
5893
+ timeout: options.timeoutMs,
5894
+ stdio: options.interactive ? ["inherit", "pipe", "inherit"] : ["ignore", "pipe", "pipe"]
5895
+ });
5896
+ if (result.error !== void 0) {
5897
+ const timedOut = isErrorWithCode(result.error, "ETIMEDOUT");
5898
+ return { status: result.status, stdout: "", stderr: timedOut ? "" : result.error.message, timedOut };
5899
+ }
5900
+ return { status: result.status, stdout: result.stdout, stderr: options.interactive ? "" : result.stderr, timedOut: false };
5901
+ },
5902
+ personPresent: () => process.stdin.isTTY || hasDesktopSession()
5903
+ };
5604
5904
  function resolveGitBranch(run, cwd) {
5605
5905
  const result = run.run("git", ["-C", cwd, "rev-parse", "--abbrev-ref", "HEAD"]);
5606
5906
  if (result.status !== 0) {
@@ -5615,6 +5915,62 @@ function resolveGitBranch(run, cwd) {
5615
5915
  }
5616
5916
  return { branch: name, branchDetached: false };
5617
5917
  }
5918
+ function resolveGitRoot(run, cwd) {
5919
+ const result = run.run("git", ["-C", cwd, "rev-parse", "--show-toplevel"]);
5920
+ if (result.status !== 0) {
5921
+ return void 0;
5922
+ }
5923
+ const root = result.stdout.trim();
5924
+ return root === "" ? void 0 : root;
5925
+ }
5926
+ function detachedDaemonSpawnOptions(logFd, env) {
5927
+ return { detached: true, stdio: ["ignore", logFd, logFd], env };
5928
+ }
5929
+ function spawnDaemonThrough(executable) {
5930
+ return (paths, subcommand, logPath) => spawnDetachedDaemon({ command: executable, args: [subcommand] }, paths, subcommand, logPath);
5931
+ }
5932
+ function spawnDetachedDaemon(invocation, paths, subcommand, logPath) {
5933
+ fs7.mkdirSync(path20.dirname(logPath), { recursive: true });
5934
+ const logFd = fs7.openSync(logPath, "a");
5935
+ try {
5936
+ const child = spawn(invocation.command, invocation.args, detachedDaemonSpawnOptions(logFd, { ...process.env, AGENT_SHIM_HOME: paths.root }));
5937
+ child.unref();
5938
+ if (child.pid === void 0) {
5939
+ throw new Error(`spawning ${subcommand} returned no pid`);
5940
+ }
5941
+ return child.pid;
5942
+ } finally {
5943
+ fs7.closeSync(logFd);
5944
+ }
5945
+ }
5946
+ function spawnHeadroomSupervisor(paths, spawnDaemon) {
5947
+ return spawnDaemon(paths, "__headroom-supervisor", paths.headroomLogPath);
5948
+ }
5949
+ function realHeadroomPort(paths, options) {
5950
+ return {
5951
+ ensure: () => {
5952
+ const up = ensureHeadroom({
5953
+ paths,
5954
+ launcherPid: process.pid,
5955
+ ports: {
5956
+ fs: realFarmFs,
5957
+ // Zombie-aware on purpose: a supervisor that died while still a child of this launcher sits unreaped until the launcher itself exits, and a defunct supervisor answering signal 0 as alive would stretch every launch to the full start timeout.
5958
+ isRunning: realIsProcessRunning,
5959
+ now: () => Date.now(),
5960
+ sleep: realSleepSync,
5961
+ spawnSupervisor: (layout) => spawnHeadroomSupervisor(layout, options.spawnDaemon)
5962
+ }
5963
+ });
5964
+ return {
5965
+ port: up.port,
5966
+ projectId: resolveGitRoot(realRunPort, options.cwd) ?? options.cwd
5967
+ };
5968
+ },
5969
+ release: () => {
5970
+ removeSession(realFarmFs, paths.headroomSessionsDir, process.pid);
5971
+ }
5972
+ };
5973
+ }
5618
5974
  var realProcPort = {
5619
5975
  env: process.env,
5620
5976
  argv: process.argv.slice(2),
@@ -5632,7 +5988,7 @@ function listVersionsDir(dir) {
5632
5988
  throw error;
5633
5989
  }
5634
5990
  return entries.filter((entry) => entry.isFile()).map((entry) => {
5635
- const fullPath = path19.join(dir, entry.name);
5991
+ const fullPath = path20.join(dir, entry.name);
5636
5992
  const stat = fs7.statSync(fullPath);
5637
5993
  return {
5638
5994
  name: entry.name,
@@ -5647,7 +6003,7 @@ function windowsPathExtensions(pathext) {
5647
6003
  return (pathext ?? WINDOWS_DEFAULT_PATHEXT).split(";").map((ext) => ext.trim()).filter((ext) => ext.length > 0);
5648
6004
  }
5649
6005
  function resolveExecutableCandidate(dir, name, env) {
5650
- const candidate = path19.join(dir, name);
6006
+ const candidate = path20.join(dir, name);
5651
6007
  if (env.platform === "win32") {
5652
6008
  const extensions = windowsPathExtensions(env.pathext);
5653
6009
  const alreadyHasRecognisedExtension = extensions.some((ext) => candidate.toLowerCase().endsWith(ext.toLowerCase()));
@@ -5696,13 +6052,13 @@ function resolveOwnExecutablePath(env) {
5696
6052
  if (env.argv1 !== void 0 && !env.argv1.includes("/") && !env.argv1.includes("\\")) {
5697
6053
  return searchPathForExecutable(env.pathDirs, env.argv1, env.findExecutableInDir) ?? env.execPath;
5698
6054
  }
5699
- const candidate = env.argv1 === void 0 ? env.execPath : path19.resolve(env.cwd, env.argv1);
5700
- const candidateDir = path19.dirname(candidate);
5701
- const candidateDirOnPath = env.pathDirs.some((dir) => path19.resolve(dir) === candidateDir);
6055
+ const candidate = env.argv1 === void 0 ? env.execPath : path20.resolve(env.cwd, env.argv1);
6056
+ const candidateDir = path20.dirname(candidate);
6057
+ const candidateDirOnPath = env.pathDirs.some((dir) => path20.resolve(dir) === candidateDir);
5702
6058
  if (candidateDirOnPath) {
5703
6059
  return candidate;
5704
6060
  }
5705
- const viaPath = searchPathForExecutable(env.pathDirs, path19.basename(candidate), env.findExecutableInDir);
6061
+ const viaPath = searchPathForExecutable(env.pathDirs, path20.basename(candidate), env.findExecutableInDir);
5706
6062
  return viaPath ?? candidate;
5707
6063
  }
5708
6064
  function realOwnExecutablePath() {
@@ -5710,21 +6066,21 @@ function realOwnExecutablePath() {
5710
6066
  argv1: process.argv[1],
5711
6067
  execPath: process.execPath,
5712
6068
  cwd: process.cwd(),
5713
- pathDirs: (process.env.PATH ?? "").split(path19.delimiter).filter((dir) => dir !== ""),
6069
+ pathDirs: (process.env.PATH ?? "").split(path20.delimiter).filter((dir) => dir !== ""),
5714
6070
  findExecutableInDir
5715
6071
  });
5716
6072
  }
5717
6073
  function realResolveClaudeBinary(ownInstallDirs) {
5718
6074
  return () => discoverClaudeBinary({
5719
6075
  listVersionsDir,
5720
- pathDirs: (process.env.PATH ?? "").split(path19.delimiter).filter((dir) => dir !== ""),
6076
+ pathDirs: (process.env.PATH ?? "").split(path20.delimiter).filter((dir) => dir !== ""),
5721
6077
  findExecutableInDir,
5722
6078
  ownInstallDirs: [...ownInstallDirs]
5723
6079
  });
5724
6080
  }
5725
6081
 
5726
6082
  // src/checkReport.ts
5727
- import path20 from "node:path";
6083
+ import path21 from "node:path";
5728
6084
  import { z as z10 } from "zod";
5729
6085
 
5730
6086
  // src/cli/bool.ts
@@ -6046,7 +6402,7 @@ function loadCheckProvider(paths, name) {
6046
6402
  }
6047
6403
  function collectCheckReport(params) {
6048
6404
  const { paths, cwd } = params;
6049
- const home = os3.homedir();
6405
+ const home = os4.homedir();
6050
6406
  const claudeHome = resolveClaudeHome();
6051
6407
  const read = cosmiconfigReader();
6052
6408
  const classification = loadClassification(paths);
@@ -6091,10 +6447,10 @@ function collectCheckReport(params) {
6091
6447
  }).input;
6092
6448
  const providerName = cascadeProviderName(cascade);
6093
6449
  const provider = providerName === void 0 ? void 0 : loadCheckProvider(paths, providerName);
6094
- const farmRoot = identityDecision.name === void 0 ? void 0 : path20.join(paths.identitiesDir, identityDecision.name);
6450
+ const farmRoot = identityDecision.name === void 0 ? void 0 : path21.join(paths.identitiesDir, identityDecision.name);
6095
6451
  const settingsFiles = {
6096
- "settings.json": realFsPort.readFileUtf8(path20.join(claudeHome, "settings.json")),
6097
- "settings.local.json": realFsPort.readFileUtf8(path20.join(claudeHome, "settings.local.json"))
6452
+ "settings.json": realFsPort.readFileUtf8(path21.join(claudeHome, "settings.json")),
6453
+ "settings.local.json": realFsPort.readFileUtf8(path21.join(claudeHome, "settings.local.json"))
6098
6454
  };
6099
6455
  const report = runCheck({
6100
6456
  cwd,
@@ -6124,7 +6480,7 @@ function collectCheckReport(params) {
6124
6480
 
6125
6481
  // src/claudeShim.ts
6126
6482
  import fs8 from "node:fs";
6127
- import path21 from "node:path";
6483
+ import path22 from "node:path";
6128
6484
  import { z as z11 } from "zod";
6129
6485
  var ClaudeShimStateSchema = z11.strictObject({
6130
6486
  targetPath: z11.string().min(1),
@@ -6135,29 +6491,29 @@ function commandFilename(ownExecutablePath, commandName) {
6135
6491
  return ownExecutablePath.toLowerCase().endsWith(".exe") ? `${commandName}.exe` : commandName;
6136
6492
  }
6137
6493
  function resolveOwnInstallDirs(paths, ownExecutablePath) {
6138
- const dirs = [path21.dirname(ownExecutablePath)];
6494
+ const dirs = [path22.dirname(ownExecutablePath)];
6139
6495
  const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
6140
6496
  if (state !== void 0) {
6141
- dirs.push(path21.dirname(state.targetPath));
6497
+ dirs.push(path22.dirname(state.targetPath));
6142
6498
  }
6143
6499
  return dirs;
6144
6500
  }
6145
6501
  var nodeLinkFs = { link: fs8.linkSync, copyFile: fs8.copyFileSync, chmod: fs8.chmodSync };
6146
6502
  function findPathShadow(params) {
6147
- const resolvedTargetDir = path21.resolve(params.targetDir);
6503
+ const resolvedTargetDir = path22.resolve(params.targetDir);
6148
6504
  for (const dir of params.pathDirs) {
6149
6505
  const found = params.findExecutableInDir(dir, params.targetFilename);
6150
6506
  if (found === void 0) {
6151
6507
  continue;
6152
6508
  }
6153
- return path21.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
6509
+ return path22.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
6154
6510
  }
6155
- return params.pathDirs.some((dir) => path21.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
6511
+ return params.pathDirs.some((dir) => path22.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
6156
6512
  }
6157
6513
 
6158
6514
  // src/doctorReport.ts
6159
6515
  import fs9 from "node:fs";
6160
- import path22 from "node:path";
6516
+ import path23 from "node:path";
6161
6517
  function refinePathShadow(status, ownExecutablePath, realpath) {
6162
6518
  if (status.status !== "shadowed") {
6163
6519
  return status;
@@ -6181,7 +6537,7 @@ function validateJson(schema, input) {
6181
6537
  return { ok: true, data: result.data };
6182
6538
  }
6183
6539
  function pushPathResolution(push, resolution) {
6184
- const ownDir = path22.dirname(resolution.ownExecutablePath);
6540
+ const ownDir = path23.dirname(resolution.ownExecutablePath);
6185
6541
  switch (resolution.agentShim.status) {
6186
6542
  case "ok":
6187
6543
  push("path-resolution", "pass", `\`agent-shim\` on PATH resolves to this running executable, ${resolution.ownExecutablePath}.`, "agent-shim");
@@ -6249,14 +6605,14 @@ function pushProvider(push, entry) {
6249
6605
  }
6250
6606
  function pushLegacyName(push, params) {
6251
6607
  const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
6252
- if (legacyVariables.length === 0 && path22.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
6608
+ if (legacyVariables.length === 0 && path23.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
6253
6609
  push("legacy-name", "pass", "Nothing here still uses the former `claude-use` name.");
6254
6610
  return;
6255
6611
  }
6256
6612
  for (const name of legacyVariables) {
6257
6613
  push("legacy-name", "warn", `${name} is the former name of ${name.replace(LEGACY_ENV_PREFIX, ENV_PREFIX)}. Rename it; the old name still works but is only a fallback.`, name);
6258
6614
  }
6259
- if (path22.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
6615
+ if (path23.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
6260
6616
  push(
6261
6617
  "legacy-name",
6262
6618
  "warn",
@@ -6564,18 +6920,18 @@ function collectDoctorReport(params) {
6564
6920
  const { paths } = params;
6565
6921
  const identityNames = fs9.existsSync(paths.identitiesDir) ? fs9.readdirSync(paths.identitiesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && isIdentityDirectoryName(entry.name)).map((entry) => entry.name).sort() : [];
6566
6922
  const identities = identityNames.map((name) => {
6567
- const farmRoot = path22.join(paths.identitiesDir, name);
6568
- const identityPath = path22.join(farmRoot, "identity.json");
6923
+ const farmRoot = path23.join(paths.identitiesDir, name);
6924
+ const identityPath = path23.join(farmRoot, "identity.json");
6569
6925
  return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot };
6570
6926
  });
6571
6927
  const profileNames = fs9.existsSync(paths.configProfilesDir) ? fs9.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
6572
6928
  const configProfiles = profileNames.map((name) => {
6573
- const profilePath = path22.join(paths.configProfilesDir, `${name}.json`);
6929
+ const profilePath = path23.join(paths.configProfilesDir, `${name}.json`);
6574
6930
  return { name, path: profilePath, raw: realFsPort.readFileUtf8(profilePath) };
6575
6931
  });
6576
6932
  const providerNames = fs9.existsSync(paths.providersDir) ? fs9.readdirSync(paths.providersDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
6577
6933
  const providers = providerNames.map((name) => {
6578
- const providerPath = path22.join(paths.providersDir, `${name}.json`);
6934
+ const providerPath = path23.join(paths.providersDir, `${name}.json`);
6579
6935
  return { name, path: providerPath, raw: realFsPort.readFileUtf8(providerPath) };
6580
6936
  });
6581
6937
  const ownExecutablePath = realOwnExecutablePath();
@@ -6587,12 +6943,12 @@ function collectDoctorReport(params) {
6587
6943
  binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
6588
6944
  }
6589
6945
  const shimState = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
6590
- const pathDirs = (params.env.PATH ?? "").split(path22.delimiter).filter((dir) => dir !== "");
6946
+ const pathDirs = (params.env.PATH ?? "").split(path23.delimiter).filter((dir) => dir !== "");
6591
6947
  const claudeShimShadow = shimState === void 0 ? void 0 : refinePathShadow(
6592
6948
  findPathShadow({
6593
6949
  pathDirs,
6594
- targetDir: path22.dirname(shimState.targetPath),
6595
- targetFilename: path22.basename(shimState.targetPath),
6950
+ targetDir: path23.dirname(shimState.targetPath),
6951
+ targetFilename: path23.basename(shimState.targetPath),
6596
6952
  findExecutableInDir
6597
6953
  }),
6598
6954
  shimState.targetPath,
@@ -6615,7 +6971,7 @@ function collectDoctorReport(params) {
6615
6971
  agentShim: refinePathShadow(
6616
6972
  findPathShadow({
6617
6973
  pathDirs,
6618
- targetDir: path22.dirname(ownExecutablePath),
6974
+ targetDir: path23.dirname(ownExecutablePath),
6619
6975
  targetFilename: commandFilename(ownExecutablePath, "agent-shim"),
6620
6976
  findExecutableInDir
6621
6977
  }),
@@ -6633,6 +6989,975 @@ function collectDoctorReport(params) {
6633
6989
  });
6634
6990
  return report;
6635
6991
  }
6992
+
6993
+ // src/launcher.ts
6994
+ import { randomUUID as randomUUID4 } from "node:crypto";
6995
+ import path25 from "node:path";
6996
+
6997
+ // src/launcher/argv.ts
6998
+ var ConflictingIdentityError = class extends UsageError {
6999
+ constructor(positional, flag) {
7000
+ super(`The launch names two identities: "@${positional}" and "--identity ${flag}". Pass only one.`);
7001
+ this.positional = positional;
7002
+ this.flag = flag;
7003
+ this.name = "ConflictingIdentityError";
7004
+ }
7005
+ positional;
7006
+ flag;
7007
+ };
7008
+ var VALUED_FLAGS = ["--identity", "--config-profile", "--provider", "--category", "--share", "--hide"];
7009
+ var BOOLEAN_FLAGS = [
7010
+ { flag: "--headroom", key: "headroom" },
7011
+ { flag: "--track-usage", key: "trackUsage" },
7012
+ { flag: "--skip-permissions", key: "skipPermissions" },
7013
+ { flag: "--remote-control", key: "remoteControl" },
7014
+ { flag: "--wait", key: "wait" }
7015
+ ];
7016
+ var LAUNCHER_FLAG_NAMES = [
7017
+ ...VALUED_FLAGS,
7018
+ "--no-provider",
7019
+ ...BOOLEAN_FLAGS.flatMap(({ flag }) => [flag, `--no-${flag.slice(2)}`])
7020
+ ];
7021
+ var TERMINATOR2 = "--";
7022
+ function matchValuedFlag(token) {
7023
+ for (const flag of VALUED_FLAGS) {
7024
+ if (token === flag) {
7025
+ return { flag };
7026
+ }
7027
+ if (token.startsWith(`${flag}=`)) {
7028
+ return { flag, inlineValue: token.slice(flag.length + 1) };
7029
+ }
7030
+ }
7031
+ return void 0;
7032
+ }
7033
+ function matchBooleanFlag(token) {
7034
+ for (const { flag, key } of BOOLEAN_FLAGS) {
7035
+ if (token === flag) {
7036
+ return { key, value: true };
7037
+ }
7038
+ if (token === `--no-${flag.slice(2)}`) {
7039
+ return { key, value: false };
7040
+ }
7041
+ }
7042
+ return void 0;
7043
+ }
7044
+ function parseLauncherArgv(argv) {
7045
+ const first = argv[0];
7046
+ const positionalIdentity = first !== void 0 && first.startsWith("@") && first.length > 1 ? first.slice(1) : void 0;
7047
+ const remaining = positionalIdentity === void 0 ? argv : argv.slice(1);
7048
+ let flagIdentity;
7049
+ let configProfile;
7050
+ let provider;
7051
+ const booleans = {};
7052
+ const categoryFlags = [];
7053
+ const shareFlags = [];
7054
+ const hideFlags = [];
7055
+ const rest = [];
7056
+ for (let index = 0; index < remaining.length; index += 1) {
7057
+ const token = remaining[index];
7058
+ if (token === void 0) {
7059
+ continue;
7060
+ }
7061
+ if (token === TERMINATOR2) {
7062
+ rest.push(...remaining.slice(index));
7063
+ break;
7064
+ }
7065
+ if (token === "--no-provider") {
7066
+ provider = false;
7067
+ continue;
7068
+ }
7069
+ const booleanFlag = matchBooleanFlag(token);
7070
+ if (booleanFlag !== void 0) {
7071
+ booleans[booleanFlag.key] = booleanFlag.value;
7072
+ continue;
7073
+ }
7074
+ const matched = matchValuedFlag(token);
7075
+ if (matched === void 0) {
7076
+ rest.push(token);
7077
+ continue;
7078
+ }
7079
+ let value;
7080
+ if (matched.inlineValue !== void 0) {
7081
+ value = matched.inlineValue;
7082
+ } else {
7083
+ const next = remaining[index + 1];
7084
+ if (next === void 0 || next === TERMINATOR2) {
7085
+ rest.push(token);
7086
+ continue;
7087
+ }
7088
+ value = next;
7089
+ index += 1;
7090
+ }
7091
+ switch (matched.flag) {
7092
+ case "--identity":
7093
+ flagIdentity = value;
7094
+ break;
7095
+ case "--config-profile":
7096
+ configProfile = value;
7097
+ break;
7098
+ case "--provider":
7099
+ provider = value;
7100
+ break;
7101
+ case "--category":
7102
+ categoryFlags.push(value);
7103
+ break;
7104
+ case "--share":
7105
+ shareFlags.push(value);
7106
+ break;
7107
+ case "--hide":
7108
+ hideFlags.push(value);
7109
+ break;
7110
+ default:
7111
+ matched.flag;
7112
+ }
7113
+ }
7114
+ if (positionalIdentity !== void 0 && flagIdentity !== void 0 && positionalIdentity !== flagIdentity) {
7115
+ throw new ConflictingIdentityError(positionalIdentity, flagIdentity);
7116
+ }
7117
+ const identity = flagIdentity ?? positionalIdentity;
7118
+ return {
7119
+ ...identity === void 0 ? {} : { identity },
7120
+ ...configProfile === void 0 ? {} : { configProfile },
7121
+ ...provider === void 0 ? {} : { provider },
7122
+ ...booleans,
7123
+ categoryFlags,
7124
+ shareFlags,
7125
+ hideFlags,
7126
+ rest
7127
+ };
7128
+ }
7129
+
7130
+ // src/cli/pairs.ts
7131
+ function splitCommas(input) {
7132
+ if (input === "") {
7133
+ return [];
7134
+ }
7135
+ return input.split(",");
7136
+ }
7137
+ function parsePair(input) {
7138
+ const eqIndex = input.indexOf("=");
7139
+ if (eqIndex === -1) {
7140
+ throw new Error(`Expected "<key>=<value>", got "${input}" (no "=" found)`);
7141
+ }
7142
+ const key = input.slice(0, eqIndex);
7143
+ const value = input.slice(eqIndex + 1);
7144
+ if (key === "") {
7145
+ throw new Error(`Expected a non-empty key before "=" in "${input}"`);
7146
+ }
7147
+ return { key, value };
7148
+ }
7149
+ function parseBool(input) {
7150
+ const parsed = parseBoolWord(input);
7151
+ if (parsed === void 0) {
7152
+ throw new Error(`Expected "true", "false", "1" or "0", got "${input}"`);
7153
+ }
7154
+ return parsed;
7155
+ }
7156
+ function parseBoolPairList(input) {
7157
+ const result = {};
7158
+ for (const piece of splitCommas(input)) {
7159
+ const { key, value } = parsePair(piece);
7160
+ result[key] = parseBool(value);
7161
+ }
7162
+ return result;
7163
+ }
7164
+
7165
+ // src/launcher/cliOverride.ts
7166
+ var InvalidCliCategoryError = class extends CliError {
7167
+ constructor(categoryName) {
7168
+ super(`"${categoryName}" is not a category this launch may toggle (runtime, history, knowledge, settings).`);
7169
+ this.categoryName = categoryName;
7170
+ this.name = "InvalidCliCategoryError";
7171
+ }
7172
+ categoryName;
7173
+ };
7174
+ var InvalidCliEntryKeyError = class extends CliError {
7175
+ constructor(key) {
7176
+ super(`"${key}" is not a valid entries key \u2014 it must start with "<category>/", e.g. "knowledge/skills/commit".`);
7177
+ this.key = key;
7178
+ this.name = "InvalidCliEntryKeyError";
7179
+ }
7180
+ key;
7181
+ };
7182
+ function toCategoryMap(pairs) {
7183
+ const expanded = expandAllCategoryKey(pairs);
7184
+ const result = {};
7185
+ for (const [key, value] of Object.entries(expanded)) {
7186
+ if (!isOverridableCategory(key)) {
7187
+ throw new InvalidCliCategoryError(key);
7188
+ }
7189
+ result[key] = value;
7190
+ }
7191
+ return result;
7192
+ }
7193
+ function toEntries(pairs) {
7194
+ for (const key of Object.keys(pairs)) {
7195
+ if (!ENTRY_KEY_RE.test(key)) {
7196
+ throw new InvalidCliEntryKeyError(key);
7197
+ }
7198
+ }
7199
+ return pairs;
7200
+ }
7201
+ function parseOverride(source, raw, parse) {
7202
+ try {
7203
+ return parse(raw);
7204
+ } catch (error) {
7205
+ if (error instanceof Error && !(error instanceof CliError)) {
7206
+ throw new UsageError(`Invalid ${source} value "${raw}": ${error.message}.`);
7207
+ }
7208
+ throw error;
7209
+ }
7210
+ }
7211
+ function buildCliOverride(params) {
7212
+ let categoryPairs = {};
7213
+ if (params.env.AGENT_SHIM_CATEGORY_OVERRIDE !== void 0 && params.env.AGENT_SHIM_CATEGORY_OVERRIDE !== "") {
7214
+ categoryPairs = parseOverride("AGENT_SHIM_CATEGORY_OVERRIDE", params.env.AGENT_SHIM_CATEGORY_OVERRIDE, parseBoolPairList);
7215
+ }
7216
+ for (const flagValue of params.categoryFlags) {
7217
+ const pair = parseOverride("--category", flagValue, (raw) => {
7218
+ const { key, value } = parsePair(raw);
7219
+ return { key, value: parseBool(value) };
7220
+ });
7221
+ categoryPairs[pair.key] = pair.value;
7222
+ }
7223
+ let entryPairs = {};
7224
+ if (params.env.AGENT_SHIM_ENTRY_OVERRIDE !== void 0 && params.env.AGENT_SHIM_ENTRY_OVERRIDE !== "") {
7225
+ entryPairs = parseOverride("AGENT_SHIM_ENTRY_OVERRIDE", params.env.AGENT_SHIM_ENTRY_OVERRIDE, parseBoolPairList);
7226
+ }
7227
+ for (const entryPath of params.shareFlags) {
7228
+ entryPairs[entryPath] = true;
7229
+ }
7230
+ for (const entryPath of params.hideFlags) {
7231
+ entryPairs[entryPath] = false;
7232
+ }
7233
+ const hasCategories = Object.keys(categoryPairs).length > 0;
7234
+ const hasEntries = Object.keys(entryPairs).length > 0;
7235
+ const hasProvider = params.providerFlag !== void 0 && params.providerFlag !== "";
7236
+ if (!hasCategories && !hasEntries && !hasProvider) {
7237
+ return void 0;
7238
+ }
7239
+ return {
7240
+ ...hasCategories ? { categories: toCategoryMap(categoryPairs) } : {},
7241
+ ...hasEntries ? { entries: toEntries(entryPairs) } : {},
7242
+ ...hasProvider ? { launch: { provider: params.providerFlag } } : {}
7243
+ };
7244
+ }
7245
+
7246
+ // src/launcher/flags.ts
7247
+ import path24 from "node:path";
7248
+
7249
+ // src/headroom/headers.ts
7250
+ function mergeAnthropicCustomHeaders(existing, additions) {
7251
+ const merged = /* @__PURE__ */ new Map();
7252
+ for (const block of existing) {
7253
+ if (block === void 0) {
7254
+ continue;
7255
+ }
7256
+ for (const line of block.split("\n")) {
7257
+ const entry = parseCustomHeaderLine(line);
7258
+ if (entry === void 0) {
7259
+ continue;
7260
+ }
7261
+ merged.set(entry.name, entry.value);
7262
+ }
7263
+ }
7264
+ for (const entry of additions) {
7265
+ merged.set(entry.name, entry.value);
7266
+ }
7267
+ return [...merged].map(([name, value]) => `${name}: ${value}`).join("\n");
7268
+ }
7269
+ function parseCustomHeaderLine(line) {
7270
+ const trimmed = line.trim();
7271
+ if (trimmed === "") {
7272
+ return void 0;
7273
+ }
7274
+ const colon = trimmed.indexOf(":");
7275
+ if (colon <= 0) {
7276
+ return void 0;
7277
+ }
7278
+ return { name: trimmed.slice(0, colon).trim(), value: trimmed.slice(colon + 1).trim() };
7279
+ }
7280
+
7281
+ // src/launcher/flags.ts
7282
+ function resolveLaunchFlags(params) {
7283
+ return {
7284
+ skipPermissions: params.flags?.skipPermissions ?? parseEnvBool("AGENT_SHIM_SKIP_PERMISSIONS", params.env.AGENT_SHIM_SKIP_PERMISSIONS) ?? params.cascade?.skipPermissions ?? false,
7285
+ remoteControl: params.flags?.remoteControl ?? parseEnvBool("AGENT_SHIM_REMOTE_CONTROL", params.env.AGENT_SHIM_REMOTE_CONTROL) ?? params.cascade?.remoteControl ?? false,
7286
+ headroom: params.flags?.headroom ?? parseEnvBool("AGENT_SHIM_HEADROOM", params.env.AGENT_SHIM_HEADROOM) ?? params.cascade?.headroom ?? false,
7287
+ trackUsage: params.flags?.trackUsage ?? parseEnvBool("AGENT_SHIM_TRACK_USAGE", params.env.AGENT_SHIM_TRACK_USAGE) ?? params.cascade?.trackUsage ?? params.trackUsageDefault ?? false
7288
+ };
7289
+ }
7290
+ function buildFlagArgs(flags) {
7291
+ const args = [];
7292
+ if (flags.skipPermissions) {
7293
+ args.push("--dangerously-skip-permissions");
7294
+ }
7295
+ if (flags.remoteControl) {
7296
+ args.push("--remote-control=");
7297
+ }
7298
+ return args;
7299
+ }
7300
+ function buildArgv(params) {
7301
+ return [...params.toolFlags, ...params.extraFlags, ...params.passthrough];
7302
+ }
7303
+ var LOOPBACK_HOSTS = ["127.0.0.1", "localhost", "::1"];
7304
+ function isLoopbackUrl(baseUrl) {
7305
+ const host = new URL(baseUrl).hostname.replace(/^\[|\]$/g, "");
7306
+ return LOOPBACK_HOSTS.some((loopback) => loopback === host);
7307
+ }
7308
+ function withLoopbackHosts(existing) {
7309
+ const listed = (existing ?? "").split(",").map((entry) => entry.trim()).filter((entry) => entry !== "");
7310
+ return [...listed, ...LOOPBACK_HOSTS.filter((host) => !listed.includes(host))].join(",");
7311
+ }
7312
+ function buildEnv(params) {
7313
+ const env = { ...params.baseEnv };
7314
+ const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
7315
+ let providerCustomHeaders;
7316
+ if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
7317
+ env.CLAUDE_CONFIG_DIR = path24.join(params.identitiesDir, params.resolvedIdentityName);
7318
+ }
7319
+ if (params.provider !== void 0) {
7320
+ const providerEnv = params.provider.definition.env ?? {};
7321
+ providerCustomHeaders = providerEnv.ANTHROPIC_CUSTOM_HEADERS;
7322
+ env.ANTHROPIC_BASE_URL = params.provider.baseUrl;
7323
+ if (isLoopbackUrl(params.provider.baseUrl)) {
7324
+ env.NO_PROXY = withLoopbackHosts(params.baseEnv.NO_PROXY);
7325
+ env.no_proxy = withLoopbackHosts(params.baseEnv.no_proxy);
7326
+ }
7327
+ env.AGENT_SHIM_PROVIDER = params.provider.definition.displayName;
7328
+ for (const [key, value] of Object.entries(providerEnv)) {
7329
+ env[key] = value;
7330
+ }
7331
+ }
7332
+ const credential = params.provider?.credential ?? params.identityCredential;
7333
+ if (credential !== void 0) {
7334
+ for (const [variable, value] of Object.entries(credentialVariables(credential.target, credential.token))) {
7335
+ env[variable] = value;
7336
+ }
7337
+ }
7338
+ if (params.headroom !== void 0) {
7339
+ env.HEADROOM_PROXY_URL = `http://127.0.0.1:${String(params.headroom.port)}`;
7340
+ }
7341
+ if (params.frontdoor !== void 0) {
7342
+ env.ANTHROPIC_CUSTOM_HEADERS = mergeAnthropicCustomHeaders(
7343
+ [
7344
+ ...parentCustomHeaders === void 0 ? [] : [parentCustomHeaders],
7345
+ ...providerCustomHeaders === void 0 ? [] : [providerCustomHeaders]
7346
+ ],
7347
+ [
7348
+ ...params.resolvedIdentityName === void 0 ? [] : [{ name: IDENTITY_HEADER, value: params.resolvedIdentityName }],
7349
+ { name: SESSION_HEADER, value: params.sessionId },
7350
+ { name: AUTH_HEADER, value: params.frontdoor.sessionToken },
7351
+ ...params.headroom === void 0 ? [] : [
7352
+ { name: HEADROOM_FLAG_HEADER, value: "1" },
7353
+ { name: PROJECT_ID_HEADER, value: params.headroom.projectId }
7354
+ ]
7355
+ ]
7356
+ );
7357
+ env.NODE_EXTRA_CA_CERTS = params.frontdoor.trustBundlePath;
7358
+ if (params.provider === void 0) {
7359
+ env.HTTPS_PROXY = connectProxyUrl(params.frontdoor.connectPort, params.frontdoor.sessionToken);
7360
+ }
7361
+ }
7362
+ return env;
7363
+ }
7364
+
7365
+ // src/launcher/extraFlags.ts
7366
+ function splitExtraFlags(value) {
7367
+ if (value === void 0) {
7368
+ return [];
7369
+ }
7370
+ const trimmed = value.trim();
7371
+ if (trimmed === "") {
7372
+ return [];
7373
+ }
7374
+ return trimmed.split(/\s+/);
7375
+ }
7376
+
7377
+ // src/launcher.ts
7378
+ function resolveIdentityCredential(identity, credential, env, port) {
7379
+ if (port === void 0) {
7380
+ return { ok: false, status: 1, message: `agent-shim: identity ${identity} needs its credential resolved, but this launcher has no credential port wired` };
7381
+ }
7382
+ const resolution = resolveCredential({ credential, env, port, subject: `identity ${identity}` });
7383
+ return resolution.ok ? resolution : { ok: false, status: CREDENTIAL_UNAVAILABLE_EXIT, message: resolution.message };
7384
+ }
7385
+ function pickFromPool(decided, params, parsedArgv) {
7386
+ const { paths, fs: fs12, proc, log } = params;
7387
+ if (decided.pool === void 0) {
7388
+ return { identityDecision: decided };
7389
+ }
7390
+ const farmRuntime = params.farm;
7391
+ if (farmRuntime === void 0) {
7392
+ log.error(`agent-shim: pool "${decided.pool}" was selected, but this launcher has no farm wired to read usage and pick a member with.`);
7393
+ return proc.exit(1);
7394
+ }
7395
+ const resolution = resolvePoolLaunch({
7396
+ poolName: decided.pool,
7397
+ selectedVia: decided.source,
7398
+ pools: params.pools,
7399
+ paths,
7400
+ fs: fs12,
7401
+ usageFs: farmRuntime.fs,
7402
+ cwd: farmRuntime.cwd,
7403
+ now: farmRuntime.now,
7404
+ sleep: farmRuntime.lock.sleep,
7405
+ passthrough: parsedArgv.rest,
7406
+ wait: parsedArgv.wait === true,
7407
+ log
7408
+ });
7409
+ if (!resolution.ok) {
7410
+ log.error(resolution.message);
7411
+ return proc.exit(1);
7412
+ }
7413
+ return { identityDecision: { ...decided, name: resolution.identity }, poolExplanation: resolution.explanation };
7414
+ }
7415
+ function prepareLaunch(params) {
7416
+ const { paths, fs: fs12, proc, log } = params;
7417
+ const { env, argv } = proc;
7418
+ const parsedArgv = parseLauncherArgv(argv);
7419
+ const cliOverride = buildCliOverride({
7420
+ env,
7421
+ categoryFlags: parsedArgv.categoryFlags,
7422
+ shareFlags: parsedArgv.shareFlags,
7423
+ hideFlags: parsedArgv.hideFlags
7424
+ });
7425
+ const configDirEscapeHatchApplies = env.CLAUDE_CONFIG_DIR !== void 0 && env.CLAUDE_CONFIG_DIR !== "";
7426
+ const decidedIdentity = decideIdentity({
7427
+ env,
7428
+ argv0Identity: parsedArgv.identity,
7429
+ directoryPinnedIdentity: params.directoryPinnedIdentity,
7430
+ readActiveIdentityFile: () => {
7431
+ const raw = fs12.readFileUtf8(paths.activeIdentityFile);
7432
+ if (raw === void 0) {
7433
+ return void 0;
7434
+ }
7435
+ const trimmed = raw.trim();
7436
+ return trimmed === "" ? void 0 : trimmed;
7437
+ }
7438
+ });
7439
+ const { identityDecision, poolExplanation } = pickFromPool(decidedIdentity, params, parsedArgv);
7440
+ const farmIdentity = configDirEscapeHatchApplies ? void 0 : identityDecision.name;
7441
+ const farm = farmIdentity === void 0 ? void 0 : params.farm;
7442
+ if (farm !== void 0 && farmIdentity !== void 0) {
7443
+ let recovery;
7444
+ try {
7445
+ recovery = recoverFarm({
7446
+ fs: farm.fs,
7447
+ identitiesDir: paths.identitiesDir,
7448
+ identity: farmIdentity,
7449
+ now: farm.now,
7450
+ lock: farm.lock,
7451
+ classification: farm.classification
7452
+ });
7453
+ } catch (error) {
7454
+ if (error instanceof IdentityLockBusyError) {
7455
+ log.error(error.message);
7456
+ proc.exit(1);
7457
+ }
7458
+ throw error;
7459
+ }
7460
+ for (const diagnostic of recoveryDiagnostics(recovery, farmIdentity)) {
7461
+ log.warn(`agent-shim: ${diagnostic.code}: ${diagnostic.message}`);
7462
+ }
7463
+ }
7464
+ let loadedIdentity;
7465
+ if (identityDecision.name !== void 0) {
7466
+ loadedIdentity = loadIdentity(paths.identitiesDir, identityDecision.name, fs12);
7467
+ if (loadedIdentity === void 0) {
7468
+ log.error(
7469
+ `agent-shim: no identity named "${identityDecision.name}" (selected via ${identityDecision.source}). Run \`agent-shim identity add ${identityDecision.name}\` first.`
7470
+ );
7471
+ proc.exit(1);
7472
+ }
7473
+ }
7474
+ const configProfileDecision = decideConfigProfile({
7475
+ env,
7476
+ cliFlagConfigProfile: params.cliFlagConfigProfile ?? parsedArgv.configProfile,
7477
+ directoryRuleConfigProfile: params.directoryRuleConfigProfile,
7478
+ identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
7479
+ globalDefaultConfigProfile: params.globalDefaultConfigProfile
7480
+ });
7481
+ if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(path25.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
7482
+ log.error(
7483
+ `agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
7484
+ );
7485
+ proc.exit(1);
7486
+ }
7487
+ const farmContext = farm !== void 0 && farmIdentity !== void 0 ? { farm, identity: farmIdentity, cascade: farm.loadCascade(configProfileDecision.name, cliOverride) } : void 0;
7488
+ const provider = parsedArgv.provider === false ? void 0 : resolveProvider({
7489
+ paths,
7490
+ port: fs12,
7491
+ env,
7492
+ ...params.credentials === void 0 ? {} : { credentials: params.credentials },
7493
+ ...parsedArgv.provider === void 0 ? {} : { cliProvider: parsedArgv.provider },
7494
+ ...farmContext === void 0 ? {} : { cascade: farmContext.cascade }
7495
+ });
7496
+ if (provider !== void 0 && !provider.ok) {
7497
+ log.error(provider.message);
7498
+ proc.exit(provider.status);
7499
+ }
7500
+ const resolvedProvider = provider?.ok === true ? provider.provider : void 0;
7501
+ for (const warning of provider?.ok === true ? provider.warnings : []) {
7502
+ log.warn(warning);
7503
+ }
7504
+ if (farm !== void 0 && farmIdentity !== void 0) {
7505
+ try {
7506
+ const snapshot = readUsageSnapshot(farm.fs, paths.usageSnapshotsDir, farmIdentity);
7507
+ for (const warning of quotaWarnings(snapshot, resolvedProvider?.name ?? ANTHROPIC_PROVIDER, farm.now())) {
7508
+ log.warn(warning);
7509
+ }
7510
+ } catch (error) {
7511
+ if (!(error instanceof UsageSnapshotError)) {
7512
+ throw error;
7513
+ }
7514
+ log.warn(`agent-shim: ${error.message}`);
7515
+ }
7516
+ }
7517
+ const identityCredentialBlock = loadedIdentity?.config.credential;
7518
+ const identityResolution = resolvedProvider === void 0 && farmIdentity !== void 0 && identityCredentialBlock !== void 0 ? resolveIdentityCredential(farmIdentity, identityCredentialBlock, env, params.credentials) : void 0;
7519
+ if (identityResolution !== void 0 && !identityResolution.ok) {
7520
+ log.error(identityResolution.message);
7521
+ proc.exit(identityResolution.status);
7522
+ }
7523
+ const identityCredential = identityResolution?.ok === true ? identityResolution.credential : void 0;
7524
+ for (const warning of identityCredential?.warnings ?? []) {
7525
+ log.warn(warning);
7526
+ }
7527
+ const guardResult = evaluateAmbientCredentialGuard({
7528
+ env,
7529
+ allowAmbientCredential: loadedIdentity?.config.allowAmbientCredential ?? false,
7530
+ allowAmbientCredentialOverride: parseEnvBool("AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL", env.AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL) === true,
7531
+ identityName: identityDecision.name,
7532
+ providerSelected: resolvedProvider !== void 0,
7533
+ ...identityCredential === void 0 ? {} : { injectedCredential: { variable: CREDENTIAL_TARGET_VARS[identityCredential.target], token: identityCredential.token } }
7534
+ });
7535
+ if (!guardResult.ok) {
7536
+ log.error(guardResult.message);
7537
+ proc.exit(1);
7538
+ }
7539
+ log.info(
7540
+ `agent-shim: identity ${identityDecision.name ?? "(none)"} (${identityDecision.source}${poolExplanation === void 0 ? "" : `, ${poolExplanation}`}), config profile ${configProfileDecision.name ?? "(none)"} (${configProfileDecision.source})` + (resolvedProvider === void 0 ? "" : `, provider ${resolvedProvider.name} (credential ${resolvedProvider.credential.target} from ${describeSource(resolvedProvider.credential.source)})`) + (identityCredential === void 0 ? "" : `, identity credential ${identityCredential.target} from ${describeSource(identityCredential.source)}`)
7541
+ );
7542
+ let cascadeLaunch;
7543
+ if (farmContext !== void 0) {
7544
+ const { farm: resyncFarmRuntime, identity: resyncIdentity, cascade } = farmContext;
7545
+ let result;
7546
+ try {
7547
+ result = resyncFarm({
7548
+ fs: resyncFarmRuntime.fs,
7549
+ identitiesDir: paths.identitiesDir,
7550
+ identity: resyncIdentity,
7551
+ ...configProfileDecision.name === void 0 ? {} : { configProfile: configProfileDecision.name },
7552
+ claudeHome: resyncFarmRuntime.claudeHome,
7553
+ home: resyncFarmRuntime.home,
7554
+ cwd: resyncFarmRuntime.cwd,
7555
+ env,
7556
+ ...resyncFarmRuntime.branch === void 0 ? {} : { branch: resyncFarmRuntime.branch },
7557
+ ...resyncFarmRuntime.branchDetached === void 0 ? {} : { branchDetached: resyncFarmRuntime.branchDetached },
7558
+ cascade,
7559
+ classification: resyncFarmRuntime.classification,
7560
+ now: resyncFarmRuntime.now,
7561
+ uniqueSuffix: resyncFarmRuntime.uniqueSuffix,
7562
+ lock: resyncFarmRuntime.lock
7563
+ });
7564
+ } catch (error) {
7565
+ if (error instanceof IdentityLockBusyError) {
7566
+ log.error(error.message);
7567
+ proc.exit(1);
7568
+ }
7569
+ throw error;
7570
+ }
7571
+ for (const diagnostic of result.diagnostics) {
7572
+ if (diagnostic.severity === "error") {
7573
+ log.error(`agent-shim: ${diagnostic.code}: ${diagnostic.message}`);
7574
+ } else if (diagnostic.severity === "warning") {
7575
+ log.warn(`agent-shim: ${diagnostic.code}: ${diagnostic.message}`);
7576
+ }
7577
+ }
7578
+ log.info(
7579
+ result.noOp ? `agent-shim: farm at ${result.farmRoot} already matches the resolved cascade` : `agent-shim: farm at ${result.farmRoot} resynced (${String(result.manifest.links.length)} link(s), ${String(result.manifest.materialised.length)} built director(ies)${result.adopted.length === 0 ? "" : `, ${String(result.adopted.length)} adopted into ${resyncFarmRuntime.claudeHome}`})`
7580
+ );
7581
+ cascadeLaunch = result.resolved.flattened.launch;
7582
+ } else if (params.farm !== void 0) {
7583
+ cascadeLaunch = flattenLayers(assembleCascade(params.farm.loadCascade(configProfileDecision.name, cliOverride)).layers, { home: params.farm.home }).launch;
7584
+ }
7585
+ const discovered = params.resolveClaudeBinary();
7586
+ const resolvedFlags = resolveLaunchFlags({
7587
+ env,
7588
+ // A pool pick reads the usage the front door records, so a pool launch records its own unless something says otherwise.
7589
+ ...poolExplanation === void 0 ? {} : { trackUsageDefault: true },
7590
+ ...cascadeLaunch === void 0 ? {} : { cascade: cascadeLaunch },
7591
+ flags: {
7592
+ ...parsedArgv.skipPermissions === void 0 ? {} : { skipPermissions: parsedArgv.skipPermissions },
7593
+ ...parsedArgv.remoteControl === void 0 ? {} : { remoteControl: parsedArgv.remoteControl },
7594
+ ...parsedArgv.headroom === void 0 ? {} : { headroom: parsedArgv.headroom },
7595
+ ...parsedArgv.trackUsage === void 0 ? {} : { trackUsage: parsedArgv.trackUsage }
7596
+ }
7597
+ });
7598
+ const frontDoorPort = params.frontdoor;
7599
+ const frontDoorEngaged = resolvedProvider !== void 0 || resolvedFlags.headroom || resolvedFlags.trackUsage;
7600
+ if (frontDoorEngaged && frontDoorPort === void 0) {
7601
+ log.error("agent-shim: this launch routes through the front-door daemon, but this launcher has no front-door port wired; refusing to launch without it.");
7602
+ proc.exit(1);
7603
+ }
7604
+ const frontDoor = frontDoorEngaged && frontDoorPort !== void 0 ? frontDoorPort.ensure(env.NODE_EXTRA_CA_CERTS) : void 0;
7605
+ if (frontDoor?.trustWarning !== void 0) {
7606
+ log.warn(frontDoor.trustWarning);
7607
+ }
7608
+ let routedProvider;
7609
+ if (resolvedProvider !== void 0 && frontDoor !== void 0) {
7610
+ routedProvider = { ...resolvedProvider, baseUrl: providerBaseUrl(frontDoor.port, resolvedProvider.name) };
7611
+ }
7612
+ let headroom;
7613
+ const headroomPort = params.headroom;
7614
+ if (resolvedFlags.headroom && headroomPort !== void 0) {
7615
+ headroom = headroomPort.ensure();
7616
+ const via = resolvedProvider === void 0 ? `OAuth via the door's CONNECT surface on 127.0.0.1:${String(frontDoor?.connectPort ?? 0)}` : `provider ${resolvedProvider.name}`;
7617
+ log.info(`agent-shim: routing through the front door on 127.0.0.1:${String(frontDoor?.port ?? 0)} with headroom on 127.0.0.1:${String(headroom.port)} (${via}, project ${headroom.projectId})`);
7618
+ } else if (resolvedFlags.headroom) {
7619
+ log.error("agent-shim: headroom routing was requested but this launcher has no headroom port wired; refusing to launch without it.");
7620
+ proc.exit(1);
7621
+ } else if (frontDoor !== void 0) {
7622
+ log.info(`agent-shim: routing through the front door on 127.0.0.1:${String(frontDoor.port)}${resolvedProvider === void 0 ? ` (OAuth via the door's CONNECT surface on 127.0.0.1:${String(frontDoor.connectPort)}, usage recorded)` : ` (provider ${resolvedProvider.name})`}`);
7623
+ }
7624
+ const frontDoorRelease = frontDoor === void 0 ? void 0 : frontDoorPort?.release;
7625
+ const finalArgv = buildArgv({
7626
+ toolFlags: buildFlagArgs(resolvedFlags),
7627
+ extraFlags: splitExtraFlags(env.CLAUDE_EXTRA_FLAGS),
7628
+ passthrough: parsedArgv.rest
7629
+ });
7630
+ const finalEnv = buildEnv({
7631
+ baseEnv: env,
7632
+ configDirEscapeHatch: configDirEscapeHatchApplies,
7633
+ resolvedIdentityName: identityDecision.name,
7634
+ identitiesDir: paths.identitiesDir,
7635
+ ...routedProvider === void 0 ? {} : { provider: routedProvider },
7636
+ ...identityCredential === void 0 ? {} : { identityCredential },
7637
+ ...frontDoor === void 0 ? {} : { frontdoor: frontDoor },
7638
+ ...headroom === void 0 ? {} : { headroom },
7639
+ sessionId: randomUUID4()
7640
+ });
7641
+ const releases = [...headroom === void 0 || headroomPort === void 0 ? [] : [headroomPort.release], ...frontDoorRelease === void 0 ? [] : [frontDoorRelease]];
7642
+ const release = () => {
7643
+ for (const registered of releases) {
7644
+ registered();
7645
+ }
7646
+ };
7647
+ return { bin: discovered.path, args: finalArgv, env: finalEnv, release };
7648
+ }
7649
+
7650
+ // src/launchWiring.ts
7651
+ import os5 from "node:os";
7652
+ import { randomUUID as randomUUID5 } from "node:crypto";
7653
+
7654
+ // src/realCredentialCache.ts
7655
+ import { spawnSync as spawnSync2 } from "node:child_process";
7656
+ import fs10 from "node:fs";
7657
+ import path26 from "node:path";
7658
+ var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
7659
+ var CACHE_DIR_MODE = 448;
7660
+ var CACHE_FILE_MODE = 384;
7661
+ function cacheFileNameFor(owner) {
7662
+ return `${owner.replace(/[^A-Za-z0-9._-]/g, "_")}.json`;
7663
+ }
7664
+ function parseEntry(raw) {
7665
+ let json;
7666
+ try {
7667
+ json = JSON.parse(raw);
7668
+ } catch {
7669
+ return void 0;
7670
+ }
7671
+ const parsed = CachedCredentialSchema.safeParse(json);
7672
+ return parsed.success ? parsed.data : void 0;
7673
+ }
7674
+ function requireKeychain() {
7675
+ if (process.platform !== "darwin") {
7676
+ throw new Error("the keychain credential store needs macOS; use --credential-cache-store file");
7677
+ }
7678
+ }
7679
+ function security(args, stdin) {
7680
+ const result = spawnSync2("security", args, { encoding: "utf8", ...stdin === void 0 ? {} : { input: stdin }, stdio: ["pipe", "pipe", "ignore"] });
7681
+ return { status: result.status, stdout: result.stdout };
7682
+ }
7683
+ function createRealCredentialCache(root) {
7684
+ const dir = path26.join(root, "credential-cache");
7685
+ const filePath = (owner) => path26.join(dir, cacheFileNameFor(owner));
7686
+ return {
7687
+ read(store, owner) {
7688
+ if (store === "file") {
7689
+ try {
7690
+ return parseEntry(fs10.readFileSync(filePath(owner), "utf8"));
7691
+ } catch {
7692
+ return void 0;
7693
+ }
7694
+ }
7695
+ requireKeychain();
7696
+ const result = security(["find-generic-password", "-s", KEYCHAIN_CACHE_SERVICE, "-a", owner, "-w"]);
7697
+ return result.status === 0 ? parseEntry(Buffer.from(result.stdout.trim(), "base64").toString("utf8")) : void 0;
7698
+ },
7699
+ write(store, owner, entry) {
7700
+ const serialised = JSON.stringify(entry);
7701
+ if (store === "file") {
7702
+ fs10.mkdirSync(dir, { recursive: true, mode: CACHE_DIR_MODE });
7703
+ fs10.chmodSync(dir, CACHE_DIR_MODE);
7704
+ const target = filePath(owner);
7705
+ const temp = `${target}.${String(process.pid)}.tmp`;
7706
+ fs10.writeFileSync(temp, serialised, { mode: CACHE_FILE_MODE });
7707
+ fs10.renameSync(temp, target);
7708
+ return;
7709
+ }
7710
+ requireKeychain();
7711
+ const encoded = Buffer.from(serialised, "utf8").toString("base64");
7712
+ const result = security(["-i"], `add-generic-password -U -s ${KEYCHAIN_CACHE_SERVICE} -a ${JSON.stringify(owner)} -w ${encoded}
7713
+ `);
7714
+ if (result.status !== 0) {
7715
+ throw new Error(`could not write the keychain credential cache for ${owner}`);
7716
+ }
7717
+ },
7718
+ remove(store, owner) {
7719
+ if (store === "file") {
7720
+ fs10.rmSync(filePath(owner), { force: true });
7721
+ return;
7722
+ }
7723
+ requireKeychain();
7724
+ security(["delete-generic-password", "-s", KEYCHAIN_CACHE_SERVICE, "-a", owner]);
7725
+ }
7726
+ };
7727
+ }
7728
+ function realCredentialCacheEnv(paths) {
7729
+ return { port: createRealCredentialCache(paths.root), platform: process.platform, now: () => Date.now() };
7730
+ }
7731
+
7732
+ // src/frontdoor/realFrontDoorPort.ts
7733
+ import fs11 from "node:fs";
7734
+
7735
+ // src/frontdoor/probe.ts
7736
+ import { Worker } from "node:worker_threads";
7737
+ var PROBE_TIMEOUT_MS = 2e3;
7738
+ var PROBE_WAIT_MARGIN_MS = 1e3;
7739
+ var REASON_BYTES = 1024;
7740
+ var HEADER_SLOTS = 2;
7741
+ var INT32_BYTES = 4;
7742
+ var VERDICT_PENDING = 0;
7743
+ var VERDICT_OK = 1;
7744
+ var VERDICT_FAILED = 2;
7745
+ var PROBE_SOURCE = `
7746
+ const { workerData } = require("node:worker_threads");
7747
+ const https = require("node:https");
7748
+ const { port, ca, timeoutMs, shared, ok, failed, headerSlots } = workerData;
7749
+ const header = new Int32Array(shared, 0, headerSlots);
7750
+ const reason = new Uint8Array(shared, headerSlots * 4);
7751
+ let done = false;
7752
+ const finish = (verdict, message) => {
7753
+ if (done) return;
7754
+ done = true;
7755
+ const bytes = Buffer.from(String(message), "utf8").subarray(0, reason.length);
7756
+ reason.set(bytes);
7757
+ Atomics.store(header, 1, bytes.length);
7758
+ Atomics.store(header, 0, verdict);
7759
+ Atomics.notify(header, 0);
7760
+ };
7761
+ const request = https.get({ host: "127.0.0.1", port, path: "/healthz", ca: [ca], agent: false }, (response) => {
7762
+ let body = "";
7763
+ response.setEncoding("utf8");
7764
+ response.on("data", (chunk) => { body += chunk; });
7765
+ response.on("end", () => {
7766
+ if (response.statusCode === 200 && body === "ok") finish(ok, "");
7767
+ else finish(failed, "the listener answered its health probe with HTTP " + String(response.statusCode));
7768
+ });
7769
+ response.on("error", (error) => finish(failed, error.message));
7770
+ });
7771
+ // A hard deadline over the whole exchange, handshake included: a listener that accepts the connection and then says nothing must still fail the probe.
7772
+ setTimeout(() => { request.destroy(new Error("no answer within " + String(timeoutMs) + "ms")); }, timeoutMs);
7773
+ request.on("error", (error) => finish(failed, (error.code ? error.code + ": " : "") + error.message));
7774
+ `;
7775
+ function probeFrontDoorSync(port, caPem) {
7776
+ const shared = new SharedArrayBuffer(HEADER_SLOTS * INT32_BYTES + REASON_BYTES);
7777
+ const header = new Int32Array(shared, 0, HEADER_SLOTS);
7778
+ const worker = new Worker(PROBE_SOURCE, {
7779
+ eval: true,
7780
+ workerData: { port, ca: caPem, timeoutMs: PROBE_TIMEOUT_MS, shared, ok: VERDICT_OK, failed: VERDICT_FAILED, headerSlots: HEADER_SLOTS }
7781
+ });
7782
+ worker.unref();
7783
+ try {
7784
+ const waited = Atomics.wait(header, 0, VERDICT_PENDING, PROBE_TIMEOUT_MS + PROBE_WAIT_MARGIN_MS);
7785
+ const verdict = Atomics.load(header, 0);
7786
+ if (waited === "timed-out" || verdict === VERDICT_PENDING) {
7787
+ return { ok: false, reason: `the probe did not finish within ${String(PROBE_TIMEOUT_MS + PROBE_WAIT_MARGIN_MS)}ms` };
7788
+ }
7789
+ if (verdict === VERDICT_OK) {
7790
+ return { ok: true };
7791
+ }
7792
+ const length = Atomics.load(header, 1);
7793
+ return { ok: false, reason: Buffer.from(new Uint8Array(shared, HEADER_SLOTS * INT32_BYTES, length)).toString("utf8") };
7794
+ } finally {
7795
+ void worker.terminate();
7796
+ }
7797
+ }
7798
+
7799
+ // src/frontdoor/trust.ts
7800
+ import { createHash as createHash5 } from "node:crypto";
7801
+ import path27 from "node:path";
7802
+ var BUNDLE_NAME_HEX_DIGITS = 16;
7803
+ function resolveTrustBundle(params) {
7804
+ const { caCertFile, bundlesDir, inherited, fs: fs12 } = params;
7805
+ if (inherited === void 0 || inherited === "" || path27.resolve(inherited) === path27.resolve(caCertFile)) {
7806
+ return { path: caCertFile };
7807
+ }
7808
+ const caPem = fs12.readFileUtf8(caCertFile);
7809
+ let inheritedPem;
7810
+ try {
7811
+ inheritedPem = fs12.readFileUtf8(inherited);
7812
+ } catch (error) {
7813
+ return {
7814
+ path: caCertFile,
7815
+ warning: `agent-shim: NODE_EXTRA_CA_CERTS names ${inherited}, which could not be read (${error instanceof Error ? error.message : String(error)}); the child trusts agent-shim's front-door CA on top of the system store, and nothing from that file`
7816
+ };
7817
+ }
7818
+ if (inheritedPem.includes(caPem.trim())) {
7819
+ return { path: inherited };
7820
+ }
7821
+ const combined = `${inheritedPem.trimEnd()}
7822
+ ${caPem}`;
7823
+ const bundle = path27.join(bundlesDir, `${createHash5("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
7824
+ if (!fs12.exists(bundle)) {
7825
+ fs12.mkdirp(bundlesDir);
7826
+ fs12.writeFileAtomic(bundle, combined);
7827
+ }
7828
+ return { path: bundle };
7829
+ }
7830
+
7831
+ // src/frontdoor/realFrontDoorPort.ts
7832
+ var realTrustBundleFs = {
7833
+ readFileUtf8: (file) => fs11.readFileSync(file, "utf8"),
7834
+ exists: (file) => fs11.existsSync(file),
7835
+ mkdirp: (dir) => {
7836
+ fs11.mkdirSync(dir, { recursive: true });
7837
+ },
7838
+ writeFileAtomic: (file, contents) => {
7839
+ realFarmFs.writeFilePrivate(file, contents);
7840
+ }
7841
+ };
7842
+ function realFrontDoorPort(paths, spawnDaemon) {
7843
+ return {
7844
+ ensure: (inheritedExtraCaCerts) => {
7845
+ const up = ensureFrontDoor({
7846
+ paths,
7847
+ launcherPid: process.pid,
7848
+ ports: {
7849
+ fs: realFarmFs,
7850
+ isRunning: realIsProcessRunning,
7851
+ now: () => Date.now(),
7852
+ sleep: realSleepSync,
7853
+ spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
7854
+ stopSupervisor: (pid) => {
7855
+ process.kill(pid, "SIGTERM");
7856
+ },
7857
+ // 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.
7858
+ verifyListener: (port) => probeFrontDoorSync(port, fs11.readFileSync(paths.frontdoorCaCertFile, "utf8"))
7859
+ }
7860
+ });
7861
+ const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
7862
+ return {
7863
+ port: up.port,
7864
+ connectPort: up.connectPort,
7865
+ trustBundlePath: trust.path,
7866
+ ...trust.warning === void 0 ? {} : { trustWarning: trust.warning },
7867
+ sessionToken: up.token
7868
+ };
7869
+ },
7870
+ release: () => {
7871
+ removeFrontDoorSession(realFarmFs, paths.frontdoorSessionsDir, process.pid);
7872
+ }
7873
+ };
7874
+ }
7875
+
7876
+ // src/launchWiring.ts
7877
+ function buildFarmRuntime(paths, cwd) {
7878
+ const home = os5.homedir();
7879
+ const read = cosmiconfigReader();
7880
+ const classification = loadClassification(paths);
7881
+ const loaded = loadCascadeInput({ paths, home, cwd, read });
7882
+ const selections = readDirectorySelections(loaded);
7883
+ const git = resolveGitBranch(realRunPort, cwd);
7884
+ return {
7885
+ runtime: {
7886
+ fs: realFarmFs,
7887
+ claudeHome: resolveClaudeHome(),
7888
+ home,
7889
+ cwd,
7890
+ ...git.branch === void 0 ? {} : { branch: git.branch },
7891
+ ...git.branchDetached === void 0 ? {} : { branchDetached: git.branchDetached },
7892
+ classification,
7893
+ loadCascade: (baseConfigProfile, cliOverride) => loadCascadeInput({
7894
+ paths,
7895
+ home,
7896
+ cwd,
7897
+ read,
7898
+ ...baseConfigProfile === void 0 ? {} : { baseConfigProfile },
7899
+ ...cliOverride === void 0 ? {} : { cliOverride }
7900
+ }).input,
7901
+ now: () => Date.now(),
7902
+ uniqueSuffix: `${String(process.pid)}.${randomUUID5()}`,
7903
+ // Zombie-aware on purpose: a previous launcher that crashed out of a resync without releasing the lock may sit unreaped, still answering signal 0 as alive, and must read as a dead holder so this launch takes the lock over instead of timing out.
7904
+ lock: { pid: process.pid, isRunning: realIsProcessRunning, sleep: realSleepSync }
7905
+ },
7906
+ ...selections.identity === void 0 ? {} : { directoryIdentity: selections.identity },
7907
+ ...selections.configProfile === void 0 ? {} : { directoryConfigProfile: selections.configProfile },
7908
+ ...loaded.globalConfig?.defaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: loaded.globalConfig.defaultConfigProfile },
7909
+ ...loaded.globalConfig?.pools === void 0 ? {} : { pools: loaded.globalConfig.pools }
7910
+ };
7911
+ }
7912
+ function realPrepareLaunchParams(paths, options) {
7913
+ const { farm } = options;
7914
+ return {
7915
+ paths,
7916
+ fs: realFsPort,
7917
+ proc: options.proc,
7918
+ log: options.log,
7919
+ resolveClaudeBinary: realResolveClaudeBinary(resolveOwnInstallDirs(paths, realOwnExecutablePath())),
7920
+ farm: farm.runtime,
7921
+ headroom: realHeadroomPort(paths, { spawnDaemon: options.spawnDaemon, cwd: farm.runtime.cwd }),
7922
+ frontdoor: realFrontDoorPort(paths, options.spawnDaemon),
7923
+ credentials: { ...realCredentialPort, cache: realCredentialCacheEnv(paths) },
7924
+ ...farm.directoryIdentity === void 0 ? {} : { directoryPinnedIdentity: farm.directoryIdentity },
7925
+ ...farm.directoryConfigProfile === void 0 ? {} : { directoryRuleConfigProfile: farm.directoryConfigProfile },
7926
+ ...farm.globalDefaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: farm.globalDefaultConfigProfile },
7927
+ ...farm.pools === void 0 ? {} : { pools: farm.pools },
7928
+ ...options.allowMissingConfigProfile === void 0 ? {} : { allowMissingConfigProfile: options.allowMissingConfigProfile }
7929
+ };
7930
+ }
7931
+ var LaunchRefusedError = class extends CliError {
7932
+ exitCode;
7933
+ constructor(message, exitCode) {
7934
+ super(message);
7935
+ this.name = "LaunchRefusedError";
7936
+ this.exitCode = exitCode;
7937
+ }
7938
+ };
7939
+ function prepareClaudeLaunch(options) {
7940
+ const paths = options.paths ?? resolveLayoutPaths();
7941
+ const refusals = [];
7942
+ const log = {
7943
+ info: () => void 0,
7944
+ warn: () => void 0,
7945
+ error: (message) => {
7946
+ refusals.push(message);
7947
+ }
7948
+ };
7949
+ const proc = {
7950
+ env: options.env,
7951
+ argv: options.argv,
7952
+ exit: (code) => {
7953
+ throw new LaunchRefusedError(refusals.join("\n") || `the launch was refused (exit ${String(code)})`, code);
7954
+ }
7955
+ };
7956
+ const spawnDaemon = options.agentShim === void 0 ? () => {
7957
+ throw new LaunchRefusedError("this launch routes through the front door or headroom, which need `agentShim`, the path of the agent-shim executable, to start their daemons", 1);
7958
+ } : spawnDaemonThrough(options.agentShim);
7959
+ return prepareLaunch(realPrepareLaunchParams(paths, { proc, log, spawnDaemon, farm: buildFarmRuntime(paths, options.cwd) }));
7960
+ }
6636
7961
  export {
6637
7962
  AMBIENT_CREDENTIAL_VARS,
6638
7963
  CONNECT_INTERCEPT_HOST,
@@ -6664,6 +7989,7 @@ export {
6664
7989
  InvalidCategoryNameError,
6665
7990
  InvalidIdentityNameError,
6666
7991
  InvalidProviderNameError,
7992
+ LaunchRefusedError,
6667
7993
  LegacyProviderFileError,
6668
7994
  PoolNameSchema,
6669
7995
  PoolNotFoundError,
@@ -6714,6 +8040,8 @@ export {
6714
8040
  listUsageSnapshots,
6715
8041
  mintLeaf,
6716
8042
  parseConnectTarget,
8043
+ prepareClaudeLaunch,
8044
+ prepareLaunch,
6717
8045
  profileExists,
6718
8046
  providerExists,
6719
8047
  readActiveIdentity,