claude-use 7.12.1 → 7.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -60,6 +60,7 @@ __export(index_exports, {
60
60
  InvalidCategoryNameError: () => InvalidCategoryNameError,
61
61
  InvalidIdentityNameError: () => InvalidIdentityNameError,
62
62
  InvalidProviderNameError: () => InvalidProviderNameError,
63
+ LaunchRefusedError: () => LaunchRefusedError,
63
64
  LegacyProviderFileError: () => LegacyProviderFileError,
64
65
  PoolNameSchema: () => PoolNameSchema,
65
66
  PoolNotFoundError: () => PoolNotFoundError,
@@ -110,6 +111,8 @@ __export(index_exports, {
110
111
  listUsageSnapshots: () => listUsageSnapshots,
111
112
  mintLeaf: () => mintLeaf,
112
113
  parseConnectTarget: () => parseConnectTarget,
114
+ prepareClaudeLaunch: () => prepareClaudeLaunch,
115
+ prepareLaunch: () => prepareLaunch,
113
116
  profileExists: () => profileExists,
114
117
  providerExists: () => providerExists,
115
118
  readActiveIdentity: () => readActiveIdentity,
@@ -1386,6 +1389,37 @@ function planFarm(params) {
1386
1389
  return { entries, materialised, links };
1387
1390
  }
1388
1391
 
1392
+ // src/resolve/walkPolicy.ts
1393
+ var ENTER_EVERYTHING = () => true;
1394
+ function readsSubtreeAggregates(rule) {
1395
+ const when = rule.when;
1396
+ return when !== void 0 && (when.newerThan !== void 0 || when.olderThan !== void 0 || when.maxSizeBytes !== void 0);
1397
+ }
1398
+ function hasUnboundedDepth(pattern) {
1399
+ return pattern.includes("**") || /[{(]/.test(pattern);
1400
+ }
1401
+ function couldMatchBeneath(rule, dirRel) {
1402
+ if (rule.matches(dirRel)) {
1403
+ return rule.when !== void 0;
1404
+ }
1405
+ if (rule.isExact) {
1406
+ return rule.canonicalPattern.startsWith(`${dirRel}/`);
1407
+ }
1408
+ const depth = dirRel.split("/").length;
1409
+ if (!hasUnboundedDepth(rule.canonicalPattern) && rule.segmentCount <= depth) {
1410
+ return false;
1411
+ }
1412
+ const prefix = rule.literalPrefix;
1413
+ return prefix === "" || prefix.startsWith(`${dirRel}/`) || dirRel.startsWith(prefix);
1414
+ }
1415
+ function descendPolicy(rules) {
1416
+ const all = [...rules];
1417
+ if (all.some(readsSubtreeAggregates)) {
1418
+ return ENTER_EVERYTHING;
1419
+ }
1420
+ return (dirRel) => all.some((rule) => couldMatchBeneath(rule, dirRel));
1421
+ }
1422
+
1389
1423
  // src/resolve/walk.ts
1390
1424
  var import_node_path4 = __toESM(require("node:path"), 1);
1391
1425
 
@@ -1564,6 +1598,9 @@ function topLevelNames(facts) {
1564
1598
  }
1565
1599
  return [...names].sort();
1566
1600
  }
1601
+ function descendPolicyFor(cascade, home) {
1602
+ return descendPolicy(flattenLayers(assembleCascade(cascade).layers, { home }).rules.values());
1603
+ }
1567
1604
  function resolveDecisions(input) {
1568
1605
  const assembled = assembleCascade(input.cascade);
1569
1606
  const flattened = flattenLayers(assembled.layers, { home: input.facts.home });
@@ -1789,8 +1826,8 @@ var FarmManifestSchema = import_zod2.z.strictObject({
1789
1826
  materialised: import_zod2.z.array(import_zod2.z.string()),
1790
1827
  links: import_zod2.z.array(import_zod2.z.strictObject({ rel: import_zod2.z.string(), target: import_zod2.z.string() }))
1791
1828
  });
1792
- function readFarmManifest(fs10, farmRoot) {
1793
- const raw = fs10.readFileUtf8(import_node_path6.default.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs10.readFileUtf8(import_node_path6.default.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1829
+ function readFarmManifest(fs12, farmRoot) {
1830
+ const raw = fs12.readFileUtf8(import_node_path6.default.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs12.readFileUtf8(import_node_path6.default.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1794
1831
  if (raw === void 0) {
1795
1832
  return void 0;
1796
1833
  }
@@ -1814,7 +1851,7 @@ function buildEntryFacts(params) {
1814
1851
  const isDirectory = stat.kind === "dir";
1815
1852
  let latestMtimeMs = stat.mtimeMs;
1816
1853
  let totalSizeBytes = stat.sizeBytes;
1817
- if (isDirectory) {
1854
+ if (isDirectory && params.descend(rel)) {
1818
1855
  for (const name of [...params.fs.readdir(absolute)].sort()) {
1819
1856
  const child = visit(`${rel}/${name}`);
1820
1857
  if (child !== void 0) {
@@ -1848,9 +1885,9 @@ function buildEntryFacts(params) {
1848
1885
  entries
1849
1886
  };
1850
1887
  }
1851
- function listSubtree(fs10, root, rel) {
1888
+ function listSubtree(fs12, root, rel) {
1852
1889
  const absolute = import_node_path6.default.join(root, rel);
1853
- const stat = fs10.lstat(absolute);
1890
+ const stat = fs12.lstat(absolute);
1854
1891
  if (stat === void 0) {
1855
1892
  return [];
1856
1893
  }
@@ -1858,10 +1895,10 @@ function listSubtree(fs10, root, rel) {
1858
1895
  return [{ rel, kind: "symlink" }];
1859
1896
  }
1860
1897
  if (stat.kind === "dir") {
1861
- const children = [...fs10.readdir(absolute)].sort().flatMap((name) => listSubtree(fs10, root, `${rel}/${name}`));
1898
+ const children = [...fs12.readdir(absolute)].sort().flatMap((name) => listSubtree(fs12, root, `${rel}/${name}`));
1862
1899
  return [{ rel, kind: "dir" }, ...children];
1863
1900
  }
1864
- const contentHash = fs10.hashFile(absolute);
1901
+ const contentHash = fs12.hashFile(absolute);
1865
1902
  return [{ rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } }];
1866
1903
  }
1867
1904
  function topLevelScopeRoots(roots) {
@@ -1875,25 +1912,25 @@ function topLevelScopeRoots(roots) {
1875
1912
  }
1876
1913
  return kept;
1877
1914
  }
1878
- function reconciliationScope(fs10, farmRoot, manifest) {
1915
+ function reconciliationScope(fs12, farmRoot, manifest) {
1879
1916
  if (manifest !== void 0) {
1880
1917
  return topLevelScopeRoots(manifest.materialised);
1881
1918
  }
1882
- return [...fs10.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs10.lstat(import_node_path6.default.join(farmRoot, name))?.kind === "dir").sort();
1919
+ return [...fs12.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs12.lstat(import_node_path6.default.join(farmRoot, name))?.kind === "dir").sort();
1883
1920
  }
1884
- function collectFarmListing(fs10, farmRoot, scopeRoots) {
1885
- return scopeRoots.flatMap((root) => listSubtree(fs10, farmRoot, root));
1921
+ function collectFarmListing(fs12, farmRoot, scopeRoots) {
1922
+ return scopeRoots.flatMap((root) => listSubtree(fs12, farmRoot, root));
1886
1923
  }
1887
- function collectCanonicalCounterparts(fs10, claudeHome, farmListing) {
1924
+ function collectCanonicalCounterparts(fs12, claudeHome, farmListing) {
1888
1925
  const out = [];
1889
1926
  for (const entry of farmListing) {
1890
1927
  const absolute = import_node_path6.default.join(claudeHome, entry.rel);
1891
- const stat = fs10.lstat(absolute);
1928
+ const stat = fs12.lstat(absolute);
1892
1929
  if (stat === void 0) {
1893
1930
  continue;
1894
1931
  }
1895
1932
  if (stat.kind === "file") {
1896
- const contentHash = fs10.hashFile(absolute);
1933
+ const contentHash = fs12.hashFile(absolute);
1897
1934
  out.push({ rel: entry.rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } });
1898
1935
  continue;
1899
1936
  }
@@ -2161,7 +2198,8 @@ function resyncFarm(params) {
2161
2198
  nowMs,
2162
2199
  env: params.env,
2163
2200
  ...params.branch === void 0 ? {} : { branch: params.branch },
2164
- ...params.branchDetached === void 0 ? {} : { branchDetached: params.branchDetached }
2201
+ ...params.branchDetached === void 0 ? {} : { branchDetached: params.branchDetached },
2202
+ descend: descendPolicyFor(params.cascade, params.home)
2165
2203
  });
2166
2204
  const resolved = resolveDecisions({ facts, cascade: params.cascade, classification: params.classification });
2167
2205
  const manifest = {
@@ -2577,8 +2615,12 @@ function pumpTapSession(secure, openUpstream, tap, prefix = Buffer.alloc(0)) {
2577
2615
  }
2578
2616
 
2579
2617
  // src/frontdoor/capability.ts
2618
+ var CONNECT_PROXY_USER = "agent-shim";
2580
2619
  var CONNECT_PROXY_REALM = "agent-shim front door";
2581
2620
  var BASIC_SCHEME = "basic";
2621
+ function connectProxyUrl(port, token) {
2622
+ return `http://${encodeURIComponent(CONNECT_PROXY_USER)}:${encodeURIComponent(token)}@127.0.0.1:${String(port)}`;
2623
+ }
2582
2624
  function capabilityFromProxyAuthorization(value) {
2583
2625
  const trimmed = value.trim();
2584
2626
  const space = trimmed.indexOf(" ");
@@ -2595,7 +2637,15 @@ function capabilityFromProxyAuthorization(value) {
2595
2637
  }
2596
2638
 
2597
2639
  // src/frontdoor/route.ts
2640
+ var IDENTITY_HEADER = "x-agent-shim-identity";
2641
+ var SESSION_HEADER = "x-agent-shim-session";
2642
+ var HEADROOM_FLAG_HEADER = "x-agent-shim-headroom";
2643
+ var PROJECT_ID_HEADER = "x-headroom-project-id";
2598
2644
  var AUTH_HEADER = "x-agent-shim-auth";
2645
+ var PROVIDER_PATH_PREFIX = "/providers/";
2646
+ function providerBaseUrl(port, provider) {
2647
+ return `https://127.0.0.1:${String(port)}${PROVIDER_PATH_PREFIX}${encodeURIComponent(provider)}`;
2648
+ }
2599
2649
 
2600
2650
  // src/frontdoor/state.ts
2601
2651
  var import_node_path7 = __toESM(require("node:path"), 1);
@@ -2632,10 +2682,10 @@ var FrontDoorStateSchema = import_zod3.z.strictObject({
2632
2682
  /** The last fatal error, kept across shutdowns so `frontdoor status` can explain a front door that is not running. */
2633
2683
  lastError: import_zod3.z.string().optional()
2634
2684
  });
2635
- function readFrontDoorState(fs10, stateFile) {
2685
+ function readFrontDoorState(fs12, stateFile) {
2636
2686
  let raw;
2637
2687
  try {
2638
- raw = fs10.readFileUtf8(stateFile);
2688
+ raw = fs12.readFileUtf8(stateFile);
2639
2689
  } catch {
2640
2690
  return void 0;
2641
2691
  }
@@ -2649,28 +2699,28 @@ function readFrontDoorState(fs10, stateFile) {
2649
2699
  return void 0;
2650
2700
  }
2651
2701
  }
2652
- function writeFrontDoorState(fs10, stateFile, state) {
2653
- fs10.mkdirp(import_node_path7.default.dirname(stateFile));
2654
- fs10.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
2702
+ function writeFrontDoorState(fs12, stateFile, state) {
2703
+ fs12.mkdirp(import_node_path7.default.dirname(stateFile));
2704
+ fs12.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
2655
2705
  `);
2656
2706
  }
2657
2707
  function frontDoorOrigin(state) {
2658
2708
  const port = state?.directPort ?? state?.lastDirectPort;
2659
2709
  return port === void 0 ? void 0 : `http://127.0.0.1:${String(port)}`;
2660
2710
  }
2661
- function writeFrontDoorSession(fs10, sessionsDir, session) {
2662
- fs10.mkdirPrivate(sessionsDir);
2663
- fs10.writeFilePrivate(import_node_path7.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2711
+ function writeFrontDoorSession(fs12, sessionsDir, session) {
2712
+ fs12.mkdirPrivate(sessionsDir);
2713
+ fs12.writeFilePrivate(import_node_path7.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2664
2714
  `);
2665
2715
  }
2666
- function listFrontDoorSessions(fs10, sessionsDir) {
2716
+ function listFrontDoorSessions(fs12, sessionsDir) {
2667
2717
  const sessions = [];
2668
- for (const name of fs10.readdir(sessionsDir)) {
2718
+ for (const name of fs12.readdir(sessionsDir)) {
2669
2719
  if (!name.endsWith(".json")) {
2670
2720
  continue;
2671
2721
  }
2672
2722
  try {
2673
- const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs10.readFileUtf8(import_node_path7.default.join(sessionsDir, name)) ?? ""));
2723
+ const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs12.readFileUtf8(import_node_path7.default.join(sessionsDir, name)) ?? ""));
2674
2724
  if (parsed.success) {
2675
2725
  sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
2676
2726
  }
@@ -2680,14 +2730,14 @@ function listFrontDoorSessions(fs10, sessionsDir) {
2680
2730
  }
2681
2731
  return sessions.sort((a, b) => a.pid - b.pid);
2682
2732
  }
2683
- function removeFrontDoorSession(fs10, sessionsDir, pid) {
2684
- fs10.removeRecursive(import_node_path7.default.join(sessionsDir, `${String(pid)}.json`));
2733
+ function removeFrontDoorSession(fs12, sessionsDir, pid) {
2734
+ fs12.removeRecursive(import_node_path7.default.join(sessionsDir, `${String(pid)}.json`));
2685
2735
  }
2686
- function pruneDeadFrontDoorSessions(fs10, sessionsDir, isRunning) {
2736
+ function pruneDeadFrontDoorSessions(fs12, sessionsDir, isRunning) {
2687
2737
  const removed = [];
2688
- for (const session of listFrontDoorSessions(fs10, sessionsDir)) {
2738
+ for (const session of listFrontDoorSessions(fs12, sessionsDir)) {
2689
2739
  if (!isRunning(session.pid)) {
2690
- removeFrontDoorSession(fs10, sessionsDir, session.pid);
2740
+ removeFrontDoorSession(fs12, sessionsDir, session.pid);
2691
2741
  removed.push(session.pid);
2692
2742
  }
2693
2743
  }
@@ -2699,8 +2749,8 @@ var FRONTDOOR_SUPERVISOR_STILL_RUNNING = -1;
2699
2749
  var FRONTDOOR_POLL_MS = 1e3;
2700
2750
  var MS_PER_MINUTE = 6e4;
2701
2751
  async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {}) {
2702
- const { fs: fs10, paths } = ports;
2703
- const previous = readFrontDoorState(fs10, paths.frontdoorStateFile);
2752
+ const { fs: fs12, paths } = ports;
2753
+ const previous = readFrontDoorState(fs12, paths.frontdoorStateFile);
2704
2754
  let lastPort = previous?.lastPort;
2705
2755
  let lastConnectPort = previous?.lastConnectPort;
2706
2756
  let lastDirectPort = previous?.lastDirectPort;
@@ -2710,12 +2760,12 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2710
2760
  ...lastDirectPort === void 0 ? {} : { lastDirectPort }
2711
2761
  });
2712
2762
  const fail = (message) => {
2713
- writeFrontDoorState(fs10, paths.frontdoorStateFile, { lastError: message, ...sticky() });
2714
- fs10.removeRecursive(paths.frontdoorLockFile);
2763
+ writeFrontDoorState(fs12, paths.frontdoorStateFile, { lastError: message, ...sticky() });
2764
+ fs12.removeRecursive(paths.frontdoorLockFile);
2715
2765
  ports.log(`agent-shim frontdoor supervisor: ${message}`);
2716
2766
  return 1;
2717
2767
  };
2718
- writeFrontDoorState(fs10, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
2768
+ writeFrontDoorState(fs12, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
2719
2769
  const previousSticky = lastPort;
2720
2770
  let http2;
2721
2771
  try {
@@ -2752,8 +2802,8 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2752
2802
  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)`);
2753
2803
  }
2754
2804
  lastDirectPort = direct.port;
2755
- writeFrontDoorState(fs10, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http2.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
2756
- fs10.removeRecursive(paths.frontdoorLockFile);
2805
+ writeFrontDoorState(fs12, paths.frontdoorStateFile, { protocol: FRONT_DOOR_PROTOCOL, supervisorPid: ports.ownPid, port: http2.port, connectPort: connect3.port, directPort: direct.port, ...sticky() });
2806
+ fs12.removeRecursive(paths.frontdoorLockFile);
2757
2807
  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)}`);
2758
2808
  let idleSince;
2759
2809
  let ticks = 0;
@@ -2762,15 +2812,15 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2762
2812
  return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
2763
2813
  }
2764
2814
  ticks += 1;
2765
- pruneDeadFrontDoorSessions(fs10, paths.frontdoorSessionsDir, ports.isRunning);
2766
- if (listFrontDoorSessions(fs10, paths.frontdoorSessionsDir).length === 0) {
2815
+ pruneDeadFrontDoorSessions(fs12, paths.frontdoorSessionsDir, ports.isRunning);
2816
+ if (listFrontDoorSessions(fs12, paths.frontdoorSessionsDir).length === 0) {
2767
2817
  idleSince ??= ports.now();
2768
2818
  if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE) {
2769
2819
  ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
2770
2820
  await direct.close();
2771
2821
  await connect3.close();
2772
2822
  await http2.close();
2773
- writeFrontDoorState(fs10, paths.frontdoorStateFile, sticky());
2823
+ writeFrontDoorState(fs12, paths.frontdoorStateFile, sticky());
2774
2824
  return 0;
2775
2825
  }
2776
2826
  } else {
@@ -2825,8 +2875,8 @@ function parseConnectTarget(authority) {
2825
2875
  function isInterceptedHost(host, interceptHosts) {
2826
2876
  return interceptHosts.includes(host);
2827
2877
  }
2828
- function servedByPipeline(path23) {
2829
- return path23?.startsWith(ROUTED_PATH_PREFIX) === true;
2878
+ function servedByPipeline(path28) {
2879
+ return path28?.startsWith(ROUTED_PATH_PREFIX) === true;
2830
2880
  }
2831
2881
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
2832
2882
  "connection",
@@ -3360,16 +3410,16 @@ function parseJson(raw, schema) {
3360
3410
  const parsed = schema.safeParse(JSON.parse(raw));
3361
3411
  return parsed.success ? parsed.data : void 0;
3362
3412
  }
3363
- function readHeadroomState(fs10, stateFile) {
3413
+ function readHeadroomState(fs12, stateFile) {
3364
3414
  try {
3365
- return parseJson(fs10.readFileUtf8(stateFile), HeadroomStateSchema);
3415
+ return parseJson(fs12.readFileUtf8(stateFile), HeadroomStateSchema);
3366
3416
  } catch {
3367
3417
  return void 0;
3368
3418
  }
3369
3419
  }
3370
- function writeHeadroomState(fs10, stateFile, state) {
3371
- fs10.mkdirp(import_node_path8.default.dirname(stateFile));
3372
- fs10.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
3420
+ function writeHeadroomState(fs12, stateFile, state) {
3421
+ fs12.mkdirp(import_node_path8.default.dirname(stateFile));
3422
+ fs12.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
3373
3423
  `);
3374
3424
  }
3375
3425
  function headroomAllowlist(providers) {
@@ -3389,14 +3439,14 @@ function headroomUpstreams(providers, frontDoorOrigin2) {
3389
3439
  function hashAllowlist(allowlist) {
3390
3440
  return (0, import_node_crypto5.createHash)("sha256").update(allowlist.join("\n")).digest("hex");
3391
3441
  }
3392
- function readAllProviders(fs10, providersDir) {
3442
+ function readAllProviders(fs12, providersDir) {
3393
3443
  const result = [];
3394
- for (const name of fs10.readdir(providersDir)) {
3444
+ for (const name of fs12.readdir(providersDir)) {
3395
3445
  if (!name.endsWith(".json")) {
3396
3446
  continue;
3397
3447
  }
3398
3448
  try {
3399
- const parsed = parseJson(fs10.readFileUtf8(import_node_path8.default.join(providersDir, name)), ProviderSchema);
3449
+ const parsed = parseJson(fs12.readFileUtf8(import_node_path8.default.join(providersDir, name)), ProviderSchema);
3400
3450
  if (parsed !== void 0) {
3401
3451
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
3402
3452
  }
@@ -3406,22 +3456,22 @@ function readAllProviders(fs10, providersDir) {
3406
3456
  }
3407
3457
  return result;
3408
3458
  }
3409
- function writeSession(fs10, sessionsDir, session) {
3410
- fs10.mkdirp(sessionsDir);
3411
- fs10.writeFileUtf8(import_node_path8.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
3459
+ function writeSession(fs12, sessionsDir, session) {
3460
+ fs12.mkdirp(sessionsDir);
3461
+ fs12.writeFileUtf8(import_node_path8.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
3412
3462
  `);
3413
3463
  }
3414
- function removeSession(fs10, sessionsDir, pid) {
3415
- fs10.removeRecursive(import_node_path8.default.join(sessionsDir, `${String(pid)}.json`));
3464
+ function removeSession(fs12, sessionsDir, pid) {
3465
+ fs12.removeRecursive(import_node_path8.default.join(sessionsDir, `${String(pid)}.json`));
3416
3466
  }
3417
- function listSessions(fs10, sessionsDir) {
3467
+ function listSessions(fs12, sessionsDir) {
3418
3468
  const sessions = [];
3419
- for (const name of fs10.readdir(sessionsDir)) {
3469
+ for (const name of fs12.readdir(sessionsDir)) {
3420
3470
  if (!name.endsWith(".json")) {
3421
3471
  continue;
3422
3472
  }
3423
3473
  try {
3424
- const parsed = parseJson(fs10.readFileUtf8(import_node_path8.default.join(sessionsDir, name)), HeadroomSessionSchema);
3474
+ const parsed = parseJson(fs12.readFileUtf8(import_node_path8.default.join(sessionsDir, name)), HeadroomSessionSchema);
3425
3475
  if (parsed !== void 0) {
3426
3476
  sessions.push(parsed);
3427
3477
  }
@@ -3431,22 +3481,22 @@ function listSessions(fs10, sessionsDir) {
3431
3481
  }
3432
3482
  return sessions.sort((a, b) => a.pid - b.pid);
3433
3483
  }
3434
- function sessionsForSupervisor(fs10, sessionsDir, supervisorPid) {
3435
- return listSessions(fs10, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
3484
+ function sessionsForSupervisor(fs12, sessionsDir, supervisorPid) {
3485
+ return listSessions(fs12, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
3436
3486
  }
3437
- function pruneDeadSessions(fs10, sessionsDir, isRunning) {
3487
+ function pruneDeadSessions(fs12, sessionsDir, isRunning) {
3438
3488
  const removed = [];
3439
- for (const session of listSessions(fs10, sessionsDir)) {
3489
+ for (const session of listSessions(fs12, sessionsDir)) {
3440
3490
  if (!isRunning(session.pid)) {
3441
- removeSession(fs10, sessionsDir, session.pid);
3491
+ removeSession(fs12, sessionsDir, session.pid);
3442
3492
  removed.push(session.pid);
3443
3493
  }
3444
3494
  }
3445
3495
  return removed;
3446
3496
  }
3447
- function readStartLock(fs10, lockFile) {
3497
+ function readStartLock(fs12, lockFile) {
3448
3498
  try {
3449
- return parseJson(fs10.readFileUtf8(lockFile), HeadroomLockSchema);
3499
+ return parseJson(fs12.readFileUtf8(lockFile), HeadroomLockSchema);
3450
3500
  } catch {
3451
3501
  return void 0;
3452
3502
  }
@@ -3697,12 +3747,12 @@ function isIdentityName(name) {
3697
3747
  function claudeJsonPath(identitiesDir, identity) {
3698
3748
  return import_node_path9.default.join(identitiesDir, identity, CLAUDE_JSON);
3699
3749
  }
3700
- function readAccountMetadata(fs10, identitiesDir, identity) {
3750
+ function readAccountMetadata(fs12, identitiesDir, identity) {
3701
3751
  if (!isIdentityName(identity)) {
3702
3752
  throw new Error(`"${identity}" is not a valid identity name.`);
3703
3753
  }
3704
3754
  const file = claudeJsonPath(identitiesDir, identity);
3705
- const raw = fs10.readFileUtf8(file);
3755
+ const raw = fs12.readFileUtf8(file);
3706
3756
  if (raw === void 0) {
3707
3757
  return void 0;
3708
3758
  }
@@ -3736,8 +3786,8 @@ function readAccountMetadata(fs10, identitiesDir, identity) {
3736
3786
  // src/usage/read.ts
3737
3787
  var SEGMENT_RE = /^(\d{4}-\d{2}-\d{2})\.(\d+)\.jsonl$/;
3738
3788
  var DAY_MS = 864e5;
3739
- function listLogSegments(fs10, logDir) {
3740
- return fs10.readdir(logDir).flatMap((name) => {
3789
+ function listLogSegments(fs12, logDir) {
3790
+ return fs12.readdir(logDir).flatMap((name) => {
3741
3791
  const match = SEGMENT_RE.exec(name);
3742
3792
  const day = match?.[1];
3743
3793
  if (day === void 0) {
@@ -3746,15 +3796,15 @@ function listLogSegments(fs10, logDir) {
3746
3796
  return [{ name, day, endsAt: Date.parse(`${day}T00:00:00.000Z`) + DAY_MS }];
3747
3797
  }).sort((left, right) => left.day.localeCompare(right.day) || left.name.localeCompare(right.name));
3748
3798
  }
3749
- function readUsageLog(fs10, logDir, options = {}) {
3799
+ function readUsageLog(fs12, logDir, options = {}) {
3750
3800
  const { sinceMs } = options;
3751
3801
  const records = [];
3752
3802
  let invalidLines = 0;
3753
- for (const segment of listLogSegments(fs10, logDir)) {
3803
+ for (const segment of listLogSegments(fs12, logDir)) {
3754
3804
  if (sinceMs !== void 0 && segment.endsAt <= sinceMs) {
3755
3805
  continue;
3756
3806
  }
3757
- const contents = fs10.readFileUtf8(import_node_path10.default.join(logDir, segment.name));
3807
+ const contents = fs12.readFileUtf8(import_node_path10.default.join(logDir, segment.name));
3758
3808
  if (contents === void 0) {
3759
3809
  continue;
3760
3810
  }
@@ -3798,9 +3848,9 @@ function snapshotPath(snapshotsDir, identity) {
3798
3848
  }
3799
3849
  return import_node_path10.default.join(snapshotsDir, `${identity}.json`);
3800
3850
  }
3801
- function readUsageSnapshot(fs10, snapshotsDir, identity) {
3851
+ function readUsageSnapshot(fs12, snapshotsDir, identity) {
3802
3852
  const file = snapshotPath(snapshotsDir, identity);
3803
- const raw = fs10.readFileUtf8(file);
3853
+ const raw = fs12.readFileUtf8(file);
3804
3854
  if (raw === void 0) {
3805
3855
  return void 0;
3806
3856
  }
@@ -3816,8 +3866,8 @@ function readUsageSnapshot(fs10, snapshotsDir, identity) {
3816
3866
  }
3817
3867
  return snapshot.data;
3818
3868
  }
3819
- function listUsageSnapshots(fs10, snapshotsDir) {
3820
- return fs10.readdir(snapshotsDir).flatMap((name) => {
3869
+ function listUsageSnapshots(fs12, snapshotsDir) {
3870
+ return fs12.readdir(snapshotsDir).flatMap((name) => {
3821
3871
  if (!name.endsWith(".json")) {
3822
3872
  return [];
3823
3873
  }
@@ -3825,7 +3875,7 @@ function listUsageSnapshots(fs10, snapshotsDir) {
3825
3875
  if (!isIdentityName(identity)) {
3826
3876
  return [];
3827
3877
  }
3828
- const snapshot = readUsageSnapshot(fs10, snapshotsDir, identity);
3878
+ const snapshot = readUsageSnapshot(fs12, snapshotsDir, identity);
3829
3879
  return snapshot === void 0 ? [] : [snapshot];
3830
3880
  }).sort((left, right) => left.identity.localeCompare(right.identity));
3831
3881
  }
@@ -4000,9 +4050,9 @@ function compareVersions(a, b) {
4000
4050
  }
4001
4051
  var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
4002
4052
  async function runSupervisor(initialConfig, ports, options = {}) {
4003
- const { fs: fs10, paths } = ports;
4053
+ const { fs: fs12, paths } = ports;
4004
4054
  let config = initialConfig;
4005
- const previousState = readHeadroomState(fs10, paths.headroomStateFile);
4055
+ const previousState = readHeadroomState(fs12, paths.headroomStateFile);
4006
4056
  if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
4007
4057
  ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
4008
4058
  return 0;
@@ -4011,19 +4061,19 @@ async function runSupervisor(initialConfig, ports, options = {}) {
4011
4061
  let lastPort = previousState?.lastPort;
4012
4062
  const sticky = () => lastPort === void 0 ? {} : { lastPort };
4013
4063
  const ownsState = () => {
4014
- const owner = readHeadroomState(fs10, paths.headroomStateFile)?.supervisorPid;
4064
+ const owner = readHeadroomState(fs12, paths.headroomStateFile)?.supervisorPid;
4015
4065
  return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
4016
4066
  };
4017
4067
  const writeOwnState = (state) => {
4018
4068
  if (!ownsState()) {
4019
4069
  return false;
4020
4070
  }
4021
- writeHeadroomState(fs10, paths.headroomStateFile, state);
4071
+ writeHeadroomState(fs12, paths.headroomStateFile, state);
4022
4072
  return true;
4023
4073
  };
4024
4074
  const fail = (message) => {
4025
4075
  if (writeOwnState({ lastError: message, ...sticky() })) {
4026
- fs10.removeRecursive(paths.headroomLockFile);
4076
+ fs12.removeRecursive(paths.headroomLockFile);
4027
4077
  }
4028
4078
  ports.log(`agent-shim headroom supervisor: ${message}`);
4029
4079
  return 1;
@@ -4072,7 +4122,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
4072
4122
  const settingsHash = hashSettings(config.settings);
4073
4123
  const allowlist = allowlistOf(ports);
4074
4124
  const allowlistHash = hashAllowlist(allowlist);
4075
- pruneDeadSessions(fs10, paths.headroomSessionsDir, ports.isRunning);
4125
+ pruneDeadSessions(fs12, paths.headroomSessionsDir, ports.isRunning);
4076
4126
  const ownsNow = ownsState();
4077
4127
  if (!ownsNow && !superseded) {
4078
4128
  ports.log("agent-shim headroom supervisor: another supervisor now owns state.json; serving this daemon's own sessions until they end");
@@ -4124,7 +4174,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
4124
4174
  ...sticky()
4125
4175
  });
4126
4176
  if (recorded) {
4127
- fs10.removeRecursive(paths.headroomLockFile);
4177
+ fs12.removeRecursive(paths.headroomLockFile);
4128
4178
  }
4129
4179
  idleSince = void 0;
4130
4180
  ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on 127.0.0.1:${String(port)}`);
@@ -4139,7 +4189,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
4139
4189
  }
4140
4190
  } else {
4141
4191
  if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
4142
- if (sessionsForSupervisor(fs10, paths.headroomSessionsDir, ports.ownPid).length === 0) {
4192
+ if (sessionsForSupervisor(fs12, paths.headroomSessionsDir, ports.ownPid).length === 0) {
4143
4193
  ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
4144
4194
  ports.stopProcess(headroomPid);
4145
4195
  headroomPid = void 0;
@@ -4148,7 +4198,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
4148
4198
  continue;
4149
4199
  }
4150
4200
  }
4151
- const sessions = sessionsForSupervisor(fs10, paths.headroomSessionsDir, ports.ownPid);
4201
+ const sessions = sessionsForSupervisor(fs12, paths.headroomSessionsDir, ports.ownPid);
4152
4202
  if (sessions.length === 0) {
4153
4203
  idleSince ??= ports.now();
4154
4204
  const idleMs = ports.now() - idleSince;
@@ -4170,9 +4220,9 @@ async function runSupervisor(initialConfig, ports, options = {}) {
4170
4220
  await ports.sleep(HEADROOM_POLL_MS);
4171
4221
  }
4172
4222
  }
4173
- function currentHeadroomAllowlist(fs10, paths) {
4174
- const providers = readAllProviders(fs10, paths.providersDir).map((entry) => entry.provider);
4175
- return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs10, paths.frontdoorStateFile))));
4223
+ function currentHeadroomAllowlist(fs12, paths) {
4224
+ const providers = readAllProviders(fs12, paths.providersDir).map((entry) => entry.provider);
4225
+ return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs12, paths.frontdoorStateFile))));
4176
4226
  }
4177
4227
  function allowlistOf(ports) {
4178
4228
  return currentHeadroomAllowlist(ports.fs, ports.paths);
@@ -4349,8 +4399,8 @@ function decideConfigProfile(params) {
4349
4399
  }
4350
4400
  return { source: "none" };
4351
4401
  }
4352
- function loadIdentity(identitiesDir, name, fs10) {
4353
- return loadConfigFile(import_node_path12.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs10.readConfigFile);
4402
+ function loadIdentity(identitiesDir, name, fs12) {
4403
+ return loadConfigFile(import_node_path12.default.join(identitiesDir, name, "identity.json"), IdentitySchema, fs12.readConfigFile);
4354
4404
  }
4355
4405
 
4356
4406
  // src/configProfilesStore.ts
@@ -4692,13 +4742,59 @@ var import_node_path15 = __toESM(require("node:path"), 1);
4692
4742
 
4693
4743
  // src/credentialCache.ts
4694
4744
  var import_zod7 = require("zod");
4745
+ var MS_PER_UNIT = { s: 1e3, m: 6e4, h: 36e5, d: 864e5 };
4695
4746
  var CachedCredentialSchema = import_zod7.z.strictObject({
4696
4747
  token: import_zod7.z.string().min(1),
4697
4748
  fetchedAt: import_zod7.z.number().int().nonnegative(),
4698
4749
  source: CredentialSourceSchema
4699
4750
  });
4751
+ function effectiveStore(cache, platform) {
4752
+ return cache.store ?? (platform === "darwin" ? "keychain" : "file");
4753
+ }
4754
+ function ttlMs(cache) {
4755
+ if (cache.ttl === void 0) {
4756
+ return void 0;
4757
+ }
4758
+ const multiplier = MS_PER_UNIT[cache.ttl.slice(-1)];
4759
+ if (multiplier === void 0) {
4760
+ throw new Error(`credential cache ttl "${cache.ttl}" has no recognised unit`);
4761
+ }
4762
+ return Number(cache.ttl.slice(0, -1)) * multiplier;
4763
+ }
4764
+ function isFresh(entry, cache, now) {
4765
+ const limit = ttlMs(cache);
4766
+ if (entry.fetchedAt > now) {
4767
+ return false;
4768
+ }
4769
+ return limit === void 0 || now - entry.fetchedAt < limit;
4770
+ }
4700
4771
 
4701
4772
  // src/credential.ts
4773
+ var CREDENTIAL_UNAVAILABLE_EXIT = 64;
4774
+ var CREDENTIAL_COMMAND_TIMEOUT_MS = 1e4;
4775
+ var CREDENTIAL_INTERACTIVE_TIMEOUT_MS = 12e4;
4776
+ var GROUP_OTHER_PERMISSION_BITS = 63;
4777
+ var PERMISSION_BITS = 511;
4778
+ var OCTAL_RADIX = 8;
4779
+ function commandArgv(source) {
4780
+ if ("command" in source) {
4781
+ return source.command;
4782
+ }
4783
+ if ("op" in source) {
4784
+ return ["op", "read", source.op];
4785
+ }
4786
+ const account = source.keychain.account;
4787
+ return ["security", "find-generic-password", "-s", source.keychain.service, ...account === void 0 ? [] : ["-a", account], "-w"];
4788
+ }
4789
+ function isInteractiveSource(source, env) {
4790
+ if ("command" in source || "keychain" in source) {
4791
+ return source.interactive ?? false;
4792
+ }
4793
+ if ("op" in source) {
4794
+ return source.interactive ?? (env.OP_SERVICE_ACCOUNT_TOKEN ?? "") === "";
4795
+ }
4796
+ return false;
4797
+ }
4702
4798
  function summariseSource(source) {
4703
4799
  if ("env" in source) {
4704
4800
  return { kind: "env", variable: source.env };
@@ -4746,6 +4842,9 @@ function formatSourceSummary(summary) {
4746
4842
  return summary;
4747
4843
  }
4748
4844
  }
4845
+ function describeSource(source) {
4846
+ return formatSourceSummary(summariseSource(source));
4847
+ }
4749
4848
  function formatCredentialSummary(summary) {
4750
4849
  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`}`;
4751
4850
  return `${summary.target} from ${summary.sources.map(formatSourceSummary).join(", then ")}${cache}`;
@@ -4753,6 +4852,88 @@ function formatCredentialSummary(summary) {
4753
4852
  function describeCredential(credential) {
4754
4853
  return formatCredentialSummary(summariseCredential(credential));
4755
4854
  }
4855
+ function trySource(source, params) {
4856
+ const none = (reason, warn = false) => ({ ok: false, reason, warn });
4857
+ if ("env" in source) {
4858
+ const value = params.env[source.env];
4859
+ return value === void 0 || value === "" ? none("is unset or empty") : { ok: true, token: value };
4860
+ }
4861
+ if ("literal" in source) {
4862
+ return { ok: true, token: source.literal };
4863
+ }
4864
+ if ("file" in source) {
4865
+ const read = params.port.readSecretFile(source.file);
4866
+ if (!read.found) {
4867
+ return none("does not exist");
4868
+ }
4869
+ if (read.mode !== void 0 && (read.mode & GROUP_OTHER_PERMISSION_BITS) !== 0) {
4870
+ return none(
4871
+ `is readable or writable by group or others (mode ${(read.mode & PERMISSION_BITS).toString(OCTAL_RADIX)}); run \`chmod 600 ${source.file}\``,
4872
+ true
4873
+ );
4874
+ }
4875
+ const token2 = read.content.trim();
4876
+ return token2 === "" ? none("is empty") : { ok: true, token: token2 };
4877
+ }
4878
+ const argv = commandArgv(source);
4879
+ const interactive = isInteractiveSource(source, params.env);
4880
+ if (interactive && !params.port.personPresent()) {
4881
+ return none("needs a person to approve it, but there is no terminal or desktop session");
4882
+ }
4883
+ const timeoutMs = source.timeoutMs ?? (interactive ? CREDENTIAL_INTERACTIVE_TIMEOUT_MS : CREDENTIAL_COMMAND_TIMEOUT_MS);
4884
+ const result = params.port.runCommand(argv, { timeoutMs, interactive });
4885
+ if (result.timedOut) {
4886
+ return none(`timed out after ${String(timeoutMs)}ms`);
4887
+ }
4888
+ if (result.status !== 0) {
4889
+ const stderr = result.stderr.trim();
4890
+ const outcome = result.status === null ? "could not be run or was killed by a signal" : `exited with status ${String(result.status)}`;
4891
+ return none(`${outcome}${stderr === "" ? "" : `: ${stderr}`}`);
4892
+ }
4893
+ const token = result.stdout.trim();
4894
+ return token === "" ? none("printed no token") : { ok: true, token };
4895
+ }
4896
+ function warmCommandFor(subject) {
4897
+ const [kind, name] = subject.split(" ");
4898
+ return kind === "provider" ? `agent-shim credential warm --provider ${name ?? ""}` : `agent-shim credential warm ${name ?? ""}`;
4899
+ }
4900
+ function resolveCredential(params) {
4901
+ const target = params.credential.target ?? "bearer";
4902
+ const cacheBlock = params.credential.cache;
4903
+ const cache = cacheBlock === void 0 ? void 0 : params.port.cache;
4904
+ const store = cacheBlock === void 0 || cache === void 0 ? void 0 : effectiveStore(cacheBlock, cache.platform);
4905
+ if (cacheBlock !== void 0 && cache !== void 0 && store !== void 0 && params.refresh !== true) {
4906
+ const entry = cache.port.read(store, params.subject);
4907
+ if (entry !== void 0 && isFresh(entry, cacheBlock, cache.now())) {
4908
+ return { ok: true, credential: { target, token: entry.token, source: entry.source, warnings: [], cachedAt: entry.fetchedAt } };
4909
+ }
4910
+ }
4911
+ const attempts = [];
4912
+ const warnings = [];
4913
+ for (const source of params.credential.sources) {
4914
+ const outcome = trySource(source, params);
4915
+ if (outcome.ok) {
4916
+ if (cache !== void 0 && store !== void 0) {
4917
+ cache.port.write(store, params.subject, { token: outcome.token, fetchedAt: cache.now(), source });
4918
+ }
4919
+ return { ok: true, credential: { target, token: outcome.token, source, warnings } };
4920
+ }
4921
+ const line = `${describeSource(source)} ${outcome.reason}`;
4922
+ attempts.push(line);
4923
+ if (outcome.warn) {
4924
+ warnings.push(`agent-shim: ${params.subject}: skipped ${line}`);
4925
+ }
4926
+ }
4927
+ const hint = cacheBlock === void 0 ? "" : `; fill the cache from a terminal with \`${warmCommandFor(params.subject)}\``;
4928
+ return { ok: false, message: `agent-shim: ${params.subject} has no usable credential: ${attempts.join("; ")}${hint}` };
4929
+ }
4930
+ function credentialVariables(target, token) {
4931
+ return {
4932
+ ANTHROPIC_AUTH_TOKEN: target === "bearer" ? token : void 0,
4933
+ ANTHROPIC_API_KEY: target === "apiKey" ? token : void 0,
4934
+ CLAUDE_CODE_OAUTH_TOKEN: target === "oauthToken" ? token : void 0
4935
+ };
4936
+ }
4756
4937
 
4757
4938
  // src/providersStore.ts
4758
4939
  var ProviderNotFoundError = class extends CliError {
@@ -4858,6 +5039,11 @@ function readProvider(paths, name) {
4858
5039
  const raw = JSON.parse(import_node_fs5.default.readFileSync(filePath, "utf8"));
4859
5040
  return parseProviderFile(filePath, raw);
4860
5041
  }
5042
+ function loadProvider(providersDir, name, port) {
5043
+ const filePath = import_node_path15.default.join(providersDir, `${name}.json`);
5044
+ const raw = port.readConfigFile(filePath);
5045
+ return raw === void 0 ? void 0 : parseProviderFile(filePath, raw);
5046
+ }
4861
5047
  function listProviders(paths) {
4862
5048
  const names = listProviderNames(
4863
5049
  (dir) => import_node_fs5.default.readdirSync(dir),
@@ -4990,6 +5176,30 @@ function cascadeProviderName(cascade) {
4990
5176
  }
4991
5177
  return name;
4992
5178
  }
5179
+ function resolveProvider(params) {
5180
+ const cliName = params.cliProvider !== void 0 && params.cliProvider !== "" ? params.cliProvider : void 0;
5181
+ const name = cliName ?? (params.cascade === void 0 ? void 0 : cascadeProviderName(params.cascade));
5182
+ if (name === void 0) {
5183
+ return void 0;
5184
+ }
5185
+ const definition = loadProvider(params.paths.providersDir, name, params.port);
5186
+ if (definition === void 0) {
5187
+ const known = listProviderNames(params.port.readdir, params.paths.providersDir);
5188
+ return {
5189
+ ok: false,
5190
+ status: 1,
5191
+ message: `agent-shim: no provider named "${name}". ` + (known.length > 0 ? `Known providers: ${known.join(", ")}.` : "No providers are defined yet; run `agent-shim provider add`.")
5192
+ };
5193
+ }
5194
+ if (params.credentials === void 0) {
5195
+ return { ok: false, status: 1, message: `agent-shim: provider ${name} needs its credential resolved, but this launcher has no credential port wired` };
5196
+ }
5197
+ const resolution = resolveCredential({ credential: definition.credential, env: params.env, port: params.credentials, subject: `provider ${name}` });
5198
+ if (!resolution.ok) {
5199
+ return { ok: false, status: CREDENTIAL_UNAVAILABLE_EXIT, message: resolution.message };
5200
+ }
5201
+ return { ok: true, provider: { name, definition, credential: resolution.credential }, warnings: resolution.credential.warnings };
5202
+ }
4993
5203
 
4994
5204
  // src/directoryRulesStore.ts
4995
5205
  var DirectoryRuleNotFoundError = class extends CliError {
@@ -5082,7 +5292,7 @@ function removeDirectoryRule(paths, rulePath) {
5082
5292
  }
5083
5293
 
5084
5294
  // src/checkReport.ts
5085
- var import_node_os3 = __toESM(require("node:os"), 1);
5295
+ var import_node_os4 = __toESM(require("node:os"), 1);
5086
5296
 
5087
5297
  // src/launcher/cascade.ts
5088
5298
  var import_node_path17 = __toESM(require("node:path"), 1);
@@ -5178,6 +5388,7 @@ var MS_PER_SECOND2 = 1e3;
5178
5388
  var SECONDS_PER_MINUTE = 60;
5179
5389
  var MINUTES_PER_HOUR = 60;
5180
5390
  var HOURS_PER_DAY = 24;
5391
+ var WARNING_STATUSES = /* @__PURE__ */ new Set(["allowed_warning", "rejected"]);
5181
5392
  function formatAge(ms) {
5182
5393
  const minutes = Math.floor(ms / (MS_PER_SECOND2 * SECONDS_PER_MINUTE));
5183
5394
  if (minutes < MINUTES_PER_HOUR) {
@@ -5198,8 +5409,30 @@ function effectiveWindow(window, nowMs) {
5198
5409
  ...window.status === void 0 ? {} : { status: window.status }
5199
5410
  };
5200
5411
  }
5412
+ function quotaWarnings(snapshot, provider, nowMs) {
5413
+ const rateLimit = snapshot?.providers[provider]?.rateLimit;
5414
+ const unified = rateLimit?.unified;
5415
+ if (snapshot === void 0 || rateLimit === void 0 || unified === void 0) {
5416
+ return [];
5417
+ }
5418
+ const age = formatAge(nowMs - Date.parse(rateLimit.observedAt));
5419
+ const windows = [
5420
+ { name: "five-hour", window: unified.fiveHour },
5421
+ { name: "seven-day", window: unified.sevenDay }
5422
+ ];
5423
+ return windows.flatMap(({ name, window }) => {
5424
+ const effective = window === void 0 ? void 0 : effectiveWindow(window, nowMs);
5425
+ if (window === void 0 || effective?.status === void 0 || !WARNING_STATUSES.has(effective.status)) {
5426
+ return [];
5427
+ }
5428
+ const reset = window.resetsAt === void 0 ? "" : `, resets ${window.resetsAt}`;
5429
+ const verdict = effective.status === "rejected" ? "exhausted" : "nearly used";
5430
+ return [`agent-shim: identity ${snapshot.identity}: the ${name} quota is ${verdict}${reset} (last seen ${age} ago)`];
5431
+ });
5432
+ }
5201
5433
 
5202
5434
  // src/usage/poolPick.ts
5435
+ var import_node_path18 = __toESM(require("node:path"), 1);
5203
5436
  var import_zod9 = require("zod");
5204
5437
 
5205
5438
  // src/usage/plan.ts
@@ -5452,14 +5685,14 @@ var PicksFileSchema = import_zod9.z.strictObject({
5452
5685
  function errorMessage(error) {
5453
5686
  return error instanceof Error ? error.message : String(error);
5454
5687
  }
5455
- function loadPoolMembers(fs10, paths, identities, nowMs) {
5688
+ function loadPoolMembers(fs12, paths, identities, nowMs) {
5456
5689
  const windowStartMs = nowMs - FIVE_HOUR_WINDOW_MS;
5457
- const log = readUsageLog(fs10, paths.usageLogDir, { sinceMs: windowStartMs });
5690
+ const log = readUsageLog(fs12, paths.usageLogDir, { sinceMs: windowStartMs });
5458
5691
  return identities.map((identity) => {
5459
5692
  const records = log.records.filter((record) => record.identity === identity && record.provider === ANTHROPIC_PROVIDER && Date.parse(record.at) >= windowStartMs);
5460
5693
  try {
5461
- const snapshot = readUsageSnapshot(fs10, paths.usageSnapshotsDir, identity);
5462
- const account = readAccountMetadata(fs10, paths.identitiesDir, identity) ?? snapshot?.account;
5694
+ const snapshot = readUsageSnapshot(fs12, paths.usageSnapshotsDir, identity);
5695
+ const account = readAccountMetadata(fs12, paths.identitiesDir, identity) ?? snapshot?.account;
5463
5696
  return { identity, records, ...snapshot === void 0 ? {} : { snapshot }, ...account === void 0 ? {} : { account } };
5464
5697
  } catch (error) {
5465
5698
  if (error instanceof UsageSnapshotError || error instanceof AccountMetadataError) {
@@ -5477,9 +5710,9 @@ function rankPoolFromStore(params) {
5477
5710
  ...params.sticky === void 0 ? {} : { sticky: params.sticky }
5478
5711
  });
5479
5712
  }
5480
- function readPicksFile(fs10, file) {
5713
+ function readPicksFile(fs12, file) {
5481
5714
  const empty = { schemaVersion: SCHEMA_VERSION, picks: {} };
5482
- const raw = fs10.readFileUtf8(file);
5715
+ const raw = fs12.readFileUtf8(file);
5483
5716
  if (raw === void 0) {
5484
5717
  return { file: empty };
5485
5718
  }
@@ -5492,17 +5725,72 @@ function readPicksFile(fs10, file) {
5492
5725
  const result = PicksFileSchema.safeParse(parsed);
5493
5726
  return result.success ? { file: result.data } : { file: empty, problem: `${file} is not a picks file this agent-shim can read` };
5494
5727
  }
5495
- function readStickyPick(fs10, picksFile, directory) {
5496
- const read = readPicksFile(fs10, picksFile);
5728
+ function readStickyPick(fs12, picksFile, directory) {
5729
+ const read = readPicksFile(fs12, picksFile);
5497
5730
  const entry = read.file.picks[directory];
5498
5731
  return { ...entry === void 0 ? {} : { sticky: entry }, ...read.problem === void 0 ? {} : { problem: read.problem } };
5499
5732
  }
5733
+ function recordStickyPick(fs12, picksFile, directory, identity, nowMs) {
5734
+ const current = readPicksFile(fs12, picksFile).file.picks;
5735
+ const kept = Object.entries(current).filter(([, entry]) => nowMs - Date.parse(entry.at) <= USAGE_RETENTION_MS);
5736
+ const next = { schemaVersion: SCHEMA_VERSION, picks: { ...Object.fromEntries(kept), [directory]: { identity, at: new Date(nowMs).toISOString() } } };
5737
+ fs12.mkdirPrivate(import_node_path18.default.dirname(picksFile));
5738
+ fs12.writeFilePrivate(picksFile, `${JSON.stringify(next, null, 2)}
5739
+ `);
5740
+ }
5500
5741
 
5501
5742
  // src/launcher/pool.ts
5502
- function splitMembers(pool, paths, fs10) {
5503
- const exists = (name) => loadIdentity(paths.identitiesDir, name, fs10) !== void 0;
5743
+ var RESUME_FLAGS = /* @__PURE__ */ new Set(["--continue", "-c", "--resume", "-r"]);
5744
+ var TERMINATOR = "--";
5745
+ var REASONS_LOGGED = 3;
5746
+ function splitMembers(pool, paths, fs12) {
5747
+ const exists = (name) => loadIdentity(paths.identitiesDir, name, fs12) !== void 0;
5504
5748
  return { present: pool.identities.filter(exists), missing: pool.identities.filter((name) => !exists(name)) };
5505
5749
  }
5750
+ function isResuming(passthrough) {
5751
+ const end = passthrough.indexOf(TERMINATOR);
5752
+ return (end === -1 ? passthrough : passthrough.slice(0, end)).some((token) => RESUME_FLAGS.has(token));
5753
+ }
5754
+ function resolvePoolLaunch(params) {
5755
+ const { poolName, log } = params;
5756
+ const pool = params.pools?.[poolName];
5757
+ if (pool === void 0) {
5758
+ return { ok: false, message: `agent-shim: no pool named "${poolName}" (selected via ${params.selectedVia}). Run \`agent-shim pool add ${poolName} --identity <name>...\` first.` };
5759
+ }
5760
+ const { present: identities, missing } = splitMembers(pool, params.paths, params.fs);
5761
+ for (const name of missing) {
5762
+ log.warn(`agent-shim: pool "${poolName}" names identity "${name}", which does not exist; skipping it`);
5763
+ }
5764
+ if (identities.length === 0) {
5765
+ return { ok: false, message: `agent-shim: no member of pool "${poolName}" is an existing identity.` };
5766
+ }
5767
+ const resuming = isResuming(params.passthrough);
5768
+ const stickyRead = readStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd);
5769
+ if (stickyRead.problem !== void 0) {
5770
+ log.warn(`agent-shim: ${stickyRead.problem}; ignoring the last-pick record`);
5771
+ }
5772
+ for (; ; ) {
5773
+ const nowMs = params.now();
5774
+ const ranking = rankPoolFromStore({ fs: params.usageFs, paths: params.paths, identities, nowMs, resuming, ...stickyRead.sticky === void 0 ? {} : { sticky: stickyRead.sticky } });
5775
+ const { pick, earliestReturn } = ranking;
5776
+ if (pick !== void 0) {
5777
+ recordStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd, pick.identity, nowMs);
5778
+ return { ok: true, identity: pick.identity, explanation: `pool ${poolName}: ${pick.reasons.slice(0, REASONS_LOGGED).join("; ")}` };
5779
+ }
5780
+ if (earliestReturn === void 0) {
5781
+ return { ok: false, message: `agent-shim: no member of pool "${poolName}" can be picked.` };
5782
+ }
5783
+ const until = new Date(earliestReturn.atMs).toISOString();
5784
+ if (!params.wait) {
5785
+ return {
5786
+ ok: false,
5787
+ 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.`
5788
+ };
5789
+ }
5790
+ log.info(`agent-shim: every member of pool "${poolName}" is refused; waiting until ${until} for ${earliestReturn.identity}`);
5791
+ params.sleep(Math.max(earliestReturn.atMs - nowMs, 0));
5792
+ }
5793
+ }
5506
5794
 
5507
5795
  // src/poolPickReport.ts
5508
5796
  function candidateView(candidate) {
@@ -5542,14 +5830,15 @@ function collectPoolPick(params) {
5542
5830
  var import_node_child_process = require("node:child_process");
5543
5831
  var import_node_crypto8 = require("node:crypto");
5544
5832
  var import_node_fs6 = __toESM(require("node:fs"), 1);
5545
- var import_node_path19 = __toESM(require("node:path"), 1);
5833
+ var import_node_os3 = __toESM(require("node:os"), 1);
5834
+ var import_node_path20 = __toESM(require("node:path"), 1);
5546
5835
  var import_node_sea = require("node:sea");
5547
5836
 
5548
5837
  // src/versionDiscovery.ts
5549
5838
  var import_node_os2 = __toESM(require("node:os"), 1);
5550
- var import_node_path18 = __toESM(require("node:path"), 1);
5839
+ var import_node_path19 = __toESM(require("node:path"), 1);
5551
5840
  function defaultVersionsDir() {
5552
- return import_node_path18.default.join(import_node_os2.default.homedir(), ".local", "share", "claude", "versions");
5841
+ return import_node_path19.default.join(import_node_os2.default.homedir(), ".local", "share", "claude", "versions");
5553
5842
  }
5554
5843
  var NUMERIC_DOTTED_VERSION_RE = /^\d+(?:\.\d+)*$/;
5555
5844
  function isNumericDottedVersion(name) {
@@ -5591,14 +5880,14 @@ function discoverClaudeBinary(options) {
5591
5880
  const highestVersion = pickHighestVersion(entries);
5592
5881
  if (highestVersion !== void 0) {
5593
5882
  return {
5594
- path: import_node_path18.default.join(versionsDir, highestVersion),
5883
+ path: import_node_path19.default.join(versionsDir, highestVersion),
5595
5884
  source: "versions-dir",
5596
5885
  version: highestVersion
5597
5886
  };
5598
5887
  }
5599
- const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) => import_node_path18.default.resolve(dir)));
5888
+ const ownInstallDirs = new Set(options.ownInstallDirs.map((dir) => import_node_path19.default.resolve(dir)));
5600
5889
  for (const dir of options.pathDirs) {
5601
- if (ownInstallDirs.has(import_node_path18.default.resolve(dir))) {
5890
+ if (ownInstallDirs.has(import_node_path19.default.resolve(dir))) {
5602
5891
  continue;
5603
5892
  }
5604
5893
  const found = options.findExecutableInDir(dir, "claude");
@@ -5643,7 +5932,7 @@ function isErrorWithCode(error, code) {
5643
5932
  }
5644
5933
  var OWNER_ONLY_DIR_MODE = 448;
5645
5934
  var OWNER_ONLY_FILE_MODE = 384;
5646
- var PERMISSION_BITS = 511;
5935
+ var PERMISSION_BITS2 = 511;
5647
5936
  var realFarmFs = {
5648
5937
  lstat(filePath) {
5649
5938
  let stat;
@@ -5709,7 +5998,7 @@ var realFarmFs = {
5709
5998
  appendFilePrivate(filePath, contents) {
5710
5999
  const descriptor = import_node_fs6.default.openSync(filePath, "a", OWNER_ONLY_FILE_MODE);
5711
6000
  try {
5712
- if ((import_node_fs6.default.fstatSync(descriptor).mode & PERMISSION_BITS) !== OWNER_ONLY_FILE_MODE) {
6001
+ if ((import_node_fs6.default.fstatSync(descriptor).mode & PERMISSION_BITS2) !== OWNER_ONLY_FILE_MODE) {
5713
6002
  import_node_fs6.default.fchmodSync(descriptor, OWNER_ONLY_FILE_MODE);
5714
6003
  }
5715
6004
  const bytes = Buffer.from(contents, "utf8");
@@ -5743,6 +6032,10 @@ var realFarmFs = {
5743
6032
  }
5744
6033
  }
5745
6034
  };
6035
+ var INT32_BYTE_LENGTH = 4;
6036
+ function realSleepSync(ms) {
6037
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(INT32_BYTE_LENGTH)), 0, 0, ms);
6038
+ }
5746
6039
  function realIsProcessAlive(pid) {
5747
6040
  try {
5748
6041
  process.kill(pid, 0);
@@ -5764,6 +6057,51 @@ var realRunPort = {
5764
6057
  return { status: result.status, stdout: result.stdout, stderr: result.stderr };
5765
6058
  }
5766
6059
  };
6060
+ function expandHome2(filePath) {
6061
+ return filePath.startsWith("~/") ? import_node_path20.default.join(import_node_os3.default.homedir(), filePath.slice(1)) : filePath;
6062
+ }
6063
+ var MACOS_GUI_SESSION_MANAGER = "Aqua";
6064
+ function hasDesktopSession() {
6065
+ if (process.platform === "darwin") {
6066
+ const result = (0, import_node_child_process.spawnSync)("launchctl", ["managername"], { encoding: "utf8" });
6067
+ return result.status === 0 && result.stdout.trim() === MACOS_GUI_SESSION_MANAGER;
6068
+ }
6069
+ if (process.platform === "win32") {
6070
+ return false;
6071
+ }
6072
+ return (process.env.DISPLAY ?? "") !== "" || (process.env.WAYLAND_DISPLAY ?? "") !== "";
6073
+ }
6074
+ var realCredentialPort = {
6075
+ readSecretFile(filePath) {
6076
+ const resolved = expandHome2(filePath);
6077
+ let content;
6078
+ let stat;
6079
+ try {
6080
+ stat = import_node_fs6.default.statSync(resolved);
6081
+ content = import_node_fs6.default.readFileSync(resolved, "utf8");
6082
+ } catch (error) {
6083
+ if (isEnoent3(error)) {
6084
+ return { found: false };
6085
+ }
6086
+ throw error;
6087
+ }
6088
+ return { found: true, content, mode: process.platform === "win32" ? void 0 : stat.mode };
6089
+ },
6090
+ runCommand(argv, options) {
6091
+ const [command, ...args] = argv;
6092
+ const result = (0, import_node_child_process.spawnSync)(command, args, {
6093
+ encoding: "utf8",
6094
+ timeout: options.timeoutMs,
6095
+ stdio: options.interactive ? ["inherit", "pipe", "inherit"] : ["ignore", "pipe", "pipe"]
6096
+ });
6097
+ if (result.error !== void 0) {
6098
+ const timedOut = isErrorWithCode(result.error, "ETIMEDOUT");
6099
+ return { status: result.status, stdout: "", stderr: timedOut ? "" : result.error.message, timedOut };
6100
+ }
6101
+ return { status: result.status, stdout: result.stdout, stderr: options.interactive ? "" : result.stderr, timedOut: false };
6102
+ },
6103
+ personPresent: () => process.stdin.isTTY || hasDesktopSession()
6104
+ };
5767
6105
  function resolveGitBranch(run, cwd) {
5768
6106
  const result = run.run("git", ["-C", cwd, "rev-parse", "--abbrev-ref", "HEAD"]);
5769
6107
  if (result.status !== 0) {
@@ -5778,6 +6116,62 @@ function resolveGitBranch(run, cwd) {
5778
6116
  }
5779
6117
  return { branch: name, branchDetached: false };
5780
6118
  }
6119
+ function resolveGitRoot(run, cwd) {
6120
+ const result = run.run("git", ["-C", cwd, "rev-parse", "--show-toplevel"]);
6121
+ if (result.status !== 0) {
6122
+ return void 0;
6123
+ }
6124
+ const root = result.stdout.trim();
6125
+ return root === "" ? void 0 : root;
6126
+ }
6127
+ function detachedDaemonSpawnOptions(logFd, env) {
6128
+ return { detached: true, stdio: ["ignore", logFd, logFd], env };
6129
+ }
6130
+ function spawnDaemonThrough(executable) {
6131
+ return (paths, subcommand, logPath) => spawnDetachedDaemon({ command: executable, args: [subcommand] }, paths, subcommand, logPath);
6132
+ }
6133
+ function spawnDetachedDaemon(invocation, paths, subcommand, logPath) {
6134
+ import_node_fs6.default.mkdirSync(import_node_path20.default.dirname(logPath), { recursive: true });
6135
+ const logFd = import_node_fs6.default.openSync(logPath, "a");
6136
+ try {
6137
+ const child = (0, import_node_child_process.spawn)(invocation.command, invocation.args, detachedDaemonSpawnOptions(logFd, { ...process.env, AGENT_SHIM_HOME: paths.root }));
6138
+ child.unref();
6139
+ if (child.pid === void 0) {
6140
+ throw new Error(`spawning ${subcommand} returned no pid`);
6141
+ }
6142
+ return child.pid;
6143
+ } finally {
6144
+ import_node_fs6.default.closeSync(logFd);
6145
+ }
6146
+ }
6147
+ function spawnHeadroomSupervisor(paths, spawnDaemon) {
6148
+ return spawnDaemon(paths, "__headroom-supervisor", paths.headroomLogPath);
6149
+ }
6150
+ function realHeadroomPort(paths, options) {
6151
+ return {
6152
+ ensure: () => {
6153
+ const up = ensureHeadroom({
6154
+ paths,
6155
+ launcherPid: process.pid,
6156
+ ports: {
6157
+ fs: realFarmFs,
6158
+ // 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.
6159
+ isRunning: realIsProcessRunning,
6160
+ now: () => Date.now(),
6161
+ sleep: realSleepSync,
6162
+ spawnSupervisor: (layout) => spawnHeadroomSupervisor(layout, options.spawnDaemon)
6163
+ }
6164
+ });
6165
+ return {
6166
+ port: up.port,
6167
+ projectId: resolveGitRoot(realRunPort, options.cwd) ?? options.cwd
6168
+ };
6169
+ },
6170
+ release: () => {
6171
+ removeSession(realFarmFs, paths.headroomSessionsDir, process.pid);
6172
+ }
6173
+ };
6174
+ }
5781
6175
  var realProcPort = {
5782
6176
  env: process.env,
5783
6177
  argv: process.argv.slice(2),
@@ -5795,7 +6189,7 @@ function listVersionsDir(dir) {
5795
6189
  throw error;
5796
6190
  }
5797
6191
  return entries.filter((entry) => entry.isFile()).map((entry) => {
5798
- const fullPath = import_node_path19.default.join(dir, entry.name);
6192
+ const fullPath = import_node_path20.default.join(dir, entry.name);
5799
6193
  const stat = import_node_fs6.default.statSync(fullPath);
5800
6194
  return {
5801
6195
  name: entry.name,
@@ -5810,7 +6204,7 @@ function windowsPathExtensions(pathext) {
5810
6204
  return (pathext ?? WINDOWS_DEFAULT_PATHEXT).split(";").map((ext) => ext.trim()).filter((ext) => ext.length > 0);
5811
6205
  }
5812
6206
  function resolveExecutableCandidate(dir, name, env) {
5813
- const candidate = import_node_path19.default.join(dir, name);
6207
+ const candidate = import_node_path20.default.join(dir, name);
5814
6208
  if (env.platform === "win32") {
5815
6209
  const extensions = windowsPathExtensions(env.pathext);
5816
6210
  const alreadyHasRecognisedExtension = extensions.some((ext) => candidate.toLowerCase().endsWith(ext.toLowerCase()));
@@ -5859,13 +6253,13 @@ function resolveOwnExecutablePath(env) {
5859
6253
  if (env.argv1 !== void 0 && !env.argv1.includes("/") && !env.argv1.includes("\\")) {
5860
6254
  return searchPathForExecutable(env.pathDirs, env.argv1, env.findExecutableInDir) ?? env.execPath;
5861
6255
  }
5862
- const candidate = env.argv1 === void 0 ? env.execPath : import_node_path19.default.resolve(env.cwd, env.argv1);
5863
- const candidateDir = import_node_path19.default.dirname(candidate);
5864
- const candidateDirOnPath = env.pathDirs.some((dir) => import_node_path19.default.resolve(dir) === candidateDir);
6256
+ const candidate = env.argv1 === void 0 ? env.execPath : import_node_path20.default.resolve(env.cwd, env.argv1);
6257
+ const candidateDir = import_node_path20.default.dirname(candidate);
6258
+ const candidateDirOnPath = env.pathDirs.some((dir) => import_node_path20.default.resolve(dir) === candidateDir);
5865
6259
  if (candidateDirOnPath) {
5866
6260
  return candidate;
5867
6261
  }
5868
- const viaPath = searchPathForExecutable(env.pathDirs, import_node_path19.default.basename(candidate), env.findExecutableInDir);
6262
+ const viaPath = searchPathForExecutable(env.pathDirs, import_node_path20.default.basename(candidate), env.findExecutableInDir);
5869
6263
  return viaPath ?? candidate;
5870
6264
  }
5871
6265
  function realOwnExecutablePath() {
@@ -5873,21 +6267,21 @@ function realOwnExecutablePath() {
5873
6267
  argv1: process.argv[1],
5874
6268
  execPath: process.execPath,
5875
6269
  cwd: process.cwd(),
5876
- pathDirs: (process.env.PATH ?? "").split(import_node_path19.default.delimiter).filter((dir) => dir !== ""),
6270
+ pathDirs: (process.env.PATH ?? "").split(import_node_path20.default.delimiter).filter((dir) => dir !== ""),
5877
6271
  findExecutableInDir
5878
6272
  });
5879
6273
  }
5880
6274
  function realResolveClaudeBinary(ownInstallDirs) {
5881
6275
  return () => discoverClaudeBinary({
5882
6276
  listVersionsDir,
5883
- pathDirs: (process.env.PATH ?? "").split(import_node_path19.default.delimiter).filter((dir) => dir !== ""),
6277
+ pathDirs: (process.env.PATH ?? "").split(import_node_path20.default.delimiter).filter((dir) => dir !== ""),
5884
6278
  findExecutableInDir,
5885
6279
  ownInstallDirs: [...ownInstallDirs]
5886
6280
  });
5887
6281
  }
5888
6282
 
5889
6283
  // src/checkReport.ts
5890
- var import_node_path20 = __toESM(require("node:path"), 1);
6284
+ var import_node_path21 = __toESM(require("node:path"), 1);
5891
6285
  var import_zod10 = require("zod");
5892
6286
 
5893
6287
  // src/cli/bool.ts
@@ -6076,7 +6470,8 @@ function runCheck(params) {
6076
6470
  nowMs: params.nowMs,
6077
6471
  env: params.env,
6078
6472
  ...params.branch === void 0 ? {} : { branch: params.branch },
6079
- ...params.branchDetached === void 0 ? {} : { branchDetached: params.branchDetached }
6473
+ ...params.branchDetached === void 0 ? {} : { branchDetached: params.branchDetached },
6474
+ descend: descendPolicyFor(params.cascade, params.home)
6080
6475
  });
6081
6476
  const resolved = resolveDecisions({ facts, cascade: params.cascade, classification: params.classification });
6082
6477
  const decisionLines = [...resolved.decisions.values()].slice().sort((a, b) => a.relPath < b.relPath ? -1 : a.relPath > b.relPath ? 1 : 0).map(formatDecision);
@@ -6209,7 +6604,7 @@ function loadCheckProvider(paths, name) {
6209
6604
  }
6210
6605
  function collectCheckReport(params) {
6211
6606
  const { paths, cwd } = params;
6212
- const home = import_node_os3.default.homedir();
6607
+ const home = import_node_os4.default.homedir();
6213
6608
  const claudeHome = resolveClaudeHome();
6214
6609
  const read = cosmiconfigReader();
6215
6610
  const classification = loadClassification(paths);
@@ -6254,10 +6649,10 @@ function collectCheckReport(params) {
6254
6649
  }).input;
6255
6650
  const providerName = cascadeProviderName(cascade);
6256
6651
  const provider = providerName === void 0 ? void 0 : loadCheckProvider(paths, providerName);
6257
- const farmRoot = identityDecision.name === void 0 ? void 0 : import_node_path20.default.join(paths.identitiesDir, identityDecision.name);
6652
+ const farmRoot = identityDecision.name === void 0 ? void 0 : import_node_path21.default.join(paths.identitiesDir, identityDecision.name);
6258
6653
  const settingsFiles = {
6259
- "settings.json": realFsPort.readFileUtf8(import_node_path20.default.join(claudeHome, "settings.json")),
6260
- "settings.local.json": realFsPort.readFileUtf8(import_node_path20.default.join(claudeHome, "settings.local.json"))
6654
+ "settings.json": realFsPort.readFileUtf8(import_node_path21.default.join(claudeHome, "settings.json")),
6655
+ "settings.local.json": realFsPort.readFileUtf8(import_node_path21.default.join(claudeHome, "settings.local.json"))
6261
6656
  };
6262
6657
  const report = runCheck({
6263
6658
  cwd,
@@ -6287,7 +6682,7 @@ function collectCheckReport(params) {
6287
6682
 
6288
6683
  // src/claudeShim.ts
6289
6684
  var import_node_fs7 = __toESM(require("node:fs"), 1);
6290
- var import_node_path21 = __toESM(require("node:path"), 1);
6685
+ var import_node_path22 = __toESM(require("node:path"), 1);
6291
6686
  var import_zod11 = require("zod");
6292
6687
  var ClaudeShimStateSchema = import_zod11.z.strictObject({
6293
6688
  targetPath: import_zod11.z.string().min(1),
@@ -6298,29 +6693,29 @@ function commandFilename(ownExecutablePath, commandName) {
6298
6693
  return ownExecutablePath.toLowerCase().endsWith(".exe") ? `${commandName}.exe` : commandName;
6299
6694
  }
6300
6695
  function resolveOwnInstallDirs(paths, ownExecutablePath) {
6301
- const dirs = [import_node_path21.default.dirname(ownExecutablePath)];
6696
+ const dirs = [import_node_path22.default.dirname(ownExecutablePath)];
6302
6697
  const state = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
6303
6698
  if (state !== void 0) {
6304
- dirs.push(import_node_path21.default.dirname(state.targetPath));
6699
+ dirs.push(import_node_path22.default.dirname(state.targetPath));
6305
6700
  }
6306
6701
  return dirs;
6307
6702
  }
6308
6703
  var nodeLinkFs = { link: import_node_fs7.default.linkSync, copyFile: import_node_fs7.default.copyFileSync, chmod: import_node_fs7.default.chmodSync };
6309
6704
  function findPathShadow(params) {
6310
- const resolvedTargetDir = import_node_path21.default.resolve(params.targetDir);
6705
+ const resolvedTargetDir = import_node_path22.default.resolve(params.targetDir);
6311
6706
  for (const dir of params.pathDirs) {
6312
6707
  const found = params.findExecutableInDir(dir, params.targetFilename);
6313
6708
  if (found === void 0) {
6314
6709
  continue;
6315
6710
  }
6316
- return import_node_path21.default.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
6711
+ return import_node_path22.default.resolve(dir) === resolvedTargetDir ? { status: "ok" } : { status: "shadowed", by: found };
6317
6712
  }
6318
- return params.pathDirs.some((dir) => import_node_path21.default.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
6713
+ return params.pathDirs.some((dir) => import_node_path22.default.resolve(dir) === resolvedTargetDir) ? { status: "ok" } : { status: "not-on-path" };
6319
6714
  }
6320
6715
 
6321
6716
  // src/doctorReport.ts
6322
6717
  var import_node_fs8 = __toESM(require("node:fs"), 1);
6323
- var import_node_path22 = __toESM(require("node:path"), 1);
6718
+ var import_node_path23 = __toESM(require("node:path"), 1);
6324
6719
  function refinePathShadow(status, ownExecutablePath, realpath) {
6325
6720
  if (status.status !== "shadowed") {
6326
6721
  return status;
@@ -6344,7 +6739,7 @@ function validateJson(schema, input) {
6344
6739
  return { ok: true, data: result.data };
6345
6740
  }
6346
6741
  function pushPathResolution(push, resolution) {
6347
- const ownDir = import_node_path22.default.dirname(resolution.ownExecutablePath);
6742
+ const ownDir = import_node_path23.default.dirname(resolution.ownExecutablePath);
6348
6743
  switch (resolution.agentShim.status) {
6349
6744
  case "ok":
6350
6745
  push("path-resolution", "pass", `\`agent-shim\` on PATH resolves to this running executable, ${resolution.ownExecutablePath}.`, "agent-shim");
@@ -6412,14 +6807,14 @@ function pushProvider(push, entry) {
6412
6807
  }
6413
6808
  function pushLegacyName(push, params) {
6414
6809
  const legacyVariables = Object.keys(params.env).filter((name) => name.startsWith(LEGACY_ENV_PREFIX) && params.env[name] !== void 0).sort();
6415
- if (legacyVariables.length === 0 && import_node_path22.default.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
6810
+ if (legacyVariables.length === 0 && import_node_path23.default.basename(params.rootPath) !== LEGACY_HOME_DIRNAME) {
6416
6811
  push("legacy-name", "pass", "Nothing here still uses the former `claude-use` name.");
6417
6812
  return;
6418
6813
  }
6419
6814
  for (const name of legacyVariables) {
6420
6815
  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);
6421
6816
  }
6422
- if (import_node_path22.default.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
6817
+ if (import_node_path23.default.basename(params.rootPath) === LEGACY_HOME_DIRNAME) {
6423
6818
  push(
6424
6819
  "legacy-name",
6425
6820
  "warn",
@@ -6727,18 +7122,18 @@ function collectDoctorReport(params) {
6727
7122
  const { paths } = params;
6728
7123
  const identityNames = import_node_fs8.default.existsSync(paths.identitiesDir) ? import_node_fs8.default.readdirSync(paths.identitiesDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && isIdentityDirectoryName(entry.name)).map((entry) => entry.name).sort() : [];
6729
7124
  const identities = identityNames.map((name) => {
6730
- const farmRoot = import_node_path22.default.join(paths.identitiesDir, name);
6731
- const identityPath = import_node_path22.default.join(farmRoot, "identity.json");
7125
+ const farmRoot = import_node_path23.default.join(paths.identitiesDir, name);
7126
+ const identityPath = import_node_path23.default.join(farmRoot, "identity.json");
6732
7127
  return { name, path: identityPath, raw: realFsPort.readFileUtf8(identityPath), farmRoot };
6733
7128
  });
6734
7129
  const profileNames = import_node_fs8.default.existsSync(paths.configProfilesDir) ? import_node_fs8.default.readdirSync(paths.configProfilesDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
6735
7130
  const configProfiles = profileNames.map((name) => {
6736
- const profilePath = import_node_path22.default.join(paths.configProfilesDir, `${name}.json`);
7131
+ const profilePath = import_node_path23.default.join(paths.configProfilesDir, `${name}.json`);
6737
7132
  return { name, path: profilePath, raw: realFsPort.readFileUtf8(profilePath) };
6738
7133
  });
6739
7134
  const providerNames = import_node_fs8.default.existsSync(paths.providersDir) ? import_node_fs8.default.readdirSync(paths.providersDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => entry.name.slice(0, -".json".length)).sort() : [];
6740
7135
  const providers = providerNames.map((name) => {
6741
- const providerPath = import_node_path22.default.join(paths.providersDir, `${name}.json`);
7136
+ const providerPath = import_node_path23.default.join(paths.providersDir, `${name}.json`);
6742
7137
  return { name, path: providerPath, raw: realFsPort.readFileUtf8(providerPath) };
6743
7138
  });
6744
7139
  const ownExecutablePath = realOwnExecutablePath();
@@ -6750,12 +7145,12 @@ function collectDoctorReport(params) {
6750
7145
  binaryDiscovery = { ok: false, message: error instanceof Error ? error.message : String(error) };
6751
7146
  }
6752
7147
  const shimState = readJson(paths.claudeShimFile, ClaudeShimStateSchema);
6753
- const pathDirs = (params.env.PATH ?? "").split(import_node_path22.default.delimiter).filter((dir) => dir !== "");
7148
+ const pathDirs = (params.env.PATH ?? "").split(import_node_path23.default.delimiter).filter((dir) => dir !== "");
6754
7149
  const claudeShimShadow = shimState === void 0 ? void 0 : refinePathShadow(
6755
7150
  findPathShadow({
6756
7151
  pathDirs,
6757
- targetDir: import_node_path22.default.dirname(shimState.targetPath),
6758
- targetFilename: import_node_path22.default.basename(shimState.targetPath),
7152
+ targetDir: import_node_path23.default.dirname(shimState.targetPath),
7153
+ targetFilename: import_node_path23.default.basename(shimState.targetPath),
6759
7154
  findExecutableInDir
6760
7155
  }),
6761
7156
  shimState.targetPath,
@@ -6778,7 +7173,7 @@ function collectDoctorReport(params) {
6778
7173
  agentShim: refinePathShadow(
6779
7174
  findPathShadow({
6780
7175
  pathDirs,
6781
- targetDir: import_node_path22.default.dirname(ownExecutablePath),
7176
+ targetDir: import_node_path23.default.dirname(ownExecutablePath),
6782
7177
  targetFilename: commandFilename(ownExecutablePath, "agent-shim"),
6783
7178
  findExecutableInDir
6784
7179
  }),
@@ -6796,6 +7191,975 @@ function collectDoctorReport(params) {
6796
7191
  });
6797
7192
  return report;
6798
7193
  }
7194
+
7195
+ // src/launcher.ts
7196
+ var import_node_crypto9 = require("node:crypto");
7197
+ var import_node_path25 = __toESM(require("node:path"), 1);
7198
+
7199
+ // src/launcher/argv.ts
7200
+ var ConflictingIdentityError = class extends UsageError {
7201
+ constructor(positional, flag) {
7202
+ super(`The launch names two identities: "@${positional}" and "--identity ${flag}". Pass only one.`);
7203
+ this.positional = positional;
7204
+ this.flag = flag;
7205
+ this.name = "ConflictingIdentityError";
7206
+ }
7207
+ positional;
7208
+ flag;
7209
+ };
7210
+ var VALUED_FLAGS = ["--identity", "--config-profile", "--provider", "--category", "--share", "--hide"];
7211
+ var BOOLEAN_FLAGS = [
7212
+ { flag: "--headroom", key: "headroom" },
7213
+ { flag: "--track-usage", key: "trackUsage" },
7214
+ { flag: "--skip-permissions", key: "skipPermissions" },
7215
+ { flag: "--remote-control", key: "remoteControl" },
7216
+ { flag: "--wait", key: "wait" }
7217
+ ];
7218
+ var LAUNCHER_FLAG_NAMES = [
7219
+ ...VALUED_FLAGS,
7220
+ "--no-provider",
7221
+ ...BOOLEAN_FLAGS.flatMap(({ flag }) => [flag, `--no-${flag.slice(2)}`])
7222
+ ];
7223
+ var TERMINATOR2 = "--";
7224
+ function matchValuedFlag(token) {
7225
+ for (const flag of VALUED_FLAGS) {
7226
+ if (token === flag) {
7227
+ return { flag };
7228
+ }
7229
+ if (token.startsWith(`${flag}=`)) {
7230
+ return { flag, inlineValue: token.slice(flag.length + 1) };
7231
+ }
7232
+ }
7233
+ return void 0;
7234
+ }
7235
+ function matchBooleanFlag(token) {
7236
+ for (const { flag, key } of BOOLEAN_FLAGS) {
7237
+ if (token === flag) {
7238
+ return { key, value: true };
7239
+ }
7240
+ if (token === `--no-${flag.slice(2)}`) {
7241
+ return { key, value: false };
7242
+ }
7243
+ }
7244
+ return void 0;
7245
+ }
7246
+ function parseLauncherArgv(argv) {
7247
+ const first = argv[0];
7248
+ const positionalIdentity = first !== void 0 && first.startsWith("@") && first.length > 1 ? first.slice(1) : void 0;
7249
+ const remaining = positionalIdentity === void 0 ? argv : argv.slice(1);
7250
+ let flagIdentity;
7251
+ let configProfile;
7252
+ let provider;
7253
+ const booleans = {};
7254
+ const categoryFlags = [];
7255
+ const shareFlags = [];
7256
+ const hideFlags = [];
7257
+ const rest = [];
7258
+ for (let index = 0; index < remaining.length; index += 1) {
7259
+ const token = remaining[index];
7260
+ if (token === void 0) {
7261
+ continue;
7262
+ }
7263
+ if (token === TERMINATOR2) {
7264
+ rest.push(...remaining.slice(index));
7265
+ break;
7266
+ }
7267
+ if (token === "--no-provider") {
7268
+ provider = false;
7269
+ continue;
7270
+ }
7271
+ const booleanFlag = matchBooleanFlag(token);
7272
+ if (booleanFlag !== void 0) {
7273
+ booleans[booleanFlag.key] = booleanFlag.value;
7274
+ continue;
7275
+ }
7276
+ const matched = matchValuedFlag(token);
7277
+ if (matched === void 0) {
7278
+ rest.push(token);
7279
+ continue;
7280
+ }
7281
+ let value;
7282
+ if (matched.inlineValue !== void 0) {
7283
+ value = matched.inlineValue;
7284
+ } else {
7285
+ const next = remaining[index + 1];
7286
+ if (next === void 0 || next === TERMINATOR2) {
7287
+ rest.push(token);
7288
+ continue;
7289
+ }
7290
+ value = next;
7291
+ index += 1;
7292
+ }
7293
+ switch (matched.flag) {
7294
+ case "--identity":
7295
+ flagIdentity = value;
7296
+ break;
7297
+ case "--config-profile":
7298
+ configProfile = value;
7299
+ break;
7300
+ case "--provider":
7301
+ provider = value;
7302
+ break;
7303
+ case "--category":
7304
+ categoryFlags.push(value);
7305
+ break;
7306
+ case "--share":
7307
+ shareFlags.push(value);
7308
+ break;
7309
+ case "--hide":
7310
+ hideFlags.push(value);
7311
+ break;
7312
+ default:
7313
+ matched.flag;
7314
+ }
7315
+ }
7316
+ if (positionalIdentity !== void 0 && flagIdentity !== void 0 && positionalIdentity !== flagIdentity) {
7317
+ throw new ConflictingIdentityError(positionalIdentity, flagIdentity);
7318
+ }
7319
+ const identity = flagIdentity ?? positionalIdentity;
7320
+ return {
7321
+ ...identity === void 0 ? {} : { identity },
7322
+ ...configProfile === void 0 ? {} : { configProfile },
7323
+ ...provider === void 0 ? {} : { provider },
7324
+ ...booleans,
7325
+ categoryFlags,
7326
+ shareFlags,
7327
+ hideFlags,
7328
+ rest
7329
+ };
7330
+ }
7331
+
7332
+ // src/cli/pairs.ts
7333
+ function splitCommas(input) {
7334
+ if (input === "") {
7335
+ return [];
7336
+ }
7337
+ return input.split(",");
7338
+ }
7339
+ function parsePair(input) {
7340
+ const eqIndex = input.indexOf("=");
7341
+ if (eqIndex === -1) {
7342
+ throw new Error(`Expected "<key>=<value>", got "${input}" (no "=" found)`);
7343
+ }
7344
+ const key = input.slice(0, eqIndex);
7345
+ const value = input.slice(eqIndex + 1);
7346
+ if (key === "") {
7347
+ throw new Error(`Expected a non-empty key before "=" in "${input}"`);
7348
+ }
7349
+ return { key, value };
7350
+ }
7351
+ function parseBool(input) {
7352
+ const parsed = parseBoolWord(input);
7353
+ if (parsed === void 0) {
7354
+ throw new Error(`Expected "true", "false", "1" or "0", got "${input}"`);
7355
+ }
7356
+ return parsed;
7357
+ }
7358
+ function parseBoolPairList(input) {
7359
+ const result = {};
7360
+ for (const piece of splitCommas(input)) {
7361
+ const { key, value } = parsePair(piece);
7362
+ result[key] = parseBool(value);
7363
+ }
7364
+ return result;
7365
+ }
7366
+
7367
+ // src/launcher/cliOverride.ts
7368
+ var InvalidCliCategoryError = class extends CliError {
7369
+ constructor(categoryName) {
7370
+ super(`"${categoryName}" is not a category this launch may toggle (runtime, history, knowledge, settings).`);
7371
+ this.categoryName = categoryName;
7372
+ this.name = "InvalidCliCategoryError";
7373
+ }
7374
+ categoryName;
7375
+ };
7376
+ var InvalidCliEntryKeyError = class extends CliError {
7377
+ constructor(key) {
7378
+ super(`"${key}" is not a valid entries key \u2014 it must start with "<category>/", e.g. "knowledge/skills/commit".`);
7379
+ this.key = key;
7380
+ this.name = "InvalidCliEntryKeyError";
7381
+ }
7382
+ key;
7383
+ };
7384
+ function toCategoryMap(pairs) {
7385
+ const expanded = expandAllCategoryKey(pairs);
7386
+ const result = {};
7387
+ for (const [key, value] of Object.entries(expanded)) {
7388
+ if (!isOverridableCategory(key)) {
7389
+ throw new InvalidCliCategoryError(key);
7390
+ }
7391
+ result[key] = value;
7392
+ }
7393
+ return result;
7394
+ }
7395
+ function toEntries(pairs) {
7396
+ for (const key of Object.keys(pairs)) {
7397
+ if (!ENTRY_KEY_RE.test(key)) {
7398
+ throw new InvalidCliEntryKeyError(key);
7399
+ }
7400
+ }
7401
+ return pairs;
7402
+ }
7403
+ function parseOverride(source, raw, parse) {
7404
+ try {
7405
+ return parse(raw);
7406
+ } catch (error) {
7407
+ if (error instanceof Error && !(error instanceof CliError)) {
7408
+ throw new UsageError(`Invalid ${source} value "${raw}": ${error.message}.`);
7409
+ }
7410
+ throw error;
7411
+ }
7412
+ }
7413
+ function buildCliOverride(params) {
7414
+ let categoryPairs = {};
7415
+ if (params.env.AGENT_SHIM_CATEGORY_OVERRIDE !== void 0 && params.env.AGENT_SHIM_CATEGORY_OVERRIDE !== "") {
7416
+ categoryPairs = parseOverride("AGENT_SHIM_CATEGORY_OVERRIDE", params.env.AGENT_SHIM_CATEGORY_OVERRIDE, parseBoolPairList);
7417
+ }
7418
+ for (const flagValue of params.categoryFlags) {
7419
+ const pair = parseOverride("--category", flagValue, (raw) => {
7420
+ const { key, value } = parsePair(raw);
7421
+ return { key, value: parseBool(value) };
7422
+ });
7423
+ categoryPairs[pair.key] = pair.value;
7424
+ }
7425
+ let entryPairs = {};
7426
+ if (params.env.AGENT_SHIM_ENTRY_OVERRIDE !== void 0 && params.env.AGENT_SHIM_ENTRY_OVERRIDE !== "") {
7427
+ entryPairs = parseOverride("AGENT_SHIM_ENTRY_OVERRIDE", params.env.AGENT_SHIM_ENTRY_OVERRIDE, parseBoolPairList);
7428
+ }
7429
+ for (const entryPath of params.shareFlags) {
7430
+ entryPairs[entryPath] = true;
7431
+ }
7432
+ for (const entryPath of params.hideFlags) {
7433
+ entryPairs[entryPath] = false;
7434
+ }
7435
+ const hasCategories = Object.keys(categoryPairs).length > 0;
7436
+ const hasEntries = Object.keys(entryPairs).length > 0;
7437
+ const hasProvider = params.providerFlag !== void 0 && params.providerFlag !== "";
7438
+ if (!hasCategories && !hasEntries && !hasProvider) {
7439
+ return void 0;
7440
+ }
7441
+ return {
7442
+ ...hasCategories ? { categories: toCategoryMap(categoryPairs) } : {},
7443
+ ...hasEntries ? { entries: toEntries(entryPairs) } : {},
7444
+ ...hasProvider ? { launch: { provider: params.providerFlag } } : {}
7445
+ };
7446
+ }
7447
+
7448
+ // src/launcher/flags.ts
7449
+ var import_node_path24 = __toESM(require("node:path"), 1);
7450
+
7451
+ // src/headroom/headers.ts
7452
+ function mergeAnthropicCustomHeaders(existing, additions) {
7453
+ const merged = /* @__PURE__ */ new Map();
7454
+ for (const block of existing) {
7455
+ if (block === void 0) {
7456
+ continue;
7457
+ }
7458
+ for (const line of block.split("\n")) {
7459
+ const entry = parseCustomHeaderLine(line);
7460
+ if (entry === void 0) {
7461
+ continue;
7462
+ }
7463
+ merged.set(entry.name, entry.value);
7464
+ }
7465
+ }
7466
+ for (const entry of additions) {
7467
+ merged.set(entry.name, entry.value);
7468
+ }
7469
+ return [...merged].map(([name, value]) => `${name}: ${value}`).join("\n");
7470
+ }
7471
+ function parseCustomHeaderLine(line) {
7472
+ const trimmed = line.trim();
7473
+ if (trimmed === "") {
7474
+ return void 0;
7475
+ }
7476
+ const colon = trimmed.indexOf(":");
7477
+ if (colon <= 0) {
7478
+ return void 0;
7479
+ }
7480
+ return { name: trimmed.slice(0, colon).trim(), value: trimmed.slice(colon + 1).trim() };
7481
+ }
7482
+
7483
+ // src/launcher/flags.ts
7484
+ function resolveLaunchFlags(params) {
7485
+ return {
7486
+ skipPermissions: params.flags?.skipPermissions ?? parseEnvBool("AGENT_SHIM_SKIP_PERMISSIONS", params.env.AGENT_SHIM_SKIP_PERMISSIONS) ?? params.cascade?.skipPermissions ?? false,
7487
+ remoteControl: params.flags?.remoteControl ?? parseEnvBool("AGENT_SHIM_REMOTE_CONTROL", params.env.AGENT_SHIM_REMOTE_CONTROL) ?? params.cascade?.remoteControl ?? false,
7488
+ headroom: params.flags?.headroom ?? parseEnvBool("AGENT_SHIM_HEADROOM", params.env.AGENT_SHIM_HEADROOM) ?? params.cascade?.headroom ?? false,
7489
+ trackUsage: params.flags?.trackUsage ?? parseEnvBool("AGENT_SHIM_TRACK_USAGE", params.env.AGENT_SHIM_TRACK_USAGE) ?? params.cascade?.trackUsage ?? params.trackUsageDefault ?? false
7490
+ };
7491
+ }
7492
+ function buildFlagArgs(flags) {
7493
+ const args = [];
7494
+ if (flags.skipPermissions) {
7495
+ args.push("--dangerously-skip-permissions");
7496
+ }
7497
+ if (flags.remoteControl) {
7498
+ args.push("--remote-control=");
7499
+ }
7500
+ return args;
7501
+ }
7502
+ function buildArgv(params) {
7503
+ return [...params.toolFlags, ...params.extraFlags, ...params.passthrough];
7504
+ }
7505
+ var LOOPBACK_HOSTS = ["127.0.0.1", "localhost", "::1"];
7506
+ function isLoopbackUrl(baseUrl) {
7507
+ const host = new URL(baseUrl).hostname.replace(/^\[|\]$/g, "");
7508
+ return LOOPBACK_HOSTS.some((loopback) => loopback === host);
7509
+ }
7510
+ function withLoopbackHosts(existing) {
7511
+ const listed = (existing ?? "").split(",").map((entry) => entry.trim()).filter((entry) => entry !== "");
7512
+ return [...listed, ...LOOPBACK_HOSTS.filter((host) => !listed.includes(host))].join(",");
7513
+ }
7514
+ function buildEnv(params) {
7515
+ const env = { ...params.baseEnv };
7516
+ const parentCustomHeaders = params.baseEnv.ANTHROPIC_CUSTOM_HEADERS;
7517
+ let providerCustomHeaders;
7518
+ if (!params.configDirEscapeHatch && params.resolvedIdentityName !== void 0) {
7519
+ env.CLAUDE_CONFIG_DIR = import_node_path24.default.join(params.identitiesDir, params.resolvedIdentityName);
7520
+ }
7521
+ if (params.provider !== void 0) {
7522
+ const providerEnv = params.provider.definition.env ?? {};
7523
+ providerCustomHeaders = providerEnv.ANTHROPIC_CUSTOM_HEADERS;
7524
+ env.ANTHROPIC_BASE_URL = params.provider.baseUrl;
7525
+ if (isLoopbackUrl(params.provider.baseUrl)) {
7526
+ env.NO_PROXY = withLoopbackHosts(params.baseEnv.NO_PROXY);
7527
+ env.no_proxy = withLoopbackHosts(params.baseEnv.no_proxy);
7528
+ }
7529
+ env.AGENT_SHIM_PROVIDER = params.provider.definition.displayName;
7530
+ for (const [key, value] of Object.entries(providerEnv)) {
7531
+ env[key] = value;
7532
+ }
7533
+ }
7534
+ const credential = params.provider?.credential ?? params.identityCredential;
7535
+ if (credential !== void 0) {
7536
+ for (const [variable, value] of Object.entries(credentialVariables(credential.target, credential.token))) {
7537
+ env[variable] = value;
7538
+ }
7539
+ }
7540
+ if (params.headroom !== void 0) {
7541
+ env.HEADROOM_PROXY_URL = `http://127.0.0.1:${String(params.headroom.port)}`;
7542
+ }
7543
+ if (params.frontdoor !== void 0) {
7544
+ env.ANTHROPIC_CUSTOM_HEADERS = mergeAnthropicCustomHeaders(
7545
+ [
7546
+ ...parentCustomHeaders === void 0 ? [] : [parentCustomHeaders],
7547
+ ...providerCustomHeaders === void 0 ? [] : [providerCustomHeaders]
7548
+ ],
7549
+ [
7550
+ ...params.resolvedIdentityName === void 0 ? [] : [{ name: IDENTITY_HEADER, value: params.resolvedIdentityName }],
7551
+ { name: SESSION_HEADER, value: params.sessionId },
7552
+ { name: AUTH_HEADER, value: params.frontdoor.sessionToken },
7553
+ ...params.headroom === void 0 ? [] : [
7554
+ { name: HEADROOM_FLAG_HEADER, value: "1" },
7555
+ { name: PROJECT_ID_HEADER, value: params.headroom.projectId }
7556
+ ]
7557
+ ]
7558
+ );
7559
+ env.NODE_EXTRA_CA_CERTS = params.frontdoor.trustBundlePath;
7560
+ if (params.provider === void 0) {
7561
+ env.HTTPS_PROXY = connectProxyUrl(params.frontdoor.connectPort, params.frontdoor.sessionToken);
7562
+ }
7563
+ }
7564
+ return env;
7565
+ }
7566
+
7567
+ // src/launcher/extraFlags.ts
7568
+ function splitExtraFlags(value) {
7569
+ if (value === void 0) {
7570
+ return [];
7571
+ }
7572
+ const trimmed = value.trim();
7573
+ if (trimmed === "") {
7574
+ return [];
7575
+ }
7576
+ return trimmed.split(/\s+/);
7577
+ }
7578
+
7579
+ // src/launcher.ts
7580
+ function resolveIdentityCredential(identity, credential, env, port) {
7581
+ if (port === void 0) {
7582
+ return { ok: false, status: 1, message: `agent-shim: identity ${identity} needs its credential resolved, but this launcher has no credential port wired` };
7583
+ }
7584
+ const resolution = resolveCredential({ credential, env, port, subject: `identity ${identity}` });
7585
+ return resolution.ok ? resolution : { ok: false, status: CREDENTIAL_UNAVAILABLE_EXIT, message: resolution.message };
7586
+ }
7587
+ function pickFromPool(decided, params, parsedArgv) {
7588
+ const { paths, fs: fs12, proc, log } = params;
7589
+ if (decided.pool === void 0) {
7590
+ return { identityDecision: decided };
7591
+ }
7592
+ const farmRuntime = params.farm;
7593
+ if (farmRuntime === void 0) {
7594
+ log.error(`agent-shim: pool "${decided.pool}" was selected, but this launcher has no farm wired to read usage and pick a member with.`);
7595
+ return proc.exit(1);
7596
+ }
7597
+ const resolution = resolvePoolLaunch({
7598
+ poolName: decided.pool,
7599
+ selectedVia: decided.source,
7600
+ pools: params.pools,
7601
+ paths,
7602
+ fs: fs12,
7603
+ usageFs: farmRuntime.fs,
7604
+ cwd: farmRuntime.cwd,
7605
+ now: farmRuntime.now,
7606
+ sleep: farmRuntime.lock.sleep,
7607
+ passthrough: parsedArgv.rest,
7608
+ wait: parsedArgv.wait === true,
7609
+ log
7610
+ });
7611
+ if (!resolution.ok) {
7612
+ log.error(resolution.message);
7613
+ return proc.exit(1);
7614
+ }
7615
+ return { identityDecision: { ...decided, name: resolution.identity }, poolExplanation: resolution.explanation };
7616
+ }
7617
+ function prepareLaunch(params) {
7618
+ const { paths, fs: fs12, proc, log } = params;
7619
+ const { env, argv } = proc;
7620
+ const parsedArgv = parseLauncherArgv(argv);
7621
+ const cliOverride = buildCliOverride({
7622
+ env,
7623
+ categoryFlags: parsedArgv.categoryFlags,
7624
+ shareFlags: parsedArgv.shareFlags,
7625
+ hideFlags: parsedArgv.hideFlags
7626
+ });
7627
+ const configDirEscapeHatchApplies = env.CLAUDE_CONFIG_DIR !== void 0 && env.CLAUDE_CONFIG_DIR !== "";
7628
+ const decidedIdentity = decideIdentity({
7629
+ env,
7630
+ argv0Identity: parsedArgv.identity,
7631
+ directoryPinnedIdentity: params.directoryPinnedIdentity,
7632
+ readActiveIdentityFile: () => {
7633
+ const raw = fs12.readFileUtf8(paths.activeIdentityFile);
7634
+ if (raw === void 0) {
7635
+ return void 0;
7636
+ }
7637
+ const trimmed = raw.trim();
7638
+ return trimmed === "" ? void 0 : trimmed;
7639
+ }
7640
+ });
7641
+ const { identityDecision, poolExplanation } = pickFromPool(decidedIdentity, params, parsedArgv);
7642
+ const farmIdentity = configDirEscapeHatchApplies ? void 0 : identityDecision.name;
7643
+ const farm = farmIdentity === void 0 ? void 0 : params.farm;
7644
+ if (farm !== void 0 && farmIdentity !== void 0) {
7645
+ let recovery;
7646
+ try {
7647
+ recovery = recoverFarm({
7648
+ fs: farm.fs,
7649
+ identitiesDir: paths.identitiesDir,
7650
+ identity: farmIdentity,
7651
+ now: farm.now,
7652
+ lock: farm.lock,
7653
+ classification: farm.classification
7654
+ });
7655
+ } catch (error) {
7656
+ if (error instanceof IdentityLockBusyError) {
7657
+ log.error(error.message);
7658
+ proc.exit(1);
7659
+ }
7660
+ throw error;
7661
+ }
7662
+ for (const diagnostic of recoveryDiagnostics(recovery, farmIdentity)) {
7663
+ log.warn(`agent-shim: ${diagnostic.code}: ${diagnostic.message}`);
7664
+ }
7665
+ }
7666
+ let loadedIdentity;
7667
+ if (identityDecision.name !== void 0) {
7668
+ loadedIdentity = loadIdentity(paths.identitiesDir, identityDecision.name, fs12);
7669
+ if (loadedIdentity === void 0) {
7670
+ log.error(
7671
+ `agent-shim: no identity named "${identityDecision.name}" (selected via ${identityDecision.source}). Run \`agent-shim identity add ${identityDecision.name}\` first.`
7672
+ );
7673
+ proc.exit(1);
7674
+ }
7675
+ }
7676
+ const configProfileDecision = decideConfigProfile({
7677
+ env,
7678
+ cliFlagConfigProfile: params.cliFlagConfigProfile ?? parsedArgv.configProfile,
7679
+ directoryRuleConfigProfile: params.directoryRuleConfigProfile,
7680
+ identityDefaultConfigProfile: loadedIdentity?.config.defaultConfigProfile,
7681
+ globalDefaultConfigProfile: params.globalDefaultConfigProfile
7682
+ });
7683
+ if (configProfileDecision.name !== void 0 && params.allowMissingConfigProfile !== true && fs12.readConfigFile(import_node_path25.default.join(paths.configProfilesDir, `${configProfileDecision.name}.json`)) === void 0) {
7684
+ log.error(
7685
+ `agent-shim: no configuration profile named "${configProfileDecision.name}" (selected via ${configProfileDecision.source}). Run \`agent-shim profile add ${configProfileDecision.name}\` first.`
7686
+ );
7687
+ proc.exit(1);
7688
+ }
7689
+ const farmContext = farm !== void 0 && farmIdentity !== void 0 ? { farm, identity: farmIdentity, cascade: farm.loadCascade(configProfileDecision.name, cliOverride) } : void 0;
7690
+ const provider = parsedArgv.provider === false ? void 0 : resolveProvider({
7691
+ paths,
7692
+ port: fs12,
7693
+ env,
7694
+ ...params.credentials === void 0 ? {} : { credentials: params.credentials },
7695
+ ...parsedArgv.provider === void 0 ? {} : { cliProvider: parsedArgv.provider },
7696
+ ...farmContext === void 0 ? {} : { cascade: farmContext.cascade }
7697
+ });
7698
+ if (provider !== void 0 && !provider.ok) {
7699
+ log.error(provider.message);
7700
+ proc.exit(provider.status);
7701
+ }
7702
+ const resolvedProvider = provider?.ok === true ? provider.provider : void 0;
7703
+ for (const warning of provider?.ok === true ? provider.warnings : []) {
7704
+ log.warn(warning);
7705
+ }
7706
+ if (farm !== void 0 && farmIdentity !== void 0) {
7707
+ try {
7708
+ const snapshot = readUsageSnapshot(farm.fs, paths.usageSnapshotsDir, farmIdentity);
7709
+ for (const warning of quotaWarnings(snapshot, resolvedProvider?.name ?? ANTHROPIC_PROVIDER, farm.now())) {
7710
+ log.warn(warning);
7711
+ }
7712
+ } catch (error) {
7713
+ if (!(error instanceof UsageSnapshotError)) {
7714
+ throw error;
7715
+ }
7716
+ log.warn(`agent-shim: ${error.message}`);
7717
+ }
7718
+ }
7719
+ const identityCredentialBlock = loadedIdentity?.config.credential;
7720
+ const identityResolution = resolvedProvider === void 0 && farmIdentity !== void 0 && identityCredentialBlock !== void 0 ? resolveIdentityCredential(farmIdentity, identityCredentialBlock, env, params.credentials) : void 0;
7721
+ if (identityResolution !== void 0 && !identityResolution.ok) {
7722
+ log.error(identityResolution.message);
7723
+ proc.exit(identityResolution.status);
7724
+ }
7725
+ const identityCredential = identityResolution?.ok === true ? identityResolution.credential : void 0;
7726
+ for (const warning of identityCredential?.warnings ?? []) {
7727
+ log.warn(warning);
7728
+ }
7729
+ const guardResult = evaluateAmbientCredentialGuard({
7730
+ env,
7731
+ allowAmbientCredential: loadedIdentity?.config.allowAmbientCredential ?? false,
7732
+ allowAmbientCredentialOverride: parseEnvBool("AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL", env.AGENT_SHIM_ALLOW_AMBIENT_CREDENTIAL) === true,
7733
+ identityName: identityDecision.name,
7734
+ providerSelected: resolvedProvider !== void 0,
7735
+ ...identityCredential === void 0 ? {} : { injectedCredential: { variable: CREDENTIAL_TARGET_VARS[identityCredential.target], token: identityCredential.token } }
7736
+ });
7737
+ if (!guardResult.ok) {
7738
+ log.error(guardResult.message);
7739
+ proc.exit(1);
7740
+ }
7741
+ log.info(
7742
+ `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)}`)
7743
+ );
7744
+ let cascadeLaunch;
7745
+ if (farmContext !== void 0) {
7746
+ const { farm: resyncFarmRuntime, identity: resyncIdentity, cascade } = farmContext;
7747
+ let result;
7748
+ try {
7749
+ result = resyncFarm({
7750
+ fs: resyncFarmRuntime.fs,
7751
+ identitiesDir: paths.identitiesDir,
7752
+ identity: resyncIdentity,
7753
+ ...configProfileDecision.name === void 0 ? {} : { configProfile: configProfileDecision.name },
7754
+ claudeHome: resyncFarmRuntime.claudeHome,
7755
+ home: resyncFarmRuntime.home,
7756
+ cwd: resyncFarmRuntime.cwd,
7757
+ env,
7758
+ ...resyncFarmRuntime.branch === void 0 ? {} : { branch: resyncFarmRuntime.branch },
7759
+ ...resyncFarmRuntime.branchDetached === void 0 ? {} : { branchDetached: resyncFarmRuntime.branchDetached },
7760
+ cascade,
7761
+ classification: resyncFarmRuntime.classification,
7762
+ now: resyncFarmRuntime.now,
7763
+ uniqueSuffix: resyncFarmRuntime.uniqueSuffix,
7764
+ lock: resyncFarmRuntime.lock
7765
+ });
7766
+ } catch (error) {
7767
+ if (error instanceof IdentityLockBusyError) {
7768
+ log.error(error.message);
7769
+ proc.exit(1);
7770
+ }
7771
+ throw error;
7772
+ }
7773
+ for (const diagnostic of result.diagnostics) {
7774
+ if (diagnostic.severity === "error") {
7775
+ log.error(`agent-shim: ${diagnostic.code}: ${diagnostic.message}`);
7776
+ } else if (diagnostic.severity === "warning") {
7777
+ log.warn(`agent-shim: ${diagnostic.code}: ${diagnostic.message}`);
7778
+ }
7779
+ }
7780
+ log.info(
7781
+ 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}`})`
7782
+ );
7783
+ cascadeLaunch = result.resolved.flattened.launch;
7784
+ } else if (params.farm !== void 0) {
7785
+ cascadeLaunch = flattenLayers(assembleCascade(params.farm.loadCascade(configProfileDecision.name, cliOverride)).layers, { home: params.farm.home }).launch;
7786
+ }
7787
+ const discovered = params.resolveClaudeBinary();
7788
+ const resolvedFlags = resolveLaunchFlags({
7789
+ env,
7790
+ // A pool pick reads the usage the front door records, so a pool launch records its own unless something says otherwise.
7791
+ ...poolExplanation === void 0 ? {} : { trackUsageDefault: true },
7792
+ ...cascadeLaunch === void 0 ? {} : { cascade: cascadeLaunch },
7793
+ flags: {
7794
+ ...parsedArgv.skipPermissions === void 0 ? {} : { skipPermissions: parsedArgv.skipPermissions },
7795
+ ...parsedArgv.remoteControl === void 0 ? {} : { remoteControl: parsedArgv.remoteControl },
7796
+ ...parsedArgv.headroom === void 0 ? {} : { headroom: parsedArgv.headroom },
7797
+ ...parsedArgv.trackUsage === void 0 ? {} : { trackUsage: parsedArgv.trackUsage }
7798
+ }
7799
+ });
7800
+ const frontDoorPort = params.frontdoor;
7801
+ const frontDoorEngaged = resolvedProvider !== void 0 || resolvedFlags.headroom || resolvedFlags.trackUsage;
7802
+ if (frontDoorEngaged && frontDoorPort === void 0) {
7803
+ 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.");
7804
+ proc.exit(1);
7805
+ }
7806
+ const frontDoor = frontDoorEngaged && frontDoorPort !== void 0 ? frontDoorPort.ensure(env.NODE_EXTRA_CA_CERTS) : void 0;
7807
+ if (frontDoor?.trustWarning !== void 0) {
7808
+ log.warn(frontDoor.trustWarning);
7809
+ }
7810
+ let routedProvider;
7811
+ if (resolvedProvider !== void 0 && frontDoor !== void 0) {
7812
+ routedProvider = { ...resolvedProvider, baseUrl: providerBaseUrl(frontDoor.port, resolvedProvider.name) };
7813
+ }
7814
+ let headroom;
7815
+ const headroomPort = params.headroom;
7816
+ if (resolvedFlags.headroom && headroomPort !== void 0) {
7817
+ headroom = headroomPort.ensure();
7818
+ const via = resolvedProvider === void 0 ? `OAuth via the door's CONNECT surface on 127.0.0.1:${String(frontDoor?.connectPort ?? 0)}` : `provider ${resolvedProvider.name}`;
7819
+ 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})`);
7820
+ } else if (resolvedFlags.headroom) {
7821
+ log.error("agent-shim: headroom routing was requested but this launcher has no headroom port wired; refusing to launch without it.");
7822
+ proc.exit(1);
7823
+ } else if (frontDoor !== void 0) {
7824
+ 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})`}`);
7825
+ }
7826
+ const frontDoorRelease = frontDoor === void 0 ? void 0 : frontDoorPort?.release;
7827
+ const finalArgv = buildArgv({
7828
+ toolFlags: buildFlagArgs(resolvedFlags),
7829
+ extraFlags: splitExtraFlags(env.CLAUDE_EXTRA_FLAGS),
7830
+ passthrough: parsedArgv.rest
7831
+ });
7832
+ const finalEnv = buildEnv({
7833
+ baseEnv: env,
7834
+ configDirEscapeHatch: configDirEscapeHatchApplies,
7835
+ resolvedIdentityName: identityDecision.name,
7836
+ identitiesDir: paths.identitiesDir,
7837
+ ...routedProvider === void 0 ? {} : { provider: routedProvider },
7838
+ ...identityCredential === void 0 ? {} : { identityCredential },
7839
+ ...frontDoor === void 0 ? {} : { frontdoor: frontDoor },
7840
+ ...headroom === void 0 ? {} : { headroom },
7841
+ sessionId: (0, import_node_crypto9.randomUUID)()
7842
+ });
7843
+ const releases = [...headroom === void 0 || headroomPort === void 0 ? [] : [headroomPort.release], ...frontDoorRelease === void 0 ? [] : [frontDoorRelease]];
7844
+ const release = () => {
7845
+ for (const registered of releases) {
7846
+ registered();
7847
+ }
7848
+ };
7849
+ return { bin: discovered.path, args: finalArgv, env: finalEnv, release };
7850
+ }
7851
+
7852
+ // src/launchWiring.ts
7853
+ var import_node_os5 = __toESM(require("node:os"), 1);
7854
+ var import_node_crypto11 = require("node:crypto");
7855
+
7856
+ // src/realCredentialCache.ts
7857
+ var import_node_child_process2 = require("node:child_process");
7858
+ var import_node_fs9 = __toESM(require("node:fs"), 1);
7859
+ var import_node_path26 = __toESM(require("node:path"), 1);
7860
+ var KEYCHAIN_CACHE_SERVICE = "agent-shim-credential-cache";
7861
+ var CACHE_DIR_MODE = 448;
7862
+ var CACHE_FILE_MODE = 384;
7863
+ function cacheFileNameFor(owner) {
7864
+ return `${owner.replace(/[^A-Za-z0-9._-]/g, "_")}.json`;
7865
+ }
7866
+ function parseEntry(raw) {
7867
+ let json;
7868
+ try {
7869
+ json = JSON.parse(raw);
7870
+ } catch {
7871
+ return void 0;
7872
+ }
7873
+ const parsed = CachedCredentialSchema.safeParse(json);
7874
+ return parsed.success ? parsed.data : void 0;
7875
+ }
7876
+ function requireKeychain() {
7877
+ if (process.platform !== "darwin") {
7878
+ throw new Error("the keychain credential store needs macOS; use --credential-cache-store file");
7879
+ }
7880
+ }
7881
+ function security(args, stdin) {
7882
+ const result = (0, import_node_child_process2.spawnSync)("security", args, { encoding: "utf8", ...stdin === void 0 ? {} : { input: stdin }, stdio: ["pipe", "pipe", "ignore"] });
7883
+ return { status: result.status, stdout: result.stdout };
7884
+ }
7885
+ function createRealCredentialCache(root) {
7886
+ const dir = import_node_path26.default.join(root, "credential-cache");
7887
+ const filePath = (owner) => import_node_path26.default.join(dir, cacheFileNameFor(owner));
7888
+ return {
7889
+ read(store, owner) {
7890
+ if (store === "file") {
7891
+ try {
7892
+ return parseEntry(import_node_fs9.default.readFileSync(filePath(owner), "utf8"));
7893
+ } catch {
7894
+ return void 0;
7895
+ }
7896
+ }
7897
+ requireKeychain();
7898
+ const result = security(["find-generic-password", "-s", KEYCHAIN_CACHE_SERVICE, "-a", owner, "-w"]);
7899
+ return result.status === 0 ? parseEntry(Buffer.from(result.stdout.trim(), "base64").toString("utf8")) : void 0;
7900
+ },
7901
+ write(store, owner, entry) {
7902
+ const serialised = JSON.stringify(entry);
7903
+ if (store === "file") {
7904
+ import_node_fs9.default.mkdirSync(dir, { recursive: true, mode: CACHE_DIR_MODE });
7905
+ import_node_fs9.default.chmodSync(dir, CACHE_DIR_MODE);
7906
+ const target = filePath(owner);
7907
+ const temp = `${target}.${String(process.pid)}.tmp`;
7908
+ import_node_fs9.default.writeFileSync(temp, serialised, { mode: CACHE_FILE_MODE });
7909
+ import_node_fs9.default.renameSync(temp, target);
7910
+ return;
7911
+ }
7912
+ requireKeychain();
7913
+ const encoded = Buffer.from(serialised, "utf8").toString("base64");
7914
+ const result = security(["-i"], `add-generic-password -U -s ${KEYCHAIN_CACHE_SERVICE} -a ${JSON.stringify(owner)} -w ${encoded}
7915
+ `);
7916
+ if (result.status !== 0) {
7917
+ throw new Error(`could not write the keychain credential cache for ${owner}`);
7918
+ }
7919
+ },
7920
+ remove(store, owner) {
7921
+ if (store === "file") {
7922
+ import_node_fs9.default.rmSync(filePath(owner), { force: true });
7923
+ return;
7924
+ }
7925
+ requireKeychain();
7926
+ security(["delete-generic-password", "-s", KEYCHAIN_CACHE_SERVICE, "-a", owner]);
7927
+ }
7928
+ };
7929
+ }
7930
+ function realCredentialCacheEnv(paths) {
7931
+ return { port: createRealCredentialCache(paths.root), platform: process.platform, now: () => Date.now() };
7932
+ }
7933
+
7934
+ // src/frontdoor/realFrontDoorPort.ts
7935
+ var import_node_fs10 = __toESM(require("node:fs"), 1);
7936
+
7937
+ // src/frontdoor/probe.ts
7938
+ var import_node_worker_threads = require("node:worker_threads");
7939
+ var PROBE_TIMEOUT_MS = 2e3;
7940
+ var PROBE_WAIT_MARGIN_MS = 1e3;
7941
+ var REASON_BYTES = 1024;
7942
+ var HEADER_SLOTS = 2;
7943
+ var INT32_BYTES = 4;
7944
+ var VERDICT_PENDING = 0;
7945
+ var VERDICT_OK = 1;
7946
+ var VERDICT_FAILED = 2;
7947
+ var PROBE_SOURCE = `
7948
+ const { workerData } = require("node:worker_threads");
7949
+ const https = require("node:https");
7950
+ const { port, ca, timeoutMs, shared, ok, failed, headerSlots } = workerData;
7951
+ const header = new Int32Array(shared, 0, headerSlots);
7952
+ const reason = new Uint8Array(shared, headerSlots * 4);
7953
+ let done = false;
7954
+ const finish = (verdict, message) => {
7955
+ if (done) return;
7956
+ done = true;
7957
+ const bytes = Buffer.from(String(message), "utf8").subarray(0, reason.length);
7958
+ reason.set(bytes);
7959
+ Atomics.store(header, 1, bytes.length);
7960
+ Atomics.store(header, 0, verdict);
7961
+ Atomics.notify(header, 0);
7962
+ };
7963
+ const request = https.get({ host: "127.0.0.1", port, path: "/healthz", ca: [ca], agent: false }, (response) => {
7964
+ let body = "";
7965
+ response.setEncoding("utf8");
7966
+ response.on("data", (chunk) => { body += chunk; });
7967
+ response.on("end", () => {
7968
+ if (response.statusCode === 200 && body === "ok") finish(ok, "");
7969
+ else finish(failed, "the listener answered its health probe with HTTP " + String(response.statusCode));
7970
+ });
7971
+ response.on("error", (error) => finish(failed, error.message));
7972
+ });
7973
+ // A hard deadline over the whole exchange, handshake included: a listener that accepts the connection and then says nothing must still fail the probe.
7974
+ setTimeout(() => { request.destroy(new Error("no answer within " + String(timeoutMs) + "ms")); }, timeoutMs);
7975
+ request.on("error", (error) => finish(failed, (error.code ? error.code + ": " : "") + error.message));
7976
+ `;
7977
+ function probeFrontDoorSync(port, caPem) {
7978
+ const shared = new SharedArrayBuffer(HEADER_SLOTS * INT32_BYTES + REASON_BYTES);
7979
+ const header = new Int32Array(shared, 0, HEADER_SLOTS);
7980
+ const worker = new import_node_worker_threads.Worker(PROBE_SOURCE, {
7981
+ eval: true,
7982
+ workerData: { port, ca: caPem, timeoutMs: PROBE_TIMEOUT_MS, shared, ok: VERDICT_OK, failed: VERDICT_FAILED, headerSlots: HEADER_SLOTS }
7983
+ });
7984
+ worker.unref();
7985
+ try {
7986
+ const waited = Atomics.wait(header, 0, VERDICT_PENDING, PROBE_TIMEOUT_MS + PROBE_WAIT_MARGIN_MS);
7987
+ const verdict = Atomics.load(header, 0);
7988
+ if (waited === "timed-out" || verdict === VERDICT_PENDING) {
7989
+ return { ok: false, reason: `the probe did not finish within ${String(PROBE_TIMEOUT_MS + PROBE_WAIT_MARGIN_MS)}ms` };
7990
+ }
7991
+ if (verdict === VERDICT_OK) {
7992
+ return { ok: true };
7993
+ }
7994
+ const length = Atomics.load(header, 1);
7995
+ return { ok: false, reason: Buffer.from(new Uint8Array(shared, HEADER_SLOTS * INT32_BYTES, length)).toString("utf8") };
7996
+ } finally {
7997
+ void worker.terminate();
7998
+ }
7999
+ }
8000
+
8001
+ // src/frontdoor/trust.ts
8002
+ var import_node_crypto10 = require("node:crypto");
8003
+ var import_node_path27 = __toESM(require("node:path"), 1);
8004
+ var BUNDLE_NAME_HEX_DIGITS = 16;
8005
+ function resolveTrustBundle(params) {
8006
+ const { caCertFile, bundlesDir, inherited, fs: fs12 } = params;
8007
+ if (inherited === void 0 || inherited === "" || import_node_path27.default.resolve(inherited) === import_node_path27.default.resolve(caCertFile)) {
8008
+ return { path: caCertFile };
8009
+ }
8010
+ const caPem = fs12.readFileUtf8(caCertFile);
8011
+ let inheritedPem;
8012
+ try {
8013
+ inheritedPem = fs12.readFileUtf8(inherited);
8014
+ } catch (error) {
8015
+ return {
8016
+ path: caCertFile,
8017
+ 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`
8018
+ };
8019
+ }
8020
+ if (inheritedPem.includes(caPem.trim())) {
8021
+ return { path: inherited };
8022
+ }
8023
+ const combined = `${inheritedPem.trimEnd()}
8024
+ ${caPem}`;
8025
+ const bundle = import_node_path27.default.join(bundlesDir, `${(0, import_node_crypto10.createHash)("sha256").update(combined).digest("hex").slice(0, BUNDLE_NAME_HEX_DIGITS)}.pem`);
8026
+ if (!fs12.exists(bundle)) {
8027
+ fs12.mkdirp(bundlesDir);
8028
+ fs12.writeFileAtomic(bundle, combined);
8029
+ }
8030
+ return { path: bundle };
8031
+ }
8032
+
8033
+ // src/frontdoor/realFrontDoorPort.ts
8034
+ var realTrustBundleFs = {
8035
+ readFileUtf8: (file) => import_node_fs10.default.readFileSync(file, "utf8"),
8036
+ exists: (file) => import_node_fs10.default.existsSync(file),
8037
+ mkdirp: (dir) => {
8038
+ import_node_fs10.default.mkdirSync(dir, { recursive: true });
8039
+ },
8040
+ writeFileAtomic: (file, contents) => {
8041
+ realFarmFs.writeFilePrivate(file, contents);
8042
+ }
8043
+ };
8044
+ function realFrontDoorPort(paths, spawnDaemon) {
8045
+ return {
8046
+ ensure: (inheritedExtraCaCerts) => {
8047
+ const up = ensureFrontDoor({
8048
+ paths,
8049
+ launcherPid: process.pid,
8050
+ ports: {
8051
+ fs: realFarmFs,
8052
+ isRunning: realIsProcessRunning,
8053
+ now: () => Date.now(),
8054
+ sleep: realSleepSync,
8055
+ spawnSupervisor: (layout) => spawnDaemon(layout, "__frontdoor-supervisor", layout.frontdoorLogPath),
8056
+ stopSupervisor: (pid) => {
8057
+ process.kill(pid, "SIGTERM");
8058
+ },
8059
+ // 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.
8060
+ verifyListener: (port) => probeFrontDoorSync(port, import_node_fs10.default.readFileSync(paths.frontdoorCaCertFile, "utf8"))
8061
+ }
8062
+ });
8063
+ const trust = resolveTrustBundle({ caCertFile: paths.frontdoorCaCertFile, bundlesDir: paths.frontdoorCaBundlesDir, inherited: inheritedExtraCaCerts, fs: realTrustBundleFs });
8064
+ return {
8065
+ port: up.port,
8066
+ connectPort: up.connectPort,
8067
+ trustBundlePath: trust.path,
8068
+ ...trust.warning === void 0 ? {} : { trustWarning: trust.warning },
8069
+ sessionToken: up.token
8070
+ };
8071
+ },
8072
+ release: () => {
8073
+ removeFrontDoorSession(realFarmFs, paths.frontdoorSessionsDir, process.pid);
8074
+ }
8075
+ };
8076
+ }
8077
+
8078
+ // src/launchWiring.ts
8079
+ function buildFarmRuntime(paths, cwd) {
8080
+ const home = import_node_os5.default.homedir();
8081
+ const read = cosmiconfigReader();
8082
+ const classification = loadClassification(paths);
8083
+ const loaded = loadCascadeInput({ paths, home, cwd, read });
8084
+ const selections = readDirectorySelections(loaded);
8085
+ const git = resolveGitBranch(realRunPort, cwd);
8086
+ return {
8087
+ runtime: {
8088
+ fs: realFarmFs,
8089
+ claudeHome: resolveClaudeHome(),
8090
+ home,
8091
+ cwd,
8092
+ ...git.branch === void 0 ? {} : { branch: git.branch },
8093
+ ...git.branchDetached === void 0 ? {} : { branchDetached: git.branchDetached },
8094
+ classification,
8095
+ loadCascade: (baseConfigProfile, cliOverride) => loadCascadeInput({
8096
+ paths,
8097
+ home,
8098
+ cwd,
8099
+ read,
8100
+ ...baseConfigProfile === void 0 ? {} : { baseConfigProfile },
8101
+ ...cliOverride === void 0 ? {} : { cliOverride }
8102
+ }).input,
8103
+ now: () => Date.now(),
8104
+ uniqueSuffix: `${String(process.pid)}.${(0, import_node_crypto11.randomUUID)()}`,
8105
+ // 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.
8106
+ lock: { pid: process.pid, isRunning: realIsProcessRunning, sleep: realSleepSync }
8107
+ },
8108
+ ...selections.identity === void 0 ? {} : { directoryIdentity: selections.identity },
8109
+ ...selections.configProfile === void 0 ? {} : { directoryConfigProfile: selections.configProfile },
8110
+ ...loaded.globalConfig?.defaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: loaded.globalConfig.defaultConfigProfile },
8111
+ ...loaded.globalConfig?.pools === void 0 ? {} : { pools: loaded.globalConfig.pools }
8112
+ };
8113
+ }
8114
+ function realPrepareLaunchParams(paths, options) {
8115
+ const { farm } = options;
8116
+ return {
8117
+ paths,
8118
+ fs: realFsPort,
8119
+ proc: options.proc,
8120
+ log: options.log,
8121
+ resolveClaudeBinary: realResolveClaudeBinary(resolveOwnInstallDirs(paths, realOwnExecutablePath())),
8122
+ farm: farm.runtime,
8123
+ headroom: realHeadroomPort(paths, { spawnDaemon: options.spawnDaemon, cwd: farm.runtime.cwd }),
8124
+ frontdoor: realFrontDoorPort(paths, options.spawnDaemon),
8125
+ credentials: { ...realCredentialPort, cache: realCredentialCacheEnv(paths) },
8126
+ ...farm.directoryIdentity === void 0 ? {} : { directoryPinnedIdentity: farm.directoryIdentity },
8127
+ ...farm.directoryConfigProfile === void 0 ? {} : { directoryRuleConfigProfile: farm.directoryConfigProfile },
8128
+ ...farm.globalDefaultConfigProfile === void 0 ? {} : { globalDefaultConfigProfile: farm.globalDefaultConfigProfile },
8129
+ ...farm.pools === void 0 ? {} : { pools: farm.pools },
8130
+ ...options.allowMissingConfigProfile === void 0 ? {} : { allowMissingConfigProfile: options.allowMissingConfigProfile }
8131
+ };
8132
+ }
8133
+ var LaunchRefusedError = class extends CliError {
8134
+ exitCode;
8135
+ constructor(message, exitCode) {
8136
+ super(message);
8137
+ this.name = "LaunchRefusedError";
8138
+ this.exitCode = exitCode;
8139
+ }
8140
+ };
8141
+ function prepareClaudeLaunch(options) {
8142
+ const paths = options.paths ?? resolveLayoutPaths();
8143
+ const refusals = [];
8144
+ const log = {
8145
+ info: () => void 0,
8146
+ warn: () => void 0,
8147
+ error: (message) => {
8148
+ refusals.push(message);
8149
+ }
8150
+ };
8151
+ const proc = {
8152
+ env: options.env,
8153
+ argv: options.argv,
8154
+ exit: (code) => {
8155
+ throw new LaunchRefusedError(refusals.join("\n") || `the launch was refused (exit ${String(code)})`, code);
8156
+ }
8157
+ };
8158
+ const spawnDaemon = options.agentShim === void 0 ? () => {
8159
+ 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);
8160
+ } : spawnDaemonThrough(options.agentShim);
8161
+ return prepareLaunch(realPrepareLaunchParams(paths, { proc, log, spawnDaemon, farm: buildFarmRuntime(paths, options.cwd) }));
8162
+ }
6799
8163
  // Annotate the CommonJS export names for ESM import in node:
6800
8164
  0 && (module.exports = {
6801
8165
  AMBIENT_CREDENTIAL_VARS,
@@ -6828,6 +8192,7 @@ function collectDoctorReport(params) {
6828
8192
  InvalidCategoryNameError,
6829
8193
  InvalidIdentityNameError,
6830
8194
  InvalidProviderNameError,
8195
+ LaunchRefusedError,
6831
8196
  LegacyProviderFileError,
6832
8197
  PoolNameSchema,
6833
8198
  PoolNotFoundError,
@@ -6878,6 +8243,8 @@ function collectDoctorReport(params) {
6878
8243
  listUsageSnapshots,
6879
8244
  mintLeaf,
6880
8245
  parseConnectTarget,
8246
+ prepareClaudeLaunch,
8247
+ prepareLaunch,
6881
8248
  profileExists,
6882
8249
  providerExists,
6883
8250
  readActiveIdentity,