agent-shim 7.4.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/README.md CHANGED
@@ -226,6 +226,7 @@ Issues and pull requests are welcome. Please keep the tool itself free of assump
226
226
  - [docs/architecture.md](docs/architecture.md): the source layout file by file, error reporting design, schema rationale, and resolver mechanics.
227
227
  - [docs/release-process.md](docs/release-process.md): the semantic-release pipeline, the Node SEA build, its macOS x64 limitation, and npm/GitHub Packages publishing.
228
228
  - [docs/testing.md](docs/testing.md): the full list of cases the test suites cover.
229
+ - [docs/library.md](docs/library.md): using agent-shim in process: what the library exposes, and what stays CLI-only.
229
230
  - [docs/installation.md](docs/installation.md): every install channel in full, with the platform support matrix.
230
231
  - [docs/development.md](docs/development.md): test isolation, commit hooks, and the secret-redaction filter rationale.
231
232
 
package/dist/cli.cjs CHANGED
@@ -61051,7 +61051,7 @@ function resolveLaunchIdentity(paths, cwd) {
61051
61051
  // package.json
61052
61052
  var package_default = {
61053
61053
  name: "agent-shim",
61054
- version: "7.4.0",
61054
+ version: "7.5.0",
61055
61055
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
61056
61056
  license: "MIT",
61057
61057
  author: "Joseph Mearman <joseph@mearman.co.uk>",
package/dist/index.cjs CHANGED
@@ -34,13 +34,35 @@ __export(index_exports, {
34
34
  CONNECT_INTERCEPT_HOST: () => CONNECT_INTERCEPT_HOST,
35
35
  CONNECT_INTERCEPT_HOSTS: () => CONNECT_INTERCEPT_HOSTS,
36
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,
37
50
  FARM_MANIFEST_FILENAME: () => FARM_MANIFEST_FILENAME,
38
51
  FrontDoorStartError: () => FrontDoorStartError,
52
+ GlobalConfigSchema: () => GlobalConfigSchema,
39
53
  HeadroomStartError: () => HeadroomStartError,
54
+ IdentitySchema: () => IdentitySchema,
55
+ PoolNameSchema: () => PoolNameSchema,
56
+ PoolSchema: () => PoolSchema,
57
+ PortableConfigSchema: () => PortableConfigSchema,
58
+ ProviderSchema: () => ProviderSchema,
40
59
  ROUTED_PATH_PREFIX: () => ROUTED_PATH_PREFIX,
60
+ UsageError: () => UsageError,
41
61
  UsageSnapshotError: () => UsageSnapshotError,
42
62
  UsageSnapshotSchema: () => UsageSnapshotSchema,
63
+ WhenSchema: () => WhenSchema,
43
64
  buildEntryFacts: () => buildEntryFacts,
65
+ buildLayoutPaths: () => buildLayoutPaths,
44
66
  carryOver: () => carryOver,
45
67
  createLeafCache: () => createLeafCache,
46
68
  detectAmbientCredential: () => detectAmbientCredential,
@@ -61,7 +83,10 @@ __export(index_exports, {
61
83
  realConnectEffects: () => realConnectEffects,
62
84
  recoverFarm: () => recoverFarm,
63
85
  recoveryDiagnostics: () => recoveryDiagnostics,
86
+ resolveAgentShimHome: () => resolveAgentShimHome,
87
+ resolveClaudeHome: () => resolveClaudeHome,
64
88
  resolveDecisions: () => resolveDecisions,
89
+ resolveLayoutPaths: () => resolveLayoutPaths,
65
90
  resolveSupervisorConfig: () => resolveSupervisorConfig,
66
91
  resyncFarm: () => resyncFarm,
67
92
  runFrontDoorSupervisor: () => runFrontDoorSupervisor,
@@ -323,10 +348,18 @@ var import_cosmiconfig = require("cosmiconfig");
323
348
 
324
349
  // src/cliError.ts
325
350
  var EXIT_FAILURE = 1;
351
+ var EXIT_USAGE = 2;
326
352
  var CliError = class extends Error {
327
353
  /** The process exit status this failure maps to. `EXIT_FAILURE` unless a subclass says otherwise. */
328
354
  exitCode = EXIT_FAILURE;
329
355
  };
356
+ var UsageError = class extends CliError {
357
+ exitCode = EXIT_USAGE;
358
+ constructor(message) {
359
+ super(message);
360
+ this.name = "UsageError";
361
+ }
362
+ };
330
363
 
331
364
  // src/config/classify.ts
332
365
  var GLOB_METACHARACTERS = /[*?[\]{}!()]/;
@@ -1287,6 +1320,8 @@ function planReconciliation(params) {
1287
1320
  }
1288
1321
 
1289
1322
  // src/legacy.ts
1323
+ var HOME_DIRNAME = ".agent-shim";
1324
+ var LEGACY_HOME_DIRNAME = ".claude-use";
1290
1325
  var LEGACY_FARM_MANIFEST_FILENAME = ".claude-use-farm.json";
1291
1326
 
1292
1327
  // src/launcher/lock.ts
@@ -1388,8 +1423,8 @@ var FarmManifestSchema = import_zod2.z.strictObject({
1388
1423
  materialised: import_zod2.z.array(import_zod2.z.string()),
1389
1424
  links: import_zod2.z.array(import_zod2.z.strictObject({ rel: import_zod2.z.string(), target: import_zod2.z.string() }))
1390
1425
  });
1391
- function readFarmManifest(fs2, farmRoot) {
1392
- 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));
1393
1428
  if (raw === void 0) {
1394
1429
  return void 0;
1395
1430
  }
@@ -1447,9 +1482,9 @@ function buildEntryFacts(params) {
1447
1482
  entries
1448
1483
  };
1449
1484
  }
1450
- function listSubtree(fs2, root, rel) {
1485
+ function listSubtree(fs3, root, rel) {
1451
1486
  const absolute = import_node_path4.default.join(root, rel);
1452
- const stat = fs2.lstat(absolute);
1487
+ const stat = fs3.lstat(absolute);
1453
1488
  if (stat === void 0) {
1454
1489
  return [];
1455
1490
  }
@@ -1457,10 +1492,10 @@ function listSubtree(fs2, root, rel) {
1457
1492
  return [{ rel, kind: "symlink" }];
1458
1493
  }
1459
1494
  if (stat.kind === "dir") {
1460
- 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}`));
1461
1496
  return [{ rel, kind: "dir" }, ...children];
1462
1497
  }
1463
- const contentHash = fs2.hashFile(absolute);
1498
+ const contentHash = fs3.hashFile(absolute);
1464
1499
  return [{ rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } }];
1465
1500
  }
1466
1501
  function topLevelScopeRoots(roots) {
@@ -1474,25 +1509,25 @@ function topLevelScopeRoots(roots) {
1474
1509
  }
1475
1510
  return kept;
1476
1511
  }
1477
- function reconciliationScope(fs2, farmRoot, manifest) {
1512
+ function reconciliationScope(fs3, farmRoot, manifest) {
1478
1513
  if (manifest !== void 0) {
1479
1514
  return topLevelScopeRoots(manifest.materialised);
1480
1515
  }
1481
- 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();
1482
1517
  }
1483
- function collectFarmListing(fs2, farmRoot, scopeRoots) {
1484
- return scopeRoots.flatMap((root) => listSubtree(fs2, farmRoot, root));
1518
+ function collectFarmListing(fs3, farmRoot, scopeRoots) {
1519
+ return scopeRoots.flatMap((root) => listSubtree(fs3, farmRoot, root));
1485
1520
  }
1486
- function collectCanonicalCounterparts(fs2, claudeHome, farmListing) {
1521
+ function collectCanonicalCounterparts(fs3, claudeHome, farmListing) {
1487
1522
  const out = [];
1488
1523
  for (const entry of farmListing) {
1489
1524
  const absolute = import_node_path4.default.join(claudeHome, entry.rel);
1490
- const stat = fs2.lstat(absolute);
1525
+ const stat = fs3.lstat(absolute);
1491
1526
  if (stat === void 0) {
1492
1527
  continue;
1493
1528
  }
1494
1529
  if (stat.kind === "file") {
1495
- const contentHash = fs2.hashFile(absolute);
1530
+ const contentHash = fs3.hashFile(absolute);
1496
1531
  out.push({ rel: entry.rel, kind: "file", ...contentHash === void 0 ? {} : { contentHash } });
1497
1532
  continue;
1498
1533
  }
@@ -2176,10 +2211,10 @@ var FrontDoorStateSchema = import_zod3.z.strictObject({
2176
2211
  /** The last fatal error, kept across shutdowns so `frontdoor status` can explain a front door that is not running. */
2177
2212
  lastError: import_zod3.z.string().optional()
2178
2213
  });
2179
- function readFrontDoorState(fs2, stateFile) {
2214
+ function readFrontDoorState(fs3, stateFile) {
2180
2215
  let raw;
2181
2216
  try {
2182
- raw = fs2.readFileUtf8(stateFile);
2217
+ raw = fs3.readFileUtf8(stateFile);
2183
2218
  } catch {
2184
2219
  return void 0;
2185
2220
  }
@@ -2193,28 +2228,28 @@ function readFrontDoorState(fs2, stateFile) {
2193
2228
  return void 0;
2194
2229
  }
2195
2230
  }
2196
- function writeFrontDoorState(fs2, stateFile, state) {
2197
- fs2.mkdirp(import_node_path5.default.dirname(stateFile));
2198
- 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)}
2199
2234
  `);
2200
2235
  }
2201
2236
  function frontDoorOrigin(state) {
2202
2237
  const port = state?.directPort ?? state?.lastDirectPort;
2203
2238
  return port === void 0 ? void 0 : `http://127.0.0.1:${String(port)}`;
2204
2239
  }
2205
- function writeFrontDoorSession(fs2, sessionsDir, session) {
2206
- fs2.mkdirPrivate(sessionsDir);
2207
- 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)}
2208
2243
  `);
2209
2244
  }
2210
- function listFrontDoorSessions(fs2, sessionsDir) {
2245
+ function listFrontDoorSessions(fs3, sessionsDir) {
2211
2246
  const sessions = [];
2212
- for (const name of fs2.readdir(sessionsDir)) {
2247
+ for (const name of fs3.readdir(sessionsDir)) {
2213
2248
  if (!name.endsWith(".json")) {
2214
2249
  continue;
2215
2250
  }
2216
2251
  try {
2217
- 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)) ?? ""));
2218
2253
  if (parsed.success) {
2219
2254
  sessions.push({ pid: parsed.data.pid, startedAt: parsed.data.startedAt });
2220
2255
  }
@@ -2224,14 +2259,14 @@ function listFrontDoorSessions(fs2, sessionsDir) {
2224
2259
  }
2225
2260
  return sessions.sort((a, b) => a.pid - b.pid);
2226
2261
  }
2227
- function removeFrontDoorSession(fs2, sessionsDir, pid) {
2228
- 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`));
2229
2264
  }
