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.cjs CHANGED
@@ -32,14 +32,37 @@ var index_exports = {};
32
32
  __export(index_exports, {
33
33
  AMBIENT_CREDENTIAL_VARS: () => AMBIENT_CREDENTIAL_VARS,
34
34
  CONNECT_INTERCEPT_HOST: () => CONNECT_INTERCEPT_HOST,
35
+ CONNECT_INTERCEPT_HOSTS: () => CONNECT_INTERCEPT_HOSTS,
35
36
  CONNECT_LIMITS: () => CONNECT_LIMITS,
37
+ CategoryClassificationOverlaySchema: () => CategoryClassificationOverlaySchema,
38
+ CategoryClassificationSchema: () => CategoryClassificationSchema,
39
+ CategoryMapSchema: () => CategoryMapSchema,
40
+ CliError: () => CliError,
41
+ ConfigProfileSchema: () => ConfigProfileSchema,
42
+ CredentialCacheSchema: () => CredentialCacheSchema,
43
+ CredentialSchema: () => CredentialSchema,
44
+ CredentialSourceSchema: () => CredentialSourceSchema,
45
+ DirectoryRuleSchema: () => DirectoryRuleSchema,
46
+ DirectoryRulesSchema: () => DirectoryRulesSchema,
47
+ EXIT_FAILURE: () => EXIT_FAILURE,
48
+ EXIT_USAGE: () => EXIT_USAGE,
49
+ EntryValueSchema: () => EntryValueSchema,
36
50
  FARM_MANIFEST_FILENAME: () => FARM_MANIFEST_FILENAME,
37
51
  FrontDoorStartError: () => FrontDoorStartError,
52
+ GlobalConfigSchema: () => GlobalConfigSchema,
38
53
  HeadroomStartError: () => HeadroomStartError,
54
+ IdentitySchema: () => IdentitySchema,
55
+ PoolNameSchema: () => PoolNameSchema,
56
+ PoolSchema: () => PoolSchema,
57
+ PortableConfigSchema: () => PortableConfigSchema,
58
+ ProviderSchema: () => ProviderSchema,
39
59
  ROUTED_PATH_PREFIX: () => ROUTED_PATH_PREFIX,
60
+ UsageError: () => UsageError,
40
61
  UsageSnapshotError: () => UsageSnapshotError,
41
62
  UsageSnapshotSchema: () => UsageSnapshotSchema,
63
+ WhenSchema: () => WhenSchema,
42
64
  buildEntryFacts: () => buildEntryFacts,
65
+ buildLayoutPaths: () => buildLayoutPaths,
43
66
  carryOver: () => carryOver,
44
67
  createLeafCache: () => createLeafCache,
45
68
  detectAmbientCredential: () => detectAmbientCredential,
@@ -60,7 +83,10 @@ __export(index_exports, {
60
83
  realConnectEffects: () => realConnectEffects,
61
84
  recoverFarm: () => recoverFarm,
62
85
  recoveryDiagnostics: () => recoveryDiagnostics,
86
+ resolveAgentShimHome: () => resolveAgentShimHome,
87
+ resolveClaudeHome: () => resolveClaudeHome,
63
88
  resolveDecisions: () => resolveDecisions,
89
+ resolveLayoutPaths: () => resolveLayoutPaths,
64
90
  resolveSupervisorConfig: () => resolveSupervisorConfig,
65
91
  resyncFarm: () => resyncFarm,
66
92
  runFrontDoorSupervisor: () => runFrontDoorSupervisor,
@@ -322,10 +348,18 @@ var import_cosmiconfig = require("cosmiconfig");
322
348
 
323
349
  // src/cliError.ts
324
350
  var EXIT_FAILURE = 1;
351
+ var EXIT_USAGE = 2;
325
352
  var CliError = class extends Error {
326
353
  /** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
327
354
  exitCode = EXIT_FAILURE;
328
355
  };
356
+ var UsageError = class extends CliError {
357
+ exitCode = EXIT_USAGE;
358
+ constructor(message) {
359
+ super(message);
360
+ this.name = "UsageError";
361
+ }
362
+ };
329
363
 
330
364
  // src/config/classify.ts
331
365
  var GLOB_METACHARACTERS = /[*?[\]{}!()]/;
@@ -1286,6 +1320,8 @@ function planReconciliation(params) {
1286
1320
  }
1287
1321
 
1288
1322
  // src/legacy.ts
1323
+ var HOME_DIRNAME = ".agent-shim";
1324
+ var LEGACY_HOME_DIRNAME = ".claude-use";
1289
1325
  var LEGACY_FARM_MANIFEST_FILENAME = ".claude-use-farm.json";
1290
1326
 
1291
1327
  // src/launcher/lock.ts
@@ -1387,8 +1423,8 @@ var FarmManifestSchema = import_zod2.z.strictObject({
1387
1423
  materialised: import_zod2.z.array(import_zod2.z.string()),
1388
1424
  links: import_zod2.z.array(import_zod2.z.strictObject({ rel: import_zod2.z.string(), target: import_zod2.z.string() }))
1389
1425
  });
1390
- function readFarmManifest(fs2, farmRoot) {
1391
- const raw = fs2.readFileUtf8(import_node_path4.default.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs2.readFileUtf8(import_node_path4.default.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1426
+ function readFarmManifest(fs3, farmRoot) {
1427
+ const raw = fs3.readFileUtf8(import_node_path4.default.join(farmRoot, FARM_MANIFEST_FILENAME)) ?? fs3.readFileUtf8(import_node_path4.default.join(farmRoot, LEGACY_FARM_MANIFEST_FILENAME));
1392
1428
  if (raw === void 0) {
1393
1429
  return void 0;
1394
1430
  }
@@ -1446,9 +1482,9 @@ function buildEntryFacts(params) {
1446
1482
  entries
1447
1483
  };
1448
1484
  }
1449
- function listSubtree(fs2, root, rel) {
1485
+ function listSubtree(fs3, root, rel) {
1450
1486
  const absolute = import_node_path4.default.join(root, rel);
1451
- const stat = fs2.lstat(absolute);
1487
+ const stat = fs3.lstat(absolute);
1452
1488
  if (stat === void 0) {
1453
1489
  return [];
1454
1490
  }
@@ -1456,10 +1492,10 @@ function listSubtree(fs2, root, rel) {
1456
1492
  return [{ rel, kind: "symlink" }];
1457
1493
  }
1458
1494
  if (stat.kind === "dir") {
1459
- const children = [...fs2.readdir(absolute)].sort().flatMap((name) => listSubtree(fs2, root, `${rel}/${name}`));
1495
+ const children = [...fs3.readdir(absolute)].sort().flatMap((name) => listSubtree(fs3, root, `${rel}/${name}`));
1460
1496
  return [{ rel, kind: "dir" }, ...children];
1461
1497
  }
1462
- const contentHash = fs2.hashFile(absolute);
1498
+ const contentHash = fs3.hashFile(absolute);
1463
1499
  return [{ rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } }];
1464
1500
  }
1465
1501
  function topLevelScopeRoots(roots) {
@@ -1473,25 +1509,25 @@ function topLevelScopeRoots(roots) {
1473
1509
  }
1474
1510
  return kept;
1475
1511
  }
1476
- function reconciliationScope(fs2, farmRoot, manifest) {
1512
+ function reconciliationScope(fs3, farmRoot, manifest) {
1477
1513
  if (manifest !== void 0) {
1478
1514
  return topLevelScopeRoots(manifest.materialised);
1479
1515
  }
1480
- return [...fs2.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs2.lstat(import_node_path4.default.join(farmRoot, name))?.kind === "dir").sort();
1516
+ return [...fs3.readdir(farmRoot)].filter((name) => name !== FARM_MANIFEST_FILENAME && name !== LEGACY_FARM_MANIFEST_FILENAME && fs3.lstat(import_node_path4.default.join(farmRoot, name))?.kind === "dir").sort();
1481
1517
  }
1482
- function collectFarmListing(fs2, farmRoot, scopeRoots) {
1483
- return scopeRoots.flatMap((root) => listSubtree(fs2, farmRoot, root));
1518
+ function collectFarmListing(fs3, farmRoot, scopeRoots) {
1519
+ return scopeRoots.flatMap((root) => listSubtree(fs3, farmRoot, root));
1484
1520
  }
1485
- function collectCanonicalCounterparts(fs2, claudeHome, farmListing) {
1521
+ function collectCanonicalCounterparts(fs3, claudeHome, farmListing) {
1486
1522
  const out = [];
1487
1523
  for (const entry of farmListing) {
1488
1524
  const absolute = import_node_path4.default.join(claudeHome, entry.rel);
1489
- const stat = fs2.lstat(absolute);
1525
+ const stat = fs3.lstat(absolute);
1490
1526
  if (stat === void 0) {
1491
1527
  continue;
1492
1528
  }
1493
1529
  if (stat.kind === "file") {
1494
- const contentHash = fs2.hashFile(absolute);
1530
+ const contentHash = fs3.hashFile(absolute);
1495
1531
  out.push({ rel: entry.rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } });
1496
1532
  continue;
1497
1533
  }
@@ -2175,10 +2211,10 @@ var FrontDoorStateSchema = import_zod3.z.strictObject({
2175
2211
  /** The last fatal error, kept across shutdowns so `frontdoor status` can explain a front door that is not running. */
2176
2212
  lastError: import_zod3.z.string().optional()
2177
2213
  });
2178
- function readFrontDoorState(fs2, stateFile) {
2214
+ function readFrontDoorState(fs3, stateFile) {
2179
2215
  let raw;
2180
2216
  try {
2181
- raw = fs2.readFileUtf8(stateFile);
2217
+ raw = fs3.readFileUtf8(stateFile);
2182
2218
  } catch {
2183
2219
  return void 0;
2184
2220
  }
@@ -2192,28 +2228,28 @@ function readFrontDoorState(fs2, stateFile) {
2192
2228
  return void 0;
2193
2229
  }
2194
2230
  }
2195
- function writeFrontDoorState(fs2, stateFile, state) {
2196
- fs2.mkdirp(import_node_path5.default.dirname(stateFile));
2197
- fs2.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
2231
+ function writeFrontDoorState(fs3, stateFile, state) {
2232
+ fs3.mkdirp(import_node_path5.default.dirname(stateFile));
2233
+ fs3.writeFileUtf8(stateFile, `${JSON.stringify(state, null, 2)}
2198
2234
  `);
2199
2235
  }
2200
2236
  function frontDoorOrigin(state) {
2201
2237
  const port = state?.directPort ?? state?.lastDirectPort;
2202
2238
  return port === void 0 ? void 0 : `http://127.0.0.1:${String(port)}`;
2203
2239
  }
2204
- function writeFrontDoorSession(fs2, sessionsDir, session) {
2205
- fs2.mkdirPrivate(sessionsDir);
2206
- fs2.writeFilePrivate(import_node_path5.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2240
+ function writeFrontDoorSession(fs3, sessionsDir, session) {
2241
+ fs3.mkdirPrivate(sessionsDir);
2242
+ fs3.writeFilePrivate(import_node_path5.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2207
2243
  `);
2208
2244
  }
2209
- function listFrontDoorSessions(fs2, sessionsDir) {
2245
+ function listFrontDoorSessions(fs3, sessionsDir) {
2210
2246
  const sessions = [];
2211
- for (const name of fs2.readdir(sessionsDir)) {
2247
+ for (const name of fs3.readdir(sessionsDir)) {
2212
2248
  if (!name.endsWith(".json")) {
2213
2249
  continue;
2214
2250
  }
2215
2251
  try {
2216
- const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs2.readFileUtf8(import_node_path5.default.join(sessionsDir, name)) ?? ""));
2252
+ const parsed = FrontDoorSessionSchema.safeParse(JSON.parse(fs3.readFileUtf8(import_node_path5.default.join(sessionsDir, name)) ?? ""));
2217
2253
  if (parsed.success) {
2218
2254
  sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
2219
2255
  }
@@ -2223,14 +2259,14 @@ function listFrontDoorSessions(fs2, sessionsDir) {
2223
2259
  }
2224
2260
  return sessions.sort((a, b) => a.pid - b.pid);
2225
2261
  }
2226
- function removeFrontDoorSession(fs2, sessionsDir, pid) {
2227
- fs2.removeRecursive(import_node_path5.default.join(sessionsDir, `${String(pid)}.json`));
2262
+ function removeFrontDoorSession(fs3, sessionsDir, pid) {
2263
+ fs3.removeRecursive(import_node_path5.default.join(sessionsDir, `${String(pid)}.json`));
2228
2264
  }
2229
- function pruneDeadFrontDoorSessions(fs2, sessionsDir, isRunning) {
2265
+ function pruneDeadFrontDoorSessions(fs3, sessionsDir, isRunning) {
2230
2266
  const removed = [];
2231
- for (const session of listFrontDoorSessions(fs2, sessionsDir)) {
2267
+ for (const session of listFrontDoorSessions(fs3, sessionsDir)) {
2232
2268
  if (!isRunning(session.pid)) {
2233
- removeFrontDoorSession(fs2, sessionsDir, session.pid);
2269
+ removeFrontDoorSession(fs3, sessionsDir, session.pid);
2234
2270
  removed.push(session.pid);
2235
2271
  }
2236
2272
  }
@@ -2242,8 +2278,8 @@ var FRONTDOOR_SUPERVISOR_STILL_RUNNING = -1;
2242
2278
  var FRONTDOOR_POLL_MS = 1e3;
2243
2279
  var MS_PER_MINUTE = 6e4;
2244
2280
  async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {}) {
2245
- const { fs: fs2, paths } = ports;
2246
- const previous = readFrontDoorState(fs2, paths.frontdoorStateFile);
2281
+ const { fs: fs3, paths } = ports;
2282
+ const previous = readFrontDoorState(fs3, paths.frontdoorStateFile);
2247
2283
  let lastPort = previous?.lastPort;
2248
2284
  let lastConnectPort = previous?.lastConnectPort;
2249
2285
  let lastDirectPort = previous?.lastDirectPort;
@@ -2253,12 +2289,12 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2253
2289
  ...lastDirectPort === void 0 ? {} : { lastDirectPort }
2254
2290
  });
2255
2291
  const fail = (message) => {
2256
- writeFrontDoorState(fs2, paths.frontdoorStateFile, { lastError: message, ...sticky() });
2257
- fs2.removeRecursive(paths.frontdoorLockFile);
2292
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, { lastError: message, ...sticky() });
2293
+ fs3.removeRecursive(paths.frontdoorLockFile);
2258
2294
  ports.log(`agent-shim frontdoor supervisor: ${message}`);
2259
2295
  return 1;
2260
2296
  };
2261
- writeFrontDoorState(fs2, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
2297
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
2262
2298
  const previousSticky = lastPort;
2263
2299
  let http2;
2264
2300
  try {
@@ -2295,8 +2331,8 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2295
2331
  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)`);
2296
2332
  }
2297
2333
  lastDirectPort = direct.port;
2298
- writeFrontDoorState(fs2, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http2.port, connectPort: connect2.port, directPort: direct.port, ...sticky() });
2299
- fs2.removeRecursive(paths.frontdoorLockFile);
2334
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http2.port, connectPort: connect2.port, directPort: direct.port, ...sticky() });
2335
+ fs3.removeRecursive(paths.frontdoorLockFile);
2300
2336
  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)}`);
2301
2337
  let idleSince;
2302
2338
  let ticks = 0;
@@ -2305,15 +2341,15 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2305
2341
  return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
2306
2342
  }
2307
2343
  ticks += 1;
2308
- pruneDeadFrontDoorSessions(fs2, paths.frontdoorSessionsDir, ports.isRunning);
2309
- if (listFrontDoorSessions(fs2, paths.frontdoorSessionsDir).length === 0) {
2344
+ pruneDeadFrontDoorSessions(fs3, paths.frontdoorSessionsDir, ports.isRunning);
2345
+ if (listFrontDoorSessions(fs3, paths.frontdoorSessionsDir).length === 0) {
2310
2346
  idleSince ??= ports.now();
2311
2347
  if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE) {
2312
2348
  ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
2313
2349
  await direct.close();
2314
2350
  await connect2.close();
2315
2351
  await http2.close();
2316
- writeFrontDoorState(fs2, paths.frontdoorStateFile, sticky());
2352
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, sticky());
2317
2353
  return 0;
2318
2354
  }
2319
2355
  } else {
@@ -2325,6 +2361,7 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2325
2361
 
2326
2362
  // src/frontdoor/connect.ts
2327
2363
  var CONNECT_INTERCEPT_HOST = "api.anthropic.com";
2364
+ var CONNECT_INTERCEPT_HOSTS = [CONNECT_INTERCEPT_HOST, "platform.claude.com"];
2328
2365
  var ROUTED_PATH_PREFIX = "/v1/";
2329
2366
  var HTTPS_PORT = 443;
2330
2367
  var MAX_PORT = 65535;
@@ -2364,11 +2401,11 @@ function parseConnectTarget(authority) {
2364
2401
  }
2365
2402
  return { host, port };
2366
2403
  }
2367
- function isInterceptedHost(host, interceptHost) {
2368
- return host === interceptHost;
2404
+ function isInterceptedHost(host, interceptHosts) {
2405
+ return interceptHosts.includes(host);
2369
2406
  }
2370
- function servedByPipeline(path8) {
2371
- return path8?.startsWith(ROUTED_PATH_PREFIX) === true;
2407
+ function servedByPipeline(path9) {
2408
+ return path9?.startsWith(ROUTED_PATH_PREFIX) === true;
2372
2409
  }
2373
2410
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
2374
2411
  "connection",
@@ -2435,28 +2472,34 @@ function caParses(ca) {
2435
2472
  }
2436
2473
  }
2437
2474
  async function startConnectServer(config, effects, preferredPort) {
2438
- const handler = (request3, response) => {
2439
- if (servedByPipeline(request3.url)) {
2440
- config.serveRouted(request3, response);
2441
- return;
2442
- }
2443
- effects.forwardHttp(config.upstream, request3, response, config.capture?.observePassthrough(request3));
2444
- };
2445
- const httpSession = effects.createHttpSession(handler, config.capture === void 0 ? void 0 : (request3) => config.capture?.upgrade(request3));
2446
- const tlsAcceptor = effects.createTlsAcceptor(config.leafFor(config.interceptHost), (secure) => {
2447
- httpSession.serve(secure);
2475
+ const onUpgrade = config.capture === void 0 ? void 0 : (request3) => config.capture?.upgrade(request3);
2476
+ const sessions = config.interceptHosts.map((host) => {
2477
+ const handler = (request3, response) => {
2478
+ if (host === config.routedHost && servedByPipeline(request3.url)) {
2479
+ config.serveRouted(request3, response);
2480
+ return;
2481
+ }
2482
+ effects.forwardHttp(config.upstreamFor(host), request3, response, config.capture?.observePassthrough(request3));
2483
+ };
2484
+ const httpSession = effects.createHttpSession(handler, onUpgrade);
2485
+ const tlsAcceptor = effects.createTlsAcceptor(config.leafFor(host), (secure) => {
2486
+ httpSession.serve(secure);
2487
+ });
2488
+ return { host, httpSession, tlsAcceptor };
2448
2489
  });
2449
2490
  const ledger = createConnectionLedger(config.limits, config.isLiveCapability);
2450
2491
  const listener = await effects.listenLoopback(preferredPort, (socket) => {
2451
- handleConnect(socket, { config, effects, tlsAcceptor, ledger });
2492
+ handleConnect(socket, { config, effects, sessions, ledger });
2452
2493
  });
2453
2494
  return {
2454
2495
  port: listener.port,
2455
2496
  close: async () => {
2456
2497
  ledger.close();
2457
2498
  await listener.close();
2458
- tlsAcceptor.close();
2459
- httpSession.close();
2499
+ for (const { httpSession, tlsAcceptor } of sessions) {
2500
+ tlsAcceptor.close();
2501
+ httpSession.close();
2502
+ }
2460
2503
  }
2461
2504
  };
2462
2505
  }
@@ -2576,7 +2619,7 @@ function proxyAuthorizationOf(head) {
2576
2619
  return values.length === 1 ? value : void 0;
2577
2620
  }
2578
2621
  function routeConnect(socket, head, context) {
2579
- const { config, effects, tlsAcceptor, ledger } = context;
2622
+ const { config, effects, sessions, ledger } = context;
2580
2623
  const credential = proxyAuthorizationOf(head);
2581
2624
  const capability = credential === void 0 ? void 0 : capabilityFromProxyAuthorization(credential);
2582
2625
  if (capability === void 0 || !config.isLiveCapability(capability)) {
@@ -2595,10 +2638,11 @@ function routeConnect(socket, head, context) {
2595
2638
  refuse(socket, REFUSAL.serviceUnavailable);
2596
2639
  return;
2597
2640
  }
2598
- config.capture?.connect(target, isInterceptedHost(target.host, config.interceptHost));
2641
+ const session = sessions.find((entry) => entry.host === target.host);
2642
+ config.capture?.connect(target, session !== void 0);
2599
2643
  socket.write(CONNECT_ESTABLISHED);
2600
- if (isInterceptedHost(target.host, config.interceptHost)) {
2601
- tlsAcceptor.accept(socket);
2644
+ if (session !== void 0) {
2645
+ session.tlsAcceptor.accept(socket);
2602
2646
  return;
2603
2647
  }
2604
2648
  void blindTunnel(socket, target, effects);
@@ -2844,16 +2888,16 @@ function parseJson(raw, schema) {
2844
2888
  const parsed = schema.safeParse(JSON.parse(raw));
2845
2889
  return parsed.success ? parsed.data : void 0;
2846
2890
  }
2847
- function readHeadroomState(fs2, stateFile) {
2891
+ function readHeadroomState(fs3, stateFile) {
2848
2892
  try {
2849
- return parseJson(fs2.readFileUtf8(stateFile), HeadroomStateSchema);
2893
+ return parseJson(fs3.readFileUtf8(stateFile), HeadroomStateSchema);
2850
2894
  } catch {
2851
2895
  return void 0;
2852
2896
  }
2853
2897
  }
2854
- function writeHeadroomState(fs2, stateFile, state) {
2855
- fs2.mkdirp(import_node_path6.default.dirname(stateFile));
2856
- fs2.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
2898
+ function writeHeadroomState(fs3, stateFile, state) {
2899
+ fs3.mkdirp(import_node_path6.default.dirname(stateFile));
2900
+ fs3.writeFilePrivate(stateFile, `${JSON.stringify(state, null, 2)}
2857
2901
  `);
2858
2902
  }
2859
2903
  function headroomAllowlist(providers) {
@@ -2873,14 +2917,14 @@ function headroomUpstreams(providers, frontDoorOrigin2) {
2873
2917
  function hashAllowlist(allowlist) {
2874
2918
  return (0, import_node_crypto4.createHash)("sha256").update(allowlist.join("\n")).digest("hex");
2875
2919
  }
2876
- function readAllProviders(fs2, providersDir) {
2920
+ function readAllProviders(fs3, providersDir) {
2877
2921
  const result = [];
2878
- for (const name of fs2.readdir(providersDir)) {
2922
+ for (const name of fs3.readdir(providersDir)) {
2879
2923
  if (!name.endsWith(".json")) {
2880
2924
  continue;
2881
2925
  }
2882
2926
  try {
2883
- const parsed = parseJson(fs2.readFileUtf8(import_node_path6.default.join(providersDir, name)), ProviderSchema);
2927
+ const parsed = parseJson(fs3.readFileUtf8(import_node_path6.default.join(providersDir, name)), ProviderSchema);
2884
2928
  if (parsed !== void 0) {
2885
2929
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
2886
2930
  }
@@ -2890,22 +2934,22 @@ function readAllProviders(fs2, providersDir) {
2890
2934
  }
2891
2935
  return result;
2892
2936
  }
2893
- function writeSession(fs2, sessionsDir, session) {
2894
- fs2.mkdirp(sessionsDir);
2895
- fs2.writeFileUtf8(import_node_path6.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2937
+ function writeSession(fs3, sessionsDir, session) {
2938
+ fs3.mkdirp(sessionsDir);
2939
+ fs3.writeFileUtf8(import_node_path6.default.join(sessionsDir, `${String(session.pid)}.json`), `${JSON.stringify(session, null, 2)}
2896
2940
  `);
2897
2941
  }
2898
- function removeSession(fs2, sessionsDir, pid) {
2899
- fs2.removeRecursive(import_node_path6.default.join(sessionsDir, `${String(pid)}.json`));
2942
+ function removeSession(fs3, sessionsDir, pid) {
2943
+ fs3.removeRecursive(import_node_path6.default.join(sessionsDir, `${String(pid)}.json`));
2900
2944
  }
2901
- function listSessions(fs2, sessionsDir) {
2945
+ function listSessions(fs3, sessionsDir) {
2902
2946
  const sessions = [];
2903
- for (const name of fs2.readdir(sessionsDir)) {
2947
+ for (const name of fs3.readdir(sessionsDir)) {
2904
2948
  if (!name.endsWith(".json")) {
2905
2949
  continue;
2906
2950
  }
2907
2951
  try {
2908
- const parsed = parseJson(fs2.readFileUtf8(import_node_path6.default.join(sessionsDir, name)), HeadroomSessionSchema);
2952
+ const parsed = parseJson(fs3.readFileUtf8(import_node_path6.default.join(sessionsDir, name)), HeadroomSessionSchema);
2909
2953
  if (parsed !== void 0) {
2910
2954
  sessions.push(parsed);
2911
2955
  }
@@ -2915,22 +2959,22 @@ function listSessions(fs2, sessionsDir) {
2915
2959
  }
2916
2960
  return sessions.sort((a, b) => a.pid - b.pid);
2917
2961
  }
2918
- function sessionsForSupervisor(fs2, sessionsDir, supervisorPid) {
2919
- return listSessions(fs2, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
2962
+ function sessionsForSupervisor(fs3, sessionsDir, supervisorPid) {
2963
+ return listSessions(fs3, sessionsDir).filter((session) => session.supervisorPid === supervisorPid);
2920
2964
  }
2921
- function pruneDeadSessions(fs2, sessionsDir, isRunning) {
2965
+ function pruneDeadSessions(fs3, sessionsDir, isRunning) {
2922
2966
  const removed = [];
2923
- for (const session of listSessions(fs2, sessionsDir)) {
2967
+ for (const session of listSessions(fs3, sessionsDir)) {
2924
2968
  if (!isRunning(session.pid)) {
2925
- removeSession(fs2, sessionsDir, session.pid);
2969
+ removeSession(fs3, sessionsDir, session.pid);
2926
2970
  removed.push(session.pid);
2927
2971
  }
2928
2972
  }
2929
2973
  return removed;
2930
2974
  }
2931
- function readStartLock(fs2, lockFile) {
2975
+ function readStartLock(fs3, lockFile) {
2932
2976
  try {
2933
- return parseJson(fs2.readFileUtf8(lockFile), HeadroomLockSchema);
2977
+ return parseJson(fs3.readFileUtf8(lockFile), HeadroomLockSchema);
2934
2978
  } catch {
2935
2979
  return void 0;
2936
2980
  }
@@ -3167,9 +3211,9 @@ function snapshotPath(snapshotsDir, identity) {
3167
3211
  }
3168
3212
  return import_node_path7.default.join(snapshotsDir, `${identity}.json`);
3169
3213
  }
3170
- function readUsageSnapshot(fs2, snapshotsDir, identity) {
3214
+ function readUsageSnapshot(fs3, snapshotsDir, identity) {
3171
3215
  const file = snapshotPath(snapshotsDir, identity);
3172
- const raw = fs2.readFileUtf8(file);
3216
+ const raw = fs3.readFileUtf8(file);
3173
3217
  if (raw === void 0) {
3174
3218
  return void 0;
3175
3219
  }
@@ -3185,8 +3229,8 @@ function readUsageSnapshot(fs2, snapshotsDir, identity) {
3185
3229
  }
3186
3230
  return snapshot.data;
3187
3231
  }
3188
- function listUsageSnapshots(fs2, snapshotsDir) {
3189
- return fs2.readdir(snapshotsDir).flatMap((name) => {
3232
+ function listUsageSnapshots(fs3, snapshotsDir) {
3233
+ return fs3.readdir(snapshotsDir).flatMap((name) => {
3190
3234
  if (!name.endsWith(".json")) {
3191
3235
  return [];
3192
3236
  }
@@ -3194,7 +3238,7 @@ function listUsageSnapshots(fs2, snapshotsDir) {
3194
3238
  if (!isIdentityName(identity)) {
3195
3239
  return [];
3196
3240
  }
3197
- const snapshot = readUsageSnapshot(fs2, snapshotsDir, identity);
3241
+ const snapshot = readUsageSnapshot(fs3, snapshotsDir, identity);
3198
3242
  return snapshot === void 0 ? [] : [snapshot];
3199
3243
  }).sort((left, right) => left.identity.localeCompare(right.identity));
3200
3244
  }
@@ -3361,9 +3405,9 @@ function compareVersions(a, b) {
3361
3405
  }
3362
3406
  var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
3363
3407
  async function runSupervisor(initialConfig, ports, options = {}) {
3364
- const { fs: fs2, paths } = ports;
3408
+ const { fs: fs3, paths } = ports;
3365
3409
  let config = initialConfig;
3366
- const previousState = readHeadroomState(fs2, paths.headroomStateFile);
3410
+ const previousState = readHeadroomState(fs3, paths.headroomStateFile);
3367
3411
  if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
3368
3412
  ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
3369
3413
  return 0;
@@ -3372,19 +3416,19 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3372
3416
  let lastPort = previousState?.lastPort;
3373
3417
  const sticky = () => lastPort === void 0 ? {} : { lastPort };
3374
3418
  const ownsState = () => {
3375
- const owner = readHeadroomState(fs2, paths.headroomStateFile)?.supervisorPid;
3419
+ const owner = readHeadroomState(fs3, paths.headroomStateFile)?.supervisorPid;
3376
3420
  return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
3377
3421
  };
3378
3422
  const writeOwnState = (state) => {
3379
3423
  if (!ownsState()) {
3380
3424
  return false;
3381
3425
  }
3382
- writeHeadroomState(fs2, paths.headroomStateFile, state);
3426
+ writeHeadroomState(fs3, paths.headroomStateFile, state);
3383
3427
  return true;
3384
3428
  };
3385
3429
  const fail = (message) => {
3386
3430
  if (writeOwnState({ lastError: message, ...sticky() })) {
3387
- fs2.removeRecursive(paths.headroomLockFile);
3431
+ fs3.removeRecursive(paths.headroomLockFile);
3388
3432
  }
3389
3433
  ports.log(`agent-shim headroom supervisor: ${message}`);
3390
3434
  return 1;
@@ -3433,7 +3477,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3433
3477
  const settingsHash = hashSettings(config.settings);
3434
3478
  const allowlist = allowlistOf(ports);
3435
3479
  const allowlistHash = hashAllowlist(allowlist);
3436
- pruneDeadSessions(fs2, paths.headroomSessionsDir, ports.isRunning);
3480
+ pruneDeadSessions(fs3, paths.headroomSessionsDir, ports.isRunning);
3437
3481
  const ownsNow = ownsState();
3438
3482
  if (!ownsNow && !superseded) {
3439
3483
  ports.log("agent-shim headroom supervisor: another supervisor now owns state.json; serving this daemon's own sessions until they end");
@@ -3485,7 +3529,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3485
3529
  ...sticky()
3486
3530
  });
3487
3531
  if (recorded) {
3488
- fs2.removeRecursive(paths.headroomLockFile);
3532
+ fs3.removeRecursive(paths.headroomLockFile);
3489
3533
  }
3490
3534
  idleSince = void 0;
3491
3535
  ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on 127.0.0.1:${String(port)}`);
@@ -3500,7 +3544,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3500
3544
  }
