agent-shim 7.3.0 → 7.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -248,10 +248,18 @@ import { cosmiconfigSync } from "cosmiconfig";
248
248
 
249
249
  // src/cliError.ts
250
250
  var EXIT_FAILURE = 1;
251
+ var EXIT_USAGE = 2;
251
252
  var CliError = class extends Error {
252
253
  /** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
253
254
  exitCode = EXIT_FAILURE;
254
255
  };
256
+ var UsageError = class extends CliError {
257
+ exitCode = EXIT_USAGE;
258
+ constructor(message) {
259
+ super(message);
260
+ this.name = "UsageError";
261
+ }
262
+ };
255
263
 
256
264
  // src/config/classify.ts
257
265
  var GLOB_METACHARACTERS = /[*?[\]{}!()]/;
@@ -1212,6 +1220,8 @@ function planReconciliation(params) {
1212
1220
  }
1213
1221
 
1214
1222
  // src/legacy.ts
1223
+ var HOME_DIRNAME = ".agent-shim";
1224
+ var LEGACY_HOME_DIRNAME = ".claude-use";
1215
1225
  var LEGACY_FARM_MANIFEST_FILENAME = ".claude-use-farm.json";
1216
1226
 
1217
1227
  // src/launcher/lock.ts
@@ -1313,8 +1323,8 @@ var FarmManifestSchema = z2.strictObject({
1313
1323
  materialised: z2.array(z2.string()),
1314
1324
  links: z2.array(z2.strictObject({ rel: z2.string(), target: z2.string() }))
1315
1325
  });
1316
- function readFarmManifest(fs2, farmRoot) {
1317
- const raw = fs2.readFileUtf8(path4.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs2.readFileUtf8(path4.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1326
+ function readFarmManifest(fs3, farmRoot) {
1327
+ const raw = fs3.readFileUtf8(path4.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs3.readFileUtf8(path4.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1318
1328
  if (raw === void 0) {
1319
1329
  return void 0;
1320
1330
  }
@@ -1372,9 +1382,9 @@ function buildEntryFacts(params) {
1372
1382
  entries
1373
1383
  };
1374
1384
  }
1375
- function listSubtree(fs2, root, rel) {
1385
+ function listSubtree(fs3, root, rel) {
1376
1386
  const absolute = path4.join(root, rel);
1377
- const stat = fs2.lstat(absolute);
1387
+ const stat = fs3.lstat(absolute);
1378
1388
  if (stat === void 0) {
1379
1389
  return [];
1380
1390
  }
@@ -1382,10 +1392,10 @@ function listSubtree(fs2, root, rel) {
1382
1392
  return [{ rel, kind: "symlink" }];
1383
1393
  }
1384
1394
  if (stat.kind === "dir") {
1385
- const children = [...fs2.readdir(absolute)].sort().flatMap((name) => listSubtree(fs2, root, `${rel}/${name}`));
1395
+ const children = [...fs3.readdir(absolute)].sort().flatMap((name) => listSubtree(fs3, root, `${rel}/${name}`));
1386
1396
  return [{ rel, kind: "dir" }, ...children];
1387
1397
  }
1388
- const contentHash = fs2.hashFile(absolute);
1398
+ const contentHash = fs3.hashFile(absolute);
1389
1399
  return [{ rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } }];
1390
1400
  }
1391
1401
  function topLevelScopeRoots(roots) {
@@ -1399,25 +1409,25 @@ function topLevelScopeRoots(roots) {
1399
1409
  }
1400
1410
  return kept;
1401
1411
  }
1402
- function reconciliationScope(fs2, farmRoot, manifest) {
1412
+ function reconciliationScope(fs3, farmRoot, manifest) {
1403
1413
  if (manifest !== void 0) {
1404
1414
  return topLevelScopeRoots(manifest.materialised);
1405
1415
  }
1406
- return [...fs2.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs2.lstat(path4.join(farmRoot, name))?.kind === "dir").sort();
1416
+ return [...fs3.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs3.lstat(path4.join(farmRoot, name))?.kind === "dir").sort();
1407
1417
  }
1408
- function collectFarmListing(fs2, farmRoot, scopeRoots) {
1409
- return scopeRoots.flatMap((root) => listSubtree(fs2, farmRoot, root));
1418
+ function collectFarmListing(fs3, farmRoot, scopeRoots) {
1419
+ return scopeRoots.flatMap((root) => listSubtree(fs3, farmRoot, root));
1410
1420
  }
1411
- function collectCanonicalCounterparts(fs2, claudeHome, farmListing) {
1421
+ function collectCanonicalCounterparts(fs3, claudeHome, farmListing) {
1412
1422
  const out = [];
1413
1423
  for (const entry of farmListing) {
1414
1424
  const absolute = path4.join(claudeHome, entry.rel);
1415
- const stat = fs2.lstat(absolute);
1425
+ const stat = fs3.lstat(absolute);
1416
1426
  if (stat === void 0) {
1417
1427
  continue;
1418
1428
  }
1419
1429
  if (stat.kind === "file") {
1420
- const contentHash = fs2.hashFile(absolute);
1430
+ const contentHash = fs3.hashFile(absolute);
1421
1431
  out.push({ rel: entry.rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } });
1422
1432
  continue;
1423
1433
  }
@@ -2101,10 +2111,10 @@ var FrontDoorStateSchema = z3.strictObject({
2101
2111
  /** The last fatal error, kept across shutdowns so `frontdoor status` can explain a front door that is not running. */
2102
2112
  lastError: z3.string().optional()
2103
2113
  });