2230
- function pruneDeadFrontDoorSessions(fs2, sessionsDir, isRunning) {
2265
+ function pruneDeadFrontDoorSessions(fs3, sessionsDir, isRunning) {
2231
2266
  const removed = [];
2232
- for (const session of listFrontDoorSessions(fs2, sessionsDir)) {
2267
+ for (const session of listFrontDoorSessions(fs3, sessionsDir)) {
2233
2268
  if (!isRunning(session.pid)) {
2234
- removeFrontDoorSession(fs2, sessionsDir, session.pid);
2269
+ removeFrontDoorSession(fs3, sessionsDir, session.pid);
2235
2270
  removed.push(session.pid);
2236
2271
  }
2237
2272
  }
@@ -2243,8 +2278,8 @@ var FRONTDOOR_SUPERVISOR_STILL_RUNNING = -1;
2243
2278
  var FRONTDOOR_POLL_MS = 1e3;
2244
2279
  var MS_PER_MINUTE = 6e4;
2245
2280
  async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {}) {
2246
- const { fs: fs2, paths } = ports;
2247
- const previous = readFrontDoorState(fs2, paths.frontdoorStateFile);
2281
+ const { fs: fs3, paths } = ports;
2282
+ const previous = readFrontDoorState(fs3, paths.frontdoorStateFile);
2248
2283
  let lastPort = previous?.lastPort;
2249
2284
  let lastConnectPort = previous?.lastConnectPort;
2250
2285
  let lastDirectPort = previous?.lastDirectPort;
@@ -2254,12 +2289,12 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2254
2289
  ...lastDirectPort === void 0 ? {} : { lastDirectPort }
2255
2290
  });
2256
2291
  const fail = (message) => {
2257
- writeFrontDoorState(fs2, paths.frontdoorStateFile, { lastError: message, ...sticky() });
2258
- fs2.removeRecursive(paths.frontdoorLockFile);
2292
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, { lastError: message, ...sticky() });
2293
+ fs3.removeRecursive(paths.frontdoorLockFile);
2259
2294
  ports.log(`agent-shim frontdoor supervisor: ${message}`);
2260
2295
  return 1;
2261
2296
  };