3501
3545
  } else {
3502
3546
  if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
3503
- if (sessionsForSupervisor(fs2, paths.headroomSessionsDir, ports.ownPid).length === 0) {
3547
+ if (sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid).length === 0) {
3504
3548
  ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
3505
3549
  ports.stopProcess(headroomPid);
3506
3550
  headroomPid = void 0;
@@ -3509,7 +3553,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3509
3553
  continue;
3510
3554
  }
3511
3555
  }
3512
- const sessions = sessionsForSupervisor(fs2, paths.headroomSessionsDir, ports.ownPid);
3556
+ const sessions = sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid);
3513
3557
  if (sessions.length === 0) {
3514
3558
  idleSince ??= ports.now();
3515
3559
  const idleMs = ports.now() - idleSince;
@@ -3531,9 +3575,9 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3531
3575
  await ports.sleep(HEADROOM_POLL_MS);
3532
3576
  }
3533
3577
  }
3534
- function currentHeadroomAllowlist(fs2, paths) {
3535
- const providers = readAllProviders(fs2, paths.providersDir).map((entry) => entry.provider);
3536
- return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs2, paths.frontdoorStateFile))));
3578
+ function currentHeadroomAllowlist(fs3, paths) {
3579
+ const providers = readAllProviders(fs3, paths.providersDir).map((entry) => entry.provider);
3580
+ return headroomAllowlist(headroomUpstreams(providers, frontDoorOrigin(readFrontDoorState(fs3, paths.frontdoorStateFile))));
3537
3581
  }