2104
- function readFrontDoorState(fs2, stateFile) {
2114
+ function readFrontDoorState(fs3, stateFile) {
2105
2115
  let raw;
2106
2116
  try {
2107
- raw = fs2.readFileUtf8(stateFile);
2117
+ raw = fs3.readFileUtf8(stateFile);
2108
2118
  } catch {
2109
2119
  return void 0;
2110
2120
  }
@@ -2118,28 +2128,28 @@ function readFrontDoorState(fs2, stateFile) {
2118
2128
  return void 0;
2119
2129
  }
2120
2130
  }
2121
- function writeFrontDoorState(fs2, stateFile, state) {
2122
- fs2.mkdirp(path5.dirname(stateFile));
2123
- fs2.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
2131
+ function writeFrontDoorState(fs3, stateFile, state) {
2132
+ fs3.mkdirp(path5.dirname(stateFile));
2133
+ fs3.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
2124
2134
  `);
2125
2135
  }
2126
2136
  function frontDoorOrigin(state) {
2127
2137
  const port = state?.directPort ?? state?.lastDirectPort;
2128
2138
  return port === void 0 ? void 0 : `http://127.0.0.1:${String(port)}`;
2129
2139
  }
2130
- function writeFrontDoorSession(fs2, sessionsDir, session) {
2131
- fs2.mkdirPrivate(sessionsDir);
2132
- fs2.writeFilePrivate(path5.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2140
+ function writeFrontDoorSession(fs3, sessionsDir, session) {
2141
+ fs3.mkdirPrivate(sessionsDir);
2142
+ fs3.writeFilePrivate(path5.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2133
2143
  `);
2134
2144
  }
2135
- function listFrontDoorSessions(fs2, sessionsDir) {
2145
+ function listFrontDoorSessions(fs3, sessionsDir) {
2136
2146
  const sessions = [];
2137
- for (const name of fs2.readdir(sessionsDir)) {
2147
+ for (const name of fs3.readdir(sessionsDir)) {
2138
2148
  if (!name.endsWith(".json")) {
2139
2149
  continue;
2140
2150
  }
2141
2151
  try {
2142
- const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs2.readFileUtf8(path5.join(sessionsDir, name)) ?? ""));
2152
+ const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs3.readFileUtf8(path5.join(sessionsDir, name)) ?? ""));
2143
2153
  if (parsed.success) {
2144
2154
  sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
2145
2155
  }
@@ -2149,14 +2159,14 @@ function listFrontDoorSessions(fs2, sessionsDir) {
2149
2159
  }
2150
2160
  return sessions.sort((a, b) => a.pid - b.pid);
2151
2161
  }
2152
- function removeFrontDoorSession(fs2, sessionsDir, pid) {
2153
- fs2.removeRecursive(path5.join(sessionsDir, `${String(pid)}.json`));
2162
+ function removeFrontDoorSession(fs3, sessionsDir, pid) {
2163
+ fs3.removeRecursive(path5.join(sessionsDir, `${String(pid)}.json`));
2154
2164
  }
2155
- function pruneDeadFrontDoorSessions(fs2, sessionsDir, isRunning) {
2165
+ function pruneDeadFrontDoorSessions(fs3, sessionsDir, isRunning) {
2156
2166
  const removed = [];
2157
- for (const session of listFrontDoorSessions(fs2, sessionsDir)) {
2167
+ for (const session of listFrontDoorSessions(fs3, sessionsDir)) {
2158
2168
  if (!isRunning(session.pid)) {
2159
- removeFrontDoorSession(fs2, sessionsDir, session.pid);
2169
+ removeFrontDoorSession(fs3, sessionsDir, session.pid);
2160
2170
  removed.push(session.pid);
2161
2171
  }
2162
2172
  }
@@ -2168,8 +2178,8 @@ var FRONTDOOR_SUPERVISOR_STILL_RUNNING = -1;
2168
2178
  var FRONTDOOR_POLL_MS = 1e3;
2169
2179
  var MS_PER_MINUTE = 6e4;
2170
2180
  async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {}) {
2171
- const { fs: fs2, paths } = ports;
2172
- const previous = readFrontDoorState(fs2, paths.frontdoorStateFile);
2181
+ const { fs: fs3, paths } = ports;
2182
+ const previous = readFrontDoorState(fs3, paths.frontdoorStateFile);
2173
2183
  let lastPort = previous?.lastPort;
2174
2184
  let lastConnectPort = previous?.lastConnectPort;
2175
2185
  let lastDirectPort = previous?.lastDirectPort;
@@ -2179,12 +2189,12 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2179
2189
  ...lastDirectPort === void 0 ? {} : { lastDirectPort }
2180
2190
  });
2181
2191
  const fail = (message) => {
2182
- writeFrontDoorState(fs2, paths.frontdoorStateFile, { lastError: message, ...sticky() });
2183
- fs2.removeRecursive(paths.frontdoorLockFile);
2192
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, { lastError: message, ...sticky() });
2193
+ fs3.removeRecursive(paths.frontdoorLockFile);
2184
2194
  ports.log(`agent-shim frontdoor supervisor: ${message}`);
2185
2195
  return 1;
2186
2196
  };
2187
- writeFrontDoorState(fs2, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
2197
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
2188
2198
  const previousSticky = lastPort;
2189
2199
  let http2;
2190
2200
  try {
@@ -2221,8 +2231,8 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2221
2231
  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)`);
2222
2232
  }
2223
2233
  lastDirectPort = direct.port;
2224
- writeFrontDoorState(fs2, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http2.port, connectPort: connect2.port, directPort: direct.port, ...sticky() });
2225
- fs2.removeRecursive(paths.frontdoorLockFile);
2234
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http2.port, connectPort: connect2.port, directPort: direct.port, ...sticky() });
2235
+ fs3.removeRecursive(paths.frontdoorLockFile);
2226
2236
  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(connect2.port)}`);
2227
2237
  let idleSince;
2228
2238
  let ticks = 0;
@@ -2231,15 +2241,15 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2231
2241
  return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
2232
2242
  }
2233
2243
  ticks += 1;
2234
- pruneDeadFrontDoorSessions(fs2, paths.frontdoorSessionsDir, ports.isRunning);
2235
- if (listFrontDoorSessions(fs2, paths.frontdoorSessionsDir).length === 0) {
2244
+ pruneDeadFrontDoorSessions(fs3, paths.frontdoorSessionsDir, ports.isRunning);
2245
+ if (listFrontDoorSessions(fs3, paths.frontdoorSessionsDir).length === 0) {
2236
2246
  idleSince ??= ports.now();
2237
2247
  if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE) {
2238
2248
  ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
2239
2249
  await direct.close();
2240
2250
  await connect2.close();
2241
2251
  await http2.close();
2242
- writeFrontDoorState(fs2, paths.frontdoorStateFile, sticky());
2252
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, sticky());
2243
2253
  return 0;
2244
2254
  }
2245
2255
  } else {
@@ -2251,6 +2261,7 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2251
2261
 
2252
2262
  // src/frontdoor/connect.ts
2253
2263
  var CONNECT_INTERCEPT_HOST = "api.anthropic.com";
2264
+ var CONNECT_INTERCEPT_HOSTS = [CONNECT_INTERCEPT_HOST, "platform.claude.com"];
2254
2265
  var ROUTED_PATH_PREFIX = "/v1/";
2255
2266
  var HTTPS_PORT = 443;
2256
2267
  var MAX_PORT = 65535;
@@ -2290,11 +2301,11 @@ function parseConnectTarget(authority) {
2290
2301
  }
2291
2302
  return { host, port };
2292
2303
  }
2293
- function isInterceptedHost(host, interceptHost) {
2294
- return host === interceptHost;
2304
+ function isInterceptedHost(host, interceptHosts) {
2305
+ return interceptHosts.includes(host);
2295
2306
  }
2296
- function servedByPipeline(path8) {
2297
- return path8?.startsWith(ROUTED_PATH_PREFIX) === true;
2307
+ function servedByPipeline(path9) {
2308
+ return path9?.startsWith(ROUTED_PATH_PREFIX) === true;
2298
2309
  }
2299
2310
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
2300
2311
  "connection",
@@ -2361,28 +2372,34 @@ function caParses(ca) {
2361
2372
  }
2362
2373
  }
2363
2374
  async function startConnectServer(config, effects, preferredPort) {
2364
- const handler = (request3, response) => {
2365
- if (servedByPipeline(request3.url)) {
2366
- config.serveRouted(request3, response);
2367
- return;
2368
- }
2369
- effects.forwardHttp(config.upstream, request3, response, config.capture?.observePassthrough(request3));
2370
- };
2371
- const httpSession = effects.createHttpSession(handler, config.capture === void 0 ? void 0 : (request3) => config.capture?.upgrade(request3));
2372
- const tlsAcceptor = effects.createTlsAcceptor(config.leafFor(config.interceptHost), (secure) => {
2373
- httpSession.serve(secure);
2375
+ const onUpgrade = config.capture === void 0 ? void 0 : (request3) => config.capture?.upgrade(request3);
2376
+ const sessions = config.interceptHosts.map((host) => {
2377
+ const handler = (request3, response) => {
2378
+ if (host === config.routedHost && servedByPipeline(request3.url)) {
2379
+ config.serveRouted(request3, response);
2380
+ return;
2381
+ }
2382
+ effects.forwardHttp(config.upstreamFor(host), request3, response, config.capture?.observePassthrough(request3));
2383
+ };
2384
+ const httpSession = effects.createHttpSession(handler, onUpgrade);
2385
+ const tlsAcceptor = effects.createTlsAcceptor(config.leafFor(host), (secure) => {
2386
+ httpSession.serve(secure);
2387
+ });
2388
+ return { host, httpSession, tlsAcceptor };
2374
2389
  });
2375
2390
  const ledger = createConnectionLedger(config.limits, config.isLiveCapability);
2376
2391
  const listener = await effects.listenLoopback(preferredPort, (socket) => {
2377
- handleConnect(socket, { config, effects, tlsAcceptor, ledger });
2392
+ handleConnect(socket, { config, effects, sessions, ledger });
2378
2393
  });
2379
2394
  return {
2380
2395
  port: listener.port,
2381
2396
  close: async () => {
2382
2397
  ledger.close();
2383
2398
  await listener.close();
2384
- tlsAcceptor.close();
2385
- httpSession.close();
2399
+ for (const { httpSession, tlsAcceptor } of sessions) {
2400
+ tlsAcceptor.close();
2401
+ httpSession.close();
2402
+ }
2386
2403
  }
2387
2404
  };
2388
2405
  }
@@ -2502,7 +2519,7 @@ function proxyAuthorizationOf(head) {
2502
2519
  return values.length === 1 ? value : void 0;
2503
2520
  }
2504
2521
  function routeConnect(socket, head, context) {
2505
- const { config, effects, tlsAcceptor, ledger } = context;
2522
+ const { config, effects, sessions, ledger } = context;
2506
2523
  const credential = proxyAuthorizationOf(head);
2507
2524
  const capability = credential === void 0 ? void 0 : capabilityFromProxyAuthorization(credential);
2508
2525
  if (capability === void 0 || !config.isLiveCapability(capability)) {
@@ -2521,10 +2538,11 @@ function routeConnect(socket, head, context) {
2521
2538
  refuse(socket, REFUSAL.serviceUnavailable);
2522
2539
  return;
2523
2540
  }
2524
- config.capture?.connect(target, isInterceptedHost(target.host, config.interceptHost));
2541
+ const session = sessions.find((entry) => entry.host === target.host);
2542
+ config.capture?.connect(target, session !== void 0);
2525
2543
  socket.write(CONNECT_ESTABLISHED);
2526
- if (isInterceptedHost(target.host, config.interceptHost)) {
2527
- tlsAcceptor.accept(socket);
2544
+ if (session !== void 0) {
2545
+ session.tlsAcceptor.accept(socket);
2528
2546
  return;
2529
2547
  }
2530
2548
  void blindTunnel(socket, target, effects);
@@ -2770,16 +2788,16 @@ function parseJson(raw, schema) {
2770
2788
  const parsed = schema.safeParse(JSON.parse(raw));
2771
2789
  return parsed.success ? parsed.data : void 0;
2772
2790
  }
2773
- function readHeadroomState(fs2, stateFile) {
2791
+ function readHeadroomState(fs3, stateFile) {
2774
2792
  try {
2775
- return parseJson(fs2.readFileUtf8(stateFile), HeadroomStateSchema);
2793
+ return parseJson(fs3.readFileUtf8(stateFile), HeadroomStateSchema);
2776
2794
  } catch {
2777
2795
  return void 0;
2778
2796
  }
2779
2797
  }
2780
- function writeHeadroomState(fs2, stateFile, state) {
2781
- fs2.mkdirp(path6.dirname(stateFile));
2782
- fs2.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
2798
+ function writeHeadroomState(fs3, stateFile, state) {
2799
+ fs3.mkdirp(path6.dirname(stateFile));
2800
+ fs3.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
2783
2801
  `);