2262
- writeFrontDoorState(fs2, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
2297
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, ...sticky() });
2263
2298
  const previousSticky = lastPort;
2264
2299
  let http2;
2265
2300
  try {
@@ -2296,8 +2331,8 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2296
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)`);
2297
2332
  }
2298
2333
  lastDirectPort = direct.port;
2299
- writeFrontDoorState(fs2, paths.frontdoorStateFile, { supervisorPid: ports.ownPid, port: http2.port, connectPort: connect2.port, directPort: direct.port, ...sticky() });
2300
- 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);
2301
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)}`);
2302
2337
  let idleSince;
2303
2338
  let ticks = 0;
@@ -2306,15 +2341,15 @@ async function runFrontDoorSupervisor(idleShutdownMinutes, ports, options = {})
2306
2341
  return FRONTDOOR_SUPERVISOR_STILL_RUNNING;
2307
2342
  }
2308
2343
  ticks += 1;
2309
- pruneDeadFrontDoorSessions(fs2, paths.frontdoorSessionsDir, ports.isRunning);
2310
- if (listFrontDoorSessions(fs2, paths.frontdoorSessionsDir).length === 0) {
2344
+ pruneDeadFrontDoorSessions(fs3, paths.frontdoorSessionsDir, ports.isRunning);
2345
+ if (listFrontDoorSessions(fs3, paths.frontdoorSessionsDir).length === 0) {
2311
2346
  idleSince ??= ports.now();
2312
2347
  if (ports.now() - idleSince >= idleShutdownMinutes * MS_PER_MINUTE) {
2313
2348
  ports.log(`agent-shim frontdoor supervisor: no sessions for ${String(idleShutdownMinutes)} minute(s); closing the front door and exiting`);
2314
2349
  await direct.close();
2315
2350
  await connect2.close();
2316
2351
  await http2.close();
2317
- writeFrontDoorState(fs2, paths.frontdoorStateFile, sticky());
2352
+ writeFrontDoorState(fs3, paths.frontdoorStateFile, sticky());
2318
2353
  return 0;
2319
2354
  }
2320
2355
  } else {
@@ -2369,8 +2404,8 @@ function parseConnectTarget(authority) {
2369
2404
  function isInterceptedHost(host, interceptHosts) {
2370
2405
  return interceptHosts.includes(host);
2371
2406
  }
2372
- function servedByPipeline(path8) {
2373
- return path8?.startsWith(ROUTED_PATH_PREFIX) === true;
2407
+ function servedByPipeline(path9) {
2408
+ return path9?.startsWith(ROUTED_PATH_PREFIX) === true;
2374
2409
  }
2375
2410
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
2376
2411
  "connection",
@@ -2853,16 +2888,16 @@ function parseJson(raw, schema) {
2853
2888
  const parsed = schema.safeParse(JSON.parse(raw));
2854
2889
  return parsed.success ? parsed.data : void 0;
2855
2890
  }
2856
- function readHeadroomState(fs2, stateFile) {
2891
+ function readHeadroomState(fs3, stateFile) {
2857
2892
  try {
2858
- return parseJson(fs2.readFileUtf8(stateFile), HeadroomStateSchema);
2893
+ return parseJson(fs3.readFileUtf8(stateFile), HeadroomStateSchema);
2859
2894
  } catch {
2860
2895
  return void 0;
2861
2896
  }
2862
2897
  }
2863
- function writeHeadroomState(fs2, stateFile, state) {
2864
- fs2.mkdirp(import_node_path6.default.dirname(stateFile));
2865
- 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)}
2866
2901
  `);
2867
2902
  }
2868
2903
  function headroomAllowlist(providers) {
@@ -2882,14 +2917,14 @@ function headroomUpstreams(providers, frontDoorOrigin2) {
2882
2917
  function hashAllowlist(allowlist) {
2883
2918
  return (0, import_node_crypto4.createHash)("sha256").update(allowlist.join("\n")).digest("hex");
2884
2919
  }
2885
- function readAllProviders(fs2, providersDir) {
2920
+ function readAllProviders(fs3, providersDir) {
2886
2921
  const result = [];
2887
- for (const name of fs2.readdir(providersDir)) {
2922
+ for (const name of fs3.readdir(providersDir)) {
2888
2923
  if (!name.endsWith(".json")) {
2889
2924
  continue;
2890
2925
  }
2891
2926
  try {
2892
- 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);
2893
2928
  if (parsed !== void 0) {
2894
2929
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
2895
2930
  }
@@ -2899,22 +2934,22 @@ function readAllProviders(fs2, providersDir) {
2899
2934
  }
2900
2935
  return result;
2901
2936
  }
2902
- function writeSession(fs2, sessionsDir, session) {
2903
- fs2.mkdirp(sessionsDir);
2904
- 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)}
2905
2940
  `);
2906
2941
  }
2907
- function removeSession(fs2, sessionsDir, pid) {
2908
- 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`));
2909
2944
  }
2910
- function listSessions(fs2, sessionsDir) {
2945
+ function listSessions(fs3, sessionsDir) {
2911
2946
  const sessions = [];
2912
- for (const name of fs2.readdir(sessionsDir)) {
2947
+ for (const name of fs3.readdir(sessionsDir)) {
2913
2948
  if (!name.endsWith(".json")) {
2914
2949
  continue;
2915
2950
  }
2916
2951
  try {
2917
- 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);
2918
2953
  if (parsed !== void 0) {
2919
2954
  sessions.push(parsed);
2920
2955
  }
@@ -2924,22 +2959,22 @@ function listSessions(fs2, sessionsDir) {
2924
2959
  }
2925
2960
  return sessions.sort((a, b) => a.pid - b.pid);
2926
2961
  }
2927
- function sessionsForSupervisor(fs2, sessionsDir, supervisorPid) {
2928
- 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);
2929
2964
  }
2930
- function pruneDeadSessions(fs2, sessionsDir, isRunning) {
2965
+ function pruneDeadSessions(fs3, sessionsDir, isRunning) {
2931
2966
  const removed = [];
2932
- for (const session of listSessions(fs2, sessionsDir)) {
2967
+ for (const session of listSessions(fs3, sessionsDir)) {
2933
2968
  if (!isRunning(session.pid)) {
2934
- removeSession(fs2, sessionsDir, session.pid);
2969
+ removeSession(fs3, sessionsDir, session.pid);
2935
2970
  removed.push(session.pid);
2936
2971
  }
2937
2972
  }
2938
2973
  return removed;
2939
2974
  }
2940
- function readStartLock(fs2, lockFile) {
2975
+ function readStartLock(fs3, lockFile) {
2941
2976
  try {
2942
- return parseJson(fs2.readFileUtf8(lockFile), HeadroomLockSchema);
2977
+ return parseJson(fs3.readFileUtf8(lockFile), HeadroomLockSchema);
2943
2978
  } catch {
2944
2979
  return void 0;
2945
2980
  }
@@ -3176,9 +3211,9 @@ function snapshotPath(snapshotsDir, identity) {
3176
3211
  }
3177
3212
  return import_node_path7.default.join(snapshotsDir, `${identity}.json`);
3178
3213
  }
3179
- function readUsageSnapshot(fs2, snapshotsDir, identity) {
3214
+ function readUsageSnapshot(fs3, snapshotsDir, identity) {
3180
3215
  const file = snapshotPath(snapshotsDir, identity);
3181
- const raw = fs2.readFileUtf8(file);
3216
+ const raw = fs3.readFileUtf8(file);
3182
3217
  if (raw === void 0) {
3183
3218
  return void 0;
3184
3219
  }
@@ -3194,8 +3229,8 @@ function readUsageSnapshot(fs2, snapshotsDir, identity) {
3194
3229
  }
3195
3230
  return snapshot.data;
3196
3231
  }
3197
- function listUsageSnapshots(fs2, snapshotsDir) {
3198
- return fs2.readdir(snapshotsDir).flatMap((name) => {
3232
+ function listUsageSnapshots(fs3, snapshotsDir) {
3233
+ return fs3.readdir(snapshotsDir).flatMap((name) => {
3199
3234
  if (!name.endsWith(".json")) {
3200
3235
  return [];
3201
3236
  }
@@ -3203,7 +3238,7 @@ function listUsageSnapshots(fs2, snapshotsDir) {
3203
3238
  if (!isIdentityName(identity)) {
3204
3239
  return [];
3205
3240
  }
3206
- const snapshot = readUsageSnapshot(fs2, snapshotsDir, identity);
3241
+ const snapshot = readUsageSnapshot(fs3, snapshotsDir, identity);
3207
3242
  return snapshot === void 0 ? [] : [snapshot];
3208
3243
  }).sort((left, right) => left.identity.localeCompare(right.identity));
3209
3244
  }
@@ -3370,9 +3405,9 @@ function compareVersions(a, b) {
3370
3405
  }
3371
3406
  var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
3372
3407
  async function runSupervisor(initialConfig, ports, options = {}) {
3373
- const { fs: fs2, paths } = ports;
3408
+ const { fs: fs3, paths } = ports;
3374
3409
  let config = initialConfig;
3375
- const previousState = readHeadroomState(fs2, paths.headroomStateFile);
3410
+ const previousState = readHeadroomState(fs3, paths.headroomStateFile);
3376
3411
  if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
3377
3412
  ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
3378
3413
  return 0;
@@ -3381,19 +3416,19 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3381
3416
  let lastPort = previousState?.lastPort;
3382
3417
  const sticky = () => lastPort === void 0 ? {} : { lastPort };
3383
3418
  const ownsState = () => {
3384
- const owner = readHeadroomState(fs2, paths.headroomStateFile)?.supervisorPid;
3419
+ const owner = readHeadroomState(fs3, paths.headroomStateFile)?.supervisorPid;
3385
3420
  return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
3386
3421
  };
3387
3422
  const writeOwnState = (state) => {
3388
3423
  if (!ownsState()) {
3389
3424
  return false;
3390
3425
  }
3391
- writeHeadroomState(fs2, paths.headroomStateFile, state);
3426
+ writeHeadroomState(fs3, paths.headroomStateFile, state);
3392
3427
  return true;
3393
3428
  };
3394
3429
  const fail = (message) => {
3395
3430
  if (writeOwnState({ lastError: message, ...sticky() })) {
3396
- fs2.removeRecursive(paths.headroomLockFile);
3431
+ fs3.removeRecursive(paths.headroomLockFile);
3397
3432
  }
3398
3433
  ports.log(`agent-shim headroom supervisor: ${message}`);
3399
3434
  return 1;
@@ -3442,7 +3477,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3442
3477
  const settingsHash = hashSettings(config.settings);
3443
3478
  const allowlist = allowlistOf(ports);
3444
3479
  const allowlistHash = hashAllowlist(allowlist);
3445
- pruneDeadSessions(fs2, paths.headroomSessionsDir, ports.isRunning);
3480
+ pruneDeadSessions(fs3, paths.headroomSessionsDir, ports.isRunning);
3446
3481
  const ownsNow = ownsState();
3447
3482
  if (!ownsNow && !superseded) {
3448
3483
  ports.log("agent-shim headroom supervisor: another supervisor now owns state.json; serving this daemon's own sessions until they end");
@@ -3494,7 +3529,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3494
3529
  ...sticky()
3495
3530
  });
3496
3531
  if (recorded) {
3497
- fs2.removeRecursive(paths.headroomLockFile);
3532
+ fs3.removeRecursive(paths.headroomLockFile);
3498
3533
  }
3499
3534
  idleSince = void 0;
3500
3535
  ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on 127.0.0.1:${String(port)}`);
@@ -3509,7 +3544,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3509
3544
  }
3510
3545
  } else {
3511
3546
  if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
3512
- if (sessionsForSupervisor(fs2, paths.headroomSessionsDir, ports.ownPid).length === 0) {
3547
+ if (sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid).length === 0) {
3513
3548
  ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
3514
3549
  ports.stopProcess(headroomPid);
3515
3550
  headroomPid = void 0;
@@ -3518,7 +3553,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3518
3553
  continue;
3519
3554
  }
3520
3555
  }