3538
3582
  function allowlistOf(ports) {
3539
3583
  return currentHeadroomAllowlist(ports.fs, ports.paths);
@@ -3597,18 +3641,100 @@ function evaluateAmbientCredentialGuard(params) {
3597
3641
  message: formatAmbientCredentialGuardMessage(detected.variable, params.identityName)
3598
3642
  };
3599
3643
  }
3644
+
3645
+ // src/paths.ts
3646
+ var import_node_fs = __toESM(require("node:fs"), 1);
3647
+ var import_node_os = __toESM(require("node:os"), 1);
3648
+ var import_node_path8 = __toESM(require("node:path"), 1);
3649
+ function resolveAgentShimHome(env = process.env, home = import_node_os.default.homedir(), isDirectory = isExistingDirectory) {
3650
+ const fromEnv = env.AGENT_SHIM_HOME;
3651
+ if (fromEnv !== void 0 && fromEnv !== "") {
3652
+ return fromEnv;
3653
+ }
3654
+ const current = import_node_path8.default.join(home, HOME_DIRNAME);
3655
+ const legacy = import_node_path8.default.join(home, LEGACY_HOME_DIRNAME);
3656
+ return !isDirectory(current) && isDirectory(legacy) ? legacy : current;
3657
+ }
3658
+ function isExistingDirectory(candidate) {
3659
+ return import_node_fs.default.statSync(candidate, { throwIfNoEntry: false })?.isDirectory() ?? false;
3660
+ }
3661
+ function resolveClaudeHome() {
3662
+ const fromEnv = process.env.AGENT_SHIM_CLAUDE_HOME;
3663
+ if (fromEnv !== void 0 && fromEnv !== "") {
3664
+ return fromEnv;
3665
+ }
3666
+ return import_node_path8.default.join(import_node_os.default.homedir(), ".claude");
3667
+ }
3668
+ function buildLayoutPaths(root) {
3669
+ return {
3670
+ root,
3671
+ identitiesDir: import_node_path8.default.join(root, "identities"),
3672
+ configProfilesDir: import_node_path8.default.join(root, "config-profiles"),
3673
+ providersDir: import_node_path8.default.join(root, "providers"),
3674
+ directoryRulesFile: import_node_path8.default.join(root, "directory-rules.json"),
3675
+ activeIdentityFile: import_node_path8.default.join(root, "active-identity"),
3676
+ globalConfigFile: import_node_path8.default.join(root, "config.json"),
3677
+ categoriesLocalFile: import_node_path8.default.join(root, "categories.local.json"),
3678
+ claudeShimFile: import_node_path8.default.join(root, "claude-shim.json"),
3679
+ headroomDir: import_node_path8.default.join(root, "headroom"),
3680
+ headroomStateFile: import_node_path8.default.join(root, "headroom", "state.json"),
3681
+ headroomLockFile: import_node_path8.default.join(root, "headroom", "start.lock"),
3682
+ headroomSessionsDir: import_node_path8.default.join(root, "headroom", "sessions"),
3683
+ logsDir: import_node_path8.default.join(root, "logs"),
3684
+ headroomLogPath: import_node_path8.default.join(root, "logs", "headroom.log"),
3685
+ frontdoorDir: import_node_path8.default.join(root, "frontdoor"),
3686
+ frontdoorCaDir: import_node_path8.default.join(root, "frontdoor", "ca"),
3687
+ frontdoorCaCertFile: import_node_path8.default.join(root, "frontdoor", "ca", "ca.pem"),
3688
+ frontdoorCaKeyFile: import_node_path8.default.join(root, "frontdoor", "ca", "ca.key"),
3689
+ frontdoorCaBundlesDir: import_node_path8.default.join(root, "frontdoor", "ca", "bundles"),
3690
+ frontdoorStateFile: import_node_path8.default.join(root, "frontdoor", "state.json"),
3691
+ frontdoorLockFile: import_node_path8.default.join(root, "frontdoor", "start.lock"),
3692
+ frontdoorSessionsDir: import_node_path8.default.join(root, "frontdoor", "sessions"),
3693
+ frontdoorLogPath: import_node_path8.default.join(root, "logs", "frontdoor.log"),
3694
+ usageDir: import_node_path8.default.join(root, "usage"),
3695
+ usageLogDir: import_node_path8.default.join(root, "usage", "log"),
3696
+ usageSnapshotsDir: import_node_path8.default.join(root, "usage", "snapshots"),
3697
+ usagePicksFile: import_node_path8.default.join(root, "usage", "picks.json")
3698
+ };
3699
+ }
3700
+ function resolveLayoutPaths() {
3701
+ return buildLayoutPaths(resolveAgentShimHome());
3702
+ }
3600
3703
  // Annotate the CommonJS export names for ESM import in node:
3601
3704
  0 && (module.exports = {
3602
3705
  AMBIENT_CREDENTIAL_VARS,
3603
3706
  CONNECT_INTERCEPT_HOST,
3707
+ CONNECT_INTERCEPT_HOSTS,
3604
3708
  CONNECT_LIMITS,
3709
+ CategoryClassificationOverlaySchema,
3710
+ CategoryClassificationSchema,
3711
+ CategoryMapSchema,
3712
+ CliError,
3713
+ ConfigProfileSchema,
3714
+ CredentialCacheSchema,
3715
+ CredentialSchema,
3716
+ CredentialSourceSchema,
3717
+ DirectoryRuleSchema,
3718
+ DirectoryRulesSchema,
3719
+ EXIT_FAILURE,
3720
+ EXIT_USAGE,
3721
+ EntryValueSchema,
3605
3722
  FARM_MANIFEST_FILENAME,
3606
3723
  FrontDoorStartError,
3724
+ GlobalConfigSchema,
3607
3725
  HeadroomStartError,
3726
+ IdentitySchema,
3727
+ PoolNameSchema,
3728
+ PoolSchema,
3729
+ PortableConfigSchema,
3730
+ ProviderSchema,
3608
3731
  ROUTED_PATH_PREFIX,
3732
+ UsageError,
3609
3733
  UsageSnapshotError,
3610
3734
  UsageSnapshotSchema,
3735
+ WhenSchema,
3611
3736
  buildEntryFacts,
3737
+ buildLayoutPaths,
3612
3738
  carryOver,
3613
3739
  createLeafCache,
3614
3740
  detectAmbientCredential,
@@ -3629,7 +3755,10 @@ function evaluateAmbientCredentialGuard(params) {
3629
3755
  realConnectEffects,
3630
3756
  recoverFarm,
3631
3757
  recoveryDiagnostics,
3758
+ resolveAgentShimHome,
3759
+ resolveClaudeHome,
3632
3760
  resolveDecisions,
3761
+ resolveLayoutPaths,
3633
3762
  resolveSupervisorConfig,
3634
3763
  resyncFarm,
3635
3764
  runFrontDoorSupervisor,