2784
2802
  }
2785
2803
  function headroomAllowlist(providers) {
@@ -2799,14 +2817,14 @@ function headroomUpstreams(providers, frontDoorOrigin2) {
2799
2817
  function hashAllowlist(allowlist) {
2800
2818
  return createHash2("sha256").update(allowlist.join("\n")).digest("hex");
2801
2819
  }
2802
- function readAllProviders(fs2, providersDir) {
2820
+ function readAllProviders(fs3, providersDir) {
2803
2821
  const result = [];
2804
- for (const name of fs2.readdir(providersDir)) {
2822
+ for (const name of fs3.readdir(providersDir)) {
2805
2823
  if (!name.endsWith(".json")) {
2806
2824
  continue;
2807
2825
  }
2808
2826
  try {
2809
- const parsed = parseJson(fs2.readFileUtf8(path6.join(providersDir, name)), ProviderSchema);
2827
+ const parsed = parseJson(fs3.readFileUtf8(path6.join(providersDir, name)), ProviderSchema);
2810
2828
  if (parsed !== void 0) {
2811
2829
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
2812
2830
  }
@@ -2816,22 +2834,22 @@ function readAllProviders(fs2, providersDir) {
2816
2834
  }
2817
2835
  return result;
2818
2836
  }
2819
- function writeSession(fs2, sessionsDir, session) {
2820
- fs2.mkdirp(sessionsDir);
2821
- fs2.writeFileUtf8(path6.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2837
+ function writeSession(fs3, sessionsDir, session) {
2838
+ fs3.mkdirp(sessionsDir);
2839
+ fs3.writeFileUtf8(path6.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2822
2840
  `);
2823
2841
  }
2824
- function removeSession(fs2, sessionsDir, pid) {
2825
- fs2.removeRecursive(path6.join(sessionsDir, `${String(pid)}.json`));
2842
+ function removeSession(fs3, sessionsDir, pid) {
2843
+ fs3.removeRecursive(path6.join(sessionsDir, `${String(pid)}.json`));
2826
2844
  }
2827
- function listSessions(fs2, sessionsDir) {
2845
+ function listSessions(fs3, sessionsDir) {
2828
2846
  const sessions = [];
2829
- for (const name of fs2.readdir(sessionsDir)) {
2847
+ for (const name of fs3.readdir(sessionsDir)) {
2830
2848
  if (!name.endsWith(".json")) {
2831
2849
  continue;
2832
2850
  }
2833
2851
  try {
2834
- const parsed = parseJson(fs2.readFileUtf8(path6.join(sessionsDir, name)), HeadroomSessionSchema);
2852
+ const parsed = parseJson(fs3.readFileUtf8(path6.join(sessionsDir, name)), HeadroomSessionSchema);
2835
2853
  if (parsed !== void 0) {
2836
2854
  sessions.push(parsed);
2837
2855
  }
@@ -2841,22 +2859,22 @@ function listSessions(fs2, sessionsDir) {
2841
2859
  }
2842
2860
  return sessions.sort((a, b) => a.pid - b.pid);
2843
2861
  }
2844
- function sessionsForSupervisor(fs2, sessionsDir, supervisorPid) {
2845
- return listSessions(fs2, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
2862
+ function sessionsForSupervisor(fs3, sessionsDir, supervisorPid) {
2863
+ return listSessions(fs3, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
2846
2864
  }
2847
- function pruneDeadSessions(fs2, sessionsDir, isRunning) {
2865
+ function pruneDeadSessions(fs3, sessionsDir, isRunning) {
2848
2866
  const removed = [];
2849
- for (const session of listSessions(fs2, sessionsDir)) {
2867
+ for (const session of listSessions(fs3, sessionsDir)) {
2850
2868
  if (!isRunning(session.pid)) {
2851
- removeSession(fs2, sessionsDir, session.pid);
2869
+ removeSession(fs3, sessionsDir, session.pid);
2852
2870
  removed.push(session.pid);
2853
2871
  }
2854
2872
  }
2855
2873
  return removed;
2856
2874
  }
2857
- function readStartLock(fs2, lockFile) {
2875
+ function readStartLock(fs3, lockFile) {
2858
2876
  try {
2859
- return parseJson(fs2.readFileUtf8(lockFile), HeadroomLockSchema);
2877
+ return parseJson(fs3.readFileUtf8(lockFile), HeadroomLockSchema);
2860
2878
  } catch {
2861
2879
  return void 0;
2862
2880
  }
@@ -3093,9 +3111,9 @@ function snapshotPath(snapshotsDir, identity) {
3093
3111
  }
3094
3112
  return path7.join(snapshotsDir, `${identity}.json`);
3095
3113
  }
3096
- function readUsageSnapshot(fs2, snapshotsDir, identity) {
3114
+ function readUsageSnapshot(fs3, snapshotsDir, identity) {
3097
3115
  const file = snapshotPath(snapshotsDir, identity);
3098
- const raw = fs2.readFileUtf8(file);
3116
+ const raw = fs3.readFileUtf8(file);
3099
3117
  if (raw === void 0) {
3100
3118
  return void 0;
3101
3119
  }
@@ -3111,8 +3129,8 @@ function readUsageSnapshot(fs2, snapshotsDir, identity) {
3111
3129
  }
3112
3130
  return snapshot.data;
3113
3131
  }
3114
- function listUsageSnapshots(fs2, snapshotsDir) {
3115
- return fs2.readdir(snapshotsDir).flatMap((name) => {
3132
+ function listUsageSnapshots(fs3, snapshotsDir) {
3133
+ return fs3.readdir(snapshotsDir).flatMap((name) => {
3116
3134
  if (!name.endsWith(".json")) {
3117
3135
  return [];
3118
3136
  }
@@ -3120,7 +3138,7 @@ function listUsageSnapshots(fs2, snapshotsDir) {
3120
3138
  if (!isIdentityName(identity)) {
3121
3139
  return [];
3122
3140
  }
3123
- const snapshot = readUsageSnapshot(fs2, snapshotsDir, identity);
3141
+ const snapshot = readUsageSnapshot(fs3, snapshotsDir, identity);
3124
3142
  return snapshot === void 0 ? [] : [snapshot];
3125
3143
  }).sort((left, right) => left.identity.localeCompare(right.identity));
3126
3144
  }
@@ -3287,9 +3305,9 @@ function compareVersions(a, b) {
3287
3305
  }
3288
3306
  var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
3289
3307
  async function runSupervisor(initialConfig, ports, options = {}) {
3290
- const { fs: fs2, paths } = ports;
3308
+ const { fs: fs3, paths } = ports;
3291
3309
  let config = initialConfig;
3292
- const previousState = readHeadroomState(fs2, paths.headroomStateFile);
3310
+ const previousState = readHeadroomState(fs3, paths.headroomStateFile);
3293
3311
  if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
3294
3312
  ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
3295
3313
  return 0;
@@ -3298,19 +3316,19 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3298
3316
  let lastPort = previousState?.lastPort;
3299
3317
  const sticky = () => lastPort === void 0 ? {} : { lastPort };
3300
3318
  const ownsState = () => {
3301
- const owner = readHeadroomState(fs2, paths.headroomStateFile)?.supervisorPid;
3319
+ const owner = readHeadroomState(fs3, paths.headroomStateFile)?.supervisorPid;
3302
3320
  return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
3303
3321
  };
3304
3322
  const writeOwnState = (state) => {
3305
3323
  if (!ownsState()) {
3306
3324
  return false;
3307
3325
  }
3308
- writeHeadroomState(fs2, paths.headroomStateFile, state);
3326
+ writeHeadroomState(fs3, paths.headroomStateFile, state);
3309
3327
  return true;
3310
3328
  };
3311
3329
  const fail = (message) => {
3312
3330
  if (writeOwnState({ lastError: message, ...sticky() })) {
3313
- fs2.removeRecursive(paths.headroomLockFile);
3331
+ fs3.removeRecursive(paths.headroomLockFile);
3314
3332
  }
3315
3333
  ports.log(`agent-shim headroom supervisor: ${message}`);
3316
3334
  return 1;
@@ -3359,7 +3377,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3359
3377
  const settingsHash = hashSettings(config.settings);
3360
3378
  const allowlist = allowlistOf(ports);
3361
3379
  const allowlistHash = hashAllowlist(allowlist);
3362
- pruneDeadSessions(fs2, paths.headroomSessionsDir, ports.isRunning);
3380
+ pruneDeadSessions(fs3, paths.headroomSessionsDir, ports.isRunning);
3363
3381
  const ownsNow = ownsState();
3364
3382
  if (!ownsNow && !superseded) {
3365
3383
  ports.log("agent-shim headroom supervisor: another supervisor now owns state.json; serving this daemon's own sessions until they end");
@@ -3411,7 +3429,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3411
3429
  ...sticky()
3412
3430
  });
3413
3431
  if (recorded) {
3414
- fs2.removeRecursive(paths.headroomLockFile);
3432
+ fs3.removeRecursive(paths.headroomLockFile);
3415
3433
  }
3416
3434
  idleSince = void 0;
3417
3435
  ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on 127.0.0.1:${String(port)}`);
@@ -3426,7 +3444,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3426
3444
  }
3427
3445
  } else {
3428
3446
  if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
3429
- if (sessionsForSupervisor(fs2, paths.headroomSessionsDir, ports.ownPid).length === 0) {
3447
+ if (sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid).length === 0) {
3430
3448
  ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
3431
3449
  ports.stopProcess(headroomPid);
3432
3450
  headroomPid = void 0;
@@ -3435,7 +3453,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3435
3453
  continue;
3436
3454
  }
3437
3455
  }
3438
- const sessions = sessionsForSupervisor(fs2, paths.headroomSessionsDir, ports.ownPid);
3456
+ const sessions = sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid);
3439
3457
  if (sessions.length === 0) {
3440
3458
  idleSince ??= ports.now();
3441
3459
  const idleMs = ports.now() - idleSince;
@@ -3457,9 +3475,9 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3457
3475
  await ports.sleep(HEADROOM_POLL_MS);
3458
3476
  }
3459
3477
  }
3460
- function currentHeadroomAllowlist(fs2, paths) {
3461
- const providers = readAllProviders(fs2, paths.providersDir).map((entry) => entry.provider);
3462
- return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs2, paths.frontdoorStateFile))));
3478
+ function currentHeadroomAllowlist(fs3, paths) {
3479
+ const providers = readAllProviders(fs3, paths.providersDir).map((entry) => entry.provider);
3480
+ return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs3, paths.frontdoorStateFile))));
3463
3481
  }