3521
- const sessions = sessionsForSupervisor(fs2, paths.headroomSessionsDir, ports.ownPid);
3556
+ const sessions = sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid);
3522
3557
  if (sessions.length === 0) {
3523
3558
  idleSince ??= ports.now();
3524
3559
  const idleMs = ports.now() - idleSince;
@@ -3540,9 +3575,9 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3540
3575
  await ports.sleep(HEADROOM_POLL_MS);
3541
3576
  }
3542
3577
  }
3543
- function currentHeadroomAllowlist(fs2, paths) {
3544
- const providers = readAllProviders(fs2, paths.providersDir).map((entry) => entry.provider);
3545
- 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))));
3546
3581
  }
3547
3582
  function allowlistOf(ports) {
3548
3583
  return currentHeadroomAllowlist(ports.fs, ports.paths);
@@ -3606,19 +3641,100 @@ function evaluateAmbientCredentialGuard(params) {
3606
3641
  message: formatAmbientCredentialGuardMessage(detected.variable, params.identityName)
3607
3642
  };
3608
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
+ }
3609
3703
  // Annotate the CommonJS export names for ESM import in node:
3610
3704
  0 && (module.exports = {
3611
3705
  AMBIENT_CREDENTIAL_VARS,
3612
3706
  CONNECT_INTERCEPT_HOST,
3613
3707
  CONNECT_INTERCEPT_HOSTS,
3614
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,
3615
3722
  FARM_MANIFEST_FILENAME,
3616
3723
  FrontDoorStartError,
3724
+ GlobalConfigSchema,
3617
3725
  HeadroomStartError,
3726
+ IdentitySchema,
3727
+ PoolNameSchema,
3728
+ PoolSchema,
3729
+ PortableConfigSchema,
3730
+ ProviderSchema,
3618
3731
  ROUTED_PATH_PREFIX,
3732
+ UsageError,
3619
3733
  UsageSnapshotError,
3620
3734
  UsageSnapshotSchema,
3735
+ WhenSchema,
3621
3736
  buildEntryFacts,
3737
+ buildLayoutPaths,
3622
3738
  carryOver,
3623
3739
  createLeafCache,
3624
3740
  detectAmbientCredential,
@@ -3639,7 +3755,10 @@ function evaluateAmbientCredentialGuard(params) {
3639
3755
  realConnectEffects,
3640
3756
  recoverFarm,
3641
3757
  recoveryDiagnostics,
3758
+ resolveAgentShimHome,
3759
+ resolveClaudeHome,
3642
3760
  resolveDecisions,
3761
+ resolveLayoutPaths,
3643
3762
  resolveSupervisorConfig,
3644
3763
  resyncFarm,
3645
3764
  runFrontDoorSupervisor,
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 {
@@ -2294,8 +2304,8 @@ function parseConnectTarget(authority) {
2294
2304
  function isInterceptedHost(host, interceptHosts) {
2295
2305
  return interceptHosts.includes(host);
2296
2306
  }
2297
- function servedByPipeline(path8) {
2298
- return path8?.startsWith(ROUTED_PATH_PREFIX) === true;
2307
+ function servedByPipeline(path9) {
2308
+ return path9?.startsWith(ROUTED_PATH_PREFIX) === true;
2299
2309
  }
2300
2310
  var HOP_BY_HOP_HEADERS = /* @__PURE__ */ new Set([
2301
2311
  "connection",
@@ -2778,16 +2788,16 @@ function parseJson(raw, schema) {
2778
2788
  const parsed = schema.safeParse(JSON.parse(raw));
2779
2789
  return parsed.success ? parsed.data : void 0;
2780
2790
  }
2781
- function readHeadroomState(fs2, stateFile) {
2791
+ function readHeadroomState(fs3, stateFile) {
2782
2792
  try {
2783
- return parseJson(fs2.readFileUtf8(stateFile), HeadroomStateSchema);
2793
+ return parseJson(fs3.readFileUtf8(stateFile), HeadroomStateSchema);
2784
2794
  } catch {
2785
2795
  return void 0;
2786
2796
  }
2787
2797
  }
2788
- function writeHeadroomState(fs2, stateFile, state) {
2789
- fs2.mkdirp(path6.dirname(stateFile));
2790
- 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)}
2791
2801
  `);
2792
2802
  }
2793
2803
  function headroomAllowlist(providers) {
@@ -2807,14 +2817,14 @@ function headroomUpstreams(providers, frontDoorOrigin2) {
2807
2817
  function hashAllowlist(allowlist) {
2808
2818
  return createHash2("sha256").update(allowlist.join("\n")).digest("hex");
2809
2819
  }
2810
- function readAllProviders(fs2, providersDir) {
2820
+ function readAllProviders(fs3, providersDir) {
2811
2821
  const result = [];
2812
- for (const name of fs2.readdir(providersDir)) {
2822
+ for (const name of fs3.readdir(providersDir)) {
2813
2823
  if (!name.endsWith(".json")) {
2814
2824
  continue;
2815
2825
  }
2816
2826
  try {
2817
- const parsed = parseJson(fs2.readFileUtf8(path6.join(providersDir, name)), ProviderSchema);
2827
+ const parsed = parseJson(fs3.readFileUtf8(path6.join(providersDir, name)), ProviderSchema);
2818
2828
  if (parsed !== void 0) {
2819
2829
  result.push({ name: name.slice(0, -".json".length), provider: parsed });
2820
2830
  }
@@ -2824,22 +2834,22 @@ function readAllProviders(fs2, providersDir) {
2824
2834
  }
2825
2835
  return result;
2826
2836
  }
2827
- function writeSession(fs2, sessionsDir, session) {
2828
- fs2.mkdirp(sessionsDir);
2829
- 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)}
2830
2840
  `);
2831
2841
  }
2832
- function removeSession(fs2, sessionsDir, pid) {
2833
- fs2.removeRecursive(path6.join(sessionsDir, `${String(pid)}.json`));
2842
+ function removeSession(fs3, sessionsDir, pid) {
2843
+ fs3.removeRecursive(path6.join(sessionsDir, `${String(pid)}.json`));
2834
2844
  }
2835
- function listSessions(fs2, sessionsDir) {
2845
+ function listSessions(fs3, sessionsDir) {
2836
2846
  const sessions = [];
2837
- for (const name of fs2.readdir(sessionsDir)) {
2847
+ for (const name of fs3.readdir(sessionsDir)) {
2838
2848
  if (!name.endsWith(".json")) {
2839
2849
  continue;
2840
2850
  }
2841
2851
  try {
2842
- const parsed = parseJson(fs2.readFileUtf8(path6.join(sessionsDir, name)), HeadroomSessionSchema);
2852
+ const parsed = parseJson(fs3.readFileUtf8(path6.join(sessionsDir, name)), HeadroomSessionSchema);
2843
2853
  if (parsed !== void 0) {
2844
2854
  sessions.push(parsed);
2845
2855
  }
@@ -2849,22 +2859,22 @@ function listSessions(fs2, sessionsDir) {
2849
2859
  }
2850
2860
  return sessions.sort((a, b) => a.pid - b.pid);
2851
2861
  }
2852
- function sessionsForSupervisor(fs2, sessionsDir, supervisorPid) {
2853
- 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);
2854
2864
  }
2855
- function pruneDeadSessions(fs2, sessionsDir, isRunning) {
2865
+ function pruneDeadSessions(fs3, sessionsDir, isRunning) {
2856
2866
  const removed = [];
2857
- for (const session of listSessions(fs2, sessionsDir)) {
2867
+ for (const session of listSessions(fs3, sessionsDir)) {
2858
2868
  if (!isRunning(session.pid)) {
2859
- removeSession(fs2, sessionsDir, session.pid);
2869
+ removeSession(fs3, sessionsDir, session.pid);
2860
2870
  removed.push(session.pid);
2861
2871
  }
2862
2872
  }
2863
2873
  return removed;
2864
2874
  }
2865
- function readStartLock(fs2, lockFile) {
2875
+ function readStartLock(fs3, lockFile) {
2866
2876
  try {
2867
- return parseJson(fs2.readFileUtf8(lockFile), HeadroomLockSchema);
2877
+ return parseJson(fs3.readFileUtf8(lockFile), HeadroomLockSchema);
2868
2878
  } catch {
2869
2879
  return void 0;
2870
2880
  }
@@ -3101,9 +3111,9 @@ function snapshotPath(snapshotsDir, identity) {
3101
3111
  }
3102
3112
  return path7.join(snapshotsDir, `${identity}.json`);
3103
3113
  }
3104
- function readUsageSnapshot(fs2, snapshotsDir, identity) {
3114
+ function readUsageSnapshot(fs3, snapshotsDir, identity) {
3105
3115
  const file = snapshotPath(snapshotsDir, identity);
3106
- const raw = fs2.readFileUtf8(file);
3116
+ const raw = fs3.readFileUtf8(file);
3107
3117
  if (raw === void 0) {
3108
3118
  return void 0;
3109
3119
  }
@@ -3119,8 +3129,8 @@ function readUsageSnapshot(fs2, snapshotsDir, identity) {
3119
3129
  }
3120
3130
  return snapshot.data;
3121
3131
  }
3122
- function listUsageSnapshots(fs2, snapshotsDir) {
3123
- return fs2.readdir(snapshotsDir).flatMap((name) => {
3132
+ function listUsageSnapshots(fs3, snapshotsDir) {
3133
+ return fs3.readdir(snapshotsDir).flatMap((name) => {
3124
3134
  if (!name.endsWith(".json")) {
3125
3135
  return [];
3126
3136
  }
@@ -3128,7 +3138,7 @@ function listUsageSnapshots(fs2, snapshotsDir) {
3128
3138
  if (!isIdentityName(identity)) {
3129
3139
  return [];
3130
3140
  }
3131
- const snapshot = readUsageSnapshot(fs2, snapshotsDir, identity);
3141
+ const snapshot = readUsageSnapshot(fs3, snapshotsDir, identity);
3132
3142
  return snapshot === void 0 ? [] : [snapshot];
3133
3143
  }).sort((left, right) => left.identity.localeCompare(right.identity));
3134
3144
  }
@@ -3295,9 +3305,9 @@ function compareVersions(a, b) {
3295
3305
  }
3296
3306
  var HEADROOM_SUPERVISOR_STILL_RUNNING = -1;
3297
3307
  async function runSupervisor(initialConfig, ports, options = {}) {
3298
- const { fs: fs2, paths } = ports;
3308
+ const { fs: fs3, paths } = ports;
3299
3309
  let config = initialConfig;
3300
- const previousState = readHeadroomState(fs2, paths.headroomStateFile);
3310
+ const previousState = readHeadroomState(fs3, paths.headroomStateFile);
3301
3311
  if (previousState?.supervisorPid !== void 0 && previousState.supervisorPid !== ports.ownPid && ports.isRunning(previousState.supervisorPid)) {
3302
3312
  ports.log(`agent-shim headroom supervisor ${String(ports.ownPid)}: supervisor ${String(previousState.supervisorPid)} already owns the daemon; exiting`);
3303
3313
  return 0;
@@ -3306,19 +3316,19 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3306
3316
  let lastPort = previousState?.lastPort;
3307
3317
  const sticky = () => lastPort === void 0 ? {} : { lastPort };
3308
3318
  const ownsState = () => {
3309
- const owner = readHeadroomState(fs2, paths.headroomStateFile)?.supervisorPid;
3319
+ const owner = readHeadroomState(fs3, paths.headroomStateFile)?.supervisorPid;
3310
3320
  return owner === void 0 || owner === ports.ownPid || !ports.isRunning(owner);
3311
3321
  };
3312
3322
  const writeOwnState = (state) => {
3313
3323
  if (!ownsState()) {
3314
3324
  return false;
3315
3325
  }
3316
- writeHeadroomState(fs2, paths.headroomStateFile, state);
3326
+ writeHeadroomState(fs3, paths.headroomStateFile, state);
3317
3327
  return true;
3318
3328
  };
3319
3329
  const fail = (message) => {
3320
3330
  if (writeOwnState({ lastError: message, ...sticky() })) {
3321
- fs2.removeRecursive(paths.headroomLockFile);
3331
+ fs3.removeRecursive(paths.headroomLockFile);
3322
3332
  }
3323
3333
  ports.log(`agent-shim headroom supervisor: ${message}`);
3324
3334
  return 1;
@@ -3367,7 +3377,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3367
3377
  const settingsHash = hashSettings(config.settings);
3368
3378
  const allowlist = allowlistOf(ports);
3369
3379
  const allowlistHash = hashAllowlist(allowlist);
3370
- pruneDeadSessions(fs2, paths.headroomSessionsDir, ports.isRunning);
3380
+ pruneDeadSessions(fs3, paths.headroomSessionsDir, ports.isRunning);
3371
3381
  const ownsNow = ownsState();
3372
3382
  if (!ownsNow && !superseded) {
3373
3383
  ports.log("agent-shim headroom supervisor: another supervisor now owns state.json; serving this daemon's own sessions until they end");
@@ -3419,7 +3429,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3419
3429
  ...sticky()
3420
3430
  });
3421
3431
  if (recorded) {
3422
- fs2.removeRecursive(paths.headroomLockFile);
3432
+ fs3.removeRecursive(paths.headroomLockFile);
3423
3433
  }
3424
3434
  idleSince = void 0;
3425
3435
  ports.log(`agent-shim headroom supervisor: headroom pid ${String(pid)} ready on 127.0.0.1:${String(port)}`);
@@ -3434,7 +3444,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3434
3444
  }
3435
3445
  } else {
3436
3446
  if (runningHash !== allowlistHash || runningSettingsHash !== settingsHash || installedSource !== config.source) {
3437
- if (sessionsForSupervisor(fs2, paths.headroomSessionsDir, ports.ownPid).length === 0) {
3447
+ if (sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid).length === 0) {
3438
3448
  ports.log("agent-shim headroom supervisor: configuration drifted and no sessions are live; restarting headroom");
3439
3449
  ports.stopProcess(headroomPid);
3440
3450
  headroomPid = void 0;
@@ -3443,7 +3453,7 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3443
3453
  continue;
3444
3454
  }
3445
3455
  }
3446
- const sessions = sessionsForSupervisor(fs2, paths.headroomSessionsDir, ports.ownPid);
3456
+ const sessions = sessionsForSupervisor(fs3, paths.headroomSessionsDir, ports.ownPid);
3447
3457
  if (sessions.length === 0) {
3448
3458
  idleSince ??= ports.now();
3449
3459
  const idleMs = ports.now() - idleSince;
@@ -3465,9 +3475,9 @@ async function runSupervisor(initialConfig, ports, options = {}) {
3465
3475
  await ports.sleep(HEADROOM_POLL_MS);
3466
3476
  }
3467
3477
  }
3468
- function currentHeadroomAllowlist(fs2, paths) {
3469
- const providers = readAllProviders(fs2, paths.providersDir).map((entry) => entry.provider);
3470
- 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))));
3471
3481
  }
3472
3482
  function allowlistOf(ports) {
3473
3483
  return currentHeadroomAllowlist(ports.fs, ports.paths);
@@ -3531,18 +3541,99 @@ function evaluateAmbientCredentialGuard(params) {
3531
3541
  message: formatAmbientCredentialGuardMessage(detected.variable, params.identityName)
3532
3542
  };
3533
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
+ }
3534
3603
  export {
3535
3604
  AMBIENT_CREDENTIAL_VARS,
3536
3605
  CONNECT_INTERCEPT_HOST,
3537
3606
  CONNECT_INTERCEPT_HOSTS,
3538
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,
3539
3621
  FARM_MANIFEST_FILENAME,
3540
3622
  FrontDoorStartError,
3623
+ GlobalConfigSchema,
3541
3624
  HeadroomStartError,
3625
+ IdentitySchema,
3626
+ PoolNameSchema,
3627
+ PoolSchema,
3628
+ PortableConfigSchema,
3629
+ ProviderSchema,
3542
3630
  ROUTED_PATH_PREFIX,
3631
+ UsageError,
3543
3632
  UsageSnapshotError,
3544
3633
  UsageSnapshotSchema,
3634
+ WhenSchema,
3545
3635
  buildEntryFacts,
3636
+ buildLayoutPaths,
3546
3637
  carryOver,
3547
3638
  createLeafCache,
3548
3639
  detectAmbientCredential,
@@ -3563,7 +3654,10 @@ export {
3563
3654
  realConnectEffects,
3564
3655
  recoverFarm,
3565
3656
  recoveryDiagnostics,
3657
+ resolveAgentShimHome,
3658
+ resolveClaudeHome,
3566
3659
  resolveDecisions,
3660
+ resolveLayoutPaths,
3567
3661
  resolveSupervisorConfig,
3568
3662
  resyncFarm,
3569
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>;
@@ -4,7 +4,8 @@
4
4
  * - identity and configuration-profile resolution and farm sync (`resolveDecisions`, `resyncFarm`, `buildEntryFacts`, ...), pure over facts and ports passed in;
5
5
  * - routing: the front door's Remote-Control-preserving, capability-authenticated CONNECT surface and its certificate authority, the front-door supervisor and ensure lifecycle, and the headroom supervisor and ensure lifecycle, each pure over its injected ports;
6
6
  * - the ambient-credential guard;
7
- * - the per-identity usage snapshot a statusline or launcher reads: its schema and the reader over an injected filesystem.
7
+ * - the per-identity usage snapshot a statusline or launcher reads: its schema and the reader over an injected filesystem;
8
+ * - the state root's layout (`resolveAgentShimHome`, `resolveLayoutPaths`, `buildLayoutPaths`), which includes adopting an existing `~/.claude-use` in place, and the Zod schema and inferred type of every configuration file (identity, configuration profile, provider, pool, directory rules, global config, credential), so a tool can validate or generate them with the same definitions the CLI uses.
8
9
  *
9
10
  * Everything the CLI alone needs (commander wiring, prompts, `doctor`, `check`) is deliberately not exported here.
10
11
  */
@@ -19,3 +20,6 @@ export { UsageSnapshotSchema, type UsageSnapshot } from "./usage/schema";
19
20
  export { ensureHeadroom, HeadroomStartError, type EnsureHeadroomPorts } from "./headroom/ensure";
20
21
  export { resolveSupervisorConfig, runSupervisor, type HeadroomSupervisorConfig, type RunSupervisorOptions, type SupervisorPorts } from "./headroom/supervisor";
21
22
  export { AMBIENT_CREDENTIAL_VARS, detectAmbientCredential, evaluateAmbientCredentialGuard, formatAmbientCredentialGuardMessage, type AmbientCredentialDetection, type AmbientCredentialGuardResult, type AmbientCredentialVar, type EvaluateAmbientCredentialGuardParams, type InjectedCredential, } from "./launcher/guard";
23
+ export { buildLayoutPaths, resolveAgentShimHome, resolveClaudeHome, resolveLayoutPaths, type LayoutPaths } from "./paths";
24
+ export { CliError, EXIT_FAILURE, EXIT_USAGE, UsageError } from "./cliError";
25
+ export { CategoryClassificationOverlaySchema, CategoryClassificationSchema, CategoryMapSchema, ConfigProfileSchema, CredentialCacheSchema, CredentialSchema, CredentialSourceSchema, DirectoryRuleSchema, DirectoryRulesSchema, EntryValueSchema, GlobalConfigSchema, IdentitySchema, PoolNameSchema, PoolSchema, PortableConfigSchema, ProviderSchema, WhenSchema, type CategoryMap, type ConfigProfile, type Credential, type CredentialSource, type DirectoryRule, type DirectoryRules, type EntryValue, type GlobalConfig, type Identity, type Pool, type PortableConfig, type Provider, type WhenCondition, } from "./config/schema";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-shim",
3
- "version": "7.4.0",
3
+ "version": "7.5.0",
4
4
  "description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
5
5
  "license": "MIT",
6
6
  "author": "Joseph Mearman <joseph@mearman.co.uk>",