3464
3482
  function allowlistOf(ports) {
3465
3483
  return currentHeadroomAllowlist(ports.fs, ports.paths);
@@ -3523,17 +3541,99 @@ function evaluateAmbientCredentialGuard(params) {
3523
3541
  message: formatAmbientCredentialGuardMessage(detected.variable, params.identityName)
3524
3542
  };
3525
3543
  }
3544
+
3545
+ // src/paths.ts
3546
+ import fs2 from "node:fs";
3547
+ import os from "node:os";
3548
+ import path8 from "node:path";
3549
+ function resolveAgentShimHome(env = process.env, home = os.homedir(), isDirectory = isExistingDirectory) {
3550
+ const fromEnv = env.AGENT_SHIM_HOME;
3551
+ if (fromEnv !== void 0 && fromEnv !== "") {
3552
+ return fromEnv;
3553
+ }
3554
+ const current = path8.join(home, HOME_DIRNAME);
3555
+ const legacy = path8.join(home, LEGACY_HOME_DIRNAME);
3556
+ return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
3557
+ }
3558
+ function isExistingDirectory(candidate) {
3559
+ return fs2.statSync(candidate, { throwIfNoEntry: false })?.isDirectory() ?? false;
3560
+ }
3561
+ function resolveClaudeHome() {
3562
+ const fromEnv = process.env.AGENT_SHIM_CLAUDE_HOME;
3563
+ if (fromEnv !== void 0 && fromEnv !== "") {
3564
+ return fromEnv;
3565
+ }
3566
+ return path8.join(os.homedir(), ".claude");
3567
+ }
3568
+ function buildLayoutPaths(root) {
3569
+ return {
3570
+ root,
3571
+ identitiesDir: path8.join(root, "identities"),
3572
+ configProfilesDir: path8.join(root, "config-profiles"),
3573
+ providersDir: path8.join(root, "providers"),
3574
+ directoryRulesFile: path8.join(root, "directory-rules.json"),
3575
+ activeIdentityFile: path8.join(root, "active-identity"),
3576
+ globalConfigFile: path8.join(root, "config.json"),
3577
+ categoriesLocalFile: path8.join(root, "categories.local.json"),
3578
+ claudeShimFile: path8.join(root, "claude-shim.json"),
3579
+ headroomDir: path8.join(root, "headroom"),
3580
+ headroomStateFile: path8.join(root, "headroom", "state.json"),
3581
+ headroomLockFile: path8.join(root, "headroom", "start.lock"),
3582
+ headroomSessionsDir: path8.join(root, "headroom", "sessions"),
3583
+ logsDir: path8.join(root, "logs"),
3584
+ headroomLogPath: path8.join(root, "logs", "headroom.log"),
3585
+ frontdoorDir: path8.join(root, "frontdoor"),
3586
+ frontdoorCaDir: path8.join(root, "frontdoor", "ca"),
3587
+ frontdoorCaCertFile: path8.join(root, "frontdoor", "ca", "ca.pem"),
3588
+ frontdoorCaKeyFile: path8.join(root, "frontdoor", "ca", "ca.key"),
3589
+ frontdoorCaBundlesDir: path8.join(root, "frontdoor", "ca", "bundles"),
3590
+ frontdoorStateFile: path8.join(root, "frontdoor", "state.json"),
3591
+ frontdoorLockFile: path8.join(root, "frontdoor", "start.lock"),
3592
+ frontdoorSessionsDir: path8.join(root, "frontdoor", "sessions"),
3593
+ frontdoorLogPath: path8.join(root, "logs", "frontdoor.log"),
3594
+ usageDir: path8.join(root, "usage"),
3595
+ usageLogDir: path8.join(root, "usage", "log"),
3596
+ usageSnapshotsDir: path8.join(root, "usage", "snapshots"),
3597
+ usagePicksFile: path8.join(root, "usage", "picks.json")
3598
+ };
3599
+ }
3600
+ function resolveLayoutPaths() {
3601
+ return buildLayoutPaths(resolveAgentShimHome());
3602
+ }
3526
3603
  export {
3527
3604
  AMBIENT_CREDENTIAL_VARS,
3528
3605
  CONNECT_INTERCEPT_HOST,
3606
+ CONNECT_INTERCEPT_HOSTS,
3529
3607
  CONNECT_LIMITS,
3608
+ CategoryClassificationOverlaySchema,
3609
+ CategoryClassificationSchema,
3610
+ CategoryMapSchema,
3611
+ CliError,
3612
+ ConfigProfileSchema,
3613
+ CredentialCacheSchema,
3614
+ CredentialSchema,
3615
+ CredentialSourceSchema,
3616
+ DirectoryRuleSchema,
3617
+ DirectoryRulesSchema,
3618
+ EXIT_FAILURE,
3619
+ EXIT_USAGE,
3620
+ EntryValueSchema,
3530
3621
  FARM_MANIFEST_FILENAME,
3531
3622
  FrontDoorStartError,
3623
+ GlobalConfigSchema,
3532
3624
  HeadroomStartError,
3625
+ IdentitySchema,
3626
+ PoolNameSchema,
3627
+ PoolSchema,
3628
+ PortableConfigSchema,
3629
+ ProviderSchema,
3533
3630
  ROUTED_PATH_PREFIX,
3631
+ UsageError,
3534
3632
  UsageSnapshotError,
3535
3633
  UsageSnapshotSchema,
3634
+ WhenSchema,
3536
3635
  buildEntryFacts,
3636
+ buildLayoutPaths,
3537
3637
  carryOver,
3538
3638
  createLeafCache,
3539
3639
  detectAmbientCredential,
@@ -3554,7 +3654,10 @@ export {
3554
3654
  realConnectEffects,
3555
3655
  recoverFarm,
3556
3656
  recoveryDiagnostics,
3657
+ resolveAgentShimHome,
3658
+ resolveClaudeHome,
3557
3659
  resolveDecisions,
3660
+ resolveLayoutPaths,
3558
3661
  resolveSupervisorConfig,
3559
3662
  resyncFarm,
3560
3663
  runFrontDoorSupervisor,
@@ -427,7 +427,7 @@ export declare const POOL_SELECTOR_PREFIX = "pool:";
427
427
  /** A pool's own name: the identity alphabet minus `@`, since a pool is never an email address. */
428
428
  export declare const PoolNameSchema: z.ZodString;
429
429
  /** A named, explicit set of identities to choose among at launch. Never implicit: a pool lists its members, so an identity that bills a client is only ever picked when someone put it there. */
430
- declare const PoolSchema: z.ZodObject<{
430
+ export declare const PoolSchema: z.ZodObject<{
431
431
  identities: z.ZodArray<z.ZodString>;
432
432
  }, z.core.$strict>;
433
433
  export type Pool = z.infer<typeof PoolSchema>;